Skip to content

Commit d60102d

Browse files
Harrison 3062/#25 - PMCL/KJON - SWAPI L3a alpha-sw: Added debug variables for the temperature and density values before performing the lookup
1 parent 19382dd commit d60102d

11 files changed

Lines changed: 129 additions & 57 deletions

imap_l3_processing/cdf/config/imap_swapi_l3a_variable_attrs.yaml

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -537,4 +537,44 @@ swp_flags:
537537
VALIDMIN: 0
538538
VALIDMAX: 65534
539539
FILLVAL: 65535
540-
LABLAXIS: Quality flags for SWAPI L3a
540+
LABLAXIS: Quality flags for SWAPI L3a
541+
542+
alpha_sw_pre_lut_temperature:
543+
NAME: alpha_sw_pre_lut_temperature
544+
DATA_TYPE: CDF_REAL4
545+
CATDESC: Alpha solar wind temperature pre-LUT
546+
DEPEND_0: epoch
547+
VAR_TYPE: data
548+
RECORD_VARYING: RV
549+
DISPLAY_TYPE: time_series
550+
VARIABLE_PURPOSE: DEBUG
551+
FIELDNAM: Alpha Solar Wind Temperature
552+
FORMAT: F19.3
553+
LABLAXIS: Alpha SW temperature
554+
UNITS: K
555+
VALIDMIN: 0
556+
VALIDMAX: 28000000
557+
FILLVAL: -1.000000e+31
558+
SCALETYP: log
559+
SCALEMIN: 4000
560+
SCALEMAX: 960000
561+
562+
alpha_sw_pre_lut_density:
563+
NAME: alpha_sw_pre_lut_density
564+
DATA_TYPE: CDF_REAL4
565+
CATDESC: Alpha solar wind density pre-LUT
566+
DEPEND_0: epoch
567+
VAR_TYPE: data
568+
RECORD_VARYING: RV
569+
DISPLAY_TYPE: time_series
570+
VARIABLE_PURPOSE: DEBUG
571+
FIELDNAM: Alpha Solar Wind Density
572+
FORMAT: F19.3
573+
LABLAXIS: Alpha SW density
574+
UNITS: cm!E-3!N
575+
VALIDMIN: 0
576+
VALIDMAX: 100
577+
FILLVAL: -1.000000e+31
578+
SCALETYP: log
579+
SCALEMIN: 0.001
580+
SCALEMAX: 5

imap_l3_processing/swapi/l3a/models.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
ALPHA_SOLAR_WIND_DENSITY_UNCERTAINTY_CDF_VAR_NAME = "alpha_sw_density_uncert"
3030
ALPHA_SOLAR_WIND_TEMPERATURE_CDF_VAR_NAME = "alpha_sw_temperature"
3131
ALPHA_SOLAR_WIND_TEMPERATURE_UNCERTAINTY_CDF_VAR_NAME = "alpha_sw_temperature_uncert"
32+
ALPHA_SOLAR_WIND_PRE_LUT_DENSITY_CDF_VAR_NAME = "alpha_sw_pre_lut_density"
33+
ALPHA_SOLAR_WIND_PRE_LUT_TEMPERATURE_CDF_VAR_NAME = "alpha_sw_pre_lut_temperature"
3234

3335
PUI_COOLING_INDEX_CDF_VAR_NAME = "pui_cooling_index"
3436
PUI_IONIZATION_RATE_CDF_VAR_NAME = "pui_ionization_rate"
@@ -86,6 +88,8 @@ class SwapiL3AlphaSolarWindData(DataProduct):
8688
alpha_sw_temperature: np.ndarray
8789
alpha_sw_density: np.ndarray
8890
bad_fit_flag: np.ndarray
91+
alpha_sw_pre_lut_temperature: np.ndarray
92+
alpha_sw_pre_lut_density: np.ndarray
8993

