Skip to content

Commit 7e86527

Browse files
committed
added apid 897
1 parent 9910893 commit 7e86527

8 files changed

Lines changed: 79 additions & 89 deletions

File tree

imap_processing/cdf/config/imap_ultra_global_cdf_attrs.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,18 @@ imap_ultra_l1a_90sensor-de:
5656
Logical_source: imap_ultra_l1a_90sensor-de
5757
Logical_source_description: IMAP-Ultra Instrument Level-1A Direct Event Data.
5858

59+
imap_ultra_l1a_45sensor-energy-de:
60+
<<: *instrument_base
61+
Data_type: L1A_ENERGY_DE>Level-1A Energy Direct Event
62+
Logical_source: imap_ultra_l1a_45sensor-energy-de
63+
Logical_source_description: IMAP-Ultra Instrument Level-1A Energy Direct Event Data.
64+
65+
imap_ultra_l1a_90sensor-energy-de:
66+
<<: *instrument_base
67+
Data_type: L1A_ENERGY_DE>Level-1A EnergyDirect Event
68+
Logical_source: imap_ultra_l1a_90sensor-energy-de
69+
Logical_source_description: IMAP-Ultra Instrument Level-1A Energy Direct Event Data.
70+
5971
imap_ultra_l1b_45sensor-de:
6072
<<: *instrument_base
6173
Data_type: L1B_45Sensor-DE>Level-1B Direct Events for Ultra45

imap_processing/tests/external_test_data_config.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@
6363
("IMAP-Ultra45_r1_L1_V0_shortened.csv", "ultra/data/l1/"),
6464

6565
# Ultra
66+
("ultra45_raw_sc_rawnrgevnt_FM45_UltraFM45_Functional_2024-01-22T0105_20240122T010548.csv", "ultra/data/l0/"),
67+
("ultra45_raw_sc_imgpriority1evnt_FM45_UltraFM45Extra_TV_Tests_2024-01-22T0930_20240122T093008.csv", "ultra/data/l0/"),
6668
("imap_ultra_l0_raw_20260924_v001.pkts", "ultra/data/l0/"),
6769
("imap_ultra_l1b_45sensor-de_20240207_v999.cdf", "ultra/data/l1/"),
6870
("ultra-90_raw_event_data_shortened.csv", "ultra/data/l1/"),

imap_processing/tests/ultra/unit/conftest.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
)
1313
from imap_processing.ultra.l0.ultra_utils import (
1414
ULTRA_AUX,
15+
ULTRA_ENERGY_EVENTS,
1516
ULTRA_EVENTS,
1617
ULTRA_RATES,
1718
ULTRA_TOF,
@@ -86,6 +87,19 @@ def ccsds_path_tof():
8687
)
8788

8889

90+
@pytest.fixture
91+
def ccsds_path_functional():
92+
"""Returns the ccsds directory."""
93+
return (
94+
imap_module_directory
95+
/ "tests"
96+
/ "ultra"
97+
/ "data"
98+
/ "l0"
99+
/ "FM45_UltraFM45_Functional_2024-01-22T0105_20240122T010548.CCSDS"
100+
)
101+
102+
89103
@pytest.fixture
90104
def xtce_path():
91105
"""Returns the xtce image rates directory."""
@@ -147,15 +161,17 @@ def decom_test_data(request, xtce_path):
147161

148162
strategy_dict = {
149163
ULTRA_TOF.apid[0]: process_ultra_tof,
164+
ULTRA_ENERGY_EVENTS.apid[0]: process_ultra_events,
150165
ULTRA_EVENTS.apid[0]: process_ultra_events,
151166
ULTRA_RATES.apid[0]: process_ultra_rates,
152167
ULTRA_TOF.apid[1]: process_ultra_tof,
168+
ULTRA_ENERGY_EVENTS.apid[1]: process_ultra_events,
153169
ULTRA_EVENTS.apid[1]: process_ultra_events,
154170
ULTRA_RATES.apid[1]: process_ultra_rates,
155171
}
156172

