Skip to content

Commit f4dd476

Browse files
feat: theoretical estimation of muD: functions and gui interface
1 parent 9618ab0 commit f4dd476

File tree

4 files changed

+187
-24
lines changed

4 files changed

+187
-24
lines changed

news/muD-theoretical.rst

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
**Added:**
2+
3+
* Functionalities to estimate mu*D theoretically.
4+
5+
**Changed:**
6+
7+
* <news item>
8+
9+
**Deprecated:**
10+
11+
* <news item>
12+
13+
**Removed:**
14+
15+
* <news item>
16+
17+
**Fixed:**
18+
19+
* <news item>
20+
21+
**Security:**
22+
23+
* <news item>

src/diffpy/labpdfproc/labpdfprocapp.py

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,11 @@ def _define_arguments():
152152
def _add_mud_selection_group(p, is_gui=False):
153153
"""Current Options:
154154
1. Manually enter muD (`--mud`).
155-
2. Estimate muD from a z-scan file (`-z` or `--z-scan-file`).
155+
2. Estimate from a z-scan file (`-z` or `--z-scan-file`).
156+
3. Estimate theoretically based on sample mass density
157+
(`-td` or `--theoretical-from-density`).
158+
4. Estimate theoretically based on packing fraction
159+
(`-tp` or `--theoretical-from-packing`).
156160
"""
157161
g = p.add_argument_group("Options for setting mu*D value (Required)")
158162
g = g.add_mutually_exclusive_group(required=True)
@@ -165,10 +169,39 @@ def _add_mud_selection_group(p, is_gui=False):
165169
g.add_argument(
166170
"-z",
167171
"--z-scan-file",
168-
help="Provide the path to the z-scan file to be loaded "
169-
"to determine the mu*D value.",
172+
help=(
173+
"Estimate mu*D experimentally from a z-scan file. "
174+
"Specify the path to the file "
175+
"used to compute the mu*D value."
176+
),
170177
**({"widget": "FileChooser"} if is_gui else {}),
171178
)
179+
g.add_argument(
180+
"-td",
181+
"--theoretical-from-density",
182+
help=(
183+
"Estimate mu*D theoretically using sample mass density. "
184+
"Specify the sample composition (chemical formula), "
185+
"incident x-ray energy in keV, "
186+
"and sample mass density in g/cm^3 "
187+
"in that exact order "
188+
"and separated by commas with no whitespaces "
189+
"(e.g., 'ZrO2,2,1.2')."
190+
),
191+
)
192+
g.add_argument(
193+
"-tp",
194+
"--theoretical-from-packing",
195+
help=(
196+
"Estimate mu*D theoretically using packing fraction. "
197+
"Specify the sample composition (chemical formula), "
198+
"incident x-ray energy in keV, "
199+
"and packing fraction (0 to 1) "
200+
"in that exact order "
201+
"and separated by commas with no whitespaces "
202+
"(e.g., 'ZrO2,2,0.5')."
203+
),
204+
)
172205
return p
173206

174207

@@ -186,7 +219,7 @@ def get_args(override_cli_inputs=None):
186219
return args
187220

188221

189-
@Gooey(required_cols=1, optional_cols=1, program_name="Labpdfproc GUI")
222+
@Gooey(required_cols=1, optional_cols=2, program_name="labpdfproc GUI")
190223
def gooey_parser():
191224
p = GooeyParser()
192225
p = _add_mud_selection_group(p, is_gui=True)

src/diffpy/labpdfproc/tools.py

Lines changed: 72 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from diffpy.utils.tools import (
1010
_load_config,
1111
check_and_build_global_config,
12+
compute_mu_using_xraydb,
1213
compute_mud,
1314
get_package_info,
1415
get_user_info,
@@ -31,14 +32,19 @@
3132
}
3233
known_sources = [key for key in WAVELENGTHS.keys()]
3334

