essreduce 25.5.2__py3-none-any.whl → 25.7.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,6 @@
1
1
  # SPDX-License-Identifier: BSD-3-Clause
2
2
  # Copyright (c) 2025 Scipp contributors (https://github.com/scipp)
3
3
 
4
- from dataclasses import dataclass
5
4
  from typing import NewType
6
5
 
7
6
  import sciline as sl
@@ -9,81 +8,6 @@ import scipp as sc
9
8
 
10
9
  from ..nexus.types import MonitorType, RunType
11
10
 
12
-
13
- @dataclass
14
- class SimulationResults:
15
- """
16
- Results of a time-of-flight simulation used to create a lookup table.
17
-
18
- The results (apart from ``distance``) should be flat lists (1d arrays) of length N
19
- where N is the number of neutrons, containing the properties of the neutrons in the
20
- simulation.
21
-
22
- Parameters
23
- ----------
24
- time_of_arrival:
25
- Time of arrival of the neutrons at the position where the events were recorded
26
- (1d array of size N).
27
- speed:
28
- Speed of the neutrons, typically derived from the wavelength of the neutrons
29
- (1d array of size N).
30
- wavelength:
31
- Wavelength of the neutrons (1d array of size N).
32
- weight:
33
- Weight/probability of the neutrons (1d array of size N).
34
- distance:
35
- Distance from the source to the position where the events were recorded
36
- (single value; we assume all neutrons were recorded at the same position).
37
- For a ``tof`` simulation, this is just the position of the detector where the
38
- events are recorded. For a ``McStas`` simulation, this is the distance between
39
- the source and the event monitor.
40
- """
41
-
42
- time_of_arrival: sc.Variable
43
- speed: sc.Variable
44
- wavelength: sc.Variable
45
- weight: sc.Variable
46
- distance: sc.Variable
47
-
48
-
49
- NumberOfSimulatedNeutrons = NewType("NumberOfSimulatedNeutrons", int)
50
- """
51
- Number of neutrons simulated in the simulation that is used to create the lookup table.
52
- This is typically a large number, e.g., 1e6 or 1e7.
53
- """
54
-
55
- LtotalRange = NewType("LtotalRange", tuple[sc.Variable, sc.Variable])
56
- """
57
- Range (min, max) of the total length of the flight path from the source to the detector.
58
- This is used to create the lookup table to compute the neutron time-of-flight.
59
- Note that the resulting table will extend slightly beyond this range, as the supplied
60
- range is not necessarily a multiple of the distance resolution.
61
-
62
- Note also that the range of total flight paths is supplied manually to the workflow
63
- instead of being read from the input data, as it allows us to compute the expensive part
64
- of the workflow in advance (the lookup table) and does not need to be repeated for each
65
- run, or for new data coming in in the case of live data collection.
66
- """
67
-
68
- DistanceResolution = NewType("DistanceResolution", sc.Variable)
69
- """
70
- Step size of the distance axis in the lookup table.
71
- Should be a single scalar value with a unit of length.
72
- This is typically of the order of 1-10 cm.
73
- """
74
-
75
- TimeResolution = NewType("TimeResolution", sc.Variable)
76
- """
77
- Step size of the event_time_offset axis in the lookup table.
78
- This is basically the 'time-of-flight' resolution of the detector.
79
- Should be a single scalar value with a unit of time.
80
- This is typically of the order of 0.1-0.5 ms.
81
-
82
- Since the event_time_offset range needs to span exactly one pulse period, the final
83
- resolution in the lookup table will be at least the supplied value here, but may be
84
- smaller if the pulse period is not an integer multiple of the time resolution.
85
- """
86
-
87
11
  TimeOfFlightLookupTableFilename = NewType("TimeOfFlightLookupTableFilename", str)
88
12
  """Filename of the time-of-flight lookup table."""
89
13
 
@@ -93,21 +17,6 @@ TimeOfFlightLookupTable = NewType("TimeOfFlightLookupTable", sc.DataArray)
93
17
  Lookup table giving time-of-flight as a function of distance and time of arrival.
