def get_crs_coordinates(dataset: gdal.Dataset, x_idx: float, y_idx: float) -> Coordinate2D: geotransform = dataset.GetGeoTransform() origin_x = geotransform[0] # origin_x/y is the CRS coordinate at the top left corner of the (0,0) pixel origin_y = geotransform[3] dx = geotransform[1] dy = geotransform[5] x = x_idx * dx + origin_x y = y_idx * dy + origin_y return Coordinate2D(x=x, y=y)
def convert_nml_to_project_domains(nml: dict) -> List[dict]: max_dom = nml['share']['max_dom'] # type: int nml = nml['geogrid'] map_proj = nml['map_proj'] # type: str parent_id = nml['parent_id'] # type: List[int] parent_grid_ratio = nml['parent_grid_ratio'] # type: List[int] i_parent_start = nml['i_parent_start'] # type: List[int] j_parent_start = nml['j_parent_start'] # type: List[int] e_we = nml['e_we'] # type: List[int] e_sn = nml['e_sn'] # type: List[int] dx = [nml['dx']] # type: List[float] dy = [nml['dy']] # type: List[float] ref_lon = nml['ref_lon'] # type: float ref_lat = nml['ref_lat'] # type: float truelat1 = nml.get('truelat1') truelat2 = nml.get('truelat2') standlon = nml.get('stand_lon', 0.0) # Check that there are no domains with 2 nests on the same level if parent_id != [1] + list(range(1, max_dom)): raise RuntimeError( 'We only support 1 nested domain per parent domain.') # Check whether ref_x/ref_y is omitted, so that we can assume ref == center. if 'ref_x' in nml or 'ref_y' in nml: raise NotImplementedError('ref_x/ref_y not supported in namelist.') # Create CRS object from projection metadata. if map_proj == 'lat-lon': if standlon != 0.0: raise NotImplementedError( 'Rotated lat-lon projection not supported.') crs = CRS.create_lonlat() elif map_proj == 'lambert': # It doesn't matter what the origin is. See wps_binary_to_gdal.py for details. origin = LonLat(lon=standlon, lat=(truelat1 + truelat2) / 2) crs = CRS.create_lambert(truelat1, truelat2, origin) else: raise NotImplementedError( f'Map projection "{map_proj}"" not currently supported.') ref_xy = crs.to_xy(LonLat(lon=ref_lon, lat=ref_lat)) ref_x = [ref_xy.x] # type: List[float] ref_y = [ref_xy.y] # type: List[float] min_x = [] # type: List[float] min_y = [] # type: List[float] padding_left = [] # type: List[int] padding_bottom = [] # type: List[int] padding_right = [] # type: List[int] padding_top = [] # type: List[int] cols = [i - 1 for i in e_we] rows = [i - 1 for i in e_sn] for idx in range(max_dom - 1): # Calculate horizontal grid spacing for inner domain dx.append(dx[idx] / parent_grid_ratio[idx + 1]) dy.append(dy[idx] / parent_grid_ratio[idx + 1]) if idx == 0: # Calculate min coordinates for outermost domain min_x.append(ref_x[idx] - (dx[idx] * (cols[idx] / 2))) min_y.append(ref_y[idx] - (dy[idx] * (rows[idx] / 2))) # Calculate min coordinates for outer domain min_x.append(min_x[idx] + (dx[idx] * (i_parent_start[idx + 1] - 1))) min_y.append(min_y[idx] + (dy[idx] * (j_parent_start[idx + 1] - 1))) # Calculate center coordinates for inner domain ref_x.append(min_x[idx + 1] + (dx[idx + 1] * (cols[idx + 1] / 2))) ref_y.append(min_y[idx + 1] + (dy[idx + 1] * (rows[idx + 1] / 2))) padding_left.append(i_parent_start[idx + 1] - 1) padding_bottom.append(j_parent_start[idx + 1] - 1) padding_right.append(cols[idx] - padding_left[idx] - cols[idx + 1] // parent_grid_ratio[idx + 1]) padding_top.append(rows[idx] - padding_bottom[idx] - rows[idx + 1] // parent_grid_ratio[idx + 1]) ref_lonlat = crs.to_lonlat(Coordinate2D(x=ref_x[-1], y=ref_y[-1])) first_domain = { 'map_proj': map_proj, 'cell_size': [dx[-1], dy[-1]], 'center_lonlat': [ref_lonlat.lon, ref_lonlat.lat], 'domain_size': [cols[-1], rows[-1]], 'stand_lon': standlon, } if truelat1 is not None: first_domain['truelat1'] = truelat1 if truelat2 is not None: first_domain['truelat2'] = truelat2 domains = [first_domain] for i in range(max_dom - 1): domains.append({ 'parent_cell_size_ratio': parent_grid_ratio[::-1][:-1][i], "padding_left": padding_left[::-1][i], "padding_right": padding_right[::-1][i], "padding_bottom": padding_bottom[::-1][i], "padding_top": padding_top[::-1][i] }) return domains
def fill_domains(self): ''' Updated computed fields in each domain object like cell size. ''' domains = self.data.get('domains') if domains is None: raise RuntimeError('Domains not configured yet') innermost_domain = domains[0] outermost_domain = domains[-1] innermost_domain['padding_left'] = 0 innermost_domain['padding_right'] = 0 innermost_domain['padding_bottom'] = 0 innermost_domain['padding_top'] = 0 outermost_domain['parent_start'] = [1, 1] # compute and adjust domain sizes for idx, domain in enumerate(domains): if idx == 0: continue child_domain = domains[idx - 1] # We need to make sure that the number of columns in the child domain is an integer multiple # of the nest's parent domain. As we calculate the inner most domain before calculating the outermost one, # we need to amend the value for the number of columns or rows for the inner most domain in the case the # dividend obtained by dividing the number of inner domain's columns by the user's inner-to-outer resolution ratio # in the case where is not an integer value. child_domain_size_padded = ( child_domain['domain_size'][0] + child_domain['padding_left'] + child_domain['padding_right'], child_domain['domain_size'][1] + child_domain['padding_bottom'] + child_domain['padding_top'], ) if (child_domain_size_padded[0] % domain['parent_cell_size_ratio']) != 0: new_cols = int( ceil(child_domain_size_padded[0] / domain['parent_cell_size_ratio'])) new_child_domain_padded_x = new_cols * domain[ 'parent_cell_size_ratio'] else: new_child_domain_padded_x = child_domain_size_padded[0] if (child_domain_size_padded[1] % domain['parent_cell_size_ratio']) != 0: new_rows = int( ceil(child_domain_size_padded[1] / domain['parent_cell_size_ratio'])) new_child_domain_padded_y = new_rows * domain[ 'parent_cell_size_ratio'] else: new_child_domain_padded_y = child_domain_size_padded[1] if idx == 1: child_domain['domain_size'] = [ new_child_domain_padded_x, new_child_domain_padded_y ] else: child_domain[ 'padding_right'] += new_child_domain_padded_x - child_domain_size_padded[ 0] child_domain[ 'padding_top'] += new_child_domain_padded_y - child_domain_size_padded[ 1] assert new_child_domain_padded_x % domain[ 'parent_cell_size_ratio'] == 0 assert new_child_domain_padded_y % domain[ 'parent_cell_size_ratio'] == 0 domain['domain_size'] = [ new_child_domain_padded_x // domain['parent_cell_size_ratio'], new_child_domain_padded_y // domain['parent_cell_size_ratio'] ] # compute bounding boxes, cell sizes, center lonlat, parent start for idx, domain in enumerate(domains): size_x, size_y = domain['domain_size'] padded_size_x = size_x + domain['padding_left'] + domain[ 'padding_right'] padded_size_y = size_y + domain['padding_bottom'] + domain[ 'padding_top'] domain['domain_size_padded'] = [padded_size_x, padded_size_y] if idx == 0: center_lon, center_lat = domain['center_lonlat'] center_xy = self.projection.to_xy( LonLat(lon=center_lon, lat=center_lat)) domain['bbox'] = get_bbox_from_grid_spec( center_xy.x, center_xy.y, domain['cell_size'], size_x, size_y) else: child_domain = domains[idx - 1] domain['cell_size'] = [ child_domain['cell_size'][0] * domain['parent_cell_size_ratio'], child_domain['cell_size'][1] * domain['parent_cell_size_ratio'] ] child_center_x, child_center_y = get_bbox_center( child_domain['bbox']) domain['bbox'] = get_parent_bbox_from_child_grid_spec( child_center_x=child_center_x, child_center_y=child_center_y, child_cell_size=child_domain['cell_size'], child_cols=child_domain['domain_size'][0] + child_domain['padding_left'] + child_domain['padding_right'], child_rows=child_domain['domain_size'][1] + child_domain['padding_top'] + child_domain['padding_bottom'], child_parent_res_ratio=domain['parent_cell_size_ratio'], parent_left_padding=domain['padding_left'], parent_right_padding=domain['padding_right'], parent_bottom_padding=domain['padding_bottom'], parent_top_padding=domain['padding_top']) center_x, center_y = get_bbox_center(domain['bbox']) center_lonlat = self.projection.to_lonlat( Coordinate2D(x=center_x, y=center_y)) domain['center_lonlat'] = [ center_lonlat.lon, center_lonlat.lat ] if idx < len(domains) - 1: parent_domain = domains[idx + 1] domain['parent_start'] = [ parent_domain['padding_left'] + 1, parent_domain['padding_bottom'] + 1 ]
def read_wps_binary_index_file(folder: str) -> WPSBinaryIndexMetadata: index_path = os.path.join(folder, 'index') if not os.path.exists(index_path): raise UserError(f'{index_path} is missing, this is not a valid WPS Binary dataset') with open(index_path) as f: index = '\n'.join(line.strip() for line in f.readlines()) parser = ConfigParser() parser.read_string('[root]\n' + index) meta = parser['root'] def clean_str(s: Optional[str]) -> Optional[str]: if s is None: return else: return s.strip('"') m = WPSBinaryIndexMetadata() # encoding m.little_endian = meta.get('endian') == 'little' m.signed = meta.get('signed') == 'yes' m.top_bottom = meta.get('row_order') == 'top_bottom' m.word_size = int(meta['wordsize']) m.scale_factor = float(meta.get('scale_factor', '1')) m.missing_value = float(meta['missing_value']) if 'missing_value' in meta else None # tile dimensions m.tile_x = int(meta['tile_x']) m.tile_y = int(meta['tile_y']) if 'tile_z_start' in meta: m.tile_z_start = int(meta['tile_z_start']) m.tile_z_end = int(meta['tile_z_end']) else: m.tile_z_start = 1 m.tile_z_end = int(meta['tile_z']) m.tile_bdr = int(meta.get('tile_bdr', '0')) # projection / geographic coordinate system m.proj_id = meta['projection'] m.stdlon = float(meta['stdlon']) if 'stdlon' in meta else None m.truelat1 = float(meta['truelat1']) if 'truelat1' in meta else None m.truelat2 = float(meta['truelat2']) if 'truelat2' in meta else None # grid georeferencing m.dx = float(meta['dx']) m.dy = float(meta['dy']) m.known_lonlat = LonLat(lon=float(meta['known_lon']), lat=float(meta['known_lat'])) known_x_idx = float(meta.get('known_x', '1')) known_y_idx = float(meta.get('known_y', '1')) m.known_idx = Coordinate2D(known_x_idx, known_y_idx) # categories m.categorical = meta['type'] == 'categorical' m.category_min = int(meta['category_min']) if 'category_min' in meta else None m.category_max = int(meta['category_max']) if 'category_max' in meta else None # landuse categories m.landuse_scheme = clean_str(meta.get('mminlu')) for field in LANDUSE_FIELDS: setattr(m, field, int(meta[field]) if field in meta else None) # other m.filename_digits = int(meta.get('filename_digits', '5')) m.units = clean_str(meta.get('units')) m.description = clean_str(meta.get('description')) m.validate() return m