Skip to content

Commit 1dec001

Browse files
authored
Merge pull request #92 from yucongalicechen/compute_cve
compute_cve
2 parents 224bf0f + 06daa46 commit 1dec001

File tree

6 files changed

+190
-196
lines changed

6 files changed

+190
-196
lines changed

src/diffpy/labpdfproc/fast_cve.py

Lines changed: 0 additions & 81 deletions
This file was deleted.

src/diffpy/labpdfproc/functions.py

Lines changed: 95 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,23 @@
11
import math
2+
from pathlib import Path
23

34
import numpy as np
5+
import pandas as pd
6+
from scipy.interpolate import interp1d
47

58
from diffpy.utils.scattering_objects.diffraction_objects import Diffraction_object
69

710
RADIUS_MM = 1
811
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]
1021

1122

1223
class 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

217286
def apply_corr(diffraction_pattern, absorption_correction):

0 commit comments

Comments
 (0)