Skip to content

Commit ca62010

Browse files
author
Menlo Innovations - CAVA Project
committed
Harrison 2382 - SWYN/PSCH - Retry fit calculation if density is outside 0 to 185
1 parent 05cb9cc commit ca62010

4 files changed

Lines changed: 188 additions & 32 deletions

File tree

imap_processing/swe/l3/science/moment_calculations.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -211,12 +211,12 @@ def filter_and_flatten_regress_parameters(corrected_energy_bins: np.ndarray,
211211
velocity_vectors: np.ndarray,
212212
phase_space_density: np.ndarray,
213213
weights: np.ndarray,
214-
core_breakpoint: float,
215-
core_halo_breakpoint: float) -> tuple[
214+
core_breakpoint_index: int,
215+
core_halo_breakpoint_index: int) -> tuple[
216216
np.ndarray, np.ndarray, np.ndarray]:
217217
valid_mask = np.full_like(phase_space_density, fill_value=False, dtype=bool)
218-
valid_mask[
219-
np.logical_and(core_breakpoint < corrected_energy_bins, corrected_energy_bins < core_halo_breakpoint)] = True
218+
valid_mask[core_breakpoint_index:core_halo_breakpoint_index] = True
219+
valid_mask[corrected_energy_bins <= 0] = False
220220
valid_mask[phase_space_density <= 0] = False
221221

222222
filtered_phase_space_density = phase_space_density[valid_mask]

imap_processing/swe/swe_processor.py

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -56,21 +56,29 @@ def calculate_moment_products(self, dependencies: SweL3Dependencies):
5656
ccounts = np.reshape(np.arange(24 * 30 * 7), (24, 30, 7)) * 1000
5757

5858
weights: np.ndarray[float] = compute_maxwellian_weight_factors(ccounts)
59-
core_breakpoint: int = 0
6059

61-
filtered_velocity_vectors, filtered_weights, filtered_yreg = filter_and_flatten_regress_parameters(
62-
corrected_energy_bins,
63-
velocity_vectors,
64-
swe_l2_data.phase_space_density[i],
65-
weights,
66-
core_breakpoint, halo_core - spacecraft_potential)
67-
68-
# np.savetxt("fake_velocity_vectors.csv", filtered_velocity_vectors[::100], delimiter=",")
69-
# np.savetxt("fake_weights.csv", filtered_weights[::100], delimiter=",")
70-
# np.savetxt("fake_yreg.csv", filtered_yreg[::100], delimiter=",")
71-
72-
fit_function: np.ndarray[float] = regress(filtered_velocity_vectors, filtered_weights, filtered_yreg)
73-
calculate_fit_temperature_density_velocity(fit_function)
60+
halo_core_breakpoint_index: int = next(
61+
i - 1 for i, energy in enumerate(swe_l2_data.energy) if energy > halo_core)
62+
spacecraft_potential_core_breakpoint_index: int = next(
63+
i for i, energy in enumerate(swe_l2_data.energy) if energy >= spacecraft_potential)
64+
65+
while True:
66+
filtered_velocity_vectors, filtered_weights, filtered_yreg = filter_and_flatten_regress_parameters(
67+
corrected_energy_bins,
68+
velocity_vectors,
69+
swe_l2_data.phase_space_density[i],
70+
weights,
71+
spacecraft_potential_core_breakpoint_index, halo_core_breakpoint_index)
72+
73+
fit_function, chisq = regress(filtered_velocity_vectors,
74+
filtered_weights, filtered_yreg)
75+
moments = calculate_fit_temperature_density_velocity(fit_function)
76+
77+
if 0 < moments.density < 185 or (
78+
halo_core_breakpoint_index - spacecraft_potential_core_breakpoint_index) <= 3:
79+
break
80+
else:
81+
halo_core_breakpoint_index -= 1
7482

7583
def calculate_pitch_angle_products(self, dependencies: SweL3Dependencies) -> SweL3Data:
7684
swe_l2_data = dependencies.swe_l2_data

tests/swe/l3/science/test_moments_calculation.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ def test_calculate_fit_temperature_density_velocity_is_consistent_with_heritage_
104104
self.assertAlmostEqual(21193300.548418, moments.aoo, delta=1)
105105

106106
def test_filter_and_flatten_regress_parameters(self):
107-
corrected_energy_bins = np.array([-1, 0, 3, 4, 5])
107+
corrected_energy_bins = np.array([-1, 0, 3, 4.5, 5])
108108
phase_space_density = np.array([
109109
[[1, 2], [2, 3]],
110110
[[5, 6], [6, 7]],
@@ -129,11 +129,12 @@ def test_filter_and_flatten_regress_parameters(self):
129129
[[[20, 0, 0], [8, 0, 0]], [[12, 0, 0], [23, 0, 0]]],
130130
])
131131