9094
def to_data_product_variables(self) -> list[DataProductVariable]:
9195
return [
@@ -98,7 +102,9 @@ def to_data_product_variables(self) -> list[DataProductVariable]:
98102
std_devs(self.alpha_sw_temperature)),
99103
DataProductVariable(ALPHA_SOLAR_WIND_DENSITY_CDF_VAR_NAME, nominal_values(self.alpha_sw_density)),
100104
DataProductVariable(ALPHA_SOLAR_WIND_DENSITY_UNCERTAINTY_CDF_VAR_NAME, std_devs(self.alpha_sw_density)),
101-
DataProductVariable(SWAPI_QUALITY_FLAGS_CDF_VAR_NAME, self.bad_fit_flag)
105+
DataProductVariable(SWAPI_QUALITY_FLAGS_CDF_VAR_NAME, self.bad_fit_flag),
106+
DataProductVariable(ALPHA_SOLAR_WIND_PRE_LUT_TEMPERATURE_CDF_VAR_NAME, nominal_values(self.alpha_sw_pre_lut_temperature)),
107+
DataProductVariable(ALPHA_SOLAR_WIND_PRE_LUT_DENSITY_CDF_VAR_NAME, nominal_values(self.alpha_sw_pre_lut_density)),
102108
]
103109

104110

imap_l3_processing/swapi/l3a/science/calculate_alpha_solar_wind_temperature_and_density.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,15 +98,17 @@ def model(ev_per_q, density, temperature):
9898
bad_fit_flag = SwapiL3Flags.NONE
9999
if reduced_chisq > 10:
100100
bad_fit_flag = SwapiL3Flags.HI_CHI_SQ
101-
density, temperature = correlated_values(values, covariance)
102-
density = table.lookup_density(alpha_sw_speed, density, temperature)
103-
temperature = table.lookup_temperature(alpha_sw_speed, density, temperature)
101+
pre_lut_density, pre_lut_temperature = correlated_values(values, covariance)
102+
density = table.lookup_density(alpha_sw_speed, pre_lut_density, pre_lut_temperature)
103+
temperature = table.lookup_temperature(alpha_sw_speed, pre_lut_density, pre_lut_temperature)
104104

105-
return AlphaSolarWindTemperatureAndDensity(temperature, density, bad_fit_flag)
105+
return AlphaSolarWindTemperatureAndDensity(temperature, density, pre_lut_temperature, pre_lut_density, bad_fit_flag)
106106

107107

108108
@dataclass
109109
class AlphaSolarWindTemperatureAndDensity:
110110
temperature: ufloat
111111
density: ufloat
112+
pre_lut_temperature: ufloat
113+
pre_lut_density: ufloat
112114
bad_fit_flag: int = SwapiL3Flags.NONE

imap_l3_processing/swapi/l3a/utils.py

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,11 @@
11
from datetime import datetime
22
from typing import Iterable
33

4-
import numpy as np
54
from spacepy import pycdf
65
from spacepy.pycdf import CDF
7-
from uncertainties.unumpy import uarray
86

97
from imap_l3_processing.cdf.cdf_utils import read_numeric_variable
10-
from imap_l3_processing.swapi.l3a.models import SwapiL2Data, SwapiL3AlphaSolarWindData, EPOCH_CDF_VAR_NAME, \
11-
ALPHA_SOLAR_WIND_SPEED_CDF_VAR_NAME, ALPHA_SOLAR_WIND_SPEED_UNCERTAINTY_CDF_VAR_NAME, \
12-
ALPHA_SOLAR_WIND_TEMPERATURE_CDF_VAR_NAME, ALPHA_SOLAR_WIND_TEMPERATURE_UNCERTAINTY_CDF_VAR_NAME, \
13-
ALPHA_SOLAR_WIND_DENSITY_CDF_VAR_NAME, ALPHA_SOLAR_WIND_DENSITY_UNCERTAINTY_CDF_VAR_NAME, \
14-
SWAPI_QUALITY_FLAGS_CDF_VAR_NAME
8+
from imap_l3_processing.swapi.l3a.models import SwapiL2Data
159

