Skip to content

Commit 5349680

Browse files
author
Menlo Innovations - CAVA Project
committed
Harrison 2381 - PMCL/TLAY - Replace NaNs with fill value when writing CDF
Only do so if the input is a float and the fill value is specified.
1 parent f83cbf5 commit 5349680

2 files changed

Lines changed: 36 additions & 2 deletions

File tree

imap_processing/cdf/cdf_utils.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,14 @@ def write_cdf(file_path: str, data: DataProduct, attribute_manager: ImapAttribut
2222

2323
for data_product in data.to_data_product_variables():
2424
var_name = data_product.name
25-
cdf.new(var_name, data=data_product.value,
25+
variable_attributes = attribute_manager.get_variable_attributes(var_name)
26+
data_array = np.asarray(data_product.value)
27+
if 'FILLVAL' in variable_attributes and np.issubdtype(data_array.dtype, np.floating):
28+
data_array = np.where(np.isnan(data_array), variable_attributes["FILLVAL"], data_array)
29+
cdf.new(var_name, data_array,
2630
recVary=data_product.record_varying,
2731
type=data_product.cdf_data_type)
28-
for k, v in attribute_manager.get_variable_attributes(var_name).items():
32+
for k, v in variable_attributes.items():
2933
if k == 'DEPEND_0' and v == '':
3034
continue
3135
if k == 'FILLVAL' and data_product.cdf_data_type is not None:

tests/cdf/test_cdf_utils.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,36 @@ def test_write_cdf_trims_numbers_in_logical_source_when_fetching_global_metadata
9191
self.assertEqual('global_val1', str(actual_cdf.attrs['global1']))
9292
self.assertEqual('global_val2', str(actual_cdf.attrs['global2']))
9393

94+
def test_write_cdf_replaces_nan_with_fill_value(self):
95+
epoch_data = [datetime(2025, 3, 7, 17, 0)]
96+
97+
class DataProductWithNan(DataProduct):
98+
def __init__(self):
99+
self.input_metadata = Mock()
100+
101+
def to_data_product_variables(self) -> list[DataProductVariable]:
102+
return [
103+
DataProductVariable("epoch", epoch_data, pycdf.const.CDF_TIME_TT2000),
104+
DataProductVariable("float_var", np.array([3, 5, np.nan, 9, np.nan, np.nan]),
105+
pycdf.const.CDF_REAL4),
106+
]
107+
108+
path = str(self.temp_directory / "write_cdf.cdf")
109+
data = DataProductWithNan()
110+
attribute_manager = Mock(spec=ImapAttributeManager)
111+
attribute_manager.get_global_attributes.return_value = {}
112+
attribute_manager.get_variable_attributes.side_effect = [
113+
{"VAR_NAME": "epoch", "FILLVAL": datetime.fromisoformat("9999-12-31T23:59:59.999999999")},
114+
{"VAR_NAME": "float_var", "FILLVAL": -1e31},
115+
]
116+
117+
write_cdf(path, data, attribute_manager)
118+
with pycdf.CDF(path) as actual_cdf:
119+
self.assertFalse(np.any(np.isnan(actual_cdf["float_var"][...])))
120+
np.testing.assert_array_equal(np.array([3, 5, -1e31, 9, -1e31, -1e31], dtype=np.float32),
121+
actual_cdf["float_var"][...], strict=True)
122+
np.testing.assert_array_equal(actual_cdf["epoch"][...], np.array(epoch_data), strict=True)
123+
94124
def test_does_not_write_depend_0_variable_attribute_if_it_is_empty(self):
95125
path = str(self.temp_directory / "write_cdf.cdf")
96126
data = TestDataProduct()

0 commit comments

Comments
 (0)