Skip to content

Commit

Permalink
DAS-1177 - Add and update unit tests - add_bounds not complete yet.
Browse files Browse the repository at this point in the history
  • Loading branch information
lyonthefrog committed Mar 6, 2024
1 parent 71c39c1 commit fec7cf0
Showing 1 changed file with 149 additions and 3 deletions.
152 changes: 149 additions & 3 deletions tests/unit/test_dimension_utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

from harmony.util import config
from harmony.message import Message
from pathlib import PurePosixPath
from netCDF4 import Dataset
from numpy.ma import masked_array
from numpy.testing import assert_array_equal
Expand All @@ -22,7 +23,11 @@
get_requested_index_ranges,
is_almost_in, is_dimension_ascending,
is_index_subset,
prefetch_dimension_variables)
prefetch_dimension_variables,
add_bounds_variables,
needs_bounds,
get_bounds_array,
write_bounds)
from hoss.exceptions import InvalidNamedDimension, InvalidRequestedRange


Expand All @@ -46,6 +51,7 @@ def setUpClass(cls):
'tests/data/GPM_3IMERGHH_example.dmr'
)


def setUp(self):
""" Create fixtures that should be unique per test. """
self.temp_dir = mkdtemp()
Expand Down Expand Up @@ -225,7 +231,7 @@ def test_get_dimension_indices_from_indices(self):

def test_add_index_range(self):
""" Ensure the correct combinations of index ranges are added as
suffixes to the input variable based upon that variable's
suffixes to the input variable based upon that variable'scd
dimensions.
If a dimension range has the lower index > upper index, that
Expand Down Expand Up @@ -272,8 +278,10 @@ def test_get_fill_slice(self):
slice(16, 200)
)

@patch('hoss.dimension_utilities.add_bounds_variables')
@patch('hoss.dimension_utilities.get_opendap_nc4')
def test_prefetch_dimension_variables(self, mock_get_opendap_nc4):
def test_prefetch_dimension_variables(self, mock_get_opendap_nc4,
mock_add_bounds_variables):
""" Ensure that when a list of required variables is specified, a
request to OPeNDAP will be sent requesting only those that are
grid-dimension variables (both spatial and temporal).
Expand Down Expand Up @@ -304,6 +312,144 @@ def test_prefetch_dimension_variables(self, mock_get_opendap_nc4):
output_dir, self.logger,
access_token, self.config)

mock_add_bounds_variables.assert_called_once_with(prefetch_path,
required_dimensions,
self.varinfo, self.logger)


@patch('hoss.dimension_utilities.needs_bounds')
@patch('hoss.dimension_utilities.write_bounds')
def test_add_bounds_variables(self, mock_write_bounds, mock_needs_bounds):
""" Ensure that `write_bounds` is called when it's needed,
and that it's not called when it's not needed.
"""
prefetch_dataset_name = 'tests/data/ATL16_prefetch.nc4'
varinfo_prefetch = VarInfoFromDmr(
'tests/data/ATL16_prefetch.dmr'
)
required_dimensions = {'/npolar_grid_lat','/npolar_grid_lon'}

with self.subTest('Bounds need to be written'):
mock_needs_bounds.return_value = True
add_bounds_variables(prefetch_dataset_name,
required_dimensions,
varinfo_prefetch,
self.logger)

with Dataset(prefetch_dataset_name, 'r+') as prefetch_dataset:
for dimension_name in required_dimensions:
dimension_variable = varinfo_prefetch.get_variable(dimension_name)
mock_write_bounds.assert_called_with(prefetch_dataset,
dimension_variable)

mock_needs_bounds.reset_mock()
mock_write_bounds.reset_mock()

with self.subTest('Bounds should not be written'):
mock_needs_bounds.return_value = False
add_bounds_variables(prefetch_dataset_name,
required_dimensions,
varinfo_prefetch,
self.logger)
mock_write_bounds.assert_not_called()


def test_needs_bounds(self):
""" Ensure that the correct boolean value is returned for four
different cases:
1) False - cell_alignment[edge] attribute exists and bounds variable already exists.
2) False - cell_alignment[edge] attribute does not exist and bounds variable already exists.
3) True - cell_alignment[edge] attribute exists and bounds variable does not exist.
4) False - cell_alignment[edge] attribute does not exist and bounds variable does not exist.
"""
varinfo_bounds = VarInfoFromDmr(
'tests/data/ATL16_prefetch_bnds.dmr'
)

