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 :
@@ -162,28 +173,10 @@ def get_path_length(self, grid_point, angle):
162173 return total_distance , primary_distance , secondary_distance
163174
164175
165- def compute_cve (diffraction_data , mud , wavelength ):
176+ def _cve_brute_force (diffraction_data , mud ):
166177 """
167- compute the cve for given diffraction data, mud and wavelength
168-
169- Parameters
170- ----------
171- diffraction_data Diffraction_object
172- the diffraction pattern
173- mud float
174- the mu*D of the diffraction object, where D is the diameter of the circle
175- wavelength float
176- the wavelength of the diffraction object
177-
178- Returns
179- -------
180- the diffraction object with cve curves
181-
182- it is computed as follows:
183- We first resample data and absorption correction to a more reasonable grid,
184- then calculate corresponding cve for the given mud in the resample grid
185- (since the same mu*D yields the same cve, we can assume that D/2=1, so mu=mud/2),
186- and finally interpolate cve to the original grid in diffraction_data.
178+ compute cve for the given mud on a global grid using the brute-force method
179+ assume mu=mud/2, given that the same mu*D yields the same cve and D/2=1
187180 """
188181
189182 mu_sample_invmm = mud / 2
@@ -198,10 +191,86 @@ def compute_cve(diffraction_data, mud, wavelength):
198191 muls = np .array (muls ) / abs_correction .total_points_in_grid
199192 cve = 1 / muls
200193
194+ cve_do = Diffraction_object (wavelength = diffraction_data .wavelength )
195+ cve_do .insert_scattering_quantity (
196+ TTH_GRID ,
197+ cve ,
198+ "tth" ,
199+ metadata = diffraction_data .metadata ,
200+ name = f"absorption correction, cve, for { diffraction_data .name } " ,
201+ wavelength = diffraction_data .wavelength ,
202+ scat_quantity = "cve" ,
203+ )
204+ return cve_do
205+
206+
207+ def _cve_polynomial_interpolation (diffraction_data , mud ):
208+ """
209+ compute cve using polynomial interpolation method, raise an error if mu*D is out of the range (0.5 to 6)
210+ """
211+
212+ if mud > 6 or mud < 0.5 :
213+ raise ValueError (
214+ f"mu*D is out of the acceptable range (0.5 to 6) for polynomial interpolation. "
215+ f"Please rerun with a value within this range or specifying another method from { * CVE_METHODS , } ."
216+ )
217+ coeff_a , coeff_b , coeff_c , coeff_d , coeff_e = [
218+ interpolation_function (mud ) for interpolation_function in INTERPOLATION_FUNCTIONS
219+ ]
220+ muls = np .array (coeff_a * MULS ** 4 + coeff_b * MULS ** 3 + coeff_c * MULS ** 2 + coeff_d * MULS + coeff_e )
221+ cve = 1 / muls
222+
223+ cve_do = Diffraction_object (wavelength = diffraction_data .wavelength )
224+ cve_do .insert_scattering_quantity (
225+ TTH_GRID ,
226+ cve ,
227+ "tth" ,
228+ metadata = diffraction_data .metadata ,
229+ name = f"absorption correction, cve, for { diffraction_data .name } " ,
230+ wavelength = diffraction_data .wavelength ,
231+ scat_quantity = "cve" ,
232+ )
233+ return cve_do
234+
235+
236+ def _cve_method (method ):
237+ """
238+ retrieve the cve computation function for the given method
239+ """
240+ methods = {
241+ "brute_force" : _cve_brute_force ,
242+ "polynomial_interpolation" : _cve_polynomial_interpolation ,
243+ }
244+ if method not in CVE_METHODS :
245+ raise ValueError (f"Unknown method: { method } . Allowed methods are { * CVE_METHODS , } ." )
246+ return methods [method ]
247+
248+
249+ def compute_cve (diffraction_data , mud , method = "polynomial_interpolation" ):
250+ f"""
251+ compute and interpolate the cve for the given diffraction data and mud using the selected method
252+ Parameters
253+ ----------
254+ diffraction_data Diffraction_object
255+ the diffraction pattern
256+ mud float
257+ the mu*D of the diffraction object, where D is the diameter of the circle
258+ method str
259+ the method used to calculate cve, must be one of { * CVE_METHODS , }
260+
261+ Returns
262+ -------
263+ the diffraction object with cve curves
264+ """
265+
266+ cve_function = _cve_method (method )
267+ abdo_on_global_tth = cve_function (diffraction_data , mud )
268+ global_tth = abdo_on_global_tth .on_tth [0 ]
269+ cve_on_global_tth = abdo_on_global_tth .on_tth [1 ]
201270 orig_grid = diffraction_data .on_tth [0 ]
202- newcve = np .interp (orig_grid , TTH_GRID , cve )
203- abdo = Diffraction_object (wavelength = wavelength )
204- abdo .insert_scattering_quantity (
271+ newcve = np .interp (orig_grid , global_tth , cve_on_global_tth )
272+ cve_do = Diffraction_object (wavelength = diffraction_data . wavelength )
273+ cve_do .insert_scattering_quantity (
205274 orig_grid ,
206275 newcve ,
207276 "tth" ,
@@ -211,7 +280,7 @@ def compute_cve(diffraction_data, mud, wavelength):
211280 scat_quantity = "cve" ,
212281 )
213282
214- return abdo
283+ return cve_do
215284
216285
217286def apply_corr (diffraction_pattern , absorption_correction ):
0 commit comments