1610

1711
def read_l2_swapi_data(cdf: CDF) -> SwapiL2Data:
@@ -22,24 +16,6 @@ def read_l2_swapi_data(cdf: CDF) -> SwapiL2Data:
2216
read_numeric_variable(cdf["swp_coin_rate"]),
2317
read_numeric_variable(cdf["swp_coin_rate_stat_uncert_plus"]))
2418

25-
26-
def read_l3a_alpha_sw_swapi_data(cdf: CDF) -> SwapiL3AlphaSolarWindData:
27-
alpha_sw_speed = uarray(cdf[ALPHA_SOLAR_WIND_SPEED_CDF_VAR_NAME],
28-
cdf[ALPHA_SOLAR_WIND_SPEED_UNCERTAINTY_CDF_VAR_NAME])
29-
alpha_sw_temperature = uarray(cdf[ALPHA_SOLAR_WIND_TEMPERATURE_CDF_VAR_NAME],
30-
cdf[ALPHA_SOLAR_WIND_TEMPERATURE_UNCERTAINTY_CDF_VAR_NAME])
31-
alpha_sw_density = uarray(cdf[ALPHA_SOLAR_WIND_DENSITY_CDF_VAR_NAME],
32-
cdf[ALPHA_SOLAR_WIND_DENSITY_UNCERTAINTY_CDF_VAR_NAME])
33-
alpha_sw_bad_fit_flag = np.array(cdf[SWAPI_QUALITY_FLAGS_CDF_VAR_NAME])
34-
35-
return SwapiL3AlphaSolarWindData(None,
36-
epoch=cdf[EPOCH_CDF_VAR_NAME],
37-
alpha_sw_speed=alpha_sw_speed,
38-
alpha_sw_temperature=alpha_sw_temperature,
39-
alpha_sw_density=alpha_sw_density,
40-
bad_fit_flag=alpha_sw_bad_fit_flag)
41-
42-
4319
def chunk_l2_data(data: SwapiL2Data, chunk_size: int) -> Iterable[SwapiL2Data]:
4420
i = 0
4521
while i < len(data.sci_start_time):

imap_l3_processing/swapi/swapi_processor.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,11 +176,15 @@ def process_l3a_alpha_solar_wind(self, data, dependencies) -> SwapiL3AlphaSolarW
176176
alpha_solar_wind_densities = []
177177
alpha_solar_wind_temperatures = []
178178
alpha_solar_wind_bad_fit_flags = []
179+
alpha_solar_wind_pre_lut_densities = []
180+
alpha_solar_wind_pre_lut_temperatures = []
179181

180182
for data_chunk in chunk_l2_data(data, 5):
181183
alpha_solar_wind_speed = ufloat(np.nan, np.nan)
182184
alpha_density = ufloat(np.nan, np.nan)
183185
alpha_temperature = ufloat(np.nan, np.nan)
186+
alpha_pre_lut_density = ufloat(np.nan, np.nan)
187+
alpha_pre_lut_temperature = ufloat(np.nan, np.nan)
184188
epoch = data_chunk.sci_start_time[0] + THIRTY_SECONDS_IN_NANOSECONDS
185189
bad_fit_flag = SwapiL3Flags.NONE
186190
try:
@@ -200,6 +204,8 @@ def process_l3a_alpha_solar_wind(self, data, dependencies) -> SwapiL3AlphaSolarW
200204
alpha_density = alpha_temperature_density.density
201205
alpha_temperature = alpha_temperature_density.temperature
202206
bad_fit_flag = alpha_temperature_density.bad_fit_flag
207+
alpha_pre_lut_density = alpha_temperature_density.pre_lut_density
208+
alpha_pre_lut_temperature = alpha_temperature_density.pre_lut_temperature
203209

