imap-processing 0.16.2__py3-none-any.whl → 0.18.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/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 +35 -0
- imap_processing/cdf/config/imap_codice_l1b_variable_attrs.yaml +35 -0
- imap_processing/cdf/config/imap_codice_l2_variable_attrs.yaml +24 -0
- imap_processing/cdf/config/imap_hi_variable_attrs.yaml +8 -8
- imap_processing/cdf/config/imap_hit_global_cdf_attrs.yaml +1 -1
- imap_processing/cdf/config/imap_hit_l1a_variable_attrs.yaml +163 -100
- imap_processing/cdf/config/imap_hit_l2_variable_attrs.yaml +398 -415
- imap_processing/cdf/config/imap_ialirt_l1_variable_attrs.yaml +97 -54
- imap_processing/cdf/config/imap_idex_global_cdf_attrs.yaml +9 -9
- imap_processing/cdf/config/imap_idex_l2b_variable_attrs.yaml +233 -57
- imap_processing/cdf/config/imap_idex_l2c_variable_attrs.yaml +16 -90
- imap_processing/cdf/config/imap_lo_global_cdf_attrs.yaml +30 -0
- imap_processing/cdf/config/imap_mag_global_cdf_attrs.yaml +15 -1
- imap_processing/cdf/config/imap_swapi_variable_attrs.yaml +19 -0
- imap_processing/cdf/config/imap_swe_l1b_variable_attrs.yaml +20 -0
- imap_processing/cdf/config/imap_swe_l2_variable_attrs.yaml +39 -0
- imap_processing/cdf/config/imap_ultra_global_cdf_attrs.yaml +168 -0
- imap_processing/cdf/config/imap_ultra_l1a_variable_attrs.yaml +103 -2
- imap_processing/cdf/config/imap_ultra_l1b_variable_attrs.yaml +91 -11
- imap_processing/cdf/utils.py +7 -1
- imap_processing/cli.py +42 -13
- imap_processing/codice/codice_l1a.py +125 -78
- imap_processing/codice/codice_l1b.py +1 -1
- imap_processing/codice/codice_l2.py +0 -9
- imap_processing/codice/constants.py +481 -498
- imap_processing/hi/hi_l1a.py +4 -4
- imap_processing/hi/hi_l1b.py +2 -2
- imap_processing/hi/packet_definitions/TLM_HI_COMBINED_SCI.xml +218 -38
- imap_processing/hit/hit_utils.py +2 -2
- imap_processing/hit/l0/decom_hit.py +4 -3
- imap_processing/hit/l1a/hit_l1a.py +64 -24
- imap_processing/hit/l1b/constants.py +5 -0
- imap_processing/hit/l1b/hit_l1b.py +18 -16
- imap_processing/hit/l2/constants.py +1 -1
- imap_processing/hit/l2/hit_l2.py +4 -4
- imap_processing/ialirt/constants.py +21 -0
- imap_processing/ialirt/generate_coverage.py +188 -0
- imap_processing/ialirt/l0/parse_mag.py +62 -5
- imap_processing/ialirt/l0/process_swapi.py +1 -1
- imap_processing/ialirt/l0/process_swe.py +23 -7
- imap_processing/ialirt/utils/constants.py +22 -16
- imap_processing/ialirt/utils/create_xarray.py +42 -19
- imap_processing/idex/idex_constants.py +8 -5
- imap_processing/idex/idex_l2b.py +554 -58
- imap_processing/idex/idex_l2c.py +30 -196
- imap_processing/lo/l0/lo_apid.py +1 -0
- imap_processing/lo/l0/lo_star_sensor.py +48 -0
- imap_processing/lo/l1a/lo_l1a.py +74 -30
- imap_processing/lo/packet_definitions/lo_xtce.xml +5359 -106
- imap_processing/mag/constants.py +1 -0
- imap_processing/mag/l0/decom_mag.py +9 -6
- imap_processing/mag/l0/mag_l0_data.py +46 -0
- imap_processing/mag/l1d/__init__.py +0 -0
- imap_processing/mag/l1d/mag_l1d.py +133 -0
- imap_processing/mag/l1d/mag_l1d_data.py +588 -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 +191 -130
- imap_processing/quality_flags.py +20 -2
- imap_processing/spice/geometry.py +25 -3
- imap_processing/spice/pointing_frame.py +1 -1
- imap_processing/spice/spin.py +4 -0
- imap_processing/spice/time.py +51 -0
- imap_processing/swapi/l1/swapi_l1.py +12 -2
- imap_processing/swapi/l2/swapi_l2.py +59 -14
- imap_processing/swapi/swapi_utils.py +1 -1
- imap_processing/swe/l1b/swe_l1b.py +11 -4
- imap_processing/swe/l2/swe_l2.py +111 -17
- imap_processing/ultra/constants.py +49 -1
- imap_processing/ultra/l0/decom_tools.py +28 -14
- imap_processing/ultra/l0/decom_ultra.py +225 -15
- imap_processing/ultra/l0/ultra_utils.py +281 -8
- imap_processing/ultra/l1a/ultra_l1a.py +77 -8
- imap_processing/ultra/l1b/cullingmask.py +3 -3
- imap_processing/ultra/l1b/de.py +53 -15
- imap_processing/ultra/l1b/extendedspin.py +26 -2
- imap_processing/ultra/l1b/lookup_utils.py +171 -50
- imap_processing/ultra/l1b/quality_flag_filters.py +14 -0
- imap_processing/ultra/l1b/ultra_l1b_culling.py +198 -5
- imap_processing/ultra/l1b/ultra_l1b_extended.py +304 -66
- imap_processing/ultra/l1c/helio_pset.py +54 -7
- imap_processing/ultra/l1c/spacecraft_pset.py +9 -1
- imap_processing/ultra/l1c/ultra_l1c.py +2 -0
- imap_processing/ultra/l1c/ultra_l1c_pset_bins.py +106 -109
- imap_processing/ultra/packet_definitions/ULTRA_SCI_COMBINED.xml +3 -3
- imap_processing/ultra/utils/ultra_l1_utils.py +13 -1
- imap_processing/utils.py +20 -42
- {imap_processing-0.16.2.dist-info → imap_processing-0.18.0.dist-info}/METADATA +2 -2
- {imap_processing-0.16.2.dist-info → imap_processing-0.18.0.dist-info}/RECORD +95 -103
- imap_processing/lo/l0/data_classes/star_sensor.py +0 -98
- imap_processing/lo/l0/utils/lo_base.py +0 -57
- 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.16.2.dist-info → imap_processing-0.18.0.dist-info}/LICENSE +0 -0
- {imap_processing-0.16.2.dist-info → imap_processing-0.18.0.dist-info}/WHEEL +0 -0
- {imap_processing-0.16.2.dist-info → imap_processing-0.18.0.dist-info}/entry_points.txt +0 -0
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
"""Calculate Pointing Set Grids."""
|
|
2
2
|
|
|
3
|
-
import astropy_healpix.healpy as hp
|
|
4
3
|
import numpy as np
|
|
4
|
+
import pandas as pd
|
|
5
5
|
import xarray as xr
|
|
6
6
|
|
|
7
|
-
from imap_processing.
|
|
7
|
+
from imap_processing.spice.time import sct_to_et
|
|
8
|
+
from imap_processing.ultra.l1c.ultra_l1c_pset_bins import (
|
|
9
|
+
build_energy_bins,
|
|
10
|
+
get_helio_background_rates,
|
|
11
|
+
get_helio_exposure_times,
|
|
12
|
+
get_helio_sensitivity,
|
|
13
|
+
get_spacecraft_histogram,
|
|
14
|
+
)
|
|
8
15
|
from imap_processing.ultra.utils.ultra_l1_utils import create_dataset
|
|
9
16
|
|
|
10
17
|
|
|
@@ -36,17 +43,57 @@ def calculate_helio_pset(
|
|
|
36
43
|
dataset : xarray.Dataset
|
|
37
44
|
Dataset containing the data.
|
|
38
45
|
"""
|
|
39
|
-
# TODO: Fill in the rest of this later.
|
|
40
46
|
pset_dict: dict[str, np.ndarray] = {}
|
|
41
|
-
healpix = np.arange(hp.nside2npix(128))
|
|
42
|
-
_, _, energy_bin_geometric_means = build_energy_bins()
|
|
43
47
|
|
|
48
|
+
v_mag_helio_spacecraft = np.linalg.norm(
|
|
49
|
+
de_dataset["velocity_dps_helio"].values, axis=1
|
|
50
|
+
)
|
|
51
|
+
vhat_dps_helio = (
|
|
52
|
+
de_dataset["velocity_dps_helio"].values / v_mag_helio_spacecraft[:, np.newaxis]
|
|
53
|
+
)
|
|
54
|
+
intervals, _, energy_bin_geometric_means = build_energy_bins()
|
|
55
|
+
counts, latitude, longitude, n_pix = get_spacecraft_histogram(
|
|
56
|
+
vhat_dps_helio,
|
|
57
|
+
de_dataset["energy_heliosphere"].values,
|
|
58
|
+
intervals,
|
|
59
|
+
nside=128,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
healpix = np.arange(n_pix)
|
|
63
|
+
|
|
64
|
+
# calculate background rates
|
|
65
|
+
background_rates = get_helio_background_rates()
|
|
66
|
+
|
|
67
|
+
efficiencies = ancillary_files["l1c-90sensor-efficiencies"]
|
|
68
|
+
geometric_function = ancillary_files["l1c-90sensor-gf"]
|
|
69
|
+
|
|
70
|
+
df_efficiencies = pd.read_csv(efficiencies)
|
|
71
|
+
df_geometric_function = pd.read_csv(geometric_function)
|
|
72
|
+
mid_time = sct_to_et(np.median(de_dataset["event_times"].data))
|
|
73
|
+
sensitivity = get_helio_sensitivity(
|
|
74
|
+
mid_time,
|
|
75
|
+
df_efficiencies,
|
|
76
|
+
df_geometric_function,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
# Calculate exposure
|
|
80
|
+
constant_exposure = ancillary_files["l1c-90sensor-dps-exposure"]
|
|
81
|
+
df_exposure = pd.read_csv(constant_exposure)
|
|
82
|
+
exposure_pointing = get_helio_exposure_times(mid_time, df_exposure)
|
|
83
|
+
|
|
84
|
+
# For ISTP, epoch should be the center of the time bin.
|
|
44
85
|
pset_dict["epoch"] = de_dataset.epoch.data[:1].astype(np.int64)
|
|
45
|
-
pset_dict["
|
|
86
|
+
pset_dict["counts"] = counts[np.newaxis, ...]
|
|
87
|
+
pset_dict["latitude"] = latitude[np.newaxis, ...]
|
|
88
|
+
pset_dict["longitude"] = longitude[np.newaxis, ...]
|
|
46
89
|
pset_dict["energy_bin_geometric_mean"] = energy_bin_geometric_means
|
|
47
|
-
pset_dict["
|
|
90
|
+
pset_dict["background_rates"] = background_rates[np.newaxis, ...]
|
|
91
|
+
pset_dict["helio_exposure_factor"] = exposure_pointing[np.newaxis, ...]
|
|
92
|
+
pset_dict["pixel_index"] = healpix
|
|
93
|
+
pset_dict["energy_bin_delta"] = np.diff(intervals, axis=1).squeeze()[
|
|
48
94
|
np.newaxis, ...
|
|
49
95
|
]
|
|
96
|
+
pset_dict["sensitivity"] = sensitivity[np.newaxis, ...]
|
|
50
97
|
|
|
51
98
|
dataset = create_dataset(pset_dict, name, "l1c")
|
|
52
99
|
|
|
@@ -18,6 +18,8 @@ def calculate_spacecraft_pset(
|
|
|
18
18
|
de_dataset: xr.Dataset,
|
|
19
19
|
extendedspin_dataset: xr.Dataset,
|
|
20
20
|
cullingmask_dataset: xr.Dataset,
|
|
21
|
+
rates_dataset: xr.Dataset,
|
|
22
|
+
params_dataset: xr.Dataset,
|
|
21
23
|
name: str,
|
|
22
24
|
ancillary_files: dict,
|
|
23
25
|
) -> xr.Dataset:
|
|
@@ -32,6 +34,10 @@ def calculate_spacecraft_pset(
|
|
|
32
34
|
Dataset containing extendedspin data.
|
|
33
35
|
cullingmask_dataset : xarray.Dataset
|
|
34
36
|
Dataset containing cullingmask data.
|
|
37
|
+
rates_dataset : xarray.Dataset
|
|
38
|
+
Dataset containing image rates data.
|
|
39
|
+
params_dataset : xarray.Dataset
|
|
40
|
+
Dataset containing image parameters data.
|
|
35
41
|
name : str
|
|
36
42
|
Name of the dataset.
|
|
37
43
|
ancillary_files : dict
|
|
@@ -71,7 +77,9 @@ def calculate_spacecraft_pset(
|
|
|
71
77
|
# Calculate exposure
|
|
72
78
|
constant_exposure = ancillary_files["l1c-90sensor-dps-exposure"]
|
|
73
79
|
df_exposure = pd.read_csv(constant_exposure)
|
|
74
|
-
exposure_pointing = get_spacecraft_exposure_times(
|
|
80
|
+
exposure_pointing = get_spacecraft_exposure_times(
|
|
81
|
+
df_exposure, rates_dataset, params_dataset
|
|
82
|
+
)
|
|
75
83
|
|
|
76
84
|
# For ISTP, epoch should be the center of the time bin.
|
|
77
85
|
pset_dict["epoch"] = de_dataset.epoch.data[:1].astype(np.int64)
|
|
@@ -63,6 +63,8 @@ def ultra_l1c(
|
|
|
63
63
|
data_dict[f"imap_ultra_l1b_{instrument_id}sensor-de"],
|
|
64
64
|
data_dict[f"imap_ultra_l1b_{instrument_id}sensor-extendedspin"],
|
|
65
65
|
data_dict[f"imap_ultra_l1b_{instrument_id}sensor-cullingmask"],
|
|
66
|
+
data_dict[f"imap_ultra_{instrument_id}sensor-rates"],
|
|
67
|
+
data_dict[f"imap_ultra_{instrument_id}sensor-params"],
|
|
66
68
|
f"imap_ultra_l1c_{instrument_id}sensor-spacecraftpset",
|
|
67
69
|
ancillary_files,
|
|
68
70
|
)
|
|
@@ -4,6 +4,7 @@ import astropy_healpix.healpy as hp
|
|
|
4
4
|
import numpy as np
|
|
5
5
|
import pandas
|
|
6
6
|
import pandas as pd
|
|
7
|
+
import xarray as xr
|
|
7
8
|
from numpy.typing import NDArray
|
|
8
9
|
from scipy.interpolate import interp1d
|
|
9
10
|
|
|
@@ -151,110 +152,6 @@ def get_spacecraft_histogram(
|
|
|
151
152
|
return hist, latitude, longitude, n_pix
|
|
152
153
|
|
|
153
154
|
|
|
154
|
-
def get_helio_histogram(
|
|
155
|
-
time: NDArray,
|
|
156
|
-
vhat: NDArray,
|
|
157
|
-
energy: NDArray,
|
|
158
|
-
energy_bin_edges: list[tuple[float, float]],
|
|
159
|
-
nside: int = 128,
|
|
160
|
-
nested: bool = False,
|
|
161
|
-
) -> tuple[NDArray, NDArray, NDArray, NDArray]:
|
|
162
|
-
"""
|
|
163
|
-
Compute a 3D histogram of the particle data using HEALPix binning.
|
|
164
|
-
|
|
165
|
-
Parameters
|
|
166
|
-
----------
|
|
167
|
-
time : np.ndarray
|
|
168
|
-
Median time of pointing in et.
|
|
169
|
-
vhat : tuple[np.ndarray, np.ndarray, np.ndarray]
|
|
170
|
-
The x,y,z-components of the unit velocity vector.
|
|
171
|
-
energy : np.ndarray
|
|
172
|
-
The particle energy.
|
|
173
|
-
energy_bin_edges : list[tuple[float, float]]
|
|
174
|
-
Array of energy bin edges.
|
|
175
|
-
nside : int, optional
|
|
176
|
-
The nside parameter of the Healpix tessellation.
|
|
177
|
-
Default is 128.
|
|
178
|
-
nested : bool, optional
|
|
179
|
-
Whether the Healpix tessellation is nested. Default is False.
|
|
180
|
-
|
|
181
|
-
Returns
|
|
182
|
-
-------
|
|
183
|
-
hist : np.ndarray
|
|
184
|
-
A 3D histogram array with shape (n_pix, n_energy_bins).
|
|
185
|
-
latitude : np.ndarray
|
|
186
|
-
Array of latitude values.
|
|
187
|
-
longitude : np.ndarray
|
|
188
|
-
Array of longitude values.
|
|
189
|
-
n_pix : int
|
|
190
|
-
Number of healpix pixels.
|
|
191
|
-
|
|
192
|
-
Notes
|
|
193
|
-
-----
|
|
194
|
-
The histogram will work properly for overlapping energy bins, i.e.
|
|
195
|
-
the same energy value can fall into multiple bins if the intervals overlap.
|
|
196
|
-
|
|
197
|
-
azimuthal angle [0, 360], elevation angle [-90, 90]
|
|
198
|
-
"""
|
|
199
|
-
# Compute number of HEALPix pixels that cover the sphere
|
|
200
|
-
n_pix = hp.nside2npix(nside)
|
|
201
|
-
|
|
202
|
-
# Calculate the corresponding longitude (az) latitude (el)
|
|
203
|
-
# center coordinates
|
|
204
|
-
longitude, latitude = hp.pix2ang(nside, np.arange(n_pix), lonlat=True)
|
|
205
|
-
|
|
206
|
-
# The Cartesian state vector representing the position and velocity of the
|
|
207
|
-
# IMAP spacecraft.
|
|
208
|
-
state = imap_state(time, ref_frame=SpiceFrame.IMAP_DPS)
|
|
209
|
-
|
|
210
|
-
# Extract the velocity part of the state vector
|
|
211
|
-
spacecraft_velocity = state[3:6]
|
|
212
|
-
|
|
213
|
-
# Initialize histogram: (n_energy_bins, n_HEALPix pixels)
|
|
214
|
-
hist = np.zeros((len(energy_bin_edges), n_pix))
|
|
215
|
-
|
|
216
|
-
# Bin data in energy & HEALPix space
|
|
217
|
-
for i, (e_min, e_max) in enumerate(energy_bin_edges):
|
|
218
|
-
# Convert the midpoint energy to a velocity (km/s).
|
|
219
|
-
# Based on kinetic energy equation: E = 1/2 * m * v^2.
|
|
220
|
-
energy_midpoint = (e_min + e_max) / 2
|
|
221
|
-
energy_velocity = (
|
|
222
|
-
np.sqrt(2 * energy_midpoint * UltraConstants.KEV_J / UltraConstants.MASS_H)
|
|
223
|
-
/ 1e3
|
|
224
|
-
)
|
|
225
|
-
|
|
226
|
-
# Use Galilean Transform to transform the velocity wrt spacecraft
|
|
227
|
-
# to the velocity wrt heliosphere.
|
|
228
|
-
# energy_velocity * cartesian -> apply the magnitude of the velocity
|
|
229
|
-
# to every position on the grid in the despun grid.
|
|
230
|
-
mask = (energy >= e_min) & (energy < e_max)
|
|
231
|
-
vx, vy, vz = vhat.T
|
|
232
|
-
|
|
233
|
-
# Select only the particles that fall within the energy bin.
|
|
234
|
-
vx_bin, vy_bin, vz_bin = vx[mask], vy[mask], vz[mask]
|
|
235
|
-
vhat_bin = np.stack((vx_bin, vy_bin, vz_bin), axis=1)
|
|
236
|
-
helio_velocity = spacecraft_velocity.reshape(1, 3) + energy_velocity * vhat_bin
|
|
237
|
-
|
|
238
|
-
# Normalized vectors representing the direction of the heliocentric velocity.
|
|
239
|
-
helio_normalized = -helio_velocity / np.linalg.norm(
|
|
240
|
-
helio_velocity, axis=1, keepdims=True
|
|
241
|
-
)
|
|
242
|
-
|
|
243
|
-
# Convert Cartesian heliocentric vectors into spherical coordinates.
|
|
244
|
-
# Result: azimuth (longitude) and elevation (latitude) in degrees.
|
|
245
|
-
helio_spherical = cartesian_to_spherical(np.squeeze(helio_normalized))
|
|
246
|
-
helio_spherical = np.atleast_2d(helio_spherical)
|
|
247
|
-
az, el = helio_spherical[:, 1], helio_spherical[:, 2]
|
|
248
|
-
|
|
249
|
-
# Convert azimuth/elevation directions to HEALPix pixel indices.
|
|
250
|
-
hpix_idx = hp.ang2pix(nside, az, el, nest=nested, lonlat=True)
|
|
251
|
-
|
|
252
|
-
# Only count the events that fall within the energy bin
|
|
253
|
-
hist[i, :] += np.bincount(hpix_idx, minlength=n_pix).astype(np.float64)
|
|
254
|
-
|
|
255
|
-
return hist, latitude, longitude, n_pix
|
|
256
|
-
|
|
257
|
-
|
|
258
155
|
def get_spacecraft_background_rates(
|
|
259
156
|
nside: int = 128,
|
|
260
157
|
) -> NDArray:
|
|
@@ -309,7 +206,98 @@ def get_helio_background_rates(
|
|
|
309
206
|
return background
|
|
310
207
|
|
|
311
208
|
|
|
312
|
-
def
|
|
209
|
+
def get_deadtime_correction_factors(sectored_rates_ds: xr.Dataset) -> xr.DataArray:
|
|
210
|
+
"""
|
|
211
|
+
Compute the dead time correction factor at each sector.
|
|
212
|
+
|
|
213
|
+
Further description is available in section 3.4.3 of the IMAP-Ultra Algorithm
|
|
214
|
+
Document.
|
|
215
|
+
|
|
216
|
+
Parameters
|
|
217
|
+
----------
|
|
218
|
+
sectored_rates_ds : xarray.Dataset
|
|
219
|
+
Dataset containing sector mode image rates data.
|
|
220
|
+
|
|
221
|
+
Returns
|
|
222
|
+
-------
|
|
223
|
+
dead_time_ratio : xarray.DataArray
|
|
224
|
+
Dead time correction factor for each sector.
|
|
225
|
+
"""
|
|
226
|
+
# Compute the correction factor at each sector
|
|
227
|
+
a = sectored_rates_ds.fifo_valid_events / (
|
|
228
|
+
1
|
|
229
|
+
- (sectored_rates_ds.event_active_time + 2 * sectored_rates_ds.start_pos) * 1e-7
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
start_full = sectored_rates_ds.start_rf + sectored_rates_ds.start_lf
|
|
233
|
+
b = a * np.exp(start_full * 1e-7 * 5)
|
|
234
|
+
|
|
235
|
+
coin_stop_nd = (
|
|
236
|
+
sectored_rates_ds.coin_tn
|
|
237
|
+
+ sectored_rates_ds.coin_bn
|
|
238
|
+
- sectored_rates_ds.stop_tn
|
|
239
|
+
- sectored_rates_ds.stop_bn
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
corrected_valid_events = b * np.exp(1e-7 * 8 * coin_stop_nd)
|
|
243
|
+
|
|
244
|
+
# Compute dead time ratio
|
|
245
|
+
dead_time_ratios = sectored_rates_ds.fifo_valid_events / corrected_valid_events
|
|
246
|
+
|
|
247
|
+
return dead_time_ratios
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
def get_sectored_rates(rates_ds: xr.Dataset, params_ds: xr.Dataset) -> xr.Dataset:
|
|
251
|
+
"""
|
|
252
|
+
Filter rates dataset to only include sector mode data.
|
|
253
|
+
|
|
254
|
+
Parameters
|
|
255
|
+
----------
|
|
256
|
+
rates_ds : xarray.Dataset
|
|
257
|
+
Dataset containing image rates data.
|
|
258
|
+
params_ds : xarray.Dataset
|
|
259
|
+
Dataset containing image parameters data.
|
|
260
|
+
|
|
261
|
+
Returns
|
|
262
|
+
-------
|
|
263
|
+
rates : xarray.Dataset
|
|
264
|
+
Rates dataset with only the sector mode data.
|
|
265
|
+
"""
|
|
266
|
+
# Find indices in which the parameters dataset, indicates that ULTRA was in
|
|
267
|
+
# sector mode. At the normal 15-second spin period, each 24° sector takes ~1 second.
|
|
268
|
+
|
|
269
|
+
# This means that data was collected as a function of spin allowing for fine grained
|
|
270
|
+
# rate analysis.
|
|
271
|
+
sector_mode_start_inds = np.where(params_ds["imageratescadence"] == 3)[0]
|
|
272
|
+
# get the sector mode start and stop indices
|
|
273
|
+
sector_mode_stop_inds = sector_mode_start_inds + 1
|
|
274
|
+
# get the sector mode start and stop times
|
|
275
|
+
mode_3_start = params_ds["epoch"].values[sector_mode_start_inds]
|
|
276
|
+
|
|
277
|
+
# if the last mode is a sector mode, we can assume that the sector data goes through
|
|
278
|
+
# the end of the dataset, so we append np.inf to the end of the last time range.
|
|
279
|
+
if sector_mode_stop_inds[-1] == len(params_ds["epoch"]):
|
|
280
|
+
mode_3_end = np.append(
|
|
281
|
+
params_ds["epoch"].values[sector_mode_stop_inds[:-1]], np.inf
|
|
282
|
+
)
|
|
283
|
+
else:
|
|
284
|
+
mode_3_end = params_ds["epoch"].values[sector_mode_stop_inds]
|
|
285
|
+
|
|
286
|
+
# Build a list of conditions for each sector mode time range
|
|
287
|
+
conditions = [
|
|
288
|
+
(rates_ds["epoch"] >= start) & (rates_ds["epoch"] < end)
|
|
289
|
+
for start, end in zip(mode_3_start, mode_3_end)
|
|
290
|
+
]
|
|
291
|
+
|
|
292
|
+
sector_mode_mask = np.logical_or.reduce(conditions)
|
|
293
|
+
return rates_ds.isel(epoch=sector_mode_mask)
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
def get_spacecraft_exposure_times(
|
|
297
|
+
constant_exposure: pandas.DataFrame,
|
|
298
|
+
rates_dataset: xr.Dataset,
|
|
299
|
+
params_dataset: xr.Dataset,
|
|
300
|
+
) -> NDArray:
|
|
313
301
|
"""
|
|
314
302
|
Compute exposure times for HEALPix pixels.
|
|
315
303
|
|
|
@@ -317,6 +305,10 @@ def get_spacecraft_exposure_times(constant_exposure: pandas.DataFrame) -> NDArra
|
|
|
317
305
|
----------
|
|
318
306
|
constant_exposure : pandas.DataFrame
|
|
319
307
|
Exposure data.
|
|
308
|
+
rates_dataset : xarray.Dataset
|
|
309
|
+
Dataset containing image rates data.
|
|
310
|
+
params_dataset : xarray.Dataset
|
|
311
|
+
Dataset containing image parameters data.
|
|
320
312
|
|
|
321
313
|
Returns
|
|
322
314
|
-------
|
|
@@ -325,6 +317,11 @@ def get_spacecraft_exposure_times(constant_exposure: pandas.DataFrame) -> NDArra
|
|
|
325
317
|
Healpix tessellation of the sky
|
|
326
318
|
in the pointing (dps) frame.
|
|
327
319
|
"""
|
|
320
|
+
# TODO: uncomment these lines when the deadtime correction is implemented
|
|
321
|
+
# sectored_rates = get_sectored_rates(rates_dataset, params_dataset)
|
|
322
|
+
# get_deadtime_correction_factors(sectored_rates)
|
|
323
|
+
# TODO: calculate the deadtime correction function
|
|
324
|
+
# TODO: Apply the deadtime correction to the exposure times
|
|
328
325
|
# TODO: use the universal spin table and
|
|
329
326
|
# universal pointing table here to determine actual number of spins
|
|
330
327
|
exposure_pointing = (
|
|
@@ -384,7 +381,7 @@ def get_helio_exposure_times(
|
|
|
384
381
|
# Initialize output array.
|
|
385
382
|
# Each row corresponds to a HEALPix pixel, and each column to an energy bin.
|
|
386
383
|
npix = hp.nside2npix(nside)
|
|
387
|
-
helio_exposure = np.zeros((
|
|
384
|
+
helio_exposure = np.zeros((len(energy_midpoints), npix))
|
|
388
385
|
|
|
389
386
|
# Loop through energy bins and compute transformed exposure.
|
|
390
387
|
for i, energy_midpoint in enumerate(energy_midpoints):
|
|
@@ -415,7 +412,7 @@ def get_helio_exposure_times(
|
|
|
415
412
|
hpix_idx = hp.ang2pix(nside, az, el, nest=nested, lonlat=True)
|
|
416
413
|
|
|
417
414
|
# Accumulate exposure values into HEALPix pixels for this energy bin.
|
|
418
|
-
helio_exposure[
|
|
415
|
+
helio_exposure[i, :] = np.bincount(
|
|
419
416
|
hpix_idx, weights=exposure_flat, minlength=npix
|
|
420
417
|
)
|
|
421
418
|
|
|
@@ -597,7 +594,7 @@ def get_helio_sensitivity(
|
|
|
597
594
|
# Initialize output array.
|
|
598
595
|
# Each row corresponds to a HEALPix pixel, and each column to an energy bin.
|
|
599
596
|
npix = hp.nside2npix(nside)
|
|
600
|
-
helio_sensitivity = np.zeros((
|
|
597
|
+
helio_sensitivity = np.zeros((len(energy_midpoints), npix))
|
|
601
598
|
|
|
602
599
|
# Loop through energy bins and compute transformed sensitivity.
|
|
603
600
|
for i, energy in enumerate(energy_midpoints):
|
|
@@ -628,7 +625,7 @@ def get_helio_sensitivity(
|
|
|
628
625
|
gridded_sensitivity = grid_sensitivity(efficiencies, geometric_function, energy)
|
|
629
626
|
|
|
630
627
|
# Accumulate sensitivity values into HEALPix pixels for this energy bin.
|
|
631
|
-
helio_sensitivity[
|
|
628
|
+
helio_sensitivity[i, :] = np.bincount(
|
|
632
629
|
hpix_idx, weights=gridded_sensitivity, minlength=npix
|
|
633
630
|
)
|
|
634
631
|
|
|
@@ -4726,15 +4726,15 @@
|
|
|
4726
4726
|
<xtce:IntegerParameterType name="U45_IMG_ENA_PHXTOF_HI_TIME.SPIN" signed="false">
|
|
4727
4727
|
<xtce:IntegerDataEncoding sizeInBits="8" encoding="unsigned" />
|
|
4728
4728
|
</xtce:IntegerParameterType>
|
|
4729
|
+
<xtce:IntegerParameterType name="U45_IMG_ENA_PHXTOF_HI_TIME.ABORTFLAG" signed="false">
|
|
4730
|
+
<xtce:IntegerDataEncoding sizeInBits="1" encoding="unsigned" />
|
|
4731
|
+
</xtce:IntegerParameterType>
|
|
4729
4732
|
<xtce:IntegerParameterType name="U45_IMG_ENA_PHXTOF_HI_TIME.STARTDELAY" signed="false">
|
|
4730
4733
|
<xtce:IntegerDataEncoding sizeInBits="15" encoding="unsigned" />
|
|
4731
4734
|
</xtce:IntegerParameterType>
|
|
4732
4735
|
<xtce:IntegerParameterType name="U45_IMG_ENA_PHXTOF_HI_TIME.P00" signed="false">
|
|
4733
4736
|
<xtce:IntegerDataEncoding sizeInBits="8" encoding="unsigned" />
|
|
4734
4737
|
</xtce:IntegerParameterType>
|
|
4735
|
-
<xtce:IntegerParameterType name="U45_IMG_ENA_PHXTOF_HI_TIME.ABORTFLAG" signed="false">
|
|
4736
|
-
<xtce:IntegerDataEncoding sizeInBits="8" encoding="unsigned" />
|
|
4737
|
-
</xtce:IntegerParameterType>
|
|
4738
4738
|
<xtce:BinaryParameterType name="U45_IMG_ENA_PHXTOF_HI_TIME.PACKETDATA">
|
|
4739
4739
|
<xtce:BinaryDataEncoding bitOrder="mostSignificantBitFirst">
|
|
4740
4740
|
<xtce:SizeInBits>
|
|
@@ -91,6 +91,7 @@ def create_dataset( # noqa: PLR0912
|
|
|
91
91
|
"ena_rates_threshold",
|
|
92
92
|
"quality_ena_rates",
|
|
93
93
|
}
|
|
94
|
+
rates_pulse_keys = {"start_per_spin", "stop_per_spin", "coin_per_spin"}
|
|
94
95
|
|
|
95
96
|
for key, data in data_dict.items():
|
|
96
97
|
# Skip keys that are coordinates.
|
|
@@ -114,6 +115,12 @@ def create_dataset( # noqa: PLR0912
|
|
|
114
115
|
dims=["epoch", "energy_bin_geometric_mean"],
|
|
115
116
|
attrs=cdf_manager.get_variable_attributes(key, check_schema=False),
|
|
116
117
|
)
|
|
118
|
+
elif key in rates_pulse_keys:
|
|
119
|
+
dataset[key] = xr.DataArray(
|
|
120
|
+
data,
|
|
121
|
+
dims=["spin_number"],
|
|
122
|
+
attrs=cdf_manager.get_variable_attributes(key, check_schema=False),
|
|
123
|
+
)
|
|
117
124
|
elif key in rates_keys:
|
|
118
125
|
dataset[key] = xr.DataArray(
|
|
119
126
|
data,
|
|
@@ -126,7 +133,12 @@ def create_dataset( # noqa: PLR0912
|
|
|
126
133
|
dims=["epoch", "pixel_index"],
|
|
127
134
|
attrs=cdf_manager.get_variable_attributes(key, check_schema=False),
|
|
128
135
|
)
|
|
129
|
-
elif key in {
|
|
136
|
+
elif key in {
|
|
137
|
+
"counts",
|
|
138
|
+
"background_rates",
|
|
139
|
+
"helio_exposure_factor",
|
|
140
|
+
"sensitivity",
|
|
141
|
+
}:
|
|
130
142
|
dataset[key] = xr.DataArray(
|
|
131
143
|
data,
|
|
132
144
|
dims=["epoch", "energy_bin_geometric_mean", "pixel_index"],
|
imap_processing/utils.py
CHANGED
|
@@ -15,48 +15,6 @@ from imap_processing.spice.time import met_to_ttj2000ns
|
|
|
15
15
|
logger = logging.getLogger(__name__)
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
def sort_by_time(packets: list, time_key: str) -> list:
|
|
19
|
-
"""
|
|
20
|
-
Sort packets by specified key.
|
|
21
|
-
|
|
22
|
-
Parameters
|
|
23
|
-
----------
|
|
24
|
-
packets : list
|
|
25
|
-
Decom data packets.
|
|
26
|
-
time_key : str
|
|
27
|
-
Key to sort by. Must be a key in the packets data dictionary.
|
|
28
|
-
e.g. "SHCOARSE" or "MET_TIME" or "ACQ_START_COARSE".
|
|
29
|
-
|
|
30
|
-
Returns
|
|
31
|
-
-------
|
|
32
|
-
sorted_packets : list
|
|
33
|
-
Sorted packets.
|
|
34
|
-
"""
|
|
35
|
-
sorted_packets = sorted(packets, key=lambda x: x[time_key])
|
|
36
|
-
return sorted_packets
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
def group_by_apid(packets: list) -> dict:
|
|
40
|
-
"""
|
|
41
|
-
Group data by apid.
|
|
42
|
-
|
|
43
|
-
Parameters
|
|
44
|
-
----------
|
|
45
|
-
packets : list
|
|
46
|
-
Packet list.
|
|
47
|
-
|
|
48
|
-
Returns
|
|
49
|
-
-------
|
|
50
|
-
grouped_packets : dict
|
|
51
|
-
Grouped data by apid.
|
|
52
|
-
"""
|
|
53
|
-
grouped_packets: dict[list] = collections.defaultdict(list)
|
|
54
|
-
for packet in packets:
|
|
55
|
-
apid = packet["PKT_APID"]
|
|
56
|
-
grouped_packets.setdefault(apid, []).append(packet)
|
|
57
|
-
return grouped_packets
|
|
58
|
-
|
|
59
|
-
|
|
60
18
|
def convert_raw_to_eu(
|
|
61
19
|
dataset: xr.Dataset,
|
|
62
20
|
conversion_table_path: str,
|
|
@@ -347,6 +305,26 @@ def packet_file_to_datasets(
|
|
|
347
305
|
coords={"epoch": time_data},
|
|
348
306
|
)
|
|
349
307
|
ds = ds.sortby("epoch")
|
|
308
|
+
# We may get duplicate packets within the packet file if packets were
|
|
309
|
+
# ingested multiple times by the POC. We want to drop packets where
|
|
310
|
+
# apid, epoch, and src_seq_ctr are the same.
|
|
311
|
+
|
|
312
|
+
# xarray only supports dropping duplicates by index, so we instead go
|
|
313
|
+
# to pandas multi-index dataframe to identify the unique positions
|
|
314
|
+
unique_indices = (
|
|
315
|
+
ds[["src_seq_ctr"]]
|
|
316
|
+
.to_dataframe()
|
|
317
|
+
.reset_index()
|
|
318
|
+
.drop_duplicates()
|
|
319
|
+
.index.values
|
|
320
|
+
)
|
|
321
|
+
nduplicates = len(ds["epoch"]) - len(unique_indices)
|
|
322
|
+
if nduplicates != 0:
|
|
323
|
+
logger.warning(
|
|
324
|
+
f"Found [{nduplicates}] duplicate packets for APID {apid}. "
|
|
325
|
+
"Dropping duplicate packets and continuing processing."
|
|
326
|
+
)
|
|
327
|
+
ds = ds.isel(epoch=unique_indices)
|
|
350
328
|
|
|
351
329
|
# Strip any leading characters before "." from the field names which was due
|
|
352
330
|
# to the packet_name being a part of the variable name in the XTCE definition
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: imap-processing
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.18.0
|
|
4
4
|
Summary: IMAP Science Operations Center Processing
|
|
5
5
|
License: MIT
|
|
6
6
|
Keywords: IMAP,SDC,SOC,Science Operations
|
|
@@ -30,7 +30,7 @@ Provides-Extra: tools
|
|
|
30
30
|
Requires-Dist: astropy-healpix (>=1.0)
|
|
31
31
|
Requires-Dist: cdflib (>=1.3.1,<2.0.0)
|
|
32
32
|
Requires-Dist: healpy (>=1.18.0,<2.0.0) ; extra == "map-visualization"
|
|
33
|
-
Requires-Dist: imap-data-access (>=0.
|
|
33
|
+
Requires-Dist: imap-data-access (>=0.32.0)
|
|
34
34
|
Requires-Dist: mypy (==1.10.1) ; extra == "dev"
|
|
35
35
|
Requires-Dist: netcdf4 (>=1.7.2,<2.0.0) ; extra == "test"
|
|
36
36
|
Requires-Dist: numpy (<=3)
|