From 84fda36d7e7c20958df035ada0e563af7abbcbcd Mon Sep 17 00:00:00 2001 From: Veronica Martinez Date: Mon, 30 Mar 2026 15:55:55 -0600 Subject: [PATCH 1/4] Check that exposure times are not zero to prevent division by zero when calculating photon flux and flux uncertainties. Add a unit test for this test case. --- imap_processing/glows/l2/glows_l2_data.py | 3 +-- .../tests/glows/test_glows_l2_data.py | 23 +++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/imap_processing/glows/l2/glows_l2_data.py b/imap_processing/glows/l2/glows_l2_data.py index c9fb7cf6d..4b9b4da86 100644 --- a/imap_processing/glows/l2/glows_l2_data.py +++ b/imap_processing/glows/l2/glows_l2_data.py @@ -106,8 +106,7 @@ def __post_init__(self, l1b_data: xr.Dataset, position_angle: float) -> None: self.photon_flux = np.zeros(self.number_of_bins) self.flux_uncertainties = np.zeros(self.number_of_bins) - # TODO: Only where exposure counts != 0 - if len(self.exposure_times) != 0: + if len(self.exposure_times) != 0 and self.exposure_times[0] > 0: self.photon_flux = self.raw_histograms / self.exposure_times self.flux_uncertainties = raw_uncertainties / self.exposure_times diff --git a/imap_processing/tests/glows/test_glows_l2_data.py b/imap_processing/tests/glows/test_glows_l2_data.py index d343fd630..8f0bff4fb 100644 --- a/imap_processing/tests/glows/test_glows_l2_data.py +++ b/imap_processing/tests/glows/test_glows_l2_data.py @@ -175,6 +175,29 @@ def test_zero_exposure_bins(l1b_dataset, mock_ecliptic_bin_centers): assert np.allclose(lc.exposure_times, expected_exposure) +def test_zero_exposure_values(l1b_dataset, mock_ecliptic_bin_centers): + """Zero exposure yields zero flux and zero uncertainty per bin. + + Note: all bins have the same exposure time, so if one is zero all are zero. + """ + + # Update values used to calculate exposure times to + # ensure a zero exposure result. + l1b_dataset["spin_period_average"].data[:] = 0 + l1b_dataset["number_of_spins_per_block"].data[:] = 0 + + with np.errstate(divide="raise", invalid="raise"): + lc = DailyLightcurve(l1b_dataset, position_angle=0.0) + + expected = np.zeros(l1b_dataset.sizes["bins"], dtype=float) + assert lc.exposure_times.shape == expected.shape + assert np.array_equal(lc.exposure_times, expected) + assert np.array_equal(lc.photon_flux, expected) + assert np.array_equal(lc.flux_uncertainties, expected) + assert np.all(np.isfinite(lc.photon_flux)) + assert np.all(np.isfinite(lc.flux_uncertainties)) + + def test_number_of_bins(l1b_dataset, mock_ecliptic_bin_centers): lc = DailyLightcurve(l1b_dataset, position_angle=0.0) assert lc.number_of_bins == 4 From cc88c7aaf48cd96e13bbae53c508dc6f537256c6 Mon Sep 17 00:00:00 2001 From: Veronica Martinez Date: Tue, 31 Mar 2026 10:11:30 -0600 Subject: [PATCH 2/4] Address PR comments - add check that all exposure times are the same value --- imap_processing/glows/l2/glows_l2_data.py | 6 +++++- imap_processing/tests/glows/test_glows_l2_data.py | 6 +++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/imap_processing/glows/l2/glows_l2_data.py b/imap_processing/glows/l2/glows_l2_data.py index 4b9b4da86..22c63950e 100644 --- a/imap_processing/glows/l2/glows_l2_data.py +++ b/imap_processing/glows/l2/glows_l2_data.py @@ -106,7 +106,11 @@ def __post_init__(self, l1b_data: xr.Dataset, position_angle: float) -> None: self.photon_flux = np.zeros(self.number_of_bins) self.flux_uncertainties = np.zeros(self.number_of_bins) - if len(self.exposure_times) != 0 and self.exposure_times[0] > 0: + if ( + len(self.exposure_times) != 0 + and self.exposure_times[0] > 0 + and len(np.unique(self.exposure_times)) == 1 + ): self.photon_flux = self.raw_histograms / self.exposure_times self.flux_uncertainties = raw_uncertainties / self.exposure_times diff --git a/imap_processing/tests/glows/test_glows_l2_data.py b/imap_processing/tests/glows/test_glows_l2_data.py index 8f0bff4fb..5ffe6f2fa 100644 --- a/imap_processing/tests/glows/test_glows_l2_data.py +++ b/imap_processing/tests/glows/test_glows_l2_data.py @@ -176,10 +176,9 @@ def test_zero_exposure_bins(l1b_dataset, mock_ecliptic_bin_centers): def test_zero_exposure_values(l1b_dataset, mock_ecliptic_bin_centers): - """Zero exposure yields zero flux and zero uncertainty per bin. + """Zero exposure yields zero flux and zero uncertainty per bin.""" - Note: all bins have the same exposure time, so if one is zero all are zero. - """ + # Note: all bins have the same exposure time, so if one is zero all are zero. # Update values used to calculate exposure times to # ensure a zero exposure result. @@ -191,6 +190,7 @@ def test_zero_exposure_values(l1b_dataset, mock_ecliptic_bin_centers): expected = np.zeros(l1b_dataset.sizes["bins"], dtype=float) assert lc.exposure_times.shape == expected.shape + assert len(np.unique(lc.exposure_times)) == 1 assert np.array_equal(lc.exposure_times, expected) assert np.array_equal(lc.photon_flux, expected) assert np.array_equal(lc.flux_uncertainties, expected) From b76e88a256b7a3bd68828e25d85d80dacbeb9c80 Mon Sep 17 00:00:00 2001 From: Veronica Martinez Date: Tue, 31 Mar 2026 17:45:44 -0600 Subject: [PATCH 3/4] Add handling for dataset with zero flux and exposure times to return an empty dataset --- imap_processing/glows/l2/glows_l2.py | 10 ++++++++++ imap_processing/tests/glows/test_glows_l2.py | 16 ++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/imap_processing/glows/l2/glows_l2.py b/imap_processing/glows/l2/glows_l2.py index a7fd02577..c81ae9f38 100644 --- a/imap_processing/glows/l2/glows_l2.py +++ b/imap_processing/glows/l2/glows_l2.py @@ -63,6 +63,16 @@ def glows_l2( if l2.number_of_good_l1b_inputs == 0: logger.warning("No good data found in L1B dataset. Returning empty list.") return [] + elif ( + np.all(l2.daily_lightcurve.photon_flux == 0) + and np.all(l2.daily_lightcurve.flux_uncertainties == 0) + and np.all(l2.daily_lightcurve.exposure_times == 0) + ): + logger.warning( + "All photon flux, flux uncertainties, and exposure times are zero. " + "Returning empty list." + ) + return [] else: return [create_l2_dataset(l2, cdf_attrs)] diff --git a/imap_processing/tests/glows/test_glows_l2.py b/imap_processing/tests/glows/test_glows_l2.py index 7e9bffc37..faaec83ae 100644 --- a/imap_processing/tests/glows/test_glows_l2.py +++ b/imap_processing/tests/glows/test_glows_l2.py @@ -74,9 +74,21 @@ def test_glows_l2( assert np.allclose(l2["filter_temperature_average"].values, [57.6], rtol=0.1) # Test case 2: L1B dataset has no good times (all flags 0) - l1b_hist_dataset["flags"].values = np.zeros(l1b_hist_dataset.flags.shape) + l1b_hist_dataset_no_good_times = l1b_hist_dataset.copy(deep=True) + l1b_hist_dataset_no_good_times["flags"].values = np.zeros( + l1b_hist_dataset_no_good_times.flags.shape + ) + caplog.set_level("WARNING") + result = glows_l2(l1b_hist_dataset_no_good_times, mock_pipeline_settings, None) + assert result == [] + assert any(record.levelname == "WARNING" for record in caplog.records) + + # Test case 3: Dataset has zero exposure and flux values + l1b_hist_dataset_zero_values = l1b_hist_dataset.copy(deep=True) + l1b_hist_dataset_zero_values["spin_period_average"].data[:] = 0 + l1b_hist_dataset_zero_values["number_of_spins_per_block"].data[:] = 0 caplog.set_level("WARNING") - result = glows_l2(l1b_hist_dataset, mock_pipeline_settings, None) + result = glows_l2(l1b_hist_dataset_zero_values, mock_pipeline_settings, None) assert result == [] assert any(record.levelname == "WARNING" for record in caplog.records) From 39ed28ec9587658f4bd6168a9f8efb81751e3f61 Mon Sep 17 00:00:00 2001 From: Veronica Martinez Date: Wed, 1 Apr 2026 08:59:37 -0600 Subject: [PATCH 4/4] Edit warning message --- imap_processing/glows/l2/glows_l2.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/imap_processing/glows/l2/glows_l2.py b/imap_processing/glows/l2/glows_l2.py index c81ae9f38..f96ae0ef4 100644 --- a/imap_processing/glows/l2/glows_l2.py +++ b/imap_processing/glows/l2/glows_l2.py @@ -68,10 +68,7 @@ def glows_l2( and np.all(l2.daily_lightcurve.flux_uncertainties == 0) and np.all(l2.daily_lightcurve.exposure_times == 0) ): - logger.warning( - "All photon flux, flux uncertainties, and exposure times are zero. " - "Returning empty list." - ) + logger.warning("All flux and exposure times are zero. Returning empty list.") return [] else: return [create_l2_dataset(l2, cdf_attrs)]