Skip to content

Commit 81dd9b1

Browse files
committed
lo lut refactor:
1 parent db14f32 commit 81dd9b1

File tree

4 files changed

+78
-29
lines changed

4 files changed

+78
-29
lines changed

imap_processing/codice/codice_l2.py

Lines changed: 57 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,13 @@
99
dataset = process_codice_l2(l1_filename)
1010
"""
1111

12-
import json
1312
import logging
14-
from pathlib import Path
1513

1614
import numpy as np
1715
import pandas as pd
1816
import xarray as xr
1917
from imap_data_access import ProcessingInputCollection, ScienceFilePath
18+
from numpy._typing import NDArray
2019

2120
from imap_processing.cdf.imap_cdf_manager import ImapCdfAttributes
2221
from imap_processing.cdf.utils import load_cdf
@@ -45,6 +44,39 @@
4544
logger = logging.getLogger(__name__)
4645

4746

47+
def get_lo_de_energy_luts(
48+
dependencies: ProcessingInputCollection,
49+
) -> tuple[NDArray, NDArray]:
50+
"""
51+
Get the LO DE lookup tables for energy conversions.
52+
53+
Parameters
54+
----------
55+
dependencies : ProcessingInputCollection
56+
The collection of processing input files.
57+
58+
Returns
59+
-------
60+
energy_lut : np.ndarray
61+
An array of energy in keV for each energy table index.
62+
energy_bins_lut : np.ndarray
63+
An array of energy bins.
64+
"""
65+
# Get lookup tables
66+
energy_table_file = dependencies.get_file_paths(
67+
descriptor="l2-lo-onboard-energy-table"
68+
)[0]
69+
energy_bins_file = dependencies.get_file_paths(
70+
descriptor="l2-lo-onboard-energy-bins"
71+
)[0]
72+
energy_lut = pd.read_csv(energy_table_file, header=None, skiprows=1).to_numpy()
73+
energy_bins_lut = pd.read_csv(energy_bins_file, header=None, skiprows=1).to_numpy()[
74+
:, 1
75+
]
76+
77+
return energy_lut, energy_bins_lut
78+
79+
4880
def get_mpq_calc_energy_conversion_vals(
4981
dependencies: ProcessingInputCollection,
5082
) -> np.ndarray:
@@ -86,7 +118,9 @@ def get_mpq_calc_tof_conversion_vals(
86118
tof_ns : np.ndarray
87119
Tof in ns for each TOF bit.
88120
"""
89-
mpq_calc_lut_file = dependencies.get_file_paths(descriptor="lo-mpq-cal")[0]
121+
mpq_calc_lut_file = dependencies.get_file_paths(descriptor="l2-lo-onboard-mpq-cal")[
122+
0
123+
]
90124
mpq_df = pd.read_csv(mpq_calc_lut_file, header=None)
91125
ns_channel_sq = float(mpq_df.loc[2, 1])
92126
ns_channel = float(mpq_df.loc[3, 1])
@@ -944,7 +978,7 @@ def process_lo_direct_events(dependencies: ProcessingInputCollection) -> xr.Data
944978
cdf_attrs = ImapCdfAttributes()
945979
cdf_attrs.add_instrument_global_attrs("codice")
946980
cdf_attrs.add_instrument_variable_attrs("codice", "l2-lo-direct-events")
947-
981+
energy_table, energy_bins = get_lo_de_energy_luts(dependencies)
948982
# Convert from position to elevation angle in degrees relative to the spacecraft
949983
# axis
950984
l2_dataset = l1a_dataset.copy(deep=True)
@@ -977,32 +1011,30 @@ def process_lo_direct_events(dependencies: ProcessingInputCollection) -> xr.Data
9771011
)
9781012
# convert apd energy to physical units
9791013
# Set the gain labels based on gain values
980-
gains = l2_dataset["gain"].values.flat
981-
apd_ids = l2_dataset["apd_id"].values.flat
982-
apd_energy = l2_dataset["apd_energy"].values.flat
1014+
gains = l2_dataset["gain"].values.ravel()
1015+
apd_ids = l2_dataset["apd_id"].values.ravel()
1016+
apd_energy = l2_dataset["apd_energy"].values.ravel()
9831017
apd_energy_shape = l2_dataset["apd_energy"].shape
9841018