94
18
  """
95
19
 
96
- LookupTableRelativeErrorThreshold = NewType("LookupTableRelativeErrorThreshold", float)
97
- """
98
- Threshold for the relative standard deviation (coefficient of variation) of the
99
- projected time-of-flight above which values are masked.
100
- """
101
-
102
- PulsePeriod = NewType("PulsePeriod", sc.Variable)
103
- """
104
- Period of the source pulses, i.e., time between consecutive pulse starts.
105
- """
106
-
107
- PulseStride = NewType("PulseStride", int)
108
- """
109
- Stride of used pulses. Usually 1, but may be a small integer when pulse-skipping.
110
- """
111
20
 
112
21
  PulseStrideOffset = NewType("PulseStrideOffset", int | None)
113
22
  """
@@ -130,43 +39,3 @@ class DetectorTofData(sl.Scope[RunType, sc.DataArray], sc.DataArray):
130
39
 
131
40
  class MonitorTofData(sl.Scope[RunType, MonitorType, sc.DataArray], sc.DataArray):
132
41
  """Monitor data with time-of-flight coordinate."""
133
-
134
-
135
- class ResampledDetectorTofData(sl.Scope[RunType, sc.DataArray], sc.DataArray):
136
- """
137
- Histogrammed detector data with time-of-flight coordinate, that has been resampled.
138
-
139
- Histogrammed data that has been converted to `tof` will typically have
140
- unsorted bin edges (due to either wrapping of `time_of_flight` or wavelength
141
- overlap between subframes).
142
- We thus resample the data to ensure that the bin edges are sorted.
143
- It makes use of the ``to_events`` helper which generates a number of events in each
144
- bin with a uniform distribution. The new events are then histogrammed using a set of
145
- sorted bin edges to yield a new histogram with sorted bin edges.
146
-
147
- WARNING:
148
- This function is highly experimental, has limitations and should be used with
149
- caution. It is a workaround to the issue that rebinning data with unsorted bin
150
- edges is not supported in scipp.
151
- """
152
-
153
-
154
- class ResampledMonitorTofData(
155
- sl.Scope[RunType, MonitorType, sc.DataArray], sc.DataArray
156
- ):
157
- """
158
- Histogrammed monitor data with time-of-flight coordinate, that has been resampled.
159
-
160
- Histogrammed data that has been converted to `tof` will typically have
161
- unsorted bin edges (due to either wrapping of `time_of_flight` or wavelength
162
- overlap between subframes).
163
- We thus resample the data to ensure that the bin edges are sorted.
164
- It makes use of the ``to_events`` helper which generates a number of events in each
165
- bin with a uniform distribution. The new events are then histogrammed using a set of
166
- sorted bin edges to yield a new histogram with sorted bin edges.
167
-
168
- WARNING:
169
- This function is highly experimental, has limitations and should be used with
170
- caution. It is a workaround to the issue that rebinning data with unsorted bin
171
- edges is not supported in scipp.
172
- """
@@ -1,22 +1,17 @@
1
1
  # SPDX-License-Identifier: BSD-3-Clause
2
2
  # Copyright (c) 2025 Scipp contributors (https://github.com/scipp)
3
3
  from collections.abc import Iterable
4
- from enum import Enum, auto
5
4
 
6
5
  import sciline
7
6
  import scipp as sc
8
7
 
9
8
  from ..nexus import GenericNeXusWorkflow
10
- from . import eto_to_tof, simulation
11
- from .types import TimeOfFlightLookupTable, TimeOfFlightLookupTableFilename
12
-
13
-
14
- class TofLutProvider(Enum):
15
- """Provider for the time-of-flight lookup table."""
16
-
17
- FILE = auto() # From file
18
- TOF = auto() # Computed with 'tof' package from chopper settings
19
- MCSTAS = auto() # McStas simulation (not implemented yet)
9
+ from . import eto_to_tof
10
+ from .types import (
11
+ PulseStrideOffset,
12
+ TimeOfFlightLookupTable,
13
+ TimeOfFlightLookupTableFilename,
14
+ )
20
15
 
21
16
 
