amor-eos 3.2.8__tar.gz → 3.3.1__tar.gz

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.
Files changed (42) hide show
  1. {amor_eos-3.2.8 → amor_eos-3.3.1}/PKG-INFO +5 -1
  2. {amor_eos-3.2.8 → amor_eos-3.3.1}/amor_eos.egg-info/PKG-INFO +5 -1
  3. {amor_eos-3.2.8 → amor_eos-3.3.1}/amor_eos.egg-info/SOURCES.txt +1 -0
  4. {amor_eos-3.2.8 → amor_eos-3.3.1}/amor_eos.egg-info/requires.txt +4 -0
  5. {amor_eos-3.2.8 → amor_eos-3.3.1}/eos/__init__.py +2 -2
  6. amor_eos-3.3.1/eos/compat.py +44 -0
  7. {amor_eos-3.2.8 → amor_eos-3.3.1}/eos/event_data_types.py +7 -0
  8. {amor_eos-3.2.8 → amor_eos-3.3.1}/eos/event_handling.py +27 -16
  9. {amor_eos-3.2.8 → amor_eos-3.3.1}/eos/file_reader.py +199 -75
  10. {amor_eos-3.2.8 → amor_eos-3.3.1}/eos/options.py +4 -4
  11. {amor_eos-3.2.8 → amor_eos-3.3.1}/eos/projection.py +9 -8
  12. {amor_eos-3.2.8 → amor_eos-3.3.1}/eos/reduction_e2h.py +1 -8
  13. amor_eos-3.3.1/eos/reduction_kafka.py +203 -0
  14. {amor_eos-3.2.8 → amor_eos-3.3.1}/eos/reduction_reflectivity.py +16 -11
  15. {amor_eos-3.2.8 → amor_eos-3.3.1}/setup.cfg +4 -0
  16. {amor_eos-3.2.8 → amor_eos-3.3.1}/tests/test_event_handling.py +12 -6
  17. {amor_eos-3.2.8 → amor_eos-3.3.1}/tests/test_full_analysis.py +28 -0
  18. amor_eos-3.2.8/eos/reduction_kafka.py +0 -128
  19. {amor_eos-3.2.8 → amor_eos-3.3.1}/LICENSE +0 -0
  20. {amor_eos-3.2.8 → amor_eos-3.3.1}/README.rst +0 -0
  21. {amor_eos-3.2.8 → amor_eos-3.3.1}/amor_eos.egg-info/dependency_links.txt +0 -0
  22. {amor_eos-3.2.8 → amor_eos-3.3.1}/amor_eos.egg-info/entry_points.txt +0 -0
  23. {amor_eos-3.2.8 → amor_eos-3.3.1}/amor_eos.egg-info/top_level.txt +0 -0
  24. {amor_eos-3.2.8 → amor_eos-3.3.1}/eos/__main__.py +0 -0
  25. {amor_eos-3.2.8 → amor_eos-3.3.1}/eos/command_line.py +0 -0
  26. {amor_eos-3.2.8 → amor_eos-3.3.1}/eos/const.py +0 -0
  27. {amor_eos-3.2.8 → amor_eos-3.3.1}/eos/e2h.py +0 -0
  28. {amor_eos-3.2.8 → amor_eos-3.3.1}/eos/event_analysis.py +0 -0
  29. {amor_eos-3.2.8 → amor_eos-3.3.1}/eos/header.py +0 -0
  30. {amor_eos-3.2.8 → amor_eos-3.3.1}/eos/helpers.py +0 -0
  31. {amor_eos-3.2.8 → amor_eos-3.3.1}/eos/helpers_fallback.py +0 -0
  32. {amor_eos-3.2.8 → amor_eos-3.3.1}/eos/helpers_numba.py +0 -0
  33. {amor_eos-3.2.8 → amor_eos-3.3.1}/eos/instrument.py +0 -0
  34. {amor_eos-3.2.8 → amor_eos-3.3.1}/eos/kafka_events.py +0 -0
  35. {amor_eos-3.2.8 → amor_eos-3.3.1}/eos/kafka_serializer.py +0 -0
  36. {amor_eos-3.2.8 → amor_eos-3.3.1}/eos/logconfig.py +0 -0
  37. {amor_eos-3.2.8 → amor_eos-3.3.1}/eos/ls.py +0 -0
  38. {amor_eos-3.2.8 → amor_eos-3.3.1}/eos/nicos.py +0 -0
  39. {amor_eos-3.2.8 → amor_eos-3.3.1}/eos/nicos_interface.py +0 -0
  40. {amor_eos-3.2.8 → amor_eos-3.3.1}/eos/normalization.py +0 -0
  41. {amor_eos-3.2.8 → amor_eos-3.3.1}/eos/path_handling.py +0 -0
  42. {amor_eos-3.2.8 → amor_eos-3.3.1}/pyproject.toml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: amor_eos
3
- Version: 3.2.8
3
+ Version: 3.3.1
4
4
  Summary: EOS reflectometry reduction for AMOR instrument
5
5
  Author: Jochen Stahn - Paul Scherrer Institut