204210
except Exception as e:
205211
logger.info(f"Exception occurred at epoch {epoch}, continuing with fill value", exc_info=True)
@@ -209,6 +215,8 @@ def process_l3a_alpha_solar_wind(self, data, dependencies) -> SwapiL3AlphaSolarW
209215
alpha_solar_wind_densities.append(alpha_density)
210216
alpha_solar_wind_temperatures.append(alpha_temperature)
211217
alpha_solar_wind_bad_fit_flags.append(bad_fit_flag)
218+
alpha_solar_wind_pre_lut_densities.append(alpha_pre_lut_density)
219+
alpha_solar_wind_pre_lut_temperatures.append(alpha_pre_lut_temperature)
212220

213221
alpha_solar_wind_speed_metadata = replace(self.input_metadata, descriptor="alpha-sw")
214222
alpha_solar_wind_l3_data = SwapiL3AlphaSolarWindData(alpha_solar_wind_speed_metadata,
@@ -217,6 +225,8 @@ def process_l3a_alpha_solar_wind(self, data, dependencies) -> SwapiL3AlphaSolarW
217225
np.array(alpha_solar_wind_temperatures),
218226
np.array(alpha_solar_wind_densities),
219227
np.array(alpha_solar_wind_bad_fit_flags),
228+
np.array(alpha_solar_wind_pre_lut_temperatures),
229+
np.array(alpha_solar_wind_pre_lut_densities),
220230
)
221231
return alpha_solar_wind_l3_data
222232

tests/swapi/l3a/science/test_calculate_alpha_solar_wind_temperature_and_density.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from contextlib import contextmanager
22
from pathlib import Path
33
from unittest import TestCase
4-
from unittest.mock import patch
4+
from unittest.mock import patch, Mock
55

66
import numpy as np
77
from spacepy.pycdf import CDF
@@ -56,6 +56,30 @@ def test_calculate_alpha_solar_wind_temperature_and_density_for_combined_sweeps(
5656
rtol=1e-4)
5757
np.testing.assert_allclose(4.9177e-4 / efficiency, actual_alpha_sw_temp_and_density.density.std_dev, rtol=1e-4)
5858
self.assertEqual(SwapiL3Flags.NONE, actual_alpha_sw_temp_and_density.bad_fit_flag)
59+
np.testing.assert_allclose(411596.701618, actual_alpha_sw_temp_and_density.pre_lut_temperature.nominal_value)
60+
np.testing.assert_allclose(129341.909538, actual_alpha_sw_temp_and_density.pre_lut_temperature.std_dev)
61+
np.testing.assert_allclose(0.030238, actual_alpha_sw_temp_and_density.pre_lut_density.nominal_value,
62+
rtol=1e-4)
63+
np.testing.assert_allclose(0.003842, actual_alpha_sw_temp_and_density.pre_lut_density.std_dev, rtol=1e-4)
64+
65+
def test_calculate_alpha_solar_wind_temperature_and_density_for_combined_sweeps_returns_pre_lookup_values(self):
66+
speed = ufloat(496.490, 2.811)
67+
68+
efficiency = 0.08
69+
mock_calibration_table = Mock()
70+
71+
actual_alpha_sw_temp_and_density = calculate_alpha_solar_wind_temperature_and_density_for_combined_sweeps(
72+
mock_calibration_table, speed,
73+
uarray(self.count_rate, self.count_rate_delta), self.energy, efficiency)
74+
75+
self.assertEqual(mock_calibration_table.lookup_density.call_args.args[1],
76+
actual_alpha_sw_temp_and_density.pre_lut_density)
77+
self.assertEqual(mock_calibration_table.lookup_density.call_args.args[2],
78+
actual_alpha_sw_temp_and_density.pre_lut_temperature)
79+
self.assertEqual(mock_calibration_table.lookup_temperature.call_args.args[1],
80+
actual_alpha_sw_temp_and_density.pre_lut_density)
81+
self.assertEqual(mock_calibration_table.lookup_temperature.call_args.args[2],
82+
actual_alpha_sw_temp_and_density.pre_lut_temperature)
5983

6084
@patch(
6185
'imap_l3_processing.swapi.l3a.science.calculate_alpha_solar_wind_temperature_and_density.get_alpha_peak_indices')

