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.
@@ -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)
@@ -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 fc_decoded_values
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
- "telid": {"dtype": "int32"},
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(fc_decoded_values)
462
- """A custom copy of :obj:`.fc.fc_event_decoder.fc_decoded_values`."""
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
 
@@ -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(self, orca_class_name: str) -> dict[int, dict[int, dict]]:
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"] == orca_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
@@ -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
 
@@ -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": "bool8"},
22
- "quickstartrun": {"dtype": "bool8"},
23
- "remotecontrolrun": {"dtype": "bool8"},
24
- "heartbeatrecord": {"dtype": "bool8"},
25
- "endsubrunrecord": {"dtype": "bool8"},
26
- "startsubrunrecord": {"dtype": "bool8"},
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
  }
@@ -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.uint32 | None:
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[:1]
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 != 4:
55
- raise RuntimeError(f"only got {n_bytes_read} bytes for packet header")
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((orca_packet.get_n_words(pkt_hdr) - 1) * 4, 1)
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) -> None:
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.uint32 | None:
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 - 1) * 4, 1)
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[1:n_words])
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 - 1) * 4:
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)