diff --git a/docs/changes/2769.api.rst b/docs/changes/2769.api.rst new file mode 100644 index 00000000000..ac4fa24f10c --- /dev/null +++ b/docs/changes/2769.api.rst @@ -0,0 +1,12 @@ +Update definition of the ``ctapipe.containers.EventType`` enum +to match an updated definition in the CTAO R1 and DL0 data models. + +``SKY_PEDESTAL=2`` is changed to the generic ``PEDESTAL``, +which is expected from most cameras in real data. + +New types added are ``SKY_PEDESTAL=5`` and ``RANDOM_MONO=18``. + +These types were previously assigned at the subarray event level +but in fact are per telescope event in the data model. +A new field ``event_type`` was added to the ``TelescopeTriggerContainer`` +and will be filled by the ``EventSource``-implementations in ctapipe. diff --git a/src/ctapipe/containers.py b/src/ctapipe/containers.py index b05cf4133b3..e271da02f49 100644 --- a/src/ctapipe/containers.py +++ b/src/ctapipe/containers.py @@ -149,25 +149,40 @@ class CoordinateFrameType(enum.Enum): class EventType(enum.Enum): - """Enum of EventTypes as defined in :cite:p:`ctao-r1-event-data-model`""" + """R1/DL0 EventType - # calibrations are 0-15 + Defined in :cite:p:`ctao-r1-event-data-model`. + """ + + #: Flatfield event FLATFIELD = 0 + #: Single PE event SINGLE_PE = 1 - SKY_PEDESTAL = 2 + #: Generic pedestal, assigned if no further distinction on the type could be made + PEDESTAL = 2 + #: Dark pedestal, taken with HV on, shutter closed. DARK_PEDESTAL = 3 + #: Electronics pedestal, taken with HV off. ELECTRONIC_PEDESTAL = 4 + #: Sky pedestal, taken with HV on, shutter open + SKY_PEDESTAL = 5 OTHER_CALIBRATION = 15 - #: For mono-telescope triggers (not used in MC) + #: Muon event candidate MUON = 16 + #: (LST) hardware-stereo trigger HARDWARE_STEREO = 17 + #: Random mono trigger, used in simulations to force storage + #: of event regardless of subarray trigger for certain studies. + RANDOM_MONO = 18 #: ACADA (DAQ) software trigger DAQ = 24 - #: Standard Physics stereo trigger + #: Standard Physics trigger SUBARRAY = 32 + #: Standard Physics trigger with extended readout window + LONG_EVENT = 33 UNKNOWN = 255 @@ -919,6 +934,8 @@ class SimulationConfigContainer(Container): class TelescopeTriggerContainer(Container): default_prefix = "" time = Field(NAN_TIME, description="Telescope trigger time") + event_type = Field(EventType.UNKNOWN, description="Event type") + n_trigger_pixels = Field( -1, description="Number of trigger groups (sectors) listed" ) diff --git a/src/ctapipe/io/simteleventsource.py b/src/ctapipe/io/simteleventsource.py index b9338253e27..c8a8de7826d 100644 --- a/src/ctapipe/io/simteleventsource.py +++ b/src/ctapipe/io/simteleventsource.py @@ -1,7 +1,7 @@ import enum import warnings from contextlib import nullcontext -from enum import Enum, auto, unique +from enum import Enum, IntFlag, auto, unique from gzip import GzipFile from io import BufferedReader from pathlib import Path @@ -103,6 +103,37 @@ _float32_nan = np.float32(np.nan) +class SimTelTriggerMask(IntFlag): + """sim_telarray trigger type mask (teltrg_type_mask).""" + + ANALOG_MAJORITY = auto() + ANALOG_SUM = auto() + DIGITAL_SUM = auto() + DIGITAL_MAJORITY = auto() + RESERVED4 = auto() + RESERVED5 = auto() + RESERVED6 = auto() + RESERVED7 = auto() + LONG_EVENT = auto() + MUON = auto() + RANDOM_MONO = auto() + + +def _trigger_mask_to_event_type(trigger_mask): + trigger_mask = SimTelTriggerMask(int(trigger_mask)) + + if SimTelTriggerMask.RANDOM_MONO in trigger_mask: + return EventType.RANDOM_MONO + + if SimTelTriggerMask.MUON in trigger_mask: + return EventType.MUON + + if SimTelTriggerMask.LONG_EVENT in trigger_mask: + return EventType.LONG_EVENT + + return EventType.SUBARRAY + + def _clip_altitude_if_close(altitude): """ Round absolute values slightly larger than pi/2 in float64 to pi/2 @@ -1143,8 +1174,10 @@ def _fill_trigger_info(self, array_event): central_time = parse_simtel_time(trigger["gps_time"]) tel = Map(TelescopeTriggerContainer) - for tel_id, time in zip( - trigger["triggered_telescopes"], trigger["trigger_times"] + for tel_id, time, trigger_mask in zip( + trigger["triggered_telescopes"], + trigger["trigger_times"], + trigger["teltrg_type_mask"], ): if self.allowed_tels and tel_id not in self.allowed_tels: continue @@ -1171,6 +1204,7 @@ def _fill_trigger_info(self, array_event): tel[tel_id] = TelescopeTriggerContainer( time=time, + event_type=_trigger_mask_to_event_type(trigger_mask), n_trigger_pixels=n_trigger_pixels, trigger_pixels=trigger_pixels, )