tests/swapi/l3a/test_models.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,16 @@ def test_getting_alpha_sw_data_product_variables(self):
8585
expected_flag_values[:len(epoch_data) // 2] = SwapiL3Flags.HI_CHI_SQ
8686

8787
alpha_density = uarray(expected_alpha_density_nominal_values, expected_alpha_density_std_devs)
88+
89+
expected_pre_lut_temperature_nominal_values = np.arange(400000, step=40000.)
90+
expected_pre_lut_temperature_std_devs = np.arange(20000, step=2000.)
91+
alpha_pre_lut_temperature = uarray(expected_pre_lut_temperature_nominal_values, expected_pre_lut_temperature_std_devs)
92+
expected_pre_lut_alpha_density_nominal_values = np.arange(2.4, step=.24)
93+
expected_pre_lut_alpha_density_std_devs = np.arange(1.5, step=0.15)
94+
alpha_pre_lut_density = uarray(expected_pre_lut_alpha_density_nominal_values, expected_pre_lut_alpha_density_std_devs)
95+
8896
data = SwapiL3AlphaSolarWindData(Mock(), epoch_data, alpha_speed, alpha_temperature, alpha_density,
89-
expected_flag_values)
97+
expected_flag_values, alpha_pre_lut_temperature, alpha_pre_lut_density)
9098
variables = data.to_data_product_variables()
9199

92100
self.assert_variable_attributes(variables[0], epoch_data, EPOCH_CDF_VAR_NAME)
@@ -106,6 +114,10 @@ def test_getting_alpha_sw_data_product_variables(self):
106114

107115
self.assert_variable_attributes(variables[8], expected_flag_values, "swp_flags")
108116

117+
self.assert_variable_attributes(variables[9], expected_pre_lut_temperature_nominal_values, "alpha_sw_pre_lut_temperature")
118+
self.assert_variable_attributes(variables[10], expected_pre_lut_alpha_density_nominal_values, "alpha_sw_pre_lut_density")
119+
120+
109121
def test_getting_pui_data_product_variables(self):
110122
epoch_data = np.arange(20, step=2)
111123
expected_epoch_delta = np.full(10, FIVE_MINUTES_IN_NANOSECONDS)

tests/swapi/l3a/test_utils.py

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
import os
2-
from datetime import datetime
32
from pathlib import Path
43
from unittest import TestCase
54

65
import numpy as np
76
from spacepy.pycdf import CDF
87

9-
from imap_l3_processing.swapi.l3a.models import SwapiL2Data, SwapiL3AlphaSolarWindData
10-
from imap_l3_processing.swapi.l3a.utils import chunk_l2_data, read_l2_swapi_data, read_l3a_alpha_sw_swapi_data
11-
from tests.test_helpers import get_test_data_path
8+
from imap_l3_processing.swapi.l3a.models import SwapiL2Data
9+
from imap_l3_processing.swapi.l3a.utils import chunk_l2_data, read_l2_swapi_data
1210

1311

