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
|
@@ -21,7 +21,7 @@ def mask_below_fwhm_scattering_threshold(
|
|
|
21
21
|
phi_coeffs: np.ndarray,
|
|
22
22
|
energy: np.ndarray,
|
|
23
23
|
scattering_thresholds: np.ndarray,
|
|
24
|
-
) ->
|
|
24
|
+
) -> tuple[NDArray, NDArray, NDArray]:
|
|
25
25
|
"""
|
|
26
26
|
Determine indices of theta and phi values below the FWHM scattering threshold.
|
|
27
27
|
|
|
@@ -43,8 +43,12 @@ def mask_below_fwhm_scattering_threshold(
|
|
|
43
43
|
|
|
44
44
|
Returns
|
|
45
45
|
-------
|
|
46
|
-
numpy.ndarray
|
|
46
|
+
scattering_mask : numpy.ndarray
|
|
47
47
|
Boolean array indicating indices below the scattering threshold.
|
|
48
|
+
fwhm_theta : numpy.ndarray
|
|
49
|
+
Calculated FWHM values for theta.
|
|
50
|
+
fwhm_phi : numpy.ndarray
|
|
51
|
+
Calculated FWHM values for phi.
|
|
48
52
|
"""
|
|
49
53
|
# Calculate FWHM for all pixels and all energies
|
|
50
54
|
fwhm_theta = theta_coeffs[..., 0:1] * (
|
|
@@ -58,18 +62,21 @@ def mask_below_fwhm_scattering_threshold(
|
|
|
58
62
|
|
|
59
63
|
# Combine conditions for both theta and phi.
|
|
60
64
|
# shape = (npix, energy.shape[1])
|
|
61
|
-
|
|
65
|
+
scattering_mask = np.logical_and(fwhm_theta <= thresholds, fwhm_phi <= thresholds)
|
|
66
|
+
return scattering_mask, fwhm_theta, fwhm_phi
|
|
62
67
|
|
|
63
68
|
|
|
64
|
-
def
|
|
69
|
+
def calculate_fwhm_spun_scattering(
|
|
65
70
|
for_indices_by_spin_phase: np.ndarray,
|
|
66
71
|
theta_vals: np.ndarray,
|
|
67
72
|
phi_vals: np.ndarray,
|
|
68
73
|
ancillary_files: dict,
|
|
69
74
|
instrument_id: int,
|
|
70
|
-
) -> list:
|
|
75
|
+
) -> tuple[list, NDArray, NDArray, NDArray]:
|
|
71
76
|
"""
|
|
72
|
-
Calculate
|
|
77
|
+
Calculate FWHM scattering values for each pixel, energy bin, and spin phase step.
|
|
78
|
+
|
|
79
|
+
This function also calculates a mask for pixels that are below the FWHM threshold.
|
|
73
80
|
|
|
74
81
|
Parameters
|
|
75
82
|
----------
|
|
@@ -93,6 +100,14 @@ def calculate_pixels_within_scattering_threshold(
|
|
|
93
100
|
The outer list indicates spin phase steps, the middle list indicates energy
|
|
94
101
|
bins, and the inner arrays contain indices indicating pixels that are below
|
|
95
102
|
the FWHM scattering threshold.
|
|
103
|
+
scattering_fwhm_theta : NDArray
|
|
104
|
+
Calculated FWHM scatting values for theta at each energy bin and averaged
|
|
105
|
+
over spin phase.
|
|
106
|
+
scattering_fwhm_phi : NDArray
|
|
107
|
+
Calculated FWHM scatting values for theta at each energy bin and averaged
|
|
108
|
+
over spin phase.
|
|
109
|
+
scattering_thresholds_for_energy_mean : NDArray
|
|
110
|
+
Scattering thresholds corresponding to each energy bin.
|
|
96
111
|
"""
|
|
97
112
|
# Load scattering coefficient lookup table
|
|
98
113
|
scattering_luts = load_scattering_lookup_tables(ancillary_files, instrument_id)
|
|
@@ -103,6 +118,13 @@ def calculate_pixels_within_scattering_threshold(
|
|
|
103
118
|
scattering_thresholds_for_energy_mean = get_scattering_thresholds_for_energy(
|
|
104
119
|
energy_bin_geometric_means, ancillary_files
|
|
105
120
|
)
|
|
121
|
+
# Initialize arrays to accumulate FWHM values for averaging
|
|
122
|
+
fwhm_theta_sum = np.zeros(
|
|
123
|
+
(len(energy_bin_geometric_means), for_indices_by_spin_phase.shape[0])
|
|
124
|
+
)
|
|
125
|
+
fwhm_phi_sum = np.zeros_like(fwhm_theta_sum)
|
|
126
|
+
sample_count = np.zeros_like(fwhm_theta_sum)
|
|
127
|
+
|
|
106
128
|
steps = for_indices_by_spin_phase.shape[1]
|
|
107
129
|
energies = energy_bin_geometric_means[np.newaxis, :]
|
|
108
130
|
# The "for_indices_by_spin_phase" lookup table contains the boolean values of each
|
|
@@ -132,7 +154,7 @@ def calculate_pixels_within_scattering_threshold(
|
|
|
132
154
|
theta, phi, lookup_tables=scattering_luts
|
|
133
155
|
)
|
|
134
156
|
# Get a mask for pixels below the FWHM scattering threshold
|
|
135
|
-
scattering_mask = mask_below_fwhm_scattering_threshold(
|
|
157
|
+
scattering_mask, fwhm_theta, fwhm_phi = mask_below_fwhm_scattering_threshold(
|
|
136
158
|
theta_coeffs,
|
|
137
159
|
phi_coeffs,
|
|
138
160
|
energies,
|
|
@@ -147,8 +169,19 @@ def calculate_pixels_within_scattering_threshold(
|
|
|
147
169
|
pixels_below_scattering_for_energy.append(for_pixel_indices[valid_pixels])
|
|
148
170
|
|
|
149
171
|
pixels_below_scattering.append(pixels_below_scattering_for_energy)
|
|
172
|
+
# Accumulate FWHM values for averaging
|
|
173
|
+
fwhm_theta_sum[:, for_inds] += fwhm_theta.T
|
|
174
|
+
fwhm_phi_sum[:, for_inds] += fwhm_phi.T
|
|
175
|
+
sample_count[:, for_inds] += 1
|
|
150
176
|
|
|
151
|
-
|
|
177
|
+
fwhm_phi_avg = np.divide(fwhm_theta_sum, sample_count, where=sample_count != 0)
|
|
178
|
+
fwhm_theta_avg = np.divide(fwhm_theta_sum, sample_count, where=sample_count != 0)
|
|
179
|
+
return (
|
|
180
|
+
pixels_below_scattering,
|
|
181
|
+
fwhm_theta_avg,
|
|
182
|
+
fwhm_phi_avg,
|
|
183
|
+
scattering_thresholds_for_energy_mean,
|
|
184
|
+
)
|
|
152
185
|
|
|
153
186
|
|
|
154
187
|
def get_spacecraft_pointing_lookup_tables(
|
|
@@ -184,10 +217,10 @@ def get_spacecraft_pointing_lookup_tables(
|
|
|
184
217
|
A 2D array of boundary scale factors for each HEALPix pixel at each spin phase
|
|
185
218
|
step.
|
|
186
219
|
"""
|
|
187
|
-
theta_descriptor = f"l1c-{instrument_id}sensor-sc-pointing-theta
|
|
188
|
-
phi_descriptor = f"l1c-{instrument_id}sensor-sc-pointing-phi
|
|
189
|
-
index_descriptor = f"l1c-{instrument_id}sensor-sc-pointing-index
|
|
190
|
-
bsf_descriptor = f"l1c-{instrument_id}sensor-sc-pointing-bsf
|
|
220
|
+
theta_descriptor = f"l1c-{instrument_id}sensor-sc-pointing-theta"
|
|
221
|
+
phi_descriptor = f"l1c-{instrument_id}sensor-sc-pointing-phi"
|
|
222
|
+
index_descriptor = f"l1c-{instrument_id}sensor-sc-pointing-index"
|
|
223
|
+
bsf_descriptor = f"l1c-{instrument_id}sensor-sc-pointing-bsf"
|
|
191
224
|
|
|
192
225
|
theta_vals = pd.read_csv(
|
|
193
226
|
ancillary_files[theta_descriptor], header=None, skiprows=1
|
|
@@ -2,19 +2,27 @@
|
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
4
|
|
|
5
|
+
import astropy_healpix.healpy as hp
|
|
5
6
|
import numpy as np
|
|
6
|
-
import pandas as pd
|
|
7
7
|
import xarray as xr
|
|
8
8
|
|
|
9
9
|
from imap_processing.cdf.utils import parse_filename_like
|
|
10
|
+
from imap_processing.quality_flags import ImapPSETUltraFlags
|
|
11
|
+
from imap_processing.spice.repoint import get_pointing_times
|
|
12
|
+
from imap_processing.spice.time import (
|
|
13
|
+
et_to_met,
|
|
14
|
+
met_to_ttj2000ns,
|
|
15
|
+
)
|
|
10
16
|
from imap_processing.ultra.l1b.ultra_l1b_culling import get_de_rejection_mask
|
|
11
17
|
from imap_processing.ultra.l1c.l1c_lookup_utils import (
|
|
12
|
-
|
|
18
|
+
calculate_fwhm_spun_scattering,
|
|
13
19
|
get_spacecraft_pointing_lookup_tables,
|
|
14
20
|
)
|
|
21
|
+
from imap_processing.ultra.l1c.ultra_l1c_culling import compute_culling_mask
|
|
15
22
|
from imap_processing.ultra.l1c.ultra_l1c_pset_bins import (
|
|
16
23
|
build_energy_bins,
|
|
17
24
|
get_efficiencies_and_geometric_function,
|
|
25
|
+
get_energy_delta_minus_plus,
|
|
18
26
|
get_spacecraft_background_rates,
|
|
19
27
|
get_spacecraft_exposure_times,
|
|
20
28
|
get_spacecraft_histogram,
|
|
@@ -26,14 +34,13 @@ logger = logging.getLogger(__name__)
|
|
|
26
34
|
|
|
27
35
|
def calculate_spacecraft_pset(
|
|
28
36
|
de_dataset: xr.Dataset,
|
|
29
|
-
|
|
30
|
-
cullingmask_dataset: xr.Dataset,
|
|
37
|
+
goodtimes_dataset: xr.Dataset,
|
|
31
38
|
rates_dataset: xr.Dataset,
|
|
32
39
|
params_dataset: xr.Dataset,
|
|
33
40
|
name: str,
|
|
34
41
|
ancillary_files: dict,
|
|
35
42
|
instrument_id: int,
|
|
36
|
-
species_id:
|
|
43
|
+
species_id: list,
|
|
37
44
|
) -> xr.Dataset:
|
|
38
45
|
"""
|
|
39
46
|
Create dictionary with defined datatype for Pointing Set Grid Data.
|
|
@@ -42,10 +49,8 @@ def calculate_spacecraft_pset(
|
|
|
42
49
|
----------
|
|
43
50
|
de_dataset : xarray.Dataset
|
|
44
51
|
Dataset containing de data.
|
|
45
|
-
|
|
46
|
-
Dataset containing
|
|
47
|
-
cullingmask_dataset : xarray.Dataset
|
|
48
|
-
Dataset containing cullingmask data.
|
|
52
|
+
goodtimes_dataset : xarray.Dataset
|
|
53
|
+
Dataset containing goodtimes data.
|
|
49
54
|
rates_dataset : xarray.Dataset
|
|
50
55
|
Dataset containing image rates data.
|
|
51
56
|
params_dataset : xarray.Dataset
|
|
@@ -56,8 +61,8 @@ def calculate_spacecraft_pset(
|
|
|
56
61
|
Ancillary files.
|
|
57
62
|
instrument_id : int
|
|
58
63
|
Instrument ID, either 45 or 90.
|
|
59
|
-
species_id :
|
|
60
|
-
Species ID
|
|
64
|
+
species_id : List
|
|
65
|
+
Species ID.
|
|
61
66
|
|
|
62
67
|
Returns
|
|
63
68
|
-------
|
|
@@ -65,11 +70,15 @@ def calculate_spacecraft_pset(
|
|
|
65
70
|
Dataset containing the data.
|
|
66
71
|
"""
|
|
67
72
|
pset_dict: dict[str, np.ndarray] = {}
|
|
73
|
+
|
|
68
74
|
sensor = parse_filename_like(name)["sensor"][0:2]
|
|
69
|
-
|
|
70
|
-
indices = np.where(de_dataset["species"].values == species_id)[0]
|
|
75
|
+
indices = np.where(np.isin(de_dataset["e_bin"].values, species_id))[0]
|
|
71
76
|
species_dataset = de_dataset.isel(epoch=indices)
|
|
72
77
|
|
|
78
|
+
# If there are no species return None.
|
|
79
|
+
if indices.size == 0:
|
|
80
|
+
return None
|
|
81
|
+
|
|
73
82
|
# Before we use the de_dataset to calculate the pointing set grid we need to filter.
|
|
74
83
|
rejected = get_de_rejection_mask(
|
|
75
84
|
species_dataset["quality_scattering"].values,
|
|
@@ -85,13 +94,6 @@ def calculate_spacecraft_pset(
|
|
|
85
94
|
)
|
|
86
95
|
|
|
87
96
|
intervals, _, energy_bin_geometric_means = build_energy_bins()
|
|
88
|
-
counts, latitude, longitude, n_pix = get_spacecraft_histogram(
|
|
89
|
-
vhat_dps_spacecraft,
|
|
90
|
-
species_dataset["energy_spacecraft"].values,
|
|
91
|
-
intervals,
|
|
92
|
-
nside=128,
|
|
93
|
-
)
|
|
94
|
-
healpix = np.arange(n_pix)
|
|
95
97
|
|
|
96
98
|
# Get lookup table for FOR indices by spin phase step
|
|
97
99
|
(
|
|
@@ -101,16 +103,28 @@ def calculate_spacecraft_pset(
|
|
|
101
103
|
ra_and_dec,
|
|
102
104
|
boundary_scale_factors,
|
|
103
105
|
) = get_spacecraft_pointing_lookup_tables(ancillary_files, instrument_id)
|
|
104
|
-
# Check that the number of rows in the lookup table matches the number of pixels
|
|
105
|
-
if for_indices_by_spin_phase.shape[0] != n_pix:
|
|
106
|
-
logger.warning(
|
|
107
|
-
"The lookup table is expected to have the same number of rows as "
|
|
108
|
-
"the number of HEALPix pixels."
|
|
109
|
-
)
|
|
110
106
|
|
|
111
|
-
|
|
112
|
-
|
|
107
|
+
logger.info("calculating spun FWHM scattering values.")
|
|
108
|
+
pixels_below_scattering, scattering_theta, scattering_phi, scattering_thresholds = (
|
|
109
|
+
calculate_fwhm_spun_scattering(
|
|
110
|
+
for_indices_by_spin_phase,
|
|
111
|
+
theta_vals,
|
|
112
|
+
phi_vals,
|
|
113
|
+
ancillary_files,
|
|
114
|
+
instrument_id,
|
|
115
|
+
)
|
|
113
116
|
)
|
|
117
|
+
# Determine nside from the lookup table
|
|
118
|
+
nside = hp.npix2nside(len(for_indices_by_spin_phase))
|
|
119
|
+
counts, latitude, longitude, n_pix = get_spacecraft_histogram(
|
|
120
|
+
vhat_dps_spacecraft,
|
|
121
|
+
species_dataset["energy_spacecraft"].values,
|
|
122
|
+
intervals,
|
|
123
|
+
nside=nside,
|
|
124
|
+
)
|
|
125
|
+
healpix = np.arange(n_pix)
|
|
126
|
+
|
|
127
|
+
logger.info("Calculating spun efficiencies and geometric function.")
|
|
114
128
|
# calculate efficiency and geometric function as a function of energy
|
|
115
129
|
efficiencies, geometric_function = get_efficiencies_and_geometric_function(
|
|
116
130
|
pixels_below_scattering,
|
|
@@ -122,29 +136,49 @@ def calculate_spacecraft_pset(
|
|
|
122
136
|
)
|
|
123
137
|
sensitivity = efficiencies * geometric_function
|
|
124
138
|
|
|
125
|
-
# Calculate exposure
|
|
126
|
-
|
|
127
|
-
df_exposure = pd.read_csv(constant_exposure)
|
|
128
|
-
|
|
139
|
+
# Calculate exposure times
|
|
140
|
+
logger.info("Calculating spacecraft exposure times with deadtime correction.")
|
|
129
141
|
exposure_pointing, deadtime_ratios = get_spacecraft_exposure_times(
|
|
130
|
-
df_exposure,
|
|
131
142
|
rates_dataset,
|
|
132
143
|
params_dataset,
|
|
133
144
|
pixels_below_scattering,
|
|
134
145
|
boundary_scale_factors,
|
|
146
|
+
n_pix=n_pix,
|
|
135
147
|
)
|
|
136
|
-
|
|
148
|
+
logger.info("Calculating background rates.")
|
|
137
149
|
# Calculate background rates
|
|
138
150
|
background_rates = get_spacecraft_background_rates(
|
|
139
151
|
rates_dataset,
|
|
140
152
|
sensor,
|
|
141
153
|
ancillary_files,
|
|
142
154
|
intervals,
|
|
143
|
-
|
|
155
|
+
goodtimes_dataset["spin_number"].values,
|
|
156
|
+
nside=nside,
|
|
157
|
+
)
|
|
158
|
+
spacecraft_pset_quality_flags = np.full(
|
|
159
|
+
n_pix, ImapPSETUltraFlags.NONE.value, dtype=np.uint16
|
|
144
160
|
)
|
|
145
161
|
|
|
146
|
-
|
|
147
|
-
|
|
162
|
+
start: float = np.min(species_dataset["event_times"].values)
|
|
163
|
+
end: float = np.max(species_dataset["event_times"].values)
|
|
164
|
+
|
|
165
|
+
# Time bins in 30 minute intervals
|
|
166
|
+
time_bins = np.arange(start, end + 1800, 1800)
|
|
167
|
+
|
|
168
|
+
# Compute mask for culling the Earth
|
|
169
|
+
compute_culling_mask(
|
|
170
|
+
time_bins,
|
|
171
|
+
6378.1, # Earth radius
|
|
172
|
+
spacecraft_pset_quality_flags,
|
|
173
|
+
nside=nside,
|
|
174
|
+
)
|
|
175
|
+
# Get pointing start and stop times and convert to ttj2000ns
|
|
176
|
+
pointing_start, pointing_stop = get_pointing_times(
|
|
177
|
+
float(et_to_met(species_dataset["event_times"].data[0]))
|
|
178
|
+
)
|
|
179
|
+
pointing_start = met_to_ttj2000ns(pointing_start)
|
|
180
|
+
# Epoch should be the start of the pointing
|
|
181
|
+
pset_dict["epoch"] = np.atleast_1d(pointing_start).astype(np.int64)
|
|
148
182
|
pset_dict["counts"] = counts[np.newaxis, ...]
|
|
149
183
|
pset_dict["latitude"] = latitude[np.newaxis, ...]
|
|
150
184
|
pset_dict["longitude"] = longitude[np.newaxis, ...]
|
|
@@ -155,6 +189,7 @@ def calculate_spacecraft_pset(
|
|
|
155
189
|
pset_dict["energy_bin_delta"] = np.diff(intervals, axis=1).squeeze()[
|
|
156
190
|
np.newaxis, ...
|
|
157
191
|
]
|
|
192
|
+
pset_dict["quality_flags"] = spacecraft_pset_quality_flags[np.newaxis, ...]
|
|
158
193
|
|
|
159
194
|
pset_dict["sensitivity"] = sensitivity
|
|
160
195
|
pset_dict["efficiency"] = efficiencies
|
|
@@ -162,6 +197,15 @@ def calculate_spacecraft_pset(
|
|
|
162
197
|
pset_dict["dead_time_ratio"] = deadtime_ratios
|
|
163
198
|
pset_dict["spin_phase_step"] = np.arange(len(deadtime_ratios))
|
|
164
199
|
|
|
200
|
+
pset_dict["scatter_theta"] = scattering_theta
|
|
201
|
+
pset_dict["scatter_phi"] = scattering_phi
|
|
202
|
+
pset_dict["scatter_threshold"] = scattering_thresholds
|
|
203
|
+
|
|
204
|
+
# Add the energy delta plus/minus to the dataset
|
|
205
|
+
energy_delta_minus, energy_delta_plus = get_energy_delta_minus_plus()
|
|
206
|
+
pset_dict["energy_delta_minus"] = energy_delta_minus
|
|
207
|
+
pset_dict["energy_delta_plus"] = energy_delta_plus
|
|
208
|
+
|
|
165
209
|
dataset = create_dataset(pset_dict, name, "l1c")
|
|
166
210
|
|
|
167
211
|
return dataset
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
import xarray as xr
|
|
4
4
|
|
|
5
|
+
from imap_processing.ultra.constants import UltraConstants
|
|
5
6
|
from imap_processing.ultra.l1c.helio_pset import calculate_helio_pset
|
|
6
|
-
from imap_processing.ultra.l1c.histogram import calculate_histogram
|
|
7
7
|
from imap_processing.ultra.l1c.spacecraft_pset import calculate_spacecraft_pset
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
def ultra_l1c(
|
|
11
|
-
data_dict: dict, ancillary_files: dict,
|
|
11
|
+
data_dict: dict, ancillary_files: dict, imap_frames: bool
|
|
12
12
|
) -> list[xr.Dataset]:
|
|
13
13
|
"""
|
|
14
14
|
Will process ULTRA L1A and L1B data into L1C CDF files at output_filepath.
|
|
@@ -19,8 +19,8 @@ def ultra_l1c(
|
|
|
19
19
|
The data itself and its dependent data.
|
|
20
20
|
ancillary_files : dict
|
|
21
21
|
Ancillary files.
|
|
22
|
-
|
|
23
|
-
Whether to use
|
|
22
|
+
imap_frames : bool
|
|
23
|
+
Whether to use IMAP frames.
|
|
24
24
|
|
|
25
25
|
Returns
|
|
26
26
|
-------
|
|
@@ -32,47 +32,52 @@ def ultra_l1c(
|
|
|
32
32
|
# Account for possibility of having 45 and 90 in dictionary.
|
|
33
33
|
for instrument_id in [45, 90]:
|
|
34
34
|
if (
|
|
35
|
-
f"
|
|
36
|
-
and f"imap_ultra_l1b_{instrument_id}sensor-cullingmask" in data_dict
|
|
37
|
-
):
|
|
38
|
-
histogram_dataset = calculate_histogram(
|
|
39
|
-
data_dict[f"imap_ultra_l1a_{instrument_id}sensor-histogram"],
|
|
40
|
-
f"imap_ultra_l1c_{instrument_id}sensor-histogram",
|
|
41
|
-
)
|
|
42
|
-
output_datasets = [histogram_dataset]
|
|
43
|
-
elif (
|
|
44
|
-
f"imap_ultra_l1b_{instrument_id}sensor-cullingmask" in data_dict
|
|
35
|
+
f"imap_ultra_l1b_{instrument_id}sensor-goodtimes" in data_dict
|
|
45
36
|
and f"imap_ultra_l1b_{instrument_id}sensor-de" in data_dict
|
|
46
|
-
and f"
|
|
47
|
-
and
|
|
37
|
+
and f"imap_ultra_l1a_{instrument_id}sensor-rates" in data_dict
|
|
38
|
+
and f"imap_ultra_l1a_{instrument_id}sensor-params" in data_dict
|
|
39
|
+
and imap_frames
|
|
48
40
|
):
|
|
49
41
|
helio_pset = calculate_helio_pset(
|
|
50
42
|
data_dict[f"imap_ultra_l1b_{instrument_id}sensor-de"],
|
|
51
|
-
data_dict[f"imap_ultra_l1b_{instrument_id}sensor-
|
|
52
|
-
data_dict[f"imap_ultra_l1b_{instrument_id}sensor-cullingmask"],
|
|
43
|
+
data_dict[f"imap_ultra_l1b_{instrument_id}sensor-goodtimes"],
|
|
53
44
|
data_dict[f"imap_ultra_l1a_{instrument_id}sensor-rates"],
|
|
54
45
|
data_dict[f"imap_ultra_l1a_{instrument_id}sensor-params"],
|
|
55
46
|
f"imap_ultra_l1c_{instrument_id}sensor-heliopset",
|
|
56
47
|
ancillary_files,
|
|
57
48
|
instrument_id,
|
|
49
|
+
UltraConstants.TOFXPH_SPECIES_GROUPS["proton"],
|
|
58
50
|
)
|
|
59
51
|
output_datasets = [helio_pset]
|
|
60
52
|
elif (
|
|
61
|
-
f"imap_ultra_l1b_{instrument_id}sensor-
|
|
53
|
+
f"imap_ultra_l1b_{instrument_id}sensor-goodtimes" in data_dict
|
|
62
54
|
and f"imap_ultra_l1b_{instrument_id}sensor-de" in data_dict
|
|
63
|
-
and f"
|
|
55
|
+
and f"imap_ultra_l1a_{instrument_id}sensor-rates" in data_dict
|
|
56
|
+
and f"imap_ultra_l1a_{instrument_id}sensor-params" in data_dict
|
|
64
57
|
):
|
|
65
58
|
spacecraft_pset = calculate_spacecraft_pset(
|
|
66
59
|
data_dict[f"imap_ultra_l1b_{instrument_id}sensor-de"],
|
|
67
|
-
data_dict[f"imap_ultra_l1b_{instrument_id}sensor-
|
|
68
|
-
data_dict[f"imap_ultra_l1b_{instrument_id}sensor-cullingmask"],
|
|
60
|
+
data_dict[f"imap_ultra_l1b_{instrument_id}sensor-goodtimes"],
|
|
69
61
|
data_dict[f"imap_ultra_l1a_{instrument_id}sensor-rates"],
|
|
70
62
|
data_dict[f"imap_ultra_l1a_{instrument_id}sensor-params"],
|
|
71
63
|
f"imap_ultra_l1c_{instrument_id}sensor-spacecraftpset",
|
|
72
64
|
ancillary_files,
|
|
73
65
|
instrument_id,
|
|
66
|
+
UltraConstants.TOFXPH_SPECIES_GROUPS["proton"],
|
|
74
67
|
)
|
|
75
68
|
output_datasets = [spacecraft_pset]
|
|
69
|
+
spacecraft_pset_non_proton = calculate_spacecraft_pset(
|
|
70
|
+
data_dict[f"imap_ultra_l1b_{instrument_id}sensor-de"],
|
|
71
|
+
data_dict[f"imap_ultra_l1b_{instrument_id}sensor-goodtimes"],
|
|
72
|
+
data_dict[f"imap_ultra_l1a_{instrument_id}sensor-rates"],
|
|
73
|
+
data_dict[f"imap_ultra_l1a_{instrument_id}sensor-params"],
|
|
74
|
+
f"imap_ultra_l1c_{instrument_id}sensor-spacecraftpset-nonproton",
|
|
75
|
+
ancillary_files,
|
|
76
|
+
instrument_id,
|
|
77
|
+
UltraConstants.TOFXPH_SPECIES_GROUPS["non_proton"],
|
|
78
|
+
)
|
|
79
|
+
if spacecraft_pset_non_proton is not None:
|
|
80
|
+
output_datasets.append(spacecraft_pset_non_proton)
|
|
76
81
|
if not output_datasets:
|
|
77
82
|
raise ValueError("Data dictionary does not contain the expected keys.")
|
|
78
83
|
|
|
@@ -4,6 +4,7 @@ import astropy_healpix.healpy as hp
|
|
|
4
4
|
import numpy as np
|
|
5
5
|
from numpy.typing import NDArray
|
|
6
6
|
|
|
7
|
+
from imap_processing.quality_flags import ImapPSETUltraFlags
|
|
7
8
|
from imap_processing.spice.geometry import (
|
|
8
9
|
SpiceBody,
|
|
9
10
|
SpiceFrame,
|
|
@@ -14,6 +15,7 @@ from imap_processing.spice.geometry import (
|
|
|
14
15
|
def compute_culling_mask(
|
|
15
16
|
et: NDArray,
|
|
16
17
|
keepout_radius_km: float,
|
|
18
|
+
pset_quality_flags: NDArray,
|
|
17
19
|
observer: SpiceBody = SpiceBody.EARTH,
|
|
18
20
|
nside: int = 128,
|
|
19
21
|
nested: bool = False,
|
|
@@ -27,6 +29,9 @@ def compute_culling_mask(
|
|
|
27
29
|
Ephemeris times in TDB seconds past J2000.
|
|
28
30
|
keepout_radius_km : float
|
|
29
31
|
Radius (in km) within which HEALPix pixels will be excluded.
|
|
32
|
+
pset_quality_flags : NDArray,
|
|
33
|
+
Quality flag to set when HEALPIX pixels are within a
|
|
34
|
+
keep-out radius of the target body.
|
|
30
35
|
observer : SpiceBody, optional
|
|
31
36
|
Body from which IMAP is observed.
|
|
32
37
|
nside : int, optional
|
|
@@ -81,5 +86,7 @@ def compute_culling_mask(
|
|
|
81
86
|
# Exclude pixels within the keepout angle.
|
|
82
87
|
# mask.shape = (len(et), npix)
|
|
83
88
|
mask = sep_angle > keepout_angle[:, np.newaxis]
|
|
89
|
+
culled_any_time = np.any(~mask, axis=0) # shape: (npix,)
|
|
90
|
+
pset_quality_flags[culled_any_time] |= ImapPSETUltraFlags.EARTH_FOV.value
|
|
84
91
|
|
|
85
92
|
return mask, unit_target_vecs
|