|
9 | 9 | dataset = process_codice_l2(l1_filename) |
10 | 10 | """ |
11 | 11 |
|
12 | | -import json |
13 | 12 | import logging |
14 | | -from pathlib import Path |
15 | 13 |
|
16 | 14 | import numpy as np |
17 | 15 | import pandas as pd |
18 | 16 | import xarray as xr |
19 | 17 | from imap_data_access import ProcessingInputCollection, ScienceFilePath |
| 18 | +from numpy._typing import NDArray |
20 | 19 |
|
21 | 20 | from imap_processing.cdf.imap_cdf_manager import ImapCdfAttributes |
22 | 21 | from imap_processing.cdf.utils import load_cdf |
|
45 | 44 | logger = logging.getLogger(__name__) |
46 | 45 |
|
47 | 46 |
|
| 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 | + |
48 | 80 | def get_mpq_calc_energy_conversion_vals( |
49 | 81 | dependencies: ProcessingInputCollection, |
50 | 82 | ) -> np.ndarray: |
@@ -86,7 +118,9 @@ def get_mpq_calc_tof_conversion_vals( |
86 | 118 | tof_ns : np.ndarray |
87 | 119 | Tof in ns for each TOF bit. |
88 | 120 | """ |
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 | + ] |
90 | 124 | mpq_df = pd.read_csv(mpq_calc_lut_file, header=None) |
91 | 125 | ns_channel_sq = float(mpq_df.loc[2, 1]) |
92 | 126 | ns_channel = float(mpq_df.loc[3, 1]) |
@@ -944,7 +978,7 @@ def process_lo_direct_events(dependencies: ProcessingInputCollection) -> xr.Data |
944 | 978 | cdf_attrs = ImapCdfAttributes() |
945 | 979 | cdf_attrs.add_instrument_global_attrs("codice") |
946 | 980 | cdf_attrs.add_instrument_variable_attrs("codice", "l2-lo-direct-events") |
947 | | - |
| 981 | + energy_table, energy_bins = get_lo_de_energy_luts(dependencies) |
948 | 982 | # Convert from position to elevation angle in degrees relative to the spacecraft |
949 | 983 | # axis |
950 | 984 | l2_dataset = l1a_dataset.copy(deep=True) |
@@ -977,32 +1011,30 @@ def process_lo_direct_events(dependencies: ProcessingInputCollection) -> xr.Data |
977 | 1011 | ) |
978 | 1012 | # convert apd energy to physical units |
979 | 1013 | # 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() |
983 | 1017 | apd_energy_shape = l2_dataset["apd_energy"].shape |
984 | 1018 |
|
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] |
988 | 1026 | ) |
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)] |
1003 | 1035 |
|
1004 | 1036 | 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) |
1006 | 1038 | ) |
1007 | 1039 |
|
1008 | 1040 | # Calculate TOF in nanoseconds |
|
0 commit comments