imap-processing 0.19.0__py3-none-any.whl → 0.19.2__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/cdf/config/imap_codice_global_cdf_attrs.yaml +6 -0
- imap_processing/cdf/config/imap_codice_l1a_variable_attrs.yaml +31 -894
- imap_processing/cdf/config/imap_codice_l1b_variable_attrs.yaml +279 -255
- imap_processing/cdf/config/imap_enamaps_l2-common_variable_attrs.yaml +11 -0
- imap_processing/cdf/config/imap_glows_l1b_variable_attrs.yaml +3 -1
- imap_processing/cdf/config/imap_lo_global_cdf_attrs.yaml +5 -4
- imap_processing/cdf/config/imap_ultra_global_cdf_attrs.yaml +20 -8
- imap_processing/cdf/config/imap_ultra_l1b_variable_attrs.yaml +33 -31
- imap_processing/cdf/config/imap_ultra_l1c_variable_attrs.yaml +61 -1
- imap_processing/cli.py +62 -71
- imap_processing/codice/codice_l0.py +2 -1
- imap_processing/codice/codice_l1a.py +47 -49
- imap_processing/codice/codice_l1b.py +42 -32
- imap_processing/codice/codice_l2.py +105 -7
- imap_processing/codice/constants.py +50 -8
- imap_processing/codice/data/lo_stepping_values.csv +1 -1
- imap_processing/ena_maps/ena_maps.py +39 -18
- imap_processing/ena_maps/utils/corrections.py +291 -0
- imap_processing/ena_maps/utils/map_utils.py +20 -4
- imap_processing/glows/l1b/glows_l1b.py +38 -23
- imap_processing/glows/l1b/glows_l1b_data.py +10 -11
- imap_processing/hi/hi_l1c.py +4 -109
- imap_processing/hi/hi_l2.py +34 -23
- imap_processing/hi/utils.py +109 -0
- imap_processing/ialirt/l0/ialirt_spice.py +1 -0
- imap_processing/ialirt/utils/create_xarray.py +1 -1
- imap_processing/lo/ancillary_data/imap_lo_hydrogen-geometric-factor_v001.csv +75 -0
- imap_processing/lo/ancillary_data/imap_lo_oxygen-geometric-factor_v001.csv +75 -0
- imap_processing/lo/l1b/lo_l1b.py +90 -16
- imap_processing/lo/l1c/lo_l1c.py +164 -50
- imap_processing/lo/l2/lo_l2.py +941 -127
- imap_processing/mag/l1d/mag_l1d_data.py +36 -3
- imap_processing/mag/l2/mag_l2.py +2 -0
- imap_processing/mag/l2/mag_l2_data.py +4 -3
- imap_processing/quality_flags.py +14 -0
- imap_processing/spice/geometry.py +15 -8
- imap_processing/spice/pointing_frame.py +4 -2
- imap_processing/spice/repoint.py +49 -0
- imap_processing/ultra/constants.py +29 -0
- imap_processing/ultra/l1b/badtimes.py +35 -11
- imap_processing/ultra/l1b/de.py +15 -9
- imap_processing/ultra/l1b/extendedspin.py +24 -12
- imap_processing/ultra/l1b/goodtimes.py +112 -0
- imap_processing/ultra/l1b/lookup_utils.py +1 -1
- imap_processing/ultra/l1b/ultra_l1b.py +7 -7
- imap_processing/ultra/l1b/ultra_l1b_culling.py +8 -4
- imap_processing/ultra/l1b/ultra_l1b_extended.py +79 -43
- imap_processing/ultra/l1c/helio_pset.py +68 -39
- imap_processing/ultra/l1c/l1c_lookup_utils.py +45 -12
- imap_processing/ultra/l1c/spacecraft_pset.py +81 -37
- imap_processing/ultra/l1c/ultra_l1c.py +27 -22
- imap_processing/ultra/l1c/ultra_l1c_culling.py +7 -0
- imap_processing/ultra/l1c/ultra_l1c_pset_bins.py +41 -41
- imap_processing/ultra/l2/ultra_l2.py +54 -10
- imap_processing/ultra/utils/ultra_l1_utils.py +10 -5
- {imap_processing-0.19.0.dist-info → imap_processing-0.19.2.dist-info}/METADATA +1 -1
- {imap_processing-0.19.0.dist-info → imap_processing-0.19.2.dist-info}/RECORD +62 -60
- imap_processing/ultra/l1b/cullingmask.py +0 -90
- imap_processing/ultra/l1c/histogram.py +0 -36
- /imap_processing/glows/ancillary/{imap_glows_pipeline_settings_20250923_v002.json → imap_glows_pipeline-settings_20250923_v002.json} +0 -0
- {imap_processing-0.19.0.dist-info → imap_processing-0.19.2.dist-info}/LICENSE +0 -0
- {imap_processing-0.19.0.dist-info → imap_processing-0.19.2.dist-info}/WHEEL +0 -0
- {imap_processing-0.19.0.dist-info → imap_processing-0.19.2.dist-info}/entry_points.txt +0 -0
imap_processing/lo/l1b/lo_l1b.py
CHANGED
|
@@ -9,6 +9,7 @@ import numpy as np
|
|
|
9
9
|
import xarray as xr
|
|
10
10
|
|
|
11
11
|
from imap_processing.cdf.imap_cdf_manager import ImapCdfAttributes
|
|
12
|
+
from imap_processing.lo import lo_ancillary
|
|
12
13
|
from imap_processing.lo.l1b.tof_conversions import (
|
|
13
14
|
TOF0_CONV,
|
|
14
15
|
TOF1_CONV,
|
|
@@ -16,20 +17,24 @@ from imap_processing.lo.l1b.tof_conversions import (
|
|
|
16
17
|
TOF3_CONV,
|
|
17
18
|
)
|
|
18
19
|
from imap_processing.spice.geometry import SpiceFrame, instrument_pointing
|
|
20
|
+
from imap_processing.spice.repoint import get_pointing_times
|
|
21
|
+
from imap_processing.spice.spin import get_spin_number
|
|
19
22
|
from imap_processing.spice.time import met_to_ttj2000ns, ttj2000ns_to_et
|
|
20
23
|
|
|
21
24
|
logger = logging.getLogger(__name__)
|
|
22
25
|
logger.setLevel(logging.INFO)
|
|
23
26
|
|
|
24
27
|
|
|
25
|
-
def lo_l1b(
|
|
28
|
+
def lo_l1b(sci_dependencies: dict, anc_dependencies: list) -> list[Path]:
|
|
26
29
|
"""
|
|
27
30
|
Will process IMAP-Lo L1A data into L1B CDF data products.
|
|
28
31
|
|
|
29
32
|
Parameters
|
|
30
33
|
----------
|
|
31
|
-
|
|
34
|
+
sci_dependencies : dict
|
|
32
35
|
Dictionary of datasets needed for L1B data product creation in xarray Datasets.
|
|
36
|
+
anc_dependencies : list
|
|
37
|
+
List of ancillary file paths needed for L1B data product creation.
|
|
33
38
|
|
|
34
39
|
Returns
|
|
35
40
|
-------
|
|
@@ -43,17 +48,20 @@ def lo_l1b(dependencies: dict) -> list[Path]:
|
|
|
43
48
|
# create the attribute manager to access L1A fillval attributes
|
|
44
49
|
attr_mgr_l1a = ImapCdfAttributes()
|
|
45
50
|
attr_mgr_l1a.add_instrument_variable_attrs(instrument="lo", level="l1a")
|
|
46
|
-
logger.info(f"\n Dependencies: {list(
|
|
51
|
+
logger.info(f"\n Dependencies: {list(sci_dependencies.keys())}\n")
|
|
47
52
|
# if the dependencies are used to create Annotated Direct Events
|
|
48
|
-
if "imap_lo_l1a_de" in
|
|
53
|
+
if "imap_lo_l1a_de" in sci_dependencies and "imap_lo_l1a_spin" in sci_dependencies:
|
|
49
54
|
logger.info("\nProcessing IMAP-Lo L1B Direct Events...")
|
|
50
55
|
logical_source = "imap_lo_l1b_de"
|
|
51
56
|
# get the dependency dataset for l1b direct events
|
|
52
|
-
l1a_de =
|
|
53
|
-
spin_data =
|
|
57
|
+
l1a_de = sci_dependencies["imap_lo_l1a_de"]
|
|
58
|
+
spin_data = sci_dependencies["imap_lo_l1a_spin"]
|
|
54
59
|
|
|
55
60
|
# Initialize the L1B DE dataset
|
|
56
61
|
l1b_de = initialize_l1b_de(l1a_de, attr_mgr_l1b, logical_source)
|
|
62
|
+
pointing_start_met, pointing_end_met = get_pointing_times(
|
|
63
|
+
l1a_de["met"].values[0].item()
|
|
64
|
+
)
|
|
57
65
|
# Get the start and end times for each spin epoch
|
|
58
66
|
acq_start, acq_end = convert_start_end_acq_times(spin_data)
|
|
59
67
|
# Get the average spin durations for each epoch
|
|
@@ -66,7 +74,7 @@ def lo_l1b(dependencies: dict) -> list[Path]:
|
|
|
66
74
|
# spin bins are 0 - 60 bins
|
|
67
75
|
l1b_de = set_spin_bin(l1b_de, spin_angle)
|
|
68
76
|
# set the spin cycle for each direct event
|
|
69
|
-
l1b_de = set_spin_cycle(l1a_de, l1b_de)
|
|
77
|
+
l1b_de = set_spin_cycle(pointing_start_met, l1a_de, l1b_de)
|
|
70
78
|
# get spin start times for each event
|
|
71
79
|
spin_start_time = get_spin_start_times(l1a_de, l1b_de, spin_data, acq_end)
|
|
72
80
|
# get the absolute met for each event
|
|
@@ -75,6 +83,10 @@ def lo_l1b(dependencies: dict) -> list[Path]:
|
|
|
75
83
|
)
|
|
76
84
|
# set the epoch for each event
|
|
77
85
|
l1b_de = set_each_event_epoch(l1b_de)
|
|
86
|
+
# Set the ESA mode for each direct event
|
|
87
|
+
l1b_de = set_esa_mode(
|
|
88
|
+
pointing_start_met, pointing_end_met, anc_dependencies, l1b_de
|
|
89
|
+
)
|
|
78
90
|
# Set the average spin duration for each direct event
|
|
79
91
|
l1b_de = set_avg_spin_durations_per_event(
|
|
80
92
|
l1a_de, l1b_de, avg_spin_durations_per_cycle
|
|
@@ -133,7 +145,7 @@ def initialize_l1b_de(
|
|
|
133
145
|
# TODO: Add pos to YAML file
|
|
134
146
|
# attrs=attr_mgr.get_variable_attributes("pos"),
|
|
135
147
|
)
|
|
136
|
-
l1b_de["
|
|
148
|
+
l1b_de["mode_bit"] = xr.DataArray(
|
|
137
149
|
l1a_de["mode"].values,
|
|
138
150
|
dims=["epoch"],
|
|
139
151
|
# TODO: Add mode to YAML file
|
|
@@ -155,6 +167,65 @@ def initialize_l1b_de(
|
|
|
155
167
|
return l1b_de
|
|
156
168
|
|
|
157
169
|
|
|
170
|
+
def set_esa_mode(
|
|
171
|
+
pointing_start_met: float,
|
|
172
|
+
pointing_end_met: float,
|
|
173
|
+
anc_dependencies: list,
|
|
174
|
+
l1b_de: xr.Dataset,
|
|
175
|
+
) -> xr.Dataset:
|
|
176
|
+
"""
|
|
177
|
+
Set the ESA mode for each direct event.
|
|
178
|
+
|
|
179
|
+
The ESA mode is determined from the sweep table for the time period of the pointing.
|
|
180
|
+
|
|
181
|
+
Parameters
|
|
182
|
+
----------
|
|
183
|
+
pointing_start_met : float
|
|
184
|
+
Start time for the pointing in MET seconds.
|
|
185
|
+
pointing_end_met : float
|
|
186
|
+
End time for the pointing in MET seconds.
|
|
187
|
+
anc_dependencies : list
|
|
188
|
+
List of ancillary file paths.
|
|
189
|
+
l1b_de : xarray.Dataset
|
|
190
|
+
The L1B DE dataset.
|
|
191
|
+
|
|
192
|
+
Returns
|
|
193
|
+
-------
|
|
194
|
+
l1b_de : xr.Dataset
|
|
195
|
+
The L1B DE dataset with the ESA mode added.
|
|
196
|
+
"""
|
|
197
|
+
# Read the sweep table from the ancillary files
|
|
198
|
+
sweep_df = lo_ancillary.read_ancillary_file(
|
|
199
|
+
next(str(s) for s in anc_dependencies if "sweep-table" in str(s))
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
# Get the sweep table rows that correspond to the time period of the pointing
|
|
203
|
+
pointing_sweep_df = sweep_df[
|
|
204
|
+
(sweep_df["GoodTime_start"] >= pointing_start_met)
|
|
205
|
+
& (sweep_df["GoodTime_start"] <= pointing_end_met)
|
|
206
|
+
]
|
|
207
|
+
|
|
208
|
+
# Check that there is only one ESA mode in the sweep table for the pointing
|
|
209
|
+
if len(pointing_sweep_df["ESA_Mode"].unique()) == 1:
|
|
210
|
+
# Update the ESA mode strings to be 0 for HiRes and 1 for HiThr
|
|
211
|
+
sweep_df["esa_mode"] = sweep_df["ESA_Mode"].map({"HiRes": 0, "HiThr": 1})
|
|
212
|
+
# Get the ESA mode for the pointing
|
|
213
|
+
esa_mode = sweep_df["esa_mode"].values[0]
|
|
214
|
+
# Repeat the ESA mode for each direct event in the pointing
|
|
215
|
+
esa_mode_array = np.repeat(esa_mode, len(l1b_de["epoch"]))
|
|
216
|
+
else:
|
|
217
|
+
raise ValueError("Multiple ESA modes found in sweep table for pointing.")
|
|
218
|
+
|
|
219
|
+
l1b_de["esa_mode"] = xr.DataArray(
|
|
220
|
+
esa_mode_array,
|
|
221
|
+
dims=["epoch"],
|
|
222
|
+
# TODO: Add esa_mode to YAML file
|
|
223
|
+
# attrs=attr_mgr.get_variable_attributes("esa_mode"),
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
return l1b_de
|
|
227
|
+
|
|
228
|
+
|
|
158
229
|
def convert_start_end_acq_times(
|
|
159
230
|
spin_data: xr.Dataset,
|
|
160
231
|
) -> tuple[xr.DataArray, xr.DataArray]:
|
|
@@ -252,7 +323,9 @@ def set_spin_bin(l1b_de: xr.Dataset, spin_angle: np.ndarray) -> xr.Dataset:
|
|
|
252
323
|
return l1b_de
|
|
253
324
|
|
|
254
325
|
|
|
255
|
-
def set_spin_cycle(
|
|
326
|
+
def set_spin_cycle(
|
|
327
|
+
pointing_start_met: float, l1a_de: xr.Dataset, l1b_de: xr.Dataset
|
|
328
|
+
) -> xr.Dataset:
|
|
256
329
|
"""
|
|
257
330
|
Set the spin cycle for each direct event.
|
|
258
331
|
|
|
@@ -265,6 +338,8 @@ def set_spin_cycle(l1a_de: xr.Dataset, l1b_de: xr.Dataset) -> xr.Dataset:
|
|
|
265
338
|
|
|
266
339
|
Parameters
|
|
267
340
|
----------
|
|
341
|
+
pointing_start_met : float
|
|
342
|
+
The start time of the pointing in MET seconds.
|
|
268
343
|
l1a_de : xarray.Dataset
|
|
269
344
|
The L1A DE dataset.
|
|
270
345
|
l1b_de : xarray.Dataset
|
|
@@ -275,19 +350,18 @@ def set_spin_cycle(l1a_de: xr.Dataset, l1b_de: xr.Dataset) -> xr.Dataset:
|
|
|
275
350
|
l1b_de : xarray.Dataset
|
|
276
351
|
The L1B DE dataset with the spin cycle added for each direct event.
|
|
277
352
|
"""
|
|
353
|
+
spin_start_num = get_spin_number(pointing_start_met)
|
|
278
354
|
counts = l1a_de["de_count"].values
|
|
279
355
|
# split the esa_steps into ASC groups
|
|
280
356
|
de_asc_groups = np.split(l1a_de["esa_step"].values, np.cumsum(counts)[:-1])
|
|
281
357
|
spin_cycle = []
|
|
282
|
-
for
|
|
283
|
-
# TODO: Spin Number does not reset for each pointing. Need to figure out
|
|
284
|
-
# how to retain this information across days
|
|
285
|
-
# increment the spin_start by 28 after each aggregated science cycle
|
|
286
|
-
spin_start = i * 28
|
|
358
|
+
for esa_asc_group in de_asc_groups:
|
|
287
359
|
# calculate the spin cycle for each DE in the ASC group
|
|
288
360
|
# TODO: Add equation number in algorithm document when new version is
|
|
289
|
-
#
|
|
290
|
-
spin_cycle.extend(
|
|
361
|
+
# available. Add to docstring as well
|
|
362
|
+
spin_cycle.extend(spin_start_num + 7 + (esa_asc_group - 1) * 2)
|
|
363
|
+
# increment the spin start number by 28 for the next ASC
|
|
364
|
+
spin_start_num += 28
|
|
291
365
|
|
|
292
366
|
l1b_de["spin_cycle"] = xr.DataArray(
|
|
293
367
|
spin_cycle,
|
imap_processing/lo/l1c/lo_l1c.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""IMAP-Lo L1C Data Processing."""
|
|
2
2
|
|
|
3
|
+
import logging
|
|
3
4
|
from dataclasses import Field
|
|
4
5
|
from enum import Enum
|
|
5
6
|
|
|
@@ -67,14 +68,36 @@ def lo_l1c(sci_dependencies: dict, anc_dependencies: list) -> list[xr.Dataset]:
|
|
|
67
68
|
logical_source = "imap_lo_l1c_pset"
|
|
68
69
|
l1b_de = sci_dependencies["imap_lo_l1b_de"]
|
|
69
70
|
l1b_goodtimes_only = filter_goodtimes(l1b_de, anc_dependencies)
|
|
70
|
-
pset = initialize_pset(l1b_goodtimes_only, attr_mgr, logical_source)
|
|
71
|
-
full_counts = create_pset_counts(l1b_goodtimes_only)
|
|
72
71
|
|
|
73
72
|
# Set the pointing start and end times based on the first epoch
|
|
74
73
|
pointing_start_met, pointing_end_met = get_pointing_times(
|
|
75
74
|
ttj2000ns_to_met(l1b_goodtimes_only["epoch"][0].item())
|
|
76
75
|
)
|
|
77
76
|
|
|
77
|
+
pset = xr.Dataset(
|
|
78
|
+
coords={"epoch": np.array([met_to_ttj2000ns(pointing_start_met)])},
|
|
79
|
+
attrs=attr_mgr.get_global_attributes(logical_source),
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
# ESA mode needs to be added to L1B DE. Adding try statement
|
|
83
|
+
# to avoid error until it's available in the dataset
|
|
84
|
+
if "esa_mode" not in l1b_de:
|
|
85
|
+
logging.debug(
|
|
86
|
+
"ESA mode not found in L1B DE dataset. \
|
|
87
|
+
Setting to default value of 0 for Hi-Res."
|
|
88
|
+
)
|
|
89
|
+
pset["esa_mode"] = xr.DataArray(
|
|
90
|
+
np.array([0]),
|
|
91
|
+
dims=["epoch"],
|
|
92
|
+
attrs=attr_mgr.get_variable_attributes("esa_mode"),
|
|
93
|
+
)
|
|
94
|
+
else:
|
|
95
|
+
pset["esa_mode"] = xr.DataArray(
|
|
96
|
+
np.array([l1b_de["esa_mode"].values[0]]),
|
|
97
|
+
dims=["epoch"],
|
|
98
|
+
attrs=attr_mgr.get_variable_attributes("esa_mode"),
|
|
99
|
+
)
|
|
100
|
+
|
|
78
101
|
pset["pointing_start_met"] = xr.DataArray(
|
|
79
102
|
np.array([pointing_start_met]),
|
|
80
103
|
dims="epoch",
|
|
@@ -86,12 +109,6 @@ def lo_l1c(sci_dependencies: dict, anc_dependencies: list) -> list[xr.Dataset]:
|
|
|
86
109
|
attrs=attr_mgr.get_variable_attributes("pointing_end_met"),
|
|
87
110
|
)
|
|
88
111
|
|
|
89
|
-
# Set the epoch to the start of the pointing
|
|
90
|
-
pset["epoch"] = xr.DataArray(
|
|
91
|
-
met_to_ttj2000ns(pset["pointing_start_met"].values),
|
|
92
|
-
attrs=attr_mgr.get_variable_attributes("epoch"),
|
|
93
|
-
)
|
|
94
|
-
|
|
95
112
|
# Get the start and end spin numbers based on the pointing start and end MET
|
|
96
113
|
pset["start_spin_number"] = xr.DataArray(
|
|
97
114
|
[get_spin_number(pset["pointing_start_met"].item())],
|
|
@@ -104,6 +121,8 @@ def lo_l1c(sci_dependencies: dict, anc_dependencies: list) -> list[xr.Dataset]:
|
|
|
104
121
|
attrs=attr_mgr.get_variable_attributes("end_spin_number"),
|
|
105
122
|
)
|
|
106
123
|
|
|
124
|
+
full_counts = create_pset_counts(l1b_de, FilterType.NONE)
|
|
125
|
+
|
|
107
126
|
# Set the counts
|
|
108
127
|
pset["triples_counts"] = create_pset_counts(
|
|
109
128
|
l1b_goodtimes_only, FilterType.TRIPLES
|
|
@@ -118,6 +137,32 @@ def lo_l1c(sci_dependencies: dict, anc_dependencies: list) -> list[xr.Dataset]:
|
|
|
118
137
|
pset["exposure_time"] = calculate_exposure_times(
|
|
119
138
|
full_counts, l1b_goodtimes_only
|
|
120
139
|
)
|
|
140
|
+
|
|
141
|
+
# Set backgrounds
|
|
142
|
+
(
|
|
143
|
+
pset["h_background_rates"],
|
|
144
|
+
pset["h_background_rates_stat_uncert"],
|
|
145
|
+
pset["h_background_rates_sys_err"],
|
|
146
|
+
) = set_background_rates(
|
|
147
|
+
pset["pointing_start_met"].item(),
|
|
148
|
+
pset["pointing_end_met"].item(),
|
|
149
|
+
FilterType.HYDROGEN,
|
|
150
|
+
anc_dependencies,
|
|
151
|
+
attr_mgr,
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
(
|
|
155
|
+
pset["o_background_rates"],
|
|
156
|
+
pset["o_background_rates_stat_uncert"],
|
|
157
|
+
pset["o_background_rates_sys_err"],
|
|
158
|
+
) = set_background_rates(
|
|
159
|
+
pset["pointing_start_met"].item(),
|
|
160
|
+
pset["pointing_end_met"].item(),
|
|
161
|
+
FilterType.OXYGEN,
|
|
162
|
+
anc_dependencies,
|
|
163
|
+
attr_mgr,
|
|
164
|
+
)
|
|
165
|
+
|
|
121
166
|
pset.attrs = attr_mgr.get_global_attributes(logical_source)
|
|
122
167
|
|
|
123
168
|
pset = pset.assign_coords(
|
|
@@ -131,44 +176,6 @@ def lo_l1c(sci_dependencies: dict, anc_dependencies: list) -> list[xr.Dataset]:
|
|
|
131
176
|
return [pset]
|
|
132
177
|
|
|
133
178
|
|
|
134
|
-
def initialize_pset(
|
|
135
|
-
l1b_de: xr.Dataset, attr_mgr: ImapCdfAttributes, logical_source: str
|
|
136
|
-
) -> xr.Dataset:
|
|
137
|
-
"""
|
|
138
|
-
Initialize the PSET dataset and set the Epoch.
|
|
139
|
-
|
|
140
|
-
The Epoch time is set to the first of the L1B
|
|
141
|
-
Direct Event times. There is one Epoch per PSET file.
|
|
142
|
-
|
|
143
|
-
Parameters
|
|
144
|
-
----------
|
|
145
|
-
l1b_de : xarray.Dataset
|
|
146
|
-
L1B Direct Event dataset.
|
|
147
|
-
attr_mgr : ImapCdfAttributes
|
|
148
|
-
Attribute manager used to get the L1C attributes.
|
|
149
|
-
logical_source : str
|
|
150
|
-
The logical source of the pset.
|
|
151
|
-
|
|
152
|
-
Returns
|
|
153
|
-
-------
|
|
154
|
-
pset : xarray.Dataset
|
|
155
|
-
Initialized PSET dataset.
|
|
156
|
-
"""
|
|
157
|
-
pset = xr.Dataset(
|
|
158
|
-
attrs=attr_mgr.get_global_attributes(logical_source),
|
|
159
|
-
)
|
|
160
|
-
# TODO: Need to create utility to get start of repointing to use
|
|
161
|
-
# for the pset epoch time. Setting to first DE for now
|
|
162
|
-
pset_epoch = l1b_de["epoch"][0].item()
|
|
163
|
-
pset["epoch"] = xr.DataArray(
|
|
164
|
-
np.array([pset_epoch]),
|
|
165
|
-
dims=["epoch"],
|
|
166
|
-
attrs=attr_mgr.get_variable_attributes("epoch"),
|
|
167
|
-
)
|
|
168
|
-
|
|
169
|
-
return pset
|
|
170
|
-
|
|
171
|
-
|
|
172
179
|
def filter_goodtimes(l1b_de: xr.Dataset, anc_dependencies: list) -> xr.Dataset:
|
|
173
180
|
"""
|
|
174
181
|
Filter the L1B Direct Event dataset to only include good times.
|
|
@@ -189,10 +196,12 @@ def filter_goodtimes(l1b_de: xr.Dataset, anc_dependencies: list) -> xr.Dataset:
|
|
|
189
196
|
Filtered L1B Direct Event dataset.
|
|
190
197
|
"""
|
|
191
198
|
# the goodtimes are currently the only ancillary file needed for L1C processing
|
|
192
|
-
goodtimes_table_df = lo_ancillary.read_ancillary_file(
|
|
199
|
+
goodtimes_table_df = lo_ancillary.read_ancillary_file(
|
|
200
|
+
next(str(s) for s in anc_dependencies if "good-times" in str(s))
|
|
201
|
+
)
|
|
193
202
|
|
|
194
203
|
# convert goodtimes from MET to TTJ2000
|
|
195
|
-
goodtimes_start = met_to_ttj2000ns(goodtimes_table_df["
|
|
204
|
+
goodtimes_start = met_to_ttj2000ns(goodtimes_table_df["GoodTime_start"])
|
|
196
205
|
goodtimes_end = met_to_ttj2000ns(goodtimes_table_df["GoodTime_end"])
|
|
197
206
|
|
|
198
207
|
# Create a mask for epochs within any of the start/end time ranges
|
|
@@ -254,9 +263,9 @@ def create_pset_counts(
|
|
|
254
263
|
"001000",
|
|
255
264
|
],
|
|
256
265
|
# hydrogen species identifier
|
|
257
|
-
FilterType.HYDROGEN: "
|
|
266
|
+
FilterType.HYDROGEN: "H",
|
|
258
267
|
# oxygen species identifier
|
|
259
|
-
FilterType.OXYGEN: "
|
|
268
|
+
FilterType.OXYGEN: "O",
|
|
260
269
|
}
|
|
261
270
|
|
|
262
271
|
# if the filter string is triples or doubles, filter using the coincidence type
|
|
@@ -484,3 +493,108 @@ def create_datasets(
|
|
|
484
493
|
)
|
|
485
494
|
|
|
486
495
|
return dataset
|
|
496
|
+
|
|
497
|
+
|
|
498
|
+
def set_background_rates(
|
|
499
|
+
pointing_start_met: float,
|
|
500
|
+
pointing_end_met: float,
|
|
501
|
+
species: FilterType,
|
|
502
|
+
anc_dependencies: list,
|
|
503
|
+
attr_mgr: ImapCdfAttributes,
|
|
504
|
+
) -> tuple[xr.DataArray, xr.DataArray, xr.DataArray]:
|
|
505
|
+
"""
|
|
506
|
+
Set the background rates for the specified species.
|
|
507
|
+
|
|
508
|
+
The background rates are set to a constant value of 0.01 counts/s for all bins.
|
|
509
|
+
|
|
510
|
+
Parameters
|
|
511
|
+
----------
|
|
512
|
+
pointing_start_met : float
|
|
513
|
+
The start MET time of the pointing.
|
|
514
|
+
pointing_end_met : float
|
|
515
|
+
The end MET time of the pointing.
|
|
516
|
+
species : FilterType
|
|
517
|
+
The species to set the background rates for. Can be "h" or "o".
|
|
518
|
+
anc_dependencies : list
|
|
519
|
+
Ancillary files needed for L1C data product creation.
|
|
520
|
+
attr_mgr : ImapCdfAttributes
|
|
521
|
+
Attribute manager used to get the L1C attributes.
|
|
522
|
+
|
|
523
|
+
Returns
|
|
524
|
+
-------
|
|
525
|
+
background_rates : tuple[xr.DataArray, xr.DataArray, xr.DataArray]
|
|
526
|
+
Tuple containing:
|
|
527
|
+
- The background rates for the specified species.
|
|
528
|
+
- The statistical uncertainties for the background rates.
|
|
529
|
+
- The systematic errors for the background rates.
|
|
530
|
+
"""
|
|
531
|
+
if species not in {FilterType.HYDROGEN, FilterType.OXYGEN}:
|
|
532
|
+
raise ValueError(f"Species must be 'h' or 'o', but got {species.value}.")
|
|
533
|
+
|
|
534
|
+
bg_rates = np.zeros(
|
|
535
|
+
(N_ESA_ENERGY_STEPS, N_SPIN_ANGLE_BINS, N_OFF_ANGLE_BINS), dtype=np.float16
|
|
536
|
+
)
|
|
537
|
+
bg_stat_uncert = np.zeros(
|
|
538
|
+
(N_ESA_ENERGY_STEPS, N_SPIN_ANGLE_BINS, N_OFF_ANGLE_BINS), dtype=np.float16
|
|
539
|
+
)
|
|
540
|
+
bg_sys_err = np.zeros(
|
|
541
|
+
(N_ESA_ENERGY_STEPS, N_SPIN_ANGLE_BINS, N_OFF_ANGLE_BINS), dtype=np.float16
|
|
542
|
+
)
|
|
543
|
+
|
|
544
|
+
# read in the background rates from ancillary file
|
|
545
|
+
if species == FilterType.HYDROGEN:
|
|
546
|
+
background_df = lo_ancillary.read_ancillary_file(
|
|
547
|
+
next(str(s) for s in anc_dependencies if "hydrogen-background" in str(s))
|
|
548
|
+
)
|
|
549
|
+
else:
|
|
550
|
+
background_df = lo_ancillary.read_ancillary_file(
|
|
551
|
+
next(str(s) for s in anc_dependencies if "oxygen-background" in str(s))
|
|
552
|
+
)
|
|
553
|
+
|
|
554
|
+
# find to the rows for the current pointing
|
|
555
|
+
pointing_bg_df = background_df[
|
|
556
|
+
(background_df["GoodTime_strt"] >= pointing_start_met)
|
|
557
|
+
& (background_df["GoodTime_end"] <= pointing_end_met)
|
|
558
|
+
]
|
|
559
|
+
|
|
560
|
+
# convert the bin start and end resolution from 6 degrees to .1 degrees
|
|
561
|
+
pointing_bg_df["bin_strt"] = pointing_bg_df["bin_strt"] * 60
|
|
562
|
+
# The last bin end in the file is 0, which means 60 degrees. This is
|
|
563
|
+
# converted to 0.1 degree resolution of 3600
|
|
564
|
+
pointing_bg_df["bin_end"] = pointing_bg_df["bin_end"] * 60
|
|
565
|
+
pointing_bg_df.loc[pointing_bg_df["bin_end"] == 0, "bin_end"] = 3600
|
|
566
|
+
# for each row in the bg ancillary file for this pointing
|
|
567
|
+
for _, row in pointing_bg_df.iterrows():
|
|
568
|
+
bin_start = int(row["bin_strt"])
|
|
569
|
+
bin_end = int(row["bin_end"])
|
|
570
|
+
# for each energy step, set the background rate and uncertainty
|
|
571
|
+
for esa_step in range(0, 7):
|
|
572
|
+
value = row[f"E-Step{esa_step + 1}"]
|
|
573
|
+
if row["type"] == "rate":
|
|
574
|
+
bg_rates[esa_step, bin_start:bin_end, :] = value
|
|
575
|
+
elif row["type"] == "sigma":
|
|
576
|
+
bg_stat_uncert[esa_step, bin_start:bin_end, :] = value
|
|
577
|
+
else:
|
|
578
|
+
raise ValueError("Unknown background type in ancillary file.")
|
|
579
|
+
# set the background rates, uncertainties, and systematic errors
|
|
580
|
+
bg_rates_data = xr.DataArray(
|
|
581
|
+
data=bg_rates,
|
|
582
|
+
dims=["esa_energy_step", "spin_angle", "off_angle"],
|
|
583
|
+
attrs=attr_mgr.get_variable_attributes(f"{species.value}_background_rates"),
|
|
584
|
+
)
|
|
585
|
+
bg_stat_uncert_data = xr.DataArray(
|
|
586
|
+
data=bg_stat_uncert,
|
|
587
|
+
dims=["esa_energy_step", "spin_angle", "off_angle"],
|
|
588
|
+
attrs=attr_mgr.get_variable_attributes(
|
|
589
|
+
f"{species.value}_background_rates_stat_uncert"
|
|
590
|
+
),
|
|
591
|
+
)
|
|
592
|
+
bg_sys_err_data = xr.DataArray(
|
|
593
|
+
data=bg_sys_err,
|
|
594
|
+
dims=["esa_energy_step", "spin_angle", "off_angle"],
|
|
595
|
+
attrs=attr_mgr.get_variable_attributes(
|
|
596
|
+
f"{species.value}_background_rates_sys_err"
|
|
597
|
+
),
|
|
598
|
+
)
|
|
599
|
+
|
|
600
|
+
return bg_rates_data, bg_stat_uncert_data, bg_sys_err_data
|