Skip to content

Commit d73d824

Browse files
authored
ULTRA l1b fix repoint filtering (#2380)
* fix repoint filtering
1 parent 1254f55 commit d73d824

File tree

5 files changed

+66
-25
lines changed

5 files changed

+66
-25
lines changed

imap_processing/quality_flags.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class ImapDEOutliersUltraFlags(FlagNameMixin):
4545
PHCORR = 2**1 # bit 1
4646
COINPH = 2**2 # bit 2 # Event validity
4747
INVALID_ENERGY = 2**3 # bit 3
48+
DURINGREPOINT = 2**4 # bit 4 # event during a repointing
4849

4950

5051
class ImapHkUltraFlags(FlagNameMixin):
@@ -65,7 +66,6 @@ class ImapAttitudeUltraFlags(FlagNameMixin):
6566
AUXMISMATCH = 2**1 # bit 1 # aux packet does not match Universal Spin Table
6667
SPINPHASE = 2**2 # bit 2 # spin phase flagged by Universal Spin Table
6768
SPINPERIOD = 2**3 # bit 3 # spin period flagged by Universal Spin Table
68-
DURINGREPOINT = 2**4 # bit 4 # spin during a repointing
6969

7070

7171
class ImapRatesUltraFlags(FlagNameMixin):

imap_processing/tests/ultra/unit/test_ultra_l1b.py

Lines changed: 51 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
from imap_processing import imap_module_directory
88
from imap_processing.cdf.utils import load_cdf, write_cdf
9+
from imap_processing.quality_flags import ImapDEOutliersUltraFlags
10+
from imap_processing.ultra.l1b.de import FILLVAL_FLOAT32
911
from imap_processing.ultra.l1b.ultra_l1b import ultra_l1b
1012
from imap_processing.ultra.utils.ultra_l1_utils import create_dataset
1113

@@ -71,6 +73,29 @@ def mock_data_l1b_extendedspin_dict():
7173
return data_dict
7274

7375

76+
@pytest.fixture
77+
def mock_get_annotated_particle_velocity():
78+
"""
79+
Mock behavior of get_annotated_particle_velocity.
80+
81+
Returns NaN-filled arrays matching the expected output shape.
82+
"""
83+
84+
def side_effect_func(event_times, position, ultra_frame, dps_frame, sc_frame):
85+
num_events = event_times.size
86+
return (
87+
np.full((num_events, 3), np.nan), # sc_velocity
88+
np.full((num_events, 3), np.nan), # sc_dps_velocity
89+
np.full((num_events, 3), np.nan), # helio_velocity
90+
)
91+
92+
with mock.patch(
93+
"imap_processing.ultra.l1b.de.get_annotated_particle_velocity"
94+
) as mocked_func:
95+
mocked_func.side_effect = side_effect_func
96+
yield mocked_func
97+
98+
7499
def test_create_extendedspin_dataset(mock_data_l1b_extendedspin_dict):
75100
"""Tests that dataset is created as expected."""
76101
dataset = create_dataset(
@@ -101,13 +126,12 @@ def test_create_de_dataset(mock_data_l1b_de_dict):
101126

102127

103128
@pytest.mark.external_test_data
104-
@mock.patch("imap_processing.ultra.l1b.de.get_annotated_particle_velocity")
105129
def test_cdf_de(
106-
mock_get_annotated_particle_velocity,
107130
de_dataset,
108131
use_fake_spin_data_for_time,
109132
ancillary_files,
110133
use_fake_repoint_data_for_time,
134+
mock_get_annotated_particle_velocity,
111135
):
112136
"""Tests that CDF file is created and contains same attributes as xarray."""
113137

@@ -118,22 +142,6 @@ def test_cdf_de(
118142
use_fake_spin_data_for_time(511000000, 511000000 + 86400 * 5)
119143
use_fake_repoint_data_for_time(np.arange(511000000, 511000000 + 86400 * 5, 86400))
120144

121-
# Mock get_annotated_particle_velocity to avoid needing kernels
122-
def side_effect_func(event_times, position, ultra_frame, dps_frame, sc_frame):
123-
"""
124-
Mock behavior of get_annotated_particle_velocity.
125-
126-
Returns NaN-filled arrays matching the expected output shape.
127-
"""
128-
num_events = event_times.size
129-
return (
130-
np.full((num_events, 3), np.nan), # sc_velocity
131-
np.full((num_events, 3), np.nan), # sc_dps_velocity
132-
np.full((num_events, 3), np.nan), # helio_velocity
133-
)
134-
135-
mock_get_annotated_particle_velocity.side_effect = side_effect_func
136-
137145
l1b_de_dataset = ultra_l1b(data_dict, ancillary_files)
138146

139147
assert (
@@ -151,6 +159,31 @@ def side_effect_func(event_times, position, ultra_frame, dps_frame, sc_frame):
151159
)
152160

153161

162+
@pytest.mark.external_test_data
163+
def test_cdf_de_flags(
164+
mock_get_annotated_particle_velocity,
165+
de_dataset,
166+
use_fake_spin_data_for_time,
167+
ancillary_files,
168+
use_fake_repoint_data_for_time,
169+
):
170+
"""Tests that the de code flags events not in a repointing."""
171+
data_dict = {}
172+
de_dataset.attrs["Repointing"] = "repoint00000"
173+
data_dict[de_dataset.attrs["Logical_source"]] = de_dataset
174+
# Create a spin table that cover spin 0-141
175+
use_fake_spin_data_for_time(511000000, 511000000 + 86400 * 5)
176+
# Use repoint data that will NOT cover the event times to test flag setting
177+
use_fake_repoint_data_for_time(np.arange(0, +86400 * 5, 86400))
178+
179+
l1b_de_dataset = ultra_l1b(data_dict, ancillary_files)
180+
# All valid events should be flagged as DURINGREPOINT since the repoint data does
181+
# not cover any of the event times
182+
valid_events = l1b_de_dataset[0]["event_times"] != FILLVAL_FLOAT32
183+
flags = l1b_de_dataset[0]["quality_outliers"].values[valid_events]
184+
assert np.all((flags & ImapDEOutliersUltraFlags.DURINGREPOINT.value) != 0)
185+
186+
154187
@pytest.mark.external_test_data
155188
def test_ultra_l1b_extendedspin(
156189
use_fake_spin_data_for_time, faux_aux_dataset, rates_dataset

imap_processing/ultra/l1b/de.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55

66
from imap_processing.cdf.utils import parse_filename_like
77
from imap_processing.quality_flags import (
8-
ImapAttitudeUltraFlags,
98
ImapDEOutliersUltraFlags,
109
ImapDEScatteringUltraFlags,
1110
)
@@ -326,10 +325,10 @@ def calculate_de(
326325
in_pointing = calculate_events_in_pointing(
327326
repoint_id, event_times[valid_events]
328327
)
328+
events_to_flag = np.zeros(len(quality_flags), dtype=bool)
329+
events_to_flag[valid_events] = ~in_pointing
329330
# Update quality flags for valid events that are not in the pointing
330-
quality_flags[valid_events][~in_pointing] |= (
331-
ImapAttitudeUltraFlags.DURINGREPOINT.value
332-
)
331+
quality_flags[events_to_flag] |= ImapDEOutliersUltraFlags.DURINGREPOINT.value
333332
# Update valid_events to only include times within a pointing
334333
valid_events[valid_events] &= in_pointing
335334

imap_processing/ultra/l1b/quality_flag_filters.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@
1616
}
1717

1818
DE_QUALITY_FLAG_FILTERS: dict[str, list[FlagNameMixin]] = {
19-
"quality_outliers": [ImapDEOutliersUltraFlags.FOV],
19+
"quality_outliers": [
20+
ImapDEOutliersUltraFlags.FOV,
21+
ImapDEOutliersUltraFlags.DURINGREPOINT,
22+
],
2023
"quality_scattering": [
2124
ImapDEScatteringUltraFlags.ABOVE_THRESHOLD,
2225
],

imap_processing/ultra/l1c/ultra_l1c_pset_bins.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ def get_deadtime_ratios_by_spin_phase(
292292
numpy.ndarray
293293
Nominal deadtime ratios at every spin phase step.
294294
"""
295-
if sectored_rates is None:
295+
if sectored_rates is None or sectored_rates.epoch.size == 0:
296296
logger.warning(
297297
"No sector mode data found in the parameters dataset. Using "
298298
"static dead time ratios from an ancillary file."
@@ -455,6 +455,12 @@ def get_spacecraft_exposure_times(
455455
nominal_deadtime_ratios : np.ndarray
456456
Deadtime ratios at each spin phase step (1ms res).
457457
"""
458+
# filter rates dataset to only include data during a pointing
459+
rates_time = ttj2000ns_to_met(rates_dataset.epoch.data)
460+
pointing_mask = (rates_time >= pointing_range_met[0]) & (
461+
rates_time <= pointing_range_met[1]
462+
)
463+
rates_dataset.isel(epoch=pointing_mask)
458464
sectored_rates = get_sectored_rates(rates_dataset, params_dataset)
459465
# Get the number of steps used in the spun pointing lookup tables
460466
spin_steps = len(pixels_below_scattering)

0 commit comments

Comments
 (0)