132-
core_breakpoint = 0
133-
core_halo_breakpoint = 4.5
132+
core_breakpoint_index = 1
133+
core_halo_breakpoint_index = 4
134134
vectors, actual_weights, yreg = filter_and_flatten_regress_parameters(corrected_energy_bins, velocity_vectors,
135135
phase_space_density, weights,
136-
core_breakpoint, core_halo_breakpoint)
136+
core_breakpoint_index,
137+
core_halo_breakpoint_index)
137138

138139
np.testing.assert_array_equal(vectors, [[3, 0, 0], [4, 0, 0], [10, 0, 0], [10, 0, 0], [0, 0, 0]])
139140
np.testing.assert_array_equal(actual_weights, [3, 1e-36, 10, 11, 12])

tests/swe/test_swe_processor.py

Lines changed: 157 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -233,15 +233,14 @@ def test_calculate_moment_products(self, mock_calculate_fit_temperature_density_
233233
epoch_delta=np.repeat(timedelta(seconds=30), 2),
234234
phase_space_density=np.arange(9).reshape(3, 3) + 100,
235235
flux=np.arange(9).reshape(3, 3),
236-
energy=np.array([2, 4, 6]),
236+
energy=np.array([9, 10, 12, 14, 36, 54, 96, 102, 112, 156]),
237237
inst_el=np.array([]),
238238
inst_az_spin_sector=np.arange(10, 19).reshape(3, 3),
239239
acquisition_time=np.array([]),
240240
)
241241

242-
expected_core_breakpoint = 0
243242
expected_breakpoint_1 = (12, 96)
244-
expected_breakpoint_2 = (16, 86)
243+
expected_breakpoint_2 = (14, 54)
245244
mock_find_breakpoints.side_effect = [
246245
expected_breakpoint_1,
247246
expected_breakpoint_2
@@ -279,7 +278,9 @@ def test_calculate_moment_products(self, mock_calculate_fit_temperature_density_
279278
)
280279
]
281280

