Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 0 additions & 81 deletions src/diffpy/labpdfproc/fast_cve.py

This file was deleted.

121 changes: 95 additions & 26 deletions src/diffpy/labpdfproc/functions.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,23 @@
import math
from pathlib import Path

import numpy as np
import pandas as pd
from scipy.interpolate import interp1d

from diffpy.utils.scattering_objects.diffraction_objects import Diffraction_object

RADIUS_MM = 1
N_POINTS_ON_DIAMETER = 300
TTH_GRID = np.arange(1, 141, 1)
TTH_GRID = np.arange(1, 180.1, 0.1)
CVE_METHODS = ["brute_force", "polynomial_interpolation"]

# pre-computed datasets for polynomial interpolation (fast calculation)
MUD_LIST = [0.5, 1, 2, 3, 4, 5, 6]
CWD = Path(__file__).parent.resolve()
MULS = np.loadtxt(CWD / "data" / "inverse_cve.xy")
COEFFICIENT_LIST = np.array(pd.read_csv(CWD / "data" / "coefficient_list.csv", header=None))
INTERPOLATION_FUNCTIONS = [interp1d(MUD_LIST, coefficients, kind="quadratic") for coefficients in COEFFICIENT_LIST]


class Gridded_circle:
Expand Down Expand Up @@ -172,28 +183,10 @@ def get_path_length(self, grid_point, angle):
return total_distance, primary_distance, secondary_distance


def compute_cve(diffraction_data, mud, wavelength):
def _cve_brute_force(diffraction_data, mud):
"""
compute the cve for given diffraction data, mud and wavelength

Parameters
----------
diffraction_data Diffraction_object
the diffraction pattern
mud float
the mu*D of the diffraction object, where D is the diameter of the circle
wavelength float
the wavelength of the diffraction object

Returns
-------
the diffraction object with cve curves

it is computed as follows:
We first resample data and absorption correction to a more reasonable grid,
then calculate corresponding cve for the given mud in the resample grid
(since the same mu*D yields the same cve, we can assume that D/2=1, so mu=mud/2),
and finally interpolate cve to the original grid in diffraction_data.
compute cve for the given mud on a global grid using the brute-force method
assume mu=mud/2, given that the same mu*D yields the same cve and D/2=1
"""

mu_sample_invmm = mud / 2
Expand All @@ -208,10 +201,86 @@ def compute_cve(diffraction_data, mud, wavelength):
muls = np.array(muls) / abs_correction.total_points_in_grid
cve = 1 / muls

cve_do = Diffraction_object(wavelength=diffraction_data.wavelength)
cve_do.insert_scattering_quantity(
TTH_GRID,
cve,
"tth",
metadata=diffraction_data.metadata,
name=f"absorption correction, cve, for {diffraction_data.name}",
wavelength=diffraction_data.wavelength,
scat_quantity="cve",
)
return cve_do


def _cve_polynomial_interpolation(diffraction_data, mud):
"""
compute cve using polynomial interpolation method, raise an error if mu*D is out of the range (0.5 to 6)
"""

if mud > 6 or mud < 0.5:
raise ValueError(
f"mu*D is out of the acceptable range (0.5 to 6) for polynomial interpolation. "
f"Please rerun with a value within this range or specifying another method from {* CVE_METHODS, }."
)
coeff_a, coeff_b, coeff_c, coeff_d, coeff_e = [
interpolation_function(mud) for interpolation_function in INTERPOLATION_FUNCTIONS
]
muls = np.array(coeff_a * MULS**4 + coeff_b * MULS**3 + coeff_c * MULS**2 + coeff_d * MULS + coeff_e)
cve = 1 / muls

cve_do = Diffraction_object(wavelength=diffraction_data.wavelength)
cve_do.insert_scattering_quantity(
TTH_GRID,
cve,
"tth",
metadata=diffraction_data.metadata,
name=f"absorption correction, cve, for {diffraction_data.name}",
wavelength=diffraction_data.wavelength,
scat_quantity="cve",
)
return cve_do


def _cve_method(method):
"""
retrieve the cve computation function for the given method
"""
methods = {
"brute_force": _cve_brute_force,
"polynomial_interpolation": _cve_polynomial_interpolation,
}
if method not in CVE_METHODS:
raise ValueError(f"Unknown method: {method}. Allowed methods are {*CVE_METHODS, }.")
return methods[method]


def compute_cve(diffraction_data, mud, method="polynomial_interpolation"):
f"""
compute and interpolate the cve for the given diffraction data and mud using the selected method
Parameters
----------
diffraction_data Diffraction_object
the diffraction pattern
mud float
the mu*D of the diffraction object, where D is the diameter of the circle
method str
the method used to calculate cve, must be one of {* CVE_METHODS, }

Returns
-------
the diffraction object with cve curves
"""

