Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion improver/utilities/save.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ def save_netcdf(
filename: str,
compression_level: int = 1,
least_significant_digit: Optional[int] = None,
fill_value: Optional[float] = None,
) -> None:
"""Save the input Cube or CubeList as a NetCDF file and check metadata
where required for integrity.
Expand All @@ -80,7 +81,11 @@ def save_netcdf(
http://www.esrl.noaa.gov/psd/data/gridded/conventions/cdc_netcdf_standard.shtml
for details. When used with `compression level`, this will result in lossy
compression.

fill_value:
If specified, will set the fill value for missing data. If not specified,
the default fill value for the data type will be used. If the data is not masked then
the numpy array's fill value will retain the default value while the _FillValue attribute
in the NetCDF file will be updated.
Raises:
warning if cubelist contains cubes of varying dimensions.
"""
Expand Down Expand Up @@ -144,5 +149,6 @@ def save_netcdf(
zlib=compression_level > 0,
chunksizes=chunksizes,
least_significant_digit=least_significant_digit,
fill_value=fill_value,
)
os.rename(ftmp, filename)
39 changes: 39 additions & 0 deletions improver_tests/utilities/test_save.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,45 @@ def test_remove_least_significant_digit(self):
cube = load_cube(self.filepath)
self.assertNotIn("least_significant_digit", cube.attributes)

def test_fill_value_no_mask(self):
"""Test that the default fill_value is not overriden if there
is no masked data."""
save_netcdf(self.cube, self.filepath)
cube = load_cube(self.filepath)
self.assertEqual(
cube.data.get_fill_value(), 1e20
) # Default fill value for float32

def test_fill_value_no_mask_integer_data(self):
"""Test that the default fill_value is not overriden if there is
no masked data and integer data is provided."""
cube = self.cube.copy()
cube.data = np.array(cube.data.astype(int))

save_netcdf(cube, self.filepath)
cube = load_cube(self.filepath)
self.assertEqual(
cube.data.get_fill_value(), 999999
) # default fill value for int32

def test_fill_value_with_mask(self):
"""Test that fill_value can be overriden."""
cube = self.cube.copy()
mask = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]
cube.data = np.ma.masked_array(cube.data, mask=mask)
save_netcdf(cube, self.filepath, fill_value=99)
cube = load_cube(self.filepath)
self.assertEqual(cube.data.get_fill_value(), 99)

def test_fill_value_with_mask_integer_data(self):
"""Test that fill_value can be overriden when integer data is provided."""
cube = self.cube.copy()
mask = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]
cube.data = np.ma.masked_array(cube.data.astype(int), mask=mask)
save_netcdf(cube, self.filepath, fill_value=99)
cube = load_cube(self.filepath)
self.assertEqual(cube.data.get_fill_value(), 99)


@pytest.fixture(name="bitshaving_cube")
def bitshaving_cube_fixture():
Expand Down