def write_cross_reference_module(module_path, xrefs): gen_helpers.prep_module_file(module_path) with open(module_path, "a") as module_file: module_file.write(HEADER) module_file.write(CODE_PREAMBLE) module_file.write("STASH_TRANS = {\n") for xref in xrefs: stash = xref.get("stash") try: STASH.from_msi(stash.replace('"', "")) except ValueError: msg = "stash code is not of a recognised" '"m??s??i???" form: {}'.format(stash) print msg grid = xref.get("grid") if grid is not None: try: int(grid) except ValueError: msg = "grid code retrieved from STASH lookup" "is not an interger: {}".format(grid) print msg else: grid = 0 lbfc = xref.get("lbfcn") try: int(lbfc) except (ValueError, TypeError): lbfc = 0 module_file.write(' "{}": Stash({}, {}),\n'.format(stash, grid, lbfc)) module_file.write("}\n")
def write_cross_reference_module(module_path, xrefs): gen_helpers.prep_module_file(module_path) with open(module_path, 'a') as module_file: module_file.write(HEADER) module_file.write(CODE_PREAMBLE) module_file.write('STASH_TRANS = {\n') for xref in xrefs: stash = xref.get('stash') try: STASH.from_msi(stash.replace('"', '')) except ValueError: msg = ('stash code is not of a recognised' '"m??s??i???" form: {}'.format(stash)) print(msg) grid = xref.get('grid') if grid is not None: try: int(grid) except ValueError: msg = ('grid code retrieved from STASH lookup' 'is not an integer: {}'.format(grid)) print(msg) else: grid = 0 lbfc = _value_from_xref(xref, 'lbfcn') pseudT = _value_from_xref(xref, 'pseudT') module_file.write(' "{}": Stash({}, {}, {}),\n'.format( stash, grid, lbfc, pseudT)) module_file.write('}\n')
def write_cross_reference_module(module_path, xrefs): gen_helpers.prep_module_file(module_path) with open(module_path, 'a') as module_file: module_file.write(HEADER) module_file.write(CODE_PREAMBLE) module_file.write('STASH_TRANS = {\n') for xref in xrefs: stash = xref.get('stash') try: STASH.from_msi(stash.replace('"', '')) except ValueError: msg = ('stash code is not of a recognised' '"m??s??i???" form: {}'.format(stash)) print(msg) grid = xref.get('grid') if grid is not None: try: int(grid) except ValueError: msg = ('grid code retrieved from STASH lookup' 'is not an interger: {}'.format(grid)) print(msg) else: grid = 0 lbfc = xref.get('lbfcn') try: int(lbfc) except (ValueError, TypeError): lbfc = 0 module_file.write( ' "{}": Stash({}, {}),\n'.format(stash, grid, lbfc)) module_file.write('}\n')
def test_double_stash(self): stcube236 = mock.Mock(stash=STASH.from_msi('m01s03i236')) stcube4 = mock.Mock(stash=STASH.from_msi('m01s00i004')) stcube7 = mock.Mock(stash=STASH.from_msi('m01s00i007')) constraints = [iris.AttributeConstraint(STASH='m01s03i236'), iris.AttributeConstraint(STASH='m01s00i004')] pp_filter = _convert_constraints(constraints) self.assertTrue(pp_filter(stcube236)) self.assertTrue(pp_filter(stcube4)) self.assertFalse(pp_filter(stcube7))
def test_double_stash(self): stcube236 = mock.Mock(stash=STASH.from_msi('m01s03i236')) stcube4 = mock.Mock(stash=STASH.from_msi('m01s00i004')) stcube7 = mock.Mock(stash=STASH.from_msi('m01s00i007')) constraints = [iris.AttributeConstraint(STASH='m01s03i236'), iris.AttributeConstraint(STASH='m01s00i004')] pp_filter = _convert_constraints(constraints) self.assertTrue(pp_filter(stcube236)) self.assertTrue(pp_filter(stcube4)) self.assertFalse(pp_filter(stcube7))
def test_callable_stash(self): stcube236 = mock.Mock(stash=STASH.from_msi('m01s03i236')) stcube4 = mock.Mock(stash=STASH.from_msi('m01s00i004')) stcube7 = mock.Mock(stash=STASH.from_msi('m01s00i007')) con1 = iris.AttributeConstraint(STASH=lambda s: s.endswith("004")) con2 = iris.AttributeConstraint(STASH=lambda s: s == "m01s00i007") constraints = [con1, con2] pp_filter = _convert_constraints(constraints) self.assertFalse(pp_filter(stcube236)) self.assertTrue(pp_filter(stcube4)) self.assertTrue(pp_filter(stcube7))
def test_callable_stash(self): stcube236 = mock.Mock(stash=STASH.from_msi('m01s03i236')) stcube4 = mock.Mock(stash=STASH.from_msi('m01s00i004')) stcube7 = mock.Mock(stash=STASH.from_msi('m01s00i007')) con1 = iris.AttributeConstraint(STASH=lambda s: s.endswith("004")) con2 = iris.AttributeConstraint(STASH=lambda s: s == "m01s00i007") constraints = [con1, con2] pp_filter = _convert_constraints(constraints) self.assertFalse(pp_filter(stcube236)) self.assertTrue(pp_filter(stcube4)) self.assertTrue(pp_filter(stcube7))
def test_summary_stash(self): self.cubes[0].attributes["STASH"] = STASH.from_msi("m01s00i004") expected = ( "0: m01s00i004 / (unknown) " " (latitude: 3; longitude: 4)" ) self.assertEqual(str(self.cubes), expected)
def write_cross_reference_module(module_path, xrefs): gen_helpers.prep_module_file(module_path) with open(module_path, 'a') as module_file: module_file.write(HEADER) module_file.write('STASH_GRID = {\n') for xref in xrefs: stash = xref.get('stash') try: STASH.from_msi(stash) except ValueError: msg = ('stash code is not of a recognised' '"m??s??i???" form: {}'.format(stash)) grid = xref.get('grid') try: int(grid) except ValueError: msg = ('grid code retrieved from STASH lookup' 'is not an interger: {}'.format(grid)) module_file.write(" {}: {},\n".format(stash, grid)) module_file.write('}\n')
def test_surface_pressure(self): # Ensure that surface pressure fields are not filtered. pp_filter = self._single_stash() pressure_cube = mock.Mock(stash=STASH.from_msi('m01s00i001')) self.assertTrue(pp_filter(pressure_cube))
def test_surface_altitude(self): # Ensure that surface altitude fields are not filtered. pp_filter = self._single_stash() orography_cube = mock.Mock(stash=STASH.from_msi('m01s00i033')) self.assertTrue(pp_filter(orography_cube))
def test_stash_object(self): constraint = iris.AttributeConstraint( STASH=STASH.from_msi('m01s03i236')) pp_filter = _convert_constraints(constraint) stcube = mock.Mock(stash=STASH.from_msi('m01s03i236')) self.assertTrue(pp_filter(stcube))
def test_single_stash(self): pp_filter = self._single_stash() stcube = mock.Mock(stash=STASH.from_msi('m01s03i236')) self.assertTrue(pp_filter(stcube))
def test_stash_object(self): constraint = iris.AttributeConstraint( STASH=STASH.from_msi('m01s03i236')) pp_filter = _convert_constraints(constraint) stcube = mock.Mock(stash=STASH.from_msi('m01s03i236')) self.assertTrue(pp_filter(stcube))
def fields(self, c_t=None, cft=None, ctp=None, c_h=None, c_p=None, phn=0, mmm=None, pse=None): # Return a list of 2d cubes representing raw PPFields, from args # specifying sequences of (scalar) coordinate values. # TODO? : add bounds somehow ? # # Arguments 'c<xx>' are either a single int value, making a scalar # coord, or a string of characters : '0'-'9' (index) or '-' (missing). # The indexes select point values from fixed list of possibles. # # Argument 'c_h' and 'c_p' represent height or pressure values, so # ought to be mutually exclusive -- these control LBVC. # # Argument 'phn' indexes phenomenon types. # # Argument 'mmm' denotes existence (or not) of a cell method of type # 'average' or 'min' or 'max' (values '012' respectively), applying to # the time values -- ultimately, this controls LBTIM. # # Argument 'pse' denotes pseudo-level numbers. # These translate into 'LBUSER5' values. # Get the number of result cubes, defined by the 'longest' arg. def arglen(arg): # Get the 'length' of a control argument. if arg is None: result = 0 elif isinstance(arg, six.string_types): result = len(arg) else: result = 1 return result n_flds = max(arglen(x) for x in (c_t, cft, ctp, c_h, c_p, mmm)) # Make basic anonymous test cubes. ny, nx = 3, 5 data = np.arange(n_flds * ny * nx, dtype=np.float32) data = data.reshape((n_flds, ny, nx)) cubes = [Cube(data[i]) for i in range(n_flds)] # Define test point values for making coordinates. time_unit = 'hours since 1970-01-01' period_unit = 'hours' height_unit = 'm' pressure_unit = 'hPa' time_values = 24.0 * np.arange(10) height_values = 100.0 * np.arange(1, 11) pressure_values = [100.0, 150.0, 200.0, 250.0, 300.0, 500.0, 850.0, 1000.0] pseudolevel_values = range(1, 11) # A valid value is >= 1. # Test phenomenon details. # NOTE: in order to write/readback as identical, these also contain a # canonical unit and matching STASH attribute. # Those could in principle be looked up, but it's a bit awkward. phenomenon_values = [ ('air_temperature', 'K', 'm01s01i004'), ('x_wind', 'm s-1', 'm01s00i002'), ('y_wind', 'm s-1', 'm01s00i003'), ('specific_humidity', 'kg kg-1', 'm01s00i010'), ] # Test cell-methods. # NOTE: if you add an *interval* to any of these cell-methods, it is # not saved into the PP file (?? or maybe not loaded back again ??). # This could be a PP save/load bug, or maybe just because no bounds ? cell_method_values = [ CellMethod('mean', 'time'), CellMethod('maximum', 'time'), CellMethod('minimum', 'time'), ] # Define helper to decode an argument as a list of test values. def arg_vals(arg, vals): # Decode an argument to a list of 'n_flds' coordinate point values. # (or 'None' where missing) # First get a list of value indices from the argument. # Can be: a single index value; a list of indices; or a string. if (isinstance(arg, Iterable) and not isinstance(arg, six.string_types)): # Can also just pass a simple iterable of values. inds = [int(val) for val in arg] else: n_vals = arglen(arg) if n_vals == 0: inds = [None] * n_flds elif n_vals == 1: inds = [int(arg)] * n_flds else: assert isinstance(arg, six.string_types) inds = [None if char == '-' else int(char) for char in arg] # Convert indices to selected point values. values = [None if ind is None else vals[int(ind)] for ind in inds] return values # Apply phenomenon_values definitions. phenomena = arg_vals(phn, phenomenon_values) for cube, (name, units, stash) in zip(cubes, phenomena): cube.rename(name) # NOTE: in order to get a cube that will write+readback the same, # the units must be the canonical one. cube.units = units # NOTE: in order to get a cube that will write+readback the same, # we must include a STASH attribute. cube.attributes['STASH'] = STASH.from_msi(stash) # Add x and y coords. cs = GeogCS(EARTH_RADIUS) xvals = np.linspace(0.0, 180.0, nx) co_x = DimCoord(np.array(xvals, dtype=np.float32), standard_name='longitude', units='degrees', coord_system=cs) yvals = np.linspace(-45.0, 45.0, ny) co_y = DimCoord(np.array(yvals, dtype=np.float32), standard_name='latitude', units='degrees', coord_system=cs) for cube in cubes: cube.add_dim_coord(co_y, 0) cube.add_dim_coord(co_x, 1) # Add multiple scalar coordinates as defined by the arguments. def arg_coords(arg, name, unit, vals=None): # Decode an argument to a list of scalar coordinates. if vals is None: vals = np.arange(n_flds + 2) # Note allowance vals = arg_vals(arg, vals) coords = [None if val is None else DimCoord([val], units=unit) for val in vals] # Apply names separately, as 'pressure' is not a standard name. for coord in coords: if coord: coord.rename(name) # Also fix heights to match what comes from a PP file. if name == 'height': coord.attributes['positive'] = 'up' return coords def add_arg_coords(arg, name, unit, vals=None): # Add scalar coordinates to each cube, for one argument. coords = arg_coords(arg, name, unit, vals) for cube, coord in zip(cubes, coords): if coord: cube.add_aux_coord(coord) add_arg_coords(c_t, 'time', time_unit, time_values) add_arg_coords(cft, 'forecast_reference_time', time_unit) add_arg_coords(ctp, 'forecast_period', period_unit, time_values) add_arg_coords(c_h, 'height', height_unit, height_values) add_arg_coords(c_p, 'pressure', pressure_unit, pressure_values) add_arg_coords(pse, 'pseudo_level', '1', pseudolevel_values) # Add cell methods as required. methods = arg_vals(mmm, cell_method_values) for cube, method in zip(cubes, methods): if method: cube.add_cell_method(method) return cubes
def test_surface_pressure(self): # Ensure that surface pressure fields are not filtered. pp_filter = self._single_stash() pressure_cube = mock.Mock(stash=STASH.from_msi('m01s00i001')) self.assertTrue(pp_filter(pressure_cube))
def test_surface_altitude(self): # Ensure that surface altitude fields are not filtered. pp_filter = self._single_stash() orography_cube = mock.Mock(stash=STASH.from_msi('m01s00i033')) self.assertTrue(pp_filter(orography_cube))
def test_single_stash(self): pp_filter = self._single_stash() stcube = mock.Mock(stash=STASH.from_msi('m01s03i236')) self.assertTrue(pp_filter(stcube))
def test_summary_stash(self): self.cubes[0].attributes['STASH'] = STASH.from_msi('m01s00i004') expected = ('0: m01s00i004 / (unknown) ' ' (latitude: 3; longitude: 4)') self.assertEqual(str(self.cubes), expected)
def fields(self, c_t=None, cft=None, ctp=None, c_h=None, c_p=None, phn=0, mmm=None, pse=None): # Return a list of 2d cubes representing raw PPFields, from args # specifying sequences of (scalar) coordinate values. # TODO? : add bounds somehow ? # # Arguments 'c<xx>' are either a single int value, making a scalar # coord, or a string of characters : '0'-'9' (index) or '-' (missing). # The indexes select point values from fixed list of possibles. # # Argument 'c_h' and 'c_p' represent height or pressure values, so # ought to be mutually exclusive -- these control LBVC. # # Argument 'phn' indexes phenomenon types. # # Argument 'mmm' denotes existence (or not) of a cell method of type # 'average' or 'min' or 'max' (values '012' respectively), applying to # the time values -- ultimately, this controls LBTIM. # # Argument 'pse' denotes pseudo-level numbers. # These translate into 'LBUSER5' values. # Get the number of result cubes, defined by the 'longest' arg. def arglen(arg): # Get the 'length' of a control argument. if arg is None: result = 0 elif isinstance(arg, six.string_types): result = len(arg) else: result = 1 return result n_flds = max(arglen(x) for x in (c_t, cft, ctp, c_h, c_p, mmm)) # Make basic anonymous test cubes. ny, nx = 3, 5 data = np.arange(n_flds * ny * nx, dtype=np.float32) data = data.reshape((n_flds, ny, nx)) cubes = [Cube(data[i]) for i in range(n_flds)] # Define test point values for making coordinates. time_unit = 'hours since 1970-01-01' period_unit = 'hours' height_unit = 'm' pressure_unit = 'hPa' time_values = 24.0 * np.arange(10) height_values = 100.0 * np.arange(1, 11) pressure_values = [ 100.0, 150.0, 200.0, 250.0, 300.0, 500.0, 850.0, 1000.0 ] pseudolevel_values = range(1, 11) # A valid value is >= 1. # Test phenomenon details. # NOTE: in order to write/readback as identical, these also contain a # canonical unit and matching STASH attribute. # Those could in principle be looked up, but it's a bit awkward. phenomenon_values = [ ('air_temperature', 'K', 'm01s01i004'), ('x_wind', 'm s-1', 'm01s00i002'), ('y_wind', 'm s-1', 'm01s00i003'), ('specific_humidity', 'kg kg-1', 'm01s00i010'), ] # Test cell-methods. # NOTE: if you add an *interval* to any of these cell-methods, it is # not saved into the PP file (?? or maybe not loaded back again ??). # This could be a PP save/load bug, or maybe just because no bounds ? cell_method_values = [ CellMethod('mean', 'time'), CellMethod('maximum', 'time'), CellMethod('minimum', 'time'), ] # Define helper to decode an argument as a list of test values. def arg_vals(arg, vals): # Decode an argument to a list of 'n_flds' coordinate point values. # (or 'None' where missing) # First get a list of value indices from the argument. # Can be: a single index value; a list of indices; or a string. if (isinstance(arg, Iterable) and not isinstance(arg, six.string_types)): # Can also just pass a simple iterable of values. inds = [int(val) for val in arg] else: n_vals = arglen(arg) if n_vals == 0: inds = [None] * n_flds elif n_vals == 1: inds = [int(arg)] * n_flds else: assert isinstance(arg, six.string_types) inds = [None if char == '-' else int(char) for char in arg] # Convert indices to selected point values. values = [None if ind is None else vals[int(ind)] for ind in inds] return values # Apply phenomenon_values definitions. phenomena = arg_vals(phn, phenomenon_values) for cube, (name, units, stash) in zip(cubes, phenomena): cube.rename(name) # NOTE: in order to get a cube that will write+readback the same, # the units must be the canonical one. cube.units = units # NOTE: in order to get a cube that will write+readback the same, # we must include a STASH attribute. cube.attributes['STASH'] = STASH.from_msi(stash) # Add x and y coords. cs = GeogCS(EARTH_RADIUS) xvals = np.linspace(0.0, 180.0, nx) co_x = DimCoord(np.array(xvals, dtype=np.float32), standard_name='longitude', units='degrees', coord_system=cs) yvals = np.linspace(-45.0, 45.0, ny) co_y = DimCoord(np.array(yvals, dtype=np.float32), standard_name='latitude', units='degrees', coord_system=cs) for cube in cubes: cube.add_dim_coord(co_y, 0) cube.add_dim_coord(co_x, 1) # Add multiple scalar coordinates as defined by the arguments. def arg_coords(arg, name, unit, vals=None): # Decode an argument to a list of scalar coordinates. if vals is None: vals = np.arange(n_flds + 2) # Note allowance vals = arg_vals(arg, vals) coords = [ None if val is None else DimCoord([val], units=unit) for val in vals ] # Apply names separately, as 'pressure' is not a standard name. for coord in coords: if coord: coord.rename(name) # Also fix heights to match what comes from a PP file. if name == 'height': coord.attributes['positive'] = 'up' return coords def add_arg_coords(arg, name, unit, vals=None): # Add scalar coordinates to each cube, for one argument. coords = arg_coords(arg, name, unit, vals) for cube, coord in zip(cubes, coords): if coord: cube.add_aux_coord(coord) add_arg_coords(c_t, 'time', time_unit, time_values) add_arg_coords(cft, 'forecast_reference_time', time_unit) add_arg_coords(ctp, 'forecast_period', period_unit, time_values) add_arg_coords(c_h, 'height', height_unit, height_values) add_arg_coords(c_p, 'pressure', pressure_unit, pressure_values) add_arg_coords(pse, 'pseudo_level', '1', pseudolevel_values) # Add cell methods as required. methods = arg_vals(mmm, cell_method_values) for cube, method in zip(cubes, methods): if method: cube.add_cell_method(method) return cubes