From 30abcf05c2efcd3b6f3ad50cec4f21546d0781e1 Mon Sep 17 00:00:00 2001 From: Neil Vaytet Date: Thu, 23 Jan 2025 15:33:50 +0100 Subject: [PATCH 1/7] fix bug when making copy of workflow pipeline --- src/ess/reduce/time_of_flight/toa_to_tof.py | 2 +- tests/time_of_flight/workflow_test.py | 61 +++++++++++++++++++++ 2 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 tests/time_of_flight/workflow_test.py diff --git a/src/ess/reduce/time_of_flight/toa_to_tof.py b/src/ess/reduce/time_of_flight/toa_to_tof.py index ccbe3d3c..4e813096 100644 --- a/src/ess/reduce/time_of_flight/toa_to_tof.py +++ b/src/ess/reduce/time_of_flight/toa_to_tof.py @@ -540,6 +540,6 @@ def visualize(self, *args, **kwargs) -> Any: return self.pipeline.visualize(*args, **kwargs) def copy(self) -> TofWorkflow: - out = self.__class__(choppers=None, facility=None, ltotal_range=None) + out = self.__class__(simulated_neutrons=None, ltotal_range=None) out.pipeline = self.pipeline.copy() return out diff --git a/tests/time_of_flight/workflow_test.py b/tests/time_of_flight/workflow_test.py new file mode 100644 index 00000000..eb5f878d --- /dev/null +++ b/tests/time_of_flight/workflow_test.py @@ -0,0 +1,61 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2025 Scipp contributors (https://github.com/scipp) + +import pytest +import scipp as sc + +from ess.reduce import time_of_flight +from ess.reduce.time_of_flight import fakes + + +@pytest.fixture(scope="module") +def simulation_results(): + return time_of_flight.simulate_beamline( + choppers=fakes.psc_choppers(), neutrons=100_000, seed=432 + ) + + +def test_create_workflow(simulation_results): + wf = time_of_flight.TofWorkflow( + simulated_neutrons=simulation_results, + ltotal_range=(sc.scalar(77.0, unit='m'), sc.scalar(82.0, unit='m')), + error_threshold=1.0e-3, + ) + + assert wf.compute(time_of_flight.LookupTableRelativeErrorThreshold) == 1.0e-3 + assert ( + wf.compute(time_of_flight.PulsePeriod) + == time_of_flight.default_parameters()[time_of_flight.PulsePeriod] + ) + + +def test_workflow_setitem(simulation_results): + wf = time_of_flight.TofWorkflow( + simulated_neutrons=simulation_results, + ltotal_range=(sc.scalar(77.0, unit='m'), sc.scalar(82.0, unit='m')), + error_threshold=1.0e-3, + ) + + assert wf.compute(time_of_flight.LookupTableRelativeErrorThreshold) == 1.0e-3 + + wf[time_of_flight.LookupTableRelativeErrorThreshold] = 1.0e-4 + assert wf.compute(time_of_flight.LookupTableRelativeErrorThreshold) == 1.0e-4 + + wf[time_of_flight.PulsePeriod] = sc.scalar(1.0, unit='s') + assert wf.compute(time_of_flight.PulsePeriod) == sc.scalar(1.0, unit='s') + + +def test_workflow_copy(simulation_results): + wf = time_of_flight.TofWorkflow( + simulated_neutrons=simulation_results, + ltotal_range=(sc.scalar(77.0, unit='m'), sc.scalar(82.0, unit='m')), + error_threshold=1.0e-3, + ) + + wf_copy = wf.copy() + assert wf.compute( + time_of_flight.LookupTableRelativeErrorThreshold + ) == wf_copy.compute(time_of_flight.LookupTableRelativeErrorThreshold) + assert wf.compute(time_of_flight.PulsePeriod) == wf_copy.compute( + time_of_flight.PulsePeriod + ) From 0025a9f8e6776b7ffd817a9c888da037fc5ac347 Mon Sep 17 00:00:00 2001 From: Neil Vaytet Date: Fri, 24 Jan 2025 09:21:14 +0100 Subject: [PATCH 2/7] add insert method to class --- src/ess/reduce/time_of_flight/toa_to_tof.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ess/reduce/time_of_flight/toa_to_tof.py b/src/ess/reduce/time_of_flight/toa_to_tof.py index 3b1001e1..c1c8954d 100644 --- a/src/ess/reduce/time_of_flight/toa_to_tof.py +++ b/src/ess/reduce/time_of_flight/toa_to_tof.py @@ -542,6 +542,9 @@ def visualize(self, *args, **kwargs) -> Any: return self.pipeline.visualize(*args, **kwargs) def copy(self) -> TofWorkflow: - out = self.__class__(simulated_neutrons=None, ltotal_range=None) + out = self.__class__(None, None) out.pipeline = self.pipeline.copy() return out + + def insert(self, *args, **kwargs) -> None: + self.pipeline.insert(*args, **kwargs) From 5d0a2ebb443142d8c5e4f61c7811c8d6771e8581 Mon Sep 17 00:00:00 2001 From: Neil Vaytet Date: Fri, 24 Jan 2025 13:26:04 +0100 Subject: [PATCH 3/7] try to use free functions instead --- src/ess/reduce/time_of_flight/toa_to_tof.py | 101 ++++++++++---------- 1 file changed, 52 insertions(+), 49 deletions(-) diff --git a/src/ess/reduce/time_of_flight/toa_to_tof.py b/src/ess/reduce/time_of_flight/toa_to_tof.py index 0970e425..f0a6a566 100644 --- a/src/ess/reduce/time_of_flight/toa_to_tof.py +++ b/src/ess/reduce/time_of_flight/toa_to_tof.py @@ -459,7 +459,15 @@ def providers() -> tuple[Callable]: ) -class TofWorkflow: +def tof_workflow( + simulated_neutrons: SimulationResults, + ltotal_range: LtotalRange, + pulse_stride: PulseStride | None = None, + pulse_stride_offset: PulseStrideOffset | None = None, + distance_resolution: DistanceResolution | None = None, + toa_resolution: TimeOfArrivalResolution | None = None, + error_threshold: LookupTableRelativeErrorThreshold | None = None, +): """ Helper class to build a time-of-flight workflow and cache the expensive part of the computation: running the simulation and building the lookup table. @@ -494,58 +502,53 @@ class TofWorkflow: are masked. """ - def __init__( - self, - simulated_neutrons: SimulationResults, - ltotal_range: LtotalRange, - pulse_stride: PulseStride | None = None, - pulse_stride_offset: PulseStrideOffset | None = None, - distance_resolution: DistanceResolution | None = None, - toa_resolution: TimeOfArrivalResolution | None = None, - error_threshold: LookupTableRelativeErrorThreshold | None = None, - ): - import sciline as sl - - self.pipeline = sl.Pipeline(providers()) - self.pipeline[SimulationResults] = simulated_neutrons - self.pipeline[LtotalRange] = ltotal_range - - params = default_parameters() - self.pipeline[PulsePeriod] = params[PulsePeriod] - self.pipeline[PulseStride] = pulse_stride or params[PulseStride] - self.pipeline[PulseStrideOffset] = ( - pulse_stride_offset or params[PulseStrideOffset] - ) - self.pipeline[DistanceResolution] = ( - distance_resolution or params[DistanceResolution] - ) - self.pipeline[TimeOfArrivalResolution] = ( - toa_resolution or params[TimeOfArrivalResolution] - ) - self.pipeline[LookupTableRelativeErrorThreshold] = ( - error_threshold or params[LookupTableRelativeErrorThreshold] - ) + import sciline as sl + + pipeline = sl.Pipeline(providers()) + pipeline[SimulationResults] = simulated_neutrons + pipeline[LtotalRange] = ltotal_range + + params = default_parameters() + pipeline[PulsePeriod] = params[PulsePeriod] + pipeline[PulseStride] = pulse_stride or params[PulseStride] + pipeline[PulseStrideOffset] = pulse_stride_offset or params[PulseStrideOffset] + pipeline[DistanceResolution] = distance_resolution or params[DistanceResolution] + pipeline[TimeOfArrivalResolution] = ( + toa_resolution or params[TimeOfArrivalResolution] + ) + pipeline[LookupTableRelativeErrorThreshold] = ( + error_threshold or params[LookupTableRelativeErrorThreshold] + ) + + return pipeline + + +def cache_expensive_part(pipeline: sl.Pipeline): + out = pipeline.copy() + for t in (SimulationResults, MaskedTimeOfFlightLookupTable, FastestNeutron): + out[t] = out.compute(t) + return out - def __getitem__(self, key): - return self.pipeline[key] + # def __getitem__(self, key): + # return pipeline[key] - def __setitem__(self, key, value): - self.pipeline[key] = value + # def __setitem__(self, key, value): + # pipeline[key] = value - def persist(self) -> None: - for t in (SimulationResults, MaskedTimeOfFlightLookupTable, FastestNeutron): - self.pipeline[t] = self.pipeline.compute(t) + # def persist(self) -> None: + # for t in (SimulationResults, MaskedTimeOfFlightLookupTable, FastestNeutron): + # pipeline[t] = pipeline.compute(t) - def compute(self, *args, **kwargs) -> Any: - return self.pipeline.compute(*args, **kwargs) + # def compute(self, *args, **kwargs) -> Any: + # return pipeline.compute(*args, **kwargs) - def visualize(self, *args, **kwargs) -> Any: - return self.pipeline.visualize(*args, **kwargs) + # def visualize(self, *args, **kwargs) -> Any: + # return pipeline.visualize(*args, **kwargs) - def copy(self) -> TofWorkflow: - out = self.__class__(None, None) - out.pipeline = self.pipeline.copy() - return out + # def copy(self) -> TofWorkflow: + # out = __class__(None, None) + # out.pipeline = pipeline.copy() + # return out - def insert(self, *args, **kwargs) -> None: - self.pipeline.insert(*args, **kwargs) + # def insert(self, *args, **kwargs) -> None: + # pipeline.insert(*args, **kwargs) From f277362ba600bd8194d791878543f3a17d1fa5e0 Mon Sep 17 00:00:00 2001 From: Neil Vaytet Date: Mon, 27 Jan 2025 10:40:14 +0100 Subject: [PATCH 4/7] rework interface to function which caches the results --- src/ess/reduce/time_of_flight/__init__.py | 6 ++- src/ess/reduce/time_of_flight/toa_to_tof.py | 53 +++++++++------------ 2 files changed, 27 insertions(+), 32 deletions(-) diff --git a/src/ess/reduce/time_of_flight/__init__.py b/src/ess/reduce/time_of_flight/__init__.py index 07d910e6..0ef799f1 100644 --- a/src/ess/reduce/time_of_flight/__init__.py +++ b/src/ess/reduce/time_of_flight/__init__.py @@ -7,10 +7,11 @@ """ from .toa_to_tof import ( + cache_results, default_parameters, resample_tof_data, providers, - TofWorkflow, + tof_workflow, ) from .simulation import simulate_beamline from .types import ( @@ -54,11 +55,12 @@ "TimeOfArrivalMinusPivotTimeModuloPeriod", "TimeOfFlightLookupTable", "TofData", - "TofWorkflow", "UnwrappedTimeOfArrival", "UnwrappedTimeOfArrivalMinusPivotTime", + "cache_results", "default_parameters", "providers", "resample_tof_data", "simulate_beamline", + "tof_workflow", ] diff --git a/src/ess/reduce/time_of_flight/toa_to_tof.py b/src/ess/reduce/time_of_flight/toa_to_tof.py index f0a6a566..c96508fc 100644 --- a/src/ess/reduce/time_of_flight/toa_to_tof.py +++ b/src/ess/reduce/time_of_flight/toa_to_tof.py @@ -10,13 +10,17 @@ from __future__ import annotations from collections.abc import Callable -from typing import Any +from typing import TYPE_CHECKING import numpy as np import scipp as sc from scipp._scipp.core import _bins_no_validate from scippneutron._utils import elem_unit +if TYPE_CHECKING: + import sciline + + from .to_events import to_events from .types import ( DistanceResolution, @@ -467,10 +471,9 @@ def tof_workflow( distance_resolution: DistanceResolution | None = None, toa_resolution: TimeOfArrivalResolution | None = None, error_threshold: LookupTableRelativeErrorThreshold | None = None, -): +) -> sciline.Pipeline: """ - Helper class to build a time-of-flight workflow and cache the expensive part of - the computation: running the simulation and building the lookup table. + Helper function to make it easy to build a time-of-flight workflow. Parameters ---------- @@ -523,32 +526,22 @@ def tof_workflow( return pipeline -def cache_expensive_part(pipeline: sl.Pipeline): +def cache_results( + pipeline: sciline.Pipeline, + results=(SimulationResults, MaskedTimeOfFlightLookupTable, FastestNeutron), +) -> sciline.Pipeline: + """ + Cache a list of (usually expensive to compute) intermediate results of the + time-of-flight workflow and return a new pipeline with these results computed. + + Parameters + ---------- + pipeline: + Time-of-flight workflow pipeline. + results: + List of results to cache. + """ out = pipeline.copy() - for t in (SimulationResults, MaskedTimeOfFlightLookupTable, FastestNeutron): + for t in results: out[t] = out.compute(t) return out - - # def __getitem__(self, key): - # return pipeline[key] - - # def __setitem__(self, key, value): - # pipeline[key] = value - - # def persist(self) -> None: - # for t in (SimulationResults, MaskedTimeOfFlightLookupTable, FastestNeutron): - # pipeline[t] = pipeline.compute(t) - - # def compute(self, *args, **kwargs) -> Any: - # return pipeline.compute(*args, **kwargs) - - # def visualize(self, *args, **kwargs) -> Any: - # return pipeline.visualize(*args, **kwargs) - - # def copy(self) -> TofWorkflow: - # out = __class__(None, None) - # out.pipeline = pipeline.copy() - # return out - - # def insert(self, *args, **kwargs) -> None: - # pipeline.insert(*args, **kwargs) From 52bfcc27c4b0e9a98b12624ef466639517e87790 Mon Sep 17 00:00:00 2001 From: Neil Vaytet Date: Mon, 27 Jan 2025 10:47:14 +0100 Subject: [PATCH 5/7] remove old workflow tests --- tests/time_of_flight/workflow_test.py | 61 --------------------------- 1 file changed, 61 deletions(-) delete mode 100644 tests/time_of_flight/workflow_test.py diff --git a/tests/time_of_flight/workflow_test.py b/tests/time_of_flight/workflow_test.py deleted file mode 100644 index eb5f878d..00000000 --- a/tests/time_of_flight/workflow_test.py +++ /dev/null @@ -1,61 +0,0 @@ -# SPDX-License-Identifier: BSD-3-Clause -# Copyright (c) 2025 Scipp contributors (https://github.com/scipp) - -import pytest -import scipp as sc - -from ess.reduce import time_of_flight -from ess.reduce.time_of_flight import fakes - - -@pytest.fixture(scope="module") -def simulation_results(): - return time_of_flight.simulate_beamline( - choppers=fakes.psc_choppers(), neutrons=100_000, seed=432 - ) - - -def test_create_workflow(simulation_results): - wf = time_of_flight.TofWorkflow( - simulated_neutrons=simulation_results, - ltotal_range=(sc.scalar(77.0, unit='m'), sc.scalar(82.0, unit='m')), - error_threshold=1.0e-3, - ) - - assert wf.compute(time_of_flight.LookupTableRelativeErrorThreshold) == 1.0e-3 - assert ( - wf.compute(time_of_flight.PulsePeriod) - == time_of_flight.default_parameters()[time_of_flight.PulsePeriod] - ) - - -def test_workflow_setitem(simulation_results): - wf = time_of_flight.TofWorkflow( - simulated_neutrons=simulation_results, - ltotal_range=(sc.scalar(77.0, unit='m'), sc.scalar(82.0, unit='m')), - error_threshold=1.0e-3, - ) - - assert wf.compute(time_of_flight.LookupTableRelativeErrorThreshold) == 1.0e-3 - - wf[time_of_flight.LookupTableRelativeErrorThreshold] = 1.0e-4 - assert wf.compute(time_of_flight.LookupTableRelativeErrorThreshold) == 1.0e-4 - - wf[time_of_flight.PulsePeriod] = sc.scalar(1.0, unit='s') - assert wf.compute(time_of_flight.PulsePeriod) == sc.scalar(1.0, unit='s') - - -def test_workflow_copy(simulation_results): - wf = time_of_flight.TofWorkflow( - simulated_neutrons=simulation_results, - ltotal_range=(sc.scalar(77.0, unit='m'), sc.scalar(82.0, unit='m')), - error_threshold=1.0e-3, - ) - - wf_copy = wf.copy() - assert wf.compute( - time_of_flight.LookupTableRelativeErrorThreshold - ) == wf_copy.compute(time_of_flight.LookupTableRelativeErrorThreshold) - assert wf.compute(time_of_flight.PulsePeriod) == wf_copy.compute( - time_of_flight.PulsePeriod - ) From d15974770d8f44b6f4cf0b7c63baf71afb499ede Mon Sep 17 00:00:00 2001 From: Neil Vaytet Date: Tue, 28 Jan 2025 12:00:30 +0100 Subject: [PATCH 6/7] go back to using a class --- src/ess/reduce/time_of_flight/__init__.py | 11 +- src/ess/reduce/time_of_flight/toa_to_tof.py | 169 ++++++++++---------- 2 files changed, 83 insertions(+), 97 deletions(-) diff --git a/src/ess/reduce/time_of_flight/__init__.py b/src/ess/reduce/time_of_flight/__init__.py index 0ef799f1..025c3910 100644 --- a/src/ess/reduce/time_of_flight/__init__.py +++ b/src/ess/reduce/time_of_flight/__init__.py @@ -6,13 +6,7 @@ neutron time-of-arrival at the detectors. """ -from .toa_to_tof import ( - cache_results, - default_parameters, - resample_tof_data, - providers, - tof_workflow, -) +from .toa_to_tof import default_parameters, resample_tof_data, providers, TofWorkflow from .simulation import simulate_beamline from .types import ( DistanceResolution, @@ -55,12 +49,11 @@ "TimeOfArrivalMinusPivotTimeModuloPeriod", "TimeOfFlightLookupTable", "TofData", + "TofWorkflow", "UnwrappedTimeOfArrival", "UnwrappedTimeOfArrivalMinusPivotTime", - "cache_results", "default_parameters", "providers", "resample_tof_data", "simulate_beamline", - "tof_workflow", ] diff --git a/src/ess/reduce/time_of_flight/toa_to_tof.py b/src/ess/reduce/time_of_flight/toa_to_tof.py index c96508fc..b85dee40 100644 --- a/src/ess/reduce/time_of_flight/toa_to_tof.py +++ b/src/ess/reduce/time_of_flight/toa_to_tof.py @@ -7,20 +7,13 @@ event_time_offset coordinates to data with a time-of-flight coordinate. """ -from __future__ import annotations - from collections.abc import Callable -from typing import TYPE_CHECKING import numpy as np import scipp as sc from scipp._scipp.core import _bins_no_validate from scippneutron._utils import elem_unit -if TYPE_CHECKING: - import sciline - - from .to_events import to_events from .types import ( DistanceResolution, @@ -463,85 +456,85 @@ def providers() -> tuple[Callable]: ) -def tof_workflow( - simulated_neutrons: SimulationResults, - ltotal_range: LtotalRange, - pulse_stride: PulseStride | None = None, - pulse_stride_offset: PulseStrideOffset | None = None, - distance_resolution: DistanceResolution | None = None, - toa_resolution: TimeOfArrivalResolution | None = None, - error_threshold: LookupTableRelativeErrorThreshold | None = None, -) -> sciline.Pipeline: - """ - Helper function to make it easy to build a time-of-flight workflow. - - Parameters - ---------- - simulated_neutrons: - Results of a time-of-flight simulation used to create a lookup table. - The results should be a flat table with columns for time-of-arrival, speed, - wavelength, and weight. - ltotal_range: - Range of total flight path lengths from the source to the detector. - This is used to create the lookup table to compute the neutron time-of-flight. - Note that the resulting table will extend slightly beyond this range, as the - supplied range is not necessarily a multiple of the distance resolution. - pulse_stride: - Stride of used pulses. Usually 1, but may be a small integer when - pulse-skipping. - pulse_stride_offset: - Integer offset of the first pulse in the stride (typically zero unless we are - using pulse-skipping and the events do not begin with the first pulse in the - stride). - distance_resolution: - Resolution of the distance axis in the lookup table. - Should be a single scalar value with a unit of length. - This is typically of the order of 1-10 cm. - toa_resolution: - Resolution of the time of arrival axis in the lookup table. - Can be an integer (number of bins) or a sc.Variable (bin width). - error_threshold: - Threshold for the variance of the projected time-of-flight above which regions - are masked. - """ - - import sciline as sl - - pipeline = sl.Pipeline(providers()) - pipeline[SimulationResults] = simulated_neutrons - pipeline[LtotalRange] = ltotal_range - - params = default_parameters() - pipeline[PulsePeriod] = params[PulsePeriod] - pipeline[PulseStride] = pulse_stride or params[PulseStride] - pipeline[PulseStrideOffset] = pulse_stride_offset or params[PulseStrideOffset] - pipeline[DistanceResolution] = distance_resolution or params[DistanceResolution] - pipeline[TimeOfArrivalResolution] = ( - toa_resolution or params[TimeOfArrivalResolution] - ) - pipeline[LookupTableRelativeErrorThreshold] = ( - error_threshold or params[LookupTableRelativeErrorThreshold] - ) - - return pipeline - - -def cache_results( - pipeline: sciline.Pipeline, - results=(SimulationResults, MaskedTimeOfFlightLookupTable, FastestNeutron), -) -> sciline.Pipeline: - """ - Cache a list of (usually expensive to compute) intermediate results of the - time-of-flight workflow and return a new pipeline with these results computed. +class TofWorkflow: + def __init__( + self, + simulated_neutrons: SimulationResults, + ltotal_range: LtotalRange, + pulse_stride: PulseStride | None = None, + pulse_stride_offset: PulseStrideOffset | None = None, + distance_resolution: DistanceResolution | None = None, + toa_resolution: TimeOfArrivalResolution | None = None, + error_threshold: LookupTableRelativeErrorThreshold | None = None, + ): + """ + Helper class to make it easy to build a time-of-flight workflow. + + Parameters + ---------- + simulated_neutrons: + Results of a time-of-flight simulation used to create a lookup table. + The results should be a flat table with columns for time-of-arrival, speed, + wavelength, and weight. + ltotal_range: + Range of total flight path lengths from the source to the detector. + This is used to create the lookup table to compute the neutron + time-of-flight. + Note that the resulting table will extend slightly beyond this range, as the + supplied range is not necessarily a multiple of the distance resolution. + pulse_stride: + Stride of used pulses. Usually 1, but may be a small integer when + pulse-skipping. + pulse_stride_offset: + Integer offset of the first pulse in the stride (typically zero unless we + are using pulse-skipping and the events do not begin with the first pulse in + the stride). + distance_resolution: + Resolution of the distance axis in the lookup table. + Should be a single scalar value with a unit of length. + This is typically of the order of 1-10 cm. + toa_resolution: + Resolution of the time of arrival axis in the lookup table. + Can be an integer (number of bins) or a sc.Variable (bin width). + error_threshold: + Threshold for the variance of the projected time-of-flight above which + regions are masked. + """ + + import sciline as sl + + self.pipeline = sl.Pipeline(providers()) + self.pipeline[SimulationResults] = simulated_neutrons + self.pipeline[LtotalRange] = ltotal_range + + params = default_parameters() + self.pipeline[PulsePeriod] = params[PulsePeriod] + self.pipeline[PulseStride] = pulse_stride or params[PulseStride] + self.pipeline[PulseStrideOffset] = ( + pulse_stride_offset or params[PulseStrideOffset] + ) + self.pipeline[DistanceResolution] = ( + distance_resolution or params[DistanceResolution] + ) + self.pipeline[TimeOfArrivalResolution] = ( + toa_resolution or params[TimeOfArrivalResolution] + ) + self.pipeline[LookupTableRelativeErrorThreshold] = ( + error_threshold or params[LookupTableRelativeErrorThreshold] + ) - Parameters - ---------- - pipeline: - Time-of-flight workflow pipeline. - results: - List of results to cache. - """ - out = pipeline.copy() - for t in results: - out[t] = out.compute(t) - return out + def cache_results( + self, + results=(SimulationResults, MaskedTimeOfFlightLookupTable, FastestNeutron), + ) -> None: + """ + Cache a list of (usually expensive to compute) intermediate results of the + time-of-flight workflow and return a new pipeline with these results computed. + + Parameters + ---------- + results: + List of results to cache. + """ + for t in results: + self.pipeline[t] = self.pipeline.compute(t) From fa405bae5385cf967fca479613a5c78e3b9e404f Mon Sep 17 00:00:00 2001 From: Neil Vaytet Date: Tue, 28 Jan 2025 12:03:14 +0100 Subject: [PATCH 7/7] fix docstrings --- src/ess/reduce/time_of_flight/toa_to_tof.py | 71 +++++++++++---------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/src/ess/reduce/time_of_flight/toa_to_tof.py b/src/ess/reduce/time_of_flight/toa_to_tof.py index b85dee40..0bb1d50e 100644 --- a/src/ess/reduce/time_of_flight/toa_to_tof.py +++ b/src/ess/reduce/time_of_flight/toa_to_tof.py @@ -457,6 +457,41 @@ def providers() -> tuple[Callable]: class TofWorkflow: + """ + Helper class to build a time-of-flight workflow and cache the expensive part of the + computation: running the simulation and building the lookup table. + + Parameters + ---------- + simulated_neutrons: + Results of a time-of-flight simulation used to create a lookup table. + The results should be a flat table with columns for time-of-arrival, speed, + wavelength, and weight. + ltotal_range: + Range of total flight path lengths from the source to the detector. + This is used to create the lookup table to compute the neutron + time-of-flight. + Note that the resulting table will extend slightly beyond this range, as the + supplied range is not necessarily a multiple of the distance resolution. + pulse_stride: + Stride of used pulses. Usually 1, but may be a small integer when + pulse-skipping. + pulse_stride_offset: + Integer offset of the first pulse in the stride (typically zero unless we + are using pulse-skipping and the events do not begin with the first pulse in + the stride). + distance_resolution: + Resolution of the distance axis in the lookup table. + Should be a single scalar value with a unit of length. + This is typically of the order of 1-10 cm. + toa_resolution: + Resolution of the time of arrival axis in the lookup table. + Can be an integer (number of bins) or a sc.Variable (bin width). + error_threshold: + Threshold for the variance of the projected time-of-flight above which + regions are masked. + """ + def __init__( self, simulated_neutrons: SimulationResults, @@ -467,40 +502,6 @@ def __init__( toa_resolution: TimeOfArrivalResolution | None = None, error_threshold: LookupTableRelativeErrorThreshold | None = None, ): - """ - Helper class to make it easy to build a time-of-flight workflow. - - Parameters - ---------- - simulated_neutrons: - Results of a time-of-flight simulation used to create a lookup table. - The results should be a flat table with columns for time-of-arrival, speed, - wavelength, and weight. - ltotal_range: - Range of total flight path lengths from the source to the detector. - This is used to create the lookup table to compute the neutron - time-of-flight. - Note that the resulting table will extend slightly beyond this range, as the - supplied range is not necessarily a multiple of the distance resolution. - pulse_stride: - Stride of used pulses. Usually 1, but may be a small integer when - pulse-skipping. - pulse_stride_offset: - Integer offset of the first pulse in the stride (typically zero unless we - are using pulse-skipping and the events do not begin with the first pulse in - the stride). - distance_resolution: - Resolution of the distance axis in the lookup table. - Should be a single scalar value with a unit of length. - This is typically of the order of 1-10 cm. - toa_resolution: - Resolution of the time of arrival axis in the lookup table. - Can be an integer (number of bins) or a sc.Variable (bin width). - error_threshold: - Threshold for the variance of the projected time-of-flight above which - regions are masked. - """ - import sciline as sl self.pipeline = sl.Pipeline(providers()) @@ -529,7 +530,7 @@ def cache_results( ) -> None: """ Cache a list of (usually expensive to compute) intermediate results of the - time-of-flight workflow and return a new pipeline with these results computed. + time-of-flight workflow. Parameters ----------