Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@
(r"py:.*", r".*numpy._typing._array_like._ScalarType_co.*"),
(r"py:.*", r".*idex.l1a.TRIGGER_DESCRIPTION.*"),
(r"py:.*", r".*idex.l1b.TriggerOrigin.*"),
(r"py:.*", r".*idex.l1b.EventMessage.*"),
(r"py:.*", r".*idex.l2a.BaselineNoiseTime.*"),
(r"py:.*", r".*PacketProperties"),
(r"py:.*", r".*.spice.geometry.SpiceBody.*"),
Expand Down
16 changes: 8 additions & 8 deletions imap_processing/cdf/config/imap_idex_global_cdf_attrs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ imap_idex_l1a_sci:
Logical_source_description: IMAP Mission IDEX Instrument Level-1A Weekly Data.

imap_idex_l1a_msg:
<<: *instrument_base
Data_type: L1A_MSG>Level-1A Event Message Data
Logical_source: imap_idex_l1a_msg
Logical_source_description: IMAP Mission IDEX Instrument Level-1A Event Message Data.
<<: *instrument_base
Data_type: L1A_MSG>Level-1A Event Message Data
Logical_source: imap_idex_l1a_msg
Logical_source_description: IMAP Mission IDEX Instrument Level-1A Event Message Data.

imap_idex_l1a_catlst:
<<: *instrument_base
Expand All @@ -34,10 +34,10 @@ imap_idex_l1b_sci:
Logical_source_description: IMAP Mission IDEX Instrument Level-1B Weekly Data.

imap_idex_l1b_msg:
<<: *instrument_base
Data_type: L1B_MSG>Level-1B Event Message Data
Logical_source: imap_idex_l1b_msg
Logical_source_description: IMAP Mission IDEX Instrument Level-1B Event Message Data.
<<: *instrument_base
Data_type: L1B_MSG>Level-1B Event Message Data
Logical_source: imap_idex_l1b_msg
Logical_source_description: IMAP Mission IDEX Instrument Level-1B Event Message Data.

imap_idex_l1b_catlst:
<<: *instrument_base
Expand Down
2 changes: 2 additions & 0 deletions imap_processing/cdf/config/imap_idex_l1a_variable_attrs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ shcoarse:
FIELDNAM: Secondary header coarse time
LABLAXIS: Packet Generation Time (Coarse)
UNITS: seconds
FILLVAL: 4294967295

shfine:
<<: *trigger_base
Expand All @@ -207,6 +208,7 @@ shfine:
VALIDMAX: *max_uint16
LABLAXIS: Packet Generation Time (Fine)
UNITS: seconds
FILLVAL: 65535

messages:
<<: *string_base
Expand Down
22 changes: 22 additions & 0 deletions imap_processing/cdf/config/imap_idex_l1b_variable_attrs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,28 @@ trigger_origin:
FIELDNAM: Trigger Origin
CATDESC: Trigger Origin of the event.

pulser_on:
<<: *trigger_base
FIELDNAM: Pulser On
CATDESC: Pulser state flag derived from message events (0=off, 1=on).
LABLAXIS: Pulser On
FORMAT: I1
FILLVAL: 255
VAR_TYPE: support_data
VALIDMIN: 0
VALIDMAX: 1

science_on:
<<: *trigger_base
FIELDNAM: Science On
CATDESC: Science acquisition state flag derived from message events (0=off, 1=on).
LABLAXIS: Science On
FORMAT: I1
FILLVAL: 255
VAR_TYPE: support_data
VALIDMIN: 0
VALIDMAX: 1

