Skip to content

Commit 7d0f90e

Browse files
authored
I-ALiRT - MAG l1b equivalent (IMAP-Science-Operations-Center#1661)
1 parent 5ac07b3 commit 7d0f90e

File tree

3 files changed

+206
-23
lines changed

3 files changed

+206
-23
lines changed

imap_processing/ialirt/l0/parse_mag.py

Lines changed: 138 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""Functions to support I-ALiRT MAG packet parsing."""
22

33
import logging
4+
from typing import Union
45

56
import numpy as np
67
import xarray as xr
@@ -13,6 +14,13 @@
1314
)
1415
from imap_processing.ialirt.utils.grouping import find_groups
1516
from imap_processing.ialirt.utils.time import calculate_time
17+
from imap_processing.mag.l1a.mag_l1a_data import TimeTuple
18+
from imap_processing.mag.l1b.mag_l1b import (
19+
calibrate_vector,
20+
retrieve_matrix_from_l1b_calibration,
21+
shift_time,
22+
)
23+
from imap_processing.spice.time import met_to_ttj2000ns
1624

1725
logger = logging.getLogger(__name__)
1826

@@ -132,7 +140,13 @@ def extract_magnetic_vectors(science_values: xr.DataArray) -> dict:
132140
return vectors
133141

134142

135-
def get_time(grouped_data: xr.Dataset, group: int, pkt_counter: xr.DataArray) -> dict:
143+
def get_time(
144+
grouped_data: xr.Dataset,
145+
group: int,
146+
pkt_counter: xr.DataArray,
147+
time_shift_mago: xr.DataArray,
148+
time_shift_magi: xr.DataArray,
149+
) -> dict:
136150
"""
137151
Get the time for the grouped data.
138152
@@ -144,12 +158,22 @@ def get_time(grouped_data: xr.Dataset, group: int, pkt_counter: xr.DataArray) ->
144158
Group number.
145159
pkt_counter : xr.DataArray
146160
Packet counter.
161+
time_shift_mago : xr.DataArray
162+
Time shift value mago.
163+
time_shift_magi : xr.DataArray
164+
Time shift value magi.
147165
148166
Returns
149167
-------
150168
time_data : dict
151169
Coarse and fine time for Primary and Secondary Sensors.
170+
171+
Notes
172+
-----
173+
Packet id 0 is course and fine time for the primary sensor PRI.
174+
Packet id 2 is the course time for the secondary sensor SEC.
152175
"""
176+
# Get the coarse and fine time for the primary and secondary sensors.
153177
pri_coarsetm = grouped_data["mag_acq_tm_coarse"][
154178
(grouped_data["group"] == group).values
155179
][pkt_counter == 0]
@@ -166,24 +190,111 @@ def get_time(grouped_data: xr.Dataset, group: int, pkt_counter: xr.DataArray) ->
166190
(grouped_data["group"] == group).values
167191
][pkt_counter == 2]
168192

169-
time_data = {
170-
"pri_coarsetm": int(pri_coarsetm),
171-
"pri_fintm": int(pri_fintm),
172-
"sec_coarsetm": int(sec_coarsetm),
173-
"sec_fintm": int(sec_fintm),
193+
time_data: dict[str, Union[int, float]] = {
194+
"pri_coarsetm": int(pri_coarsetm.item()),
195+
"pri_fintm": int(pri_fintm.item()),
196+
"sec_coarsetm": int(sec_coarsetm.item()),
197+
"sec_fintm": int(sec_fintm.item()),
174198
}
175199

200+
primary_time = TimeTuple(int(pri_coarsetm.item()), int(pri_fintm.item()))
201+
secondary_time = TimeTuple(int(sec_coarsetm.item()), int(sec_fintm.item()))
202+
time_data_pri_met = primary_time.to_seconds()
203+
time_data_primary_ttj2000ns = met_to_ttj2000ns(time_data_pri_met)
204+
time_data["primary_epoch"] = shift_time(
205+
time_data_primary_ttj2000ns, time_shift_mago
206+
)
207+
time_data_sec_met = secondary_time.to_seconds()
208+
time_data_secondary_ttj2000ns = met_to_ttj2000ns(time_data_sec_met)
209+
time_data["secondary_epoch"] = shift_time(
210+
time_data_secondary_ttj2000ns, time_shift_magi
211+
)
212+
176213
return time_data
177214

178215

179-
def parse_packet(accumulated_data: xr.Dataset) -> list[dict]:
216+
def calculate_l1b(
217+
grouped_data: xr.Dataset,
218+
group: int,
219+
pkt_counter: xr.DataArray,
220+
science_data: dict,
221+
status_data: dict,
222+
calibration_dataset: xr.Dataset,
223+
) -> tuple[np.ndarray, np.ndarray, dict]:
224+
"""
225+
Calculate equivalent of l1b data product.
226+
227+
Parameters
228+
----------
229+
grouped_data : xr.Dataset
230+
Grouped data.
231+
group : int
232+
Group number.
233+
pkt_counter : xr.DataArray
234+
Packet counter.
235+
science_data : dict
236+
Science data.
237+
status_data : dict
238+
Status data.
239+
calibration_dataset : xr.Dataset
240+
Calibration dataset.
241+
242+
Returns
243+
-------
244+
updated_vector_mago : numpy.ndarray
245+
Calibrated mago vector.
246+
updated_vector_magi : numpy.ndarray
247+
Calibrated magi vector.
248+
time_data : dict
249+
Time data.
250+
"""
251+
calibration_matrix_mago, time_shift_mago = retrieve_matrix_from_l1b_calibration(
252+
calibration_dataset, is_mago=True
253+
)
254+
calibration_matrix_magi, time_shift_magi = retrieve_matrix_from_l1b_calibration(
255+
calibration_dataset, is_mago=False
256+
)
257+
258+
# Get time values for each group.
259+
time_data = get_time(
260+
grouped_data, group, pkt_counter, time_shift_mago, time_shift_magi
261+
)
262+
263+
input_vector_mago = np.array(
264+
[
265+
science_data["pri_x"],
266+
science_data["pri_y"],
267+
science_data["pri_z"],
268+
status_data["fob_range"],
269+
]
270+
)
271+
input_vector_magi = np.array(
272+
[
273+
science_data["sec_x"],
274+
science_data["sec_y"],
275+
science_data["sec_z"],
276+
status_data["fib_range"],
277+
]
278+
)
279+
280+
updated_vector_mago = calibrate_vector(input_vector_mago, calibration_matrix_mago)
281+
updated_vector_magi = calibrate_vector(input_vector_magi, calibration_matrix_magi)
282+
283+
return updated_vector_mago, updated_vector_magi, time_data
284+
285+
286+
def process_packet(
287+
accumulated_data: xr.Dataset, calibration_dataset: xr.Dataset
288+
) -> list[dict]:
180289
"""
181290
Parse the MAG packets.
182291
183292
Parameters
184293
----------
185294
accumulated_data : xr.Dataset
186295
Packets dataset accumulated over 1 min.
296+
calibration_dataset : xr.Dataset
297+
Calibration dataset.
187298
188299
Returns
189300
-------
@@ -237,9 +348,26 @@ def parse_packet(accumulated_data: xr.Dataset) -> list[dict]:
237348
(grouped_data["group"] == group).values
238349
]
239350
science_data = extract_magnetic_vectors(science_values)
240-
241-
# Get time values for each group.
242-
time_data = get_time(grouped_data, group, pkt_counter)
351+
updated_vector_mago, updated_vector_magi, time_data = calculate_l1b(
352+
grouped_data,
353+
group,
354+
pkt_counter,
355+
science_data,
356+
status_data,
357+
calibration_dataset,
358+
)
359+
360+
# Note: primary = MAGo, secondary = MAGi.
361+
science_data.update(
362+
{
363+
"calibrated_pri_x": updated_vector_mago[0],
364+
"calibrated_pri_y": updated_vector_mago[1],
365+
"calibrated_pri_z": updated_vector_mago[2],
366+
"calibrated_sec_x": updated_vector_magi[0],
367+
"calibrated_sec_y": updated_vector_magi[1],
368+
"calibrated_sec_z": updated_vector_magi[2],
369+
}
370+
)
243371

