imap-processing 0.19.0__py3-none-any.whl → 0.19.3__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 +55 -0
- imap_processing/cdf/config/imap_enamaps_l2-healpix_variable_attrs.yaml +29 -0
- imap_processing/cdf/config/imap_enamaps_l2-rectangular_variable_attrs.yaml +32 -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 +28 -16
- 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 -1
- imap_processing/ialirt/l0/parse_mag.py +18 -4
- imap_processing/ialirt/l0/process_hit.py +9 -4
- imap_processing/ialirt/l0/process_swapi.py +9 -4
- imap_processing/ialirt/l0/process_swe.py +9 -4
- 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 +13 -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/l0/decom_tools.py +58 -46
- imap_processing/ultra/l0/decom_ultra.py +21 -9
- imap_processing/ultra/l0/ultra_utils.py +4 -4
- 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 +75 -18
- imap_processing/ultra/utils/ultra_l1_utils.py +10 -5
- {imap_processing-0.19.0.dist-info → imap_processing-0.19.3.dist-info}/METADATA +2 -2
- {imap_processing-0.19.0.dist-info → imap_processing-0.19.3.dist-info}/RECORD +71 -69
- 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.3.dist-info}/LICENSE +0 -0
- {imap_processing-0.19.0.dist-info → imap_processing-0.19.3.dist-info}/WHEEL +0 -0
- {imap_processing-0.19.0.dist-info → imap_processing-0.19.3.dist-info}/entry_points.txt +0 -0
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
|