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
|
@@ -1,27 +1,46 @@
|
|
|
1
1
|
"""Calculate Pointing Set Grids."""
|
|
2
2
|
|
|
3
|
+
import logging
|
|
4
|
+
|
|
5
|
+
import astropy_healpix.healpy as hp
|
|
3
6
|
import numpy as np
|
|
4
|
-
import pandas as pd
|
|
5
7
|
import xarray as xr
|
|
6
8
|
|
|
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
|
+
)
|
|
16
|
+
from imap_processing.ultra.l1b.ultra_l1b_culling import get_de_rejection_mask
|
|
17
|
+
from imap_processing.ultra.l1c.l1c_lookup_utils import (
|
|
18
|
+
calculate_fwhm_spun_scattering,
|
|
19
|
+
get_spacecraft_pointing_lookup_tables,
|
|
20
|
+
)
|
|
21
|
+
from imap_processing.ultra.l1c.ultra_l1c_culling import compute_culling_mask
|
|
7
22
|
from imap_processing.ultra.l1c.ultra_l1c_pset_bins import (
|
|
8
23
|
build_energy_bins,
|
|
24
|
+
get_efficiencies_and_geometric_function,
|
|
25
|
+
get_energy_delta_minus_plus,
|
|
9
26
|
get_spacecraft_background_rates,
|
|
10
27
|
get_spacecraft_exposure_times,
|
|
11
28
|
get_spacecraft_histogram,
|
|
12
|
-
interpolate_sensitivity,
|
|
13
29
|
)
|
|
14
30
|
from imap_processing.ultra.utils.ultra_l1_utils import create_dataset
|
|
15
31
|
|
|
32
|
+
logger = logging.getLogger(__name__)
|
|
33
|
+
|
|
16
34
|
|
|
17
35
|
def calculate_spacecraft_pset(
|
|
18
36
|
de_dataset: xr.Dataset,
|
|
19
|
-
|
|
20
|
-
cullingmask_dataset: xr.Dataset,
|
|
37
|
+
goodtimes_dataset: xr.Dataset,
|
|
21
38
|
rates_dataset: xr.Dataset,
|
|
22
39
|
params_dataset: xr.Dataset,
|
|
23
40
|
name: str,
|
|
24
41
|
ancillary_files: dict,
|
|
42
|
+
instrument_id: int,
|
|
43
|
+
species_id: list,
|
|
25
44
|
) -> xr.Dataset:
|
|
26
45
|
"""
|
|
27
46
|
Create dictionary with defined datatype for Pointing Set Grid Data.
|
|
@@ -30,10 +49,8 @@ def calculate_spacecraft_pset(
|
|
|
30
49
|
----------
|
|
31
50
|
de_dataset : xarray.Dataset
|
|
32
51
|
Dataset containing de data.
|
|
33
|
-
|
|
34
|
-
Dataset containing
|
|
35
|
-
cullingmask_dataset : xarray.Dataset
|
|
36
|
-
Dataset containing cullingmask data.
|
|
52
|
+
goodtimes_dataset : xarray.Dataset
|
|
53
|
+
Dataset containing goodtimes data.
|
|
37
54
|
rates_dataset : xarray.Dataset
|
|
38
55
|
Dataset containing image rates data.
|
|
39
56
|
params_dataset : xarray.Dataset
|
|
@@ -42,6 +59,10 @@ def calculate_spacecraft_pset(
|
|
|
42
59
|
Name of the dataset.
|
|
43
60
|
ancillary_files : dict
|
|
44
61
|
Ancillary files.
|
|
62
|
+
instrument_id : int
|
|
63
|
+
Instrument ID, either 45 or 90.
|
|
64
|
+
species_id : List
|
|
65
|
+
Species ID.
|
|
45
66
|
|
|
46
67
|
Returns
|
|
47
68
|
-------
|
|
@@ -50,50 +71,140 @@ def calculate_spacecraft_pset(
|
|
|
50
71
|
"""
|
|
51
72
|
pset_dict: dict[str, np.ndarray] = {}
|
|
52
73
|
|
|
53
|
-
|
|
74
|
+
sensor = parse_filename_like(name)["sensor"][0:2]
|
|
75
|
+
indices = np.where(np.isin(de_dataset["e_bin"].values, species_id))[0]
|
|
76
|
+
species_dataset = de_dataset.isel(epoch=indices)
|
|
77
|
+
|
|
78
|
+
# If there are no species return None.
|
|
79
|
+
if indices.size == 0:
|
|
80
|
+
return None
|
|
81
|
+
|
|
82
|
+
# Before we use the de_dataset to calculate the pointing set grid we need to filter.
|
|
83
|
+
rejected = get_de_rejection_mask(
|
|
84
|
+
species_dataset["quality_scattering"].values,
|
|
85
|
+
species_dataset["quality_outliers"].values,
|
|
86
|
+
)
|
|
87
|
+
species_dataset = species_dataset.isel(epoch=~rejected)
|
|
88
|
+
|
|
89
|
+
v_mag_dps_spacecraft = np.linalg.norm(
|
|
90
|
+
species_dataset["velocity_dps_sc"].values, axis=1
|
|
91
|
+
)
|
|
54
92
|
vhat_dps_spacecraft = (
|
|
55
|
-
|
|
93
|
+
species_dataset["velocity_dps_sc"].values / v_mag_dps_spacecraft[:, np.newaxis]
|
|
56
94
|
)
|
|
57
95
|
|
|
58
96
|
intervals, _, energy_bin_geometric_means = build_energy_bins()
|
|
97
|
+
|
|
98
|
+
# Get lookup table for FOR indices by spin phase step
|
|
99
|
+
(
|
|
100
|
+
for_indices_by_spin_phase,
|
|
101
|
+
theta_vals,
|
|
102
|
+
phi_vals,
|
|
103
|
+
ra_and_dec,
|
|
104
|
+
boundary_scale_factors,
|
|
105
|
+
) = get_spacecraft_pointing_lookup_tables(ancillary_files, instrument_id)
|
|
106
|
+
|
|
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
|
+
)
|
|
116
|
+
)
|
|
117
|
+
# Determine nside from the lookup table
|
|
118
|
+
nside = hp.npix2nside(len(for_indices_by_spin_phase))
|
|
59
119
|
counts, latitude, longitude, n_pix = get_spacecraft_histogram(
|
|
60
120
|
vhat_dps_spacecraft,
|
|
61
|
-
|
|
121
|
+
species_dataset["energy_spacecraft"].values,
|
|
62
122
|
intervals,
|
|
63
|
-
nside=
|
|
123
|
+
nside=nside,
|
|
64
124
|
)
|
|
65
125
|
healpix = np.arange(n_pix)
|
|
66
126
|
|
|
67
|
-
|
|
68
|
-
|
|
127
|
+
logger.info("Calculating spun efficiencies and geometric function.")
|
|
128
|
+
# calculate efficiency and geometric function as a function of energy
|
|
129
|
+
efficiencies, geometric_function = get_efficiencies_and_geometric_function(
|
|
130
|
+
pixels_below_scattering,
|
|
131
|
+
boundary_scale_factors,
|
|
132
|
+
theta_vals,
|
|
133
|
+
phi_vals,
|
|
134
|
+
n_pix,
|
|
135
|
+
ancillary_files,
|
|
136
|
+
)
|
|
137
|
+
sensitivity = efficiencies * geometric_function
|
|
69
138
|
|
|
70
|
-
|
|
71
|
-
|
|
139
|
+
# Calculate exposure times
|
|
140
|
+
logger.info("Calculating spacecraft exposure times with deadtime correction.")
|
|
141
|
+
exposure_pointing, deadtime_ratios = get_spacecraft_exposure_times(
|
|
142
|
+
rates_dataset,
|
|
143
|
+
params_dataset,
|
|
144
|
+
pixels_below_scattering,
|
|
145
|
+
boundary_scale_factors,
|
|
146
|
+
n_pix=n_pix,
|
|
147
|
+
)
|
|
148
|
+
logger.info("Calculating background rates.")
|
|
149
|
+
# Calculate background rates
|
|
150
|
+
background_rates = get_spacecraft_background_rates(
|
|
151
|
+
rates_dataset,
|
|
152
|
+
sensor,
|
|
153
|
+
ancillary_files,
|
|
154
|
+
intervals,
|
|
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
|
|
160
|
+
)
|
|
72
161
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
sensitivity = interpolate_sensitivity(df_efficiencies, df_geometric_function)
|
|
162
|
+
start: float = np.min(species_dataset["event_times"].values)
|
|
163
|
+
end: float = np.max(species_dataset["event_times"].values)
|
|
76
164
|
|
|
77
|
-
#
|
|
78
|
-
|
|
79
|
-
df_exposure = pd.read_csv(constant_exposure)
|
|
80
|
-
exposure_pointing = get_spacecraft_exposure_times(
|
|
81
|
-
df_exposure, rates_dataset, params_dataset
|
|
82
|
-
)
|
|
165
|
+
# Time bins in 30 minute intervals
|
|
166
|
+
time_bins = np.arange(start, end + 1800, 1800)
|
|
83
167
|
|
|
84
|
-
#
|
|
85
|
-
|
|
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)
|
|
86
182
|
pset_dict["counts"] = counts[np.newaxis, ...]
|
|
87
183
|
pset_dict["latitude"] = latitude[np.newaxis, ...]
|
|
88
184
|
pset_dict["longitude"] = longitude[np.newaxis, ...]
|
|
89
185
|
pset_dict["energy_bin_geometric_mean"] = energy_bin_geometric_means
|
|
90
186
|
pset_dict["background_rates"] = background_rates[np.newaxis, ...]
|
|
91
|
-
pset_dict["exposure_factor"] = exposure_pointing
|
|
187
|
+
pset_dict["exposure_factor"] = exposure_pointing
|
|
92
188
|
pset_dict["pixel_index"] = healpix
|
|
93
189
|
pset_dict["energy_bin_delta"] = np.diff(intervals, axis=1).squeeze()[
|
|
94
190
|
np.newaxis, ...
|
|
95
191
|
]
|
|
96
|
-
pset_dict["
|
|
192
|
+
pset_dict["quality_flags"] = spacecraft_pset_quality_flags[np.newaxis, ...]
|
|
193
|
+
|
|
194
|
+
pset_dict["sensitivity"] = sensitivity
|
|
195
|
+
pset_dict["efficiency"] = efficiencies
|
|
196
|
+
pset_dict["geometric_function"] = geometric_function
|
|
197
|
+
pset_dict["dead_time_ratio"] = deadtime_ratios
|
|
198
|
+
pset_dict["spin_phase_step"] = np.arange(len(deadtime_ratios))
|
|
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
|
|
97
208
|
|
|
98
209
|
dataset = create_dataset(pset_dict, name, "l1c")
|
|
99
210
|
|
|
@@ -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,43 +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"
|
|
43
|
+
data_dict[f"imap_ultra_l1b_{instrument_id}sensor-goodtimes"],
|
|
44
|
+
data_dict[f"imap_ultra_l1a_{instrument_id}sensor-rates"],
|
|
45
|
+
data_dict[f"imap_ultra_l1a_{instrument_id}sensor-params"],
|
|
53
46
|
f"imap_ultra_l1c_{instrument_id}sensor-heliopset",
|
|
54
47
|
ancillary_files,
|
|
48
|
+
instrument_id,
|
|
49
|
+
UltraConstants.TOFXPH_SPECIES_GROUPS["proton"],
|
|
55
50
|
)
|
|
56
51
|
output_datasets = [helio_pset]
|
|
57
52
|
elif (
|
|
58
|
-
f"imap_ultra_l1b_{instrument_id}sensor-
|
|
53
|
+
f"imap_ultra_l1b_{instrument_id}sensor-goodtimes" in data_dict
|
|
59
54
|
and f"imap_ultra_l1b_{instrument_id}sensor-de" in data_dict
|
|
60
|
-
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
|
|
61
57
|
):
|
|
62
58
|
spacecraft_pset = calculate_spacecraft_pset(
|
|
63
59
|
data_dict[f"imap_ultra_l1b_{instrument_id}sensor-de"],
|
|
64
|
-
data_dict[f"imap_ultra_l1b_{instrument_id}sensor-
|
|
65
|
-
data_dict[f"
|
|
66
|
-
data_dict[f"
|
|
67
|
-
data_dict[f"imap_ultra_{instrument_id}sensor-params"],
|
|
60
|
+
data_dict[f"imap_ultra_l1b_{instrument_id}sensor-goodtimes"],
|
|
61
|
+
data_dict[f"imap_ultra_l1a_{instrument_id}sensor-rates"],
|
|
62
|
+
data_dict[f"imap_ultra_l1a_{instrument_id}sensor-params"],
|
|
68
63
|
f"imap_ultra_l1c_{instrument_id}sensor-spacecraftpset",
|
|
69
64
|
ancillary_files,
|
|
65
|
+
instrument_id,
|
|
66
|
+
UltraConstants.TOFXPH_SPECIES_GROUPS["proton"],
|
|
70
67
|
)
|
|
71
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)
|
|
72
81
|
if not output_datasets:
|
|
73
82
|
raise ValueError("Data dictionary does not contain the expected keys.")
|
|
74
83
|
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""Culling for ULTRA L1c."""
|
|
2
|
+
|
|
3
|
+
import astropy_healpix.healpy as hp
|
|
4
|
+
import numpy as np
|
|
5
|
+
from numpy.typing import NDArray
|
|
6
|
+
|
|
7
|
+
from imap_processing.quality_flags import ImapPSETUltraFlags
|
|
8
|
+
from imap_processing.spice.geometry import (
|
|
9
|
+
SpiceBody,
|
|
10
|
+
SpiceFrame,
|
|
11
|
+
imap_state,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def compute_culling_mask(
|
|
16
|
+
et: NDArray,
|
|
17
|
+
keepout_radius_km: float,
|
|
18
|
+
pset_quality_flags: NDArray,
|
|
19
|
+
observer: SpiceBody = SpiceBody.EARTH,
|
|
20
|
+
nside: int = 128,
|
|
21
|
+
nested: bool = False,
|
|
22
|
+
) -> tuple[NDArray, NDArray]:
|
|
23
|
+
"""
|
|
24
|
+
Compute a mask for HEALPix pixels within a keep-out radius of the target body.
|
|
25
|
+
|
|
26
|
+
Parameters
|
|
27
|
+
----------
|
|
28
|
+
et : NDArray
|
|
29
|
+
Ephemeris times in TDB seconds past J2000.
|
|
30
|
+
keepout_radius_km : float
|
|
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.
|
|
35
|
+
observer : SpiceBody, optional
|
|
36
|
+
Body from which IMAP is observed.
|
|
37
|
+
nside : int, optional
|
|
38
|
+
HEALPix NSIDE resolution. Default is 128.
|
|
39
|
+
nested : bool, optional
|
|
40
|
+
Whether to use NESTED indexing.
|
|
41
|
+
|
|
42
|
+
Returns
|
|
43
|
+
-------
|
|
44
|
+
mask : tuple[NDArray, NDArray]
|
|
45
|
+
Boolean array of shape (len(et), npix).
|
|
46
|
+
unit_target_vecs : NDArray
|
|
47
|
+
Unit vectors from IMAP to the target body
|
|
48
|
+
(e.g., Earth), shape (len(et), 3).
|
|
49
|
+
"""
|
|
50
|
+
# Compute number of HEALPix pixels
|
|
51
|
+
npix = hp.nside2npix(nside)
|
|
52
|
+
|
|
53
|
+
# Compute IMAP to Earth position in the pointing frame.
|
|
54
|
+
state = imap_state(et, ref_frame=SpiceFrame.IMAP_DPS, observer=observer)
|
|
55
|
+
# Flip to get vector from IMAP to Earth
|
|
56
|
+
# position.shape = (len(et), 3)
|
|
57
|
+
position = -state[:, :3]
|
|
58
|
+
|
|
59
|
+
# Distance from IMAP to target (e.g. Earth) (km):
|
|
60
|
+
# distance.shape = (len(et),)
|
|
61
|
+
distance = np.linalg.norm(position, axis=1) # shape (len(et),)
|
|
62
|
+
|
|
63
|
+
# Calculate the keepout angle (radians).
|
|
64
|
+
# keepout_angle.shape = (len(et),)
|
|
65
|
+
keepout_angle = np.arcsin(keepout_radius_km / distance) # radians
|
|
66
|
+
|
|
67
|
+
# Calculate the direction from IMAP to Earth. (shape: [N, 3])
|
|
68
|
+
# unit_target_vecs.shape = (len(et), 3)
|
|
69
|
+
unit_target_vecs = position / distance[:, np.newaxis]
|
|
70
|
+
|
|
71
|
+
# Get pixel unit vectors pointing from the center of the
|
|
72
|
+
# HEALPix sphere to the center of each pixel on the sky.
|
|
73
|
+
pixel_vecs = np.column_stack(
|
|
74
|
+
hp.pix2vec(nside, np.arange(npix), nest=nested)
|
|
75
|
+
) # shape: (npix, 3)
|
|
76
|
+
|
|
77
|
+
# Returns cos(theta) where theta is the separation angle between:
|
|
78
|
+
# (1) vector from IMAP to Earth
|
|
79
|
+
# (2) vector from IMAP to HEALPix pixel center
|
|
80
|
+
# If theta is within the keepout angle, then the pixel is culled.
|
|
81
|
+
cos_sep = np.dot(unit_target_vecs, pixel_vecs.T) # shape (N, npix)
|
|
82
|
+
cos_sep = np.clip(cos_sep, -1.0, 1.0)
|
|
83
|
+
# Get theta here.
|
|
84
|
+
sep_angle = np.arccos(cos_sep)
|
|
85
|
+
|
|
86
|
+
# Exclude pixels within the keepout angle.
|
|
87
|
+
# mask.shape = (len(et), npix)
|
|
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
|
|
91
|
+
|
|
92
|
+
return mask, unit_target_vecs
|