imap-processing 0.19.0__py3-none-any.whl → 0.19.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of imap-processing might be problematic. Click here for more details.
- imap_processing/_version.py +2 -2
- imap_processing/cdf/config/imap_codice_global_cdf_attrs.yaml +6 -0
- imap_processing/cdf/config/imap_codice_l1a_variable_attrs.yaml +31 -894
- imap_processing/cdf/config/imap_codice_l1b_variable_attrs.yaml +279 -255
- imap_processing/cdf/config/imap_enamaps_l2-common_variable_attrs.yaml +11 -0
- imap_processing/cdf/config/imap_glows_l1b_variable_attrs.yaml +3 -1
- imap_processing/cdf/config/imap_lo_global_cdf_attrs.yaml +5 -4
- imap_processing/cdf/config/imap_ultra_global_cdf_attrs.yaml +20 -8
- imap_processing/cdf/config/imap_ultra_l1b_variable_attrs.yaml +33 -31
- imap_processing/cdf/config/imap_ultra_l1c_variable_attrs.yaml +61 -1
- imap_processing/cli.py +62 -71
- imap_processing/codice/codice_l0.py +2 -1
- imap_processing/codice/codice_l1a.py +47 -49
- imap_processing/codice/codice_l1b.py +42 -32
- imap_processing/codice/codice_l2.py +105 -7
- imap_processing/codice/constants.py +50 -8
- imap_processing/codice/data/lo_stepping_values.csv +1 -1
- imap_processing/ena_maps/ena_maps.py +39 -18
- imap_processing/ena_maps/utils/corrections.py +291 -0
- imap_processing/ena_maps/utils/map_utils.py +20 -4
- imap_processing/glows/l1b/glows_l1b.py +38 -23
- imap_processing/glows/l1b/glows_l1b_data.py +10 -11
- imap_processing/hi/hi_l1c.py +4 -109
- imap_processing/hi/hi_l2.py +34 -23
- imap_processing/hi/utils.py +109 -0
- imap_processing/ialirt/l0/ialirt_spice.py +1 -0
- imap_processing/ialirt/utils/create_xarray.py +1 -1
- imap_processing/lo/ancillary_data/imap_lo_hydrogen-geometric-factor_v001.csv +75 -0
- imap_processing/lo/ancillary_data/imap_lo_oxygen-geometric-factor_v001.csv +75 -0
- imap_processing/lo/l1b/lo_l1b.py +90 -16
- imap_processing/lo/l1c/lo_l1c.py +164 -50
- imap_processing/lo/l2/lo_l2.py +941 -127
- imap_processing/mag/l1d/mag_l1d_data.py +36 -3
- imap_processing/mag/l2/mag_l2.py +2 -0
- imap_processing/mag/l2/mag_l2_data.py +4 -3
- imap_processing/quality_flags.py +14 -0
- imap_processing/spice/geometry.py +15 -8
- imap_processing/spice/pointing_frame.py +4 -2
- imap_processing/spice/repoint.py +49 -0
- imap_processing/ultra/constants.py +29 -0
- imap_processing/ultra/l1b/badtimes.py +35 -11
- imap_processing/ultra/l1b/de.py +15 -9
- imap_processing/ultra/l1b/extendedspin.py +24 -12
- imap_processing/ultra/l1b/goodtimes.py +112 -0
- imap_processing/ultra/l1b/lookup_utils.py +1 -1
- imap_processing/ultra/l1b/ultra_l1b.py +7 -7
- imap_processing/ultra/l1b/ultra_l1b_culling.py +8 -4
- imap_processing/ultra/l1b/ultra_l1b_extended.py +79 -43
- imap_processing/ultra/l1c/helio_pset.py +68 -39
- imap_processing/ultra/l1c/l1c_lookup_utils.py +45 -12
- imap_processing/ultra/l1c/spacecraft_pset.py +81 -37
- imap_processing/ultra/l1c/ultra_l1c.py +27 -22
- imap_processing/ultra/l1c/ultra_l1c_culling.py +7 -0
- imap_processing/ultra/l1c/ultra_l1c_pset_bins.py +41 -41
- imap_processing/ultra/l2/ultra_l2.py +54 -10
- imap_processing/ultra/utils/ultra_l1_utils.py +10 -5
- {imap_processing-0.19.0.dist-info → imap_processing-0.19.2.dist-info}/METADATA +1 -1
- {imap_processing-0.19.0.dist-info → imap_processing-0.19.2.dist-info}/RECORD +62 -60
- imap_processing/ultra/l1b/cullingmask.py +0 -90
- imap_processing/ultra/l1c/histogram.py +0 -36
- /imap_processing/glows/ancillary/{imap_glows_pipeline_settings_20250923_v002.json → imap_glows_pipeline-settings_20250923_v002.json} +0 -0
- {imap_processing-0.19.0.dist-info → imap_processing-0.19.2.dist-info}/LICENSE +0 -0
- {imap_processing-0.19.0.dist-info → imap_processing-0.19.2.dist-info}/WHEEL +0 -0
- {imap_processing-0.19.0.dist-info → imap_processing-0.19.2.dist-info}/entry_points.txt +0 -0
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"""Module to create pointing sets."""
|
|
2
2
|
|
|
3
|
+
import logging
|
|
4
|
+
|
|
3
5
|
import astropy_healpix.healpy as hp
|
|
4
6
|
import numpy as np
|
|
5
|
-
import pandas
|
|
6
7
|
import xarray as xr
|
|
7
8
|
from numpy.typing import NDArray
|
|
8
9
|
from scipy import interpolate
|
|
@@ -13,6 +14,7 @@ from imap_processing.spice.geometry import (
|
|
|
13
14
|
imap_state,
|
|
14
15
|
)
|
|
15
16
|
from imap_processing.spice.spin import get_spacecraft_spin_phase, get_spin_angle
|
|
17
|
+
from imap_processing.spice.time import ttj2000ns_to_met
|
|
16
18
|
from imap_processing.ultra.constants import UltraConstants
|
|
17
19
|
from imap_processing.ultra.l1b.lookup_utils import (
|
|
18
20
|
get_geometric_factor,
|
|
@@ -31,6 +33,8 @@ from imap_processing.ultra.l1b.ultra_l1b_extended import (
|
|
|
31
33
|
# TODO: add species binning.
|
|
32
34
|
FILLVAL_FLOAT32 = -1.0e31
|
|
33
35
|
|
|
36
|
+
logger = logging.getLogger(__name__)
|
|
37
|
+
|
|
34
38
|
|
|
35
39
|
def build_energy_bins() -> tuple[list[tuple[float, float]], np.ndarray, np.ndarray]:
|
|
36
40
|
"""
|
|
@@ -46,7 +50,7 @@ def build_energy_bins() -> tuple[list[tuple[float, float]], np.ndarray, np.ndarr
|
|
|
46
50
|
Array of geometric means of energy bins.
|
|
47
51
|
"""
|
|
48
52
|
# Create energy bins.
|
|
49
|
-
energy_bin_edges = np.array(UltraConstants.
|
|
53
|
+
energy_bin_edges = np.array(UltraConstants.PSET_ENERGY_BIN_EDGES)
|
|
50
54
|
energy_midpoints = (energy_bin_edges[:-1] + energy_bin_edges[1:]) / 2
|
|
51
55
|
|
|
52
56
|
intervals = [
|
|
@@ -222,7 +226,6 @@ def get_deadtime_ratios(sectored_rates_ds: xr.Dataset) -> xr.DataArray:
|
|
|
222
226
|
- sectored_rates_ds.stop_tn
|
|
223
227
|
- sectored_rates_ds.stop_bn
|
|
224
228
|
)
|
|
225
|
-
|
|
226
229
|
corrected_valid_events = b * np.exp(1e-7 * 8 * coin_stop_nd)
|
|
227
230
|
|
|
228
231
|
# Compute dead time ratio
|
|
@@ -252,21 +255,24 @@ def get_sectored_rates(rates_ds: xr.Dataset, params_ds: xr.Dataset) -> xr.Datase
|
|
|
252
255
|
|
|
253
256
|
# This means that data was collected as a function of spin allowing for fine grained
|
|
254
257
|
# rate analysis.
|
|
255
|
-
|
|
258
|
+
# Only get unique combinations of epoch and imageratescadence
|
|
259
|
+
params = params_ds.groupby(["epoch", "imageratescadence"]).first()
|
|
260
|
+
|
|
261
|
+
sector_mode_start_inds = np.where(params["imageratescadence"] == 3)[0]
|
|
262
|
+
if len(sector_mode_start_inds) == 0:
|
|
263
|
+
raise ValueError("No sector mode data found in the parameters dataset.")
|
|
256
264
|
# get the sector mode start and stop indices
|
|
257
265
|
sector_mode_stop_inds = sector_mode_start_inds + 1
|
|
258
266
|
# get the sector mode start and stop times
|
|
259
|
-
mode_3_start =
|
|
260
|
-
|
|
267
|
+
mode_3_start = params["epoch"].values[sector_mode_start_inds]
|
|
261
268
|
# if the last mode is a sector mode, we can assume that the sector data goes through
|
|
262
269
|
# the end of the dataset, so we append np.inf to the end of the last time range.
|
|
263
|
-
if sector_mode_stop_inds[-1] == len(
|
|
270
|
+
if sector_mode_stop_inds[-1] == len(params["epoch"]):
|
|
264
271
|
mode_3_end = np.append(
|
|
265
|
-
|
|
272
|
+
params["epoch"].values[sector_mode_stop_inds[:-1]], np.inf
|
|
266
273
|
)
|
|
267
274
|
else:
|
|
268
|
-
mode_3_end =
|
|
269
|
-
|
|
275
|
+
mode_3_end = params["epoch"].values[sector_mode_stop_inds]
|
|
270
276
|
# Build a list of conditions for each sector mode time range
|
|
271
277
|
conditions = [
|
|
272
278
|
(rates_ds["epoch"] >= start) & (rates_ds["epoch"] < end)
|
|
@@ -295,10 +301,9 @@ def get_deadtime_ratios_by_spin_phase(
|
|
|
295
301
|
"""
|
|
296
302
|
deadtime_ratios = get_deadtime_ratios(sectored_rates)
|
|
297
303
|
# Get the spin phase at the start of each sector rate measurement
|
|
304
|
+
met_times = ttj2000ns_to_met(sectored_rates.epoch.data)
|
|
298
305
|
spin_phases = np.asarray(
|
|
299
|
-
get_spin_angle(
|
|
300
|
-
get_spacecraft_spin_phase(np.array(sectored_rates.epoch.data)), degrees=True
|
|
301
|
-
)
|
|
306
|
+
get_spin_angle(get_spacecraft_spin_phase(met_times), degrees=True)
|
|
302
307
|
)
|
|
303
308
|
# Assume the sectored rate data is evenly spaced in time, and find the middle spin
|
|
304
309
|
# phase value for each sector.
|
|
@@ -325,11 +330,16 @@ def get_deadtime_ratios_by_spin_phase(
|
|
|
325
330
|
deadtime_by_spin_phase = deadtime_by_spin_phase.sortby("spin_phase")
|
|
326
331
|
# Group by spin phase and calculate the median dead time ratio for each phase
|
|
327
332
|
deadtime_medians = deadtime_by_spin_phase.groupby("spin_phase").median(skipna=True)
|
|
328
|
-
|
|
329
333
|
if np.any(np.isnan(deadtime_medians["deadtime_ratio"].values)):
|
|
330
|
-
|
|
331
|
-
"
|
|
334
|
+
if not np.any(np.isfinite(deadtime_medians["deadtime_ratio"].values)):
|
|
335
|
+
raise ValueError("All dead time ratios are NaN, cannot interpolate.")
|
|
336
|
+
logger.warning(
|
|
337
|
+
"Dead time ratios contain NaN values, filtering data to only include "
|
|
338
|
+
"finite values."
|
|
332
339
|
)
|
|
340
|
+
deadtime_medians = deadtime_medians.where(
|
|
341
|
+
np.isfinite(deadtime_medians["deadtime_ratio"]), drop=True
|
|
342
|
+
)
|
|
333
343
|
interpolator = interpolate.PchipInterpolator(
|
|
334
344
|
deadtime_medians["spin_phase"].values, deadtime_medians["deadtime_ratio"].values
|
|
335
345
|
)
|
|
@@ -340,19 +350,17 @@ def get_deadtime_ratios_by_spin_phase(
|
|
|
340
350
|
return interpolator(nominal_spin_phases_1ms_res)
|
|
341
351
|
|
|
342
352
|
|
|
343
|
-
def
|
|
344
|
-
exposure_pointing: pandas.DataFrame,
|
|
353
|
+
def calculate_exposure_time(
|
|
345
354
|
deadtime_ratios: np.ndarray,
|
|
346
355
|
pixels_below_scattering: list,
|
|
347
356
|
boundary_scale_factors: NDArray,
|
|
357
|
+
n_pix: int,
|
|
348
358
|
) -> np.ndarray:
|
|
349
359
|
"""
|
|
350
360
|
Adjust the exposure time at each pixel to account for dead time.
|
|
351
361
|
|
|
352
362
|
Parameters
|
|
353
363
|
----------
|
|
354
|
-
exposure_pointing : pandas.DataFrame
|
|
355
|
-
Exposure data.
|
|
356
364
|
deadtime_ratios : PchipInterpolator
|
|
357
365
|
Interpolating function for dead time ratios.
|
|
358
366
|
pixels_below_scattering : list
|
|
@@ -362,6 +370,8 @@ def apply_deadtime_correction(
|
|
|
362
370
|
the FWHM scattering threshold.
|
|
363
371
|
boundary_scale_factors : np.ndarray
|
|
364
372
|
Boundary scale factors for each pixel at each spin phase.
|
|
373
|
+
n_pix : int
|
|
374
|
+
Number of HEALPix pixels.
|
|
365
375
|
|
|
366
376
|
Returns
|
|
367
377
|
-------
|
|
@@ -370,12 +380,8 @@ def apply_deadtime_correction(
|
|
|
370
380
|
"""
|
|
371
381
|
# Get energy bin geometric means
|
|
372
382
|
energy_bin_geometric_means = build_energy_bins()[2]
|
|
373
|
-
# Exposure time should now be of shape (
|
|
374
|
-
exposure_pointing = np.
|
|
375
|
-
exposure_pointing.to_numpy()[np.newaxis, :],
|
|
376
|
-
len(energy_bin_geometric_means),
|
|
377
|
-
axis=0,
|
|
378
|
-
)
|
|
383
|
+
# Exposure time should now be of shape (energy, npix)
|
|
384
|
+
exposure_pointing = np.zeros((len(energy_bin_geometric_means), n_pix))
|
|
379
385
|
# nominal spin phase step.
|
|
380
386
|
nominal_ms_step = 15 / len(pixels_below_scattering) # time step
|
|
381
387
|
# Query the dead-time ratio and apply the nominal exposure time to pixels in the FOR
|
|
@@ -400,19 +406,17 @@ def apply_deadtime_correction(
|
|
|
400
406
|
|
|
401
407
|
|
|
402
408
|
def get_spacecraft_exposure_times(
|
|
403
|
-
constant_exposure: pandas.DataFrame,
|
|
404
409
|
rates_dataset: xr.Dataset,
|
|
405
410
|
params_dataset: xr.Dataset,
|
|
406
411
|
pixels_below_scattering: list[list],
|
|
407
412
|
boundary_scale_factors: NDArray,
|
|
413
|
+
n_pix: int,
|
|
408
414
|
) -> tuple[NDArray, NDArray]:
|
|
409
415
|
"""
|
|
410
416
|
Compute exposure times for HEALPix pixels.
|
|
411
417
|
|
|
412
418
|
Parameters
|
|
413
419
|
----------
|
|
414
|
-
constant_exposure : pandas.DataFrame
|
|
415
|
-
Exposure data.
|
|
416
420
|
rates_dataset : xarray.Dataset
|
|
417
421
|
Dataset containing image rates data.
|
|
418
422
|
params_dataset : xarray.Dataset
|
|
@@ -424,6 +428,8 @@ def get_spacecraft_exposure_times(
|
|
|
424
428
|
below the FWHM scattering threshold.
|
|
425
429
|
boundary_scale_factors : np.ndarray
|
|
426
430
|
Boundary scale factors for each pixel at each spin phase.
|
|
431
|
+
n_pix : int
|
|
432
|
+
Number of HEALPix pixels.
|
|
427
433
|
|
|
428
434
|
Returns
|
|
429
435
|
-------
|
|
@@ -438,14 +444,8 @@ def get_spacecraft_exposure_times(
|
|
|
438
444
|
# universal pointing table here to determine actual number of spins
|
|
439
445
|
sectored_rates = get_sectored_rates(rates_dataset, params_dataset)
|
|
440
446
|
nominal_deadtime_ratios = get_deadtime_ratios_by_spin_phase(sectored_rates)
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
) # 5760 spins per pointing (for now)
|
|
444
|
-
exposure_pointing_adjusted = apply_deadtime_correction(
|
|
445
|
-
exposure_pointing,
|
|
446
|
-
nominal_deadtime_ratios,
|
|
447
|
-
pixels_below_scattering,
|
|
448
|
-
boundary_scale_factors,
|
|
447
|
+
exposure_pointing_adjusted = calculate_exposure_time(
|
|
448
|
+
nominal_deadtime_ratios, pixels_below_scattering, boundary_scale_factors, n_pix
|
|
449
449
|
)
|
|
450
450
|
return exposure_pointing_adjusted, nominal_deadtime_ratios
|
|
451
451
|
|
|
@@ -664,7 +664,7 @@ def get_spacecraft_background_rates(
|
|
|
664
664
|
sensor: str,
|
|
665
665
|
ancillary_files: dict,
|
|
666
666
|
energy_bin_edges: list[tuple[float, float]],
|
|
667
|
-
|
|
667
|
+
goodtimes_spin_number: NDArray,
|
|
668
668
|
nside: int = 128,
|
|
669
669
|
) -> NDArray:
|
|
670
670
|
"""
|
|
@@ -680,9 +680,9 @@ def get_spacecraft_background_rates(
|
|
|
680
680
|
Ancillary files containing the lookup tables.
|
|
681
681
|
energy_bin_edges : list[tuple[float, float]]
|
|
682
682
|
Energy bin edges.
|
|
683
|
-
|
|
683
|
+
goodtimes_spin_number : NDArray
|
|
684
684
|
Goodtime spins.
|
|
685
|
-
Ex. imap_ultra_l1b_45sensor-
|
|
685
|
+
Ex. imap_ultra_l1b_45sensor-goodtimes[0]["spin_number"]
|
|
686
686
|
This is used to determine the number of pulses per spin.
|
|
687
687
|
nside : int, optional
|
|
688
688
|
The nside parameter of the Healpix tessellation (default is 128).
|
|
@@ -714,7 +714,7 @@ def get_spacecraft_background_rates(
|
|
|
714
714
|
background_rates = np.zeros((len(energy_bin_edges), n_pix))
|
|
715
715
|
|
|
716
716
|
# Only select pulses from goodtimes.
|
|
717
|
-
goodtime_mask = np.isin(spin_number,
|
|
717
|
+
goodtime_mask = np.isin(spin_number, goodtimes_spin_number)
|
|
718
718
|
mean_start_pulses = np.mean(pulses.start_pulses[goodtime_mask])
|
|
719
719
|
mean_stop_pulses = np.mean(pulses.stop_pulses[goodtime_mask])
|
|
720
720
|
mean_coin_pulses = np.mean(pulses.coin_pulses[goodtime_mask])
|
|
@@ -10,6 +10,7 @@ import xarray as xr
|
|
|
10
10
|
from numpy.typing import NDArray
|
|
11
11
|
|
|
12
12
|
from imap_processing.cdf.imap_cdf_manager import ImapCdfAttributes
|
|
13
|
+
from imap_processing.cdf.utils import load_cdf
|
|
13
14
|
from imap_processing.ena_maps import ena_maps
|
|
14
15
|
from imap_processing.ena_maps.utils.coordinates import CoordNames
|
|
15
16
|
from imap_processing.ena_maps.utils.naming import (
|
|
@@ -17,6 +18,7 @@ from imap_processing.ena_maps.utils.naming import (
|
|
|
17
18
|
MapDescriptor,
|
|
18
19
|
ns_to_duration_months,
|
|
19
20
|
)
|
|
21
|
+
from imap_processing.quality_flags import ImapPSETUltraFlags
|
|
20
22
|
from imap_processing.ultra.l1c.ultra_l1c_pset_bins import get_energy_delta_minus_plus
|
|
21
23
|
|
|
22
24
|
logger = logging.getLogger(__name__)
|
|
@@ -58,7 +60,15 @@ REQUIRED_L1C_VARIABLES_PULL = [
|
|
|
58
60
|
"background_rates",
|
|
59
61
|
"obs_date",
|
|
60
62
|
]
|
|
61
|
-
|
|
63
|
+
# These variables are expected but not strictly required. In certain test scenarios,
|
|
64
|
+
# they may be missing, in which case we will raise a warning and continue.
|
|
65
|
+
# All psets must be consistent and either have these variables or not.
|
|
66
|
+
EXPECTED_L1C_VARIABLES_PULL = [
|
|
67
|
+
"geometric_function",
|
|
68
|
+
"efficiency",
|
|
69
|
+
"scatter_theta",
|
|
70
|
+
"scatter_phi",
|
|
71
|
+
]
|
|
62
72
|
# These variables are projected to the map as the mean of pointing set pixels value,
|
|
63
73
|
# weighted by that pointing set pixel's exposure and solid angle
|
|
64
74
|
VARIABLES_TO_WEIGHT_BY_POINTING_SET_EXPOSURE_TIMES_SOLID_ANGLE = [
|
|
@@ -71,12 +81,9 @@ VARIABLES_TO_WEIGHT_BY_POINTING_SET_EXPOSURE_TIMES_SOLID_ANGLE = [
|
|
|
71
81
|
# calculate ena_intensity and its statistical uncertainty
|
|
72
82
|
# They will not be present in the final map
|
|
73
83
|
VARIABLES_TO_DROP_AFTER_INTENSITY_CALCULATION = [
|
|
74
|
-
"counts",
|
|
75
|
-
"background_rates",
|
|
76
84
|
"pointing_set_exposure_times_solid_angle",
|
|
77
85
|
"num_pointing_set_pixel_members",
|
|
78
86
|
"corrected_count_rate",
|
|
79
|
-
"obs_date_for_std",
|
|
80
87
|
"obs_date_squared_for_std",
|
|
81
88
|
]
|
|
82
89
|
|
|
@@ -127,6 +134,8 @@ def get_variable_attributes_optional_energy_dependence(
|
|
|
127
134
|
and (CoordNames.ENERGY_ULTRA_L1C.value not in variable_dims)
|
|
128
135
|
):
|
|
129
136
|
variable_name = f"{variable_name}_energy_independent"
|
|
137
|
+
if variable_name == "counts":
|
|
138
|
+
variable_name = "ena_count"
|
|
130
139
|
|
|
131
140
|
metadata = cdf_attrs.get_variable_attributes(
|
|
132
141
|
variable_name=variable_name,
|
|
@@ -205,7 +214,7 @@ def generate_ultra_healpix_skymap(
|
|
|
205
214
|
output_map_structure.values_to_push_project.extend(
|
|
206
215
|
[
|
|
207
216
|
"num_pointing_set_pixel_members",
|
|
208
|
-
"
|
|
217
|
+
"obs_date_range",
|
|
209
218
|
"obs_date_squared_for_std",
|
|
210
219
|
]
|
|
211
220
|
)
|
|
@@ -235,6 +244,27 @@ def generate_ultra_healpix_skymap(
|
|
|
235
244
|
f"PUSH Variables: {output_map_structure.values_to_push_project} \n"
|
|
236
245
|
f"PULL Variables: {output_map_structure.values_to_pull_project}"
|
|
237
246
|
)
|
|
247
|
+
# TODO remove this in the future once all test data includes these variables
|
|
248
|
+
# Add expected but not required variables to the pull projection list
|
|
249
|
+
# Log a warning if they are missing from any PSET but continue processing.
|
|
250
|
+
expected_present_vars = []
|
|
251
|
+
first_pset = (
|
|
252
|
+
load_cdf(ultra_l1c_psets[0])
|
|
253
|
+
if isinstance(ultra_l1c_psets[0], (str, Path))
|
|
254
|
+
else ultra_l1c_psets[0]
|
|
255
|
+
)
|
|
256
|
+
for var in EXPECTED_L1C_VARIABLES_PULL:
|
|
257
|
+
if var not in first_pset.variables:
|
|
258
|
+
logger.warning(
|
|
259
|
+
f"Expected variable {var} not found in the first L1C PSET. "
|
|
260
|
+
"This variable will not be projected to the map."
|
|
261
|
+
)
|
|
262
|
+
else:
|
|
263
|
+
expected_present_vars.append(var)
|
|
264
|
+
|
|
265
|
+
output_map_structure.values_to_pull_project = list(
|
|
266
|
+
set(output_map_structure.values_to_pull_project + expected_present_vars)
|
|
267
|
+
)
|
|
238
268
|
|
|
239
269
|
all_pset_epochs = []
|
|
240
270
|
for ultra_l1c_pset in ultra_l1c_psets:
|
|
@@ -248,9 +278,15 @@ def generate_ultra_healpix_skymap(
|
|
|
248
278
|
"\nThese values will be pull projected: "
|
|
249
279
|
f">> {output_map_structure.values_to_pull_project}",
|
|
250
280
|
)
|
|
281
|
+
flags_1d = pointing_set.data["quality_flags"].isel(epoch=0)
|
|
282
|
+
# This is a good pixel mask where zero is when the earth is not in the FOV.
|
|
283
|
+
good_pixel_mask = (
|
|
284
|
+
(flags_1d & ImapPSETUltraFlags.EARTH_FOV.value) == 0
|
|
285
|
+
).to_numpy()
|
|
251
286
|
|
|
287
|
+
# Only count the number of pointing set pixels which are not flagged.
|
|
252
288
|
pointing_set.data["num_pointing_set_pixel_members"] = xr.DataArray(
|
|
253
|
-
|
|
289
|
+
good_pixel_mask.astype(int),
|
|
254
290
|
dims=(CoordNames.HEALPIX_INDEX.value),
|
|
255
291
|
)
|
|
256
292
|
|
|
@@ -261,11 +297,11 @@ def generate_ultra_healpix_skymap(
|
|
|
261
297
|
fill_value=pointing_set.epoch,
|
|
262
298
|
dtype=np.int64,
|
|
263
299
|
)
|
|
264
|
-
pointing_set.data["
|
|
300
|
+
pointing_set.data["obs_date_range"] = pointing_set.data["obs_date"].astype(
|
|
265
301
|
np.float64
|
|
266
302
|
)
|
|
267
303
|
pointing_set.data["obs_date_squared_for_std"] = (
|
|
268
|
-
pointing_set.data["
|
|
304
|
+
pointing_set.data["obs_date_range"] ** 2
|
|
269
305
|
)
|
|
270
306
|
|
|
271
307
|
# Add solid_angle * exposure of pointing set as data_var
|
|
@@ -276,15 +312,22 @@ def generate_ultra_healpix_skymap(
|
|
|
276
312
|
|
|
277
313
|
# Initial processing for weighted quantities at PSET level
|
|
278
314
|
# Weight the values by exposure and solid angle
|
|
315
|
+
# Ensure only valid pointing set pixels contribute to the weighted mean.
|
|
279
316
|
pointing_set.data[
|
|
280
317
|
VARIABLES_TO_WEIGHT_BY_POINTING_SET_EXPOSURE_TIMES_SOLID_ANGLE
|
|
281
|
-
]
|
|
318
|
+
] = (
|
|
319
|
+
pointing_set.data[
|
|
320
|
+
VARIABLES_TO_WEIGHT_BY_POINTING_SET_EXPOSURE_TIMES_SOLID_ANGLE
|
|
321
|
+
]
|
|
322
|
+
* pointing_set.data["pointing_set_exposure_times_solid_angle"]
|
|
323
|
+
).where(good_pixel_mask)
|
|
282
324
|
|
|
283
325
|
# Project values such as counts via the PUSH method
|
|
284
326
|
skymap.project_pset_values_to_map(
|
|
285
327
|
pointing_set=pointing_set,
|
|
286
328
|
value_keys=output_map_structure.values_to_push_project,
|
|
287
329
|
index_match_method=ena_maps.IndexMatchMethod.PUSH,
|
|
330
|
+
pset_valid_mask=good_pixel_mask,
|
|
288
331
|
)
|
|
289
332
|
|
|
290
333
|
# Project values such as exposure_factor via the PULL method
|
|
@@ -292,6 +335,7 @@ def generate_ultra_healpix_skymap(
|
|
|
292
335
|
pointing_set=pointing_set,
|
|
293
336
|
value_keys=output_map_structure.values_to_pull_project,
|
|
294
337
|
index_match_method=ena_maps.IndexMatchMethod.PULL,
|
|
338
|
+
pset_valid_mask=good_pixel_mask,
|
|
295
339
|
)
|
|
296
340
|
|
|
297
341
|
# Subsequent processing for weighted quantities at SkyMap level
|
|
@@ -347,7 +391,7 @@ def generate_ultra_healpix_skymap(
|
|
|
347
391
|
)
|
|
348
392
|
- (
|
|
349
393
|
(
|
|
350
|
-
skymap.data_1d["
|
|
394
|
+
skymap.data_1d["obs_date_range"]
|
|
351
395
|
/ (skymap.data_1d["num_pointing_set_pixel_members"])
|
|
352
396
|
)
|
|
353
397
|
** 2
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
"""Create dataset."""
|
|
2
2
|
|
|
3
|
-
import numpy as np
|
|
4
3
|
import xarray as xr
|
|
5
4
|
|
|
6
5
|
from imap_processing.cdf.imap_cdf_manager import ImapCdfAttributes
|
|
@@ -32,7 +31,7 @@ def create_dataset( # noqa: PLR0912
|
|
|
32
31
|
cdf_manager.add_instrument_global_attrs("ultra")
|
|
33
32
|
cdf_manager.add_instrument_variable_attrs("ultra", level)
|
|
34
33
|
|
|
35
|
-
# L1b extended spin, badtimes, and
|
|
34
|
+
# L1b extended spin, badtimes, and goodtimes data products
|
|
36
35
|
if "spin_number" in data_dict.keys():
|
|
37
36
|
coords = {
|
|
38
37
|
"spin_number": ("spin_number", data_dict["spin_number"]),
|
|
@@ -40,7 +39,6 @@ def create_dataset( # noqa: PLR0912
|
|
|
40
39
|
"energy_bin_geometric_mean",
|
|
41
40
|
data_dict["energy_bin_geometric_mean"],
|
|
42
41
|
),
|
|
43
|
-
"epoch": ("spin_number", np.asarray(data_dict["epoch"])),
|
|
44
42
|
}
|
|
45
43
|
default_dimension = "spin_number"
|
|
46
44
|
# L1c pset data products
|
|
@@ -110,7 +108,12 @@ def create_dataset( # noqa: PLR0912
|
|
|
110
108
|
dims=["epoch", "component"],
|
|
111
109
|
attrs=cdf_manager.get_variable_attributes(key, check_schema=False),
|
|
112
110
|
)
|
|
113
|
-
elif key
|
|
111
|
+
elif key in [
|
|
112
|
+
"ena_rates_threshold",
|
|
113
|
+
"scatter_threshold",
|
|
114
|
+
"energy_delta_minus",
|
|
115
|
+
"energy_delta_plus",
|
|
116
|
+
]:
|
|
114
117
|
dataset[key] = xr.DataArray(
|
|
115
118
|
data,
|
|
116
119
|
dims=["energy_bin_geometric_mean"],
|
|
@@ -134,7 +137,7 @@ def create_dataset( # noqa: PLR0912
|
|
|
134
137
|
dims=["energy_bin_geometric_mean", "spin_number"],
|
|
135
138
|
attrs=cdf_manager.get_variable_attributes(key, check_schema=False),
|
|
136
139
|
)
|
|
137
|
-
elif key in {"latitude", "longitude"}:
|
|
140
|
+
elif key in {"quality_flags", "latitude", "longitude"}:
|
|
138
141
|
dataset[key] = xr.DataArray(
|
|
139
142
|
data,
|
|
140
143
|
dims=["epoch", "pixel_index"],
|
|
@@ -155,6 +158,8 @@ def create_dataset( # noqa: PLR0912
|
|
|
155
158
|
"sensitivity",
|
|
156
159
|
"efficiency",
|
|
157
160
|
"geometric_function",
|
|
161
|
+
"scatter_theta",
|
|
162
|
+
"scatter_phi",
|
|
158
163
|
}:
|
|
159
164
|
dataset[key] = xr.DataArray(
|
|
160
165
|
data,
|