157173
process_function = strategy_dict.get(apid, lambda *args: False)
158-
data_packet_xarray = process_function(datasets_by_apid[apid])
174+
data_packet_xarray = process_function(datasets_by_apid[apid], apid)
159175

160176
return data_packet_xarray
161177

imap_processing/tests/ultra/unit/test_ultra_l1a.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from imap_processing.ultra.l0.decom_ultra import get_event_id
99
from imap_processing.ultra.l0.ultra_utils import (
1010
ULTRA_AUX,
11+
ULTRA_ENERGY_EVENTS,
1112
ULTRA_EVENTS,
1213
ULTRA_RATES,
1314
ULTRA_TOF,
@@ -123,6 +124,20 @@ def test_cdf_events(ccsds_path_theta_0):
123124
)
124125

125126

127+
def test_cdf_energy_events(ccsds_path_functional):
128+
"""Tests that CDF file can be created."""
129+
test_data = ultra_l1a(ccsds_path_functional, apid_input=ULTRA_ENERGY_EVENTS.apid[0])
130+
test_data[0].attrs["Data_version"] = "999"
131+
test_data[0].attrs["Repointing"] = "repoint99999"
132+
test_data_path = write_cdf(test_data[0], istp=True)
133+
134+
assert test_data_path.exists()
135+
assert (
136+
test_data_path.name
137+
== "imap_ultra_l1a_45sensor-energy-de_20240122-repoint99999_v999.cdf"
138+
)
139+
140+
126141
def test_cdf_hk(ccsds_path_theta_0):
127142
"""Tests that CDF file can be created."""
128143
test_data = ultra_l1a(ccsds_path_theta_0, apid_input=869)

imap_processing/ultra/l0/decom_tools.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ def decompress_image(
239239
def read_image_raw_events_binary(
240240
event_data: bytes,
241241
count: int,
242+
field_ranges: dict,
242243
) -> NDArray:
243244
"""
244245
Convert contents of binary string 'EVENTDATA' into values.
@@ -249,22 +250,25 @@ def read_image_raw_events_binary(
249250
Event data.
250251
count : int
251252
Number of events.
253+
field_ranges : dict
254+
Field ranges for the event data.
252255
253256
Returns
254257
-------
255258
event_data : NDArray
256259
Event data.
257260
"""
258261
binary = convert_to_binary_string(event_data)
259-
# 166 bits per event
260-
event_length = 166 if count else 0
262+
length = max(end for _, (_, end) in field_ranges.items())
263+
# bits per event
264+
event_length = length if count else 0
261265
event_data_list = []
262266

263267
# For all packets with event data, parses the binary string
264268
for i in range(count):
265269
start_index = i * event_length
266270
event_binary = binary[start_index : start_index + event_length]
267-
parsed_event = parse_event(event_binary)
271+
parsed_event = parse_event(event_binary, field_ranges)
268272
event_data_list.append(parsed_event)
269273

270274
return np.array(event_data_list)

imap_processing/ultra/l0/decom_ultra.py

Lines changed: 16 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
ENERGY_EVENT_FIELD_RANGES,
1919
EVENT_FIELD_RANGES,
2020
RATES_KEYS,
21+
ULTRA_ENERGY_EVENTS,
22+
ULTRA_EVENTS,
2123
ULTRA_RATES,
2224
ULTRA_TOF,
2325
)
@@ -137,93 +139,29 @@ def get_event_id(shcoarse: NDArray) -> NDArray:
137139
return np.array(event_ids, dtype=np.int64)
138140

139141