cve_function = _cve_method(method)
abdo_on_global_tth = cve_function(diffraction_data, mud)
global_tth = abdo_on_global_tth.on_tth[0]
cve_on_global_tth = abdo_on_global_tth.on_tth[1]
orig_grid = diffraction_data.on_tth[0]
newcve = np.interp(orig_grid, TTH_GRID, cve)
abdo = Diffraction_object(wavelength=wavelength)
abdo.insert_scattering_quantity(
newcve = np.interp(orig_grid, global_tth, cve_on_global_tth)
cve_do = Diffraction_object(wavelength=diffraction_data.wavelength)
cve_do.insert_scattering_quantity(
orig_grid,
newcve,
"tth",
Expand All @@ -221,7 +290,7 @@ def compute_cve(diffraction_data, mud, wavelength):
scat_quantity="cve",
)

return abdo
return cve_do


def apply_corr(diffraction_pattern, absorption_correction):
Expand Down
11 changes: 9 additions & 2 deletions src/diffpy/labpdfproc/labpdfprocapp.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import sys
from argparse import ArgumentParser

from diffpy.labpdfproc.functions import apply_corr, compute_cve
from diffpy.labpdfproc.functions import CVE_METHODS, apply_corr, compute_cve
from diffpy.labpdfproc.tools import known_sources, load_metadata, preprocessing_args
from diffpy.utils.parsers.loaddata import loadData
from diffpy.utils.scattering_objects.diffraction_objects import XQUANTITIES, Diffraction_object
Expand Down Expand Up @@ -72,6 +72,13 @@ def get_args(override_cli_inputs=None):
action="store_true",
help="Outputs will not overwrite existing file unless --force is specified.",
)
p.add_argument(
"-m",
"--method",
help=f"The method for computing absorption correction. Allowed methods: {*CVE_METHODS, }. "
f"Default method is polynomial interpolation if not specified. ",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am worried about the indentation of this line. I am not sure if it will break things or not, but but it would be better indented to line up with the line above in any case.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

black seems to automatically adjust the indentation for all help messages and aligns them at help. I can try to add a paranthesis around the messages to make sure they line up with the lines above, if that's helpful?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've fixed the indentation issue in the latest commit. There are some conflicts with labpdfprocapp.py, but my local branch shows that the code is up-to-date when I try to merge from main to resolve conflicts. I think we can accept the edits for labpdfprocapp.py in this PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, we have to fix it. Did you commit to main by mistake? That could cause this behavior

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I managed to resolve conflicts. I think it just needs me to merge from main again.

default="polynomial_interpolation",
)
p.add_argument(
"-u",
"--user-metadata",
Expand Down Expand Up @@ -134,7 +141,7 @@ def main():
metadata=load_metadata(args, filepath),
)

absorption_correction = compute_cve(input_pattern, args.mud, args.wavelength)
absorption_correction = compute_cve(input_pattern, args.mud, args.method)
corrected_data = apply_corr(input_pattern, absorption_correction)
corrected_data.name = f"Absorption corrected input_data: {input_pattern.name}"
corrected_data.dump(f"{outfile}", xtype="tth")
Expand Down
48 changes: 0 additions & 48 deletions src/diffpy/labpdfproc/tests/test_fast_cve.py

This file was deleted.

6 changes: 3 additions & 3 deletions src/diffpy/labpdfproc/tests/test_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,14 @@ def test_compute_cve(mocker):
mocker.patch("diffpy.labpdfproc.functions.TTH_GRID", xarray)
mocker.patch("numpy.interp", return_value=expected_cve)
input_pattern = _instantiate_test_do(xarray, yarray)
actual_abdo = compute_cve(input_pattern, mud=1, wavelength=1.54)
expected_abdo = _instantiate_test_do(
actual_cve_do = compute_cve(input_pattern, mud=1)
expected_cve_do = _instantiate_test_do(
xarray,
expected_cve,
name="absorption correction, cve, for test",
scat_quantity="cve",
)
assert actual_abdo == expected_abdo
assert actual_cve_do == expected_cve_do


def test_apply_corr(mocker):
Expand Down
1 change: 1 addition & 0 deletions src/diffpy/labpdfproc/tests/test_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,7 @@ def test_load_metadata(mocker, user_filesystem):
"wavelength": 0.71,
"output_directory": str(Path.cwd().resolve()),
"xtype": "tth",
"method": "polynomial_interpolation",
"key": "value",
"username": "cli_username",
"email": "cli@email.com",
Expand Down