imap-processing 0.17.0__py3-none-any.whl → 0.19.0__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/ccsds/excel_to_xtce.py +12 -0
- imap_processing/cdf/config/imap_codice_global_cdf_attrs.yaml +6 -6
- imap_processing/cdf/config/imap_codice_l1a_variable_attrs.yaml +312 -274
- imap_processing/cdf/config/imap_codice_l1b_variable_attrs.yaml +39 -28
- imap_processing/cdf/config/imap_codice_l2_variable_attrs.yaml +1048 -183
- imap_processing/cdf/config/imap_constant_attrs.yaml +4 -2
- imap_processing/cdf/config/imap_glows_l1b_variable_attrs.yaml +12 -0
- 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_hit_l1a_variable_attrs.yaml +163 -100
- imap_processing/cdf/config/imap_hit_l2_variable_attrs.yaml +4 -4
- imap_processing/cdf/config/imap_ialirt_l1_variable_attrs.yaml +97 -54
- imap_processing/cdf/config/imap_idex_l2a_variable_attrs.yaml +33 -4
- imap_processing/cdf/config/imap_idex_l2b_variable_attrs.yaml +44 -44
- imap_processing/cdf/config/imap_idex_l2c_variable_attrs.yaml +77 -61
- imap_processing/cdf/config/imap_lo_global_cdf_attrs.yaml +30 -0
- 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 +99 -2
- imap_processing/cdf/config/imap_mag_l1c_variable_attrs.yaml +24 -1
- imap_processing/cdf/config/imap_ultra_global_cdf_attrs.yaml +60 -0
- imap_processing/cdf/config/imap_ultra_l1b_variable_attrs.yaml +99 -11
- imap_processing/cdf/config/imap_ultra_l1c_variable_attrs.yaml +50 -7
- imap_processing/cli.py +121 -44
- imap_processing/codice/codice_l1a.py +165 -77
- imap_processing/codice/codice_l1b.py +1 -1
- imap_processing/codice/codice_l2.py +118 -19
- imap_processing/codice/constants.py +1217 -1089
- imap_processing/decom.py +1 -4
- imap_processing/ena_maps/ena_maps.py +32 -25
- 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 +99 -9
- imap_processing/glows/l1b/glows_l1b_data.py +350 -38
- 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_l2.py +84 -51
- imap_processing/hi/utils.py +153 -8
- imap_processing/hit/l0/constants.py +3 -0
- imap_processing/hit/l0/decom_hit.py +5 -8
- imap_processing/hit/l1a/hit_l1a.py +375 -45
- imap_processing/hit/l1b/constants.py +5 -0
- imap_processing/hit/l1b/hit_l1b.py +61 -131
- imap_processing/hit/l2/constants.py +1 -1
- imap_processing/hit/l2/hit_l2.py +10 -11
- imap_processing/ialirt/calculate_ingest.py +219 -0
- imap_processing/ialirt/constants.py +32 -1
- imap_processing/ialirt/generate_coverage.py +201 -0
- imap_processing/ialirt/l0/ialirt_spice.py +5 -2
- imap_processing/ialirt/l0/parse_mag.py +337 -29
- imap_processing/ialirt/l0/process_hit.py +5 -3
- imap_processing/ialirt/l0/process_swapi.py +41 -25
- imap_processing/ialirt/l0/process_swe.py +23 -7
- imap_processing/ialirt/process_ephemeris.py +70 -14
- imap_processing/ialirt/utils/constants.py +22 -16
- imap_processing/ialirt/utils/create_xarray.py +42 -19
- imap_processing/idex/idex_constants.py +1 -5
- 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 +313 -119
- imap_processing/idex/idex_utils.py +1 -3
- imap_processing/lo/l0/lo_apid.py +1 -0
- imap_processing/lo/l0/lo_science.py +25 -24
- imap_processing/lo/l1a/lo_l1a.py +44 -0
- imap_processing/lo/l1b/lo_l1b.py +3 -3
- imap_processing/lo/l1c/lo_l1c.py +116 -50
- imap_processing/lo/l2/lo_l2.py +29 -29
- imap_processing/lo/lo_ancillary.py +55 -0
- imap_processing/lo/packet_definitions/lo_xtce.xml +5359 -106
- imap_processing/mag/constants.py +1 -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/__init__.py +0 -0
- imap_processing/mag/l1d/mag_l1d.py +176 -0
- imap_processing/mag/l1d/mag_l1d_data.py +725 -0
- imap_processing/mag/l2/__init__.py +0 -0
- imap_processing/mag/l2/mag_l2.py +25 -20
- imap_processing/mag/l2/mag_l2_data.py +199 -130
- imap_processing/quality_flags.py +28 -2
- imap_processing/spice/geometry.py +101 -36
- imap_processing/spice/pointing_frame.py +1 -7
- imap_processing/spice/repoint.py +29 -2
- imap_processing/spice/spin.py +32 -8
- imap_processing/spice/time.py +60 -19
- imap_processing/swapi/l1/swapi_l1.py +10 -4
- imap_processing/swapi/l2/swapi_l2.py +66 -24
- imap_processing/swapi/swapi_utils.py +1 -1
- imap_processing/swe/l1b/swe_l1b.py +3 -6
- imap_processing/ultra/constants.py +28 -3
- imap_processing/ultra/l0/decom_tools.py +15 -8
- imap_processing/ultra/l0/decom_ultra.py +35 -11
- imap_processing/ultra/l0/ultra_utils.py +102 -12
- imap_processing/ultra/l1a/ultra_l1a.py +26 -6
- imap_processing/ultra/l1b/cullingmask.py +6 -3
- imap_processing/ultra/l1b/de.py +122 -26
- imap_processing/ultra/l1b/extendedspin.py +29 -2
- imap_processing/ultra/l1b/lookup_utils.py +424 -50
- imap_processing/ultra/l1b/quality_flag_filters.py +23 -0
- imap_processing/ultra/l1b/ultra_l1b_culling.py +356 -5
- imap_processing/ultra/l1b/ultra_l1b_extended.py +534 -90
- imap_processing/ultra/l1c/helio_pset.py +127 -7
- imap_processing/ultra/l1c/l1c_lookup_utils.py +256 -0
- imap_processing/ultra/l1c/spacecraft_pset.py +90 -15
- imap_processing/ultra/l1c/ultra_l1c.py +6 -0
- imap_processing/ultra/l1c/ultra_l1c_culling.py +85 -0
- imap_processing/ultra/l1c/ultra_l1c_pset_bins.py +446 -341
- imap_processing/ultra/l2/ultra_l2.py +0 -1
- imap_processing/ultra/utils/ultra_l1_utils.py +40 -3
- imap_processing/utils.py +3 -4
- {imap_processing-0.17.0.dist-info → imap_processing-0.19.0.dist-info}/METADATA +3 -3
- {imap_processing-0.17.0.dist-info → imap_processing-0.19.0.dist-info}/RECORD +126 -126
- imap_processing/idex/idex_l2c.py +0 -250
- imap_processing/spice/kernels.py +0 -187
- imap_processing/ultra/lookup_tables/Angular_Profiles_FM45_LeftSlit.csv +0 -526
- imap_processing/ultra/lookup_tables/Angular_Profiles_FM45_RightSlit.csv +0 -526
- imap_processing/ultra/lookup_tables/Angular_Profiles_FM90_LeftSlit.csv +0 -526
- imap_processing/ultra/lookup_tables/Angular_Profiles_FM90_RightSlit.csv +0 -524
- imap_processing/ultra/lookup_tables/EgyNorm.mem.csv +0 -32769
- imap_processing/ultra/lookup_tables/FM45_Startup1_ULTRA_IMGPARAMS_20240719.csv +0 -2
- imap_processing/ultra/lookup_tables/FM90_Startup1_ULTRA_IMGPARAMS_20240719.csv +0 -2
- imap_processing/ultra/lookup_tables/dps_grid45_compressed.cdf +0 -0
- imap_processing/ultra/lookup_tables/ultra45_back-pos-luts.csv +0 -4097
- imap_processing/ultra/lookup_tables/ultra45_tdc_norm.csv +0 -2050
- imap_processing/ultra/lookup_tables/ultra90_back-pos-luts.csv +0 -4097
- imap_processing/ultra/lookup_tables/ultra90_tdc_norm.csv +0 -2050
- imap_processing/ultra/lookup_tables/yadjust.csv +0 -257
- {imap_processing-0.17.0.dist-info → imap_processing-0.19.0.dist-info}/LICENSE +0 -0
- {imap_processing-0.17.0.dist-info → imap_processing-0.19.0.dist-info}/WHEEL +0 -0
- {imap_processing-0.17.0.dist-info → imap_processing-0.19.0.dist-info}/entry_points.txt +0 -0
|
@@ -11,15 +11,12 @@ Paradigms for developing this module:
|
|
|
11
11
|
|
|
12
12
|
import typing
|
|
13
13
|
from enum import IntEnum
|
|
14
|
-
from typing import Union
|
|
15
14
|
|
|
16
15
|
import numpy as np
|
|
17
16
|
import numpy.typing as npt
|
|
18
17
|
import spiceypy
|
|
19
18
|
from numpy.typing import NDArray
|
|
20
19
|
|
|
21
|
-
from imap_processing.spice.kernels import ensure_spice
|
|
22
|
-
|
|
23
20
|
|
|
24
21
|
class SpiceBody(IntEnum):
|
|
25
22
|
"""Enum containing SPICE IDs for bodies that we use."""
|
|
@@ -27,7 +24,7 @@ class SpiceBody(IntEnum):
|
|
|
27
24
|
# A subset of IMAP Specific bodies as defined in imap_wkcp.tf
|
|
28
25
|
IMAP = -43
|
|
29
26
|
IMAP_SPACECRAFT = -43000
|
|
30
|
-
# IMAP Pointing Frame (Despun) as defined in
|
|
27
|
+
# IMAP Pointing Frame (Despun) as defined in imap_science_xxx.tf
|
|
31
28
|
IMAP_DPS = -43901
|
|
32
29
|
# Standard NAIF bodies
|
|
33
30
|
SOLAR_SYSTEM_BARYCENTER = spiceypy.bodn2c("SOLAR_SYSTEM_BARYCENTER")
|
|
@@ -36,13 +33,13 @@ class SpiceBody(IntEnum):
|
|
|
36
33
|
|
|
37
34
|
|
|
38
35
|
class SpiceFrame(IntEnum):
|
|
39
|
-
"""
|
|
36
|
+
"""SPICE IDs for reference frames in imap_wkcp.tf and imap_science_xxx.tf."""
|
|
40
37
|
|
|
41
38
|
# Standard SPICE Frames
|
|
42
39
|
J2000 = spiceypy.irfnum("J2000")
|
|
43
40
|
ECLIPJ2000 = spiceypy.irfnum("ECLIPJ2000")
|
|
44
41
|
ITRF93 = 13000
|
|
45
|
-
# IMAP Pointing Frame (Despun) as defined in
|
|
42
|
+
# IMAP Pointing Frame (Despun) as defined in imap_science_xxx.tf
|
|
46
43
|
IMAP_DPS = -43901
|
|
47
44
|
# IMAP specific as defined in imap_wkcp.tf
|
|
48
45
|
IMAP_SPACECRAFT = -43000
|
|
@@ -61,6 +58,28 @@ class SpiceFrame(IntEnum):
|
|
|
61
58
|
IMAP_IDEX = -43700
|
|
62
59
|
IMAP_GLOWS = -43750
|
|
63
60
|
|
|
61
|
+
# IMAP Science Frames (new additions from imap_science_xxx.tf)
|
|
62
|
+
IMAP_OMD = -43900
|
|
63
|
+
IMAP_EARTHFIXED = -43910
|
|
64
|
+
IMAP_ECLIPDATE = -43911
|
|
65
|
+
IMAP_MDI = -43912
|
|
66
|
+
IMAP_MDR = -43913
|
|
67
|
+
IMAP_GMC = -43914
|
|
68
|
+
IMAP_GEI = -43915
|
|
69
|
+
IMAP_GSE = -43916
|
|
70
|
+
IMAP_GSM = -43917
|
|
71
|
+
IMAP_SMD = -43918
|
|
72
|
+
IMAP_RTN = -43920
|
|
73
|
+
IMAP_HCI = -43921 # HGI_J2K
|
|
74
|
+
IMAP_HCD = -43922 # HGI_D
|
|
75
|
+
IMAP_HGC = -43923 # HGS_D
|
|
76
|
+
IMAP_HAE = -43924
|
|
77
|
+
IMAP_HAED = -43925
|
|
78
|
+
IMAP_HEE = -43926
|
|
79
|
+
IMAP_HRE = -43927
|
|
80
|
+
IMAP_HNU = -43928
|
|
81
|
+
IMAP_GCS = -43929
|
|
82
|
+
|
|
64
83
|
|
|
65
84
|
BORESIGHT_LOOKUP = {
|
|
66
85
|
SpiceFrame.IMAP_LO_BASE: np.array([0, -1, 0]),
|
|
@@ -78,10 +97,8 @@ BORESIGHT_LOOKUP = {
|
|
|
78
97
|
}
|
|
79
98
|
|
|
80
99
|
|
|
81
|
-
@typing.no_type_check
|
|
82
|
-
@ensure_spice
|
|
83
100
|
def imap_state(
|
|
84
|
-
et:
|
|
101
|
+
et: np.ndarray | float,
|
|
85
102
|
ref_frame: SpiceFrame = SpiceFrame.ECLIPJ2000,
|
|
86
103
|
abcorr: str = "NONE",
|
|
87
104
|
observer: SpiceBody = SpiceBody.SUN,
|
|
@@ -115,14 +132,65 @@ def imap_state(
|
|
|
115
132
|
return np.asarray(state)
|
|
116
133
|
|
|
117
134
|
|
|
135
|
+
def get_instrument_mounting_az_el(instrument: SpiceFrame) -> np.ndarray:
|
|
136
|
+
"""
|
|
137
|
+
Calculate the azimuth and elevation angle of instrument mounting.
|
|
138
|
+
|
|
139
|
+
Azimuth and elevation to instrument mounting in the spacecraft frame.
|
|
140
|
+
Azimuth is measured in degrees from the spacecraft x-axis. Elevation is measured
|
|
141
|
+
in degrees from the spacecraft x-y plane.
|
|
142
|
+
|
|
143
|
+
Parameters
|
|
144
|
+
----------
|
|
145
|
+
instrument : SpiceFrame
|
|
146
|
+
Instrument to get the azimuth and elevation angles for.
|
|
147
|
+
|
|
148
|
+
Returns
|
|
149
|
+
-------
|
|
150
|
+
instrument_mounting_az_el : np.ndarray
|
|
151
|
+
2-element array containing azimuth and elevation of the instrument
|
|
152
|
+
mounting in the spacecraft frame. Azimuth is measured in degrees from
|
|
153
|
+
the spacecraft x-axis. Elevation is measured in degrees from the
|
|
154
|
+
spacecraft x-y plane.
|
|
155
|
+
"""
|
|
156
|
+
# Each instrument can have a unique basis vector in the instrument
|
|
157
|
+
# frame that is used to compute the s/c to instrument mounting.
|
|
158
|
+
# Most of these vectors are the same as the instrument boresight vector.
|
|
159
|
+
mounting_normal_vector = {
|
|
160
|
+
SpiceFrame.IMAP_LO_BASE: np.array([0, -1, 0]),
|
|
161
|
+
SpiceFrame.IMAP_HI_45: np.array([0, 1, 0]),
|
|
162
|
+
SpiceFrame.IMAP_HI_90: np.array([0, 1, 0]),
|
|
163
|
+
SpiceFrame.IMAP_ULTRA_45: np.array([0, 0, 1]),
|
|
164
|
+
SpiceFrame.IMAP_ULTRA_90: np.array([0, 0, 1]),
|
|
165
|
+
SpiceFrame.IMAP_MAG: np.array([-1, 0, 0]),
|
|
166
|
+
SpiceFrame.IMAP_SWE: np.array([-1, 0, 0]),
|
|
167
|
+
SpiceFrame.IMAP_SWAPI: np.array([0, 0, -1]),
|
|
168
|
+
SpiceFrame.IMAP_CODICE: np.array([-1, 0, 0]),
|
|
169
|
+
SpiceFrame.IMAP_HIT: np.array([0, 1, 0]),
|
|
170
|
+
SpiceFrame.IMAP_IDEX: np.array([0, 1, 0]),
|
|
171
|
+
SpiceFrame.IMAP_GLOWS: np.array([0, 0, -1]),
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
# Get the instrument mounting normal vector expressed in the spacecraft frame
|
|
175
|
+
# The reference frames are fixed, so the et argument can be fixed at 0
|
|
176
|
+
instrument_normal_sc = frame_transform(
|
|
177
|
+
0, mounting_normal_vector[instrument], instrument, SpiceFrame.IMAP_SPACECRAFT
|
|
178
|
+
)
|
|
179
|
+
# Convert the cartesian coordinate to azimuth/elevation angles in degrees
|
|
180
|
+
return np.rad2deg(
|
|
181
|
+
spiceypy.recazl(instrument_normal_sc, azccw=True, elplsz=True)[1:]
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
|
|
118
185
|
def get_spacecraft_to_instrument_spin_phase_offset(instrument: SpiceFrame) -> float:
|
|
119
186
|
"""
|
|
120
187
|
Get the spin phase offset from the spacecraft to the instrument.
|
|
121
188
|
|
|
122
189
|
For now, the offset is a fixed lookup based on `Table 1: Nominal Instrument
|
|
123
|
-
to S/C CS Transformations` in document `7516-0011_drw.pdf`.
|
|
124
|
-
|
|
125
|
-
|
|
190
|
+
to S/C CS Transformations` in document `7516-0011_drw.pdf`. That Table
|
|
191
|
+
defines the angle from the spacecraft y-axis. We add 90 and take the modulous
|
|
192
|
+
with 360 in order to get the angle from the spacecraft x-axis. These fixed
|
|
193
|
+
values will need to be updated based on calibration data.
|
|
126
194
|
|
|
127
195
|
Parameters
|
|
128
196
|
----------
|
|
@@ -134,26 +202,25 @@ def get_spacecraft_to_instrument_spin_phase_offset(instrument: SpiceFrame) -> fl
|
|
|
134
202
|
spacecraft_to_instrument_spin_phase_offset : float
|
|
135
203
|
The spin phase offset from the spacecraft to the instrument.
|
|
136
204
|
"""
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
SpiceFrame.
|
|
140
|
-
SpiceFrame.
|
|
141
|
-
SpiceFrame.
|
|
142
|
-
SpiceFrame.
|
|
143
|
-
SpiceFrame.
|
|
144
|
-
SpiceFrame.
|
|
145
|
-
SpiceFrame.
|
|
146
|
-
SpiceFrame.
|
|
147
|
-
SpiceFrame.
|
|
148
|
-
SpiceFrame.
|
|
149
|
-
SpiceFrame.
|
|
150
|
-
SpiceFrame.IMAP_MAG: 0 / 360,
|
|
205
|
+
phase_offset_lookup = {
|
|
206
|
+
SpiceFrame.IMAP_LO_BASE: 60 / 360, # (330 + 90) % 360 = 60
|
|
207
|
+
SpiceFrame.IMAP_HI_45: 345 / 360, # 255 + 90 = 345
|
|
208
|
+
SpiceFrame.IMAP_HI_90: 15 / 360, # (285 + 90) % 360 = 15
|
|
209
|
+
SpiceFrame.IMAP_ULTRA_45: 123 / 360, # 33 + 90 = 123
|
|
210
|
+
SpiceFrame.IMAP_ULTRA_90: 300 / 360, # 210 + 90 = 300
|
|
211
|
+
SpiceFrame.IMAP_SWAPI: 258 / 360, # 168 + 90 = 258
|
|
212
|
+
SpiceFrame.IMAP_IDEX: 180 / 360, # 90 + 90 = 180
|
|
213
|
+
SpiceFrame.IMAP_CODICE: 226 / 360, # 136 + 90 = 226
|
|
214
|
+
SpiceFrame.IMAP_HIT: 120 / 360, # 30 + 90 = 120
|
|
215
|
+
SpiceFrame.IMAP_SWE: 243 / 360, # 153 + 90 = 243
|
|
216
|
+
SpiceFrame.IMAP_GLOWS: 217 / 360, # 127 + 90 = 217
|
|
217
|
+
SpiceFrame.IMAP_MAG: 90 / 360, # 0 + 90 = 90
|
|
151
218
|
}
|
|
152
|
-
return
|
|
219
|
+
return phase_offset_lookup[instrument]
|
|
153
220
|
|
|
154
221
|
|
|
155
222
|
def frame_transform(
|
|
156
|
-
et:
|
|
223
|
+
et: float | npt.NDArray,
|
|
157
224
|
position: npt.NDArray,
|
|
158
225
|
from_frame: SpiceFrame,
|
|
159
226
|
to_frame: SpiceFrame,
|
|
@@ -227,7 +294,7 @@ def frame_transform(
|
|
|
227
294
|
|
|
228
295
|
|
|
229
296
|
def frame_transform_az_el(
|
|
230
|
-
et:
|
|
297
|
+
et: float | npt.NDArray,
|
|
231
298
|
az_el: npt.NDArray,
|
|
232
299
|
from_frame: SpiceFrame,
|
|
233
300
|
to_frame: SpiceFrame,
|
|
@@ -276,10 +343,8 @@ def frame_transform_az_el(
|
|
|
276
343
|
return to_frame_az_el[..., 1:3]
|
|
277
344
|
|
|
278
345
|
|
|
279
|
-
@typing.no_type_check
|
|
280
|
-
@ensure_spice
|
|
281
346
|
def get_rotation_matrix(
|
|
282
|
-
et:
|
|
347
|
+
et: float | npt.NDArray,
|
|
283
348
|
from_frame: SpiceFrame,
|
|
284
349
|
to_frame: SpiceFrame,
|
|
285
350
|
) -> npt.NDArray:
|
|
@@ -317,7 +382,7 @@ def get_rotation_matrix(
|
|
|
317
382
|
|
|
318
383
|
|
|
319
384
|
def instrument_pointing(
|
|
320
|
-
et:
|
|
385
|
+
et: float | npt.NDArray,
|
|
321
386
|
instrument: SpiceFrame,
|
|
322
387
|
to_frame: SpiceFrame,
|
|
323
388
|
cartesian: bool = False,
|
|
@@ -355,7 +420,7 @@ def instrument_pointing(
|
|
|
355
420
|
|
|
356
421
|
|
|
357
422
|
def basis_vectors(
|
|
358
|
-
et:
|
|
423
|
+
et: float | npt.NDArray,
|
|
359
424
|
from_frame: SpiceFrame,
|
|
360
425
|
to_frame: SpiceFrame,
|
|
361
426
|
) -> npt.NDArray:
|
|
@@ -528,9 +593,9 @@ def cartesian_to_latitudinal(coords: NDArray, degrees: bool = True) -> NDArray:
|
|
|
528
593
|
|
|
529
594
|
|
|
530
595
|
def solar_longitude(
|
|
531
|
-
et:
|
|
596
|
+
et: np.ndarray | float,
|
|
532
597
|
degrees: bool = True,
|
|
533
|
-
) ->
|
|
598
|
+
) -> float | npt.NDArray:
|
|
534
599
|
"""
|
|
535
600
|
Compute the solar longitude of the Imap Spacecraft.
|
|
536
601
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"""Functions for retrieving repointing table data."""
|
|
2
2
|
|
|
3
3
|
import logging
|
|
4
|
-
import typing
|
|
5
4
|
from collections.abc import Generator
|
|
6
5
|
from contextlib import contextmanager
|
|
7
6
|
from datetime import datetime, timezone
|
|
@@ -13,7 +12,6 @@ from imap_data_access import SPICEFilePath
|
|
|
13
12
|
from numpy.typing import NDArray
|
|
14
13
|
|
|
15
14
|
from imap_processing.spice.geometry import SpiceFrame
|
|
16
|
-
from imap_processing.spice.kernels import ensure_spice
|
|
17
15
|
from imap_processing.spice.repoint import get_repoint_data
|
|
18
16
|
from imap_processing.spice.time import (
|
|
19
17
|
TICK_DURATION,
|
|
@@ -164,8 +162,6 @@ def write_pointing_frame_ck(
|
|
|
164
162
|
)
|
|
165
163
|
|
|
166
164
|
|
|
167
|
-
@typing.no_type_check
|
|
168
|
-
@ensure_spice
|
|
169
165
|
def calculate_pointing_attitude_segments(
|
|
170
166
|
ck_path: Path,
|
|
171
167
|
) -> NDArray:
|
|
@@ -200,7 +196,7 @@ def calculate_pointing_attitude_segments(
|
|
|
200
196
|
- Latest NAIF leapseconds kernel (naif0012.tls)
|
|
201
197
|
- The latest IMAP sclk (imap_sclk_NNNN.tsc)
|
|
202
198
|
- The latest IMAP frame kernel (imap_wkcp.tf)
|
|
203
|
-
- IMAP DPS frame kernel (
|
|
199
|
+
- IMAP DPS frame kernel (imap_science_100.tf)
|
|
204
200
|
- IMAP historical attitude kernel from which the pointing frame kernel will
|
|
205
201
|
be generated.
|
|
206
202
|
"""
|
|
@@ -292,8 +288,6 @@ def calculate_pointing_attitude_segments(
|
|
|
292
288
|
return pointing_segments
|
|
293
289
|
|
|
294
290
|
|
|
295
|
-
@typing.no_type_check
|
|
296
|
-
@ensure_spice
|
|
297
291
|
def _average_quaternions(et_times: np.ndarray) -> NDArray:
|
|
298
292
|
"""
|
|
299
293
|
Average the quaternions.
|
imap_processing/spice/repoint.py
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
import functools
|
|
4
4
|
import logging
|
|
5
5
|
from pathlib import Path
|
|
6
|
-
from typing import Union
|
|
7
6
|
|
|
8
7
|
import numpy as np
|
|
9
8
|
import pandas as pd
|
|
@@ -113,7 +112,7 @@ def _load_repoint_data_with_cache(csv_path: Path) -> pd.DataFrame:
|
|
|
113
112
|
|
|
114
113
|
|
|
115
114
|
def interpolate_repoint_data(
|
|
116
|
-
query_met_times:
|
|
115
|
+
query_met_times: float | npt.NDArray,
|
|
117
116
|
) -> pd.DataFrame:
|
|
118
117
|
"""
|
|
119
118
|
Interpolate repointing data to the queried MET times.
|
|
@@ -194,3 +193,31 @@ def interpolate_repoint_data(
|
|
|
194
193
|
out_df["repoint_in_progress"] = query_met_times < out_df["repoint_end_met"].values
|
|
195
194
|
|
|
196
195
|
return out_df
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def get_pointing_times(met_time: float) -> tuple[float, float]:
|
|
199
|
+
"""
|
|
200
|
+
Get the start and end MET times for the pointing that contains the query MET time.
|
|
201
|
+
|
|
202
|
+
Parameters
|
|
203
|
+
----------
|
|
204
|
+
met_time : float
|
|
205
|
+
The MET time in a pointing.
|
|
206
|
+
|
|
207
|
+
Returns
|
|
208
|
+
-------
|
|
209
|
+
pointing_start_time : float
|
|
210
|
+
The MET time of the repoint maneuver that ends before the query MET time.
|
|
211
|
+
pointing_end_time : float
|
|
212
|
+
The MET time of the repoint maneuver that starts after the query MET time.
|
|
213
|
+
"""
|
|
214
|
+
# Find the pointing start time by finding the repoint end time
|
|
215
|
+
repoint_df = interpolate_repoint_data(met_time)
|
|
216
|
+
pointing_start_met = repoint_df["repoint_end_met"].item()
|
|
217
|
+
# Find the pointing end time by finding the next repoint start time
|
|
218
|
+
repoint_df = get_repoint_data()
|
|
219
|
+
pointing_idx = repoint_df.index[
|
|
220
|
+
repoint_df["repoint_end_met"] == pointing_start_met
|
|
221
|
+
][0]
|
|
222
|
+
pointing_end_met = repoint_df["repoint_start_met"].iloc[pointing_idx + 1].item()
|
|
223
|
+
return pointing_start_met, pointing_end_met
|
imap_processing/spice/spin.py
CHANGED
|
@@ -4,7 +4,6 @@ import functools
|
|
|
4
4
|
import logging
|
|
5
5
|
from functools import reduce
|
|
6
6
|
from pathlib import Path
|
|
7
|
-
from typing import Union
|
|
8
7
|
|
|
9
8
|
import numpy as np
|
|
10
9
|
import pandas as pd
|
|
@@ -129,7 +128,7 @@ def _load_spin_data_with_cache(csv_paths: tuple[Path]) -> pd.DataFrame:
|
|
|
129
128
|
return combined_df
|
|
130
129
|
|
|
131
130
|
|
|
132
|
-
def interpolate_spin_data(query_met_times:
|
|
131
|
+
def interpolate_spin_data(query_met_times: float | npt.NDArray) -> pd.DataFrame:
|
|
133
132
|
"""
|
|
134
133
|
Interpolate spin table data to the queried MET times.
|
|
135
134
|
|
|
@@ -197,6 +196,10 @@ def interpolate_spin_data(query_met_times: Union[float, npt.NDArray]) -> pd.Data
|
|
|
197
196
|
# spin_period_valid columns.
|
|
198
197
|
invalid_spin_phase_range = (spin_phases < 0) | (spin_phases >= 1)
|
|
199
198
|
|
|
199
|
+
# TODO: add optional to filter this if this flag means
|
|
200
|
+
# that repointing is happening. otherwise, then keep it.
|
|
201
|
+
# This needs to be discussed and receive guidance at
|
|
202
|
+
# the project level.
|
|
200
203
|
invalid_spins = (out_df["spin_phase_valid"].values == 0) | (
|
|
201
204
|
out_df["spin_period_valid"].values == 0
|
|
202
205
|
)
|
|
@@ -209,10 +212,31 @@ def interpolate_spin_data(query_met_times: Union[float, npt.NDArray]) -> pd.Data
|
|
|
209
212
|
return out_df
|
|
210
213
|
|
|
211
214
|
|
|
215
|
+
def get_spin_number(met_time: float) -> int:
|
|
216
|
+
"""
|
|
217
|
+
Get the spin number for the input query time.
|
|
218
|
+
|
|
219
|
+
The spin number is the index of the spin table row that contains the
|
|
220
|
+
spin data for the input query time.
|
|
221
|
+
|
|
222
|
+
Parameters
|
|
223
|
+
----------
|
|
224
|
+
met_time : float
|
|
225
|
+
Query time in Mission Elapsed Time (MET).
|
|
226
|
+
|
|
227
|
+
Returns
|
|
228
|
+
-------
|
|
229
|
+
spin_number : int
|
|
230
|
+
Spin number for the input query time.
|
|
231
|
+
"""
|
|
232
|
+
spin_df = interpolate_spin_data(met_time)
|
|
233
|
+
return spin_df["spin_number"].item()
|
|
234
|
+
|
|
235
|
+
|
|
212
236
|
def get_spin_angle(
|
|
213
|
-
spin_phases:
|
|
237
|
+
spin_phases: float | npt.NDArray,
|
|
214
238
|
degrees: bool = False,
|
|
215
|
-
) ->
|
|
239
|
+
) -> float | npt.NDArray:
|
|
216
240
|
"""
|
|
217
241
|
Convert spin_phases to radians or degrees.
|
|
218
242
|
|
|
@@ -245,8 +269,8 @@ def get_spin_angle(
|
|
|
245
269
|
|
|
246
270
|
|
|
247
271
|
def get_spacecraft_spin_phase(
|
|
248
|
-
query_met_times:
|
|
249
|
-
) ->
|
|
272
|
+
query_met_times: float | npt.NDArray,
|
|
273
|
+
) -> float | npt.NDArray:
|
|
250
274
|
"""
|
|
251
275
|
Get the spacecraft spin phase for the input query times.
|
|
252
276
|
|
|
@@ -270,8 +294,8 @@ def get_spacecraft_spin_phase(
|
|
|
270
294
|
|
|
271
295
|
|
|
272
296
|
def get_instrument_spin_phase(
|
|
273
|
-
query_met_times:
|
|
274
|
-
) ->
|
|
297
|
+
query_met_times: float | npt.NDArray, instrument: SpiceFrame
|
|
298
|
+
) -> float | npt.NDArray:
|
|
275
299
|
"""
|
|
276
300
|
Get the instrument spin phase for the input query times.
|
|
277
301
|
|
imap_processing/spice/time.py
CHANGED
|
@@ -3,14 +3,12 @@
|
|
|
3
3
|
import typing
|
|
4
4
|
from collections.abc import Collection, Iterable
|
|
5
5
|
from datetime import datetime
|
|
6
|
-
from typing import Union
|
|
7
6
|
|
|
8
7
|
import numpy as np
|
|
9
8
|
import numpy.typing as npt
|
|
10
9
|
import spiceypy
|
|
11
10
|
|
|
12
11
|
from imap_processing.spice import IMAP_SC_ID
|
|
13
|
-
from imap_processing.spice.kernels import ensure_spice
|
|
14
12
|
|
|
15
13
|
TICK_DURATION = 2e-5 # 20 microseconds as defined in imap_sclk_0000.tsc
|
|
16
14
|
|
|
@@ -103,7 +101,6 @@ def met_to_ttj2000ns(
|
|
|
103
101
|
|
|
104
102
|
|
|
105
103
|
@typing.no_type_check
|
|
106
|
-
@ensure_spice
|
|
107
104
|
def ttj2000ns_to_et(tt_ns: npt.ArrayLike) -> npt.NDArray[float]:
|
|
108
105
|
"""
|
|
109
106
|
Convert TT J2000 epoch nanoseconds to TDB J2000 epoch seconds.
|
|
@@ -131,7 +128,6 @@ def ttj2000ns_to_et(tt_ns: npt.ArrayLike) -> npt.NDArray[float]:
|
|
|
131
128
|
|
|
132
129
|
|
|
133
130
|
@typing.no_type_check
|
|
134
|
-
@ensure_spice
|
|
135
131
|
def et_to_ttj2000ns(et: npt.ArrayLike) -> npt.NDArray[float]:
|
|
136
132
|
"""
|
|
137
133
|
Convert TDB J2000 epoch seconds to TT J2000 epoch nanoseconds.
|
|
@@ -157,7 +153,6 @@ def et_to_ttj2000ns(et: npt.ArrayLike) -> npt.NDArray[float]:
|
|
|
157
153
|
|
|
158
154
|
|
|
159
155
|
@typing.no_type_check
|
|
160
|
-
@ensure_spice(time_kernels_only=True)
|
|
161
156
|
def met_to_utc(met: npt.ArrayLike, precision: int = 9) -> npt.NDArray[str]:
|
|
162
157
|
"""
|
|
163
158
|
Convert mission elapsed time (MET) to UTC.
|
|
@@ -184,7 +179,7 @@ def met_to_utc(met: npt.ArrayLike, precision: int = 9) -> npt.NDArray[str]:
|
|
|
184
179
|
|
|
185
180
|
def met_to_datetime64(
|
|
186
181
|
met: npt.ArrayLike,
|
|
187
|
-
) ->
|
|
182
|
+
) -> np.datetime64 | npt.NDArray[np.datetime64]:
|
|
188
183
|
"""
|
|
189
184
|
Convert mission elapsed time (MET) to datetime.datetime.
|
|
190
185
|
|
|
@@ -203,7 +198,7 @@ def met_to_datetime64(
|
|
|
203
198
|
|
|
204
199
|
def et_to_datetime64(
|
|
205
200
|
et: npt.ArrayLike,
|
|
206
|
-
) ->
|
|
201
|
+
) -> np.datetime64 | npt.NDArray[np.datetime64]:
|
|
207
202
|
"""
|
|
208
203
|
Convert ET to numpy datetime64.
|
|
209
204
|
|
|
@@ -221,10 +216,59 @@ def et_to_datetime64(
|
|
|
221
216
|
|
|
222
217
|
|
|
223
218
|
@typing.no_type_check
|
|
224
|
-
|
|
219
|
+
def et_to_met(
|
|
220
|
+
et: float | Collection[float],
|
|
221
|
+
) -> float | np.ndarray:
|
|
222
|
+
"""
|
|
223
|
+
Convert ephemeris time to mission elapsed time (MET).
|
|
224
|
+
|
|
225
|
+
This function converts ET to spacecraft clock ticks and then to MET seconds.
|
|
226
|
+
This is the inverse of the MET to ET conversion process.
|
|
227
|
+
|
|
228
|
+
Parameters
|
|
229
|
+
----------
|
|
230
|
+
et : Union[float, Collection[float]]
|
|
231
|
+
Input ephemeris time value(s) to be converted to MET.
|
|
232
|
+
|
|
233
|
+
Returns
|
|
234
|
+
-------
|
|
235
|
+
met: np.ndarray
|
|
236
|
+
Mission elapsed time in seconds.
|
|
237
|
+
"""
|
|
238
|
+
vectorized_sce2c = _vectorize(spiceypy.sce2c, otypes=[float], excluded=[0])
|
|
239
|
+
sclk_ticks = vectorized_sce2c(IMAP_SC_ID, et)
|
|
240
|
+
met = np.asarray(sclk_ticks, dtype=float) * TICK_DURATION
|
|
241
|
+
return met
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def ttj2000ns_to_met(
|
|
245
|
+
tt_ns: npt.ArrayLike,
|
|
246
|
+
) -> npt.NDArray[float]:
|
|
247
|
+
"""
|
|
248
|
+
Convert terrestrial time nanoseconds since J2000 to mission elapsed time (MET).
|
|
249
|
+
|
|
250
|
+
This is the inverse of met_to_ttj2000ns. The conversion process is:
|
|
251
|
+
TTJ2000ns -> ET -> MET
|
|
252
|
+
|
|
253
|
+
Parameters
|
|
254
|
+
----------
|
|
255
|
+
tt_ns : float, numpy.ndarray
|
|
256
|
+
Number of nanoseconds since the J2000 epoch in the TT timescale.
|
|
257
|
+
|
|
258
|
+
Returns
|
|
259
|
+
-------
|
|
260
|
+
numpy.ndarray[float]
|
|
261
|
+
The mission elapsed time in seconds.
|
|
262
|
+
"""
|
|
263
|
+
et = ttj2000ns_to_et(tt_ns)
|
|
264
|
+
met = et_to_met(et)
|
|
265
|
+
return met
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
@typing.no_type_check
|
|
225
269
|
def sct_to_et(
|
|
226
|
-
sclk_ticks:
|
|
227
|
-
) ->
|
|
270
|
+
sclk_ticks: float | Collection[float],
|
|
271
|
+
) -> float | np.ndarray:
|
|
228
272
|
"""
|
|
229
273
|
Convert encoded spacecraft clock "ticks" to ephemeris time.
|
|
230
274
|
|
|
@@ -247,10 +291,9 @@ def sct_to_et(
|
|
|
247
291
|
|
|
248
292
|
|
|
249
293
|
@typing.no_type_check
|
|
250
|
-
@ensure_spice
|
|
251
294
|
def sct_to_ttj2000s(
|
|
252
|
-
sclk_ticks:
|
|
253
|
-
) ->
|
|
295
|
+
sclk_ticks: float | Iterable[float],
|
|
296
|
+
) -> float | np.ndarray:
|
|
254
297
|
"""
|
|
255
298
|
Convert encoded spacecraft clock "ticks" to terrestrial time (TT).
|
|
256
299
|
|
|
@@ -279,10 +322,9 @@ def sct_to_ttj2000s(
|
|
|
279
322
|
|
|
280
323
|
|
|
281
324
|
@typing.no_type_check
|
|
282
|
-
@ensure_spice
|
|
283
325
|
def str_to_et(
|
|
284
|
-
time_str:
|
|
285
|
-
) ->
|
|
326
|
+
time_str: str | Iterable[str],
|
|
327
|
+
) -> float | np.ndarray:
|
|
286
328
|
"""
|
|
287
329
|
Convert string to ephemeris time.
|
|
288
330
|
|
|
@@ -305,13 +347,12 @@ def str_to_et(
|
|
|
305
347
|
|
|
306
348
|
|
|
307
349
|
@typing.no_type_check
|
|
308
|
-
@ensure_spice
|
|
309
350
|
def et_to_utc(
|
|
310
|
-
et:
|
|
351
|
+
et: float | Iterable[float],
|
|
311
352
|
format_str: str = "ISOC",
|
|
312
353
|
precision: int = 3,
|
|
313
354
|
utclen: int = 24,
|
|
314
|
-
) ->
|
|
355
|
+
) -> str | np.ndarray:
|
|
315
356
|
"""
|
|
316
357
|
Convert ephemeris time to UTC.
|
|
317
358
|
|
|
@@ -138,7 +138,7 @@ def decompress_count(
|
|
|
138
138
|
|
|
139
139
|
# SWAPI suggested using big value to indicate overflow.
|
|
140
140
|
new_count[compressed_indices & (count_data == 0xFFFF)] = np.iinfo(np.int32).max
|
|
141
|
-
return new_count
|
|
141
|
+
return (new_count).astype(np.float32)
|
|
142
142
|
|
|
143
143
|
|
|
144
144
|
def find_sweep_starts(packets: xr.Dataset) -> npt.NDArray:
|
|
@@ -474,6 +474,12 @@ def process_swapi_science(
|
|
|
474
474
|
swp_scem_counts = decompress_count(raw_scem_count, scem_compression_flags)
|
|
475
475
|
swp_coin_counts = decompress_count(raw_coin_count, coin_compression_flags)
|
|
476
476
|
|
|
477
|
+
# Fill first index of 72 steps with nan value per
|
|
478
|
+
# SWAPI team's instruction. nan helps with plotting.
|
|
479
|
+
swp_pcem_counts[:, 0] = np.nan
|
|
480
|
+
swp_scem_counts[:, 0] = np.nan
|
|
481
|
+
swp_coin_counts[:, 0] = np.nan
|
|
482
|
+
|
|
477
483
|
# ====================================================
|
|
478
484
|
# Load the CDF attributes
|
|
479
485
|
# ====================================================
|
|
@@ -600,17 +606,17 @@ def process_swapi_science(
|
|
|
600
606
|
)
|
|
601
607
|
|
|
602
608
|
dataset["swp_pcem_counts"] = xr.DataArray(
|
|
603
|
-
|
|
609
|
+
swp_pcem_counts,
|
|
604
610
|
dims=["epoch", "esa_step"],
|
|
605
611
|
attrs=cdf_manager.get_variable_attributes("pcem_counts"),
|
|
606
612
|
)
|
|
607
613
|
dataset["swp_scem_counts"] = xr.DataArray(
|
|
608
|
-
|
|
614
|
+
swp_scem_counts,
|
|
609
615
|
dims=["epoch", "esa_step"],
|
|
610
616
|
attrs=cdf_manager.get_variable_attributes("scem_counts"),
|
|
611
617
|
)
|
|
612
618
|
dataset["swp_coin_counts"] = xr.DataArray(
|
|
613
|
-
|
|
619
|
+
swp_coin_counts,
|
|
614
620
|
dims=["epoch", "esa_step"],
|
|
615
621
|
attrs=cdf_manager.get_variable_attributes("coin_counts"),
|
|
616
622
|
)
|