140-
def process_ultra_events(ds: xr.Dataset) -> xr.Dataset:
142+
def process_ultra_events(ds: xr.Dataset, apid: int) -> xr.Dataset:
141143
"""
142144
Unpack and decode Ultra EVENTS packets.
143145
144146
Parameters
145147
----------
146148
ds : xarray.Dataset
147149
Events dataset.
150+
apid : int
151+
APID of the events dataset.
148152
149153
Returns
150154
-------
151155
ds : xarray.Dataset
152156
Dataset containing the decoded and decompressed data.
153157
"""
154-
all_events = []
155-
all_indices = []
156-
157-
attrs = ImapCdfAttributes()
158-
attrs.add_instrument_variable_attrs("ultra", level="l1a")
159-
160-
empty_event = {
161-
field: attrs.get_variable_attributes(field).get(
162-
"FILLVAL", np.iinfo(np.int64).min
163-
)
164-
for field in EVENT_FIELD_RANGES
165-
}
166-
167-
counts = ds["count"].values
168-
eventdata_array = ds["eventdata"].values
169-
170-
for i, count in enumerate(counts):
171-
if count == 0:
172-
all_events.append(empty_event)
173-
all_indices.append(i)
174-
else:
175-
# Here there are multiple images in a single packet,
176-
# so we need to loop through each image and decompress it.
177-
event_data_list = read_image_raw_events_binary(eventdata_array[i], count)
178-
all_events.extend(event_data_list)
179-
# Keep track of how many times does the event occurred at this epoch.
180-
all_indices.extend([i] * count)
158+
if apid in ULTRA_EVENTS.apid:
159+
field_ranges = EVENT_FIELD_RANGES
160+
elif apid in ULTRA_ENERGY_EVENTS.apid:
161+
field_ranges = ENERGY_EVENT_FIELD_RANGES
162+
else:
163+
logger.error(f"APID {apid} not recognized for Ultra events processing.")
181164

182-
# Now we have the event data, we need to create the xarray dataset.
183-
# We cannot append to the existing dataset (sorted_packets)
184-
# because there are multiple events for each epoch.
185-
idx = np.array(all_indices)
186-
187-
# Expand the existing dataset so that it is the same length as the event data.
188-
expanded_data = {
189-
var: ds[var].values[idx] for var in ds.data_vars if var != "eventdata"
190-
}
191-
192-
# Add the event data to the expanded dataset.
193-
for key in EVENT_FIELD_RANGES:
194-
expanded_data[key] = np.array([event[key] for event in all_events])
195-
196-
event_ids = get_event_id(expanded_data["shcoarse"])
197-
198-
coords = {
199-
"epoch": ds["epoch"].values[idx],
200-
"event_id": ("epoch", event_ids),
201-
}
202-
203-
dataset = xr.Dataset(coords=coords)
204-
for key, data in expanded_data.items():
205-
dataset[key] = xr.DataArray(
206-
data,
207-
dims=["epoch"],
208-
)
209-
210-
return dataset
211-
212-
213-
def process_ultra_energy_events(ds: xr.Dataset) -> xr.Dataset:
214-
"""
215-
Unpack and decode Ultra ENERGY EVENTS packets.
216-
217-
Parameters
218-
----------
219-
ds : xarray.Dataset
220-
Events dataset.
221-
222-
Returns
223-
-------
224-
ds : xarray.Dataset
225-
Dataset containing the decoded and decompressed data.
226-
"""
227165
all_events = []
228166
all_indices = []
229167

@@ -234,7 +172,7 @@ def process_ultra_energy_events(ds: xr.Dataset) -> xr.Dataset:
234172
field: attrs.get_variable_attributes(field).get(
235173
"FILLVAL", np.iinfo(np.int64).min
236174
)
237-
for field in ENERGY_EVENT_FIELD_RANGES
175+
for field in field_ranges
238176
}
239177

240178
counts = ds["count"].values
@@ -247,7 +185,9 @@ def process_ultra_energy_events(ds: xr.Dataset) -> xr.Dataset:
247185
else:
248186
# Here there are multiple images in a single packet,
249187
# so we need to loop through each image and decompress it.
250-
event_data_list = read_image_raw_events_binary(eventdata_array[i], count)
188+
event_data_list = read_image_raw_events_binary(
189+
eventdata_array[i], count, field_ranges
190+
)
251191
all_events.extend(event_data_list)
252192
# Keep track of how many times does the event occurred at this epoch.
253193
all_indices.extend([i] * count)
@@ -263,7 +203,7 @@ def process_ultra_energy_events(ds: xr.Dataset) -> xr.Dataset:
263203
}
264204

