diff --git a/src/ctapipe_io_lst/__init__.py b/src/ctapipe_io_lst/__init__.py index ba5209e3..8766e3ea 100644 --- a/src/ctapipe_io_lst/__init__.py +++ b/src/ctapipe_io_lst/__init__.py @@ -32,7 +32,7 @@ from ctapipe_io_lst.ground_frame import ground_frame_from_earth_location from .multifiles import MultiFiles -from .containers import LSTArrayEventContainer, LSTServiceContainer, LSTEventContainer +from .containers import LSTArrayEventContainer, LSTServiceContainer, LSTEventContainer, LSTCameraContainer from .version import __version__ from .calibration import LSTR0Corrections from .event_time import EventTimeCalculator, cta_high_res_to_time @@ -456,8 +456,7 @@ def fill_from_cta_r1(self, array_event, zfits_event): ) array_event.r0.tel[self.tel_id] = R0CameraContainer() - array_event.lst.tel[1].evt.first_capacitor_id = zfits_event.first_cell_id - array_event.lst.tel[1].evt.local_clock_counter = zfits_event.module_hires_local_clock_counter + array_event.lst.tel[self.tel_id] = self.fill_lst_from_ctar1(zfits_event) trigger = array_event.trigger trigger.time = cta_high_res_to_time(zfits_event.event_time_s, zfits_event.event_time_qns) @@ -465,6 +464,69 @@ def fill_from_cta_r1(self, array_event, zfits_event): trigger.tel[tel_id].time = trigger.time trigger.event_type = self._event_type_from_trigger_bits(zfits_event.event_type) + def fill_lst_from_ctar1(self, zfits_event): + evt = LSTEventContainer( + pixel_status=zfits_event.pixel_status, + first_capacitor_id=zfits_event.first_cell_id, + calibration_monitoring_id=zfits_event.calibration_monitoring_id, + local_clock_counter=zfits_event.module_hires_local_clock_counter, + ) + + if zfits_event.debug is not None: + debug = zfits_event.debug + evt.module_status = debug.module_status + evt.extdevices_presence = debug.extdevices_presence + evt.chips_flags = debug.chips_flags + evt.charges_hg = debug.charges_gain1 + evt.charges_lg = debug.charges_gain2 + + # unpack Dragon counters + counters = debug.counters.view(DRAGON_COUNTERS_DTYPE) + evt.pps_counter = counters['pps_counter'] + evt.tenMHz_counter = counters['tenMHz_counter'] + evt.event_counter = counters['event_counter'] + evt.trigger_counter = counters['trigger_counter'] + evt.local_clock_counter = counters['local_clock_counter'] + + # if TIB data are there + if evt.extdevices_presence & 1: + tib = debug.tib_data.view(TIB_DTYPE)[0] + evt.tib_event_counter = tib['event_counter'] + evt.tib_pps_counter = tib['pps_counter'] + evt.tib_tenMHz_counter = tib['tenMHz_counter'] + evt.tib_stereo_pattern = tib['stereo_pattern'] + evt.tib_masked_trigger = tib['masked_trigger'] + + # if UCTS data are there + if evt.extdevices_presence & 2: + cdts = debug.cdts_data.view(CDTS_AFTER_37201_DTYPE)[0] + evt.ucts_timestamp = cdts["timestamp"] + evt.ucts_address = cdts["address"] + evt.ucts_event_counter = cdts["event_counter"] + evt.ucts_busy_counter = cdts["busy_counter"] + evt.ucts_pps_counter = cdts["pps_counter"] + evt.ucts_clock_counter = cdts["clock_counter"] + evt.ucts_trigger_type = cdts["trigger_type"] + evt.ucts_white_rabbit_status = cdts["white_rabbit_status"] + evt.ucts_stereo_pattern = cdts["stereo_pattern"] + evt.ucts_num_in_bunch = cdts["num_in_bunch"] + evt.ucts_cdts_version = cdts["cdts_version"] + + # if SWAT data are there + if evt.extdevices_presence & 4: + # unpack SWAT data + swat = debug.swat_data.view(SWAT_DTYPE)[0] + evt.swat_timestamp = swat["timestamp"] + evt.swat_counter1 = swat["counter1"] + evt.swat_counter2 = swat["counter2"] + evt.swat_event_type = swat["event_type"] + evt.swat_camera_flag = swat["camera_flag"] + evt.swat_camera_event_num = swat["camera_event_num"] + evt.swat_array_flag = swat["array_flag"] + evt.swat_array_event_num = swat["event_num"] + + return LSTCameraContainer(evt=evt, svc=self.lst_service) + def _generator(self): # container for LST data diff --git a/src/ctapipe_io_lst/containers.py b/src/ctapipe_io_lst/containers.py index 38162078..883d76f9 100644 --- a/src/ctapipe_io_lst/containers.py +++ b/src/ctapipe_io_lst/containers.py @@ -1,6 +1,7 @@ """ Container structures for data that should be read or written to disk """ +import numpy as np from ctapipe.core import Container, Field, Map from ctapipe.containers import ArrayEventContainer from functools import partial @@ -55,20 +56,24 @@ class LSTEventContainer(Container): """ Container for Fields that are specific to each LST event """ + # present in CTA R1 but not in ctapipe R1CameraEvent + pixel_status = Field(None, "status of the pixels (n_pixels)", dtype=np.uint8) + first_capacitor_id = Field(None, "first capacitor id") + calibration_monitoring_id = Field(None, "calibration id of applied pre-calibration") + local_clock_counter = Field(None, "Dragon local 133 MHz counter (n_modules)") - # Data from the CameraEvent table - configuration_id = Field(None, "id of the CameraConfiguration") - event_id = Field(None, "local id of the event") - tel_event_id = Field(None, "global id of the event") - pixel_status = Field([], "status of the pixels (n_pixels)") - ped_id = Field(None, "tel_event_id of the event used for pedestal substraction") - module_status = Field([], "status of the modules (n_modules)") + # in debug event + module_status = Field(None, "status of the modules (n_modules)") extdevices_presence = Field(None, "presence of data for external devices") + chips_flags = Field(None, "chips flags") + charges_hg = Field(None, "charges of high gain channel") + charges_lg = Field(None, "charges of low gain channel") + tdp_action = Field(None, "tdp action") - tib_event_counter = Field(-1, "TIB event counter") - tib_pps_counter = Field(-1, "TIB pps counter") - tib_tenMHz_counter = Field(-1, "TIB 10 MHz counter") - tib_stereo_pattern = Field(0, "TIB stereo pattern") + tib_event_counter = Field(np.uint32(0), "TIB event counter", dtype=np.uint32) + tib_pps_counter = Field(np.uint16(0), "TIB pps counter", dtype=np.uint16) + tib_tenMHz_counter = Field(np.uint32(0), "TIB 10 MHz counter", dtype=np.uint32) + tib_stereo_pattern = Field(np.uint16(0), "TIB stereo pattern", dtype=np.uint16) tib_masked_trigger = Field(0, "TIB trigger mask") ucts_event_counter = Field(-1, "UCTS event counter") @@ -97,13 +102,17 @@ class LSTEventContainer(Container): tenMHz_counter = Field(None, "Dragon 10 MHz counter (n_modules)") event_counter = Field(None, "Dragon event counter (n_modules)") trigger_counter = Field(None, "Dragon trigger counter (n_modules)") - local_clock_counter = Field(None, "Dragon local 133 MHz counter (n_modules)") - chips_flags = Field(None, "chips flags") - first_capacitor_id = Field(None, "first capacitor id") + # Only in old R1 + configuration_id = Field(None, "id of the CameraConfiguration") + event_id = Field(None, "global id of the event") + tel_event_id = Field(None, "local id of the event") + ped_id = Field(None, "tel_event_id of the event used for pedestal substraction") + drs_tag_status = Field(None, "DRS tag status") drs_tag = Field(None, "DRS tag") + # custom here ucts_jump = Field(False, "A ucts jump happened in the current event") diff --git a/src/ctapipe_io_lst/tests/test_cta_r1.py b/src/ctapipe_io_lst/tests/test_cta_r1.py index 8b249ee3..9b22caae 100644 --- a/src/ctapipe_io_lst/tests/test_cta_r1.py +++ b/src/ctapipe_io_lst/tests/test_cta_r1.py @@ -13,8 +13,10 @@ from protozfits.CoreMessages_pb2 import AnyArray from traitlets.config import Config from ctapipe_io_lst import LSTEventSource +from ctapipe_io_lst.anyarray_dtypes import CDTS_AFTER_37201_DTYPE, TIB_DTYPE from ctapipe_io_lst.constants import CLOCK_FREQUENCY_KHZ from ctapipe.image.toymodel import WaveformModel, Gaussian +import socket from ctapipe_io_lst.event_time import time_to_cta_high @@ -120,6 +122,7 @@ def dummy_cta_r1(dummy_cta_r1_dir): num_samples = 40 num_pixels = 1855 num_modules = 265 + ucts_address = np.frombuffer(socket.inet_pton(socket.AF_INET, "10.0.100.123"), dtype=np.uint32)[0] run_start = Time("2023-05-16T16:06:31.123") camera_config = CameraConfiguration( @@ -161,14 +164,17 @@ def dummy_cta_r1(dummy_cta_r1_dir): if event_count % 20 == 18: # flatfield event_type = 0 + trigger_type = 0b0000_0001 image, peak_time = create_flat_field(rng) elif event_count % 20 == 19: # pedestal event_type = 2 + trigger_type = 0b0100_0000 image, peak_time = create_pedestal(rng) else: # air shower event_type = 32 + trigger_type = 0b0000_0100 image, peak_time = create_shower(rng) delta = rng.exponential(1 / event_rate.to_value(1 / u.s)) * u.s @@ -194,6 +200,32 @@ def dummy_cta_r1(dummy_cta_r1_dir): jitter = rng.choice([-2, 1, 0, 1, -2], size=num_modules) module_hires_local_clock_counter[:] += np.uint64(CLOCK_FREQUENCY_KHZ * delta.to_value(u.ms) + jitter) + # uint64 unix_tai, whole ns + timestamp = np.uint64(event_time_s) * np.uint64(1e9) + np.uint64(np.round(event_time_qns / 4.0)) + cdts_data = ( + timestamp, + ucts_address, + event_count + 1, # event_counter + 0, # busy_counter + 0, # pps_counter + 0, # clock_counter + trigger_type, # trigger_type + 0, # white_rabbit_status + 0, # stereo_pattern + event_count % 10, # num_in_bunch + 1234, # cdts_version + ) + cdts_data = np.array([cdts_data], dtype=CDTS_AFTER_37201_DTYPE) + + tib_data = ( + event_count + 1, + 0, # pps_counter + 0, # tenMHz_counter + 0, # stereo pattern + trigger_type, + ) + tib_data = np.array([tib_data], dtype=TIB_DTYPE) + event = Event( event_id=event_count + 1, tel_id=1, @@ -208,6 +240,12 @@ def dummy_cta_r1(dummy_cta_r1_dir): waveform=to_anyarray(waveform), first_cell_id=to_anyarray(first_cell_id), module_hires_local_clock_counter=to_anyarray(module_hires_local_clock_counter), + debug=DebugEvent( + module_status=to_anyarray(np.ones(num_modules, dtype=np.uint8)), + extdevices_presence=0b011, + cdts_data=to_anyarray(cdts_data.view(np.uint8)), + tib_data=to_anyarray(tib_data.view(np.uint8)), + ) )