def test_conform(self): ## conversion of celsius units to kelvin var = Variable(name='tas',units='celsius',value=self.value) var.cfunits_conform(Units('kelvin')) self.assertNumpyAll(var.value,np.ma.array([278.15]*3)) self.assertEqual(var.cfunits,Units('kelvin')) self.assertEqual(var.units,'kelvin')
def test_iter_melted(self): def _assert_key_(attr, key, row, actual_none=None): key_value = row[key] if attr is not None: self.assertEqual(key_value, attr) else: if actual_none is None: self.assertIsNone(key_value) else: self.assertEqual(key_value, actual_none) keywords = dict(value=[np.ma.array([[4, 5], [6, 7]], mask=[[False, True], [False, False]])], use_mask=[True, False], name=[None, 'tmax'], alias=[None, 'tmax_alias'], units=[None, 'celsius'], uid=[None, 3], did=[None, 7], name_uid=[None, 'vid'], attrs=[None, {'foo': 1, 'foo3': 2}]) for k in self.iter_product_keywords(keywords): var = Variable(value=k.value, name=k.name, alias=k.alias, units=k.units, uid=k.uid, did=k.did, attrs=k.attrs) rows = [] for row in var.iter_melted(use_mask=k.use_mask): self.assertAsSetEqual(row.keys(), ['slice', 'name', 'did', 'value', 'alias', 'units', 'uid', 'attrs']) self.assertIn('slice', row) if k.name is None: if k.alias is None: self.assertIsNone(row['alias']) else: self.assertEqual(row['alias'], k.alias) else: if k.alias is None: self.assertEqual(row['alias'], k.name) else: self.assertEqual(row['alias'], k.alias) _assert_key_(k.name, 'name', row) _assert_key_(k.units, 'units', row) _assert_key_(k.uid, 'uid', row) _assert_key_(k.did, 'did', row) _assert_key_(k.attrs, 'attrs', row, actual_none=OrderedDict()) rows.append(row) if k.use_mask: self.assertEqual(len(rows), 3) else: self.assertEqual(len(rows), 4)
def test_get_empty_like(self): kwargs = dict(name='tas', alias='tas2', units='celsius', meta={'foo': 5}, uid=5, data='foo', did=5) value = np.array([1, 2, 3, 4, 5]) value = np.ma.array(value, mask=[False, True, False, True, False]) kwargs['value'] = value kwargs['attrs'] = OrderedDict(foo=5) var = Variable(**kwargs) for shape in [None, (2, 2)]: new_var = var.get_empty_like(shape=shape) self.assertDictEqual(new_var.attrs, kwargs['attrs']) new_var.attrs['hi'] = 'wow' self.assertNotEqual(new_var.attrs, kwargs['attrs']) self.assertEqual(new_var.uid, var.uid) if shape is None: actual = np.ma.array(np.zeros(5), dtype=var.dtype, fill_value=var.fill_value, mask=value.mask) else: actual = np.ma.array(np.zeros((2, 2)), dtype=var.dtype, fill_value=var.fill_value, mask=False) self.assertNumpyAll(actual, new_var.value) # the meta dictionary should be deepcopied new_var.meta['hi'] = 'there' self.assertDictEqual(var.meta, {'foo': 5})
def test_cfunits_conform(self): # conversion of celsius units to kelvin attrs = {k: 1 for k in NETCDF_ATTRIBUTES_TO_REMOVE_ON_VALUE_CHANGE} var = Variable(name='tas', units='celsius', value=self.value, attrs=attrs) self.assertEqual(len(var.attrs), 2) var.cfunits_conform(Units('kelvin')) self.assertNumpyAll(var.value, np.ma.array([278.15] * 3)) self.assertEqual(var.cfunits, Units('kelvin')) self.assertEqual(var.units, 'kelvin') self.assertEqual(len(var.attrs), 0) # if there are no units associated with a variable, conforming the units should fail var = Variable(name='tas', units=None, value=self.value) with self.assertRaises(NoUnitsError): var.cfunits_conform(Units('kelvin')) # conversion should fail for nonequivalent units var = Variable(name='tas', units='kelvin', value=self.value) with self.assertRaises(ValueError): var.cfunits_conform(Units('grams')) # the data type should always be updated to match the output from cfunits av = FakeAbstractValueVariable(value=np.array([4, 5, 6]), dtype=int) self.assertEqual(av.dtype, np.dtype(int)) with self.assertRaises(NoUnitsError): av.cfunits_conform('K') av.units = 'celsius' av.cfunits_conform('K') self.assertIsNone(av._dtype) self.assertEqual(av.dtype, av.value.dtype) # calendar can be finicky - those need to be stripped from the string conversion conform_units_to = Units('days since 1949-1-1', calendar='standard') units = Units('days since 1900-1-1', calendar='standard') av = FakeAbstractValueVariable(value=np.array([4000, 5000, 6000]), units=units, conform_units_to=conform_units_to) self.assertEqual(av.units, 'days since 1949-1-1')
def test_getitem(self): var = Variable(value=np.random.rand(1, 1, 1, 1, 51), name='foo') slc = [slice(None, None, None), slice(None, None, None), slice(None, None, None), np.array([0]), np.array([14])] ret = var.__getitem__(slc) self.assertEqual(ret.shape, tuple([1] * 5))
def test_cfunits_conform_masked_array(self): # assert mask is respected by inplace unit conversion value = np.ma.array(data=[5, 5, 5], mask=[False, True, False]) var = Variable(name='tas', units=Units('celsius'), value=value) var.cfunits_conform(Units('kelvin')) self.assertNumpyAll(np.ma.array([278.15, 278.15, 278.15], mask=[False, True, False]), var.value)
def test_cfunits_conform(self): units_kelvin = get_units_object('kelvin') # Conversion of celsius units to kelvin. attrs = {k: 1 for k in NETCDF_ATTRIBUTES_TO_REMOVE_ON_VALUE_CHANGE} var = Variable(name='tas', units='celsius', value=self.value, attrs=attrs) self.assertEqual(len(var.attrs), 4) var.cfunits_conform(units_kelvin) self.assertNumpyAll(var.value, np.ma.array([278.15] * 3)) self.assertEqual(var.cfunits, units_kelvin) self.assertEqual(var.units, 'kelvin') self.assertEqual(len(var.attrs), 0) # If there are no units associated with a variable, conforming the units should fail. var = Variable(name='tas', units=None, value=self.value) with self.assertRaises(NoUnitsError): var.cfunits_conform(units_kelvin) # Conversion should fail for nonequivalent units. var = Variable(name='tas', units='kelvin', value=self.value) with self.assertRaises(ValueError): var.cfunits_conform(get_units_object('grams')) # The data type should always be updated to match the output from CF units backend. av = Variable(value=np.array([4, 5, 6]), dtype=int) self.assertEqual(av.dtype, np.dtype(int)) with self.assertRaises(NoUnitsError): av.cfunits_conform('K') av.units = 'celsius' av.cfunits_conform('K') self.assertIsNone(av._dtype) self.assertEqual(av.dtype, av.value.dtype)
def test_write_netcdf(self): keywords = dict(file_only=[False, True], second_variable_alias=[None, 'tmin_alias'], with_realization=[False, True], remove_dimension_names=[False, True], crs=[None, Spherical()], with_level=[True, False], variable_kwargs=[{}, {'zlib': True, 'complevel': 5}, {'bad': 'keyword'}]) path = os.path.join(self.current_dir_output, 'foo.nc') for k in itr_products_keywords(keywords, as_namedtuple=True): field = self.get_field(with_value=True, with_realization=k.with_realization, crs=k.crs, with_level=k.with_level) if k.remove_dimension_names: try: field.level.name = None except AttributeError: self.assertFalse(k.with_level) field.temporal.name = None field.spatial.grid.row.name = None field.spatial.grid.col.name = None # Add another variable. value = np.random.rand(*field.shape) second_variable_name = 'tmin' second_variable_alias = k.second_variable_alias or second_variable_name variable = Variable(value=value, name=second_variable_name, alias=k.second_variable_alias) variable.attrs['open'] = 'up' field.variables.add_variable(variable, assign_new_uid=True) # Add some attributes. field.attrs['foo'] = 'some information' field.attrs['another'] = 'some more information' with nc_scope(path, 'w') as ds: try: field.write_netcdf(ds, file_only=k.file_only, **k.variable_kwargs) except TypeError: # Test variable keyword are actually passed by providing a bad keyword argument. self.assertDictEqual(k.variable_kwargs, {'bad': 'keyword'}) continue except ValueError: self.assertTrue(k.with_realization) self.assertIsNotNone(field.realization) continue with nc_scope(path) as ds: self.assertEqual(ds.another, 'some more information') try: variable_names = ['time', 'time_bounds', 'latitude', 'latitude_bounds', 'longitude', 'longitude_bounds', 'tmax', second_variable_alias] dimension_names = ['time', 'bounds', 'latitude', 'longitude'] if k.crs is not None: variable_names.append(k.crs.name) if k.with_level: variable_names += ['level', 'level_bounds'] dimension_names.append('level') self.assertEqual(set(ds.variables.keys()), set(variable_names)) self.assertEqual(set(ds.dimensions.keys()), set(dimension_names)) except AssertionError: self.assertTrue(k.remove_dimension_names) variable_names = ['time', 'time_bounds', 'yc', 'yc_bounds', 'xc', 'xc_bounds', 'tmax', second_variable_alias] dimension_names = ['time', 'bounds', 'yc', 'xc'] if k.crs is not None: variable_names.append(k.crs.name) if k.with_level: variable_names += ['level', 'level_bounds'] dimension_names.append('level') self.assertEqual(set(ds.variables.keys()), set(variable_names)) self.assertEqual(set(ds.dimensions.keys()), set(dimension_names)) nc_second_variable = ds.variables[second_variable_alias] try: for field_variable in field.variables.itervalues(): self.assertEqual(ds.variables[field_variable.alias].grid_mapping, k.crs.name) except AttributeError: self.assertIsNone(k.crs) self.assertEqual(nc_second_variable.open, 'up') try: self.assertNumpyAll(nc_second_variable[:], value.squeeze()) except AssertionError: self.assertTrue(k.file_only) self.assertTrue(nc_second_variable[:].mask.all()) self.assertEqual(ds.variables['tmax'].units, field.variables['tmax'].units) self.assertEqual(nc_second_variable.units, '') new_field = RequestDataset(path).get() self.assertEqual(new_field.variables.keys(), ['tmax', second_variable_alias]) if k.with_level: level_shape = 2 else: level_shape = 1 self.assertEqual(new_field.shape, (1, 31, level_shape, 3, 4))
def test_conform_no_units(self): ## if there are no units associate with a variable, conforming the units ## should fail var = Variable(name='tas',units=None,value=self.value) with self.assertRaises(NoUnitsError): var.cfunits_conform(Units('kelvin'))
def test_conform_nonequivalent_units(self): ## conversion should fail for nonequivalent units var = Variable(name='tas',units='kelvin',value=self.value) with self.assertRaises(ValueError): var.cfunits_conform(Units('grams'))