Skip to content

Commit 9d19c54

Browse files
author
Menlo Innovations - CAVA Project
committed
Harrison 3098 - EYEA - Maps: Use default SP values of 1 where there is no GLOWS data
1 parent eff9e94 commit 9d19c54

11 files changed

Lines changed: 257 additions & 50 deletions

imap_l3_processing/maps/rectangular_survival_probability.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from typing import Optional
2+
13
import numpy as np
24
import xarray as xr
35
from imap_processing.ena_maps.ena_maps import RectangularSkyMap, PointingSet
@@ -23,7 +25,7 @@ def interpolate_angular_data_to_nearest_neighbor(input_azimuths: np.array, glows
2325

2426
class RectangularSurvivalProbabilityPointingSet(PointingSet):
2527
def __init__(self, l1c_dataset: InputRectangularPointingSet, sensor: Sensor, spin_phase: SpinPhase,
26-
glows_dataset: GlowsL3eRectangularMapInputData, energies: np.ndarray, cg_corrected: bool = False):
28+
glows_dataset: GlowsL3eRectangularMapInputData | None, energies: np.ndarray, cg_corrected: bool = False):
2729
num_spin_angle_bins = l1c_dataset.exposure_times.shape[-1]
2830

2931
deg_spacing = 360 / num_spin_angle_bins
@@ -135,7 +137,7 @@ def __init__(self, l1c_dataset: InputRectangularPointingSet, sensor: Sensor, spi
135137
self.azimuths, glows_dataset.spin_angle, sp_interpolated_to_hi_energies)
136138
sp_final = sp_interpolated_to_pset_angles
137139
else:
138-
sp_final = np.full((1, len(energies), 3600), np.nan)
140+
sp_final = np.ones((1, len(energies), 3600))
139141

