def get_area_def(self, dataset_id): """Get the area definition of the band. In general, image data from one window/area is available. For the HRV channel in FES mode, however, data from two windows ('Lower' and 'Upper') are available. Hence, we collect lists of area-extents and corresponding number of image lines/columns. In case of FES HRV data, two area definitions are computed, stacked and squeezed. For other cases, the lists will only have one entry each, from which a single area definition is computed. Note that the AreaDefinition area extents returned by this function for Native data will be slightly different compared to the area extents returned by the SEVIRI HRIT reader. This is due to slightly different pixel size values when calculated using the data available in the files. E.g. for the 3 km grid: ``Native: data15hd['ImageDescription']['ReferenceGridVIS_IR']['ColumnDirGridStep'] == 3000.4031658172607`` ``HRIT: np.deg2rad(2.**16 / pdict['lfac']) * pdict['h'] == 3000.4032785810186`` This results in the Native 3 km full-disk area extents being approx. 20 cm shorter in each direction. The method for calculating the area extents used by the HRIT reader (CFAC/LFAC mechanism) keeps the highest level of numeric precision and is used as reference by EUM. For this reason, the standard area definitions defined in the `areas.yaml` file correspond to the HRIT ones. """ pdict = {} pdict['a'] = self.mda['projection_parameters']['a'] pdict['b'] = self.mda['projection_parameters']['b'] pdict['h'] = self.mda['projection_parameters']['h'] pdict['ssp_lon'] = self.mda['projection_parameters']['ssp_longitude'] area_naming_input_dict = { 'platform_name': 'msg', 'instrument_name': 'seviri', 'resolution': int(dataset_id['resolution']) } area_naming = get_geos_area_naming({ **area_naming_input_dict, **get_service_mode('seviri', pdict['ssp_lon']) }) pdict['a_name'] = area_naming['area_id'] pdict['a_desc'] = area_naming['description'] pdict['p_id'] = "" area_extent = self.get_area_extent(dataset_id) areas = list() for aex, nlines, ncolumns in zip(area_extent['area_extent'], area_extent['nlines'], area_extent['ncolumns']): pdict['nlines'] = nlines pdict['ncols'] = ncolumns areas.append(get_area_definition(pdict, aex)) if len(areas) == 2: area = geometry.StackedAreaDefinition(areas[0], areas[1]) area = area.squeeze() else: area = areas[0] return area
def _construct_area_def(self, dataset_id): """Construct a standardized AreaDefinition based on satellite, instrument, resolution and sub-satellite point. Returns: AreaDefinition: A pyresample AreaDefinition object containing the area definition. """ res = dataset_id['resolution'] area_naming_input_dict = { 'platform_name': 'msg', 'instrument_name': 'seviri', 'resolution': res, } area_naming = get_geos_area_naming({ **area_naming_input_dict, **get_service_mode('seviri', self.ssp_lon) }) # Datasets with a segment size of 3 pixels extend outside the original SEVIRI 3km grid (with 1238 x 1238 # segments a 3 pixels). Hence, we need to use corresponding area defintions in areas.yaml if self.seg_size == 3: area_naming['area_id'] += '_ext' area_naming[ 'description'] += ' (extended outside original 3km grid)' # Construct AreaDefinition from standardized area definition in areas.yaml. stand_area_def = get_area_def(area_naming['area_id']) return stand_area_def
def _get_proj_dict(self, dataset_id): loff = np.float32(self.mda['loff']) nlines = np.int32(self.mda['number_of_lines']) loff = nlines - loff name_dict = get_geos_area_naming({ 'platform_name': self.platform_name, 'instrument_name': SENSOR_NAME, # Partial scans are padded to full disk 'service_name': 'FD', 'service_desc': 'Full Disk', 'resolution': dataset_id['resolution'] }) return { 'a': EQUATOR_RADIUS, 'b': POLE_RADIUS, 'ssp_lon': float(self.prologue['SubSatLongitude']), 'h': ALTITUDE, 'proj': 'geos', 'units': 'm', 'a_name': name_dict['area_id'], 'a_desc': name_dict['description'], 'p_id': '', 'nlines': nlines, 'ncols': np.int32(self.mda['number_of_columns']), 'cfac': np.int32(self.mda['cfac']), 'lfac': np.int32(self.mda['lfac']), 'coff': np.float32(self.mda['coff']), 'loff': loff, 'scandir': 'N2S' }
def _construct_area_def(self, dataset_id): """Construct the area definition. Returns: AreaDefinition: A pyresample AreaDefinition object containing the area definition. """ res = dataset_id.resolution area_naming_input_dict = {'platform_name': 'mtg', 'instrument_name': 'fci', 'resolution': res, } area_naming = get_geos_area_naming({**area_naming_input_dict, **get_service_mode('fci', self.ssp_lon)}) # Construct area definition from standardized area definition. stand_area_def = get_area_def(area_naming['area_id']) if (stand_area_def.x_size != self.ncols) | (stand_area_def.y_size != self.nlines): raise NotImplementedError('Unrecognised AreaDefinition.') mod_area_extent = self._modify_area_extent(stand_area_def.area_extent) area_def = geometry.AreaDefinition( stand_area_def.area_id, stand_area_def.description, "", stand_area_def.proj_dict, stand_area_def.x_size, stand_area_def.y_size, mod_area_extent) return area_def
def _get_proj_area(self, dataset_id): """Extract projection and area information.""" # Read the projection data from the mtg_geos_projection variable a = float(self._projection.attrs['semi_major_axis']) h = float(self._projection.attrs['perspective_point_height']) # Some L2PF test data files have a typo in the keyname for the inverse flattening parameter. Use a default value # as fallback until all L2PF test files are correctly formatted. rf = float(self._projection.attrs.get('inverse_flattening', 298.257223563)) res = dataset_id.resolution area_naming_input_dict = {'platform_name': 'mtg', 'instrument_name': 'fci', 'resolution': res, } area_naming = get_geos_area_naming({**area_naming_input_dict, **get_service_mode('fci', self.ssp_lon)}) proj_dict = {'a': a, 'lon_0': self.ssp_lon, 'h': h, "rf": rf, 'proj': 'geos', 'units': 'm', "sweep": 'y'} return area_naming, proj_dict
def test_get_geos_area_naming(self): """Test the geos area naming function.""" input_dict = {'platform_name': 'testplatform', 'instrument_name': 'testinstrument', 'resolution': 1000, 'service_name': 'testservicename', 'service_desc': 'testdesc'} output_dict = get_geos_area_naming(input_dict) self.assertEqual(output_dict['area_id'], 'testplatform_testinstrument_testservicename_1km') self.assertEqual(output_dict['description'], 'TESTPLATFORM TESTINSTRUMENT testdesc area definition' ' with 1 km resolution')
def get_area_def(self, dataset_id): """Get the area def. Note that the AreaDefinition area extents returned by this function for NetCDF data will be slightly different compared to the area extents returned by the SEVIRI HRIT reader. This is due to slightly different pixel size values when calculated using the data available in the files. E.g. for the 3 km grid: ``NetCDF: self.nc.attrs['vis_ir_column_dir_grid_step'] == 3000.4031658172607`` ``HRIT: np.deg2rad(2.**16 / pdict['lfac']) * pdict['h'] == 3000.4032785810186`` This results in the Native 3 km full-disk area extents being approx. 20 cm shorter in each direction. The method for calculating the area extents used by the HRIT reader (CFAC/LFAC mechanism) keeps the highest level of numeric precision and is used as reference by EUM. For this reason, the standard area definitions defined in the `areas.yaml` file correspond to the HRIT ones. """ pdict = {} pdict['a'] = self.mda['projection_parameters']['a'] pdict['b'] = self.mda['projection_parameters']['b'] pdict['h'] = self.mda['projection_parameters']['h'] pdict['ssp_lon'] = self.mda['projection_parameters']['ssp_longitude'] area_naming_input_dict = { 'platform_name': 'msg', 'instrument_name': 'seviri', 'resolution': int(dataset_id['resolution']) } area_naming = get_geos_area_naming({ **area_naming_input_dict, **get_service_mode('seviri', pdict['ssp_lon']) }) if dataset_id['name'] == 'HRV': pdict['nlines'] = self.mda['hrv_number_of_lines'] pdict['ncols'] = self.mda['hrv_number_of_columns'] pdict['a_name'] = area_naming['area_id'] pdict['a_desc'] = area_naming['description'] pdict['p_id'] = "" else: pdict['nlines'] = self.mda['number_of_lines'] pdict['ncols'] = self.mda['number_of_columns'] pdict['a_name'] = area_naming['area_id'] pdict['a_desc'] = area_naming['description'] pdict['p_id'] = "" area = get_area_definition(pdict, self.get_area_extent(dataset_id)) return area
def get_area_def(self, key): """Calculate on-fly area definition for a dataset in geos-projection.""" # assumption: channels with same resolution should have same area # cache results to improve performance if key['resolution'] in self._cache: return self._cache[key['resolution']] a = float(self["data/mtg_geos_projection/attr/semi_major_axis"]) h = float( self["data/mtg_geos_projection/attr/perspective_point_height"]) rf = float(self["data/mtg_geos_projection/attr/inverse_flattening"]) lon_0 = float(self[ "data/mtg_geos_projection/attr/longitude_of_projection_origin"]) sweep = str(self["data/mtg_geos_projection"].sweep_angle_axis) area_extent, nlines, ncols = self.calc_area_extent(key) logger.debug('Calculated area extent: {}'.format(''.join( str(area_extent)))) # use a (semi-major axis) and rf (reverse flattening) to define ellipsoid as recommended by EUM (see PUG) proj_dict = { 'a': a, 'lon_0': lon_0, 'h': h, "rf": rf, 'proj': 'geos', 'units': 'm', "sweep": sweep } area_naming_input_dict = { 'platform_name': 'mtg', 'instrument_name': 'fci', 'resolution': int(key['resolution']) } area_naming = get_geos_area_naming({ **area_naming_input_dict, **get_service_mode('fci', lon_0) }) area = geometry.AreaDefinition(area_naming['area_id'], area_naming['description'], "", proj_dict, ncols, nlines, area_extent) self._cache[key['resolution']] = area return area
def get_area_def(self, dsid): """Get the area definition of the band.""" # Common parameters for both HRV and other channels nlines = int(self.mda['number_of_lines']) loff = np.float32(self.mda['loff']) pdict = {} pdict['cfac'] = np.int32(self.mda['cfac']) pdict['lfac'] = np.int32(self.mda['lfac']) pdict['coff'] = np.float32(self.mda['coff']) pdict['a'] = self.mda['projection_parameters']['a'] pdict['b'] = self.mda['projection_parameters']['b'] pdict['h'] = self.mda['projection_parameters']['h'] pdict['ssp_lon'] = self.mda['projection_parameters']['SSP_longitude'] pdict['nlines'] = nlines pdict['ncols'] = int(self.mda['number_of_columns']) if (self.prologue['ImageDescription']['Level15ImageProduction'] ['ImageProcDirection'] == 0): pdict['scandir'] = 'N2S' else: pdict['scandir'] = 'S2N' area_naming_input_dict = { 'platform_name': 'msg', 'instrument_name': 'seviri', 'resolution': int(dsid['resolution']) } area_naming = get_geos_area_naming({ **area_naming_input_dict, **get_service_mode('seviri', pdict['ssp_lon']) }) # Compute area definition for non-HRV channels: if dsid['name'] != 'HRV': pdict['loff'] = loff - nlines aex = self._get_area_extent(pdict) pdict['a_name'] = area_naming['area_id'] pdict['a_desc'] = area_naming['description'] pdict['p_id'] = "" area = get_area_definition(pdict, aex) self.area = area return self.area segment_number = self.mda['segment_sequence_number'] current_first_line = ( (segment_number - self.mda['planned_start_segment_number']) * pdict['nlines']) # Or, if we are processing HRV: pdict['a_name'] = area_naming['area_id'] pdict['p_id'] = "" bounds = self.epilogue['ImageProductionStats'][ 'ActualL15CoverageHRV'].copy() if self.fill_hrv: bounds['UpperEastColumnActual'] = 1 bounds['UpperWestColumnActual'] = HRV_NUM_COLUMNS bounds['LowerEastColumnActual'] = 1 bounds['LowerWestColumnActual'] = HRV_NUM_COLUMNS pdict['ncols'] = HRV_NUM_COLUMNS upper_south_line = bounds[ 'LowerNorthLineActual'] - current_first_line - 1 upper_south_line = min(max(upper_south_line, 0), pdict['nlines']) lower_coff = (5566 - bounds['LowerEastColumnActual'] + 1) upper_coff = (5566 - bounds['UpperEastColumnActual'] + 1) # First we look at the lower window pdict['nlines'] = upper_south_line pdict['loff'] = loff - upper_south_line pdict['coff'] = lower_coff pdict['a_desc'] = area_naming['description'] lower_area_extent = self._get_area_extent(pdict) lower_area = get_area_definition(pdict, lower_area_extent) # Now the upper window pdict['nlines'] = nlines - upper_south_line pdict['loff'] = loff - pdict['nlines'] - upper_south_line pdict['coff'] = upper_coff pdict['a_desc'] = area_naming['description'] upper_area_extent = self._get_area_extent(pdict) upper_area = get_area_definition(pdict, upper_area_extent) area = geometry.StackedAreaDefinition(lower_area, upper_area) self.area = area.squeeze() return self.area
def _get_proj_area(self, gid): """Compute the dictionary with the projection and area definition from a GRIB message. Args: gid: The ID of the GRIB message. Returns: tuple: A tuple of two dictionaries for the projection and the area definition. pdict: a: Earth major axis [m] b: Earth minor axis [m] h: Height over surface [m] ssp_lon: longitude of subsatellite point [deg] nlines: number of lines ncols: number of columns a_name: name of the area a_desc: description of the area p_id: id of the projection area_dict: center_point: coordinate of the center point north: coodinate of the north limit east: coodinate of the east limit west: coodinate of the west limit south: coodinate of the south limit """ # Get name of area definition area_naming_input_dict = { 'platform_name': 'msg', 'instrument_name': 'seviri', 'resolution': self._res, } area_naming = get_geos_area_naming({ **area_naming_input_dict, **get_service_mode('seviri', self._ssp_lon) }) # Read all projection and area parameters from the message earth_major_axis_in_meters = self._get_from_msg( gid, 'earthMajorAxis') * 1000.0 # [m] earth_minor_axis_in_meters = self._get_from_msg( gid, 'earthMinorAxis') * 1000.0 # [m] earth_major_axis_in_meters = self._scale_earth_axis( earth_major_axis_in_meters) earth_minor_axis_in_meters = self._scale_earth_axis( earth_minor_axis_in_meters) nr_in_radius_of_earth = self._get_from_msg(gid, 'NrInRadiusOfEarth') xp_in_grid_lengths = self._get_from_msg(gid, 'XpInGridLengths') h_in_meters = earth_major_axis_in_meters * (nr_in_radius_of_earth - 1.0 ) # [m] # Create the dictionary with the projection data pdict = { 'a': earth_major_axis_in_meters, 'b': earth_minor_axis_in_meters, 'h': h_in_meters, 'ssp_lon': self._ssp_lon, 'nlines': self._ncols, 'ncols': self._nrows, 'a_name': area_naming['area_id'], 'a_desc': area_naming['description'], 'p_id': "", } # Compute the dictionary with the area extension area_dict = { 'center_point': xp_in_grid_lengths, 'north': self._nrows, 'east': 1, 'west': self._ncols, 'south': 1, } return pdict, area_dict