6
6
  Author-email: jochen.stahn@psi.ch
@@ -16,6 +16,10 @@ Requires-Dist: numpy
16
16
  Requires-Dist: h5py
17
17
  Requires-Dist: orsopy
18
18
  Requires-Dist: numba
19
+ Requires-Dist: matplotlib
20
+ Requires-Dist: tabulate
21
+ Requires-Dist: ess-streaming-data-types
22
+ Requires-Dist: confluent-kafka
19
23
  Requires-Dist: backports.strenum; python_version < "3.11"
20
24
  Requires-Dist: backports.zoneinfo; python_version < "3.9"
21
25
  Dynamic: license-file
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: amor_eos
3
- Version: 3.2.8
3
+ Version: 3.3.1
4
4
  Summary: EOS reflectometry reduction for AMOR instrument
5
5
  Author: Jochen Stahn - Paul Scherrer Institut
6
6
  Author-email: jochen.stahn@psi.ch
@@ -16,6 +16,10 @@ Requires-Dist: numpy
16
16
  Requires-Dist: h5py
17
17
  Requires-Dist: orsopy
18
18
  Requires-Dist: numba
19
+ Requires-Dist: matplotlib
20
+ Requires-Dist: tabulate
21
+ Requires-Dist: ess-streaming-data-types
22
+ Requires-Dist: confluent-kafka
19
23
  Requires-Dist: backports.strenum; python_version < "3.11"
20
24
  Requires-Dist: backports.zoneinfo; python_version < "3.9"
21
25
  Dynamic: license-file
@@ -11,6 +11,7 @@ amor_eos.egg-info/top_level.txt
11
11
  eos/__init__.py
12
12
  eos/__main__.py
13
13
  eos/command_line.py
14
+ eos/compat.py
14
15
  eos/const.py
15
16
  eos/e2h.py
16
17
  eos/event_analysis.py
@@ -2,6 +2,10 @@ numpy
2
2
  h5py
3
3
  orsopy
4
4
  numba
5
+ matplotlib
6
+ tabulate
7
+ ess-streaming-data-types
8
+ confluent-kafka
5
9
 
6
10
  [:python_version < "3.11"]
7
11
  backports.strenum
@@ -2,5 +2,5 @@
2
2
  Package to handle data redction at AMOR instrument to be used by __main__.py script.
