diff --git a/src/pygama/lgdo/lh5_store.py b/src/pygama/lgdo/lh5_store.py index 55745df9e..cdd04a364 100644 --- a/src/pygama/lgdo/lh5_store.py +++ b/src/pygama/lgdo/lh5_store.py @@ -307,7 +307,7 @@ def read_object( if datatype == "scalar": value = h5f[name][()] if elements == "bool": - value = np.bool(value) + value = np.bool_(value) if obj_buf is not None: obj_buf.value = value obj_buf.attrs.update(h5f[name].attrs) @@ -631,7 +631,7 @@ def read_object( # special handling for bools # (c and Julia store as uint8 so cast to bool) if elements == "bool": - nda = nda.astype(np.bool) + nda = nda.astype(np.bool_) # Finally, set attributes and return objects attrs = h5f[name].attrs diff --git a/src/pygama/raw/orca/orca_run_decoder.py b/src/pygama/raw/orca/orca_run_decoder.py new file mode 100644 index 000000000..6442cae9d --- /dev/null +++ b/src/pygama/raw/orca/orca_run_decoder.py @@ -0,0 +1,63 @@ +import logging +from typing import Any + +from pygama.raw.orca.orca_base import OrcaDecoder +from pygama.raw.orca.orca_header import OrcaHeader +from pygama.raw.orca.orca_packet import OrcaPacket +from pygama.raw.raw_buffer import RawBufferLibrary + +log = logging.getLogger(__name__) + + +class ORRunDecoderForRun(OrcaDecoder): + """Decoder for Run Control data written by ORCA.""" + + def __init__(self, header: OrcaHeader = None, **kwargs) -> None: + # quickstartrun through startsubrunrecord are in order + # of increasing bit location with respect to the rightmost + # bit in data packet + self.decoded_values = { + "subrun_number": {"dtype": "uint16"}, + "runstartorstop": {"dtype": "bool8"}, + "quickstartrun": {"dtype": "bool8"}, + "remotecontrolrun": {"dtype": "bool8"}, + "heartbeatrecord": {"dtype": "bool8"}, + "endsubrunrecord": {"dtype": "bool8"}, + "startsubrunrecord": {"dtype": "bool8"}, + "run_number": {"dtype": "int32"}, + "time": {"dtype": "int32"}, + } + super().__init__(header=header, **kwargs) + + def get_decoded_values(self, key: int = None) -> dict[str, Any]: + return self.decoded_values + + def decode_packet( + self, packet: OrcaPacket, packet_id: int, rbl: RawBufferLibrary + ) -> bool: + """ + Decode the ORCA Run packet. + + Format is taken from the ORCA website: `Run Control + `_ + + """ + + if len(rbl) != 1: + log.warning( + f"got {len(rbl)} rb's, should have only 1 (no keyed decoded values)" + ) + rb = rbl[0] + tbl = rb.lgdo + ii = rb.loc + + tbl["subrun_number"].nda[ii] = (packet[1] & 0xFFFF0000) >> 16 + for i, k in enumerate(self.decoded_values): + if 0 < i < 7: + tbl[k].nda[ii] = (packet[1] & (1 << (i - 1))) >> (i - 1) + + tbl["run_number"].nda[ii] = packet[2] + tbl["time"].nda[ii] = packet[3] + + rb.loc += 1 + return rb.is_full() diff --git a/src/pygama/raw/orca/orca_streamer.py b/src/pygama/raw/orca/orca_streamer.py index e5665b19d..e36c342f7 100644 --- a/src/pygama/raw/orca/orca_streamer.py +++ b/src/pygama/raw/orca/orca_streamer.py @@ -19,6 +19,7 @@ ORFlashCamWaveformDecoder, ) from pygama.raw.orca.orca_header_decoder import OrcaHeaderDecoder +from pygama.raw.orca.orca_run_decoder import ORRunDecoderForRun # noqa: F401 from pygama.raw.raw_buffer import RawBuffer, RawBufferLibrary log = logging.getLogger(__name__) diff --git a/tests/raw/orca/conftest.py b/tests/raw/orca/conftest.py new file mode 100644 index 000000000..8ad036d0b --- /dev/null +++ b/tests/raw/orca/conftest.py @@ -0,0 +1,12 @@ +import pytest + +from pygama.raw.orca.orca_streamer import OrcaStreamer + + +@pytest.fixture(scope="module") +def orca_stream(lgnd_test_data): + orstr = OrcaStreamer() + orstr.open_stream( + lgnd_test_data.get_path("orca/fc/L200-comm-20220519-phy-geds.orca") + ) + return orstr diff --git a/tests/raw/orca/test_or_run_decoder_for_run.py b/tests/raw/orca/test_or_run_decoder_for_run.py new file mode 100644 index 000000000..c77b3f7c4 --- /dev/null +++ b/tests/raw/orca/test_or_run_decoder_for_run.py @@ -0,0 +1,65 @@ +import pytest + +from pygama import lgdo +from pygama.raw.orca.orca_run_decoder import ORRunDecoderForRun +from pygama.raw.raw_buffer import RawBuffer + + +@pytest.fixture(scope="module") +def run_rbkd(orca_stream): + + decoder = ORRunDecoderForRun(header=orca_stream.header) + + rbkd = {} + rbkd[0] = RawBuffer(lgdo=decoder.make_lgdo(size=1)) + + this_packet = orca_stream.load_packet(skip_unknown_ids=False) + orca_stream.close_stream() # avoid leaving file open + + # assert correct type for ORRunDecoderForRun + assert (this_packet[0] >> 18) == 7 + + # assert that it worked and the buffer is full + assert decoder.decode_packet(packet=this_packet, packet_id=1, rbl=rbkd) + + return rbkd, this_packet + + +def test_decoding(run_rbkd): + assert run_rbkd[0] != {} + + +def test_data_types(run_rbkd): + + for _, v in run_rbkd[0].items(): + tbl = v.lgdo + assert isinstance(tbl, lgdo.Struct) + assert isinstance(tbl["subrun_number"], lgdo.Array) + assert isinstance(tbl["runstartorstop"], lgdo.Array) + assert isinstance(tbl["quickstartrun"], lgdo.Array) + assert isinstance(tbl["remotecontrolrun"], lgdo.Array) + assert isinstance(tbl["heartbeatrecord"], lgdo.Array) + assert isinstance(tbl["endsubrunrecord"], lgdo.Array) + assert isinstance(tbl["startsubrunrecord"], lgdo.Array) + assert isinstance(tbl["run_number"], lgdo.Array) + assert isinstance(tbl["time"], lgdo.Array) + + +def test_values(run_rbkd): + + this_packet = run_rbkd[1] + + decoded_values = ORRunDecoderForRun().decoded_values + + for _, v in run_rbkd[0].items(): + loc = v.loc - 1 + tbl = v.lgdo + + assert tbl["subrun_number"].nda[loc] == (this_packet[1] & 0xFFFF0000) >> 16 + + for i, k in enumerate(decoded_values): + if 0 < i < 7: + assert tbl[k].nda[loc] == (this_packet[1] & (1 << (i - 1))) >> (i - 1) + + assert tbl["run_number"].nda[loc] == this_packet[2] + assert tbl["time"].nda[loc] == this_packet[3]