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
|
@@ -12,7 +12,7 @@ from imap_processing.cdf.imap_cdf_manager import ImapCdfAttributes
|
|
|
12
12
|
logger = logging.getLogger(__name__)
|
|
13
13
|
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
SWAPI_LIVETIME = 0.145 # seconds
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
def solve_full_sweep_energy(
|
|
@@ -66,7 +66,7 @@ def solve_full_sweep_energy(
|
|
|
66
66
|
|
|
67
67
|
first_63_energies = []
|
|
68
68
|
|
|
69
|
-
for time, sweep_id in zip(data_time, sweep_table):
|
|
69
|
+
for time, sweep_id in zip(data_time, sweep_table, strict=False):
|
|
70
70
|
# Find the sweep's ESA data for the given time and sweep_id
|
|
71
71
|
subset = esa_table_df[
|
|
72
72
|
(esa_table_df["timestamp"] <= time) & (esa_table_df["Sweep #"] == sweep_id)
|
|
@@ -159,14 +159,12 @@ def swapi_l2(
|
|
|
159
159
|
|
|
160
160
|
To process science data to L2, we need to:
|
|
161
161
|
- convert counts to rates. This is done by dividing the counts by the
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
(12 s, coarse + fine sweep) by the total energy steps (72),
|
|
165
|
-
i.e., TIME_PER_BIN = 12/72 = 0.167 s. This will be constant.
|
|
162
|
+
SWAPI_LIVETIME time. LIVETIME is data acquisition time. It will
|
|
163
|
+
be constant, SWAPI_LIVETIME = 0.145 s.
|
|
166
164
|
|
|
167
165
|
- update uncertainty. Calculate new uncertainty value using
|
|
168
|
-
SWP_PCEM_ERR data from level one and divide by
|
|
169
|
-
SWP_PCEM_UNC = SWP_PCEM_ERR /
|
|
166
|
+
SWP_PCEM_ERR data from level one and divide by SWAPI_LIVETIME. Eg.
|
|
167
|
+
SWP_PCEM_UNC = SWP_PCEM_ERR / SWAPI_LIVETIME
|
|
170
168
|
Do the same for SCEM and COIN data.
|
|
171
169
|
|
|
172
170
|
Parameters
|
|
@@ -233,9 +231,9 @@ def swapi_l2(
|
|
|
233
231
|
]
|
|
234
232
|
|
|
235
233
|
# convert counts to rate
|
|
236
|
-
l2_dataset["swp_pcem_rate"] = l1_dataset["swp_pcem_counts"] /
|
|
237
|
-
l2_dataset["swp_scem_rate"] = l1_dataset["swp_scem_counts"] /
|
|
238
|
-
l2_dataset["swp_coin_rate"] = l1_dataset["swp_coin_counts"] /
|
|
234
|
+
l2_dataset["swp_pcem_rate"] = l1_dataset["swp_pcem_counts"] / SWAPI_LIVETIME
|
|
235
|
+
l2_dataset["swp_scem_rate"] = l1_dataset["swp_scem_counts"] / SWAPI_LIVETIME
|
|
236
|
+
l2_dataset["swp_coin_rate"] = l1_dataset["swp_coin_counts"] / SWAPI_LIVETIME
|
|
239
237
|
# update attrs
|
|
240
238
|
l2_dataset["swp_pcem_rate"].attrs = cdf_manager.get_variable_attributes("pcem_rate")
|
|
241
239
|
l2_dataset["swp_scem_rate"].attrs = cdf_manager.get_variable_attributes("scem_rate")
|
|
@@ -243,22 +241,22 @@ def swapi_l2(
|
|
|
243
241
|
|
|
244
242
|
# update uncertainty
|
|
245
243
|
l2_dataset["swp_pcem_rate_stat_uncert_plus"] = (
|
|
246
|
-
l1_dataset["swp_pcem_counts_stat_uncert_plus"] /
|
|
244
|
+
l1_dataset["swp_pcem_counts_stat_uncert_plus"] / SWAPI_LIVETIME
|
|
247
245
|
)
|
|
248
246
|
l2_dataset["swp_pcem_rate_stat_uncert_minus"] = (
|
|
249
|
-
l1_dataset["swp_pcem_counts_stat_uncert_minus"] /
|
|
247
|
+
l1_dataset["swp_pcem_counts_stat_uncert_minus"] / SWAPI_LIVETIME
|
|
250
248
|
)
|
|
251
249
|
l2_dataset["swp_scem_rate_stat_uncert_plus"] = (
|
|
252
|
-
l1_dataset["swp_scem_counts_stat_uncert_plus"] /
|
|
250
|
+
l1_dataset["swp_scem_counts_stat_uncert_plus"] / SWAPI_LIVETIME
|
|
253
251
|
)
|
|
254
252
|
l2_dataset["swp_scem_rate_stat_uncert_minus"] = (
|
|
255
|
-
l1_dataset["swp_scem_counts_stat_uncert_minus"] /
|
|
253
|
+
l1_dataset["swp_scem_counts_stat_uncert_minus"] / SWAPI_LIVETIME
|
|
256
254
|
)
|
|
257
255
|
l2_dataset["swp_coin_rate_stat_uncert_plus"] = (
|
|
258
|
-
l1_dataset["swp_coin_counts_stat_uncert_plus"] /
|
|
256
|
+
l1_dataset["swp_coin_counts_stat_uncert_plus"] / SWAPI_LIVETIME
|
|
259
257
|
)
|
|
260
258
|
l2_dataset["swp_coin_rate_stat_uncert_minus"] = (
|
|
261
|
-
l1_dataset["swp_coin_counts_stat_uncert_minus"] /
|
|
259
|
+
l1_dataset["swp_coin_counts_stat_uncert_minus"] / SWAPI_LIVETIME
|
|
262
260
|
)
|
|
263
261
|
# update attrs
|
|
264
262
|
l2_dataset[
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
4
|
from pathlib import Path
|
|
5
|
-
from typing import Union
|
|
6
5
|
|
|
7
6
|
import numpy as np
|
|
8
7
|
import numpy.typing as npt
|
|
@@ -51,7 +50,7 @@ def get_esa_dataframe(esa_table_number: int) -> pd.DataFrame:
|
|
|
51
50
|
|
|
52
51
|
|
|
53
52
|
def deadtime_correction(
|
|
54
|
-
counts: np.ndarray, acq_duration:
|
|
53
|
+
counts: np.ndarray, acq_duration: int | npt.NDArray
|
|
55
54
|
) -> npt.NDArray:
|
|
56
55
|
"""
|
|
57
56
|
Calculate deadtime correction.
|
|
@@ -51,7 +51,6 @@ class UltraConstants:
|
|
|
51
51
|
Z_DSTOP: float = 2.6 / 2 # Position of stop foil on Z axis [mm]
|
|
52
52
|
Z_DS: float = 46.19 - (2.6 / 2) # Position of slit on Z axis [mm]
|
|
53
53
|
DF: float = 3.39 # Distance from slit to foil [mm]
|
|
54
|
-
|
|
55
54
|
# Derived constants
|
|
56
55
|
DMIN_PH_CTOF: float = (
|
|
57
56
|
Z_DS - (2**0.5) * DF
|
|
@@ -79,53 +78,60 @@ class UltraConstants:
|
|
|
79
78
|
CULLING_RPM_MIN = 2.0
|
|
80
79
|
CULLING_RPM_MAX = 6.0
|
|
81
80
|
|
|
82
|
-
# Thresholds for culling based on counts.
|
|
81
|
+
# Thresholds for culling based on counts (keV).
|
|
83
82
|
CULLING_ENERGY_BIN_EDGES: ClassVar[list] = [
|
|
83
|
+
3.0,
|
|
84
|
+
10.0,
|
|
85
|
+
20.0,
|
|
86
|
+
50.0,
|
|
87
|
+
300.0,
|
|
88
|
+
1e5,
|
|
89
|
+
]
|
|
90
|
+
PSET_ENERGY_BIN_EDGES: ClassVar[list] = [
|
|
84
91
|
3.385,
|
|
85
92
|
4.13722222222222,
|
|
86
|
-
4.13722222222222,
|
|
87
93
|
5.05660493827161,
|
|
88
|
-
5.05660493827161,
|
|
89
|
-
6.18029492455419,
|
|
90
94
|
6.18029492455419,
|
|
91
95
|
7.55369379667734,
|
|
92
|
-
7.55369379667734,
|
|
93
96
|
9.23229241816119,
|
|
94
|
-
9.23229241816119,
|
|
95
|
-
11.2839129555303,
|
|
96
97
|
11.2839129555303,
|
|
97
98
|
13.7914491678704,
|
|
98
|
-
13.7914491678704,
|
|
99
|
-
16.8562156496194,
|
|
100
99
|
16.8562156496194,
|
|
101
100
|
20.6020413495348,
|
|
102
|
-
20.6020413495348,
|
|
103
|
-
25.1802727605426,
|
|
104
101
|
25.1802727605426,
|
|
105
102
|
30.775888929552,
|
|
106
|
-
30.775888929552,
|
|
107
103
|
37.6149753583414,
|
|
108
|
-
37.6149753583414,
|
|
109
|
-
45.9738587713061,
|
|
110
104
|
45.9738587713061,
|
|
111
105
|
56.1902718315964,
|
|
112
|
-
56.1902718315964,
|
|
113
|
-
68.6769989052845,
|
|
114
106
|
68.6769989052845,
|
|
115
107
|
83.93855421757,
|
|
116
|
-
83.93855421757,
|
|
117
|
-
102.591566265919,
|
|
118
108
|
102.591566265919,
|
|
119
109
|
125.38969210279,
|
|
120
|
-
125.38969210279,
|
|
121
110
|
153.254068125632,
|
|
122
|
-
153.254068125632,
|
|
123
|
-
187.310527709106,
|
|
124
111
|
187.310527709106,
|
|
125
112
|
228.93508942224,
|
|
126
|
-
228.93508942224,
|
|
127
|
-
279.809553738294,
|
|
128
113
|
279.809553738294,
|
|
129
114
|
341.989454569026,
|
|
130
115
|
1e5,
|
|
131
116
|
]
|
|
117
|
+
|
|
118
|
+
# Valid event filter constants
|
|
119
|
+
# Note these appear similar to image params constants
|
|
120
|
+
# but they should be used only for the valid event filter.
|
|
121
|
+
ETOFOFF1_EVENTFILTER = 100
|
|
122
|
+
ETOFOFF2_EVENTFILTER = -50
|
|
123
|
+
ETOFSLOPE1_EVENTFILTER = 6667
|
|
124
|
+
ETOFSLOPE2_EVENTFILTER = 7500
|
|
125
|
+
ETOFMAX_EVENTFILTER = 90
|
|
126
|
+
ETOFMIN_EVENTFILTER = -400
|
|
127
|
+
TOFDIFFTPMIN_EVENTFILTER = 226
|
|
128
|
+
TOFDIFFTPMAX_EVENTFILTER = 266
|
|
129
|
+
|
|
130
|
+
TOFXE_SPECIES_GROUPS: ClassVar[dict[str, list[int]]] = {
|
|
131
|
+
"proton": [3],
|
|
132
|
+
"non_proton": [20, 28, 36],
|
|
133
|
+
}
|
|
134
|
+
TOFXPH_SPECIES_GROUPS: ClassVar[dict[str, list[int]]] = {
|
|
135
|
+
"proton": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
|
|
136
|
+
"non_proton": [20, 21, 22, 23, 24, 25, 26],
|
|
137
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Contains data classes to support Ultra L0 processing."""
|
|
2
2
|
|
|
3
|
-
from typing import NamedTuple
|
|
3
|
+
from typing import NamedTuple
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
class PacketProperties(NamedTuple):
|
|
@@ -9,23 +9,21 @@ class PacketProperties(NamedTuple):
|
|
|
9
9
|
apid: list # List of APIDs
|
|
10
10
|
logical_source: list # List of logical sources
|
|
11
11
|
addition_to_logical_desc: str # Description of the logical source
|
|
12
|
-
width:
|
|
12
|
+
width: int | None # Width of binary data (could be None).
|
|
13
13
|
# Block, image_planes, pixel_window_rows, and pixel_window_columns are important for
|
|
14
14
|
# decompressing the images and a description is available on page 171 of IMAP-Ultra
|
|
15
15
|
# Flight Software Specification document (7523-9009_Rev_-.pdf).
|
|
16
|
-
block:
|
|
17
|
-
len_array:
|
|
18
|
-
|
|
19
|
-
] # Length of the array to be decompressed (could be None).
|
|
20
|
-
mantissa_bit_length: Union[int, None] # used to determine the level of
|
|
16
|
+
block: int | None # Number of values in each block (could be None).
|
|
17
|
+
len_array: int | None # Length of the array to be decompressed (could be None).
|
|
18
|
+
mantissa_bit_length: int | None # used to determine the level of
|
|
21
19
|
# precision that can be recovered from compressed data (could be None).
|
|
22
|
-
image_planes:
|
|
20
|
+
image_planes: int | None = None
|
|
23
21
|
# number of images. See table 11 in the FSSD.
|
|
24
|
-
pixel_window_rows:
|
|
22
|
+
pixel_window_rows: int | None = None
|
|
25
23
|
# number of rows in each image. See table 49 in the FSSD.
|
|
26
|
-
pixel_window_columns:
|
|
24
|
+
pixel_window_columns: int | None = None
|
|
27
25
|
# number of columns in each image. See table 49 in the FSSD.
|
|
28
|
-
image_planes_per_packet:
|
|
26
|
+
image_planes_per_packet: int | None = None
|
|
29
27
|
# number of image planes in each packet. See table 52 in the FSSD.
|
|
30
28
|
|
|
31
29
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"""Generate ULTRA L1a CDFs."""
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
|
-
from typing import Optional
|
|
5
4
|
|
|
6
5
|
import xarray as xr
|
|
7
6
|
|
|
@@ -44,7 +43,7 @@ logger = logging.getLogger(__name__)
|
|
|
44
43
|
|
|
45
44
|
|
|
46
45
|
def ultra_l1a( # noqa: PLR0912
|
|
47
|
-
packet_file: str, apid_input:
|
|
46
|
+
packet_file: str, apid_input: int | None = None
|
|
48
47
|
) -> list[xr.Dataset]:
|
|
49
48
|
"""
|
|
50
49
|
Will process ULTRA L0 data into L1A CDF files at output_filepath.
|
|
@@ -7,13 +7,14 @@ from numpy.typing import NDArray
|
|
|
7
7
|
from imap_processing.ultra.utils.ultra_l1_utils import create_dataset, extract_data_dict
|
|
8
8
|
|
|
9
9
|
FILLVAL_UINT16 = 65535
|
|
10
|
+
FILLVAL_FLOAT32 = -1.0e31
|
|
10
11
|
FILLVAL_FLOAT64 = -1.0e31
|
|
11
12
|
FILLVAL_UINT32 = 4294967295
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
def calculate_badtimes(
|
|
15
16
|
extendedspin_dataset: xr.Dataset,
|
|
16
|
-
|
|
17
|
+
goodtimes_spins: NDArray,
|
|
17
18
|
name: str,
|
|
18
19
|
) -> xr.Dataset:
|
|
19
20
|
"""
|
|
@@ -23,7 +24,7 @@ def calculate_badtimes(
|
|
|
23
24
|
----------
|
|
24
25
|
extendedspin_dataset : xarray.Dataset
|
|
25
26
|
Dataset containing the data.
|
|
26
|
-
|
|
27
|
+
goodtimes_spins : np.ndarray
|
|
27
28
|
Dataset containing the culled data.
|
|
28
29
|
name : str
|
|
29
30
|
Name of the dataset.
|
|
@@ -33,11 +34,9 @@ def calculate_badtimes(
|
|
|
33
34
|
badtimes_dataset : xarray.Dataset
|
|
34
35
|
Dataset containing the extendedspin data that has been culled.
|
|
35
36
|
"""
|
|
37
|
+
n_bins = extendedspin_dataset.dims["energy_bin_geometric_mean"]
|
|
36
38
|
culled_spins = np.setdiff1d(
|
|
37
|
-
extendedspin_dataset["spin_number"].values,
|
|
38
|
-
)
|
|
39
|
-
extendedspin_dataset = extendedspin_dataset.assign_coords(
|
|
40
|
-
epoch=("spin_number", extendedspin_dataset["epoch"].values)
|
|
39
|
+
extendedspin_dataset["spin_number"].values, goodtimes_spins
|
|
41
40
|
)
|
|
42
41
|
filtered_dataset = extendedspin_dataset.sel(spin_number=culled_spins)
|
|
43
42
|
|
|
@@ -48,9 +47,6 @@ def calculate_badtimes(
|
|
|
48
47
|
if badtimes_dataset["spin_number"].size == 0:
|
|
49
48
|
badtimes_dataset = badtimes_dataset.drop_dims("spin_number")
|
|
50
49
|
badtimes_dataset = badtimes_dataset.expand_dims(spin_number=[FILLVAL_UINT32])
|
|
51
|
-
badtimes_dataset = badtimes_dataset.assign_coords(
|
|
52
|
-
epoch=("spin_number", [extendedspin_dataset["epoch"].values[0]])
|
|
53
|
-
)
|
|
54
50
|
badtimes_dataset["spin_start_time"] = xr.DataArray(
|
|
55
51
|
np.array([FILLVAL_FLOAT64], dtype="float64"), dims=["spin_number"]
|
|
56
52
|
)
|
|
@@ -60,16 +56,44 @@ def calculate_badtimes(
|
|
|
60
56
|
badtimes_dataset["spin_rate"] = xr.DataArray(
|
|
61
57
|
np.array([FILLVAL_FLOAT64], dtype="float64"), dims=["spin_number"]
|
|
62
58
|
)
|
|
59
|
+
badtimes_dataset["start_pulses_per_spin"] = xr.DataArray(
|
|
60
|
+
np.array([FILLVAL_FLOAT32], dtype="float32"),
|
|
61
|
+
dims=["spin_number"],
|
|
62
|
+
)
|
|
63
|
+
badtimes_dataset["stop_pulses_per_spin"] = xr.DataArray(
|
|
64
|
+
np.array([FILLVAL_FLOAT32], dtype="float32"),
|
|
65
|
+
dims=["spin_number"],
|
|
66
|
+
)
|
|
67
|
+
badtimes_dataset["coin_pulses_per_spin"] = xr.DataArray(
|
|
68
|
+
np.array([FILLVAL_FLOAT32], dtype="float32"),
|
|
69
|
+
dims=["spin_number"],
|
|
70
|
+
)
|
|
71
|
+
badtimes_dataset["rejected_events_per_spin"] = xr.DataArray(
|
|
72
|
+
np.array([FILLVAL_UINT32], dtype="uint32"),
|
|
73
|
+
dims=["spin_number"],
|
|
74
|
+
)
|
|
63
75
|
badtimes_dataset["quality_attitude"] = xr.DataArray(
|
|
64
76
|
np.array([FILLVAL_UINT16], dtype="uint16"), dims=["spin_number"]
|
|
65
77
|
)
|
|
78
|
+
badtimes_dataset["quality_hk"] = xr.DataArray(
|
|
79
|
+
np.array([FILLVAL_UINT16], dtype="uint16"),
|
|
80
|
+
dims=["spin_number"],
|
|
81
|
+
)
|
|
82
|
+
badtimes_dataset["quality_instruments"] = xr.DataArray(
|
|
83
|
+
np.array([FILLVAL_UINT16], dtype="uint16"),
|
|
84
|
+
dims=["spin_number"],
|
|
85
|
+
)
|
|
66
86
|
badtimes_dataset["quality_ena_rates"] = (
|
|
67
87
|
("energy_bin_geometric_mean", "spin_number"),
|
|
68
|
-
np.full((
|
|
88
|
+
np.full((n_bins, 1), FILLVAL_UINT16, dtype="uint16"),
|
|
69
89
|
)
|
|
70
90
|
badtimes_dataset["ena_rates"] = (
|
|
71
91
|
("energy_bin_geometric_mean", "spin_number"),
|
|
72
|
-
np.full((
|
|
92
|
+
np.full((n_bins, 1), FILLVAL_FLOAT64, dtype="float64"),
|
|
93
|
+
)
|
|
94
|
+
badtimes_dataset["ena_rates_threshold"] = (
|
|
95
|
+
("energy_bin_geometric_mean", "spin_number"),
|
|
96
|
+
np.full((n_bins, 1), FILLVAL_FLOAT32, dtype="float32"),
|
|
73
97
|
)
|
|
74
98
|
|
|
75
99
|
return badtimes_dataset
|
imap_processing/ultra/l1b/de.py
CHANGED
|
@@ -4,12 +4,16 @@ import numpy as np
|
|
|
4
4
|
import xarray as xr
|
|
5
5
|
|
|
6
6
|
from imap_processing.cdf.utils import parse_filename_like
|
|
7
|
-
from imap_processing.quality_flags import
|
|
7
|
+
from imap_processing.quality_flags import (
|
|
8
|
+
ImapDEOutliersUltraFlags,
|
|
9
|
+
ImapDEScatteringUltraFlags,
|
|
10
|
+
)
|
|
8
11
|
from imap_processing.spice.geometry import SpiceFrame
|
|
9
12
|
from imap_processing.ultra.l1b.lookup_utils import get_geometric_factor
|
|
10
13
|
from imap_processing.ultra.l1b.ultra_l1b_annotated import (
|
|
11
14
|
get_annotated_particle_velocity,
|
|
12
15
|
)
|
|
16
|
+
from imap_processing.ultra.l1b.ultra_l1b_culling import flag_scattering
|
|
13
17
|
from imap_processing.ultra.l1b.ultra_l1b_extended import (
|
|
14
18
|
StopType,
|
|
15
19
|
determine_ebin_pulse_height,
|
|
@@ -32,10 +36,13 @@ from imap_processing.ultra.l1b.ultra_l1b_extended import (
|
|
|
32
36
|
get_spin_number,
|
|
33
37
|
get_ssd_back_position_and_tof_offset,
|
|
34
38
|
get_ssd_tof,
|
|
39
|
+
is_back_tof_valid,
|
|
40
|
+
is_coin_ph_valid,
|
|
35
41
|
)
|
|
36
42
|
from imap_processing.ultra.utils.ultra_l1_utils import create_dataset
|
|
37
43
|
|
|
38
44
|
FILLVAL_UINT8 = 255
|
|
45
|
+
FILLVAL_UINT32 = 4294967295
|
|
39
46
|
FILLVAL_FLOAT32 = -1.0e31
|
|
40
47
|
|
|
41
48
|
|
|
@@ -76,7 +83,6 @@ def calculate_de(
|
|
|
76
83
|
"event_type",
|
|
77
84
|
"de_event_met",
|
|
78
85
|
"phase_angle",
|
|
79
|
-
"spin",
|
|
80
86
|
]
|
|
81
87
|
dataset_keys = [
|
|
82
88
|
"coin_type",
|
|
@@ -84,11 +90,13 @@ def calculate_de(
|
|
|
84
90
|
"stop_type",
|
|
85
91
|
"shcoarse",
|
|
86
92
|
"phase_angle",
|
|
87
|
-
"spin",
|
|
88
93
|
]
|
|
89
94
|
|
|
90
95
|
de_dict.update(
|
|
91
|
-
{
|
|
96
|
+
{
|
|
97
|
+
key: de_dataset[dataset_key]
|
|
98
|
+
for key, dataset_key in zip(keys, dataset_keys, strict=False)
|
|
99
|
+
}
|
|
92
100
|
)
|
|
93
101
|
|
|
94
102
|
valid_mask = de_dataset["start_type"].data != FILLVAL_UINT8
|
|
@@ -114,9 +122,11 @@ def calculate_de(
|
|
|
114
122
|
tof = np.full(len(de_dataset["epoch"]), FILLVAL_FLOAT32, dtype=np.float32)
|
|
115
123
|
etof = np.full(len(de_dataset["epoch"]), FILLVAL_FLOAT32, dtype=np.float32)
|
|
116
124
|
ctof = np.full(len(de_dataset["epoch"]), FILLVAL_FLOAT32, dtype=np.float32)
|
|
125
|
+
tof_energy = np.full(len(de_dataset["epoch"]), FILLVAL_FLOAT32, dtype=np.float32)
|
|
117
126
|
magnitude_v = np.full(len(de_dataset["epoch"]), FILLVAL_FLOAT32, dtype=np.float32)
|
|
118
127
|
energy = np.full(len(de_dataset["epoch"]), FILLVAL_FLOAT32, dtype=np.float32)
|
|
119
128
|
e_bin = np.full(len(de_dataset["epoch"]), FILLVAL_UINT8, dtype=np.uint8)
|
|
129
|
+
e_bin_l1a = np.full(len(de_dataset["epoch"]), FILLVAL_UINT8, dtype=np.uint8)
|
|
120
130
|
species_bin = np.full(len(de_dataset["epoch"]), FILLVAL_UINT8, dtype=np.uint8)
|
|
121
131
|
t2 = np.full(len(de_dataset["epoch"]), FILLVAL_FLOAT32, dtype=np.float32)
|
|
122
132
|
event_times = np.full(len(de_dataset["epoch"]), FILLVAL_FLOAT32, dtype=np.float32)
|
|
@@ -125,10 +135,19 @@ def calculate_de(
|
|
|
125
135
|
sc_dps_velocity = np.full(shape, FILLVAL_FLOAT32, dtype=np.float32)
|
|
126
136
|
helio_velocity = np.full(shape, FILLVAL_FLOAT32, dtype=np.float32)
|
|
127
137
|
spin_starts = np.full(len(de_dataset["epoch"]), FILLVAL_FLOAT32, dtype=np.float64)
|
|
138
|
+
velocities = np.full(shape, FILLVAL_FLOAT32, dtype=np.float32)
|
|
139
|
+
v_hat = np.full(shape, FILLVAL_FLOAT32, dtype=np.float32)
|
|
140
|
+
r_hat = np.full(shape, FILLVAL_FLOAT32, dtype=np.float32)
|
|
128
141
|
|
|
129
142
|
start_type = np.full(len(de_dataset["epoch"]), FILLVAL_UINT8, dtype=np.uint8)
|
|
130
143
|
quality_flags = np.full(
|
|
131
|
-
de_dataset["epoch"].shape,
|
|
144
|
+
de_dataset["epoch"].shape, ImapDEOutliersUltraFlags.NONE.value, dtype=np.uint16
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
scattering_quality_flags = np.full(
|
|
148
|
+
de_dataset["epoch"].shape,
|
|
149
|
+
ImapDEScatteringUltraFlags.NONE.value,
|
|
150
|
+
dtype=np.uint16,
|
|
132
151
|
)
|
|
133
152
|
|
|
134
153
|
xf[valid_indices] = get_front_x_position(
|
|
@@ -149,9 +168,13 @@ def calculate_de(
|
|
|
149
168
|
)
|
|
150
169
|
|
|
151
170
|
# Pulse height
|
|
152
|
-
|
|
153
|
-
|
|
171
|
+
ph_result = get_ph_tof_and_back_positions(
|
|
172
|
+
de_dataset, xf, f"ultra{sensor}", ancillary_files
|
|
154
173
|
)
|
|
174
|
+
tof[ph_indices] = ph_result.tof
|
|
175
|
+
t2[ph_indices] = ph_result.t2
|
|
176
|
+
xb[ph_indices] = ph_result.xb
|
|
177
|
+
yb[ph_indices] = ph_result.yb
|
|
155
178
|
d[ph_indices], yf[ph_indices] = get_front_y_position(
|
|
156
179
|
de_dataset["start_type"].data[ph_indices], yb[ph_indices], ancillary_files
|
|
157
180
|
)
|
|
@@ -174,16 +197,39 @@ def calculate_de(
|
|
|
174
197
|
(xb[ph_indices], yb[ph_indices]),
|
|
175
198
|
d[ph_indices],
|
|
176
199
|
)
|
|
177
|
-
e_bin[ph_indices] = determine_ebin_pulse_height(
|
|
178
|
-
energy[ph_indices], tof[ph_indices], r[ph_indices]
|
|
179
|
-
)
|
|
180
|
-
species_bin[ph_indices] = determine_species(tof[ph_indices], r[ph_indices], "PH")
|
|
181
200
|
etof[ph_indices], xc[ph_indices] = get_coincidence_positions(
|
|
182
201
|
de_dataset.isel(epoch=ph_indices),
|
|
183
202
|
t2[ph_indices],
|
|
184
203
|
f"ultra{sensor}",
|
|
185
204
|
ancillary_files,
|
|
186
205
|
)
|
|
206
|
+
backtofvalid = is_back_tof_valid(
|
|
207
|
+
de_dataset,
|
|
208
|
+
xf,
|
|
209
|
+
f"ultra{sensor}",
|
|
210
|
+
ancillary_files,
|
|
211
|
+
)
|
|
212
|
+
coinphvalid = is_coin_ph_valid(
|
|
213
|
+
etof[ph_indices],
|
|
214
|
+
xc[ph_indices],
|
|
215
|
+
xb[ph_indices],
|
|
216
|
+
de_dataset["stop_north_tdc"][ph_indices].values,
|
|
217
|
+
de_dataset["stop_south_tdc"][ph_indices].values,
|
|
218
|
+
de_dataset["stop_east_tdc"][ph_indices].values,
|
|
219
|
+
de_dataset["stop_west_tdc"][ph_indices].values,
|
|
220
|
+
f"ultra{sensor}",
|
|
221
|
+
ancillary_files,
|
|
222
|
+
quality_flags[ph_indices],
|
|
223
|
+
)
|
|
224
|
+
e_bin[ph_indices] = determine_ebin_pulse_height(
|
|
225
|
+
energy[ph_indices],
|
|
226
|
+
tof[ph_indices],
|
|
227
|
+
r[ph_indices],
|
|
228
|
+
backtofvalid,
|
|
229
|
+
coinphvalid,
|
|
230
|
+
ancillary_files,
|
|
231
|
+
)
|
|
232
|
+
species_bin[ph_indices] = determine_species(e_bin[ph_indices], "PH")
|
|
187
233
|
ctof[ph_indices], magnitude_v[ph_indices] = get_ctof(
|
|
188
234
|
tof[ph_indices], r[ph_indices], "PH"
|
|
189
235
|
)
|
|
@@ -211,11 +257,13 @@ def calculate_de(
|
|
|
211
257
|
d[ssd_indices],
|
|
212
258
|
)
|
|
213
259
|
e_bin[ssd_indices] = determine_ebin_ssd(
|
|
214
|
-
energy[ssd_indices],
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
260
|
+
energy[ssd_indices],
|
|
261
|
+
tof[ssd_indices],
|
|
262
|
+
r[ssd_indices],
|
|
263
|
+
f"ultra{sensor}",
|
|
264
|
+
ancillary_files,
|
|
218
265
|
)
|
|
266
|
+
species_bin[ssd_indices] = determine_species(e_bin[ssd_indices], "SSD")
|
|
219
267
|
ctof[ssd_indices], magnitude_v[ssd_indices] = get_ctof(
|
|
220
268
|
tof[ssd_indices], r[ssd_indices], "SSD"
|
|
221
269
|
)
|
|
@@ -237,19 +285,26 @@ def calculate_de(
|
|
|
237
285
|
de_dict["phi"] = phi
|
|
238
286
|
de_dict["theta"] = theta
|
|
239
287
|
|
|
240
|
-
|
|
241
|
-
(
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
288
|
+
velocities[valid_indices], v_hat[valid_indices], r_hat[valid_indices] = (
|
|
289
|
+
get_de_velocity(
|
|
290
|
+
(de_dict["x_front"][valid_indices], de_dict["y_front"][valid_indices]),
|
|
291
|
+
(de_dict["x_back"][valid_indices], de_dict["y_back"][valid_indices]),
|
|
292
|
+
de_dict["front_back_distance"][valid_indices],
|
|
293
|
+
de_dict["tof_start_stop"][valid_indices],
|
|
294
|
+
)
|
|
245
295
|
)
|
|
246
|
-
de_dict["
|
|
247
|
-
de_dict["
|
|
248
|
-
de_dict["direct_event_unit_position"] = r.astype(np.float32)
|
|
296
|
+
de_dict["direct_event_unit_velocity"] = v_hat.astype(np.float32)
|
|
297
|
+
de_dict["direct_event_unit_position"] = r_hat.astype(np.float32)
|
|
249
298
|
|
|
250
|
-
|
|
299
|
+
tof_energy[valid_indices] = get_de_energy_kev(
|
|
300
|
+
velocities[valid_indices], species_bin[valid_indices]
|
|
301
|
+
)
|
|
302
|
+
de_dict["tof_energy"] = tof_energy
|
|
251
303
|
de_dict["energy"] = energy
|
|
252
|
-
de_dict["
|
|
304
|
+
de_dict["computed_ebin"] = e_bin
|
|
305
|
+
valid_ebin = de_dataset["bin"].values != FILLVAL_UINT32
|
|
306
|
+
e_bin_l1a[valid_ebin] = de_dataset["bin"].values[valid_ebin]
|
|
307
|
+
de_dict["ebin"] = e_bin_l1a
|
|
253
308
|
de_dict["species"] = species_bin
|
|
254
309
|
|
|
255
310
|
# Annotated Events.
|
|
@@ -264,7 +319,7 @@ def calculate_de(
|
|
|
264
319
|
helio_velocity[valid_events],
|
|
265
320
|
) = get_annotated_particle_velocity(
|
|
266
321
|
event_times[valid_events],
|
|
267
|
-
|
|
322
|
+
velocities.astype(np.float32)[valid_events],
|
|
268
323
|
ultra_frame,
|
|
269
324
|
SpiceFrame.IMAP_DPS,
|
|
270
325
|
SpiceFrame.IMAP_SPACECRAFT,
|
|
@@ -289,20 +344,29 @@ def calculate_de(
|
|
|
289
344
|
de_dict["tof_energy"], de_dict["phi"], de_dict["theta"], ancillary_files
|
|
290
345
|
)
|
|
291
346
|
de_dict["geometric_factor_blades"] = get_geometric_factor(
|
|
292
|
-
ancillary_files,
|
|
293
|
-
"l1b-sensor-gf-blades",
|
|
294
347
|
de_dict["phi"],
|
|
295
348
|
de_dict["theta"],
|
|
296
349
|
quality_flags,
|
|
350
|
+
ancillary_files,
|
|
351
|
+
"l1b-sensor-gf-blades",
|
|
297
352
|
)
|
|
298
353
|
de_dict["geometric_factor_noblades"] = get_geometric_factor(
|
|
299
|
-
ancillary_files,
|
|
300
|
-
"l1b-sensor-gf-noblades",
|
|
301
354
|
de_dict["phi"],
|
|
302
355
|
de_dict["theta"],
|
|
303
356
|
quality_flags,
|
|
357
|
+
ancillary_files,
|
|
358
|
+
"l1b-sensor-gf-noblades",
|
|
359
|
+
)
|
|
360
|
+
de_dict["quality_outliers"] = quality_flags
|
|
361
|
+
flag_scattering(
|
|
362
|
+
de_dict["tof_energy"],
|
|
363
|
+
de_dict["theta"],
|
|
364
|
+
de_dict["phi"],
|
|
365
|
+
ancillary_files,
|
|
366
|
+
sensor,
|
|
367
|
+
scattering_quality_flags,
|
|
304
368
|
)
|
|
305
|
-
de_dict["
|
|
369
|
+
de_dict["quality_scattering"] = scattering_quality_flags
|
|
306
370
|
|
|
307
371
|
dataset = create_dataset(de_dict, name, "l1b")
|
|
308
372
|
|
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
import numpy as np
|
|
4
4
|
import xarray as xr
|
|
5
|
+
from numpy.typing import NDArray
|
|
5
6
|
|
|
6
7
|
from imap_processing.ultra.l1b.ultra_l1b_culling import (
|
|
8
|
+
count_rejected_events_per_spin,
|
|
7
9
|
flag_attitude,
|
|
8
10
|
flag_hk,
|
|
9
11
|
flag_imap_instruments,
|
|
@@ -14,6 +16,7 @@ from imap_processing.ultra.l1b.ultra_l1b_culling import (
|
|
|
14
16
|
from imap_processing.ultra.utils.ultra_l1_utils import create_dataset
|
|
15
17
|
|
|
16
18
|
FILLVAL_UINT16 = 65535
|
|
19
|
+
FILLVAL_FLOAT32 = -1.0e31
|
|
17
20
|
|
|
18
21
|
|
|
19
22
|
def calculate_extendedspin(
|
|
@@ -43,7 +46,7 @@ def calculate_extendedspin(
|
|
|
43
46
|
de_dataset = dict_datasets[f"imap_ultra_l1b_{instrument_id}sensor-de"]
|
|
44
47
|
|
|
45
48
|
extendedspin_dict = {}
|
|
46
|
-
rates_qf, spin,
|
|
49
|
+
rates_qf, spin, energy_bin_geometric_mean, n_sigma_per_energy = flag_rates(
|
|
47
50
|
de_dataset["spin"].values,
|
|
48
51
|
de_dataset["energy"].values,
|
|
49
52
|
)
|
|
@@ -57,34 +60,46 @@ def calculate_extendedspin(
|
|
|
57
60
|
hk_qf = flag_hk(de_dataset["spin"].values)
|
|
58
61
|
inst_qf = flag_imap_instruments(de_dataset["spin"].values)
|
|
59
62
|
|
|
60
|
-
# Get the first epoch for each spin.
|
|
61
|
-
mask = xr.DataArray(np.isin(de_dataset["spin"], spin), dims="epoch")
|
|
62
|
-
filtered_dataset = de_dataset.where(mask, drop=True)
|
|
63
|
-
_, first_indices = np.unique(filtered_dataset["spin"].values, return_index=True)
|
|
64
|
-
first_epochs = filtered_dataset["epoch"].values[first_indices]
|
|
65
|
-
|
|
66
63
|
# Get the number of pulses per spin.
|
|
67
|
-
|
|
64
|
+
pulses = get_pulses_per_spin(rates_dataset)
|
|
68
65
|
|
|
66
|
+
# Track rejected events in each spin based on
|
|
67
|
+
# quality flags in de l1b data.
|
|
68
|
+
rejected_counts = count_rejected_events_per_spin(
|
|
69
|
+
de_dataset["spin"].values,
|
|
70
|
+
de_dataset["quality_scattering"].values,
|
|
71
|
+
de_dataset["quality_outliers"].values,
|
|
72
|
+
)
|
|
69
73
|
# These will be the coordinates.
|
|
70
|
-
extendedspin_dict["epoch"] = first_epochs
|
|
71
74
|
extendedspin_dict["spin_number"] = spin
|
|
72
|
-
extendedspin_dict["energy_bin_geometric_mean"] =
|
|
75
|
+
extendedspin_dict["energy_bin_geometric_mean"] = energy_bin_geometric_mean
|
|
73
76
|
|
|
74
77
|
extendedspin_dict["ena_rates"] = count_rates
|
|
75
78
|
extendedspin_dict["ena_rates_threshold"] = n_sigma_per_energy
|
|
76
79
|
extendedspin_dict["spin_start_time"] = spin_starttime
|
|
77
80
|
extendedspin_dict["spin_period"] = spin_period
|
|
78
81
|
extendedspin_dict["spin_rate"] = spin_rates
|
|
82
|
+
|
|
83
|
+
# Get index of pulses.unique_spins corresponding to each spin.
|
|
84
|
+
idx: NDArray[np.intp] = np.searchsorted(pulses.unique_spins, spin)
|
|
85
|
+
|
|
86
|
+
# Validate that the spin values match
|
|
87
|
+
valid = (idx < pulses.unique_spins.size) & (pulses.unique_spins[idx] == spin)
|
|
88
|
+
|
|
89
|
+
start_per_spin = np.full(len(spin), FILLVAL_FLOAT32, dtype=np.float32)
|
|
90
|
+
stop_per_spin = np.full(len(spin), FILLVAL_FLOAT32, dtype=np.float32)
|
|
91
|
+
coin_per_spin = np.full(len(spin), FILLVAL_FLOAT32, dtype=np.float32)
|
|
92
|
+
|
|
93
|
+
# Fill only the valid ones
|
|
94
|
+
start_per_spin[valid] = pulses.start_per_spin[idx[valid]]
|
|
95
|
+
stop_per_spin[valid] = pulses.stop_per_spin[idx[valid]]
|
|
96
|
+
coin_per_spin[valid] = pulses.coin_per_spin[idx[valid]]
|
|
97
|
+
|
|
98
|
+
# account for rates spins which are not in the direct event spins
|
|
79
99
|
extendedspin_dict["start_pulses_per_spin"] = start_per_spin
|
|
80
100
|
extendedspin_dict["stop_pulses_per_spin"] = stop_per_spin
|
|
81
101
|
extendedspin_dict["coin_pulses_per_spin"] = coin_per_spin
|
|
82
|
-
|
|
83
|
-
# spin based on quality flags in de l1b data.
|
|
84
|
-
extendedspin_dict["rejected_events_per_spin"] = np.full_like(
|
|
85
|
-
spin, FILLVAL_UINT16, dtype=np.uint16
|
|
86
|
-
)
|
|
87
|
-
|
|
102
|
+
extendedspin_dict["rejected_events_per_spin"] = rejected_counts
|
|
88
103
|
extendedspin_dict["quality_attitude"] = attitude_qf
|
|
89
104
|
extendedspin_dict["quality_ena_rates"] = rates_qf
|
|
90
105
|
extendedspin_dict["quality_hk"] = hk_qf
|