265205
# Add the event data to the expanded dataset.
266-
for key in EVENT_FIELD_RANGES:
206+
for key in field_ranges:
267207
expanded_data[key] = np.array([event[key] for event in all_events])
268208

269209
event_ids = get_event_id(expanded_data["shcoarse"])

imap_processing/ultra/l0/ultra_utils.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ class PacketProperties(NamedTuple):
5353
mantissa_bit_length=4,
5454
)
5555
ULTRA_EVENTS = PacketProperties(
56-
apid=[896, 960],
56+
apid=[898, 960],
5757
logical_source=["imap_ultra_l1a_45sensor-de", "imap_ultra_l1a_90sensor-de"],
5858
addition_to_logical_desc="Single Events",
5959
width=None,
@@ -223,11 +223,11 @@ class PacketProperties(NamedTuple):
223223
# Stop Type
224224
"stop_type": (0, 4),
225225
# Energy/Pulse Height
226-
"energy_ph": (5, 17),
226+
"energy_ph": (4, 16),
227227
# Pulse Width
228-
"pulse_width": (18, 29),
228+
"pulse_width": (16, 27),
229229
# Bin
230-
"bin": (30, 34),
230+
"bin": (27, 33),
231231
}
232232

233233

@@ -348,22 +348,24 @@ class PacketProperties(NamedTuple):
348348
]
349349

350350

351-
def parse_event(event_binary: str) -> dict:
351+
def parse_event(event_binary: str, field_ranges: dict) -> dict:
352352
"""
353353
Parse a binary string representing a single event.
354354
355355
Parameters
356356
----------
357357
event_binary : str
358358
Event binary string.
359+
field_ranges : dict
360+
The field ranges for the event data.
359361
360362
Returns
361363
-------
362364
fields_dict : dict
363365
Dict of the fields for a single event.
364366
"""
365367
fields_dict = {}
366-
for field, (start, end) in EVENT_FIELD_RANGES.items():
368+
for field, (start, end) in field_ranges.items():
367369
field_value = int(event_binary[start:end], 2)
368370
fields_dict[field] = field_value
369371
return fields_dict

imap_processing/ultra/l1a/ultra_l1a.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
from imap_processing import imap_module_directory
99
from imap_processing.cdf.imap_cdf_manager import ImapCdfAttributes
1010
from imap_processing.ultra.l0.decom_ultra import (
11-
process_ultra_energy_events,
1211
process_ultra_events,
1312
process_ultra_rates,
1413
process_ultra_tof,
@@ -78,13 +77,13 @@ def ultra_l1a(packet_file: str, apid_input: Optional[int] = None) -> list[xr.Dat
7877
decom_ultra_dataset = decom_ultra_dataset.drop_vars("fastdata_00")
7978
gattr_key = ULTRA_RATES.logical_source[ULTRA_RATES.apid.index(apid)]
8079
elif apid in ULTRA_EVENTS.apid:
81-
decom_ultra_dataset = process_ultra_events(datasets_by_apid[apid])
80+
decom_ultra_dataset = process_ultra_events(datasets_by_apid[apid], apid)
8281
gattr_key = ULTRA_EVENTS.logical_source[ULTRA_EVENTS.apid.index(apid)]
8382
# Add coordinate attributes
8483
attrs = attr_mgr.get_variable_attributes("event_id")
8584
decom_ultra_dataset.coords["event_id"].attrs.update(attrs)
8685
elif apid in ULTRA_ENERGY_EVENTS.apid:
87-
decom_ultra_dataset = process_ultra_energy_events(datasets_by_apid[apid])
86+
decom_ultra_dataset = process_ultra_events(datasets_by_apid[apid], apid)
8887
gattr_key = ULTRA_ENERGY_EVENTS.logical_source[
8988
ULTRA_ENERGY_EVENTS.apid.index(apid)
9089
]

0 commit comments

Comments
 (0)