@@ -140,21 +140,6 @@ def add_args_from_pydantic_model(
140140 return parser
141141
142142
143- T = TypeVar ('T' , bound = BaseModel )
144-
145-
146- def from_args (cls : type [T ], args : argparse .Namespace ) -> T :
147- """Create an instance of the pydantic model from the argparse namespace.
148-
149- It ignores any extra arguments in the namespace that are not part of the model.
150- """
151- kwargs = {
152- field_name : _retrieve_field_value (field_name , field_info , args )
153- for field_name , field_info in cls .model_fields .items ()
154- }
155- return cls (** kwargs )
156-
157-
158143class InputConfig (BaseModel ):
159144 # Add title of the basemodel
160145 model_config = {"title" : "Input Configuration" }
@@ -201,42 +186,66 @@ class InputConfig(BaseModel):
201186 )
202187
203188
204- class TOAUnit (enum .StrEnum ):
189+ class TimeBinUnit (enum .StrEnum ):
205190 ms = 'ms'
206191 us = 'us'
207192 ns = 'ns'
208193
209194
195+ class TimeBinCoordinate (enum .StrEnum ):
196+ event_time_offset = 'event_time_offset'
197+ time_of_flight = 'time_of_flight'
198+
199+
210200class WorkflowConfig (BaseModel ):
211201 # Add title of the basemodel
212202 model_config = {"title" : "Workflow Configuration" }
203+ time_bin_coordinate : TimeBinCoordinate = Field (
204+ title = "Time Bin Coordinate" ,
205+ description = "Coordinate to bin the time data." ,
206+ default = TimeBinCoordinate .event_time_offset ,
207+ )
213208 nbins : int = Field (
214- title = "Number of TOF Bins" ,
215- description = "Number of TOF bins" ,
209+ title = "Number of Time Bins" ,
210+ description = "Number of Time bins" ,
216211 default = 50 ,
217212 )
218- min_toa : int = Field (
219- title = "Minimum Time of Arrival " ,
220- description = "Minimum time of arrival (TOA) in [toa_unit ]." ,
221- default = 0 ,
213+ min_time_bin : int | None = Field (
214+ title = "Minimum Time Bin " ,
215+ description = "Minimum time edge of [time_bin_coordinate] in [time_bin_unit ]." ,
216+ default = None ,
222217 )
223- max_toa : int = Field (
224- title = "Maximum Time of Arrival " ,
225- description = "Maximum time of arrival (TOA) in [toa_unit ]." ,
226- default = int (( 1 / 14 ) * 1_000 ) ,
218+ max_time_bin : int | None = Field (
219+ title = "Maximum Time Bin " ,
220+ description = "Maximum time edge of [time_bin_coordinate] in [time_bin_unit ]." ,
221+ default = None ,
227222 )
228- toa_unit : TOAUnit = Field (
229- title = "Unit of TOA " ,
230- description = "Unit of TOA ." ,
231- default = TOAUnit .ms ,
223+ time_bin_unit : TimeBinUnit = Field (
224+ title = "Unit of Time Bins " ,
225+ description = "Unit of time bins ." ,
226+ default = TimeBinUnit .ms ,
232227 )
233- fast_axis : Literal ['x' , 'y' ] | None = Field (
234- title = "Fast Axis" ,
235- description = "Specify the fast axis of the detector. "
236- "If None, it will be determined "
237- "automatically based on the pixel offsets." ,
228+ tof_lookup_table_file_path : str | None = Field (
229+ title = "TOF Lookup Table File Path" ,
230+ description = "Path to the TOF lookup table file. "
231+ "If None, the lookup table will be computed on-the-fly." ,
238232 default = None ,
239233 )
234+ tof_simulation_min_wavelength : float = Field (
235+ title = "TOF Simulation Minimum Wavelength" ,
236+ description = "Minimum wavelength for TOF simulation in Angstrom." ,
237+ default = 1.8 ,
238+ )
239+ tof_simulation_max_wavelength : float = Field (
240+ title = "TOF Simulation Maximum Wavelength" ,
241+ description = "Maximum wavelength for TOF simulation in Angstrom." ,
242+ default = 3.6 ,
243+ )
244+ tof_simulation_seed : int = Field (
245+ title = "TOF Simulation Seed" ,
246+ description = "Random seed for TOF simulation." ,
247+ default = 42 , # No reason.
248+ )
240249
241250
242251class OutputConfig (BaseModel ):
@@ -265,64 +274,82 @@ class ReductionConfig(BaseModel):
265274 """Container for all reduction configurations."""
266275
267276 inputs : InputConfig
268- workflow : WorkflowConfig
269- output : OutputConfig
270-
271- @classmethod
272- def build_argument_parser (cls ) -> argparse .ArgumentParser :
273- parser = argparse .ArgumentParser (
274- description = "Command line arguments for the ESS NMX reduction. "
275- "It assumes 14 Hz pulse speed."
276- )
277- parser = add_args_from_pydantic_model (model_cls = InputConfig , parser = parser )
278- parser = add_args_from_pydantic_model (model_cls = WorkflowConfig , parser = parser )
279- parser = add_args_from_pydantic_model (model_cls = OutputConfig , parser = parser )
280- return parser
281-
282- @classmethod
283- def from_args (cls , args : argparse .Namespace ) -> "ReductionConfig" :
284- return cls (
285- inputs = from_args (InputConfig , args ),
286- workflow = from_args (WorkflowConfig , args ),
287- output = from_args (OutputConfig , args ),
288- )
277+ workflow : WorkflowConfig = Field (default_factory = WorkflowConfig )
278+ output : OutputConfig = Field (default_factory = OutputConfig )
289279
290280 @property
291281 def _children (self ) -> list [BaseModel ]:
292282 return [self .inputs , self .workflow , self .output ]
293283
294- def to_command_arguments (self , one_line : bool = True ) -> list [str ] | str :
295- """Convert the config to a list of command line arguments.
296-
297- Parameters
298- ----------
299- one_line:
300- If True, return a single string with all arguments joined by spaces.
301- If False, return a list of argument strings.
302-
303- """
304- args = {}
305- for instance in self ._children :
306- args .update (instance .model_dump (mode = 'python' ))
307- args = {f"--{ k .replace ('_' , '-' )} " : v for k , v in args .items ()}
308-
309- arg_list = []
310- for k , v in args .items ():
311- if not isinstance (v , bool ):
312- arg_list .append (k )
313- if isinstance (v , list ):
314- arg_list .extend (str (item ) for item in v )
315- elif isinstance (v , enum .StrEnum ):
316- arg_list .append (v .value )
317- else :
318- arg_list .append (str (v ))
319- elif v is True :
320- arg_list .append (k )
321-
322- if one_line :
323- return ' ' .join (arg_list )
324- else :
325- return arg_list
284+
285+ T = TypeVar ('T' , bound = BaseModel )
286+
287+
288+ def from_args (cls : type [T ], args : argparse .Namespace ) -> T :
289+ """Create an instance of the pydantic model from the argparse namespace.
290+
291+ It ignores any extra arguments in the namespace that are not part of the model.
292+ """
293+ kwargs = {
294+ field_name : _retrieve_field_value (field_name , field_info , args )
295+ for field_name , field_info in cls .model_fields .items ()
296+ }
297+ return cls (** kwargs )
298+
299+
300+ def build_reduction_argument_parser () -> argparse .ArgumentParser :
301+ parser = argparse .ArgumentParser (
302+ description = "Command line arguments for the ESS NMX reduction. "
303+ "It assumes 14 Hz pulse speed."
304+ )
305+ parser = add_args_from_pydantic_model (model_cls = InputConfig , parser = parser )
306+ parser = add_args_from_pydantic_model (model_cls = WorkflowConfig , parser = parser )
307+ parser = add_args_from_pydantic_model (model_cls = OutputConfig , parser = parser )
308+ return parser
309+
310+
311+ def reduction_config_from_args (args : argparse .Namespace ) -> ReductionConfig :
312+ return ReductionConfig (
313+ inputs = from_args (InputConfig , args ),
314+ workflow = from_args (WorkflowConfig , args ),
315+ output = from_args (OutputConfig , args ),
316+ )
317+
318+
319+ def to_command_arguments (
320+ config : ReductionConfig , one_line : bool = True
321+ ) -> list [str ] | str :
322+ """Convert the config to a list of command line arguments.
323+
324+ Parameters
325+ ----------
326+ one_line:
327+ If True, return a single string with all arguments joined by spaces.
328+ If False, return a list of argument strings.
329+
330+ """
331+ args = {}
332+ for instance in config ._children :
333+ args .update (instance .model_dump (mode = 'python' ))
334+ args = {f"--{ k .replace ('_' , '-' )} " : v for k , v in args .items () if v is not None }
335+
336+ arg_list = []
337+ for k , v in args .items ():
338+ if not isinstance (v , bool ):
339+ arg_list .append (k )
340+ if isinstance (v , list ):
341+ arg_list .extend (str (item ) for item in v )
342+ elif isinstance (v , enum .StrEnum ):
343+ arg_list .append (v .value )
344+ else :
345+ arg_list .append (str (v ))
346+ elif v is True :
347+ arg_list .append (k )
348+
349+ if one_line :
350+ return ' ' .join (arg_list )
351+ else :
352+ return arg_list
326353
327354
328355def build_logger (args : argparse .Namespace | OutputConfig ) -> logging .Logger :
0 commit comments