985-
file_path = Path(
986-
"/Users/luco3133/projects/imap_processing/imap_processing/tests"
987-
"/codice/data/l2_lut/imap_codice_l2-lo-onboard.json"
1019+
# The energy table lookup columns are ordered by apd_id and gain
1020+
# E.g. APD-0-LG, APD-0-HG, APD-1-LG, APD-1-HG, ..., APD-29-LG
1021+
# So we can get the col index like so: ind = apd_id * 2 + gain
1022+
col_inds = apd_ids * 2 + gains
1023+
# Get a mask of valid indices
1024+
valid_mask = (apd_energy < energy_table.shape[0]) & (
1025+
col_inds < energy_table.shape[1]
9881026
)
989-
onboard_lut = json.loads(file_path.read_text()).get("20250519")
990-
energy_table = onboard_lut.get("energy_table", {})
991-
energy_bins = onboard_lut.get("energy_bins", {})
992-
energy_kevs = []
993-
994-
for apd_id, gain, energy_pos in zip(apd_ids, gains, apd_energy, strict=False):
995-
if (energy_pos != 65535) & (apd_id < 30) & (apd_id != 0):
996-
gain_str = "LG" if gain == 0 else "HG"
997-
# TODO remove the -1 when Joey fixes the LUT to have correct apd_id
998-
key = "APD-" + str(apd_id - 1) + "-" + gain_str
999-
energy_bin = energy_table[key][energy_pos]
1000-
energy_kevs.append(energy_bins[str(energy_bin)])
1001-
else:
1002-
energy_kevs.append(np.nan)
1027+
# Initialize output array with NaNs
1028+
energy_bins_inds = np.full(apd_energy.shape, np.nan)
1029+
energy_kev = np.full(apd_energy.shape, np.nan)
1030+
# The rows are apd_energy bins
1031+
energy_bins_inds[valid_mask] = energy_table[
1032+
apd_energy[valid_mask], col_inds[valid_mask]
1033+
]
1034+
energy_kev[valid_mask] = energy_bins[energy_bins_inds[valid_mask].astype(int)]
10031035

10041036
l2_dataset["apd_energy"].data = (
1005-
np.array(energy_kevs).astype(np.float32).reshape(apd_energy_shape)
1037+
np.array(energy_kev).astype(np.float32).reshape(apd_energy_shape)
10061038
)
10071039

10081040
# Calculate TOF in nanoseconds

imap_processing/tests/codice/conftest.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -256,8 +256,21 @@ def _side_effect(descriptor: str = None, data_type: str = None) -> list[Path]:
256256
return [
257257
TEST_DATA_PATH / "l2_lut/imap_codice_l2-lo-gfactor_20251008_v001.csv"
258258
]
259-
elif descriptor == "lo-mpq-cal":
260-
return [TEST_DATA_PATH / "l2_lut/imap_codice_lo-mpq-cal_20250101_v001.csv"]
259+
elif descriptor == "l2-lo-onboard-mpq-cal":
260+
return [
261+
TEST_DATA_PATH
262+
/ "l2_lut/imap_codice_l2-lo-onboard-mpq-cal_20250101_v001.csv"
263+
]
264+
elif descriptor == "l2-lo-onboard-energy-bins":
265+
return [
266+
TEST_DATA_PATH
267+
/ "l2_lut/imap_codice_l2-lo-onboard-energy-bins_20250101_v001.csv"
268+
]
269+
elif descriptor == "l2-lo-onboard-energy-table":
270+
return [
271+
TEST_DATA_PATH
272+
/ "l2_lut/imap_codice_l2-lo-onboard-energy-table_20250101_v001.csv"
273+
]
261274
else:
262275
raise ValueError(f"Unknown descriptor: {descriptor}")
263276

imap_processing/tests/codice/test_codice_l2.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -521,8 +521,9 @@ def test_codice_l2_lo_de(mock_get_file_paths, codice_lut_path):
521521
mock_get_file_paths.side_effect = [
522522
[file_path],
523523
[file_path],
524-
codice_lut_path(descriptor="lo-mpq-cal"),
525-
codice_lut_path(descriptor="lo-mpq-cal"),
524+
codice_lut_path(descriptor="l2-lo-onboard-energy-table"),
525+
codice_lut_path(descriptor="l2-lo-onboard-energy-bins"),
526+
codice_lut_path(descriptor="l2-lo-onboard-mpq-cal"),
526527
]
527528

528529
processed_l2_ds = process_codice_l2("lo-direct-events", ProcessingInputCollection())

imap_processing/tests/external_test_data_config.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@
8383
("imap_codice_l2-hi-ialirt-efficiency_20251008_v001.csv", "codice/data/l2_lut/"),
8484
("imap_codice_l2-lo-gfactor_20251008_v001.csv", "codice/data/l2_lut/"),
8585
("imap_codice_l2-lo-efficiency_20251008_v001.csv", "codice/data/l2_lut/"),
86+
("imap_codice_l2-lo-onboard-energy-bins_20250101_v001.csv", "codice/data/l2_lut/"),
87+
("imap_codice_l2-lo-onboard-energy-table_20250101_v001.csv", "codice/data/l2_lut/"),
88+
("imap_codice_l2-lo-onboard-mpq-cal_20250101_v001.csv", "codice/data/l2_lut/"),
8689

8790
# L2 Validation data
8891
(f"imap_codice_l2_hi-omni_{VALIDATION_FILE_DATE}_{VALIDATION_FILE_VERSION}.cdf", "codice/data/l2_validation/"),

0 commit comments

Comments
 (0)