244372
mag_data.append({**status_data, **science_data, **time_data})
245373

imap_processing/mag/l1b/mag_l1b.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ def shift_time(epoch_times: xr.DataArray, time_shift: xr.DataArray) -> xr.DataAr
369369
Parameters
370370
----------
371371
epoch_times : xr.DataArray
372-
The input epoch times, in J2000 ns.
372+
The input epoch times, in TT J2000 ns.
373373
time_shift : xr.DataArray
374374
The time shift to apply for the given sensor. This should be one value and is
375375
in seconds.

imap_processing/tests/ialirt/unit/test_parse_mag.py

Lines changed: 67 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,22 @@
1+
"""Tests to support I-ALiRT MAG packet parsing."""
2+
13
import numpy as np
24
import pandas as pd
35
import pytest
46
import xarray as xr
57

68
from imap_processing import imap_module_directory
9+
from imap_processing.cdf.utils import load_cdf
710
from imap_processing.ialirt.l0.parse_mag import (
11+
calculate_l1b,
812
extract_magnetic_vectors,
913
get_pkt_counter,
1014
get_status_data,
1115
get_time,
12-
parse_packet,
16+
process_packet,
17+
)
18+
from imap_processing.mag.l1b.mag_l1b import (
19+
retrieve_matrix_from_l1b_calibration,
1320
)
1421
from imap_processing.utils import packet_file_to_datasets
1522

