Skip to content

Commit 53c97c6

Browse files
committed
tools.py
1 parent 3c22349 commit 53c97c6

1 file changed

Lines changed: 94 additions & 71 deletions

File tree

src/diffpy/labpdfproc/tools.py

Lines changed: 94 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,10 @@
3939
# and will be written into separate arguments for clarity.
4040
METADATA_KEYS_TO_EXCLUDE = [
4141
"output_correction",
42-
"force_overwrite",
4342
"input",
4443
"input_paths",
45-
"wavelength",
46-
"theoretical_from_density",
47-
"theoretical_from_packing",
48-
"subcommand",
44+
"force",
45+
"energy",
4946
]
5047

5148

@@ -166,8 +163,52 @@ def set_input_lists(args):
166163
return args
167164

168165

166+
def normalize_wavelength(args):
167+
"""Normalize args.wavelength to a float.
168+
169+
If args.wavelength is:
170+
- None: return args unchanged
171+
- float-like: convert to float
172+
- string: look up corresponding value in WAVELENGTHS (case-insensitive)
173+
174+
Parameters
175+
----------
176+
args : argparse.Namespace
177+
The arguments from the parser.
178+
179+
Returns
180+
-------
181+
args : argparse.Namespace
182+
The updated arguments with args.wavelength.
183+
184+
Raises
185+
------
186+
ValueError
187+
If a string wavelength is not a known source.
188+
"""
189+
if args.wavelength is None:
190+
return args
191+
try:
192+
args.wavelength = float(args.wavelength)
193+
return args
194+
except (TypeError, ValueError):
195+
pass
196+
key = str(args.wavelength).strip()
197+
matched = next(
198+
(k for k in WAVELENGTHS if k.lower() == key.lower()),
199+
None,
200+
)
201+
if matched is None:
202+
raise ValueError(
203+
f"Anode type '{args.wavelength}' not recognized. "
204+
f"Please rerun specifying an anode type from {*known_sources, }."
205+
)
206+
args.wavelength = WAVELENGTHS[matched]
207+
return args
208+
209+
169210
def load_wavelength_from_config_file(args):
170-
"""Load wavelength and anode type from config files.
211+
"""Load wavelength from config files.
171212
172213
It prioritizes values in the following order:
173214
1. cli inputs, 2. local config file, 3. global config file.
@@ -184,12 +225,8 @@ def load_wavelength_from_config_file(args):
184225
"""
185226
global_config = _load_config(Path().home() / "diffpyconfig.json")
186227
local_config = _load_config(Path().cwd() / "diffpyconfig.json")
187-
local_has_data = local_config and (
188-
"wavelength" in local_config or "anode_type" in local_config
189-
)
190-
global_has_data = global_config and (
191-
"wavelength" in global_config or "anode_type" in global_config
192-
)
228+
local_has_data = local_config and "wavelength" in local_config
229+
global_has_data = global_config and "wavelength" in global_config
193230
if not local_has_data and not global_has_data:
194231
print(
195232
"No configuration file was found containing information "
@@ -202,76 +239,54 @@ def load_wavelength_from_config_file(args):
202239
"For more information, please refer to www.diffpy.org/"
203240
"diffpy.labpdfproc/examples/toolsexample.html"
204241
)
205-
206-
if args.wavelength or args.anode_type:
207-
return args
242+
if args.wavelength is not None:
243+
return normalize_wavelength(args)
208244
config = local_config if local_has_data else global_config
209245
if config:
210-
args.wavelength = args.wavelength or config.get("wavelength")
211-
args.anode_type = args.anode_type or config.get("anode_type")
246+
args.wavelength = config.get("wavelength")
247+
return normalize_wavelength(args)
212248
return args
213249

214250

215251
def set_wavelength(args):
216-
"""Set the wavelength based on the given anode_type or wavelength.
252+
"""Set the wavelength based on args.wavelength.
217253
218-
First checks from args. If neither is provided,
219-
it attempts to load from local and then global config file.
254+
args.wavelength may be:
255+
- None
256+
- a number (explicit wavelength in Å)
257+
- a string (X-ray source name)
258+
259+
If a string is provided, it must match a key in WAVELENGTHS.
220260
221261
Parameters
222262
----------
223263
args : argparse.Namespace
224-
The arguments from the parser.
225264
226265
Raises
227266
------
228267
ValueError
229-
Raised if:
230-
(1) neither wavelength or anode type is provided
231-
and xtype is not the two-theta grid,
232-
(2) both are provided,
233-
(3) anode_type is not one of the known sources,
234-
(4) wavelength is non-positive.
268+
If wavelength is required but missing,
269+
if a string wavelength is not a known source,
270+
or if a numeric wavelength is non-positive.
235271
236272
Returns
237273
-------
238274
args : argparse.Namespace
239-
The updated arguments with the wavelength.
275+
Updated arguments with args.wavelength as a float.
240276
"""
241-
args = load_wavelength_from_config_file(args)
242-
if args.wavelength is None and args.anode_type is None:
277+
args = normalize_wavelength(args)
278+
if args.wavelength is None:
243279
if args.xtype not in ANGLEQUANTITIES:
244280
raise ValueError(
245281
f"Please provide a wavelength or anode type "
246282
f"because the independent variable axis is not on two-theta. "
247283
f"Allowed anode types are {*known_sources, }."
248284
)
249-
elif args.wavelength is not None and args.anode_type is not None:
250-
raise ValueError(
251-
f"Please provide either a wavelength or an anode type, not both. "
252-
f"Allowed anode types are {*known_sources, }."
253-
)
254-
elif args.anode_type is not None:
255-
matched_anode_type = next(
256-
(
257-
key
258-
for key in WAVELENGTHS
259-
if key.lower() == args.anode_type.lower()
260-
),
261-
None,
262-
)
263-
if matched_anode_type is None:
264-
raise ValueError(
265-
f"Anode type '{args.anode_type}' not recognized. "
266-
f"Please rerun specifying an anode_type "
267-
f"from {*known_sources, }."
268-
)
269-
args.anode_type = matched_anode_type
270-
args.wavelength = WAVELENGTHS[args.anode_type]
271-
elif args.wavelength is not None and args.wavelength <= 0:
285+
return args
286+
if args.wavelength <= 0:
272287
raise ValueError(
273288
f"Wavelength = {args.wavelength} is not valid. "
274-
"Please rerun specifying a known anode_type "
289+
"Please rerun specifying a known anode type "
275290
"or a positive wavelength."
276291
)
277292
return args
@@ -336,16 +351,18 @@ def _parse_theoretical_input(input_str):
336351
def _set_theoretical_mud_from_density(args):
337352
"""Theoretical estimation of mu*D from sample composition, energy, and
338353
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
354+
args = normalize_wavelength(args)
355+
if args.wavelength is None:
356+
args = load_wavelength_from_config_file(args)
357+
energy = 12.398 / args.wavelength
343358
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,
359+
args.mud = (
360+
compute_mu_using_xraydb(
361+
args.sample_composition,
362+
args.energy,
363+
sample_mass_density=args.sample_mass_density,
364+
)
365+
* args.diameter
349366
)
350367
return args
351368

@@ -359,10 +376,13 @@ def _set_theoretical_mud_from_packing(args):
359376
args.sample_composition = sample_composition
360377
args.energy = energy
361378
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,
379+
args.mud = (
380+
compute_mu_using_xraydb(
381+
args.sample_composition,
382+
args.energy,
383+
packing_fraction=args.packing_fraction,
384+
)
385+
* args.diameter
366386
)
367387
return args
368388

@@ -386,12 +406,12 @@ def set_mud(args):
386406
args : argparse.Namespace
387407
The updated arguments with mu*D.
388408
"""
389-
if args.z_scan_file:
409+
if args.command == "mud":
410+
return args
411+
if args.command == "zscan":
390412
return _set_mud_from_zscan(args)
391-
elif args.theoretical_from_density:
413+
if args.command == "sample":
392414
return _set_theoretical_mud_from_density(args)
393-
elif args.theoretical_from_packing:
394-
return _set_theoretical_mud_from_packing(args)
395415
return args
396416

397417

@@ -507,6 +527,7 @@ def preprocessing_args(args):
507527
args : argparse.Namespace
508528
The updated argparse Namespace with arguments preprocessed.
509529
"""
530+
args = load_wavelength_from_config_file(args)
510531
args = set_mud(args)
511532
args = set_input_lists(args)
512533
args = set_output_directory(args)
@@ -518,6 +539,7 @@ def preprocessing_args(args):
518539
return args
519540

520541

542+
# Update load_metadata to use 'input_directory' consistently:
521543
def load_metadata(args, filepath):
522544
"""Load the relevant metadata from args to write into the header of the
523545
output files.
@@ -538,6 +560,7 @@ def load_metadata(args, filepath):
538560
metadata = copy.deepcopy(vars(args))
539561
for key in METADATA_KEYS_TO_EXCLUDE:
540562
metadata.pop(key, None)
563+
metadata["mud"] = round(float(metadata["mud"]), 4)
541564
metadata["input_directory"] = str(filepath)
542565
metadata["output_directory"] = str(metadata["output_directory"])
543566
return metadata

0 commit comments

Comments
 (0)