imap-processing 0.18.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/ancillary/ancillary_dataset_combiner.py +161 -1
- imap_processing/cdf/config/imap_codice_global_cdf_attrs.yaml +6 -0
- imap_processing/cdf/config/imap_codice_l1a_variable_attrs.yaml +221 -1057
- imap_processing/cdf/config/imap_codice_l1b_variable_attrs.yaml +307 -283
- imap_processing/cdf/config/imap_codice_l2_variable_attrs.yaml +1044 -203
- imap_processing/cdf/config/imap_constant_attrs.yaml +4 -2
- imap_processing/cdf/config/imap_enamaps_l2-common_variable_attrs.yaml +11 -0
- imap_processing/cdf/config/imap_glows_l1b_variable_attrs.yaml +15 -1
- imap_processing/cdf/config/imap_hi_global_cdf_attrs.yaml +5 -0
- imap_processing/cdf/config/imap_hit_global_cdf_attrs.yaml +10 -4
- imap_processing/cdf/config/imap_idex_l2a_variable_attrs.yaml +33 -4
- imap_processing/cdf/config/imap_idex_l2b_variable_attrs.yaml +8 -91
- imap_processing/cdf/config/imap_idex_l2c_variable_attrs.yaml +106 -16
- imap_processing/cdf/config/imap_lo_global_cdf_attrs.yaml +5 -4
- imap_processing/cdf/config/imap_lo_l1a_variable_attrs.yaml +4 -15
- imap_processing/cdf/config/imap_lo_l1c_variable_attrs.yaml +189 -98
- imap_processing/cdf/config/imap_mag_global_cdf_attrs.yaml +85 -2
- imap_processing/cdf/config/imap_mag_l1c_variable_attrs.yaml +24 -1
- imap_processing/cdf/config/imap_ultra_global_cdf_attrs.yaml +20 -8
- imap_processing/cdf/config/imap_ultra_l1b_variable_attrs.yaml +45 -35
- imap_processing/cdf/config/imap_ultra_l1c_variable_attrs.yaml +110 -7
- imap_processing/cli.py +138 -93
- imap_processing/codice/codice_l0.py +2 -1
- imap_processing/codice/codice_l1a.py +167 -69
- imap_processing/codice/codice_l1b.py +42 -32
- imap_processing/codice/codice_l2.py +215 -9
- imap_processing/codice/constants.py +790 -603
- imap_processing/codice/data/lo_stepping_values.csv +1 -1
- imap_processing/decom.py +1 -4
- imap_processing/ena_maps/ena_maps.py +71 -43
- imap_processing/ena_maps/utils/corrections.py +291 -0
- imap_processing/ena_maps/utils/map_utils.py +20 -4
- imap_processing/ena_maps/utils/naming.py +8 -2
- imap_processing/glows/ancillary/imap_glows_exclusions-by-instr-team_20250923_v002.dat +10 -0
- imap_processing/glows/ancillary/imap_glows_map-of-excluded-regions_20250923_v002.dat +393 -0
- imap_processing/glows/ancillary/imap_glows_map-of-uv-sources_20250923_v002.dat +593 -0
- imap_processing/glows/ancillary/imap_glows_pipeline-settings_20250923_v002.json +54 -0
- imap_processing/glows/ancillary/imap_glows_suspected-transients_20250923_v002.dat +10 -0
- imap_processing/glows/l1b/glows_l1b.py +123 -18
- imap_processing/glows/l1b/glows_l1b_data.py +358 -47
- imap_processing/glows/l2/glows_l2.py +11 -0
- imap_processing/hi/hi_l1a.py +124 -3
- imap_processing/hi/hi_l1b.py +154 -71
- imap_processing/hi/hi_l1c.py +4 -109
- imap_processing/hi/hi_l2.py +104 -60
- imap_processing/hi/utils.py +262 -8
- imap_processing/hit/l0/constants.py +3 -0
- imap_processing/hit/l0/decom_hit.py +3 -6
- imap_processing/hit/l1a/hit_l1a.py +311 -21
- imap_processing/hit/l1b/hit_l1b.py +54 -126
- imap_processing/hit/l2/hit_l2.py +6 -6
- imap_processing/ialirt/calculate_ingest.py +219 -0
- imap_processing/ialirt/constants.py +12 -2
- imap_processing/ialirt/generate_coverage.py +15 -2
- imap_processing/ialirt/l0/ialirt_spice.py +6 -2
- imap_processing/ialirt/l0/parse_mag.py +293 -42
- imap_processing/ialirt/l0/process_hit.py +5 -3
- imap_processing/ialirt/l0/process_swapi.py +41 -25
- imap_processing/ialirt/process_ephemeris.py +70 -14
- imap_processing/ialirt/utils/create_xarray.py +1 -1
- imap_processing/idex/idex_l0.py +2 -2
- imap_processing/idex/idex_l1a.py +2 -3
- imap_processing/idex/idex_l1b.py +2 -3
- imap_processing/idex/idex_l2a.py +130 -4
- imap_processing/idex/idex_l2b.py +158 -143
- imap_processing/idex/idex_utils.py +1 -3
- 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/l0/lo_science.py +25 -24
- imap_processing/lo/l1b/lo_l1b.py +93 -19
- imap_processing/lo/l1c/lo_l1c.py +273 -93
- imap_processing/lo/l2/lo_l2.py +949 -135
- imap_processing/lo/lo_ancillary.py +55 -0
- imap_processing/mag/l1a/mag_l1a.py +1 -0
- imap_processing/mag/l1a/mag_l1a_data.py +26 -0
- imap_processing/mag/l1b/mag_l1b.py +3 -2
- imap_processing/mag/l1c/interpolation_methods.py +14 -15
- imap_processing/mag/l1c/mag_l1c.py +23 -6
- imap_processing/mag/l1d/mag_l1d.py +57 -14
- imap_processing/mag/l1d/mag_l1d_data.py +202 -32
- imap_processing/mag/l2/mag_l2.py +2 -0
- imap_processing/mag/l2/mag_l2_data.py +14 -5
- imap_processing/quality_flags.py +23 -1
- imap_processing/spice/geometry.py +89 -39
- imap_processing/spice/pointing_frame.py +4 -8
- imap_processing/spice/repoint.py +78 -2
- imap_processing/spice/spin.py +28 -8
- imap_processing/spice/time.py +12 -22
- imap_processing/swapi/l1/swapi_l1.py +10 -4
- imap_processing/swapi/l2/swapi_l2.py +15 -17
- imap_processing/swe/l1b/swe_l1b.py +1 -2
- imap_processing/ultra/constants.py +30 -24
- imap_processing/ultra/l0/ultra_utils.py +9 -11
- imap_processing/ultra/l1a/ultra_l1a.py +1 -2
- imap_processing/ultra/l1b/badtimes.py +35 -11
- imap_processing/ultra/l1b/de.py +95 -31
- imap_processing/ultra/l1b/extendedspin.py +31 -16
- imap_processing/ultra/l1b/goodtimes.py +112 -0
- imap_processing/ultra/l1b/lookup_utils.py +281 -28
- imap_processing/ultra/l1b/quality_flag_filters.py +10 -1
- imap_processing/ultra/l1b/ultra_l1b.py +7 -7
- imap_processing/ultra/l1b/ultra_l1b_culling.py +169 -7
- imap_processing/ultra/l1b/ultra_l1b_extended.py +311 -69
- imap_processing/ultra/l1c/helio_pset.py +139 -37
- imap_processing/ultra/l1c/l1c_lookup_utils.py +289 -0
- imap_processing/ultra/l1c/spacecraft_pset.py +140 -29
- imap_processing/ultra/l1c/ultra_l1c.py +33 -24
- imap_processing/ultra/l1c/ultra_l1c_culling.py +92 -0
- imap_processing/ultra/l1c/ultra_l1c_pset_bins.py +400 -292
- imap_processing/ultra/l2/ultra_l2.py +54 -11
- imap_processing/ultra/utils/ultra_l1_utils.py +37 -7
- imap_processing/utils.py +3 -4
- {imap_processing-0.18.0.dist-info → imap_processing-0.19.2.dist-info}/METADATA +2 -2
- {imap_processing-0.18.0.dist-info → imap_processing-0.19.2.dist-info}/RECORD +118 -109
- imap_processing/idex/idex_l2c.py +0 -84
- imap_processing/spice/kernels.py +0 -187
- imap_processing/ultra/l1b/cullingmask.py +0 -87
- imap_processing/ultra/l1c/histogram.py +0 -36
- {imap_processing-0.18.0.dist-info → imap_processing-0.19.2.dist-info}/LICENSE +0 -0
- {imap_processing-0.18.0.dist-info → imap_processing-0.19.2.dist-info}/WHEEL +0 -0
- {imap_processing-0.18.0.dist-info → imap_processing-0.19.2.dist-info}/entry_points.txt +0 -0
imap_processing/lo/l1c/lo_l1c.py
CHANGED
|
@@ -1,15 +1,30 @@
|
|
|
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
|
|
|
6
7
|
import numpy as np
|
|
7
|
-
import pandas as pd
|
|
8
8
|
import xarray as xr
|
|
9
9
|
from scipy.stats import binned_statistic_dd
|
|
10
10
|
|
|
11
11
|
from imap_processing.cdf.imap_cdf_manager import ImapCdfAttributes
|
|
12
|
-
from imap_processing.
|
|
12
|
+
from imap_processing.lo import lo_ancillary
|
|
13
|
+
from imap_processing.spice.repoint import get_pointing_times
|
|
14
|
+
from imap_processing.spice.spin import get_spin_number
|
|
15
|
+
from imap_processing.spice.time import met_to_ttj2000ns, ttj2000ns_to_met
|
|
16
|
+
|
|
17
|
+
N_ESA_ENERGY_STEPS = 7
|
|
18
|
+
N_SPIN_ANGLE_BINS = 3600
|
|
19
|
+
N_OFF_ANGLE_BINS = 40
|
|
20
|
+
# 1 time, 7 energy steps, 3600 spin angle bins, and 40 off angle bins
|
|
21
|
+
PSET_SHAPE = (1, N_ESA_ENERGY_STEPS, N_SPIN_ANGLE_BINS, N_OFF_ANGLE_BINS)
|
|
22
|
+
PSET_DIMS = ["epoch", "esa_energy_step", "spin_angle", "off_angle"]
|
|
23
|
+
ESA_ENERGY_STEPS = np.arange(N_ESA_ENERGY_STEPS) + 1 # 1 to 7 inclusive
|
|
24
|
+
SPIN_ANGLE_BIN_EDGES = np.linspace(0, 360, N_SPIN_ANGLE_BINS + 1)
|
|
25
|
+
SPIN_ANGLE_BIN_CENTERS = (SPIN_ANGLE_BIN_EDGES[:-1] + SPIN_ANGLE_BIN_EDGES[1:]) / 2
|
|
26
|
+
OFF_ANGLE_BIN_EDGES = np.linspace(-2, 2, N_OFF_ANGLE_BINS + 1)
|
|
27
|
+
OFF_ANGLE_BIN_CENTERS = (OFF_ANGLE_BIN_EDGES[:-1] + OFF_ANGLE_BIN_EDGES[1:]) / 2
|
|
13
28
|
|
|
14
29
|
|
|
15
30
|
class FilterType(str, Enum):
|
|
@@ -52,10 +67,63 @@ def lo_l1c(sci_dependencies: dict, anc_dependencies: list) -> list[xr.Dataset]:
|
|
|
52
67
|
if "imap_lo_l1b_de" in sci_dependencies:
|
|
53
68
|
logical_source = "imap_lo_l1c_pset"
|
|
54
69
|
l1b_de = sci_dependencies["imap_lo_l1b_de"]
|
|
55
|
-
|
|
56
70
|
l1b_goodtimes_only = filter_goodtimes(l1b_de, anc_dependencies)
|
|
57
|
-
|
|
58
|
-
|
|
71
|
+
|
|
72
|
+
# Set the pointing start and end times based on the first epoch
|
|
73
|
+
pointing_start_met, pointing_end_met = get_pointing_times(
|
|
74
|
+
ttj2000ns_to_met(l1b_goodtimes_only["epoch"][0].item())
|
|
75
|
+
)
|
|
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
|
+
|
|
101
|
+
pset["pointing_start_met"] = xr.DataArray(
|
|
102
|
+
np.array([pointing_start_met]),
|
|
103
|
+
dims="epoch",
|
|
104
|
+
attrs=attr_mgr.get_variable_attributes("pointing_start_met"),
|
|
105
|
+
)
|
|
106
|
+
pset["pointing_end_met"] = xr.DataArray(
|
|
107
|
+
np.array([pointing_end_met]),
|
|
108
|
+
dims="epoch",
|
|
109
|
+
attrs=attr_mgr.get_variable_attributes("pointing_end_met"),
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
# Get the start and end spin numbers based on the pointing start and end MET
|
|
113
|
+
pset["start_spin_number"] = xr.DataArray(
|
|
114
|
+
[get_spin_number(pset["pointing_start_met"].item())],
|
|
115
|
+
dims="epoch",
|
|
116
|
+
attrs=attr_mgr.get_variable_attributes("start_spin_number"),
|
|
117
|
+
)
|
|
118
|
+
pset["end_spin_number"] = xr.DataArray(
|
|
119
|
+
[get_spin_number(pset["pointing_end_met"].item())],
|
|
120
|
+
dims="epoch",
|
|
121
|
+
attrs=attr_mgr.get_variable_attributes("end_spin_number"),
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
full_counts = create_pset_counts(l1b_de, FilterType.NONE)
|
|
125
|
+
|
|
126
|
+
# Set the counts
|
|
59
127
|
pset["triples_counts"] = create_pset_counts(
|
|
60
128
|
l1b_goodtimes_only, FilterType.TRIPLES
|
|
61
129
|
)
|
|
@@ -64,63 +132,50 @@ def lo_l1c(sci_dependencies: dict, anc_dependencies: list) -> list[xr.Dataset]:
|
|
|
64
132
|
)
|
|
65
133
|
pset["h_counts"] = create_pset_counts(l1b_goodtimes_only, FilterType.HYDROGEN)
|
|
66
134
|
pset["o_counts"] = create_pset_counts(l1b_goodtimes_only, FilterType.OXYGEN)
|
|
135
|
+
|
|
136
|
+
# Set the exposure time
|
|
67
137
|
pset["exposure_time"] = calculate_exposure_times(
|
|
68
138
|
full_counts, l1b_goodtimes_only
|
|
69
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
|
+
|
|
70
166
|
pset.attrs = attr_mgr.get_global_attributes(logical_source)
|
|
71
|
-
# TODO: Temp fix before adding attribute variables.
|
|
72
|
-
# CDF won't open if DEPEND_0 is not deleted currently.
|
|
73
|
-
del pset["epoch"].attrs["DEPEND_0"]
|
|
74
167
|
|
|
75
168
|
pset = pset.assign_coords(
|
|
76
169
|
{
|
|
77
|
-
"
|
|
78
|
-
"
|
|
79
|
-
"
|
|
170
|
+
"esa_energy_step": ESA_ENERGY_STEPS,
|
|
171
|
+
"spin_angle": SPIN_ANGLE_BIN_CENTERS,
|
|
172
|
+
"off_angle": OFF_ANGLE_BIN_CENTERS,
|
|
80
173
|
}
|
|
81
174
|
)
|
|
82
175
|
|
|
83
176
|
return [pset]
|
|
84
177
|
|
|
85
178
|
|
|
86
|
-
def initialize_pset(
|
|
87
|
-
l1b_de: xr.Dataset, attr_mgr: ImapCdfAttributes, logical_source: str
|
|
88
|
-
) -> xr.Dataset:
|
|
89
|
-
"""
|
|
90
|
-
Initialize the PSET dataset and set the Epoch.
|
|
91
|
-
|
|
92
|
-
The Epoch time is set to the first of the L1B
|
|
93
|
-
Direct Event times. There is one Epoch per PSET file.
|
|
94
|
-
|
|
95
|
-
Parameters
|
|
96
|
-
----------
|
|
97
|
-
l1b_de : xarray.Dataset
|
|
98
|
-
L1B Direct Event dataset.
|
|
99
|
-
attr_mgr : ImapCdfAttributes
|
|
100
|
-
Attribute manager used to get the L1C attributes.
|
|
101
|
-
logical_source : str
|
|
102
|
-
The logical source of the pset.
|
|
103
|
-
|
|
104
|
-
Returns
|
|
105
|
-
-------
|
|
106
|
-
pset : xarray.Dataset
|
|
107
|
-
Initialized PSET dataset.
|
|
108
|
-
"""
|
|
109
|
-
pset = xr.Dataset(
|
|
110
|
-
attrs=attr_mgr.get_global_attributes(logical_source),
|
|
111
|
-
)
|
|
112
|
-
# TODO: Need to create utility to get start of repointing to use
|
|
113
|
-
# for the pset epoch time. Setting to first DE for now
|
|
114
|
-
pset_epoch = l1b_de["epoch"][0].item()
|
|
115
|
-
pset["epoch"] = xr.DataArray(
|
|
116
|
-
np.array([pset_epoch]),
|
|
117
|
-
dims=["epoch"],
|
|
118
|
-
attrs=attr_mgr.get_variable_attributes("epoch"),
|
|
119
|
-
)
|
|
120
|
-
|
|
121
|
-
return pset
|
|
122
|
-
|
|
123
|
-
|
|
124
179
|
def filter_goodtimes(l1b_de: xr.Dataset, anc_dependencies: list) -> xr.Dataset:
|
|
125
180
|
"""
|
|
126
181
|
Filter the L1B Direct Event dataset to only include good times.
|
|
@@ -141,17 +196,19 @@ def filter_goodtimes(l1b_de: xr.Dataset, anc_dependencies: list) -> xr.Dataset:
|
|
|
141
196
|
Filtered L1B Direct Event dataset.
|
|
142
197
|
"""
|
|
143
198
|
# the goodtimes are currently the only ancillary file needed for L1C processing
|
|
144
|
-
goodtimes_table_df =
|
|
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
|
+
)
|
|
145
202
|
|
|
146
203
|
# convert goodtimes from MET to TTJ2000
|
|
147
|
-
goodtimes_start = met_to_ttj2000ns(goodtimes_table_df["
|
|
204
|
+
goodtimes_start = met_to_ttj2000ns(goodtimes_table_df["GoodTime_start"])
|
|
148
205
|
goodtimes_end = met_to_ttj2000ns(goodtimes_table_df["GoodTime_end"])
|
|
149
206
|
|
|
150
207
|
# Create a mask for epochs within any of the start/end time ranges
|
|
151
208
|
goodtimes_mask = np.zeros_like(l1b_de["epoch"], dtype=bool)
|
|
152
209
|
|
|
153
210
|
# Iterate over the good times and create a mask
|
|
154
|
-
for start, end in zip(goodtimes_start, goodtimes_end):
|
|
211
|
+
for start, end in zip(goodtimes_start, goodtimes_end, strict=False):
|
|
155
212
|
goodtimes_mask |= (l1b_de["epoch"] >= start) & (l1b_de["epoch"] < end)
|
|
156
213
|
|
|
157
214
|
# Filter the dataset using the mask
|
|
@@ -206,9 +263,9 @@ def create_pset_counts(
|
|
|
206
263
|
"001000",
|
|
207
264
|
],
|
|
208
265
|
# hydrogen species identifier
|
|
209
|
-
FilterType.HYDROGEN: "
|
|
266
|
+
FilterType.HYDROGEN: "H",
|
|
210
267
|
# oxygen species identifier
|
|
211
|
-
FilterType.OXYGEN: "
|
|
268
|
+
FilterType.OXYGEN: "O",
|
|
212
269
|
}
|
|
213
270
|
|
|
214
271
|
# if the filter string is triples or doubles, filter using the coincidence type
|
|
@@ -249,7 +306,7 @@ def create_pset_counts(
|
|
|
249
306
|
|
|
250
307
|
counts = xr.DataArray(
|
|
251
308
|
data=hist.astype(np.int16),
|
|
252
|
-
dims=
|
|
309
|
+
dims=PSET_DIMS,
|
|
253
310
|
)
|
|
254
311
|
|
|
255
312
|
return counts
|
|
@@ -275,11 +332,6 @@ def calculate_exposure_times(counts: xr.DataArray, l1b_de: xr.Dataset) -> xr.Dat
|
|
|
275
332
|
exposure_time : xarray.DataArray
|
|
276
333
|
The exposure times for the L1B Direct Event dataset.
|
|
277
334
|
"""
|
|
278
|
-
# Create bin edges
|
|
279
|
-
lon_edges = np.arange(3601)
|
|
280
|
-
lat_edges = np.arange(41)
|
|
281
|
-
energy_edges = np.arange(8)
|
|
282
|
-
|
|
283
335
|
data = np.column_stack(
|
|
284
336
|
(l1b_de["esa_step"], l1b_de["pointing_bin_lon"], l1b_de["pointing_bin_lat"])
|
|
285
337
|
)
|
|
@@ -289,14 +341,19 @@ def calculate_exposure_times(counts: xr.DataArray, l1b_de: xr.Dataset) -> xr.Dat
|
|
|
289
341
|
# exposure time equation from Lo Alg Document 10.1.1.4
|
|
290
342
|
4 * l1b_de["avg_spin_durations"].to_numpy() / 3600,
|
|
291
343
|
statistic="mean",
|
|
292
|
-
|
|
344
|
+
# NOTE: The l1b pointing_bin_lon is bin number, not actual angle
|
|
345
|
+
bins=[
|
|
346
|
+
np.arange(N_ESA_ENERGY_STEPS + 1),
|
|
347
|
+
np.arange(N_SPIN_ANGLE_BINS + 1),
|
|
348
|
+
np.arange(N_OFF_ANGLE_BINS + 1),
|
|
349
|
+
],
|
|
293
350
|
)
|
|
294
351
|
|
|
295
352
|
stat = result.statistic[np.newaxis, :, :, :]
|
|
296
353
|
|
|
297
354
|
exposure_time = xr.DataArray(
|
|
298
355
|
data=stat.astype(np.float16),
|
|
299
|
-
dims=
|
|
356
|
+
dims=PSET_DIMS,
|
|
300
357
|
)
|
|
301
358
|
|
|
302
359
|
return exposure_time
|
|
@@ -328,8 +385,6 @@ def create_datasets(
|
|
|
328
385
|
# can be used direction
|
|
329
386
|
epoch_converted_time = [1]
|
|
330
387
|
|
|
331
|
-
# Create a data array for the epoch time
|
|
332
|
-
# TODO: might need to update the attrs to use new YAML file
|
|
333
388
|
epoch_time = xr.DataArray(
|
|
334
389
|
data=epoch_converted_time,
|
|
335
390
|
name="epoch",
|
|
@@ -338,38 +393,54 @@ def create_datasets(
|
|
|
338
393
|
)
|
|
339
394
|
|
|
340
395
|
if logical_source == "imap_lo_l1c_pset":
|
|
341
|
-
|
|
342
|
-
data=
|
|
343
|
-
name="
|
|
344
|
-
dims=["
|
|
345
|
-
attrs=attr_mgr.get_variable_attributes("
|
|
346
|
-
)
|
|
347
|
-
pointing_bins = xr.DataArray(
|
|
348
|
-
data=np.arange(3600),
|
|
349
|
-
name="pointing_bins",
|
|
350
|
-
dims=["pointing_bins"],
|
|
351
|
-
attrs=attr_mgr.get_variable_attributes("pointing_bins"),
|
|
396
|
+
esa_energy_step = xr.DataArray(
|
|
397
|
+
data=ESA_ENERGY_STEPS,
|
|
398
|
+
name="esa_energy_step",
|
|
399
|
+
dims=["esa_energy_step"],
|
|
400
|
+
attrs=attr_mgr.get_variable_attributes("esa_energy_step"),
|
|
352
401
|
)
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
esa_step.values.astype(str),
|
|
402
|
+
esa_energy_step_label = xr.DataArray(
|
|
403
|
+
esa_energy_step.values.astype(str),
|
|
356
404
|
name="esa_step_label",
|
|
357
405
|
dims=["esa_step_label"],
|
|
358
406
|
attrs=attr_mgr.get_variable_attributes("esa_step_label"),
|
|
359
407
|
)
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
408
|
+
|
|
409
|
+
spin_angle = xr.DataArray(
|
|
410
|
+
data=SPIN_ANGLE_BIN_CENTERS,
|
|
411
|
+
name="spin_angle",
|
|
412
|
+
dims=["spin_angle"],
|
|
413
|
+
attrs=attr_mgr.get_variable_attributes("spin_angle"),
|
|
414
|
+
)
|
|
415
|
+
spin_angle_label = xr.DataArray(
|
|
416
|
+
spin_angle.values.astype(str),
|
|
417
|
+
name="spin_angle_label",
|
|
418
|
+
dims=["spin_angle_label"],
|
|
419
|
+
attrs=attr_mgr.get_variable_attributes("spin_angle_label"),
|
|
420
|
+
)
|
|
421
|
+
|
|
422
|
+
off_angle = xr.DataArray(
|
|
423
|
+
data=OFF_ANGLE_BIN_CENTERS,
|
|
424
|
+
name="off_angle",
|
|
425
|
+
dims=["off_angle"],
|
|
426
|
+
attrs=attr_mgr.get_variable_attributes("off_angle"),
|
|
427
|
+
)
|
|
428
|
+
off_angle_label = xr.DataArray(
|
|
429
|
+
off_angle.values.astype(str),
|
|
430
|
+
name="off_angle_label",
|
|
431
|
+
dims=["off_angle_label"],
|
|
432
|
+
attrs=attr_mgr.get_variable_attributes("off_angle_label"),
|
|
365
433
|
)
|
|
434
|
+
|
|
366
435
|
dataset = xr.Dataset(
|
|
367
436
|
coords={
|
|
368
437
|
"epoch": epoch_time,
|
|
369
|
-
"
|
|
370
|
-
"
|
|
371
|
-
"
|
|
372
|
-
"
|
|
438
|
+
"esa_energy_step": esa_energy_step,
|
|
439
|
+
"esa_energy_step_label": esa_energy_step_label,
|
|
440
|
+
"spin_angle": spin_angle,
|
|
441
|
+
"spin_angle_label": spin_angle_label,
|
|
442
|
+
"off_angle": off_angle,
|
|
443
|
+
"off_angle_label": off_angle_label,
|
|
373
444
|
},
|
|
374
445
|
attrs=attr_mgr.get_global_attributes(logical_source),
|
|
375
446
|
)
|
|
@@ -389,32 +460,141 @@ def create_datasets(
|
|
|
389
460
|
|
|
390
461
|
# Create a data array for the current field and add it to the dataset
|
|
391
462
|
# TODO: TEMPORARY. need to update to use l1b data once that's available.
|
|
392
|
-
if field in [
|
|
463
|
+
if field in [
|
|
464
|
+
"pointing_start_met",
|
|
465
|
+
"pointing_end_met",
|
|
466
|
+
"esa_mode",
|
|
467
|
+
"pivot_angle",
|
|
468
|
+
]:
|
|
393
469
|
dataset[field] = xr.DataArray(
|
|
394
470
|
data=[1],
|
|
395
471
|
dims=dims,
|
|
396
472
|
attrs=attr_mgr.get_variable_attributes(field),
|
|
397
473
|
)
|
|
398
474
|
# TODO: This is temporary.
|
|
399
|
-
# The data type will be set in the data class when that's created
|
|
400
475
|
elif field == "exposure_time":
|
|
401
476
|
dataset[field] = xr.DataArray(
|
|
402
|
-
data=np.ones((1, 7), dtype=np.float16),
|
|
477
|
+
data=np.ones((1, 7, 3600, 40), dtype=np.float16),
|
|
403
478
|
dims=dims,
|
|
404
479
|
attrs=attr_mgr.get_variable_attributes(field),
|
|
405
480
|
)
|
|
406
481
|
|
|
407
|
-
elif "
|
|
482
|
+
elif "rates" in field:
|
|
408
483
|
dataset[field] = xr.DataArray(
|
|
409
|
-
data=np.ones(
|
|
484
|
+
data=np.ones(PSET_SHAPE, dtype=np.float16),
|
|
410
485
|
dims=dims,
|
|
411
486
|
attrs=attr_mgr.get_variable_attributes(field),
|
|
412
487
|
)
|
|
413
488
|
else:
|
|
414
489
|
dataset[field] = xr.DataArray(
|
|
415
|
-
data=np.ones(
|
|
490
|
+
data=np.ones(PSET_SHAPE, dtype=np.int16),
|
|
416
491
|
dims=dims,
|
|
417
492
|
attrs=attr_mgr.get_variable_attributes(field),
|
|
418
493
|
)
|
|
419
494
|
|
|
420
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
|