3
3
  """
4
4
 
5
- __version__ = '3.2.8'
6
- __date__ = '2026-03-18'
5
+ __version__ = '3.3.1'
6
+ __date__ = '2026-07-09'
@@ -0,0 +1,44 @@
1
+ """
2
+ Presever compatibility with previous versions of AMOR datafiles.
3
+ """
4
+
5
+ from datetime import datetime
6
+
7
+ # old hdf parameter mappings, key is last date of validity
8
+ legacy_hdf_paths = {
9
+ datetime(2026, 3, 18).timestamp():
10
+ dict(
11
+ title=('entry1/title', str),
12
+ proposal_id=('entry1/proposal_id', str),
13
+ user_name=('entry1/user/name', str),
14
+ user_email=('entry1/user/email', str),
15
+ sample_name=('entry1/sample/name', str),
16
+ source_name=('entry1/Amor/source/name', str),
17
+ sample_model=('entry1/sample/model', str),
18
+ start_time=('entry1/start_time', str),
19
+ start_time_fallback=('entry1/Amor/instrument_control_parameters/start_time', str),
20
+
21
+ chopper_separation=('entry1/Amor/chopper/pair_separation', float),
22
+ detector_distance=('entry1/Amor/detector/transformation/distance', float),
23
+ chopper_distance=('entry1/Amor/chopper/distance', float),
24
+ sample_temperature=('entry1/sample/temperature', float),
25
+ sample_magnetic_field=('entry1/sample/magnetic_field', float),
26
+
27
+ mu=('entry1/Amor/instrument_control_parameters/mu', float, 'mu'),
28
+ nu=('entry1/Amor/instrument_control_parameters/nu', float, 'nu'),
29
+ kap=('entry1/Amor/instrument_control_parameters/kappa', float, 'kappa'),
30
+ kad=('entry1/Amor/instrument_control_parameters/kappa_offset', float, 'kappa_offset'),
31
+ div=('entry1/Amor/instrument_control_parameters/div', float, 'div'),
32
+ ch1_trigger_phase=('entry1/Amor/chopper/ch1_trigger_phase', float, 'ch1_trigger_phase'),
33
+ ch2_trigger_phase=('entry1/Amor/chopper/ch2_trigger_phase', float, 'ch2_trigger_phase'),
34
+ chopper_speed=('entry1/Amor/chopper/rotation_speed', float, 'chopper_phase'),
35
+ chopper_phase=('entry1/Amor/chopper/phase', float, 'chopper_phase'),
36
+ polarization_config_label=('entry1/Amor/polarization/configuration', int, 'polarization_config_label', '/*'),
37
+
38
+ data=('entry1/Amor/detector/data', None), # data group used to load events from
39
+ trigger=('entry1/Amor/chopper/ch2_trigger', float),
40
+ proton_current=('entry1/Amor/detector/proton_current', None),
41
+ ),
42
+ }
43
+ # create a sorted list of validity timestamps for quick comparison
44
+ legacy_cutoffs = list(sorted(legacy_hdf_paths.keys()))
@@ -29,11 +29,17 @@ class AmorTiming:
29
29
  chopperPhase: float
30
30
  tau: float
31
31
 
32
+ @dataclass
33
+ class DA00EventBuffer:
34
+ signal: np.ndarray
35
+ time: np.ndarray
36
+
32
37
  # Structured datatypes used for event streams
33
38
  EVENT_TYPE = np.dtype([('tof', np.float64), ('pixelID', np.uint32), ('mask', np.int32)])
34
39
  PACKET_TYPE = np.dtype([('start_index', np.uint32), ('time', np.int64)])
35
40
  PULSE_TYPE = np.dtype([('time', np.int64), ('monitor', np.float32)])
36
41
  PC_TYPE = np.dtype([('current', np.float32), ('time', np.int64)])
42
+ BM_TYPE = np.dtype([('value', np.int32), ('time', np.int64)])
37
43
  LOG_TYPE = np.dtype([('value', np.float32), ('time', np.int64)])
38
44
 
39
45
  # define the bitmask for individual event filters
@@ -63,6 +69,7 @@ class AmorEventStream:
63
69
  packets: np.recarray # PACKET_TYPE
64
70
  pulses: np.recarray # PULSE_TYPE
65
71
  proton_current: np.recarray # PC_TYPE
72
+ beam_monitor: Optional[np.recarray] = None # BM_TYPE
66
73
  device_logs: Dict[str, np.recarray] = field(default_factory=dict) # LOG_TYPE
67
74
 
68
75
  class EventDatasetProtocol(Protocol):
@@ -91,6 +91,16 @@ class AssociatePulseWithMonitor(EventDataAction):
91
91
  * 2*dataset.timing.tau * 1e-3
92
92
  elif self.monitorType==MonitorType.time:
93
93
  dataset.data.pulses.monitor = 2*dataset.timing.tau
94
+ elif self.monitorType==MonitorType.neutron_monitor:
95
+ if dataset.data.pulses.monitor is None:
96
+ logging.warning(" Neutron monitor was selected for normalization but not presend, "
97
+ "falling back to proton current")
98
+ dataset.data.pulses.monitor = self.get_current_per_pulse(dataset.data.pulses.time,
99
+ dataset.data.proton_current.time,
100
+ dataset.data.proton_current.current) \
101
+ *2*dataset.timing.tau*1e-3
102
+ else:
103
+ dataset.data.pulses.monitor = dataset.data.beam_monitor.value / 1e4
94
104
  else: # pulses
95
105
  dataset.data.pulses.monitor = 1
96
106
 
@@ -184,21 +194,22 @@ class ApplyMask(EventDataAction):
184
194
  fltr = (d.events.mask & (~self.bitmask_filter)) == 0
185
195
  d.events = d.events[fltr]
186
196
  post_filter = d.events.shape[0]
187
- logging.info(f' number of events: total = {pre_filter:7d}, filtered = {post_filter:7d}')
197
+ logging.info(f' number of events: total = {pre_filter:7d}, after filtering = {post_filter:7d}')
188
198
  if d.device_logs == {} or not hasattr(dataset, 'update_info_from_logs'):
189
199
  return
190
- # filter pulses and logs to allow update of header information
191
- from .helpers import add_log_to_pulses
192
- times = np.unique(d.events.wallTime)
193
- # make sure all log variables are associated with pulses
194
- for key, log in d.device_logs.items():
195
- if not key in d.pulses.dtype.names:
196
- # interpolate the parameter values for all existing pulses
197
- add_log_to_pulses(key, dataset)
198
- # remove all pulses that have no more events
199
- d.pulses = d.pulses[np.isin(d.pulses.time, times)]
200
- for key, log in d.device_logs.items():
201
- d.device_logs[key] = np.recarray(d.pulses.shape, dtype = log.dtype)
202
- d.device_logs[key].time = d.pulses.time
203
- d.device_logs[key].value = d.pulses[key]
204
- dataset.update_info_from_logs()
200
+ if 'wallTime' in d.events.dtype.names:
201
+ # filter pulses and logs to allow update of header information
202
+ from .helpers import add_log_to_pulses
203
+ times = np.unique(d.events.wallTime)
204
+ # make sure all log variables are associated with pulses
205
+ for key, log in d.device_logs.items():
206
+ if not key in d.pulses.dtype.names:
207
+ # interpolate the parameter values for all existing pulses
208
+ add_log_to_pulses(key, dataset)
209
+ # remove all pulses that have no more events
210
+ d.pulses = d.pulses[np.isin(d.pulses.time, times)]
211
+ for key, log in d.device_logs.items():
212
+ d.device_logs[key] = np.recarray(d.pulses.shape, dtype = log.dtype)
213
+ d.device_logs[key].time = d.pulses.time
214
+ d.device_logs[key].value = d.pulses[key]
215
+ dataset.update_info_from_logs()