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 :
@@ -162,28 +173,10 @@ def get_path_length(self, grid_point, angle):
162
173
return total_distance , primary_distance , secondary_distance
163
174
164
175
165
- def compute_cve (diffraction_data , mud , wavelength ):
176
+ def _cve_brute_force (diffraction_data , mud ):
166
177
"""
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
187
180
"""
188
181
189
182
mu_sample_invmm = mud / 2
@@ -198,10 +191,86 @@ def compute_cve(diffraction_data, mud, wavelength):
198
191
muls = np .array (muls ) / abs_correction .total_points_in_grid
199
192
cve = 1 / muls
200
193
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 ]
201
270
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 (
205
274
orig_grid ,
206
275
newcve ,
207
276
"tth" ,
@@ -211,7 +280,7 @@ def compute_cve(diffraction_data, mud, wavelength):
211
280
scat_quantity = "cve" ,
212
281
)
213
282
214
- return abdo
283
+ return cve_do
215
284
216
285
217
286
def apply_corr (diffraction_pattern , absorption_correction ):
0 commit comments