1412
class TestUtils(TestCase):
@@ -82,18 +80,3 @@ def test_reading_l2_data_into_model(self):
8280
np.testing.assert_array_equal(np.array([5, 6, 7, np.nan]), actual_swapi_l2_data.coincidence_count_rate)
8381
np.testing.assert_array_equal(np.array([2, 2, np.nan, 2, 2, 2, 2, 2]),
8482
actual_swapi_l2_data.coincidence_count_rate_uncertainty)
85-
86-
def test_read_l3a_alpha_sw_swapi_data(self):
87-
cdf = CDF(str(get_test_data_path("swapi/imap_swapi_l3a_alpha-sw_20251023_v999.cdf")))
88-
89-
actual_swapi_data: SwapiL3AlphaSolarWindData = read_l3a_alpha_sw_swapi_data(cdf)
90-
91-
self.assertIsNone(actual_swapi_data.input_metadata)
92-
self.assertEqual(10, len(actual_swapi_data.epoch))
93-
self.assertEqual(datetime(2025, 6, 6, 12, 0, 30), actual_swapi_data.epoch[0])
94-
self.assertAlmostEqual(503.8135455170878, actual_swapi_data.alpha_sw_speed[0].nominal_value)
95-
self.assertAlmostEqual(2.6674679453256007, actual_swapi_data.alpha_sw_speed[0].std_dev)
96-
self.assertAlmostEqual(517942.17964600306, actual_swapi_data.alpha_sw_temperature[0].nominal_value)
97-
self.assertAlmostEqual(153774.59736339463, actual_swapi_data.alpha_sw_temperature[0].std_dev)
98-
self.assertAlmostEqual(0.18881474473010484, actual_swapi_data.alpha_sw_density[0].nominal_value)
99-
self.assertAlmostEqual(0.0243276700645657, actual_swapi_data.alpha_sw_density[0].std_dev)

tests/swapi/test_swapi_processor.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -914,9 +914,13 @@ def test_process_l3a_alpha(self, mock_spicepy,
914914

915915
returned_alpha_temperature = ufloat(400000, 2000)
916916
returned_alpha_density = ufloat(0.15, 0.01)
917+
918+
returned_pre_lut_temp = ufloat(300000, 1000)
919+
returned_pre_lut_density = ufloat(0.2, 0.02)
920+
917921
returned_bad_flags = SwapiL3Flags.NONE
918922
mock_alpha_calculate_temperature_and_density.return_value = AlphaSolarWindTemperatureAndDensity(
919-
returned_alpha_temperature, returned_alpha_density, returned_bad_flags)
923+
returned_alpha_temperature, returned_alpha_density, returned_pre_lut_temp, returned_pre_lut_density, returned_bad_flags)
920924

921925
returned_alpha_speed = ufloat(450000, 1000)
922926
mock_calculate_alpha_solar_wind_speed.return_value = ufloat(450000, 1000)
@@ -1024,7 +1028,8 @@ def test_process_l3a_alpha(self, mock_spicepy,
10241028
f"imap_swapi_l3a_{descriptor_to_generate}_{start_date_as_str}_{input_version}"),
10251029
])
10261030

1027-
actual_alpha_metadata, actual_alpha_epoch, actual_alpha_sw_speed, actual_alpha_sw_temperature, actual_alpha_sw_density, actual_bad_fit_flag = mock_alpha_solar_wind_data_constructor.call_args.args
1031+
actual_alpha_metadata, actual_alpha_epoch, actual_alpha_sw_speed, actual_alpha_sw_temperature, actual_alpha_sw_density, actual_bad_fit_flag,\
1032+
actual_pre_lut_temp, actual_pre_lut_density= mock_alpha_solar_wind_data_constructor.call_args.args
10281033
self.assertEqual(expected_alpha_metadata, actual_alpha_metadata)
10291034

10301035
np.testing.assert_array_equal(np.array([initial_epoch + THIRTY_SECONDS_IN_NANOSECONDS]),
@@ -1039,6 +1044,11 @@ def test_process_l3a_alpha(self, mock_spicepy,
10391044
np.array([mock_alpha_calculate_temperature_and_density.return_value.bad_fit_flag]),
10401045
actual_bad_fit_flag)
10411046

1047+
np.testing.assert_array_equal(np.array([mock_alpha_calculate_temperature_and_density.return_value.pre_lut_temperature]),
1048+
actual_pre_lut_temp)
1049+
np.testing.assert_array_equal(np.array([mock_alpha_calculate_temperature_and_density.return_value.pre_lut_density]),
1050+
actual_pre_lut_density)
1051+
10421052
mock_manager.add_instrument_attrs.assert_called_once_with("swapi", "l3a", descriptor_to_generate)
10431053

10441054
self.assertEqual(input_file_names, expected_data_product.parent_file_names)
-84.4 KB
Binary file not shown.

0 commit comments

Comments
 (0)