@@ -107,6 +114,15 @@ def grouped_data():
107114
return grouped_data
108115

109116

117+
@pytest.fixture
118+
def calibration_dataset():
119+
"""Returns the calibration data."""
120+
calibration_dataset = load_cdf(
121+
imap_module_directory / "mag" / "l1b" / "imap_calibration_mag_20240229_v01.cdf"
122+
)
123+
return calibration_dataset
124+
125+
110126
def test_get_pkt_counter(xarray_data):
111127
"""Tests the get_pkt_counter function."""
112128
status_values = xarray_data["mag_status"].values
@@ -127,15 +143,24 @@ def test_get_status_data(xarray_data, mag_test_data):
127143
assert status_data[key] == matching_row[key.upper()].values[0]
128144

129145

130-
def test_get_time(grouped_data):
146+
def test_get_time(grouped_data, calibration_dataset):
131147
"""Tests the get_time function."""
132-
time_data = get_time(grouped_data, 1, np.array([0, 1, 2, 3]))
133-
assert time_data == {
134-
"pri_coarsetm": 461971386,
135-
"pri_fintm": 1500,
136-
"sec_coarsetm": 461971386,
137-
"sec_fintm": 1503,
138-
}
148+
149+
calibration_matrix_mago, time_shift_mago = retrieve_matrix_from_l1b_calibration(
150+
calibration_dataset, is_mago=True
151+
)
152+
calibration_matrix_magi, time_shift_magi = retrieve_matrix_from_l1b_calibration(
153+
calibration_dataset, is_mago=False
154+
)
155+
156+
time_data = get_time(
157+
grouped_data, 1, np.array([0, 1, 2, 3]), time_shift_mago, time_shift_magi
158+
)
159+
160+
assert time_data["pri_coarsetm"] == 461971386
161+
assert time_data["pri_fintm"] == 1500
162+
assert time_data["sec_coarsetm"] == 461971386
163+
assert time_data["sec_fintm"] == 1503
139164

140165

141166
def test_extract_magnetic_vectors():
@@ -156,13 +181,43 @@ def test_extract_magnetic_vectors():
156181
}
157182

158183

159-
def test_parse_packet(xarray_data, mag_test_data):
184+
def test_calculate_l1b(grouped_data, xarray_data, calibration_dataset):
185+
"""Tests the calculate_l1b function."""
186+
187+
pkt_counter = np.array([0.0, 1.0, 2.0, 3.0])
188+
189+
science_data = {
190+
"pri_x": 1.0,
191+
"pri_y": 2.0,
192+
"pri_z": 3.0,
193+
"sec_x": 4.0,
194+
"sec_y": 5.0,
195+
"sec_z": 6.0,
196+
}
197+
198+
status_data = {
199+
"fob_range": 1,
200+
"fib_range": 1,
201+
}
202+
203+
vec_mago, vec_magi, time_data = calculate_l1b(
204+
grouped_data, 0, pkt_counter, science_data, status_data, calibration_dataset
205+
)
206+
207+
assert vec_mago.shape == (4,)
208+
assert vec_magi.shape == (4,)
209+
assert "primary_epoch" in time_data
210+
assert "secondary_epoch" in time_data
211+
212+
213+
def test_process_packet(xarray_data, mag_test_data, calibration_dataset):
160214
"""Tests the parse_packet function."""
161-
parsed_packets = parse_packet(xarray_data)
215+
parsed_packets = process_packet(xarray_data, calibration_dataset)
162216

163217
for packet in parsed_packets:
164218
index = packet["pri_coarsetm"] == mag_test_data["PRI_COARSETM"]
165219
matching_rows = mag_test_data[index]
166220

167221
for key in packet.keys():
168-
assert packet[key] == matching_rows[key.upper()].values[0]
222+
if key.upper() in matching_rows.keys():
223+
assert packet[key] == matching_rows[key.upper()].values[0]

0 commit comments

Comments
 (0)