imap-processing 0.16.2__py3-none-any.whl → 0.18.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of imap-processing might be problematic. Click here for more details.
- imap_processing/_version.py +2 -2
- imap_processing/ccsds/excel_to_xtce.py +12 -0
- imap_processing/cdf/config/imap_codice_global_cdf_attrs.yaml +6 -6
- imap_processing/cdf/config/imap_codice_l1a_variable_attrs.yaml +35 -0
- imap_processing/cdf/config/imap_codice_l1b_variable_attrs.yaml +35 -0
- imap_processing/cdf/config/imap_codice_l2_variable_attrs.yaml +24 -0
- imap_processing/cdf/config/imap_hi_variable_attrs.yaml +8 -8
- imap_processing/cdf/config/imap_hit_global_cdf_attrs.yaml +1 -1
- imap_processing/cdf/config/imap_hit_l1a_variable_attrs.yaml +163 -100
- imap_processing/cdf/config/imap_hit_l2_variable_attrs.yaml +398 -415
- imap_processing/cdf/config/imap_ialirt_l1_variable_attrs.yaml +97 -54
- imap_processing/cdf/config/imap_idex_global_cdf_attrs.yaml +9 -9
- imap_processing/cdf/config/imap_idex_l2b_variable_attrs.yaml +233 -57
- imap_processing/cdf/config/imap_idex_l2c_variable_attrs.yaml +16 -90
- imap_processing/cdf/config/imap_lo_global_cdf_attrs.yaml +30 -0
- imap_processing/cdf/config/imap_mag_global_cdf_attrs.yaml +15 -1
- imap_processing/cdf/config/imap_swapi_variable_attrs.yaml +19 -0
- imap_processing/cdf/config/imap_swe_l1b_variable_attrs.yaml +20 -0
- imap_processing/cdf/config/imap_swe_l2_variable_attrs.yaml +39 -0
- imap_processing/cdf/config/imap_ultra_global_cdf_attrs.yaml +168 -0
- imap_processing/cdf/config/imap_ultra_l1a_variable_attrs.yaml +103 -2
- imap_processing/cdf/config/imap_ultra_l1b_variable_attrs.yaml +91 -11
- imap_processing/cdf/utils.py +7 -1
- imap_processing/cli.py +42 -13
- imap_processing/codice/codice_l1a.py +125 -78
- imap_processing/codice/codice_l1b.py +1 -1
- imap_processing/codice/codice_l2.py +0 -9
- imap_processing/codice/constants.py +481 -498
- imap_processing/hi/hi_l1a.py +4 -4
- imap_processing/hi/hi_l1b.py +2 -2
- imap_processing/hi/packet_definitions/TLM_HI_COMBINED_SCI.xml +218 -38
- imap_processing/hit/hit_utils.py +2 -2
- imap_processing/hit/l0/decom_hit.py +4 -3
- imap_processing/hit/l1a/hit_l1a.py +64 -24
- imap_processing/hit/l1b/constants.py +5 -0
- imap_processing/hit/l1b/hit_l1b.py +18 -16
- imap_processing/hit/l2/constants.py +1 -1
- imap_processing/hit/l2/hit_l2.py +4 -4
- imap_processing/ialirt/constants.py +21 -0
- imap_processing/ialirt/generate_coverage.py +188 -0
- imap_processing/ialirt/l0/parse_mag.py +62 -5
- imap_processing/ialirt/l0/process_swapi.py +1 -1
- imap_processing/ialirt/l0/process_swe.py +23 -7
- imap_processing/ialirt/utils/constants.py +22 -16
- imap_processing/ialirt/utils/create_xarray.py +42 -19
- imap_processing/idex/idex_constants.py +8 -5
- imap_processing/idex/idex_l2b.py +554 -58
- imap_processing/idex/idex_l2c.py +30 -196
- imap_processing/lo/l0/lo_apid.py +1 -0
- imap_processing/lo/l0/lo_star_sensor.py +48 -0
- imap_processing/lo/l1a/lo_l1a.py +74 -30
- imap_processing/lo/packet_definitions/lo_xtce.xml +5359 -106
- imap_processing/mag/constants.py +1 -0
- imap_processing/mag/l0/decom_mag.py +9 -6
- imap_processing/mag/l0/mag_l0_data.py +46 -0
- imap_processing/mag/l1d/__init__.py +0 -0
- imap_processing/mag/l1d/mag_l1d.py +133 -0
- imap_processing/mag/l1d/mag_l1d_data.py +588 -0
- imap_processing/mag/l2/__init__.py +0 -0
- imap_processing/mag/l2/mag_l2.py +25 -20
- imap_processing/mag/l2/mag_l2_data.py +191 -130
- imap_processing/quality_flags.py +20 -2
- imap_processing/spice/geometry.py +25 -3
- imap_processing/spice/pointing_frame.py +1 -1
- imap_processing/spice/spin.py +4 -0
- imap_processing/spice/time.py +51 -0
- imap_processing/swapi/l1/swapi_l1.py +12 -2
- imap_processing/swapi/l2/swapi_l2.py +59 -14
- imap_processing/swapi/swapi_utils.py +1 -1
- imap_processing/swe/l1b/swe_l1b.py +11 -4
- imap_processing/swe/l2/swe_l2.py +111 -17
- imap_processing/ultra/constants.py +49 -1
- imap_processing/ultra/l0/decom_tools.py +28 -14
- imap_processing/ultra/l0/decom_ultra.py +225 -15
- imap_processing/ultra/l0/ultra_utils.py +281 -8
- imap_processing/ultra/l1a/ultra_l1a.py +77 -8
- imap_processing/ultra/l1b/cullingmask.py +3 -3
- imap_processing/ultra/l1b/de.py +53 -15
- imap_processing/ultra/l1b/extendedspin.py +26 -2
- imap_processing/ultra/l1b/lookup_utils.py +171 -50
- imap_processing/ultra/l1b/quality_flag_filters.py +14 -0
- imap_processing/ultra/l1b/ultra_l1b_culling.py +198 -5
- imap_processing/ultra/l1b/ultra_l1b_extended.py +304 -66
- imap_processing/ultra/l1c/helio_pset.py +54 -7
- imap_processing/ultra/l1c/spacecraft_pset.py +9 -1
- imap_processing/ultra/l1c/ultra_l1c.py +2 -0
- imap_processing/ultra/l1c/ultra_l1c_pset_bins.py +106 -109
- imap_processing/ultra/packet_definitions/ULTRA_SCI_COMBINED.xml +3 -3
- imap_processing/ultra/utils/ultra_l1_utils.py +13 -1
- imap_processing/utils.py +20 -42
- {imap_processing-0.16.2.dist-info → imap_processing-0.18.0.dist-info}/METADATA +2 -2
- {imap_processing-0.16.2.dist-info → imap_processing-0.18.0.dist-info}/RECORD +95 -103
- imap_processing/lo/l0/data_classes/star_sensor.py +0 -98
- imap_processing/lo/l0/utils/lo_base.py +0 -57
- imap_processing/ultra/lookup_tables/Angular_Profiles_FM45_LeftSlit.csv +0 -526
- imap_processing/ultra/lookup_tables/Angular_Profiles_FM45_RightSlit.csv +0 -526
- imap_processing/ultra/lookup_tables/Angular_Profiles_FM90_LeftSlit.csv +0 -526
- imap_processing/ultra/lookup_tables/Angular_Profiles_FM90_RightSlit.csv +0 -524
- imap_processing/ultra/lookup_tables/EgyNorm.mem.csv +0 -32769
- imap_processing/ultra/lookup_tables/FM45_Startup1_ULTRA_IMGPARAMS_20240719.csv +0 -2
- imap_processing/ultra/lookup_tables/FM90_Startup1_ULTRA_IMGPARAMS_20240719.csv +0 -2
- imap_processing/ultra/lookup_tables/dps_grid45_compressed.cdf +0 -0
- imap_processing/ultra/lookup_tables/ultra45_back-pos-luts.csv +0 -4097
- imap_processing/ultra/lookup_tables/ultra45_tdc_norm.csv +0 -2050
- imap_processing/ultra/lookup_tables/ultra90_back-pos-luts.csv +0 -4097
- imap_processing/ultra/lookup_tables/ultra90_tdc_norm.csv +0 -2050
- imap_processing/ultra/lookup_tables/yadjust.csv +0 -257
- {imap_processing-0.16.2.dist-info → imap_processing-0.18.0.dist-info}/LICENSE +0 -0
- {imap_processing-0.16.2.dist-info → imap_processing-0.18.0.dist-info}/WHEEL +0 -0
- {imap_processing-0.16.2.dist-info → imap_processing-0.18.0.dist-info}/entry_points.txt +0 -0
imap_processing/ultra/l1b/de.py
CHANGED
|
@@ -4,12 +4,16 @@ import numpy as np
|
|
|
4
4
|
import xarray as xr
|
|
5
5
|
|
|
6
6
|
from imap_processing.cdf.utils import parse_filename_like
|
|
7
|
+
from imap_processing.quality_flags import ImapDEUltraFlags
|
|
7
8
|
from imap_processing.spice.geometry import SpiceFrame
|
|
9
|
+
from imap_processing.ultra.l1b.lookup_utils import get_geometric_factor
|
|
8
10
|
from imap_processing.ultra.l1b.ultra_l1b_annotated import (
|
|
9
11
|
get_annotated_particle_velocity,
|
|
10
12
|
)
|
|
11
13
|
from imap_processing.ultra.l1b.ultra_l1b_extended import (
|
|
12
14
|
StopType,
|
|
15
|
+
determine_ebin_pulse_height,
|
|
16
|
+
determine_ebin_ssd,
|
|
13
17
|
determine_species,
|
|
14
18
|
get_coincidence_positions,
|
|
15
19
|
get_ctof,
|
|
@@ -25,6 +29,7 @@ from imap_processing.ultra.l1b.ultra_l1b_extended import (
|
|
|
25
29
|
get_path_length,
|
|
26
30
|
get_ph_tof_and_back_positions,
|
|
27
31
|
get_phi_theta,
|
|
32
|
+
get_spin_number,
|
|
28
33
|
get_ssd_back_position_and_tof_offset,
|
|
29
34
|
get_ssd_tof,
|
|
30
35
|
)
|
|
@@ -59,7 +64,10 @@ def calculate_de(
|
|
|
59
64
|
|
|
60
65
|
# Define epoch and spin.
|
|
61
66
|
de_dict["epoch"] = de_dataset["epoch"].data
|
|
62
|
-
|
|
67
|
+
spin_number = get_spin_number(
|
|
68
|
+
de_dataset["shcoarse"].values, de_dataset["spin"].values
|
|
69
|
+
)
|
|
70
|
+
de_dict["spin"] = spin_number
|
|
63
71
|
|
|
64
72
|
# Add already populated fields.
|
|
65
73
|
keys = [
|
|
@@ -108,6 +116,7 @@ def calculate_de(
|
|
|
108
116
|
ctof = np.full(len(de_dataset["epoch"]), FILLVAL_FLOAT32, dtype=np.float32)
|
|
109
117
|
magnitude_v = np.full(len(de_dataset["epoch"]), FILLVAL_FLOAT32, dtype=np.float32)
|
|
110
118
|
energy = np.full(len(de_dataset["epoch"]), FILLVAL_FLOAT32, dtype=np.float32)
|
|
119
|
+
e_bin = np.full(len(de_dataset["epoch"]), FILLVAL_UINT8, dtype=np.uint8)
|
|
111
120
|
species_bin = np.full(len(de_dataset["epoch"]), FILLVAL_UINT8, dtype=np.uint8)
|
|
112
121
|
t2 = np.full(len(de_dataset["epoch"]), FILLVAL_FLOAT32, dtype=np.float32)
|
|
113
122
|
event_times = np.full(len(de_dataset["epoch"]), FILLVAL_FLOAT32, dtype=np.float32)
|
|
@@ -116,40 +125,44 @@ def calculate_de(
|
|
|
116
125
|
sc_dps_velocity = np.full(shape, FILLVAL_FLOAT32, dtype=np.float32)
|
|
117
126
|
helio_velocity = np.full(shape, FILLVAL_FLOAT32, dtype=np.float32)
|
|
118
127
|
spin_starts = np.full(len(de_dataset["epoch"]), FILLVAL_FLOAT32, dtype=np.float64)
|
|
119
|
-
|
|
120
|
-
len(de_dataset["epoch"]), FILLVAL_FLOAT32, dtype=np.float64
|
|
121
|
-
)
|
|
128
|
+
|
|
122
129
|
start_type = np.full(len(de_dataset["epoch"]), FILLVAL_UINT8, dtype=np.uint8)
|
|
130
|
+
quality_flags = np.full(
|
|
131
|
+
de_dataset["epoch"].shape, ImapDEUltraFlags.NONE.value, dtype=np.uint16
|
|
132
|
+
)
|
|
123
133
|
|
|
124
134
|
xf[valid_indices] = get_front_x_position(
|
|
125
135
|
de_dataset["start_type"].data[valid_indices],
|
|
126
136
|
de_dataset["start_pos_tdc"].data[valid_indices],
|
|
127
137
|
f"ultra{sensor}",
|
|
138
|
+
ancillary_files,
|
|
128
139
|
)
|
|
129
140
|
start_type[valid_indices] = de_dataset["start_type"].data[valid_indices]
|
|
130
141
|
|
|
131
142
|
(
|
|
132
143
|
event_times[valid_indices],
|
|
133
144
|
spin_starts[valid_indices],
|
|
134
|
-
|
|
145
|
+
_,
|
|
135
146
|
) = get_eventtimes(
|
|
136
|
-
|
|
147
|
+
de_dict["spin"][valid_indices],
|
|
137
148
|
de_dataset["phase_angle"].data[valid_indices],
|
|
138
149
|
)
|
|
139
150
|
|
|
140
151
|
# Pulse height
|
|
141
152
|
tof[ph_indices], t2[ph_indices], xb[ph_indices], yb[ph_indices] = (
|
|
142
|
-
get_ph_tof_and_back_positions(de_dataset, xf, f"ultra{sensor}")
|
|
153
|
+
get_ph_tof_and_back_positions(de_dataset, xf, f"ultra{sensor}", ancillary_files)
|
|
143
154
|
)
|
|
144
155
|
d[ph_indices], yf[ph_indices] = get_front_y_position(
|
|
145
|
-
de_dataset["start_type"].data[ph_indices], yb[ph_indices]
|
|
156
|
+
de_dataset["start_type"].data[ph_indices], yb[ph_indices], ancillary_files
|
|
146
157
|
)
|
|
147
|
-
energy[ph_indices] = get_energy_pulse_height(
|
|
158
|
+
energy[ph_indices], _ = get_energy_pulse_height(
|
|
148
159
|
de_dataset["stop_type"].data[ph_indices],
|
|
149
160
|
de_dataset["energy_ph"].data[ph_indices],
|
|
150
161
|
xb[ph_indices],
|
|
151
162
|
yb[ph_indices],
|
|
152
163
|
f"ultra{sensor}",
|
|
164
|
+
ancillary_files,
|
|
165
|
+
quality_flags[ph_indices],
|
|
153
166
|
)
|
|
154
167
|
r[ph_indices] = get_path_length(
|
|
155
168
|
(xf[ph_indices], yf[ph_indices]),
|
|
@@ -161,26 +174,32 @@ def calculate_de(
|
|
|
161
174
|
(xb[ph_indices], yb[ph_indices]),
|
|
162
175
|
d[ph_indices],
|
|
163
176
|
)
|
|
177
|
+
e_bin[ph_indices] = determine_ebin_pulse_height(
|
|
178
|
+
energy[ph_indices], tof[ph_indices], r[ph_indices]
|
|
179
|
+
)
|
|
164
180
|
species_bin[ph_indices] = determine_species(tof[ph_indices], r[ph_indices], "PH")
|
|
165
181
|
etof[ph_indices], xc[ph_indices] = get_coincidence_positions(
|
|
166
|
-
de_dataset.isel(epoch=ph_indices),
|
|
182
|
+
de_dataset.isel(epoch=ph_indices),
|
|
183
|
+
t2[ph_indices],
|
|
184
|
+
f"ultra{sensor}",
|
|
185
|
+
ancillary_files,
|
|
167
186
|
)
|
|
168
187
|
ctof[ph_indices], magnitude_v[ph_indices] = get_ctof(
|
|
169
188
|
tof[ph_indices], r[ph_indices], "PH"
|
|
170
189
|
)
|
|
171
190
|
|
|
172
191
|
# SSD
|
|
173
|
-
tof[ssd_indices] = get_ssd_tof(de_dataset, xf, f"ultra{sensor}")
|
|
192
|
+
tof[ssd_indices] = get_ssd_tof(de_dataset, xf, f"ultra{sensor}", ancillary_files)
|
|
174
193
|
yb[ssd_indices], _, ssd_number = get_ssd_back_position_and_tof_offset(
|
|
175
|
-
de_dataset, f"ultra{sensor}"
|
|
194
|
+
de_dataset, f"ultra{sensor}", ancillary_files
|
|
176
195
|
)
|
|
177
196
|
xc[ssd_indices] = np.zeros(len(ssd_indices))
|
|
178
197
|
xb[ssd_indices] = np.zeros(len(ssd_indices))
|
|
179
198
|
etof[ssd_indices] = np.zeros(len(ssd_indices))
|
|
180
199
|
d[ssd_indices], yf[ssd_indices] = get_front_y_position(
|
|
181
|
-
de_dataset["start_type"].data[ssd_indices], yb[ssd_indices]
|
|
200
|
+
de_dataset["start_type"].data[ssd_indices], yb[ssd_indices], ancillary_files
|
|
182
201
|
)
|
|
183
|
-
energy[ssd_indices] = get_energy_ssd(de_dataset, ssd_number)
|
|
202
|
+
energy[ssd_indices] = get_energy_ssd(de_dataset, ssd_number, ancillary_files)
|
|
184
203
|
r[ssd_indices] = get_path_length(
|
|
185
204
|
(xf[ssd_indices], yf[ssd_indices]),
|
|
186
205
|
(xb[ssd_indices], yb[ssd_indices]),
|
|
@@ -191,6 +210,9 @@ def calculate_de(
|
|
|
191
210
|
(xb[ssd_indices], yb[ssd_indices]),
|
|
192
211
|
d[ssd_indices],
|
|
193
212
|
)
|
|
213
|
+
e_bin[ssd_indices] = determine_ebin_ssd(
|
|
214
|
+
energy[ssd_indices], tof[ssd_indices], r[ssd_indices]
|
|
215
|
+
)
|
|
194
216
|
species_bin[ssd_indices] = determine_species(
|
|
195
217
|
tof[ssd_indices], r[ssd_indices], "SSD"
|
|
196
218
|
)
|
|
@@ -202,7 +224,6 @@ def calculate_de(
|
|
|
202
224
|
de_dict["x_front"] = xf.astype(np.float32)
|
|
203
225
|
de_dict["event_times"] = event_times
|
|
204
226
|
de_dict["spin_starts"] = spin_starts
|
|
205
|
-
de_dict["spin_period"] = spin_period_sec
|
|
206
227
|
de_dict["y_front"] = yf
|
|
207
228
|
de_dict["x_back"] = xb
|
|
208
229
|
de_dict["y_back"] = yb
|
|
@@ -228,6 +249,7 @@ def calculate_de(
|
|
|
228
249
|
|
|
229
250
|
de_dict["tof_energy"] = get_de_energy_kev(v, species_bin)
|
|
230
251
|
de_dict["energy"] = energy
|
|
252
|
+
de_dict["ebin"] = e_bin
|
|
231
253
|
de_dict["species"] = species_bin
|
|
232
254
|
|
|
233
255
|
# Annotated Events.
|
|
@@ -261,10 +283,26 @@ def calculate_de(
|
|
|
261
283
|
de_dict["tof_energy"],
|
|
262
284
|
de_dict["phi"],
|
|
263
285
|
de_dict["theta"],
|
|
286
|
+
ancillary_files,
|
|
264
287
|
)
|
|
265
288
|
de_dict["event_efficiency"] = get_efficiency(
|
|
266
289
|
de_dict["tof_energy"], de_dict["phi"], de_dict["theta"], ancillary_files
|
|
267
290
|
)
|
|
291
|
+
de_dict["geometric_factor_blades"] = get_geometric_factor(
|
|
292
|
+
ancillary_files,
|
|
293
|
+
"l1b-sensor-gf-blades",
|
|
294
|
+
de_dict["phi"],
|
|
295
|
+
de_dict["theta"],
|
|
296
|
+
quality_flags,
|
|
297
|
+
)
|
|
298
|
+
de_dict["geometric_factor_noblades"] = get_geometric_factor(
|
|
299
|
+
ancillary_files,
|
|
300
|
+
"l1b-sensor-gf-noblades",
|
|
301
|
+
de_dict["phi"],
|
|
302
|
+
de_dict["theta"],
|
|
303
|
+
quality_flags,
|
|
304
|
+
)
|
|
305
|
+
de_dict["quality_fov"] = quality_flags
|
|
268
306
|
|
|
269
307
|
dataset = create_dataset(de_dict, name, "l1b")
|
|
270
308
|
|
|
@@ -5,11 +5,16 @@ import xarray as xr
|
|
|
5
5
|
|
|
6
6
|
from imap_processing.ultra.l1b.ultra_l1b_culling import (
|
|
7
7
|
flag_attitude,
|
|
8
|
-
|
|
8
|
+
flag_hk,
|
|
9
|
+
flag_imap_instruments,
|
|
10
|
+
flag_rates,
|
|
9
11
|
get_energy_histogram,
|
|
12
|
+
get_pulses_per_spin,
|
|
10
13
|
)
|
|
11
14
|
from imap_processing.ultra.utils.ultra_l1_utils import create_dataset
|
|
12
15
|
|
|
16
|
+
FILLVAL_UINT16 = 65535
|
|
17
|
+
|
|
13
18
|
|
|
14
19
|
def calculate_extendedspin(
|
|
15
20
|
dict_datasets: dict[str, xr.Dataset],
|
|
@@ -34,10 +39,11 @@ def calculate_extendedspin(
|
|
|
34
39
|
Dataset containing the data.
|
|
35
40
|
"""
|
|
36
41
|
aux_dataset = dict_datasets[f"imap_ultra_l1a_{instrument_id}sensor-aux"]
|
|
42
|
+
rates_dataset = dict_datasets[f"imap_ultra_l1a_{instrument_id}sensor-rates"]
|
|
37
43
|
de_dataset = dict_datasets[f"imap_ultra_l1b_{instrument_id}sensor-de"]
|
|
38
44
|
|
|
39
45
|
extendedspin_dict = {}
|
|
40
|
-
rates_qf, spin, energy_midpoints, n_sigma_per_energy =
|
|
46
|
+
rates_qf, spin, energy_midpoints, n_sigma_per_energy = flag_rates(
|
|
41
47
|
de_dataset["spin"].values,
|
|
42
48
|
de_dataset["energy"].values,
|
|
43
49
|
)
|
|
@@ -47,12 +53,19 @@ def calculate_extendedspin(
|
|
|
47
53
|
attitude_qf, spin_rates, spin_period, spin_starttime = flag_attitude(
|
|
48
54
|
de_dataset["spin"].values, aux_dataset
|
|
49
55
|
)
|
|
56
|
+
# TODO: We will add to this later
|
|
57
|
+
hk_qf = flag_hk(de_dataset["spin"].values)
|
|
58
|
+
inst_qf = flag_imap_instruments(de_dataset["spin"].values)
|
|
59
|
+
|
|
50
60
|
# Get the first epoch for each spin.
|
|
51
61
|
mask = xr.DataArray(np.isin(de_dataset["spin"], spin), dims="epoch")
|
|
52
62
|
filtered_dataset = de_dataset.where(mask, drop=True)
|
|
53
63
|
_, first_indices = np.unique(filtered_dataset["spin"].values, return_index=True)
|
|
54
64
|
first_epochs = filtered_dataset["epoch"].values[first_indices]
|
|
55
65
|
|
|
66
|
+
# Get the number of pulses per spin.
|
|
67
|
+
start_per_spin, stop_per_spin, coin_per_spin = get_pulses_per_spin(rates_dataset)
|
|
68
|
+
|
|
56
69
|
# These will be the coordinates.
|
|
57
70
|
extendedspin_dict["epoch"] = first_epochs
|
|
58
71
|
extendedspin_dict["spin_number"] = spin
|
|
@@ -63,8 +76,19 @@ def calculate_extendedspin(
|
|
|
63
76
|
extendedspin_dict["spin_start_time"] = spin_starttime
|
|
64
77
|
extendedspin_dict["spin_period"] = spin_period
|
|
65
78
|
extendedspin_dict["spin_rate"] = spin_rates
|
|
79
|
+
extendedspin_dict["start_pulses_per_spin"] = start_per_spin
|
|
80
|
+
extendedspin_dict["stop_pulses_per_spin"] = stop_per_spin
|
|
81
|
+
extendedspin_dict["coin_pulses_per_spin"] = coin_per_spin
|
|
82
|
+
# TODO: this will be used to track rejected events in each
|
|
83
|
+
# spin based on quality flags in de l1b data.
|
|
84
|
+
extendedspin_dict["rejected_events_per_spin"] = np.full_like(
|
|
85
|
+
spin, FILLVAL_UINT16, dtype=np.uint16
|
|
86
|
+
)
|
|
87
|
+
|
|
66
88
|
extendedspin_dict["quality_attitude"] = attitude_qf
|
|
67
89
|
extendedspin_dict["quality_ena_rates"] = rates_qf
|
|
90
|
+
extendedspin_dict["quality_hk"] = hk_qf
|
|
91
|
+
extendedspin_dict["quality_instruments"] = inst_qf
|
|
68
92
|
|
|
69
93
|
extendedspin_dataset = create_dataset(extendedspin_dict, name, "l1b")
|
|
70
94
|
|
|
@@ -4,43 +4,12 @@ import numpy as np
|
|
|
4
4
|
import numpy.typing as npt
|
|
5
5
|
import pandas as pd
|
|
6
6
|
import xarray as xr
|
|
7
|
+
from numpy.typing import NDArray
|
|
7
8
|
|
|
8
|
-
from imap_processing import
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
_YADJUST_DF = pd.read_csv(BASE_PATH / "yadjust.csv").set_index("dYLUT")
|
|
13
|
-
_TDC_NORM_DF_ULTRA45 = pd.read_csv(
|
|
14
|
-
BASE_PATH / "ultra45_tdc_norm.csv", header=1, index_col="Index"
|
|
15
|
-
)
|
|
16
|
-
_TDC_NORM_DF_ULTRA90 = pd.read_csv(
|
|
17
|
-
BASE_PATH / "ultra90_tdc_norm.csv", header=1, index_col="Index"
|
|
18
|
-
)
|
|
19
|
-
_BACK_POS_DF_ULTRA45 = pd.read_csv(
|
|
20
|
-
BASE_PATH / "ultra45_back-pos-luts.csv", index_col="Index_offset"
|
|
21
|
-
)
|
|
22
|
-
_BACK_POS_DF_ULTRA90 = pd.read_csv(
|
|
23
|
-
BASE_PATH / "ultra90_back-pos-luts.csv", index_col="Index_offset"
|
|
24
|
-
)
|
|
25
|
-
_ENERGY_NORM_DF = pd.read_csv(BASE_PATH / "EgyNorm.mem.csv")
|
|
26
|
-
_IMAGE_PARAMS_DF = {
|
|
27
|
-
"ultra45": pd.read_csv(BASE_PATH / "FM45_Startup1_ULTRA_IMGPARAMS_20240719.csv"),
|
|
28
|
-
"ultra90": pd.read_csv(BASE_PATH / "FM90_Startup1_ULTRA_IMGPARAMS_20240719.csv"),
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
_FWHM_TABLES = {
|
|
32
|
-
("left", "ultra45"): pd.read_csv(BASE_PATH / "Angular_Profiles_FM45_LeftSlit.csv"),
|
|
33
|
-
("right", "ultra45"): pd.read_csv(
|
|
34
|
-
BASE_PATH / "Angular_Profiles_FM45_RightSlit.csv"
|
|
35
|
-
),
|
|
36
|
-
("left", "ultra90"): pd.read_csv(BASE_PATH / "Angular_Profiles_FM90_LeftSlit.csv"),
|
|
37
|
-
("right", "ultra90"): pd.read_csv(
|
|
38
|
-
BASE_PATH / "Angular_Profiles_FM90_RightSlit.csv"
|
|
39
|
-
),
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
def get_y_adjust(dy_lut: np.ndarray) -> npt.NDArray:
|
|
9
|
+
from imap_processing.quality_flags import ImapDEUltraFlags
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def get_y_adjust(dy_lut: np.ndarray, ancillary_files: dict) -> npt.NDArray:
|
|
44
13
|
"""
|
|
45
14
|
Adjust the front yf position based on the particle's trajectory.
|
|
46
15
|
|
|
@@ -52,16 +21,21 @@ def get_y_adjust(dy_lut: np.ndarray) -> npt.NDArray:
|
|
|
52
21
|
----------
|
|
53
22
|
dy_lut : np.ndarray
|
|
54
23
|
Change in y direction used for the lookup table (mm).
|
|
24
|
+
ancillary_files : dict[Path]
|
|
25
|
+
Ancillary files containing the lookup tables.
|
|
55
26
|
|
|
56
27
|
Returns
|
|
57
28
|
-------
|
|
58
29
|
yadj : np.ndarray
|
|
59
30
|
Y adjustment (mm).
|
|
60
31
|
"""
|
|
61
|
-
|
|
32
|
+
yadjust_df = pd.read_csv(ancillary_files["l1b-yadjust-lookup"]).set_index("dYLUT")
|
|
33
|
+
return yadjust_df["dYAdj"].iloc[dy_lut].values
|
|
62
34
|
|
|
63
35
|
|
|
64
|
-
def get_norm(
|
|
36
|
+
def get_norm(
|
|
37
|
+
dn: xr.DataArray, key: str, file_label: str, ancillary_files: dict
|
|
38
|
+
) -> npt.NDArray:
|
|
65
39
|
"""
|
|
66
40
|
Correct mismatches between the stop Time to Digital Converters (TDCs).
|
|
67
41
|
|
|
@@ -82,6 +56,8 @@ def get_norm(dn: xr.DataArray, key: str, file_label: str) -> npt.NDArray:
|
|
|
82
56
|
BtSpNNorm, BtSpSNorm, BtSpENorm, or BtSpWNorm.
|
|
83
57
|
file_label : str
|
|
84
58
|
Instrument (ultra45 or ultra90).
|
|
59
|
+
ancillary_files : dict[Path]
|
|
60
|
+
Ancillary files containing the lookup tables.
|
|
85
61
|
|
|
86
62
|
Returns
|
|
87
63
|
-------
|
|
@@ -89,16 +65,22 @@ def get_norm(dn: xr.DataArray, key: str, file_label: str) -> npt.NDArray:
|
|
|
89
65
|
Normalized DNs.
|
|
90
66
|
"""
|
|
91
67
|
if file_label == "ultra45":
|
|
92
|
-
tdc_norm_df =
|
|
68
|
+
tdc_norm_df = pd.read_csv(
|
|
69
|
+
ancillary_files["l1b-45sensor-tdc-norm-lookup"], header=1, index_col="Index"
|
|
70
|
+
)
|
|
93
71
|
else:
|
|
94
|
-
tdc_norm_df =
|
|
72
|
+
tdc_norm_df = pd.read_csv(
|
|
73
|
+
ancillary_files["l1b-90sensor-tdc-norm-lookup"], header=1, index_col="Index"
|
|
74
|
+
)
|
|
95
75
|
|
|
96
76
|
dn_norm = tdc_norm_df[key].iloc[dn].values
|
|
97
77
|
|
|
98
78
|
return dn_norm
|
|
99
79
|
|
|
100
80
|
|
|
101
|
-
def get_back_position(
|
|
81
|
+
def get_back_position(
|
|
82
|
+
back_index: np.ndarray, key: str, file_label: str, ancillary_files: dict
|
|
83
|
+
) -> npt.NDArray:
|
|
102
84
|
"""
|
|
103
85
|
Convert normalized TDC values using lookup tables.
|
|
104
86
|
|
|
@@ -117,6 +99,8 @@ def get_back_position(back_index: np.ndarray, key: str, file_label: str) -> npt.
|
|
|
117
99
|
XBkTp, YBkTp, XBkBt, or YBkBt.
|
|
118
100
|
file_label : str
|
|
119
101
|
Instrument (ultra45 or ultra90).
|
|
102
|
+
ancillary_files : dict[Path]
|
|
103
|
+
Ancillary files containing the lookup tables.
|
|
120
104
|
|
|
121
105
|
Returns
|
|
122
106
|
-------
|
|
@@ -124,14 +108,20 @@ def get_back_position(back_index: np.ndarray, key: str, file_label: str) -> npt.
|
|
|
124
108
|
Converted DNs to Units of hundredths of a millimeter.
|
|
125
109
|
"""
|
|
126
110
|
if file_label == "ultra45":
|
|
127
|
-
back_pos_df =
|
|
111
|
+
back_pos_df = pd.read_csv(
|
|
112
|
+
ancillary_files["l1b-45sensor-back-pos-lookup"], index_col="Index_offset"
|
|
113
|
+
)
|
|
128
114
|
else:
|
|
129
|
-
back_pos_df =
|
|
115
|
+
back_pos_df = pd.read_csv(
|
|
116
|
+
ancillary_files["l1b-90sensor-back-pos-lookup"], index_col="Index_offset"
|
|
117
|
+
)
|
|
130
118
|
|
|
131
119
|
return back_pos_df[key].values[back_index]
|
|
132
120
|
|
|
133
121
|
|
|
134
|
-
def get_energy_norm(
|
|
122
|
+
def get_energy_norm(
|
|
123
|
+
ssd: np.ndarray, composite_energy: np.ndarray, ancillary_files: dict
|
|
124
|
+
) -> npt.NDArray:
|
|
135
125
|
"""
|
|
136
126
|
Normalize composite energy per SSD using a lookup table.
|
|
137
127
|
|
|
@@ -146,6 +136,8 @@ def get_energy_norm(ssd: np.ndarray, composite_energy: np.ndarray) -> npt.NDArra
|
|
|
146
136
|
Acts as index 1.
|
|
147
137
|
composite_energy : np.ndarray
|
|
148
138
|
Acts as index 2.
|
|
139
|
+
ancillary_files : dict[Path]
|
|
140
|
+
Ancillary files containing the lookup tables.
|
|
149
141
|
|
|
150
142
|
Returns
|
|
151
143
|
-------
|
|
@@ -153,11 +145,11 @@ def get_energy_norm(ssd: np.ndarray, composite_energy: np.ndarray) -> npt.NDArra
|
|
|
153
145
|
Normalized composite energy.
|
|
154
146
|
"""
|
|
155
147
|
row_number = ssd * 4096 + composite_energy
|
|
148
|
+
norm_lookup = pd.read_csv(ancillary_files["l1b-egynorm-lookup"])
|
|
149
|
+
return norm_lookup["NormEnergy"].iloc[row_number]
|
|
156
150
|
|
|
157
|
-
return _ENERGY_NORM_DF["NormEnergy"].iloc[row_number]
|
|
158
151
|
|
|
159
|
-
|
|
160
|
-
def get_image_params(image: str, sensor: str) -> np.float64:
|
|
152
|
+
def get_image_params(image: str, sensor: str, ancillary_files: dict) -> np.float64:
|
|
161
153
|
"""
|
|
162
154
|
Lookup table for image parameters.
|
|
163
155
|
|
|
@@ -171,18 +163,26 @@ def get_image_params(image: str, sensor: str) -> np.float64:
|
|
|
171
163
|
The column name to lookup in the CSV file, e.g., 'XFTLTOFF' or 'XFTRTOFF'.
|
|
172
164
|
sensor : str
|
|
173
165
|
Sensor name: "ultra45" or "ultra90".
|
|
166
|
+
ancillary_files : dict[Path]
|
|
167
|
+
Ancillary files containing the lookup tables.
|
|
174
168
|
|
|
175
169
|
Returns
|
|
176
170
|
-------
|
|
177
171
|
value : np.float64
|
|
178
172
|
Image parameter value from the CSV file.
|
|
179
173
|
"""
|
|
180
|
-
|
|
174
|
+
if sensor == "ultra45":
|
|
175
|
+
lookup_table = pd.read_csv(ancillary_files["l1b-45sensor-imgparams-lookup"])
|
|
176
|
+
else:
|
|
177
|
+
lookup_table = pd.read_csv(ancillary_files["l1b-90sensor-imgparams-lookup"])
|
|
178
|
+
|
|
181
179
|
value: np.float64 = lookup_table[image].values[0]
|
|
182
180
|
return value
|
|
183
181
|
|
|
184
182
|
|
|
185
|
-
def get_angular_profiles(
|
|
183
|
+
def get_angular_profiles(
|
|
184
|
+
start_type: str, sensor: str, ancillary_files: dict
|
|
185
|
+
) -> pd.DataFrame:
|
|
186
186
|
"""
|
|
187
187
|
Lookup table for FWHM for theta and phi.
|
|
188
188
|
|
|
@@ -195,13 +195,16 @@ def get_angular_profiles(start_type: str, sensor: str) -> pd.DataFrame:
|
|
|
195
195
|
Start Type: Left, Right.
|
|
196
196
|
sensor : str
|
|
197
197
|
Sensor name: "ultra45" or "ultra90".
|
|
198
|
+
ancillary_files : dict[Path]
|
|
199
|
+
Ancillary files.
|
|
198
200
|
|
|
199
201
|
Returns
|
|
200
202
|
-------
|
|
201
203
|
lookup_table : DataFrame
|
|
202
204
|
Angular profile lookup table for a given start_type and sensor.
|
|
203
205
|
"""
|
|
204
|
-
|
|
206
|
+
lut_descriptor = f"l1b-{sensor[-2:]}sensor-{start_type.lower()}slit-lookup"
|
|
207
|
+
lookup_table = pd.read_csv(ancillary_files[lut_descriptor])
|
|
205
208
|
|
|
206
209
|
return lookup_table
|
|
207
210
|
|
|
@@ -227,3 +230,121 @@ def get_energy_efficiencies(ancillary_files: dict) -> pd.DataFrame:
|
|
|
227
230
|
lookup_table = pd.read_csv(ancillary_files["l1b-45sensor-logistic-interpolation"])
|
|
228
231
|
|
|
229
232
|
return lookup_table
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def get_geometric_factor(
|
|
236
|
+
ancillary_files: dict,
|
|
237
|
+
filename: str,
|
|
238
|
+
phi: NDArray,
|
|
239
|
+
theta: NDArray,
|
|
240
|
+
quality_flag: NDArray,
|
|
241
|
+
) -> tuple[NDArray, NDArray]:
|
|
242
|
+
"""
|
|
243
|
+
Lookup table for geometric factor using nearest neighbor.
|
|
244
|
+
|
|
245
|
+
Parameters
|
|
246
|
+
----------
|
|
247
|
+
ancillary_files : dict[Path]
|
|
248
|
+
Ancillary files.
|
|
249
|
+
filename : str
|
|
250
|
+
Name of the file in ancillary_files to use.
|
|
251
|
+
phi : NDArray
|
|
252
|
+
Azimuth angles in degrees.
|
|
253
|
+
theta : NDArray
|
|
254
|
+
Elevation angles in degrees.
|
|
255
|
+
quality_flag : NDArray
|
|
256
|
+
Quality flag to set when geometric factor is zero.
|
|
257
|
+
|
|
258
|
+
Returns
|
|
259
|
+
-------
|
|
260
|
+
geometric_factor : NDArray
|
|
261
|
+
Geometric factor.
|
|
262
|
+
"""
|
|
263
|
+
gf_table = pd.read_csv(
|
|
264
|
+
ancillary_files[filename], header=None, skiprows=6, nrows=301
|
|
265
|
+
).to_numpy(dtype=float)
|
|
266
|
+
theta_table = pd.read_csv(
|
|
267
|
+
ancillary_files[filename], header=None, skiprows=308, nrows=301
|
|
268
|
+
).to_numpy(dtype=float)
|
|
269
|
+
phi_table = pd.read_csv(
|
|
270
|
+
ancillary_files[filename], header=None, skiprows=610, nrows=301
|
|
271
|
+
).to_numpy(dtype=float)
|
|
272
|
+
|
|
273
|
+
# Assume uniform grids: extract 1D arrays from first row/col
|
|
274
|
+
theta_vals = theta_table[0, :] # columns represent theta
|
|
275
|
+
phi_vals = phi_table[:, 0] # rows represent phi
|
|
276
|
+
|
|
277
|
+
# Find nearest index in table for each input value
|
|
278
|
+
phi_idx = np.abs(phi_vals[:, None] - phi).argmin(axis=0)
|
|
279
|
+
theta_idx = np.abs(theta_vals[:, None] - theta).argmin(axis=0)
|
|
280
|
+
|
|
281
|
+
# Fetch geometric factor values at nearest (phi, theta) pairs
|
|
282
|
+
geometric_factor = gf_table[phi_idx, theta_idx]
|
|
283
|
+
|
|
284
|
+
phi_rad = np.deg2rad(phi)
|
|
285
|
+
numerator = 5.0 * np.cos(phi_rad)
|
|
286
|
+
denominator = 1 + 2.80 * np.cos(phi_rad)
|
|
287
|
+
# Equation 19 in the Ultra Algorithm Document.
|
|
288
|
+
theta_nom = np.arctan(numerator / denominator)
|
|
289
|
+
theta_nom = np.rad2deg(theta_nom)
|
|
290
|
+
|
|
291
|
+
outside_fov = np.abs(theta) > theta_nom
|
|
292
|
+
quality_flag[outside_fov] |= ImapDEUltraFlags.FOV.value
|
|
293
|
+
|
|
294
|
+
return geometric_factor
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
def get_ph_corrected(
|
|
298
|
+
sensor: str,
|
|
299
|
+
location: str,
|
|
300
|
+
ancillary_files: dict,
|
|
301
|
+
xlut: NDArray,
|
|
302
|
+
ylut: NDArray,
|
|
303
|
+
quality_flag: NDArray,
|
|
304
|
+
) -> tuple[NDArray, NDArray]:
|
|
305
|
+
"""
|
|
306
|
+
PH correction for stop anodes, top and bottom.
|
|
307
|
+
|
|
308
|
+
Further description is available starting on
|
|
309
|
+
page 207 of the Ultra Flight Software Document.
|
|
310
|
+
|
|
311
|
+
Parameters
|
|
312
|
+
----------
|
|
313
|
+
sensor : str
|
|
314
|
+
Sensor name: "ultra45" or "ultra90".
|
|
315
|
+
location : str
|
|
316
|
+
Location: "tp" or "bt".
|
|
317
|
+
ancillary_files : dict[Path]
|
|
318
|
+
Ancillary files.
|
|
319
|
+
xlut : NDArray
|
|
320
|
+
X lookup index for PH correction.
|
|
321
|
+
ylut : NDArray
|
|
322
|
+
Y lookup index for PH correction.
|
|
323
|
+
quality_flag : NDArray
|
|
324
|
+
Quality flag to set when there is an outlier.
|
|
325
|
+
|
|
326
|
+
Returns
|
|
327
|
+
-------
|
|
328
|
+
ph_correction : NDArray
|
|
329
|
+
Correction for pulse height.
|
|
330
|
+
quality_flag : NDArray
|
|
331
|
+
Quality flag updated with PH correction flags.
|
|
332
|
+
"""
|
|
333
|
+
ph_correct = pd.read_csv(
|
|
334
|
+
ancillary_files[f"l1b-{sensor[-2:]}sensor-sp{location}phcorr"], header=None
|
|
335
|
+
)
|
|
336
|
+
ph_correct_array = ph_correct.to_numpy()
|
|
337
|
+
|
|
338
|
+
max_x, max_y = ph_correct_array.shape[0] - 1, ph_correct_array.shape[1] - 1
|
|
339
|
+
|
|
340
|
+
# Clamp indices to nearest valid value
|
|
341
|
+
xlut_clamped = np.clip(xlut.astype(int), 0, max_x)
|
|
342
|
+
ylut_clamped = np.clip(ylut.astype(int), 0, max_y)
|
|
343
|
+
|
|
344
|
+
# Flag where clamping occurred
|
|
345
|
+
flagged_mask = (xlut != xlut_clamped) | (ylut != ylut_clamped)
|
|
346
|
+
quality_flag[flagged_mask] |= ImapDEUltraFlags.PHCORR.value
|
|
347
|
+
|
|
348
|
+
ph_correction = ph_correct_array[xlut_clamped, ylut_clamped]
|
|
349
|
+
|
|
350
|
+
return ph_correction, quality_flag
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""Contains list of QFs to use for filtering."""
|
|
2
|
+
|
|
3
|
+
from imap_processing.quality_flags import (
|
|
4
|
+
FlagNameMixin,
|
|
5
|
+
ImapRatesUltraFlags,
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
QUALITY_FLAG_FILTERS: dict[str, list[FlagNameMixin]] = {
|
|
9
|
+
"quality_attitude": [],
|
|
10
|
+
"quality_ena_rates": [
|
|
11
|
+
ImapRatesUltraFlags.FIRSTSPIN,
|
|
12
|
+
ImapRatesUltraFlags.LASTSPIN,
|
|
13
|
+
],
|
|
14
|
+
}
|