legend-daq2lh5 1.5.0__py3-none-any.whl → 1.6.1__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.
- daq2lh5/_version.py +2 -2
- daq2lh5/buffer_processor/buffer_processor.py +8 -5
- daq2lh5/buffer_processor/lh5_buffer_processor.py +8 -5
- daq2lh5/build_raw.py +4 -3
- daq2lh5/data_decoder.py +1 -3
- daq2lh5/data_streamer.py +73 -28
- daq2lh5/fc/fc_config_decoder.py +99 -28
- daq2lh5/fc/fc_event_decoder.py +127 -137
- daq2lh5/fc/fc_eventheader_decoder.py +311 -0
- daq2lh5/fc/fc_fsp_decoder.py +885 -0
- daq2lh5/fc/fc_status_decoder.py +231 -63
- daq2lh5/fc/fc_streamer.py +153 -76
- daq2lh5/llama/llama_header_decoder.py +1 -2
- daq2lh5/orca/orca_digitizers.py +1 -1
- daq2lh5/orca/orca_fcio.py +405 -0
- daq2lh5/orca/orca_flashcam.py +7 -4
- daq2lh5/orca/orca_header.py +7 -2
- daq2lh5/orca/orca_packet.py +10 -0
- daq2lh5/orca/orca_run_decoder.py +6 -6
- daq2lh5/orca/orca_streamer.py +28 -10
- daq2lh5/orca/skim_orca_file.py +54 -0
- daq2lh5/raw_buffer.py +15 -2
- {legend_daq2lh5-1.5.0.dist-info → legend_daq2lh5-1.6.1.dist-info}/METADATA +13 -14
- legend_daq2lh5-1.6.1.dist-info/RECORD +46 -0
- {legend_daq2lh5-1.5.0.dist-info → legend_daq2lh5-1.6.1.dist-info}/WHEEL +1 -1
- legend_daq2lh5-1.6.1.dist-info/entry_points.txt +3 -0
- legend_daq2lh5-1.5.0.dist-info/RECORD +0 -42
- legend_daq2lh5-1.5.0.dist-info/entry_points.txt +0 -2
- {legend_daq2lh5-1.5.0.dist-info → legend_daq2lh5-1.6.1.dist-info}/licenses/LICENSE +0 -0
- {legend_daq2lh5-1.5.0.dist-info → legend_daq2lh5-1.6.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,405 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import copy
|
4
|
+
import logging
|
5
|
+
from typing import Any
|
6
|
+
|
7
|
+
from fcio import FCIO, Tags
|
8
|
+
|
9
|
+
from daq2lh5.fc.fc_config_decoder import FCConfigDecoder
|
10
|
+
from daq2lh5.fc.fc_event_decoder import FCEventDecoder
|
11
|
+
from daq2lh5.fc.fc_eventheader_decoder import FCEventHeaderDecoder, get_fcid, get_key
|
12
|
+
from daq2lh5.fc.fc_fsp_decoder import (
|
13
|
+
FSPConfigDecoder,
|
14
|
+
FSPEventDecoder,
|
15
|
+
FSPStatusDecoder,
|
16
|
+
)
|
17
|
+
from daq2lh5.fc.fc_status_decoder import FCStatusDecoder
|
18
|
+
from daq2lh5.fc.fc_status_decoder import get_key as get_status_key
|
19
|
+
|
20
|
+
from ..raw_buffer import RawBufferList
|
21
|
+
from .orca_base import OrcaDecoder
|
22
|
+
from .orca_header import OrcaHeader
|
23
|
+
from .orca_packet import OrcaPacket
|
24
|
+
|
25
|
+
log = logging.getLogger(__name__)
|
26
|
+
|
27
|
+
|
28
|
+
# FCIO streams are stateful and need to be accessible for all decoders.
|
29
|
+
fcio_stream_library = dict()
|
30
|
+
|
31
|
+
|
32
|
+
def get_fcio_stream(streamid):
|
33
|
+
if streamid in fcio_stream_library:
|
34
|
+
return fcio_stream_library[streamid]
|
35
|
+
else:
|
36
|
+
fcio_stream_library[streamid] = FCIO()
|
37
|
+
return fcio_stream_library[streamid]
|
38
|
+
|
39
|
+
|
40
|
+
def extract_header_information(header: OrcaHeader):
|
41
|
+
|
42
|
+
fc_hdr_info = {
|
43
|
+
"key_list": {},
|
44
|
+
"n_adc": {},
|
45
|
+
"adc_card_layout": {},
|
46
|
+
"wf_len": {},
|
47
|
+
"fsp_enabled": {},
|
48
|
+
"n_card": {},
|
49
|
+
}
|
50
|
+
|
51
|
+
fc_card_info_dict = header.get_object_info(
|
52
|
+
[
|
53
|
+
"ORFlashCamGlobalTriggerModel",
|
54
|
+
"ORFlashCamTriggerModel",
|
55
|
+
"ORFlashCamADCModel",
|
56
|
+
"ORFlashCamADCStdModel",
|
57
|
+
]
|
58
|
+
)
|
59
|
+
|
60
|
+
fc_listener_info_list = header.get_readout_info("ORFlashCamListenerModel")
|
61
|
+
for fc_listener_info in fc_listener_info_list:
|
62
|
+
fcid = fc_listener_info["uniqueID"] # it should be called listener_id
|
63
|
+
if fcid == 0:
|
64
|
+
raise ValueError("got fcid=0 unexpectedly!")
|
65
|
+
aux_hw_info = header.get_auxhw_info("ORFlashCamListenerModel", fcid)
|
66
|
+
if "fspEnabled" in aux_hw_info:
|
67
|
+
fc_hdr_info["fsp_enabled"][fcid] = aux_hw_info["fspEnabled"]
|
68
|
+
else:
|
69
|
+
fc_hdr_info["fsp_enabled"][fcid] = False
|
70
|
+
|
71
|
+
fc_hdr_info["wf_len"][fcid] = header.get_auxhw_info(
|
72
|
+
"ORFlashCamListenerModel", fcid
|
73
|
+
)["eventSamples"]
|
74
|
+
fc_hdr_info["n_adc"][fcid] = 0
|
75
|
+
fc_hdr_info["n_card"][fcid] = 0
|
76
|
+
fc_hdr_info["key_list"][fcid] = []
|
77
|
+
fc_hdr_info["adc_card_layout"][fcid] = {}
|
78
|
+
for child in fc_listener_info["children"]:
|
79
|
+
|
80
|
+
crate = child["crate"]
|
81
|
+
card = child["station"]
|
82
|
+
card_address = fc_card_info_dict[crate][card]["CardAddress"]
|
83
|
+
fc_hdr_info["adc_card_layout"][fcid][card_address] = (
|
84
|
+
crate,
|
85
|
+
card,
|
86
|
+
card_address,
|
87
|
+
)
|
88
|
+
fc_hdr_info["n_card"][fcid] += 1
|
89
|
+
|
90
|
+
if crate not in fc_card_info_dict:
|
91
|
+
raise RuntimeError(f"no crate {crate} in fc_card_info_dict")
|
92
|
+
if card not in fc_card_info_dict[crate]:
|
93
|
+
raise RuntimeError(f"no card {card} in fc_card_info_dict[{crate}]")
|
94
|
+
|
95
|
+
for fc_input in range(len(fc_card_info_dict[crate][card]["Enabled"])):
|
96
|
+
if not fc_card_info_dict[crate][card]["Enabled"][fc_input]:
|
97
|
+
continue
|
98
|
+
|
99
|
+
fc_hdr_info["n_adc"][fcid] += 1
|
100
|
+
key = get_key(fcid, card_address, fc_input)
|
101
|
+
|
102
|
+
if key in fc_hdr_info["key_list"][fcid]:
|
103
|
+
log.warning(f"key {key} already in key_list...")
|
104
|
+
else:
|
105
|
+
fc_hdr_info["key_list"][fcid].append(key)
|
106
|
+
|
107
|
+
return fc_hdr_info
|
108
|
+
|
109
|
+
|
110
|
+
class ORFCIOConfigDecoder(OrcaDecoder):
|
111
|
+
def __init__(self, header: OrcaHeader = None, **kwargs) -> None:
|
112
|
+
|
113
|
+
self.decoder = FCConfigDecoder()
|
114
|
+
self.fsp_decoder = None
|
115
|
+
self.decoded_values = {}
|
116
|
+
self.key_list = {"fc_config": [], "fsp_config": []}
|
117
|
+
self.max_rows_in_packet = 0
|
118
|
+
|
119
|
+
super().__init__(header=header, **kwargs)
|
120
|
+
|
121
|
+
# The ConfigDecoder is always required for decoding fcio data.
|
122
|
+
# When OrcaStreamer.open_stream is called, we close any open fcio stream
|
123
|
+
for fcio_stream in fcio_stream_library.values():
|
124
|
+
fcio_stream.close()
|
125
|
+
|
126
|
+
def set_header(self, header: OrcaHeader) -> None:
|
127
|
+
self.header = header
|
128
|
+
self.fc_hdr_info = extract_header_information(header)
|
129
|
+
self.decoded_values = copy.deepcopy(self.decoder.get_decoded_values())
|
130
|
+
|
131
|
+
for fcid in self.fc_hdr_info["fsp_enabled"]:
|
132
|
+
key = get_key(fcid, 0, 0)
|
133
|
+
self.key_list["fc_config"].append(key)
|
134
|
+
if self.fc_hdr_info["fsp_enabled"][fcid]:
|
135
|
+
self.fsp_decoder = FSPConfigDecoder()
|
136
|
+
self.key_list["fsp_config"].append(f"fsp_config_{key}")
|
137
|
+
self.max_rows_in_packet = 1
|
138
|
+
|
139
|
+
def get_key_lists(self) -> list[list[int, str]]:
|
140
|
+
return list(self.key_list.values())
|
141
|
+
|
142
|
+
def get_decoded_values(self, key: int | str = None) -> dict[str, Any]:
|
143
|
+
if isinstance(key, str) and key.startswith("fsp_config"):
|
144
|
+
return copy.deepcopy(self.fsp_decoder.get_decoded_values())
|
145
|
+
return self.decoded_values
|
146
|
+
raise KeyError(f"no decoded values for key {key}")
|
147
|
+
|
148
|
+
def decode_packet(
|
149
|
+
self, packet: OrcaPacket, packet_id: int, rbl: RawBufferList
|
150
|
+
) -> bool:
|
151
|
+
|
152
|
+
fcio_stream = get_fcio_stream(packet[2])
|
153
|
+
if fcio_stream.is_open():
|
154
|
+
raise NotImplementedError(
|
155
|
+
f"FCIO stream with stream id {packet[2]} already opened. Update of FCIOConfig is not supported."
|
156
|
+
)
|
157
|
+
else:
|
158
|
+
fcio_stream.open(memoryview(packet[3:]))
|
159
|
+
|
160
|
+
if fcio_stream.config.streamid != packet[2]:
|
161
|
+
log.warning(
|
162
|
+
f"The expected stream id {packet[2]} does not match the contained stream id {fcio_stream.config.streamid}"
|
163
|
+
)
|
164
|
+
|
165
|
+
config_rbkd = rbl.get_keyed_dict()
|
166
|
+
|
167
|
+
# TODO: the decoders could fetch lgdo's using it's key_list
|
168
|
+
fc_key = get_key(fcio_stream.config.streamid, 0, 0)
|
169
|
+
any_full = self.decoder.decode_packet(
|
170
|
+
fcio_stream, config_rbkd[fc_key], packet_id
|
171
|
+
)
|
172
|
+
if self.fsp_decoder is not None:
|
173
|
+
fsp_key = f"fsp_config_{get_key(fcio_stream.config.streamid, 0, 0)}"
|
174
|
+
any_full |= self.fsp_decoder.decode_packet(
|
175
|
+
fcio_stream, config_rbkd[fsp_key], packet_id
|
176
|
+
)
|
177
|
+
|
178
|
+
return bool(any_full)
|
179
|
+
|
180
|
+
|
181
|
+
class ORFCIOStatusDecoder(OrcaDecoder):
|
182
|
+
def __init__(self, header: OrcaHeader = None, **kwargs) -> None:
|
183
|
+
|
184
|
+
self.decoder = FCStatusDecoder()
|
185
|
+
self.fsp_decoder = None
|
186
|
+
self.decoded_values = {}
|
187
|
+
self.key_list = {"fc_status": [], "fsp_status": []}
|
188
|
+
self.max_rows_in_packet = 0
|
189
|
+
super().__init__(header=header, **kwargs)
|
190
|
+
|
191
|
+
def set_header(self, header: OrcaHeader) -> None:
|
192
|
+
"""Setter for headers. Overload to set card parameters, etc."""
|
193
|
+
self.header = header
|
194
|
+
self.fc_hdr_info = extract_header_information(header)
|
195
|
+
self.decoded_values = copy.deepcopy(self.decoder.get_decoded_values())
|
196
|
+
|
197
|
+
for fcid in self.fc_hdr_info["n_card"]:
|
198
|
+
# If the data was taken without a master distribution module,
|
199
|
+
# i.e. only one ADC Module the decoder will just not write to the buffer.
|
200
|
+
|
201
|
+
# MDB key
|
202
|
+
self.key_list["fc_status"] = [get_status_key(fcid, 0)]
|
203
|
+
# ADC module keys
|
204
|
+
self.key_list["fc_status"] += [
|
205
|
+
get_status_key(fcid, 0x2000 + i)
|
206
|
+
for i in range(self.fc_hdr_info["n_card"][fcid])
|
207
|
+
]
|
208
|
+
|
209
|
+
if self.fc_hdr_info["fsp_enabled"][fcid]:
|
210
|
+
key = get_key(fcid, 0, 0)
|
211
|
+
self.key_list["fsp_status"].append(f"fsp_status_{key}")
|
212
|
+
self.fsp_decoder = FSPStatusDecoder()
|
213
|
+
self.max_rows_in_packet = max(self.fc_hdr_info["n_card"].values()) + 1
|
214
|
+
|
215
|
+
def get_key_lists(self) -> list[list[int | str]]:
|
216
|
+
return list(self.key_list.values())
|
217
|
+
|
218
|
+
def get_decoded_values(self, key: int | str = None) -> dict[str, Any]:
|
219
|
+
if key is None:
|
220
|
+
dec_vals_list = list(self.decoded_values)
|
221
|
+
if len(dec_vals_list) > 0:
|
222
|
+
return {dec_vals_list[0]: self.decoded_values[dec_vals_list[0]]}
|
223
|
+
raise RuntimeError("decoded_values not built")
|
224
|
+
|
225
|
+
if (
|
226
|
+
isinstance(key, str)
|
227
|
+
and key.startswith("fsp_status")
|
228
|
+
and self.fsp_decoder is not None
|
229
|
+
):
|
230
|
+
return copy.deepcopy(self.fsp_decoder.get_decoded_values())
|
231
|
+
elif isinstance(key, int):
|
232
|
+
return copy.deepcopy(self.decoder.get_decoded_values())
|
233
|
+
else:
|
234
|
+
raise KeyError(f"no decoded values for key {key}")
|
235
|
+
|
236
|
+
def get_max_rows_in_packet(self) -> int:
|
237
|
+
return self.max_rows_in_packet
|
238
|
+
|
239
|
+
def decode_packet(
|
240
|
+
self, packet: OrcaPacket, packet_id: int, rbl: RawBufferList
|
241
|
+
) -> bool:
|
242
|
+
status_rbkd = rbl.get_keyed_dict()
|
243
|
+
|
244
|
+
fcio_stream = get_fcio_stream(packet[2])
|
245
|
+
fcio_stream.set_mem_field(memoryview(packet[3:]))
|
246
|
+
|
247
|
+
any_full = False
|
248
|
+
while fcio_stream.get_record():
|
249
|
+
if fcio_stream.tag == Tags.Status:
|
250
|
+
any_full |= self.decoder.decode_packet(
|
251
|
+
fcio_stream, status_rbkd, packet_id
|
252
|
+
)
|
253
|
+
if self.fsp_decoder is not None:
|
254
|
+
any_full |= self.fsp_decoder.decode_packet(
|
255
|
+
fcio_stream, status_rbkd, packet_id
|
256
|
+
)
|
257
|
+
|
258
|
+
return bool(any_full)
|
259
|
+
|
260
|
+
|
261
|
+
class ORFCIOEventHeaderDecoder(OrcaDecoder):
|
262
|
+
def __init__(self, header: OrcaHeader = None, **kwargs) -> None:
|
263
|
+
|
264
|
+
self.decoder = FCEventHeaderDecoder()
|
265
|
+
self.fsp_decoder = None
|
266
|
+
self.decoded_values = {}
|
267
|
+
self.key_list = {"fc_eventheader": [], "fsp_eventheader": []}
|
268
|
+
|
269
|
+
super().__init__(header=header, **kwargs)
|
270
|
+
|
271
|
+
def set_header(self, header: OrcaHeader) -> None:
|
272
|
+
"""Setter for headers. Overload to set card parameters, etc."""
|
273
|
+
self.header = header
|
274
|
+
|
275
|
+
self.fc_hdr_info = extract_header_information(header)
|
276
|
+
|
277
|
+
key_list = self.fc_hdr_info["key_list"]
|
278
|
+
for fcid in key_list:
|
279
|
+
key = get_key(fcid, 0, 0)
|
280
|
+
self.key_list["fc_eventheader"].append(key)
|
281
|
+
self.decoded_values[fcid] = copy.deepcopy(self.decoder.get_decoded_values())
|
282
|
+
if self.fc_hdr_info["fsp_enabled"][fcid]:
|
283
|
+
self.fsp_decoder = FSPEventDecoder()
|
284
|
+
self.key_list["fsp_eventheader"].append(f"fsp_eventheader_{key}")
|
285
|
+
|
286
|
+
self.max_rows_in_packet = 1
|
287
|
+
|
288
|
+
def get_key_lists(self) -> list[list[int | str]]:
|
289
|
+
return list(self.key_list.values())
|
290
|
+
|
291
|
+
def get_decoded_values(self, key: int | str = None) -> dict[str, Any]:
|
292
|
+
if (
|
293
|
+
isinstance(key, str)
|
294
|
+
and key.startswith("fsp_eventheader_")
|
295
|
+
and self.fsp_decoder is not None
|
296
|
+
):
|
297
|
+
return copy.deepcopy(self.fsp_decoder.get_decoded_values())
|
298
|
+
elif isinstance(key, int):
|
299
|
+
fcid = get_fcid(key)
|
300
|
+
if fcid in self.decoded_values:
|
301
|
+
return self.decoded_values[fcid]
|
302
|
+
elif key is None and self.fsp_decoder is None:
|
303
|
+
dec_vals_list = list(self.decoded_values.values())
|
304
|
+
if len(dec_vals_list) > 0:
|
305
|
+
return dec_vals_list[0]
|
306
|
+
raise RuntimeError("decoded_values not built")
|
307
|
+
|
308
|
+
raise KeyError(f"no decoded values for key {key}")
|
309
|
+
|
310
|
+
def decode_packet(
|
311
|
+
self, packet: OrcaPacket, packet_id: int, rbl: RawBufferList
|
312
|
+
) -> bool:
|
313
|
+
evthdr_rbkd = rbl.get_keyed_dict()
|
314
|
+
fcio_stream = get_fcio_stream(packet[2])
|
315
|
+
fcio_stream.set_mem_field(memoryview(packet[3:]))
|
316
|
+
|
317
|
+
any_full = False
|
318
|
+
while fcio_stream.get_record():
|
319
|
+
if fcio_stream.tag == Tags.EventHeader:
|
320
|
+
any_full |= self.decoder.decode_packet(
|
321
|
+
fcio_stream, evthdr_rbkd, packet_id
|
322
|
+
)
|
323
|
+
if self.fsp_decoder is not None:
|
324
|
+
any_full |= self.fsp_decoder.decode_packet(
|
325
|
+
fcio_stream, evthdr_rbkd, packet_id, True
|
326
|
+
)
|
327
|
+
|
328
|
+
return bool(any_full)
|
329
|
+
|
330
|
+
|
331
|
+
class ORFCIOEventDecoder(OrcaDecoder):
|
332
|
+
"""Decoder for FlashCam FCIO stream data written by ORCA."""
|
333
|
+
|
334
|
+
def __init__(self, header: OrcaHeader = None, **kwargs) -> None:
|
335
|
+
self.decoder = FCEventDecoder()
|
336
|
+
self.fsp_decoder = None
|
337
|
+
|
338
|
+
self.key_list = {"event": [], "fsp_event": []}
|
339
|
+
self.decoded_values = {}
|
340
|
+
self.max_rows_in_packet = 0
|
341
|
+
|
342
|
+
super().__init__(header=header, **kwargs)
|
343
|
+
|
344
|
+
def set_header(self, header: OrcaHeader) -> None:
|
345
|
+
"""Setter for headers. Overload to set card parameters, etc."""
|
346
|
+
self.header = header
|
347
|
+
self.fc_hdr_info = extract_header_information(header)
|
348
|
+
key_list = self.fc_hdr_info["key_list"]
|
349
|
+
for fcid in key_list:
|
350
|
+
self.key_list["event"] += key_list[fcid]
|
351
|
+
self.decoded_values[fcid] = copy.deepcopy(self.decoder.get_decoded_values())
|
352
|
+
self.decoded_values[fcid]["waveform"]["wf_len"] = self.fc_hdr_info[
|
353
|
+
"wf_len"
|
354
|
+
][fcid]
|
355
|
+
if self.fc_hdr_info["fsp_enabled"][fcid]:
|
356
|
+
key = get_key(fcid, 0, 0)
|
357
|
+
self.key_list["fsp_event"].append(f"fsp_event_{key}")
|
358
|
+
self.fsp_decoder = FSPEventDecoder()
|
359
|
+
self.max_rows_in_packet = max(self.fc_hdr_info["n_adc"].values())
|
360
|
+
|
361
|
+
def get_key_lists(self) -> list[list[int]]:
|
362
|
+
return list(self.key_list.values())
|
363
|
+
|
364
|
+
def get_max_rows_in_packet(self) -> int:
|
365
|
+
return self.max_rows_in_packet
|
366
|
+
|
367
|
+
def get_decoded_values(self, key: int = None) -> dict[str, Any]:
|
368
|
+
if key is None:
|
369
|
+
dec_vals_list = list(self.decoded_values.values())
|
370
|
+
if len(dec_vals_list) > 0:
|
371
|
+
return dec_vals_list[0]
|
372
|
+
raise RuntimeError("decoded_values not built")
|
373
|
+
|
374
|
+
if (
|
375
|
+
isinstance(key, str)
|
376
|
+
and key.startswith("fsp_event_")
|
377
|
+
and self.fsp_decoder is not None
|
378
|
+
):
|
379
|
+
return copy.deepcopy(self.fsp_decoder.get_decoded_values())
|
380
|
+
elif isinstance(key, int):
|
381
|
+
fcid = get_fcid(key)
|
382
|
+
if fcid in self.decoded_values:
|
383
|
+
return self.decoded_values[fcid]
|
384
|
+
|
385
|
+
raise KeyError(f"no decoded values for key {key}")
|
386
|
+
|
387
|
+
def decode_packet(
|
388
|
+
self, packet: OrcaPacket, packet_id: int, rbl: RawBufferList
|
389
|
+
) -> bool:
|
390
|
+
"""Decode the ORCA FlashCam ADC packet."""
|
391
|
+
evt_rbkd = rbl.get_keyed_dict()
|
392
|
+
|
393
|
+
fcio_stream = get_fcio_stream(packet[2])
|
394
|
+
fcio_stream.set_mem_field(memoryview(packet[3:]))
|
395
|
+
|
396
|
+
any_full = False
|
397
|
+
while fcio_stream.get_record():
|
398
|
+
if fcio_stream.tag == Tags.Event or fcio_stream.tag == Tags.SparseEvent:
|
399
|
+
any_full |= self.decoder.decode_packet(fcio_stream, evt_rbkd, packet_id)
|
400
|
+
if self.fsp_decoder is not None:
|
401
|
+
any_full |= self.fsp_decoder.decode_packet(
|
402
|
+
fcio_stream, evt_rbkd, packet_id, False
|
403
|
+
)
|
404
|
+
|
405
|
+
return bool(any_full)
|
daq2lh5/orca/orca_flashcam.py
CHANGED
@@ -5,7 +5,7 @@ from typing import Any
|
|
5
5
|
|
6
6
|
import numpy as np
|
7
7
|
|
8
|
-
from ..fc.fc_event_decoder import
|
8
|
+
from ..fc.fc_event_decoder import fc_event_decoded_values
|
9
9
|
from ..raw_buffer import RawBufferLibrary
|
10
10
|
from .orca_base import OrcaDecoder
|
11
11
|
from .orca_header import OrcaHeader
|
@@ -43,7 +43,7 @@ class ORFlashCamListenerConfigDecoder(OrcaDecoder):
|
|
43
43
|
"packet_len": {"dtype": "uint32"},
|
44
44
|
"readout_id": {"dtype": "uint16"},
|
45
45
|
"fcid": {"dtype": "uint16"},
|
46
|
-
"
|
46
|
+
"streamid": {"dtype": "int32"},
|
47
47
|
"nadcs": {"dtype": "int32"},
|
48
48
|
"ntriggers": {"dtype": "int32"},
|
49
49
|
"nsamples": {"dtype": "int32"},
|
@@ -458,8 +458,8 @@ class ORFlashCamWaveformDecoder(OrcaDecoder):
|
|
458
458
|
|
459
459
|
def __init__(self, header: OrcaHeader = None, **kwargs) -> None:
|
460
460
|
# start with the values defined in fcdaq
|
461
|
-
self.decoded_values_template = copy.deepcopy(
|
462
|
-
"""A custom copy of :obj:`.fc.fc_event_decoder.
|
461
|
+
self.decoded_values_template = copy.deepcopy(fc_event_decoded_values)
|
462
|
+
"""A custom copy of :obj:`.fc.fc_event_decoder.fc_event_decoded_values`."""
|
463
463
|
# add header values from Orca
|
464
464
|
self.decoded_values_template.update(
|
465
465
|
{
|
@@ -737,6 +737,9 @@ class ORFlashCamWaveformDecoder(OrcaDecoder):
|
|
737
737
|
tbl["waveform"]["values"].nda[ii][:wf_samples] = wf
|
738
738
|
|
739
739
|
evt_rbkd[key].loc += 1
|
740
|
+
log.info(
|
741
|
+
f"-> {tbl['eventnumber'].nda[ii]} {channel} .. {evt_rbkd[key].loc}/{len(evt_rbkd[key])} {id(evt_rbkd[key])} {id(evt_rbkd[key].lgdo)}"
|
742
|
+
)
|
740
743
|
return evt_rbkd[key].is_full()
|
741
744
|
|
742
745
|
|
daq2lh5/orca/orca_header.py
CHANGED
@@ -46,16 +46,21 @@ class OrcaHeader(dict):
|
|
46
46
|
return d["Run Control"]["RunNumber"]
|
47
47
|
raise ValueError("No run number found in header!")
|
48
48
|
|
49
|
-
def get_object_info(
|
49
|
+
def get_object_info(
|
50
|
+
self, orca_class_name: str | list[str]
|
51
|
+
) -> dict[int, dict[int, dict]]:
|
50
52
|
"""Returns a ``dict[crate][card]`` with all info from the header for
|
51
53
|
each card with name `orca_class_name`.
|
52
54
|
"""
|
53
55
|
object_info_dict = {}
|
54
56
|
|
57
|
+
if isinstance(orca_class_name, str):
|
58
|
+
orca_class_name = [orca_class_name]
|
59
|
+
|
55
60
|
crates = self["ObjectInfo"]["Crates"]
|
56
61
|
for crate in crates:
|
57
62
|
for card in crate["Cards"]:
|
58
|
-
if card["Class Name"]
|
63
|
+
if card["Class Name"] in orca_class_name:
|
59
64
|
if crate["CrateNumber"] not in object_info_dict:
|
60
65
|
object_info_dict[crate["CrateNumber"]] = {}
|
61
66
|
object_info_dict[crate["CrateNumber"]][card["Card"]] = card
|
daq2lh5/orca/orca_packet.py
CHANGED
@@ -20,9 +20,19 @@ def is_short(packet: OrcaPacket) -> bool:
|
|
20
20
|
return bool(packet[0] >> 31)
|
21
21
|
|
22
22
|
|
23
|
+
def is_extended(packet: OrcaPacket) -> bool:
|
24
|
+
# if the packet is 0 size in default format
|
25
|
+
# the length if the packet is stored in the next uint32
|
26
|
+
return bool((packet[0] & 0x3FFFF) == 0)
|
27
|
+
|
28
|
+
|
23
29
|
def get_n_words(packet: OrcaPacket) -> int:
|
24
30
|
if is_short(packet):
|
25
31
|
return 1
|
32
|
+
if is_extended(packet):
|
33
|
+
# we could check here if packet is actually long enough
|
34
|
+
# to return packet[1]
|
35
|
+
return packet[1]
|
26
36
|
return packet[0] & 0x3FFFF
|
27
37
|
|
28
38
|
|
daq2lh5/orca/orca_run_decoder.py
CHANGED
@@ -18,12 +18,12 @@ class ORRunDecoderForRun(OrcaDecoder):
|
|
18
18
|
# bit in data packet
|
19
19
|
self.decoded_values = {
|
20
20
|
"subrun_number": {"dtype": "uint16"},
|
21
|
-
"runstartorstop": {"dtype": "
|
22
|
-
"quickstartrun": {"dtype": "
|
23
|
-
"remotecontrolrun": {"dtype": "
|
24
|
-
"heartbeatrecord": {"dtype": "
|
25
|
-
"endsubrunrecord": {"dtype": "
|
26
|
-
"startsubrunrecord": {"dtype": "
|
21
|
+
"runstartorstop": {"dtype": "bool"},
|
22
|
+
"quickstartrun": {"dtype": "bool"},
|
23
|
+
"remotecontrolrun": {"dtype": "bool"},
|
24
|
+
"heartbeatrecord": {"dtype": "bool"},
|
25
|
+
"endsubrunrecord": {"dtype": "bool"},
|
26
|
+
"startsubrunrecord": {"dtype": "bool"},
|
27
27
|
"run_number": {"dtype": "int32"},
|
28
28
|
"time": {"dtype": "int32"},
|
29
29
|
}
|
daq2lh5/orca/orca_streamer.py
CHANGED
@@ -15,6 +15,12 @@ from .orca_digitizers import ( # noqa: F401
|
|
15
15
|
ORSIS3302DecoderForEnergy,
|
16
16
|
ORSIS3316WaveformDecoder,
|
17
17
|
)
|
18
|
+
from .orca_fcio import ( # noqa: F401;
|
19
|
+
ORFCIOConfigDecoder,
|
20
|
+
ORFCIOEventDecoder,
|
21
|
+
ORFCIOEventHeaderDecoder,
|
22
|
+
ORFCIOStatusDecoder,
|
23
|
+
)
|
18
24
|
from .orca_flashcam import ( # noqa: F401;
|
19
25
|
ORFlashCamADCWaveformDecoder,
|
20
26
|
ORFlashCamListenerConfigDecoder,
|
@@ -41,18 +47,28 @@ class OrcaStreamer(DataStreamer):
|
|
41
47
|
self.rbl_id_dict = {} # dict of RawBufferLists for each data_id
|
42
48
|
self.missing_decoders = []
|
43
49
|
|
44
|
-
def load_packet_header(self) -> np.
|
50
|
+
def load_packet_header(self) -> np.ndarray | None:
|
45
51
|
"""Loads the packet header at the current read location into the buffer
|
46
52
|
|
47
53
|
and updates internal variables.
|
48
54
|
"""
|
49
|
-
pkt_hdr = self.buffer[:
|
55
|
+
pkt_hdr = self.buffer[:2]
|
50
56
|
n_bytes_read = self.in_stream.readinto(pkt_hdr) # buffer is at least 4 kB long
|
51
57
|
self.n_bytes_read += n_bytes_read
|
52
58
|
if n_bytes_read == 0: # EOF
|
53
59
|
return None
|
54
|
-
if n_bytes_read !=
|
55
|
-
raise RuntimeError(
|
60
|
+
if (n_bytes_read % 4) != 0:
|
61
|
+
raise RuntimeError(
|
62
|
+
f"got {n_bytes_read} bytes for packet header, expect 4 or 8."
|
63
|
+
)
|
64
|
+
if orca_packet.is_extended(pkt_hdr) and n_bytes_read < 8:
|
65
|
+
raise RuntimeError(
|
66
|
+
f"got {n_bytes_read} bytes for packet header, but require 8 for the extended header format."
|
67
|
+
)
|
68
|
+
if orca_packet.is_short(pkt_hdr) and n_bytes_read > 4:
|
69
|
+
# if more than 4 bytes were read but the packet is short, we reset the file stream
|
70
|
+
# so we can read the next uint32_t again. would not be necessary with a circular buffer
|
71
|
+
self.in_stream.seek(n_bytes_read - 4, 1)
|
56
72
|
|
57
73
|
# packet is valid. Can set the packet_id and log its location
|
58
74
|
self.packet_id += 1
|
@@ -90,7 +106,9 @@ class OrcaStreamer(DataStreamer):
|
|
90
106
|
pkt_hdr = self.load_packet_header()
|
91
107
|
if pkt_hdr is None:
|
92
108
|
return False
|
93
|
-
self.in_stream.seek(
|
109
|
+
self.in_stream.seek(
|
110
|
+
(orca_packet.get_n_words(pkt_hdr) - len(pkt_hdr)) * 4, 1
|
111
|
+
)
|
94
112
|
n -= 1
|
95
113
|
return True
|
96
114
|
|
@@ -106,14 +124,14 @@ class OrcaStreamer(DataStreamer):
|
|
106
124
|
self.in_stream.seek(loc)
|
107
125
|
self.packet_id = pid
|
108
126
|
|
109
|
-
def count_packets(self, saveloc=True) ->
|
127
|
+
def count_packets(self, saveloc=True) -> int:
|
110
128
|
self.build_packet_locs(saveloc=saveloc)
|
111
129
|
return len(self.packet_locs)
|
112
130
|
|
113
131
|
# TODO: need to correct for endianness?
|
114
132
|
def load_packet(
|
115
133
|
self, index: int = None, whence: int = 0, skip_unknown_ids: bool = False
|
116
|
-
) -> np.
|
134
|
+
) -> np.ndarray | None:
|
117
135
|
"""Loads the next packet into the internal buffer.
|
118
136
|
|
119
137
|
Returns packet as a :class:`numpy.uint32` view of the buffer (a slice),
|
@@ -177,15 +195,15 @@ class OrcaStreamer(DataStreamer):
|
|
177
195
|
and orca_packet.get_data_id(pkt_hdr, shift=False)
|
178
196
|
not in self.decoder_id_dict
|
179
197
|
):
|
180
|
-
self.in_stream.seek((n_words -
|
198
|
+
self.in_stream.seek((n_words - len(pkt_hdr)) * 4, 1)
|
181
199
|
return pkt_hdr
|
182
200
|
|
183
201
|
# load into buffer, resizing as necessary
|
184
202
|
if len(self.buffer) < n_words:
|
185
203
|
self.buffer.resize(n_words, refcheck=False)
|
186
|
-
n_bytes_read = self.in_stream.readinto(self.buffer[
|
204
|
+
n_bytes_read = self.in_stream.readinto(self.buffer[len(pkt_hdr) : n_words])
|
187
205
|
self.n_bytes_read += n_bytes_read
|
188
|
-
if n_bytes_read != (n_words -
|
206
|
+
if n_bytes_read != (n_words - len(pkt_hdr)) * 4:
|
189
207
|
log.error(
|
190
208
|
f"only got {n_bytes_read} bytes for packet read when {(n_words-1)*4} were expected. Flushing all buffers and quitting..."
|
191
209
|
)
|
@@ -0,0 +1,54 @@
|
|
1
|
+
import argparse
|
2
|
+
from pathlib import Path
|
3
|
+
|
4
|
+
from .orca_streamer import OrcaStreamer
|
5
|
+
|
6
|
+
|
7
|
+
def skim_orca_file() -> None:
|
8
|
+
parser = argparse.ArgumentParser(
|
9
|
+
prog="skim_orca_file",
|
10
|
+
description="Convert data into LEGEND HDF5 (LH5) raw format",
|
11
|
+
)
|
12
|
+
parser.add_argument("in_file", type=str, help="filename of orca file to skim")
|
13
|
+
parser.add_argument("n_packets", type=int, help="number of packets to skim")
|
14
|
+
parser.add_argument(
|
15
|
+
"--out-file", type=str, required=False, help="filename to write skimmed file to"
|
16
|
+
)
|
17
|
+
args = parser.parse_args()
|
18
|
+
|
19
|
+
if not Path(args.in_file).is_file():
|
20
|
+
print("file not found: {args.in_file}") # noqa: T201
|
21
|
+
print( # noqa: T201
|
22
|
+
"Usage: skim_orca_file [orca_file] [n_packets] (out_filename)"
|
23
|
+
)
|
24
|
+
|
25
|
+
elif args.n_packets == 0:
|
26
|
+
print("n_packets must be a positive integer") # noqa: T201
|
27
|
+
print( # noqa: T201
|
28
|
+
"Usage: skim_orca_file [orca_file] [n_packets] (out_filename)"
|
29
|
+
)
|
30
|
+
else:
|
31
|
+
if args.out_file:
|
32
|
+
out_filename = Path(args.out_file)
|
33
|
+
else:
|
34
|
+
out_filename = Path(f"{args.in_file}_first{args.n_packets}")
|
35
|
+
out_filename.parent.mkdir(parents=True, exist_ok=True)
|
36
|
+
|
37
|
+
or_streamer = OrcaStreamer()
|
38
|
+
or_streamer.open_stream(args.in_file)
|
39
|
+
header_packet = or_streamer.load_packet(0)
|
40
|
+
|
41
|
+
if out_filename.is_file():
|
42
|
+
out_filename.unlink()
|
43
|
+
|
44
|
+
with out_filename.open("ab") as out_file:
|
45
|
+
# always write header and first packet (run start)
|
46
|
+
header_packet.tofile(out_file)
|
47
|
+
packet = or_streamer.load_packet()
|
48
|
+
packet.tofile(out_file)
|
49
|
+
for _ in range(args.n_packets):
|
50
|
+
packet = or_streamer.load_packet()
|
51
|
+
packet.tofile(out_file)
|
52
|
+
# always write last packet (run end)
|
53
|
+
packet = or_streamer.load_packet(1, 2)
|
54
|
+
packet.tofile(out_file)
|