22
17
  def load_tof_lookup_table(
@@ -29,11 +24,11 @@ def GenericTofWorkflow(
29
24
  *,
30
25
  run_types: Iterable[sciline.typing.Key],
31
26
  monitor_types: Iterable[sciline.typing.Key],
32
- tof_lut_provider: TofLutProvider = TofLutProvider.FILE,
33
27
  ) -> sciline.Pipeline:
34
28
  """
35
29
  Generic workflow for computing the neutron time-of-flight for detector and monitor
36
30
  data.
31
+
37
32
  This workflow builds on the ``GenericNeXusWorkflow`` and computes time-of-flight
38
33
  from a lookup table that is created from the chopper settings, detector Ltotal and
39
34
  the neutron time-of-arrival.
@@ -58,11 +53,6 @@ def GenericTofWorkflow(
58
53
  List of monitor types to include in the workflow.
59
54
  Constrains the possible values of :class:`ess.reduce.nexus.types.MonitorType`
60
55
  and :class:`ess.reduce.nexus.types.Component`.
61
- tof_lut_provider:
62
- Specifies how the time-of-flight lookup table is provided:
63
- - FILE: Read from a file
64
- - TOF: Computed from chopper settings using the 'tof' package
65
- - MCSTAS: From McStas simulation (not implemented yet)
66
56
 
67
57
  Returns
68
58
  -------
@@ -74,16 +64,9 @@ def GenericTofWorkflow(
74
64
  for provider in eto_to_tof.providers():
75
65
  wf.insert(provider)
76
66
 
77
- if tof_lut_provider == TofLutProvider.FILE:
78
- wf.insert(load_tof_lookup_table)
79
- else:
80
- wf.insert(eto_to_tof.compute_tof_lookup_table)
81
- if tof_lut_provider == TofLutProvider.TOF:
82
- wf.insert(simulation.simulate_chopper_cascade_using_tof)
83
- if tof_lut_provider == TofLutProvider.MCSTAS:
84
- raise NotImplementedError("McStas simulation not implemented yet")
67
+ wf.insert(load_tof_lookup_table)
85
68
 
86
- for key, value in eto_to_tof.default_parameters().items():
87
- wf[key] = value
69
+ # Default parameters
70
+ wf[PulseStrideOffset] = None
88
71
 
89
72
  return wf
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: essreduce
3
- Version: 25.5.2
3
+ Version: 25.7.0
4
4
  Summary: Common data reduction tools for the ESS facility
5
5
  Author: Scipp contributors
6
6
  License: BSD 3-Clause License
@@ -18,15 +18,15 @@ ess/reduce/nexus/json_nexus.py,sha256=QrVc0p424nZ5dHX9gebAJppTw6lGZq9404P_OFl1gi
18
18
  ess/reduce/nexus/types.py,sha256=DE82JnbgpTlQnt7UN2a2Gur2N9QupV3CDL9j4Iy4lsE,9178
19
19
  ess/reduce/nexus/workflow.py,sha256=Ytt80-muk5EiXmip890ahb_m5DQqlTGRQUyaTVXRNzo,24568
20
20
  ess/reduce/scripts/grow_nexus.py,sha256=hET3h06M0xlJd62E3palNLFvJMyNax2kK4XyJcOhl-I,3387
21
- ess/reduce/time_of_flight/__init__.py,sha256=UxMvY4aFkhZQmIbGSo4FBpBGRD2wDJbczLMVqcEhCSg,1583
22
- ess/reduce/time_of_flight/eto_to_tof.py,sha256=JCu7C3AmJnB7GDJrL76oPjgxGesp67nct9xXRp3O8E4,28204
21
+ ess/reduce/time_of_flight/__init__.py,sha256=bhteT_xvkRYBh_oeJZTzCtiPg0WSW_TRrtm_xzGbzw4,1441
22
+ ess/reduce/time_of_flight/eto_to_tof.py,sha256=pkxtj1Gg0b2aF9Ryr2vL8PeL8RdujuzWbcp1L4TMghU,14712
23
23
  ess/reduce/time_of_flight/fakes.py,sha256=0gtbSX3ZQilaM4ZP5dMr3fqbnhpyoVsZX2YEb8GgREE,4489
24
24
  ess/reduce/time_of_flight/interpolator_numba.py,sha256=wh2YS3j2rOu30v1Ok3xNHcwS7t8eEtZyZvbfXOCtgrQ,3835
25
25
  ess/reduce/time_of_flight/interpolator_scipy.py,sha256=_InoAPuMm2qhJKZQBAHOGRFqtvvuQ8TStoN7j_YgS4M,1853
26
- ess/reduce/time_of_flight/simulation.py,sha256=vo-zjG6t-PLetv2_nj4dhMSTEyTQ1MsrhlM2XkhOtf8,3632
27
- ess/reduce/time_of_flight/to_events.py,sha256=w9mHpnWd3vwN2ouob-GK_1NPrTjCaOzPuC2QuEey-m0,4342
28
- ess/reduce/time_of_flight/types.py,sha256=OQeMYNN7QinXs_HDcoE6kkh_xNcyD0dEJWtnHQy5-uA,6675
29
- ess/reduce/time_of_flight/workflow.py,sha256=mwNEXwvOnm-M8n4G9Cau1Vuyqzo4qMrhCbZ-S5vszW4,3181
26
+ ess/reduce/time_of_flight/lut.py,sha256=ylZbnf6LeOUzkBkUbLCudeqVfh-Gtf9M-z8PS-l9Db4,18719
27
+ ess/reduce/time_of_flight/resample.py,sha256=Opmi-JA4zNH725l9VB99U4O9UlM37f5ACTCGtwBcows,3718
28
+ ess/reduce/time_of_flight/types.py,sha256=EroKBxi4WUErNx8d200jh8kqkhwtjAGKIV7PvBUwAJs,1310
29
+ ess/reduce/time_of_flight/workflow.py,sha256=mkgESvQ5Yt3CyAsa1iewkjBOHUqrHm5rRc1EhOQRewQ,2213
30
30
  ess/reduce/widgets/__init__.py,sha256=SoSHBv8Dc3QXV9HUvPhjSYWMwKTGYZLpsWwsShIO97Q,5325
31
31
  ess/reduce/widgets/_base.py,sha256=_wN3FOlXgx_u0c-A_3yyoIH-SdUvDENGgquh9S-h5GI,4852
32
32
  ess/reduce/widgets/_binedges_widget.py,sha256=ZCQsGjYHnJr9GFUn7NjoZc1CdsnAzm_fMzyF-fTKKVY,2785
@@ -39,9 +39,9 @@ ess/reduce/widgets/_spinner.py,sha256=2VY4Fhfa7HMXox2O7UbofcdKsYG-AJGrsgGJB85nDX
39
39
  ess/reduce/widgets/_string_widget.py,sha256=iPAdfANyXHf-nkfhgkyH6gQDklia0LebLTmwi3m-iYQ,1482
40
40
  ess/reduce/widgets/_switchable_widget.py,sha256=fjKz99SKLhIF1BLgGVBSKKn3Lu_jYBwDYGeAjbJY3Q8,2390
41
41
  ess/reduce/widgets/_vector_widget.py,sha256=aTaBqCFHZQhrIoX6-sSqFWCPePEW8HQt5kUio8jP1t8,1203
42
- essreduce-25.5.2.dist-info/licenses/LICENSE,sha256=nVEiume4Qj6jMYfSRjHTM2jtJ4FGu0g-5Sdh7osfEYw,1553
43
- essreduce-25.5.2.dist-info/METADATA,sha256=LNEHFWDdswQNdu6s_5_eVHlmkVz35siN2fvirZ0KhFI,3768
44
- essreduce-25.5.2.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
45
- essreduce-25.5.2.dist-info/entry_points.txt,sha256=PMZOIYzCifHMTe4pK3HbhxUwxjFaZizYlLD0td4Isb0,66
46
- essreduce-25.5.2.dist-info/top_level.txt,sha256=0JxTCgMKPLKtp14wb1-RKisQPQWX7i96innZNvHBr-s,4
47
- essreduce-25.5.2.dist-info/RECORD,,
42
+ essreduce-25.7.0.dist-info/licenses/LICENSE,sha256=nVEiume4Qj6jMYfSRjHTM2jtJ4FGu0g-5Sdh7osfEYw,1553
43
+ essreduce-25.7.0.dist-info/METADATA,sha256=3qNSqqDpvL6iuZoOlcFiI1P6Vyhse0kfAn7K3oeEhxw,3768
44
+ essreduce-25.7.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
45
+ essreduce-25.7.0.dist-info/entry_points.txt,sha256=PMZOIYzCifHMTe4pK3HbhxUwxjFaZizYlLD0td4Isb0,66
46
+ essreduce-25.7.0.dist-info/top_level.txt,sha256=0JxTCgMKPLKtp14wb1-RKisQPQWX7i96innZNvHBr-s,4
47
+ essreduce-25.7.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.8.0)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,108 +0,0 @@
1
- # SPDX-License-Identifier: BSD-3-Clause
2
- # Copyright (c) 2025 Scipp contributors (https://github.com/scipp)
3
- from collections.abc import Mapping
4
-
5
- import scipp as sc
6
- import scippnexus as snx
7
- from scippneutron.chopper import DiskChopper
8
-
9
- from ..nexus.types import DiskChoppers, Position, SampleRun
10
- from .types import NumberOfSimulatedNeutrons, SimulationResults
11
-
12
-
13
- def simulate_beamline(
14
- *,
15
- choppers: Mapping[str, DiskChopper],
16
- source_position: sc.Variable,
17
- neutrons: int = 1_000_000,
18
- pulses: int = 1,
19
- seed: int | None = None,
20
- facility: str = 'ess',
21
- ) -> SimulationResults:
22
- """
23
- Simulate a pulse of neutrons propagating through a chopper cascade using the
24
- ``tof`` package (https://tof.readthedocs.io).
25
-
26
- Parameters
27
- ----------
28
- choppers:
29
- A dict of DiskChopper objects representing the choppers in the beamline. See
30
- https://scipp.github.io/scippneutron/user-guide/chopper/processing-nexus-choppers.html#Build-DiskChopper
31
- for more information.
32
- source_position:
33
- A scalar variable with ``dtype=vector3`` that defines the source position.
34
- Must be in the same coordinate system as the choppers' axle positions.
35
- neutrons:
36
- Number of neutrons to simulate.
37
- pulses:
38
- Number of pulses to simulate.
39
- seed:
40
- Seed for the random number generator used in the simulation.
41
- facility:
42
- Facility where the experiment is performed.
43
- """
44
- import tof
45
-
46
- tof_choppers = [
47
- tof.Chopper(
48
- frequency=abs(ch.frequency),
49
- direction=tof.AntiClockwise
50
- if (ch.frequency.value > 0.0)
51
- else tof.Clockwise,
52
- open=ch.slit_begin,
53
- close=ch.slit_end,
54
- phase=abs(ch.phase),
55
- distance=sc.norm(
56
- ch.axle_position - source_position.to(unit=ch.axle_position.unit)
57
- ),
58
- name=name,
59
- )
60
- for name, ch in choppers.items()
61
- ]
62
- source = tof.Source(facility=facility, neutrons=neutrons, pulses=pulses, seed=seed)
63
- if not tof_choppers:
64
- events = source.data.squeeze().flatten(to='event')
65
- return SimulationResults(
66
- time_of_arrival=events.coords["birth_time"],
67
- speed=events.coords["speed"],
68
- wavelength=events.coords["wavelength"],
69
- weight=events.data,
70
- distance=0.0 * sc.units.m,
71
- )
72
- model = tof.Model(source=source, choppers=tof_choppers)
73
- results = model.run()
74
- # Find name of the furthest chopper in tof_choppers
75
- furthest_chopper = max(tof_choppers, key=lambda c: c.distance)
76
- events = results[furthest_chopper.name].data.squeeze().flatten(to='event')
77
- events = events[
78
- ~(events.masks["blocked_by_others"] | events.masks["blocked_by_me"])
79
- ]
80
- return SimulationResults(
81
- time_of_arrival=events.coords["toa"],
82
- speed=events.coords["speed"],
83
- wavelength=events.coords["wavelength"],
84
- weight=events.data,
85
- distance=furthest_chopper.distance,
86
- )
87
-
88
-
89
- def simulate_chopper_cascade_using_tof(
90
- choppers: DiskChoppers[SampleRun],
91
- neutrons: NumberOfSimulatedNeutrons,
92
- source_position: Position[snx.NXsource, SampleRun],
93
- ) -> SimulationResults:
94
- """
95
- Simulate neutrons traveling through the chopper cascade using the ``tof`` package.
96
-
97
- Parameters
98
- ----------
99
- choppers:
100
- Chopper settings.
101
- neutrons:
102
- Number of neutrons to simulate.
103
- source_position:
104
- Position of the source.
105
- """
106
- return simulate_beamline(
107
- choppers=choppers, neutrons=neutrons, source_position=source_position
108
- )
@@ -1,111 +0,0 @@
1
- # SPDX-License-Identifier: BSD-3-Clause
2
- # Copyright (c) 2025 Scipp contributors (https://github.com/scipp)
3
-
4
- from functools import reduce
5
-
6
- import numpy as np
7
- import scipp as sc
8
-
9
-
10
- def to_events(
11
- da: sc.DataArray, event_dim: str, events_per_bin: int = 500
12
- ) -> sc.DataArray:
13
- """
14
- Convert a histogrammed data array to an event list.
15
- The generated events have a uniform distribution within each bin.
16
- Each dimension with a bin-edge coordinate is converted to an event coordinate.
17
- The contract is that if we re-histogram the event list with the same bin edges,
18
- we should get the original counts back.
19
- Masks on non-bin-edge dimensions are preserved.
20
- If there are masks on bin-edge dimensions, the masked values are zeroed out in the
21
- original data before the conversion to events.
22
-
23
- Parameters
24
- ----------
25
- da:
26
- DataArray to convert to events.
27
- event_dim:
28
- Name of the new event dimension.
29
- events_per_bin:
30
- Number of events to generate per bin.
31
- """
32
- if da.bins is not None:
33
- raise ValueError("Cannot convert a binned DataArray to events.")
34
- rng = np.random.default_rng()
35
- event_coords = {}
36
- edge_dims = []
37
- midp_dims = set(da.dims)
38
- midp_coord_names = []
39
- # Separate bin-edge and midpoints coords
40
- for name in da.coords:
41
- dims = da.coords[name].dims
42
- is_edges = False if not dims else da.coords.is_edges(name)
43
- if is_edges:
44
- if name in dims:
45
- edge_dims.append(name)
46
- midp_dims -= {name}
47
- else:
48
- midp_coord_names.append(name)
49
-
50
- edge_sizes = {dim: da.sizes[da.coords[dim].dim] for dim in edge_dims}
51
- for dim in edge_dims:
52
- coord = da.coords[dim]
53
- left = sc.broadcast(coord[dim, :-1], sizes=edge_sizes).values
54
- right = sc.broadcast(coord[dim, 1:], sizes=edge_sizes).values
55
-
56
- # The numpy.random.uniform function below does not support NaNs, so we need to
57
- # replace them with zeros, and then replace them back after the random numbers
58
- # have been generated.
59
- nans = np.isnan(left) | np.isnan(right)
60
- left = np.where(nans, 0.0, left)
61
- right = np.where(nans, 0.0, right)
62
- # Ensure left <= right
63
- left, right = np.minimum(left, right), np.maximum(left, right)
64
-
65
- # In each bin, we generate a number of events with a uniform distribution.
66
- events = rng.uniform(
67
- left, right, size=(events_per_bin, *list(edge_sizes.values()))
68
- )
69
- events[..., nans] = np.nan
70
- event_coords[dim] = sc.array(
71
- dims=[event_dim, *edge_dims], values=events, unit=coord.unit
72
- )
73
-
74
- # Find and apply masks that are on a bin-edge dimension
75
- event_masks = {}
76
- other_masks = {}
77
- edge_dims_set = set(edge_dims)
78
- for key, mask in da.masks.items():
79
- if set(mask.dims) & edge_dims_set:
80
- event_masks[key] = mask
81
- else:
82
- other_masks[key] = mask
83
-
84
- data = da.data
85
- if event_masks:
86
- inv_mask = (~reduce(lambda a, b: a | b, event_masks.values())).to(dtype=int)
87
- inv_mask.unit = ""
88
- data = data * inv_mask
89
-
90
- # Create the data counts, which are the original counts divided by the number of
91
- # events per bin
92
- sizes = {event_dim: events_per_bin} | da.sizes
93
- val = sc.broadcast(sc.values(data) / float(events_per_bin), sizes=sizes)
94
- kwargs = {"dims": sizes.keys(), "values": val.values, "unit": data.unit}
95
- if data.variances is not None:
96
- # Note here that all the events are correlated.
97
- # If we later histogram the events with different edges than the original
98
- # histogram, then neighboring bins will be correlated, and the error obtained
99
- # will be too small. It is however not clear what can be done to improve this.
100
- kwargs["variances"] = sc.broadcast(
101
- sc.variances(data) / float(events_per_bin), sizes=sizes
102
- ).values
103
- new_data = sc.array(**kwargs)
104
-
105
- new = sc.DataArray(data=new_data, coords=event_coords)
106
- new = new.transpose((*midp_dims, *edge_dims, event_dim)).flatten(
107
- dims=[*edge_dims, event_dim], to=event_dim
108
- )
109
- return new.assign_coords(
110
- {dim: da.coords[dim].copy() for dim in midp_coord_names}
111
- ).assign_masks({key: mask.copy() for key, mask in other_masks.items()})