140142
dataset["survival_probability_times_exposure"] = xr.DataArray(
141143
sp_final * exposure,

imap_l3_processing/maps/sp_map_initializer.py

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,10 @@ def get_maps_that_can_be_produced(self, l3_descriptor: str) -> list[PossibleMapT
3434
map_duration = get_duration_from_map_descriptor(l3_descriptor_parts)
3535

3636
glows_file_by_repointing = self._collect_glows_psets_by_repoint(l3_descriptor_parts)
37+
3738
if len(glows_file_by_repointing) == 0:
38-
logger.info(f"No GLOWS data available for descriptor {l3_descriptor}, no maps will be produced!")
39-
return []
40-
glows_start_dates = [ScienceFilePath(glows_path).start_date for glows_path in glows_file_by_repointing.values()]
41-
glows_data_end_date = datetime.strptime(max(glows_start_dates), "%Y%m%d")
39+
logger.info(f"No GLOWS data available for descriptor {l3_descriptor}. "
40+
f"Processing will use default survival probability of 1.0.")
4241

4342
l2_descriptors = self._get_l2_dependencies(l3_descriptor_parts)
4443
l2_descriptor_strs = [map_descriptor_parts_to_string(parts) for parts in l2_descriptors]
@@ -51,9 +50,6 @@ def get_maps_that_can_be_produced(self, l3_descriptor: str) -> list[PossibleMapT
5150
possible_maps = []
5251
for str_start_date in sorted(list(possible_start_dates)):
5352
start_date = datetime.strptime(str_start_date, "%Y%m%d")
54-
if start_date + map_duration > glows_data_end_date:
55-
logger.info(f"Not enough GLOWS data to produce map {l3_descriptor} {str_start_date}")
56-
continue
5753

5854
l2_file_paths = []
5955
for l2_descriptor in l2_descriptor_strs:
@@ -83,14 +79,13 @@ def get_maps_that_can_be_produced(self, l3_descriptor: str) -> list[PossibleMapT
8379
glows_files = [glows_file_by_repointing[repoint] for repoint in l1c_repointings if
8480
repoint in glows_file_by_repointing]
8581

86-
if len(glows_files) > 0:
87-
input_metadata = InputMetadata(instrument=self.instrument, data_level='l3', start_date=start_date,
88-
end_date=start_date + map_duration, version='v001',
89-
descriptor=l3_descriptor)
82+
input_metadata = InputMetadata(instrument=self.instrument, data_level='l3', start_date=start_date,
83+
end_date=start_date + map_duration, version='v001',
84+
descriptor=l3_descriptor)
9085

91-
possible_map_to_produce = PossibleMapToProduce(
92-
input_files=set(l2_file_paths + glows_files + l1c_names + self._get_ancillary_files()),
93-
input_metadata=input_metadata
94-
)
95-
possible_maps.append(possible_map_to_produce)
86+
possible_map_to_produce = PossibleMapToProduce(
87+
input_files=set(l2_file_paths + glows_files + l1c_names + self._get_ancillary_files()),
88+
input_metadata=input_metadata
89+
)
90+
possible_maps.append(possible_map_to_produce)
9691
return possible_maps

imap_l3_processing/ultra/science/ultra_survival_probability.py

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,35 +15,41 @@
1515

1616

1717
class UltraSurvivalProbability(UltraPointingSet):
18-
def __init__(self, l1c_pset: UltraL1CPSet, l3e_glows: UltraGlowsL3eData, bin_groups: Optional[np.ndarray] = None):
18+
def __init__(self, l1c_pset: UltraL1CPSet, l3e_glows: Optional[UltraGlowsL3eData],
19+
bin_groups: Optional[np.ndarray] = None):
1920
coarse_bins = bin_pset_energy_bins(l1c_pset.to_xarray(), bin_groups)
2021
super().__init__(coarse_bins, geometry.SpiceFrame.IMAP_DPS)
2122

22-
l1c_epoch_in_et = spiceypy.unitim(self.data.coords[CoordNames.TIME.value].values[0] / ONE_SECOND_IN_NANOSECONDS,
23-
"TT", "ET")
24-
rotated_az_el_points = geometry.frame_transform_az_el(l1c_epoch_in_et, self.az_el_points,
25-
geometry.SpiceFrame.IMAP_DPS,
26-
geometry.SpiceFrame.ECLIPJ2000)
27-
glows_nside = npix_to_nside(len(l3e_glows.healpix_index))
28-
glows_healpix = HEALPix(nside=glows_nside)
23+
if l3e_glows is None:
24+
num_pixels = len(l1c_pset.healpix_index)
25+
num_energies = len(coarse_bins.energy_bin_geometric_mean)
26+
energy_interpolated_sp = np.ones((num_energies, num_pixels))
27+
else:
28+
l1c_epoch_in_et = spiceypy.unitim(
29+
self.data.coords[CoordNames.TIME.value].values[0] / ONE_SECOND_IN_NANOSECONDS, "TT", "ET")
30+
rotated_az_el_points = geometry.frame_transform_az_el(l1c_epoch_in_et, self.az_el_points,
31+
geometry.SpiceFrame.IMAP_DPS,
32+
geometry.SpiceFrame.ECLIPJ2000)
33+
glows_nside = npix_to_nside(len(l3e_glows.healpix_index))
34+
glows_healpix = HEALPix(nside=glows_nside)
2935

30-
npixels = len(l1c_pset.healpix_index)
36+
npixels = len(l1c_pset.healpix_index)
3137

32-
spatially_interpolated_sp = np.zeros((len(l3e_glows.energy), npixels))
38+
spatially_interpolated_sp = np.zeros((len(l3e_glows.energy), npixels))
3339

34-
for energy_index in range(len(l3e_glows.energy)):
35-
spatially_interpolated_sp[energy_index, :] = glows_healpix.interpolate_bilinear_lonlat(
36-
Quantity(rotated_az_el_points[:, 0], unit='deg'),
37-
Quantity(rotated_az_el_points[:, 1], unit='deg'),
38-
l3e_glows.survival_probability[0, energy_index, :])
40+
for energy_index in range(len(l3e_glows.energy)):
41+
spatially_interpolated_sp[energy_index, :] = glows_healpix.interpolate_bilinear_lonlat(
42+
Quantity(rotated_az_el_points[:, 0], unit='deg'),
43+
Quantity(rotated_az_el_points[:, 1], unit='deg'),
44+
l3e_glows.survival_probability[0, energy_index, :])
3945

40-
energy_interpolated_sp = np.zeros((len(coarse_bins.energy_bin_geometric_mean), npixels))
41-
for healpix_index in range(npixels):
42-
energy_interpolated_sp[:, healpix_index] = np.interp(
43-
np.log10(coarse_bins.energy_bin_geometric_mean),
44-
np.log10(l3e_glows.energy),
45-
spatially_interpolated_sp[:, healpix_index]
46-
)
46+
energy_interpolated_sp = np.zeros((len(coarse_bins.energy_bin_geometric_mean), npixels))
47+
for healpix_index in range(npixels):
48+
energy_interpolated_sp[:, healpix_index] = np.interp(
49+
np.log10(coarse_bins.energy_bin_geometric_mean),
50+
np.log10(l3e_glows.energy),
51+
spatially_interpolated_sp[:, healpix_index]
52+
)
4753

4854
self.data["survival_probability_times_exposure"] = (
4955
[

imap_l3_processing/utils.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -228,8 +228,8 @@ def combine_glows_l3e_with_l1c_pointing(glows_l3e_data: list[GlowsL3eData], l1c_
228228
l1c_by_repoint = {l1c.repointing: l1c for l1c in l1c_data}
229229
glows_by_repoint = {l3e.repointing: l3e for l3e in glows_l3e_data}
230230

231-
return [(l1c_by_repoint[repoint], glows_by_repoint[repoint]) for repoint in l1c_by_repoint.keys() if
232-
repoint in glows_by_repoint]
231+
return [(l1c_by_repoint[repoint], glows_by_repoint.get(repoint, None))
232+
for repoint in l1c_by_repoint.keys()]
233233

234234

235235
def get_dependency_paths_by_descriptor(deps: ProcessingInputCollection, descriptors: list[str]) -> dict[

tests/hi/test_hi_sp_initializer.py

Lines changed: 99 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,40 @@ def test_get_maps_that_can_be_produced(self, mock_read_cdf_parents):
8383
version="v001",
8484
descriptor='h45-ena-h-sf-sp-anti-hae-4deg-3mo',
8585
)
86-
)
86+
),
87+
PossibleMapToProduce(
88+
input_files={
89+
'imap_hi_l2_h45-ena-h-sf-nsp-anti-hae-4deg-3mo_20100701_v001.cdf',
90+
'imap_glows_l3e_survival-probability-hi-45_20100702-repoint00202_v001.cdf',
91+
'imap_hi_l1c_45sensor-pset_20100401-repoint00201_v001.cdf',
92+
'imap_hi_l1c_45sensor-pset_20100402-repoint00202_v001.cdf',
93+
'imap_hi_l1c_45sensor-pset_20100403-repoint00203_v001.cdf',
94+
},
95+
input_metadata=InputMetadata(
96+
instrument="hi",
97+
data_level="l3",
98+
start_date=datetime(2010, 7, 1),
99+
end_date=datetime(2010, 9, 30, 7, 30),
100+
version="v001",
101+
descriptor='h45-ena-h-sf-sp-anti-hae-4deg-3mo',
102+
)
103+
),
104+
PossibleMapToProduce(
105+
input_files={
106+
'imap_hi_l2_h45-ena-h-sf-nsp-anti-hae-4deg-3mo_20101001_v001.cdf',
107+
'imap_hi_l1c_45sensor-pset_20101001-repoint00301_v001.cdf',
108+
'imap_hi_l1c_45sensor-pset_20101002-repoint00302_v001.cdf',
109+
'imap_hi_l1c_45sensor-pset_20101003-repoint00303_v001.cdf',
110+
},
111+
input_metadata=InputMetadata(
112+
instrument="hi",
113+
data_level="l3",
114+
start_date=datetime(2010, 10, 1),
115+
end_date=datetime(2010, 12, 31, 7, 30),
116+
version="v001",
117+
descriptor='h45-ena-h-sf-sp-anti-hae-4deg-3mo',
118+
)
119+
),
87120
]
88121

89122
initializer = HiSPInitializer()
@@ -100,10 +133,39 @@ def test_get_maps_that_can_be_produced(self, mock_read_cdf_parents):
100133
mock_read_cdf_parents.assert_has_calls([
101134
call('imap_hi_l2_h45-ena-h-sf-nsp-anti-hae-4deg-3mo_20100101_v001.cdf'),
102135
call('imap_hi_l2_h45-ena-h-sf-nsp-anti-hae-4deg-3mo_20100401_v001.cdf'),
136+
call('imap_hi_l2_h45-ena-h-sf-nsp-anti-hae-4deg-3mo_20100701_v001.cdf'),
137+
call('imap_hi_l2_h45-ena-h-sf-nsp-anti-hae-4deg-3mo_20101001_v001.cdf'),
103138
], any_order=True)
104139

105140
self.assertEqual(expected_possible_maps, actual_possible_maps)
106141

142+
@patch('imap_l3_processing.maps.map_initializer.read_cdf_parents')
143+
def test_get_maps_that_can_be_produced_with_no_glows_data(self, mock_read_cdf_parents):
144+
self.mock_query.side_effect = [
145+
create_mock_query_results([]),
146+
create_mock_query_results([]),
147+
create_mock_query_results([
148+
'imap_hi_l2_h45-ena-h-sf-nsp-anti-hae-4deg-3mo_20100101_v001.cdf',
149+
'imap_hi_l2_h45-ena-h-sf-nsp-anti-hae-4deg-3mo_20100401_v001.cdf',
150+
]),
151+
create_mock_query_results([])
152+
]
153+
154+
mock_read_cdf_parents.side_effect = self.create_fake_read_cdf_parents("45")
155+
156+
initializer = HiSPInitializer()
157+
158+
actual_possible_maps = initializer.get_maps_that_can_be_produced('h45-ena-h-sf-sp-anti-hae-4deg-3mo')
159+
160+
self.assertEqual(2, len(actual_possible_maps))
161+
for possible_map in actual_possible_maps:
162+
glows_files = [f for f in possible_map.input_files if 'glows' in f]
163+
self.assertEqual([], glows_files)
164+
l2_files = [f for f in possible_map.input_files if '_l2_' in f]
165+
self.assertGreater(len(l2_files), 0)
166+
l1c_files = [f for f in possible_map.input_files if '_l1c_' in f]
167+
self.assertGreater(len(l1c_files), 0)
168+
107169
@patch('imap_l3_processing.maps.map_initializer.read_cdf_parents')
108170
def test_get_maps_that_can_be_produced_full_spin_descriptor(self, mock_read_cdf_parents):
109171
self.mock_query.side_effect = [
@@ -275,7 +337,40 @@ def test_get_maps_that_should_be_produced(self, mock_read_cdf_parents):
275337
version="v002",
276338
descriptor='h90-ena-h-sf-sp-anti-hae-4deg-3mo',
277339
)
278-
)
340+
),
341+
PossibleMapToProduce(
342+
input_files={
343+
'imap_hi_l2_h90-ena-h-sf-nsp-anti-hae-4deg-3mo_20100701_v001.cdf',
344+
'imap_glows_l3e_survival-probability-hi-90_20100702-repoint00201_v001.cdf',
345+
'imap_hi_l1c_90sensor-pset_20100401-repoint00201_v001.cdf',
346+
'imap_hi_l1c_90sensor-pset_20100402-repoint00202_v001.cdf',
347+
'imap_hi_l1c_90sensor-pset_20100403-repoint00203_v001.cdf',
348+
},
349+
input_metadata=InputMetadata(
350+
instrument="hi",
351+
data_level="l3",
352+
start_date=datetime(2010, 7, 1),
353+
end_date=datetime(2010, 9, 30, 7, 30),
354+
version="v001",
355+
descriptor='h90-ena-h-sf-sp-anti-hae-4deg-3mo',
356+
)
357+
),
358+
PossibleMapToProduce(
359+
input_files={
360+
'imap_hi_l2_h90-ena-h-sf-nsp-anti-hae-4deg-3mo_20101001_v001.cdf',
361+
'imap_hi_l1c_90sensor-pset_20101001-repoint00301_v001.cdf',
362+
'imap_hi_l1c_90sensor-pset_20101002-repoint00302_v001.cdf',
363+
'imap_hi_l1c_90sensor-pset_20101003-repoint00303_v001.cdf',
364+
},
365+
input_metadata=InputMetadata(
366+
instrument="hi",
367+
data_level="l3",
368+
start_date=datetime(2010, 10, 1),
369+
end_date=datetime(2010, 12, 31, 7, 30),
370+
version="v001",
371+
descriptor='h90-ena-h-sf-sp-anti-hae-4deg-3mo',
372+
)
373+
),
279374
]
280375

281376
initializer = HiSPInitializer()
@@ -292,6 +387,8 @@ def test_get_maps_that_should_be_produced(self, mock_read_cdf_parents):
292387
mock_read_cdf_parents.assert_has_calls([
293388
call(f'imap_hi_l2_h90-ena-h-sf-nsp-anti-hae-4deg-3mo_20100101_v001.cdf'),
294389
call(f'imap_hi_l2_h90-ena-h-sf-nsp-anti-hae-4deg-3mo_20100401_v001.cdf'),
390+
call(f'imap_hi_l2_h90-ena-h-sf-nsp-anti-hae-4deg-3mo_20100701_v001.cdf'),
391+
call(f'imap_hi_l2_h90-ena-h-sf-nsp-anti-hae-4deg-3mo_20101001_v001.cdf'),
295392

296393
call(f'imap_hi_l3_h90-ena-h-sf-sp-anti-hae-4deg-3mo_20100101_v001.cdf'),
297394
call(f'imap_hi_l3_h90-ena-h-sf-sp-anti-hae-4deg-3mo_20100401_v001.cdf'),

tests/lo/l3/test_lo_sp_initializer.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,16 @@ def test_get_maps_that_should_be_produced(self, mock_read_cdf_parents):
5555
'imap_lo_l1c_pset_20100402-repoint00102_v001.cdf',
5656
'imap_lo_l1c_pset_20100403-repoint00103_v001.cdf'
5757
],
58+
[
59+
'imap_lo_l1c_pset_20100701-repoint00201_v001.cdf',
60+
'imap_lo_l1c_pset_20100702-repoint00202_v001.cdf',
61+
'imap_lo_l1c_pset_20100703-repoint00203_v001.cdf'
62+
],
63+
[
64+
'imap_lo_l1c_pset_20101001-repoint00301_v001.cdf',
65+
'imap_lo_l1c_pset_20101002-repoint00302_v001.cdf',
66+
'imap_lo_l1c_pset_20101003-repoint00303_v001.cdf'
67+
],
5868
[
5969
'imap_glows_l3e_survival-probability-lo_20100101-repoint00001_v001.cdf',
6070
'imap_glows_l3e_survival-probability-lo_20100102-repoint00002_v001.cdf',
@@ -87,6 +97,8 @@ def test_get_maps_that_should_be_produced(self, mock_read_cdf_parents):
8797
mock_read_cdf_parents.assert_has_calls([
8898
call('imap_lo_l2_l090-ena-h-sf-nsp-ram-hae-6deg-12mo_20100101_v001.cdf'),
8999
call('imap_lo_l2_l090-ena-h-sf-nsp-ram-hae-6deg-12mo_20100401_v001.cdf'),
100+
call('imap_lo_l2_l090-ena-h-sf-nsp-ram-hae-6deg-12mo_20100701_v001.cdf'),
101+
call('imap_lo_l2_l090-ena-h-sf-nsp-ram-hae-6deg-12mo_20101001_v001.cdf'),
90102

91103
call('imap_lo_l3_l090-ena-h-sf-sp-ram-hae-6deg-12mo_20100101_v001.cdf'),
92104
call('imap_lo_l3_l090-ena-h-sf-sp-ram-hae-6deg-12mo_20100401_v001.cdf')
@@ -112,7 +124,8 @@ def test_get_maps_that_should_be_produced(self, mock_read_cdf_parents):
112124
}
113125
)
114126

115-
self.assertEqual([expected_possible_map_to_produce], actual_maps_to_produce)
127+
self.assertIn(expected_possible_map_to_produce, actual_maps_to_produce)
128+
self.assertEqual(3, len(actual_maps_to_produce))
116129

117130
@patch('imap_l3_processing.lo.l3.lo_sp_initializer.furnish_spice_metakernel')
118131
def test_furnish_spice_dependencies(self, mock_furnish_metakernel):

tests/maps/test_rectangular_survival_probability.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,15 @@ def test_exposure_weighting_with_interpolated_survival_probabilities(self):
365365
expected_mask
366366
)
367367

368+
def test_uses_default_survival_probability_of_one_when_glows_is_none(self):
369+
pointing_set = RectangularSurvivalProbabilityPointingSet(
370+
self.l1c_hi_dataset, Sensor.Hi90, SpinPhase.RamOnly,
371+
glows_dataset=None, energies=self.hi_energies)
372+
373+
sp_times_exposure = pointing_set.data["survival_probability_times_exposure"].values
374+
expected = np.ones((1, self.num_energies, 3600)) * self.l1c_hi_dataset.exposure_times
375+
np.testing.assert_array_equal(sp_times_exposure, expected)
376+
368377
def test_exposure_weighted_survivals_are_repeated_to_match_l1c_shape(self):
369378
pointing_set = RectangularSurvivalProbabilityPointingSet(self.l1c_hi_dataset, Sensor.Hi90, SpinPhase.RamOnly,
370379
self.glows_data,

tests/maps/test_survival_probability_processing.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,12 +145,13 @@ def test_integration_uses_fill_values_for_missing_l3e_data(self):
145145

146146
descriptor = parse_map_descriptor("h90-ena-h-sf-nsp-ram-hae-4deg-3mo")
147147
survival_dependencies = HiLoL3SurvivalDependencies(l2_intensity_map, l1c_psets, l3e_psets, descriptor,
148-
l2_intensity_map.intensity_map_data.energy)
148+
Mock())
149149

150150
expected_sky_strip = np.full(45, 2.0)
151+
default_sp_sky_strip = np.full(45, 1.0)
151152

152153
output_map = process_survival_probabilities(survival_dependencies, SpiceFrame.IMAP_HAE)
153154
np.testing.assert_equal(output_map.intensity_map_data.ena_intensity[0, 0, 76, :], expected_sky_strip)
154155
np.testing.assert_equal(output_map.intensity_map_data.ena_intensity[0, 0, 78, :], expected_sky_strip)
155-
np.testing.assert_equal(output_map.intensity_map_data.ena_intensity[0, 0, 79, :], np.full(45, np.nan))
156+
np.testing.assert_equal(output_map.intensity_map_data.ena_intensity[0, 0, 79, :], default_sp_sky_strip)
156157
np.testing.assert_equal(output_map.intensity_map_data.ena_intensity[0, 0, 80, :], expected_sky_strip)

tests/test_utils.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,9 @@ def test_combine_glows_l3e_with_l1c_pointing(self):
479479

480480
expected = [
481481
(hi_l1c_data[0], glows_l3e_data[0]),
482+
(hi_l1c_data[1], None),
482483
(hi_l1c_data[2], glows_l3e_data[3]),
484+
(hi_l1c_data[3], None),
483485
]
484486

485487
actual = combine_glows_l3e_with_l1c_pointing(glows_l3e_data, hi_l1c_data)

0 commit comments

Comments
 (0)