-
Notifications
You must be signed in to change notification settings - Fork 1
Add documentation of reduction interface and allow skipping file saving. #172
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: tof-sim-config
Are you sure you want to change the base?
Changes from all commits
0d7d893
78cec11
9a21d37
b5b2733
f5c15d3
f307198
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -34,5 +34,6 @@ | |
| types | ||
| mtz_io | ||
| scaling | ||
| configurations | ||
| ``` | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,6 +5,7 @@ | |
| maxdepth: 1 | ||
| --- | ||
| workflow | ||
| mcstas_workflow | ||
| mcstas_workflow_chunk | ||
| scaling_workflow | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,171 @@ | ||||||
| { | ||||||
| "cells": [ | ||||||
| { | ||||||
| "cell_type": "markdown", | ||||||
| "metadata": {}, | ||||||
| "source": [ | ||||||
| "# NMX Reduction Workflow\n", | ||||||
| "\n", | ||||||
| "> NMX does not expect users to use python interface directly.<br>\n", | ||||||
| "This documentation is mostly for instrument data scientists or instrument scientists.<br>" | ||||||
| ] | ||||||
| }, | ||||||
| { | ||||||
| "cell_type": "markdown", | ||||||
| "metadata": {}, | ||||||
| "source": [ | ||||||
| "## TL;DR" | ||||||
| ] | ||||||
| }, | ||||||
| { | ||||||
| "cell_type": "code", | ||||||
| "execution_count": null, | ||||||
| "metadata": {}, | ||||||
| "outputs": [], | ||||||
| "source": [ | ||||||
| "from ess.nmx.executables import reduction\n", | ||||||
| "from ess.nmx.data import get_small_nmx_nexus\n", | ||||||
| "from ess.nmx.configurations import (\n", | ||||||
| " ReductionConfig,\n", | ||||||
| " OutputConfig,\n", | ||||||
| " InputConfig,\n", | ||||||
| " WorkflowConfig,\n", | ||||||
| " TimeBinCoordinate,\n", | ||||||
| ")\n", | ||||||
| "\n", | ||||||
| "# Build Configuration\n", | ||||||
| "config = ReductionConfig(\n", | ||||||
| " inputs=InputConfig(\n", | ||||||
| " input_file=[get_small_nmx_nexus().as_posix()],\n", | ||||||
| " detector_ids=[0, 1, 2],\n", | ||||||
| " ),\n", | ||||||
| " output=OutputConfig(\n", | ||||||
| " output_file=\"scipp_output.hdf\", skip_file_output=False, overwrite=True\n", | ||||||
| " ),\n", | ||||||
| " workflow=WorkflowConfig(\n", | ||||||
| " time_bin_coordinate=TimeBinCoordinate.time_of_flight,\n", | ||||||
| " nbins=10,\n", | ||||||
| " tof_simulation_num_neutrons=1_000_000,\n", | ||||||
| " tof_simulation_min_wavelength=1.8,\n", | ||||||
| " tof_simulation_max_wavelength=3.6,\n", | ||||||
| " tof_simulation_seed=42,\n", | ||||||
| " ),\n", | ||||||
| ")\n", | ||||||
| "\n", | ||||||
| "# Run Reduction\n", | ||||||
| "reduction(config=config, display=display)" | ||||||
| ] | ||||||
| }, | ||||||
| { | ||||||
| "cell_type": "markdown", | ||||||
| "metadata": {}, | ||||||
| "source": [ | ||||||
| "## Configuration\n", | ||||||
| "\n", | ||||||
| "`essnmx` provides a command line data reduction tool.<br>\n", | ||||||
| "The `essnmx-reduce` interface will reduce `nexus` file <br>\n", | ||||||
| "and save the results into `NXlauetof`(not exactly but very close) format for `dials`.<br>\n", | ||||||
| "\n", | ||||||
| "Argument options could be exhaustive therefore we wrapped them into a nested pydantic model.<br>\n", | ||||||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about this...?
Suggested change
|
||||||
| "Here is a python API you can use to build the configuration and turn it into command line arguments.\n", | ||||||
| "\n", | ||||||
| "**The configuration object is a pydantic model, and it thus enforces strict checks on the types of the arguments.**" | ||||||
| ] | ||||||
| }, | ||||||
| { | ||||||
| "cell_type": "code", | ||||||
| "execution_count": null, | ||||||
| "metadata": {}, | ||||||
| "outputs": [], | ||||||
| "source": [ | ||||||
| "from ess.nmx.configurations import (\n", | ||||||
| " ReductionConfig,\n", | ||||||
| " OutputConfig,\n", | ||||||
| " InputConfig,\n", | ||||||
| " WorkflowConfig,\n", | ||||||
| " TimeBinCoordinate,\n", | ||||||
| " to_command_arguments,\n", | ||||||
| ")\n", | ||||||
| "\n", | ||||||
| "config = ReductionConfig(\n", | ||||||
| " inputs=InputConfig(\n", | ||||||
| " input_file=[\"PATH_TO_THE_NEXUS_FILE.hdf\"],\n", | ||||||
| " detector_ids=[0, 1, 2], # Detector index to be reduced in alphabetical order.\n", | ||||||
| " ),\n", | ||||||
| " output=OutputConfig(output_file=\"scipp_output.hdf\", skip_file_output=True),\n", | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of having both
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's because there is already a default output file name, which is not What do you think...? |
||||||
| " workflow=WorkflowConfig(\n", | ||||||
| " time_bin_coordinate=TimeBinCoordinate.time_of_flight,\n", | ||||||
| " nbins=10,\n", | ||||||
| " tof_simulation_num_neutrons=1_000_000,\n", | ||||||
| " tof_simulation_min_wavelength=1.8,\n", | ||||||
| " tof_simulation_max_wavelength=3.6,\n", | ||||||
| " tof_simulation_seed=42,\n", | ||||||
| " ),\n", | ||||||
| ")\n", | ||||||
| "\n", | ||||||
| "display(config)\n", | ||||||
| "print(to_command_arguments(config=config, one_line=True))" | ||||||
| ] | ||||||
| }, | ||||||
| { | ||||||
| "cell_type": "markdown", | ||||||
| "metadata": {}, | ||||||
| "source": [ | ||||||
| "## Reduce Nexus File(s)\n", | ||||||
| "\n", | ||||||
| "`OutputConfig` has an option called `skip_file_output` if you want to reduce the file and use it only on the memory.<br>\n", | ||||||
| "Then you can use `save_results` function to explicitly save the results." | ||||||
| ] | ||||||
| }, | ||||||
| { | ||||||
| "cell_type": "code", | ||||||
| "execution_count": null, | ||||||
| "metadata": {}, | ||||||
| "outputs": [], | ||||||
| "source": [ | ||||||
| "from ess.nmx.executables import reduction\n", | ||||||
| "from ess.nmx.data import get_small_nmx_nexus\n", | ||||||
| "\n", | ||||||
| "config = ReductionConfig(\n", | ||||||
| " inputs=InputConfig(input_file=[get_small_nmx_nexus().as_posix()]),\n", | ||||||
| " output=OutputConfig(skip_file_output=True),\n", | ||||||
| ")\n", | ||||||
| "results = reduction(config=config, display=display)\n", | ||||||
| "results" | ||||||
| ] | ||||||
| }, | ||||||
| { | ||||||
| "cell_type": "code", | ||||||
| "execution_count": null, | ||||||
| "metadata": {}, | ||||||
| "outputs": [], | ||||||
| "source": [ | ||||||
| "from ess.nmx.executables import save_results\n", | ||||||
| "\n", | ||||||
| "output_config = OutputConfig(output_file=\"scipp_output.hdf\", overwrite=True)\n", | ||||||
| "save_results(results=results, output_config=output_config)" | ||||||
| ] | ||||||
| } | ||||||
| ], | ||||||
| "metadata": { | ||||||
| "kernelspec": { | ||||||
| "display_name": "nmx-dev-313", | ||||||
| "language": "python", | ||||||
| "name": "python3" | ||||||
| }, | ||||||
| "language_info": { | ||||||
| "codemirror_mode": { | ||||||
| "name": "ipython", | ||||||
| "version": 3 | ||||||
| }, | ||||||
| "file_extension": ".py", | ||||||
| "mimetype": "text/x-python", | ||||||
| "name": "python", | ||||||
| "nbconvert_exporter": "python", | ||||||
| "pygments_lexer": "ipython3", | ||||||
| "version": "3.13.5" | ||||||
| } | ||||||
| }, | ||||||
| "nbformat": 4, | ||||||
| "nbformat_minor": 4 | ||||||
| } | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -140,11 +140,22 @@ class OutputConfig(BaseModel): | |
| default=False, | ||
| ) | ||
| # File output | ||
| skip_file_output: bool = Field( | ||
| title="Skip File Output", | ||
| description="If True, the output file will not be written.", | ||
| default=False, | ||
| ) | ||
| output_file: str = Field( | ||
| title="Output File", | ||
| description="Path to the output file.", | ||
| description="Path to the output file. " | ||
| "It will be overwritten if ``overwrite`` is True.", | ||
| default="scipp_output.h5", | ||
| ) | ||
| overwrite: bool = Field( | ||
| title="Overwrite Output File", | ||
| description="If True, overwrite the output file if ``output_file`` exists.", | ||
| default=False, | ||
| ) | ||
| compression: Compression = Field( | ||
| title="Compression", | ||
| description="Compress option of reduced output file.", | ||
|
|
@@ -162,3 +173,45 @@ class ReductionConfig(BaseModel): | |
| @property | ||
| def _children(self) -> list[BaseModel]: | ||
| return [self.inputs, self.workflow, self.output] | ||
|
|
||
|
|
||
| def to_command_arguments( | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I moved this interface to the |
||
| *, config: ReductionConfig, one_line: bool = True, separator: str = '\\\n' | ||
| ) -> list[str] | str: | ||
| """Convert the config to a list of command line arguments. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| one_line: | ||
| If True, return a single string with all arguments joined by spaces. | ||
| If False, return a list of argument strings. | ||
|
|
||
| """ | ||
| args = {} | ||
| for instance in config._children: | ||
| args.update(instance.model_dump(mode='python')) | ||
| args = {f"--{k.replace('_', '-')}": v for k, v in args.items() if v is not None} | ||
|
|
||
| arg_list = [] | ||
| for k, v in args.items(): | ||
| if not isinstance(v, bool): | ||
| arg_list.append(k) | ||
| if isinstance(v, list): | ||
| arg_list.extend(str(item) for item in v) | ||
| elif isinstance(v, enum.StrEnum): | ||
| arg_list.append(v.value) | ||
| else: | ||
| arg_list.append(str(v)) | ||
| elif v is True: | ||
| arg_list.append(k) | ||
|
|
||
| if one_line: | ||
| # Default separator is backslash + newline for better readability | ||
| # Users can directly copy-paste the output in a terminal or a script. | ||
| return ( | ||
| (separator + '--') | ||
| .join(" ".join(arg_list).split('--')) | ||
| .removeprefix(separator) | ||
| ) | ||
| else: | ||
| return arg_list | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure I understand what is meant here...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I meant, if we pass them as individual arguments to the function... it could be exhaustive and not so easy to know which one to change etc. We can change it to ...
For conveniences and safety, we wrapped...