with self.subTest('Variable has cell alignment and bounds'):
self.assertFalse(needs_bounds(varinfo_bounds.get_variable('/group1/group2/variable_edge_has_bnds')))

with self.subTest('Variable has no cell alignment and has bounds'):
self.assertFalse(needs_bounds(varinfo_bounds.get_variable('/group1/group2/variable_no_edge_has_bnds')))

with self.subTest('Variable has cell alignment and no bounds'):
self.assertTrue(needs_bounds(varinfo_bounds.get_variable('/group1/group2/variable_edge_no_bnds')))

with self.subTest('Variable has no cell alignment and no bounds'):
self.assertFalse(needs_bounds(varinfo_bounds.get_variable('/group1/group2/variable_no_edge_no_bnds')))


def test_get_bounds_array(self):
""" Ensure that the expected bounds array is created given
the input dimension variable values.
"""
prefetch_dataset = Dataset('tests/data/ATL16_prefetch.nc4', 'r')
dimension_path = '/npolar_grid_lat'

bounds_array = np.array([[90.0, 89.0], [89.0, 88.0], [88.0, 87.0], [87.0, 86.0],
[86.0, 85.0], [85.0, 84.0], [84.0, 83.0], [83.0, 82.0],
[82.0, 81.0], [81.0, 80.0], [80.0, 79.0], [79.0, 78.0],
[78.0, 77.0], [77.0, 76.0], [76.0, 75.0], [75.0, 74.0],
[74.0, 73.0], [73.0, 72.0], [72.0, 71.0], [71.0, 70.0],
[70.0, 69.0], [69.0, 68.0], [68.0, 67.0], [67.0, 66.0],
[66.0, 65.0], [65.0, 64.0], [64.0, 63.0], [63.0, 62.0],
[62.0, 61.0], [61.0, 60.0]])

assert_array_equal(get_bounds_array(prefetch_dataset, dimension_path),
bounds_array)


def test_write_bounds(self):
""" Ensure that bounds data array is written to the dimension
dataset, both when the dimension variable is in the root group
and in a nested group.
"""
varinfo_prefetch = VarInfoFromDmr('tests/data/ATL16_prefetch_group.dmr')
prefetch_dataset = Dataset('tests/data/ATL16_prefetch_group.nc4', 'r+')

# Expected variable contents in file.
expected_bounds_data = np.array([
[90.0, 89.0], [89.0, 88.0], [88.0, 87.0], [87.0, 86.0],
[86.0, 85.0], [85.0, 84.0], [84.0, 83.0], [83.0, 82.0],
[82.0, 81.0], [81.0, 80.0], [80.0, 79.0], [79.0, 78.0],
[78.0, 77.0], [77.0, 76.0], [76.0, 75.0], [75.0, 74.0],
[74.0, 73.0], [73.0, 72.0], [72.0, 71.0], [71.0, 70.0],
[70.0, 69.0], [69.0, 68.0], [68.0, 67.0], [67.0, 66.0],
[66.0, 65.0], [65.0, 64.0], [64.0, 63.0], [63.0, 62.0],
[62.0, 61.0], [61.0, 60.0]])

with self.subTest('Dimension variable is in the root group'):
root_variable_full_path = '/npolar_grid_lat'
root_varinfo_variable = varinfo_prefetch.get_variable(root_variable_full_path)
root_variable_name = str(PurePosixPath(root_variable_full_path).name)

write_bounds(prefetch_dataset, root_varinfo_variable)
resulting_bounds_root_data = prefetch_dataset.variables[root_variable_name
+ '_bnds'][:]
assert_array_equal(resulting_bounds_root_data,
expected_bounds_data)

with self.subTest('Dimension variable is in a nested group'):
nested_variable_full_path = '/group1/group2/zelda'
nested_varinfo_variable = varinfo_prefetch.get_variable(nested_variable_full_path)
nested_variable_name = str(PurePosixPath(nested_variable_full_path).name)
nested_variable_path = str(PurePosixPath(nested_variable_full_path).parent)
nested_group = prefetch_dataset[nested_variable_path]

write_bounds(prefetch_dataset, nested_varinfo_variable)

resulting_bounds_nested_data = nested_group.variables[nested_variable_name
+ '_bnds'][:]

assert_array_equal(resulting_bounds_nested_data,
expected_bounds_data)


@patch('hoss.dimension_utilities.get_opendap_nc4')
def test_prefetch_dimensions_with_bounds(self, mock_get_opendap_nc4):
""" Ensure that a variable which has dimensions with `bounds` metadata
Expand Down

0 comments on commit fec7cf0

Please sign in to comment.