282-
mock_regress.side_effect = [sentinel.first_regress_return, sentinel.second_regress_return]
281+
mock_calculate_fit_temperature_density_velocity.return_value = Mock(density=10)
282+
283+
mock_regress.side_effect = [(sentinel.first_regress_return, 0), (sentinel.second_regress_return, 0)]
283284
mock_average_over_look_directions.return_value = np.array([5, 10, 15])
284285
input_metadata = InputMetadata("swe", "l3", datetime(2025, 2, 21),
285286
datetime(2025, 2, 22), "v001")
@@ -328,9 +329,8 @@ def test_calculate_moment_products(self, mock_calculate_fit_temperature_density_
328329
np.testing.assert_array_equal(swe_l2_data.phase_space_density[0], filter_and_flatten_call_1.args[2])
329330
np.testing.assert_array_equal(maxwellian_weight_factors[0],
330331
filter_and_flatten_call_1.args[3])
331-
self.assertEqual(expected_core_breakpoint, filter_and_flatten_call_1.args[4])
332-
self.assertEqual(expected_breakpoint_1[1] - expected_breakpoint_1[0],
333-
filter_and_flatten_call_1.args[5])
332+
self.assertEqual(2, filter_and_flatten_call_1.args[4])
333+
self.assertEqual(6, filter_and_flatten_call_1.args[5])
334334

335335
filter_and_flatten_call_2 = mock_filter_and_flatten_regress_parameters.mock_calls[1]
336336
np.testing.assert_array_equal(swe_l2_data.energy - expected_breakpoint_2[0],
@@ -340,9 +340,8 @@ def test_calculate_moment_products(self, mock_calculate_fit_temperature_density_
340340
np.testing.assert_array_equal(swe_l2_data.phase_space_density[1], filter_and_flatten_call_2.args[2])
341341
np.testing.assert_array_equal(maxwellian_weight_factors[1],
342342
filter_and_flatten_call_2.args[3])
343-
self.assertEqual(expected_core_breakpoint, filter_and_flatten_call_2.args[4])
344-
self.assertEqual(expected_breakpoint_2[1] - expected_breakpoint_2[0],
345-
filter_and_flatten_call_2.args[5])
343+
self.assertEqual(3, filter_and_flatten_call_2.args[4])
344+
self.assertEqual(5, filter_and_flatten_call_2.args[5])
346345

347346
regress_call_1 = mock_regress.mock_calls[0]
348347
np.testing.assert_array_equal(filtered_velocity_vectors[0], regress_call_1.args[0])
@@ -356,3 +355,151 @@ def test_calculate_moment_products(self, mock_calculate_fit_temperature_density_
356355

357356
mock_calculate_fit_temperature_density_velocity.assert_has_calls(
358357
[call(sentinel.first_regress_return), call(sentinel.second_regress_return)])
358+
359+
@patch('imap_processing.swe.swe_processor.average_over_look_directions')
360+
@patch('imap_processing.swe.swe_processor.compute_maxwellian_weight_factors')
361+
@patch('imap_processing.swe.swe_processor.calculate_velocity_in_dsp_frame_km_s')
362+
@patch('imap_processing.swe.swe_processor.regress')
363+
@patch('imap_processing.swe.swe_processor.calculate_fit_temperature_density_velocity')
364+
@patch('imap_processing.swe.swe_processor.find_breakpoints')
365+
@patch('imap_processing.swe.swe_processor.filter_and_flatten_regress_parameters')
366+
def test_moment_fit_should_be_retried_until_returned_density_is_valid(self,
367+
mock_filter_and_flatten_regress_parameters,
368+
mock_find_breakpoints,
369+
mock_calculate_fit_temperature_density_velocity,
370+
mock_regress, mock_calculate_velocity,
371+
mock_compute_maxwellian_weights,
372+
_):
373+
epochs = datetime.now() + np.arange(1) * timedelta(minutes=1)
374+
swe_config = build_swe_configuration()
375+
376+
energies = np.array([1.2, 3.4, 4.6, 5.9, 8.7, 9.1, 9.2, 10.5, 11.9])
377+
378+
swe_l2_data = SweL2Data(
379+
epoch=epochs,
380+
epoch_delta=np.repeat(timedelta(seconds=30), 1),
381+
phase_space_density=np.arange(7 * 3).reshape(1, 7, 3) + 100,
382+
flux=np.arange(9).reshape(3, 3),
383+
energy=energies,
384+
inst_el=np.array([]),
385+
inst_az_spin_sector=np.arange(10, 19).reshape(3, 3),
386+
acquisition_time=np.array([]),
387+
)
388+
389+
core_breakpoint = 3.4
390+
core_halo_breakpoint = 9.2
391+
mock_find_breakpoints.return_value = (core_breakpoint, core_halo_breakpoint)
392+
393+
expected_core_energy_start_index = 1
394+
expected_core_energy_end_index = 6
395+
396+
mock_filter_and_flatten_regress_parameters.side_effect = [
397+
(sentinel.filtered_vecs_1, sentinel.filtered_weights_1, sentinel.filtered_yreg_1),
398+
(sentinel.filtered_vecs_2, sentinel.filtered_weights_2, sentinel.filtered_yreg_2),
399+
(sentinel.filtered_vecs_3, sentinel.filtered_weights_3, sentinel.filtered_yreg_3)
400+
]
401+
402+
mock_regress.side_effect = [(sentinel.first_regress_return, 0), (sentinel.second_regress_return, 0),
403+
(sentinel.third_regress_return, 0)]
404+
405+
mock_calculate_fit_temperature_density_velocity.side_effect = [(Mock(density=-1)), (Mock(density=186)),
406+
(Mock(density=10))]
407+
408+
input_metadata = InputMetadata("swe", "l3", datetime(2025, 2, 21),
409+
datetime(2025, 2, 22), "v001")
410+
411+
swel3_dependency = SweL3Dependencies(swe_l2_data, Mock(), Mock(), swe_config)
412+
swe_processor = SweProcessor(dependencies=[], input_metadata=input_metadata)
413+
414+
swe_processor.calculate_moment_products(swel3_dependency)
415+
416+
self.assertEqual(3, mock_filter_and_flatten_regress_parameters.call_count)
417+
mock_filter_and_flatten_regress_parameters.assert_has_calls([
418+
call(NumpyArrayMatcher(swe_l2_data.energy - core_breakpoint), mock_calculate_velocity.return_value,
419+
NumpyArrayMatcher(swe_l2_data.phase_space_density[0]), mock_compute_maxwellian_weights.return_value,
420+
expected_core_energy_start_index, expected_core_energy_end_index),
421+
call(NumpyArrayMatcher(swe_l2_data.energy - core_breakpoint), mock_calculate_velocity.return_value,
422+
NumpyArrayMatcher(swe_l2_data.phase_space_density[0]), mock_compute_maxwellian_weights.return_value,
423+
expected_core_energy_start_index, expected_core_energy_end_index - 1),
424+
call(NumpyArrayMatcher(swe_l2_data.energy - core_breakpoint), mock_calculate_velocity.return_value,
425+
NumpyArrayMatcher(swe_l2_data.phase_space_density[0]), mock_compute_maxwellian_weights.return_value,
426+
expected_core_energy_start_index, expected_core_energy_end_index - 2)
427+
])
428+
429+
self.assertEqual(3, mock_regress.call_count)
430+
mock_regress.assert_has_calls([
431+
call(sentinel.filtered_vecs_1, sentinel.filtered_weights_1, sentinel.filtered_yreg_1),
432+
call(sentinel.filtered_vecs_2, sentinel.filtered_weights_2, sentinel.filtered_yreg_2),
433+
call(sentinel.filtered_vecs_3, sentinel.filtered_weights_3, sentinel.filtered_yreg_3)
434+
435+
])
436+
437+
self.assertEqual(3, mock_calculate_fit_temperature_density_velocity.call_count)
438+
mock_calculate_fit_temperature_density_velocity.assert_has_calls([
439+
call(sentinel.first_regress_return),
440+
call(sentinel.second_regress_return),
441+
call(sentinel.third_regress_return)
442+
])
443+
444+
@patch('imap_processing.swe.swe_processor.average_over_look_directions')
445+
@patch('imap_processing.swe.swe_processor.compute_maxwellian_weight_factors')
446+
@patch('imap_processing.swe.swe_processor.calculate_velocity_in_dsp_frame_km_s')
447+
@patch('imap_processing.swe.swe_processor.regress')
448+
@patch('imap_processing.swe.swe_processor.calculate_fit_temperature_density_velocity')
449+
@patch('imap_processing.swe.swe_processor.find_breakpoints')
450+
@patch('imap_processing.swe.swe_processor.filter_and_flatten_regress_parameters')
451+
def test_moment_fit_should_be_ran_while_number_of_energies_between_halo_and_core_is_greater_than_3(self,
452+
mock_filter_and_flatten_regress_parameters,
453+
mock_find_breakpoints,
454+
mock_calculate_fit_temperature_density_velocity,
455+
mock_regress,
456+
mock_calculate_velocity,
457+
mock_compute_maxwellian_weights,
458+
_):
459+
epochs = datetime.now() + np.arange(1) * timedelta(minutes=1)
460+
swe_config = build_swe_configuration()
461+
462+
energies = np.array([1.2, 3.4, 4.6, 5.9, 8.7, 9.2, 10.5, 11.9])
463+
464+
swe_l2_data = SweL2Data(
465+
epoch=epochs,
466+
epoch_delta=np.repeat(timedelta(seconds=30), 1),
467+
phase_space_density=np.arange(7 * 3).reshape(1, 7, 3) + 100,
468+
flux=np.arange(9).reshape(3, 3),
469+
energy=energies,
470+
inst_el=np.array([]),
471+
inst_az_spin_sector=np.arange(10, 19).reshape(3, 3),
472+
acquisition_time=np.array([]),
473+
)
474+
475+
core_breakpoint = 3.4
476+
core_halo_breakpoint = 8.7
477+
mock_find_breakpoints.return_value = (core_breakpoint, core_halo_breakpoint)
478+
479+
expected_core_energy_start_index = 1
480+
expected_core_energy_end_index = 4
481+
482+
mock_filter_and_flatten_regress_parameters.return_value = (
483+
sentinel.filtered_vecs_1, sentinel.filtered_weights_1, sentinel.filtered_yreg_1)
484+
485+
mock_regress.return_value = (sentinel.first_regress_return, 0)
486+
487+
mock_calculate_fit_temperature_density_velocity.side_effect = [Mock(density=-1), Mock(density=10)]
488+
489+
input_metadata = InputMetadata("swe", "l3", datetime(2025, 2, 21),
490+
datetime(2025, 2, 22), "v001")
491+
492+
swel3_dependency = SweL3Dependencies(swe_l2_data, Mock(), Mock(), swe_config)
493+
swe_processor = SweProcessor(dependencies=[], input_metadata=input_metadata)
494+
495+
swe_processor.calculate_moment_products(swel3_dependency)
496+
497+
mock_filter_and_flatten_regress_parameters.assert_called_once_with(
498+
NumpyArrayMatcher(swe_l2_data.energy - core_breakpoint), mock_calculate_velocity.return_value,
499+
NumpyArrayMatcher(swe_l2_data.phase_space_density[0]), mock_compute_maxwellian_weights.return_value,
500+
expected_core_energy_start_index, expected_core_energy_end_index)
501+
502+
mock_regress.assert_called_once_with(sentinel.filtered_vecs_1, sentinel.filtered_weights_1,
503+
sentinel.filtered_yreg_1)
504+
505+
mock_calculate_fit_temperature_density_velocity.assert_called_once_with(sentinel.first_regress_return)

0 commit comments

Comments
 (0)