tof_high:
<<: *l1b_tof_base
CATDESC: Time of flight waveform on the high-gain channel
Expand Down
9 changes: 5 additions & 4 deletions imap_processing/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -1040,10 +1040,11 @@ def do_processing(
science_files = dependencies.get_file_paths(source="idex")
datasets = PacketParser(science_files[0]).data
elif self.data_level == "l1b":
if len(dependency_list) != 3:
n_expected_deps = 3 if self.descriptor == "sci-1week" else 1
if len(dependency_list) != n_expected_deps:
raise ValueError(
f"Unexpected dependencies found for IDEX L1B:"
f"{dependency_list}. Expected only three dependencies."
f"Unexpected dependencies found for IDEX L1B {self.descriptor}:"
f"{dependency_list}. Expected only {n_expected_deps} dependencies."
)
# get CDF file
science_files = dependencies.get_file_paths(source="idex")
Expand All @@ -1055,7 +1056,7 @@ def do_processing(
raise ValueError("No science files found for IDEX L1B processing.")
latest_file = max(science_datasets, key=lambda ds: ds["epoch"].data[0])
# process data
datasets = [idex_l1b(latest_file)]
datasets = [idex_l1b(latest_file, self.descriptor)]
elif self.data_level == "l2a":
if len(dependency_list) != 3:
raise ValueError(
Expand Down
2 changes: 1 addition & 1 deletion imap_processing/idex/evt_msg_decode_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def render_event_template(
Produce an event message string by replacing placeholders with parameter values.

Example template:
"Event {p0} occurred with value {p1+2:dictName}"
"Event {p0} occurred with value {p1+2|dictName}"

This would replace {p0} with the hex value of params[0], and replace {p1+2:dictName}
with the combined hex value of params[1] and params[2] (treated as big-endian bytes)
Expand Down
8 changes: 0 additions & 8 deletions imap_processing/idex/idex_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,3 @@ class ConversionFactors(float, Enum):

# Define the pointing reference frame for IDEX
IDEX_EVENT_REFERENCE_FRAME = SpiceFrame.ECLIPJ2000


class IDEXEvtAcquireCodes(IntEnum):
"""Create ENUM for event message ints that signify science acquire events."""

ACQSETUP = 2
ACQ = 3
CHILL = 5
6 changes: 4 additions & 2 deletions imap_processing/idex/idex_l1a.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,12 +135,14 @@ def _create_evt_msg_data(self, data: xr.Dataset) -> xr.Dataset:
data_vars={
"epoch": xr.DataArray(epoch, name="epoch", dims=["epoch"]),
"shfine": xr.DataArray(
data["shfine"].data, dims=["epoch"], attrs=data["shfine"].attrs
data["shfine"].data,
dims=["epoch"],
attrs=self.idex_attrs.get_variable_attributes("shfine"),
),
"shcoarse": xr.DataArray(
data["shcoarse"].data,
dims=["epoch"],
attrs=data["shcoarse"].attrs,
attrs=self.idex_attrs.get_variable_attributes("shcoarse"),
),
},
attrs=self.idex_attrs.get_global_attributes("imap_idex_l1a_msg"),
Expand Down
104 changes: 102 additions & 2 deletions imap_processing/idex/idex_l1b.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,19 @@
logger = logging.getLogger(__name__)


class EventMessage(Enum):
"""Enum class for event messages."""

PULSER_ON = "SEQ success (len=0x0580, opCodeLCDictionary(enstim))"
PULSER_OFF = "SEQ success (len=0x0580, opCodeLCDictionary(susprel))"
SCIENCE_ON = (
"SCI state change: sciState16Dictionary(ACQSETUP) ==> sciState16Dictionary(ACQ)"
)
SCIENCE_OFF = (
"SCI state change: sciState16Dictionary(ACQ) ==> sciState16Dictionary(CHILL)"
)


class TriggerOrigin(IntEnum):
"""Enum class for event trigger origins."""

Expand Down Expand Up @@ -104,9 +117,96 @@ def get_mode_label(mode: int, channel: str) -> str:
return f"{channel.upper()}{TriggerMode(mode).name}"


def idex_l1b(l1a_dataset: xr.Dataset) -> xr.Dataset:
def idex_l1b(l1a_dataset: xr.Dataset, descriptor: str) -> xr.Dataset:
"""
Process IDEX l1a data to create l1b data products based on the descriptor.

Parameters
----------
l1a_dataset : xarray.Dataset
IDEX L1a dataset to process.
descriptor : str
Descriptor to determine the type of l1b processing to perform. E.g. "sci-1week"
or "msg".

Returns
-------
l1b_dataset : xarray.Dataset
The``xarray`` dataset containing the processed data and supporting metadata.
"""
if descriptor.startswith("sci"):
return idex_l1b_science(l1a_dataset)
elif descriptor.startswith("msg"):
return idex_l1b_msg(l1a_dataset)
else:
raise ValueError(f"Unsupported descriptor: {descriptor}")


def idex_l1b_msg(l1a_dataset: xr.Dataset) -> xr.Dataset:
"""
Will process IDEX l1a msg data.

Parameters
----------
l1a_dataset : xarray.Dataset
IDEX L1a dataset to process.

Returns
-------
l1b_dataset : xarray.Dataset
The``xarray`` dataset containing the msg housekeeping data and
supporting metadata.
"""
logger.info(
f"Running IDEX L1B MSG processing on dataset: "
f"{l1a_dataset.attrs['Logical_source']}"
)
# create the attribute manager for this data level
idex_attrs = get_idex_attrs("l1b")
# set up a dataset with only epoch.
l1b_dataset = setup_dataset(l1a_dataset, [], idex_attrs, data_vars=None)
l1b_dataset.attrs = idex_attrs.get_global_attributes("imap_idex_l1b_msg")
# Compute science_on and pulser_on variables based on the event message. The
# "science_on" variable indicates when the science data collection is turned on or
# off and the "pulser_on" variable indicates when the pulser is turned on or off.
# The following logic is applied to determine the pulser_on status.
# enstim → set pulser_on = 1
# susprel AND the previous message was enstim → set pulser_on = 0
# susprel but previous message was NOT enstim → pulser_on stays whatever it was
l1a_messages = l1a_dataset.messages.values
# Set science_on to 1 when science is on and 0 when it is off. 255 otherwise.
science_on = np.where(l1a_messages == EventMessage.SCIENCE_ON.value, 1, 255)
science_on[l1a_messages == EventMessage.SCIENCE_OFF.value] = 0
# Find indices where there are consecutive PULSER_ON followed by PULSER_OFF
# messages. These are the only cases where we should set pulser_on to 1 and 0.
# Compare the messages by shifting the pulser off messages back by one and looking
# for matching overlaps.
consecutive_pulser_on_off = np.where(
(l1a_messages[:-1] == EventMessage.PULSER_ON.value)
& (l1a_messages[1:] == EventMessage.PULSER_OFF.value)
)[0]
pulser_on = np.full(len(l1a_messages), 255) # initialize with 255 (unknown)
pulser_on[consecutive_pulser_on_off] = 1
pulser_on[consecutive_pulser_on_off + 1] = 0
l1b_dataset["pulser_on"] = xr.DataArray(
data=pulser_on,
dims="epoch",
name="pulser_on",
attrs=idex_attrs.get_variable_attributes("pulser_on"),
)
l1b_dataset["science_on"] = xr.DataArray(
data=science_on,
dims="epoch",
name="science_on",
attrs=idex_attrs.get_variable_attributes("science_on"),
)
logger.info("IDEX L1B MSG data processing completed.")
return l1b_dataset


def idex_l1b_science(l1a_dataset: xr.Dataset) -> xr.Dataset:
"""
Will process IDEX l1a data to create l1b data products.
Will process IDEX l1a science data.

Parameters
----------
Expand Down
Loading
Loading