34-
# Exclude wavelength from metadata to prevent duplication,
35-
# as the dump function in diffpy.utils writes it explicitly.
35+
# Exclude wavelength to avoid duplication,
36+
# as it's written explicitly by diffpy.utils dump function.
37+
# Exclude "theoretical_from_density" and "theoretical_from_packing"
38+
# as they are only used for theoretical mu*D estimation
39+
# and will be written into separate arguments for clarity.
3640
METADATA_KEYS_TO_EXCLUDE = [
3741
"output_correction",
3842
"force_overwrite",
3943
"input",
4044
"input_paths",
4145
"wavelength",
46+
"theoretical_from_density",
47+
"theoretical_from_packing",
4248
]
4349

4450

@@ -298,19 +304,8 @@ def set_xtype(args):
298304
return args
299305

300306

301-
def _estimate_mud_from_zscan(args):
302-
"""Compute mu*D based on the given z-scan file.
303-
304-
Parameters
305-
----------
306-
args : argparse.Namespace
307-
The arguments from the parser.
308-
309-
Returns
310-
-------
311-
args : argparse.Namespace
312-
The updated arguments with mu*D.
313-
"""
307+
def _set_mud_from_zscan(args):
308+
"""Experimental estimation of mu*D from a z-scan file."""
314309
filepath = Path(args.z_scan_file).resolve()
315310
if not filepath.is_file():
316311
raise FileNotFoundError(
@@ -322,10 +317,64 @@ def _estimate_mud_from_zscan(args):
322317
return args
323318

324319

320+
def _parse_theoretical_input(input_str):
321+
"""Helper function to parse and validate the input string."""
322+
parts = input_str.split(",")
323+
if len(parts) != 3:
324+
raise ValueError(
325+
f"Invalid mu*D input '{input_str}'. "
326+
"Expected format is 'sample composition, energy, "
327+
"sample mass density or packing fraction' "
328+
"with no whitespaces (e.g., 'ZrO2,2,0.8').",
329+
)
330+
sample_composition = parts[0]
331+
energy = float(parts[1])
332+
mass_density_or_packing_fraction = float(parts[2])
333+
return sample_composition, energy, mass_density_or_packing_fraction
334+
335+
336+
def _set_theoretical_mud_from_density(args):
337+
"""Theoretical estimation of mu*D from
338+
sample composition, energy, and sample mass density."""
339+
sample_composition, energy, sample_mass_density = _parse_theoretical_input(
340+
args.theoretical_from_density
341+
)
342+
args.sample_composition = sample_composition
343+
args.energy = energy
344+
args.sample_mass_density = sample_mass_density
345+
args.mud = compute_mu_using_xraydb(
346+
args.sample_composition,
347+
args.energy,
348+
sample_mass_density=args.sample_mass_density,
349+
)
350+
return args
351+
352+
353+
def _set_theoretical_mud_from_packing(args):
354+
"""Theoretical estimation of mu*D from
355+
sample composition, energy, and packing fraction."""
356+
sample_composition, energy, packing_fraction = _parse_theoretical_input(
357+
args.theoretical_from_packing
358+
)
359+
args.sample_composition = sample_composition
360+
args.energy = energy
361+
args.packing_fraction = packing_fraction
362+
args.mud = compute_mu_using_xraydb(
363+
args.sample_composition,
364+
args.energy,
365+
packing_fraction=args.packing_fraction,
366+
)
367+
return args
368+
369+
325370
def set_mud(args):
326-
"""Compute and set mu*D based on different options.
327-
Current options include manually entering a value,
328-
or estimating from a z-scan file.
371+
"""Compute and set mu*D based on the selected method.
372+
373+
Options include:
374+
1. Manually entering a value.
375+
2. Estimating from a z-scan file.
376+
3. Estimating theoretically based on sample mass density.
377+
4. Estimating theoretically based on packing fraction.
329378
330379
Parameters
331380
----------
@@ -338,7 +387,11 @@ def set_mud(args):
338387
The updated arguments with mu*D.
339388
"""
340389
if args.z_scan_file:
341-
return _estimate_mud_from_zscan(args)
390+
return _set_mud_from_zscan(args)
391+
elif args.theoretical_from_density:
392+
return _set_theoretical_mud_from_density(args)
393+
elif args.theoretical_from_packing:
394+
return _set_theoretical_mud_from_packing(args)
342395
return args
343396

344397

tests/test_tools.py

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,12 @@ def test_set_xtype_bad():
460460
(["--mud", "2.5"], 2.5),
461461
# C2: user provides a z-scan file, expect to estimate through the file
462462
(["--z-scan-file", "test_dir/testfile.xy"], 3),
463+
# C3: user specifies sample composition, energy,
464+
# and sample mass density, expect to estimate theoretically
465+
(["--theoretical-from-density", "ZrO2,17.45,1.2"], 1.49),
466+
# C4: user specifies sample composition, energy, and packing fraction
467+
# expect to estimate theoretically
468+
# (["--theoretical-from-packing", "ZrO2,17.45,0.3"], 1.49),
463469
],
464470
)
465471
def test_set_mud(user_filesystem, inputs, expected_mud):
@@ -483,6 +489,54 @@ def test_set_mud(user_filesystem, inputs, expected_mud):
483489
"Cannot find invalid file. Please specify a valid file path.",
484490
],
485491
),
492+
# C2.1: user provides fewer than three input values
493+
# expect ValueError with a message indicating the correct format
494+
(
495+
["--theoretical-from-density", "ZrO2,0.5"],
496+
[
497+
ValueError,
498+
"Invalid mu*D input 'ZrO2,0.5'. "
499+
"Expected format is 'sample composition, energy, "
500+
"sample mass density or packing fraction' "
501+
"with no whitespaces (e.g., 'ZrO2,2,0.8').",
502+
],
503+
),
504+
# C2.1: user provides fewer than three input values
505+
# expect ValueError with a message indicating the correct format
506+
(
507+
["--theoretical-from-packing", "ZrO2,0.5"],
508+
[
509+
ValueError,
510+
"Invalid mu*D input 'ZrO2,0.5'. "
511+
"Expected format is 'sample composition, energy, "
512+
"sample mass density or packing fraction' "
513+
"with no whitespaces (e.g., 'ZrO2,2,0.8').",
514+
],
515+
),
516+
# C3.1: user provides more than 3 input values
517+
# expect ValueError with a message indicating the correct format
518+
(
519+
["--theoretical-from-density", "ZrO2,1.5,1.5,0.5"],
520+
[
521+
ValueError,
522+
"Invalid mu*D input 'ZrO2,1.5,1.5,0.5'. "
523+
"Expected format is 'sample composition, energy, "
524+
"sample mass density or packing fraction' "
525+
"with no whitespaces (e.g., 'ZrO2,2,0.8').",
526+
],
527+
),
528+
# C3.2: user provides more than 3 input values
529+
# expect ValueError with a message indicating the correct format
530+
(
531+
["--theoretical-from-packing", "ZrO2,1.5,1.5,0.5"],
532+
[
533+
ValueError,
534+
"Invalid mu*D input 'ZrO2,1.5,1.5,0.5'. "
535+
"Expected format is 'sample composition, energy, "
536+
"sample mass density or packing fraction' "
537+
"with no whitespaces (e.g., 'ZrO2,2,0.8').",
538+
],
539+
),
486540
],
487541
)
488542
def test_set_mud_bad(user_filesystem, inputs, expected):
@@ -491,7 +545,7 @@ def test_set_mud_bad(user_filesystem, inputs, expected):
491545
os.chdir(cwd)
492546
cli_inputs = ["data.xy"] + inputs
493547
actual_args = get_args(cli_inputs)
494-
with pytest.raises(expected_error, match=expected_error_msg):
548+
with pytest.raises(expected_error, match=re.escape(expected_error_msg)):
495549
actual_args = set_mud(actual_args)
496550

497551

0 commit comments

Comments
 (0)