diff --git a/hexrd/cli/preprocess.py b/hexrd/cli/preprocess.py index 52018ddf..67d095bc 100644 --- a/hexrd/cli/preprocess.py +++ b/hexrd/cli/preprocess.py @@ -83,11 +83,14 @@ def add_profile_subparser(subparsers, name, klass): ) def _remove_non_dataclass_args(args_dict): - """Remove args that do not belong to any dataclass. These are standard args we manually inserted and now remove to allows the rest initialize dataclass""" - d = {} + """Remove args that do not belong to any dataclass. These are standard args + we manually inserted and now remove to allow the rest of the arguments to + initialize dataclass""" + + extra = {} for key in ["profile", "config", "generate_default_config"]: v = args_dict.get(key, None) - d[key] = v + extra[key] = v if v is not None: del args_dict[key] - return args_dict, d + return args_dict, extra diff --git a/hexrd/preprocess/profiles.py b/hexrd/preprocess/profiles.py index a0d160dc..db5be7c8 100644 --- a/hexrd/preprocess/profiles.py +++ b/hexrd/preprocess/profiles.py @@ -1,6 +1,15 @@ +from dataclasses import dataclass, field +import glob +import os import yaml -from hexrd.preprocess.argument_classes_factory import ArgumentClassesFactory -from hexrd.preprocess.yaml_internals import HexrdScriptArgumentsDumper, HexrdScriptArgumentsSafeLoader +from hexrd.preprocess.argument_classes_factory import ( + ArgumentClassesFactory, + autoregister, +) +from hexrd.preprocess.yaml_internals import ( + HexrdScriptArgumentsDumper, + HexrdScriptArgumentsSafeLoader, +) # Classes holding script arguments and their defaults based on the detector. @@ -14,6 +23,7 @@ # yaml_tag will be used in the configuration file and profile_name is # how we refer to the argument class in the cli. + class HexrdScript_Arguments(yaml.YAMLObject): # yaml tag to help deserialiser pick the right type write It is used in the # YAML file to indicate the class that should be created when reading a @@ -53,6 +63,102 @@ def load_from_config(cls, buffer: str): """Create an HexrdScript_Arguments instance from yaml string""" try: args = yaml.load(buffer, Loader=HexrdScriptArgumentsSafeLoader) - except: - raise RuntimeError("Could not read config from buffer") + except Exception as e: + raise RuntimeError(f"Could not read config from buffer: {e}") return args + + +@dataclass +@autoregister +class Eiger_Arguments(HexrdScript_Arguments): + yaml_tag = "!Eiger_Arguments" + profile_name = "eiger" + # fields + base_dir: str = None + expt_name: str = None + samp_name: str = None + scan_number: int = None + num_frames: int = 1440 + start_frame: int = 0 + threshold: int = 5 + ome_start: float = 0.0 + ome_end: float = 360.0 + absolute_path: str = None + panel_opts: dict[str, any] = field(default_factory=dict) + style: str = "npz" + output: str = "test" + + # class helpers + # we gather all argument messages here to allow for automated help + # generation but also easier derivation of new dataclass arguments + # through inheritance + help_messages = { + "base_dir": "raw data path on chess daq", + "expt_name": "experiment name", + "samp_name": "sample name", + "scan_number": "ff scan number", + "num_frames": "number of frames to read", + "start_frame": "index of first data frame", + "threshold": "threshold for frame caches", + "ome_start": "start omega", + "ome_end": "end omega", + "absolute_path": "absolute path to image file", + "panel_opts": "detector-specific options", + "style": "format for saving framecache", + "output": "output filename", + } + + short_switches = { + "num_frames": "n", + "start_frame": "s", + "threshold": "t", + "ome_start": "o", + "ome_end": "e", + "absolute_path": "ap", + } + + @property + def ostep(self) -> float: + return (self.ome_end - self.ome_start) / float(self.num_frames) + + @property + def file_name(self) -> str: + if self.absolute_path: + file_name = os.path.abspath(self.absolute_path) + else: + file_name = glob.glob( + os.path.join( + self.base_dir, + self.expt_name, + self.samp_name, + str(self.scan_number), + "ff", + "*.h5", + ) + ) + if not os.path.exists(file_name): + raise RuntimeError(f"File {file_name} does not exist!") + + return file_name + + +@dataclass +@autoregister +class Dexelas_Arguments(Eiger_Arguments): + yaml_tag = "!Dexelas_Arguments" + profile_name = "dexelas" + # !!!: hard coded options for each dexela for April 2017 + panel_opts: dict[str, any] = field( + default_factory=lambda: { + "FF1": [ + ("add-row", 1944), + ("add-column", 1296), + ("flip", "v"), + ], + "FF2": [("add-row", 1944), ("add-column", 1296), ("flip", "h")], + } + ) + + num_frames: int = 1441 + start_frame: int = 4 # usually 4 for normal CHESS stuff + threshold: int = 50