From 2e84d87347fa1eb4be851a2c6801fb445b76514d Mon Sep 17 00:00:00 2001 From: Maxine Hartnett Date: Thu, 7 May 2026 14:23:43 -0600 Subject: [PATCH 1/2] Skipping empty chunks in mag processing --- imap_processing/mag/l1d/mag_l1d_data.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/imap_processing/mag/l1d/mag_l1d_data.py b/imap_processing/mag/l1d/mag_l1d_data.py index fac808f5dd..e0bd847145 100644 --- a/imap_processing/mag/l1d/mag_l1d_data.py +++ b/imap_processing/mag/l1d/mag_l1d_data.py @@ -523,6 +523,14 @@ def calculate_spin_offsets(self) -> xr.Dataset: chunk_vectors = self.vectors[chunk_indices[0] : chunk_indices[-1]] chunk_epoch = self.epoch[chunk_indices[0] : chunk_indices[-1]] + if len(chunk_epoch) == 0: + logging.warning( + "Skipping empty chunk at spin_starts index %d", + chunk_start, + ) + chunk_start = chunk_start + self.config.spin_count_calibration + continue + # Check if more than half of the chunk data is NaN before processing x_valid_count: int = int(np.sum(~np.isnan(chunk_vectors[:, 0]))) y_valid_count: int = int(np.sum(~np.isnan(chunk_vectors[:, 1]))) From 3973ba988673deb2f0030fd8ce6938a643f6e56b Mon Sep 17 00:00:00 2001 From: Maxine Hartnett Date: Thu, 7 May 2026 15:03:19 -0600 Subject: [PATCH 2/2] Add test --- imap_processing/mag/l1d/mag_l1d_data.py | 2 +- imap_processing/tests/mag/test_mag_l1d.py | 34 +++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/imap_processing/mag/l1d/mag_l1d_data.py b/imap_processing/mag/l1d/mag_l1d_data.py index e0bd847145..e52546b580 100644 --- a/imap_processing/mag/l1d/mag_l1d_data.py +++ b/imap_processing/mag/l1d/mag_l1d_data.py @@ -524,7 +524,7 @@ def calculate_spin_offsets(self) -> xr.Dataset: chunk_epoch = self.epoch[chunk_indices[0] : chunk_indices[-1]] if len(chunk_epoch) == 0: - logging.warning( + logger.warning( "Skipping empty chunk at spin_starts index %d", chunk_start, ) diff --git a/imap_processing/tests/mag/test_mag_l1d.py b/imap_processing/tests/mag/test_mag_l1d.py index 9c62196221..2ebe5efe76 100644 --- a/imap_processing/tests/mag/test_mag_l1d.py +++ b/imap_processing/tests/mag/test_mag_l1d.py @@ -1,3 +1,4 @@ +import logging from unittest.mock import patch import numpy as np @@ -291,6 +292,39 @@ def test_calculate_spin_offsets( np.testing.assert_allclose(offsets["y_offset"].data, expected_y_avg) +def test_calculate_spin_offsets_empty_chunk(mag_l1d_test_class, caplog): + # 166 points with 15-sample spin period produces 11 spin_starts. + # With spin_count_calibration=2, the last chunk (index 10) contains only + # one spin_start, making chunk_epoch empty and triggering the warning path. + n = 166 + mag_l1d_test_class.vectors = np.ones((n, 3)) + mag_l1d_test_class.epoch = np.arange(n, dtype=np.float64) * 1e9 + mag_l1d_test_class.frame = ValidFrames.SRF + mag_l1d_test_class.config.spin_count_calibration = 2 + + phase = (np.arange(n) % 15) / 15.0 + + with ( + patch( + "imap_processing.mag.l1d.mag_l1d_data.ttj2000ns_to_met", + side_effect=lambda *args, **kwargs: args[0] / 1e9, + ), + patch( + "imap_processing.mag.l1d.mag_l1d_data.spin.get_spacecraft_spin_phase", + return_value=phase, + ), + patch( + "imap_processing.mag.l1d.mag_l1d_data.spin.get_spin_data", + return_value={"spin_period_sec": np.array([15.0])}, + ), + caplog.at_level(logging.WARNING), + ): + offsets = mag_l1d_test_class.calculate_spin_offsets() + + assert "Skipping empty chunk" in caplog.text + assert len(offsets["epoch"]) == 5 + + def test_apply_spin_offsets(mag_l1d_test_class, fake_mag_spin_data, furnish_kernels): vectors = np.zeros((155, 3)) epoch = np.arange(155)