11import math
2+ from pathlib import Path
23
34import numpy as np
5+ import pandas as pd
6+ from scipy .interpolate import interp1d
47
58from diffpy .utils .scattering_objects .diffraction_objects import Diffraction_object
69
710RADIUS_MM = 1
811N_POINTS_ON_DIAMETER = 300
9- TTH_GRID = np .arange (1 , 141 , 1 )
12+ TTH_GRID = np .arange (1 , 180.1 , 0.1 )
13+ CVE_METHODS = ["brute_force" , "polynomial_interpolation" ]
14+
15+ # pre-computed datasets for polynomial interpolation (fast calculation)
16+ MUD_LIST = [0.5 , 1 , 2 , 3 , 4 , 5 , 6 ]
17+ CWD = Path (__file__ ).parent .resolve ()
18+ MULS = np .loadtxt (CWD / "data" / "inverse_cve.xy" )
19+ COEFFICIENT_LIST = np .array (pd .read_csv (CWD / "data" / "coefficient_list.csv" , header = None ))
20+ INTERPOLATION_FUNCTIONS = [interp1d (MUD_LIST , coefficients , kind = "quadratic" ) for coefficients in COEFFICIENT_LIST ]
1021
1122
1223class Gridded_circle :
@@ -172,28 +183,10 @@ def get_path_length(self, grid_point, angle):
172183 return total_distance , primary_distance , secondary_distance
173184
174185
175- def compute_cve (diffraction_data , mud , wavelength ):
186+ def _cve_brute_force (diffraction_data , mud ):
176187 """
177- compute the cve for given diffraction data, mud and wavelength
178-
179- Parameters
180- ----------
181- diffraction_data Diffraction_object
182- the diffraction pattern
183- mud float
184- the mu*D of the diffraction object, where D is the diameter of the circle
185- wavelength float
186- the wavelength of the diffraction object
187-
188- Returns
189- -------
190- the diffraction object with cve curves
191-
192- it is computed as follows:
193- We first resample data and absorption correction to a more reasonable grid,
194- then calculate corresponding cve for the given mud in the resample grid
195- (since the same mu*D yields the same cve, we can assume that D/2=1, so mu=mud/2),
196- and finally interpolate cve to the original grid in diffraction_data.
188+ compute cve for the given mud on a global grid using the brute-force method
189+ assume mu=mud/2, given that the same mu*D yields the same cve and D/2=1
197190 """
198191
199192 mu_sample_invmm = mud / 2
@@ -208,9 +201,85 @@ def compute_cve(diffraction_data, mud, wavelength):
208201 muls = np .array (muls ) / abs_correction .total_points_in_grid
209202 cve = 1 / muls
210203
204+ abdo = Diffraction_object (wavelength = diffraction_data .wavelength )
205+ abdo .insert_scattering_quantity (
206+ TTH_GRID ,
207+ cve ,
208+ "tth" ,
209+ metadata = diffraction_data .metadata ,
210+ name = f"absorption correction, cve, for { diffraction_data .name } " ,
211+ wavelength = diffraction_data .wavelength ,
212+ scat_quantity = "cve" ,
213+ )
214+ return abdo
215+
216+
217+ def _cve_polynomial_interpolation (diffraction_data , mud ):
218+ """
219+ compute cve using polynomial interpolation method, raise an error if mu*D is out of the range (0.5 to 6)
220+ """
221+
222+ if mud > 6 or mud < 0.5 :
223+ raise ValueError (
224+ f"mu*D is out of the acceptable range (0.5 to 6) for polynomial interpolation. "
225+ f"Please rerun with a value within this range or specifying another method from { * CVE_METHODS , } ."
226+ )
227+ coeff_a , coeff_b , coeff_c , coeff_d , coeff_e = [
228+ interpolation_function (mud ) for interpolation_function in INTERPOLATION_FUNCTIONS
229+ ]
230+ muls = np .array (coeff_a * MULS ** 4 + coeff_b * MULS ** 3 + coeff_c * MULS ** 2 + coeff_d * MULS + coeff_e )
231+ cve = 1 / muls
232+
233+ abdo = Diffraction_object (wavelength = diffraction_data .wavelength )
234+ abdo .insert_scattering_quantity (
235+ TTH_GRID ,
236+ cve ,
237+ "tth" ,
238+ metadata = diffraction_data .metadata ,
239+ name = f"absorption correction, cve, for { diffraction_data .name } " ,
240+ wavelength = diffraction_data .wavelength ,
241+ scat_quantity = "cve" ,
242+ )
243+ return abdo
244+
245+
246+ def _cve_method (method ):
247+ """
248+ retrieve the cve computation function for the given method
249+ """
250+ methods = {
251+ "brute_force" : _cve_brute_force ,
252+ "polynomial_interpolation" : _cve_polynomial_interpolation ,
253+ }
254+ if method not in CVE_METHODS :
255+ raise ValueError (f"Unknown method: { method } . Allowed methods are { * CVE_METHODS , } ." )
256+ return methods [method ]
257+
258+
259+ def compute_cve (diffraction_data , mud , method = "polynomial_interpolation" ):
260+ """
261+ compute and interpolate the cve for the given diffraction data and mud using the selected method
262+ Parameters
263+ ----------
264+ diffraction_data Diffraction_object
265+ the diffraction pattern
266+ mud float
267+ the mu*D of the diffraction object, where D is the diameter of the circle
268+ method str
269+ the method used to calculate cve
270+
271+ Returns
272+ -------
273+ the diffraction object with cve curves
274+ """
275+
276+ cve_function = _cve_method (method )
277+ abdo_on_global_tth = cve_function (diffraction_data , mud )
278+ global_tth = abdo_on_global_tth .on_tth [0 ]
279+ cve_on_global_tth = abdo_on_global_tth .on_tth [1 ]
211280 orig_grid = diffraction_data .on_tth [0 ]
212- newcve = np .interp (orig_grid , TTH_GRID , cve )
213- abdo = Diffraction_object (wavelength = wavelength )
281+ newcve = np .interp (orig_grid , global_tth , cve_on_global_tth )
282+ abdo = Diffraction_object (wavelength = diffraction_data . wavelength )
214283 abdo .insert_scattering_quantity (
215284 orig_grid ,
216285 newcve ,
0 commit comments