1
1
import math
2
+ from pathlib import Path
2
3
3
4
import numpy as np
5
+ import pandas as pd
6
+ from scipy .interpolate import interp1d
4
7
5
8
from diffpy .utils .scattering_objects .diffraction_objects import Diffraction_object
6
9
7
10
RADIUS_MM = 1
8
11
N_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 ]
10
21
11
22
12
23
class Gridded_circle :
@@ -172,28 +183,10 @@ def get_path_length(self, grid_point, angle):
172
183
return total_distance , primary_distance , secondary_distance
173
184
174
185
175
- def compute_cve (diffraction_data , mud , wavelength ):
186
+ def _cve_brute_force (diffraction_data , mud ):
176
187
"""
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
197
190
"""
198
191
199
192
mu_sample_invmm = mud / 2
@@ -208,9 +201,85 @@ def compute_cve(diffraction_data, mud, wavelength):
208
201
muls = np .array (muls ) / abs_correction .total_points_in_grid
209
202
cve = 1 / muls
210
203
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 ]
211
280
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 )
214
283
abdo .insert_scattering_quantity (
215
284
orig_grid ,
216
285
newcve ,
0 commit comments