smashbox.tools.geo_toolbox
1import numpy as np 2from scipy.ndimage import zoom 3import rasterio 4 5 6# Convert coordinates to mesh matrix row-col (from smash) 7def xy_to_rowcol(x, y, xmin, ymax, xres, yres): 8 row = int((ymax - y) / yres) 9 col = int((x - xmin) / xres) 10 return row, col 11 12 13# Convert mesh matrix row-col to geographic coordinates (from smash) 14def rowcol_to_xy(row, col, xmin, ymax, xres, yres): 15 x = int(col * xres + xmin) 16 y = int(ymax - row * yres) 17 return x, y 18 19 20def get_bbox_from_smash_mesh(mesh): 21 """ 22 Description 23 ----------- 24 Compute the bbox from a Smash mesh dictionary 25 Parameters 26 ---------- 27 mesh: dict 28 dict of smash mesh 29 return 30 ------ 31 dict() 32 the bounding box of the smash mesh 33 """ 34 35 if "xres" in mesh and "yres" in mesh: 36 dx = mesh["xres"] 37 dy = mesh["yres"] 38 else: 39 dx = np.mean(mesh["dx"]) 40 dy = np.mean(mesh["dy"]) 41 42 if "ncol" in mesh: 43 ncol = mesh["ncol"] 44 nrow = mesh["nrow"] 45 else: 46 nrow = mesh["active_cell"].shape[0] 47 ncol = mesh["active_cell"].shape[1] 48 49 left = mesh["xmin"] 50 right = mesh["xmin"] + ncol * dx 51 bottom = mesh["ymax"] - nrow * dy 52 top = mesh["ymax"] 53 bbox = {"left": left, "bottom": bottom, "right": right, "top": top} 54 55 return bbox 56 57 58def get_bbox_from_ascii_data(ascii_data): 59 """ 60 61 Description 62 ----------- 63 64 Compute the boundingbox from ascii-data stored in a dictionnary (must contain the header) 65 66 Parameters 67 ---------- 68 69 ascii_data: dict() 70 Un dictionnaire contenant un format ascii: {ascii_data,xllcorner,yllcorner,ncol,nrows,cellsize}, la clé ascii_data contient un sous dictionnaire contenant des clés associés a des sources de données {clé:numpy_array} 71 72 return 73 ------ 74 75 dict() 76 Un dictionnaire contenant la boundingbox (coordonnées): {left, bottom, right, top} 77 78 """ 79 ascii_data_l = {} 80 for key, value in ascii_data.items(): 81 ascii_data_l.update({key.lower(): value}) 82 83 bbox = { 84 "left": ascii_data_l["xllcorner"], 85 "bottom": ascii_data_l["yllcorner"], 86 "right": ascii_data_l["xllcorner"] 87 + ascii_data_l["ncols"] * ascii_data_l["cellsize"], 88 "top": ascii_data_l["yllcorner"] 89 + ascii_data_l["nrows"] * ascii_data_l["cellsize"], 90 } 91 92 return bbox 93 94 95def check_bbox_consistency(bbox_model_active_cell, bbox_param): 96 97 if bbox_model_active_cell["left"] < bbox_param["left"]: 98 print( 99 f"Warning: Model domain is larger than the domain of the parameter. {bbox_model_active_cell['left']}<{bbox_param['left']} (bbox model left < bbox param left). Expect lacuna (-99.) in model parameters" 100 ) 101 102 if bbox_model_active_cell["right"] > bbox_param["right"]: 103 print( 104 f"Warning: Model domain is larger than the domain of the parameter. {bbox_model_active_cell['right']}>{bbox_param['right']} (bbox model left < bbox param left). Expect lacuna (-99.) in model parameters" 105 ) 106 107 if bbox_model_active_cell["bottom"] < bbox_param["bottom"]: 108 print( 109 f"Warning: Model domain is larger than the domain of the parameter. {bbox_model_active_cell['bottom']}<{bbox_param['bottom']} (bbox model left < bbox param left). Expect lacuna (-99.) in model parameters" 110 ) 111 112 if bbox_model_active_cell["top"] < bbox_param["top"]: 113 print( 114 f"Warning: Model domain is larger than the domain of the parameter. {bbox_model_active_cell['top']}>{bbox_param['top']} (bbox model left < bbox param left). Expect lacuna (-99.) in model parameters" 115 ) 116 117 118def intersection_bbox(bbox1, bbox2): 119 """ 120 121 Description 122 ----------- 123 124 Function which compute the bounding boxes intersection of 2 input bbox. It return the working bbox 125 126 Parameters 127 ---------- 128 129 bbox1: dict() 130 containing the first bbox informations 131 bbox2 : dict() 132 containing the second bbox informations 133 134 returns 135 ---------- 136 137 dict() 138 containing the bbox union 139 140 Examples 141 ---------- 142 143 dataset=gdal_raster_open(filename) 144 possible_bbox=intersection_bbox(bbox,bbox_dataset) 145 146 """ 147 left = max(bbox1["left"], bbox2["left"]) 148 bottom = max(bbox1["bottom"], bbox2["bottom"]) 149 right = min(bbox1["right"], bbox2["right"]) 150 top = min(bbox1["top"], bbox2["top"]) 151 if (left < right) and (bottom < top): 152 bbox_intersection = {"left": left, "bottom": bottom, "right": right, "top": top} 153 return bbox_intersection 154 else: 155 print("Impossible bounding boxes intersection") 156 return {"left": 0, "bottom": 0, "right": 0, "top": 0} 157 158 159def get_window_from_bbox(mesh, bbox): 160 """ 161 Function to get the mesh window from a defined bbox 162 163 Parameters 164 ---------- 165 dataset: gdal object 166 bbox : dict containing the bbox 167 ---------- 168 returns 169 dic containing the computed windows 170 171 Examples 172 ---------- 173 dataset=gdal_raster_open(filename) 174 bbox_dataset=get_bbox(dataset) 175 window=get_window_from_bbox(dataset,bbox_dataset) 176 177 """ 178 179 if "xres" in mesh and "yres" in mesh: 180 dx = mesh["xres"] 181 dy = mesh["yres"] 182 else: 183 dx = np.mean(mesh["dx"]) 184 dy = np.mean(mesh["dy"]) 185 186 col_off = (bbox["left"] - mesh["xmin"]) / dx 187 row_off = (mesh["ymax"] - bbox["top"]) / dy 188 ncols = (bbox["right"] - bbox["left"]) / dx 189 nrows = (bbox["top"] - bbox["bottom"]) / dy 190 191 if (col_off < 0) or (row_off < 0): 192 raise Exception( 193 "The requested bounding box exceeds the limits of the raster domain." 194 ) 195 196 window = { 197 "row_off": int(row_off), 198 "col_off": int(col_off), 199 "nrows": int(nrows), 200 "ncols": int(ncols), 201 } 202 203 return window 204 205 206def get_cropped_window_from_bbox_intersection(bbox_intersection, bbox_origin, dx, dy): 207 """ 208 209 Description 210 ----------- 211 212 Function to compute the domain to crop between a bbox intersection (included into bbox_origin) and the origin bbox. This function return a window such as the domain with bbox_intersection can be cropped using the retruned window according the bbox_origin 213 214 Parameters 215 ---------- 216 217 bbox_intersection: dict 218 A bbox that intersect bbox_origin 219 220 bbox_origin: dict 221 a bbox from which we want to extract data 222 223 dx: float 224 size of the grid in the x direction 225 226 dy: float 227 size of the grid in the y direction 228 229 Return 230 ------ 231 232 dict() 233 a window dictionnary containing information to crop a matrix: {row_off, col_off, nrows, ncols} 234 235 236 """ 237 if ( 238 (bbox_intersection["left"] < bbox_origin["left"]) 239 or (bbox_intersection["bottom"] < bbox_origin["bottom"]) 240 or (bbox_intersection["right"] > bbox_origin["right"]) 241 or (bbox_intersection["top"] > bbox_origin["top"]) 242 ): 243 print("The domain of bbox_intersection is not included in the domain of bbox_out") 244 window = {"row_off": 0, "col_off": 0, "nrows": 0, "ncols": 0} 245 return window 246 247 col_off = (bbox_intersection["left"] - bbox_origin["left"]) / dx 248 row_off = (bbox_origin["top"] - bbox_intersection["top"]) / dy 249 250 ncols = (bbox_intersection["right"] - bbox_intersection["left"]) / dx 251 nrows = (bbox_intersection["top"] - bbox_intersection["bottom"]) / dy 252 253 window = { 254 "row_off": int(row_off), 255 "col_off": int(col_off), 256 "nrows": int(nrows), 257 "ncols": int(ncols), 258 } 259 260 return window 261 262 263def write_array_to_geotiff(filename, array, xmin, ymax, xres, yres): 264 265 metadata = { 266 "driver": "GTiff", 267 "dtype": "float64", 268 "nodata": None, 269 "width": array.shape[1], 270 "height": array.shape[0], 271 "count": 1, 272 "crs": None, 273 "transform": rasterio.Affine(xres, 0.0, xmin, 0.0, -yres, ymax), 274 } 275 276 rasterio_write_tiff(filename=filename, matrix=array, metadata=metadata) 277 278 279def rasterio_write_tiff(filename="test.tif", matrix=np.zeros(10), metadata={}): 280 281 with rasterio.Env(): 282 with rasterio.open(filename, "w", compress="lzw", **metadata) as dst: 283 dst.write(matrix, 1) 284 285 286def crop_array( 287 array, 288 bbox_in, 289 res_in, 290 bbox_out, 291 res_out, 292 order=0, 293 cval=-99.0, 294 grid_mode=True, 295): 296 """ 297 298 Description 299 -------------- 300 301 Crop a part of a numpy array with an input bbox and resolution to a new bbox with a new resolution 302 303 Parameters 304 ---------- 305 306 array : numpy.array() 307 Input gridded numpy array shape=(n,m) 308 309 bbox_in : dict() 310 bounding box of the input array. Dictionnary {"left":,"top":,"right":,"bottom":} 311 312 res_in : dict() 313 resolution of the input array in x and y direction. Disctionnary {"dx":, "dy":} 314 315 bbox_out : dict() 316 bounding box of the output array. Dictionnary {"left":,"top":,"right":,"bottom":} 317 318 res_out : dict() 319 resolution of the output array in x and y direction. Disctionnary {"dx":, "dy":} 320 321 order : int() 322 order of the resampling cubic interpolation 323 324 cval : float() | np.nan 325 fill value for the extended boundaries 326 327 grid_mode : bool() 328 True | False. if True coordinate start from the edge of the cell. If False coordinate starts from the center of the cell. 329 330 Return 331 ------ 332 333 numpy.array() 334 Cropped and resampled array according bbox_out and res_out 335 336 """ 337 338 # intersection bbox 339 bbox_intersection = intersection_bbox(bbox_in, bbox_out) 340 341 # ---------------------- fait une découpe grossière du domaine ------- 342 343 # 1- crop array on bbox_intersection+-res_in at res in: shrink the domain, speed up futur resampling on large domain ? 344 if res_in["dx"] >= res_out["dx"] and res_in["dy"] >= res_out["dy"]: 345 res_shrinked = {"dx": res_in["dx"], "dy": res_in["dy"]} 346 elif res_in["dx"] < res_out["dx"] and res_in["dy"] < res_out["dy"]: 347 res_shrinked = {"dx": res_out["dy"], "dy": res_out["dy"]} 348 elif res_in["dx"] < res_out["dx"] and res_in["dy"] >= res_out["dy"]: 349 res_shrinked = {"dx": res_out["dx"], "dy": res_in["dy"]} 350 elif res_in["dx"] >= res_out["dx"] and res_in["dy"] < res_out["dy"]: 351 res_shrinked = {"dx": res_in["dx"], "dy": res_out["dy"]} 352 353 bbox_in_shrinked = { 354 "left": bbox_in["left"] 355 + int(max(bbox_intersection["left"] - bbox_in["left"], 0) / res_shrinked["dx"]) 356 * res_shrinked["dx"], 357 "right": bbox_in["right"] 358 - int(max(bbox_in["right"] - bbox_intersection["right"], 0) / res_shrinked["dx"]) 359 * res_shrinked["dx"], 360 "bottom": bbox_in["bottom"] 361 + int( 362 max(bbox_intersection["bottom"] - bbox_in["bottom"], 0) / res_shrinked["dy"] 363 ) 364 * res_shrinked["dy"], 365 "top": bbox_in["top"] 366 - int(max(bbox_in["top"] - bbox_intersection["top"], 0) / res_shrinked["dy"]) 367 * res_shrinked["dy"], 368 } 369 bbox_intersection_shrinked = intersection_bbox(bbox_in, bbox_in_shrinked) 370 371 windows_wrap = get_window_from_bbox( 372 mesh={ 373 "xmin": bbox_in["left"], 374 "ymax": bbox_in["top"], 375 "xres": res_shrinked["dx"], 376 "yres": res_shrinked["dy"], 377 }, 378 bbox=bbox_intersection_shrinked, 379 ) 380 381 # Erase input array and bbox_in 382 array = array[ 383 windows_wrap["row_off"] : windows_wrap["row_off"] + windows_wrap["nrows"], 384 windows_wrap["col_off"] : windows_wrap["col_off"] + windows_wrap["ncols"], 385 ] 386 387 bbox_in = bbox_intersection_shrinked 388 389 # --------------------------------------------------------------------------------------- 390 391 # 2- resample the array to res_out 392 resampled_array = resample_array( 393 array, 394 res_in=res_in, 395 res_out=res_out, 396 order=order, 397 cval=cval, 398 grid_mode=grid_mode, 399 ) 400 401 # 3- crop the array on the intersection of bbox_in and bbox_out 402 # window of bbox_intersection in the domain of bbox_in (bbox_prcp, matrix to read) 403 window_intersection = get_cropped_window_from_bbox_intersection( 404 bbox_intersection, bbox_in, res_out["dx"], res_out["dy"] 405 ) 406 407 # reading the part of the matrix (array_in) 408 cropped_array = resampled_array[ 409 window_intersection["row_off"] : window_intersection["row_off"] 410 + window_intersection["nrows"], 411 window_intersection["col_off"] : window_intersection["col_off"] 412 + window_intersection["ncols"], 413 ] 414 415 # allocate out array: shape of bbox_out 416 array_out = ( 417 np.zeros( 418 shape=( 419 int((bbox_out["top"] - bbox_out["bottom"]) / res_out["dx"]), 420 int((bbox_out["right"] - bbox_out["left"]) / res_out["dy"]), 421 ) 422 ) 423 - 99.0 424 ) 425 426 # window of bbox_intersection in the domain of bbox_smash 427 window_intersection_out = get_cropped_window_from_bbox_intersection( 428 bbox_intersection, bbox_out, res_out["dx"], res_out["dy"] 429 ) 430 431 # copy crop_array (input matrix cropped) in array_out 432 array_out[ 433 window_intersection_out["row_off"] : window_intersection_out["row_off"] 434 + window_intersection_out["nrows"], 435 window_intersection_out["col_off"] : window_intersection_out["col_off"] 436 + window_intersection_out["ncols"], 437 ] = cropped_array 438 439 return array_out 440 441 442def resample_array( 443 array, 444 res_in={"dx": 1, "dy": 1}, 445 res_out={"dx": 1, "dy": 1}, 446 order=0, 447 cval=-99.0, 448 grid_mode=True, 449): 450 """ 451 452 Parameters 453 ---------- 454 455 array: numpy.array() 456 Input gridded numpy array shape=(n,m) 457 458 res_in: dict() 459 resolution of the input array in x and y direction. Disctionnary {"dx":, "dy":} 460 461 res_out: dict() 462 resolution of the output array in x and y direction. Disctionnary {"dx":, "dy":} 463 464 order: int() 465 order of the resampling cubic interpolation 466 467 cval: float() | np.nan 468 fill value for the extended boundaries 469 470 grid_mode: bool() 471 True | False. if True coordinate start from the edge of the cell. If False coordinate starts from the center of the cell. 472 473 Return 474 ------ 475 476 numpy.array() 477 Cropped and resampled array according bbox_out and res_out 478 479 """ 480 481 ratio_x = res_in["dx"] / res_out["dx"] 482 ratio_y = res_in["dy"] / res_out["dy"] 483 resampled_array = zoom( 484 array, 485 (ratio_y, ratio_x), 486 order=order, 487 mode="grid-constant", 488 cval=-99.0, 489 grid_mode=True, 490 ) 491 492 return resampled_array 493 494 495# def read_geotiff_to_ascii(path=""): 496 497# if not os.path.exists(path): 498# raise ValueError(f"{path} does not exist.") 499 500# with rasterio.open(path) as ds: 501# transform = ds.get_transform() 502# xmin = transform[0] 503# ymax = transform[3] 504# xres = transform[1] 505# yres = -transform[5] 506 507# ascii_data = { 508# "ncols": ds.width, 509# "nrows": ds.height, 510# "cellsize": xres, 511# "xllcorner": xmin, 512# "yllcorner": ymax - ds.height * yres, 513# "nodata_value": ds.nodata, 514# "data": ds.read(indexes=1), 515# } 516 517# return ascii_data 518 519 520# def write_smashparam_to_geotiff(model, path): 521 522# if not os.path.exists(path): 523# os.mkdir(path) 524 525# list_param = list(model.rr_parameters.keys) 526 527# for param in list_param: 528 529# array = model.rr_parameters.values[:, :, list_param.index(param)] 530 531# write_array_to_geotiff( 532# os.path.join(path, param + ".tif"), 533# array, 534# model.mesh.xmin, 535# model.mesh.ymax, 536# model.mesh.xres, 537# model.mesh.yres, 538# ) 539 540 541# # format standart smashop ? 542# # faire une fonction qui extrait des params depuis smash vers un dict_ascii_format ? 543# def load_param_from_tiffformat( 544# model=None, path_to_parameters="", bounding_condition=False 545# ): 546 547# # check metadata first 548 549# list_param = model.rr_parameters.keys 550 551# mesh_out = object_handler.read_object_as_dict(model.mesh) 552 553# bbox_out = get_bbox_from_smash_mesh(mesh_out) 554# res_out = {"dx": np.mean(mesh_out["dx"]), "dy": np.mean(mesh_out["dy"])} 555 556# for param in list_param: 557 558# if os.path.exists(os.path.join(path_to_parameters, param + ".tif")): 559 560# ascii_data = read_geotiff_to_ascii( 561# os.path.join(path_to_parameters, param + ".tif") 562# ) 563 564# bbox_in = get_bbox_from_ascii_data(ascii_data) 565 566# check_bbox_consistency(bbox_out, bbox_in) 567 568# res_in = {"dx": ascii_data["cellsize"], "dy": ascii_data["cellsize"]} 569 570# print(f"</> In read_param_from_asciiformat, reading param {param}") 571 572# cropped_param = crop_array( 573# ascii_data["data"], 574# bbox_in, 575# res_in, 576# bbox_out, 577# res_out, 578# resampling_method="scipy-zoom", 579# order=0, 580# cval=-99.0, 581# grid_mode=True, 582# ) 583 584# pos = np.where(list_param == param)[0][0] 585# model.rr_parameters.values[:, :, pos] = cropped_param 586 587# print("</> Removing values lower than 0") 588# model.rr_parameters.values[:, :, pos] = np.where( 589# model.rr_parameters.values[:, :, pos] < 0, 590# 0, 591# model.rr_parameters.values[:, :, pos], 592# ) 593 594# else: 595 596# print( 597# f"</> Error: in load_param_from_tiffformat, missing parameter {param} in {path_to_parameters}" 598# ) 599 600 601# # format standart smashop ? 602# # faire une fonction qui extrait des params depuis smash vers un dict_ascii_format ? 603# def load_param_from_asciiformat(model, dict_ascii_parameters, bounding_condition=False): 604 605# list_param = model.rr_parameters.keys 606 607# mesh_out = object_handler.read_object_as_dict(model.mesh) 608 609# bbox_in = get_bbox_from_ascii_data(dict_ascii_parameters) 610# res_in = { 611# "dx": dict_ascii_parameters["cellsize"], 612# "dy": dict_ascii_parameters["cellsize"], 613# } 614 615# bbox_out = get_bbox_from_smash_mesh(mesh_out) 616# res_out = {"dx": np.mean(mesh_out["dx"]), "dy": np.mean(mesh_out["dy"])} 617 618# check_bbox_consistency(bbox_out, bbox_in) 619 620# for param in list_param: 621 622# if param in dict_ascii_parameters["ascii_data"].keys(): 623 624# print(f"</> In read_param_from_asciiformat, reading param {param}") 625 626# cropped_param = crop_array( 627# param, 628# bbox_in, 629# res_in, 630# bbox_out, 631# res_out, 632# resampling_method="scipy-zoom", 633# order=0, 634# cval=-99.0, 635# grid_mode=True, 636# ) 637 638# pos = np.where(list_param == param)[0][0] 639# model.rr_parameters.values[:, :, pos] = cropped_param 640# else: 641# print( 642# f"</> In read_param_from_asciiformat, skipping missing parameter {param}" 643# ) 644 645 646# def transfert_params_to_model( 647# from_mesh=dict(), with_param=(dict | object), to_model=None 648# ): 649 650# if isinstance(with_param, dict): 651# pass 652# else: 653# with_param = object_handler.read_object_as_dict(with_param) 654 655# structure = to_model.setup.structure 656# structure_parameters = smash._constant.STRUCTURE_RR_PARAMETERS.copy() 657# # copy() obligatoire car la liste contenu dans la copie du dictionnaire n'est pas une copy mais un pointeur ... 658# parameters_list = structure_parameters[structure].copy() 659 660# mesh_out = object_handler.read_object_as_dict(to_model.mesh) 661 662# bbox_in = get_bbox_from_smash_mesh(from_mesh) 663 664# if "xres" in from_mesh and "yres" in from_mesh: 665# dx = from_mesh["xres"] 666# dy = from_mesh["yres"] 667# else: 668# dx = np.mean(from_mesh["dx"]) 669# dy = np.mean(from_mesh["dy"]) 670 671# res_in = { 672# "dx": dx, 673# "dy": dy, 674# } 675 676# bbox_out = get_bbox_from_smash_mesh(mesh_out) 677 678# if "xres" in mesh_out and "yres" in mesh_out: 679# dx = mesh_out["xres"] 680# dy = mesh_out["yres"] 681# else: 682# dx = np.mean(mesh_out["dx"]) 683# dy = np.mean(mesh_out["dy"]) 684 685# res_out = { 686# "dx": dx, 687# "dy": dy, 688# } 689 690# for i in range(len(parameters_list)): 691 692# if "values" in with_param: 693# param = with_param["values"][:, :, i] 694# pos = i 695# else: 696# param = with_param[parameters_list[i]] 697# pos = np.where(to_model.rr_parameters.keys == parameters_list[i])[0][0] 698 699# cropped_param = crop_array( 700# param, 701# bbox_in, 702# res_in, 703# bbox_out, 704# res_out, 705# resampling_method="scipy-zoom", 706# order=0, 707# cval=-99.0, 708# grid_mode=True, 709# ) 710 711# to_model.rr_parameters.values[:, :, pos] = cropped_param 712 713 714# def resample_array( 715# array, 716# res_in={"dx": 1, "dy": 1}, 717# res_out={"dx": 1, "dy": 1}, 718# # resampling_method="scipy-zoom", 719# order=3, 720# cval=-99.0, 721# grid_mode=True, 722# ): 723# """ 724 725# Description 726# ----------- 727 728# Resample an array with input resolution to the output resolution. It use zoom function form scipy package. 729 730# Parameters 731# ---------- 732 733# array: numpy.array() 734# Input gridded numpy array shape=(n,m) 735 736# res_in: dict() 737# resolution of the input array in x and y direction. Disctionnary {"dx":, "dy":} 738 739# res_out: dict() 740# resolution of the output array in x and y direction. Disctionnary {"dx":, "dy":} 741 742# resampling_method: str() 743# scipy-zoom | numpy ; scipy-zoom use the zoom function from scipy (see function resample_array_scipy_zoom for other input arg). numpy only resample using basic function np.repeat ans basic calculation (not suitable for every case). 744 745# Return 746# ------ 747 748# numpy.array() 749# Resampled array according res_out 750 751# """ 752# if resampling_method == "numpy": 753# resampled_array = resample_array_numpy(array, res_in=res_in, res_out=res_out) 754 755# if resampled_array is None: 756# print("</>Fallback to scipy-zoom resampling (scipy.ndimage.zoom method)") 757# resampling_method = "scipy-zoom" 758 759# if resampling_method == "scipy-zoom": 760# resampled_array = resample_array_scipy_zoom( 761# array, res_in, res_out, order=0, cval=-99.0, grid_mode=True 762# ) 763 764# return resampled_array 765 766 767# def resample_array_numpy(array, res_in={"dx": 1, "dy": 1}, res_out={"dx": 1, "dy": 1}): 768# """ 769 770# Description 771# ----------- 772 773# resample an array with input resolution to the output resolution. It simpy use numpy functions. 774 775# Parameters 776# ---------- 777 778# array: numpy.array() 779# Input gridded numpy array shape=(n,m) 780 781# res_in: dict() 782# resolution of the input array in x and y direction. Disctionnary {"dx":, "dy":} 783 784# res_out: dict() 785# resolution of the output array in x and y direction. Disctionnary {"dx":, "dy":} 786 787# Return 788# ------ 789 790# numpy.array() 791# Resampled array according res_out 792 793# """ 794# # 1Resampling 795# if (res_in["dx"] >= res_out["dx"]) and (res_in["dy"] >= res_out["dy"]): 796# ratio_x = int(res_in["dx"] / res_out["dx"]) 797# ratio_y = int(res_in["dy"] / res_out["dy"]) 798# # resampling input matrix to dx,dy smash si résolution demandée est inférieur 799# resampled_array = np.repeat(np.repeat(array, ratio_x, axis=0), ratio_y, axis=1) 800 801# elif (res_in["dx"] < res_out["dx"]) and (res_in["dy"] < res_out["dy"]): 802 803# ratio_x = int(res_out["dx"] / res_in["dx"]) 804# ratio_y = int(res_out["dy"] / res_in["dy"]) 805# # resampling input matrix si résolution demandée est supérieur: 806# xsize = int(np.ceil(array.shape[0] / ratio_x)) 807# ysize = int(np.ceil(array.shape[1] / ratio_y)) 808# resampled_array = np.full(shape=(xsize, ysize), fill_value=0) 809 810# xr = 0 811# for x in range(0, xsize): 812# yr = 0 813# for y in range(0, ysize): 814# buffer = array[xr : xr + ratio_x, yr : yr + ratio_y] 815# average = np.mean(buffer, axis=(0, 1)) 816# resampled_array[x, y, :] = average 817# yr = yr + ratio_y 818# xr = xr + ratio_x 819# else: 820# print( 821# "</> average resampling method impossible, different resampling resolution in x and y axis." 822# ) 823# return None 824 825# return resampled_array 826 827 828# def import_parameters(model: Model, path_to_parameters: FilePath): 829# """ 830# Description 831# ----------- 832# Read a geotif, resample if necessarry then clip it on the bouning box of the smash mesh 833 834# Parameters 835# ---------- 836# model: object 837# SMASH model object 838# path_to_parameters: str 839# Path to the directory which contain the geotiff files (parameters) 840 841# return 842# ------ 843# np.ndarray 844# The data clipped on the SMASH bounding box 845# """ 846# list_param = model.rr_parameters.keys 847 848# for param in list_param: 849# if os.path.exists(os.path.join(path_to_parameters, param + ".tif")): 850# cropped_param = _rasterio_read_param2( 851# path=os.path.join(path_to_parameters, param + ".tif"), mesh=model.mesh 852# ) 853 854# pos = np.argwhere(list_param == param).item() 855# model.rr_parameters.values[:, :, pos] = cropped_param 856 857# else: 858# raise ValueError(f"Missing parameter {param} in {path_to_parameters}") 859 860 861# def _rasterio_read_param(path: FilePath, mesh: MeshDT): 862# """ 863# Description 864# ----------- 865# Read a geotif, resample if necessarry then clip it on the bouning box of the smash mesh 866 867# Parameters 868# ---------- 869# path: str 870# Path to a geotiff file. 871# mesh: object 872# object of the smash mesh 873 874# return 875# ------ 876# np.ndarray 877# The data clipped on the SMASH bounding box 878# """ 879# bounds = get_bbox_from_smash_mesh(mesh) 880# xres = mesh.xres 881# yres = mesh.yres 882 883# # Open the larger raster 884# with rasterio.open(path) as dataset: 885# x_scale_factor = dataset.res[0] / xres 886# y_scale_factor = dataset.res[1] / yres 887 888# # resampling first to avoid spatial shifting of the parameters 889# data = dataset.read( 890# out_shape=( 891# dataset.count, 892# int(dataset.height * y_scale_factor), 893# int(dataset.width * x_scale_factor), 894# ), 895# resampling=Resampling.nearest, 896# ) 897 898# bbox_dataset = { 899# "left": dataset.bounds.left, 900# "bottom": dataset.bounds.bottom, 901# "right": dataset.bounds.right, 902# "top": dataset.bounds.top, 903# } 904 905# bbox_intersection = intersection_bbox(bbox_dataset, bounds) 906 907# window_intersection = get_cropped_window_from_bbox_intersection( 908# bbox_intersection, bbox_dataset, xres, yres 909# ) 910 911# cropped_array = data[ 912# 0, 913# window_intersection["row_off"] : window_intersection["row_off"] 914# + window_intersection["nrows"], 915# window_intersection["col_off"] : window_intersection["col_off"] 916# + window_intersection["ncols"], 917# ] 918 919# # allocate out array: shape of bbox_out 920# array_out = np.zeros( 921# shape=( 922# int((bounds["top"] - bounds["bottom"]) / xres), 923# int((bounds["right"] - bounds["left"]) / yres), 924# ) 925# ) 926 927# # window of bbox_intersection in the domain of bbox_smash 928# window_intersection_out = get_cropped_window_from_bbox_intersection( 929# bbox_intersection, bounds, xres, yres 930# ) 931 932# # copy crop_array (input matrix cropped) in array_out 933# array_out[ 934# window_intersection_out["row_off"] : window_intersection_out["row_off"] 935# + window_intersection_out["nrows"], 936# window_intersection_out["col_off"] : window_intersection_out["col_off"] 937# + window_intersection_out["ncols"], 938# ] = cropped_array 939 940# return array_out 941 942 943# def _rasterio_read_param2(path: FilePath, mesh: MeshDT): 944# """ 945# Description 946# ----------- 947# Read a geotif, resample if necessarry then clip it on the bouning box of the smash mesh 948 949# Parameters 950# ---------- 951# path: str 952# Path to a geotiff file. 953# mesh: object 954# object of the smash mesh 955 956# return 957# ------ 958# np.ndarray 959# The data clipped on the SMASH bounding box 960# """ 961# input_bbox = get_bbox_from_smash_mesh(mesh) 962 963# xres = mesh.xres 964# yres = mesh.yres 965 966# output_crs = rasterio.CRS.from_epsg(mesh.epsg) 967 968# # Open the larger raster 969# with rasterio.open(path) as dataset: 970 971# x_scale_factor = dataset.res[0] / xres 972# y_scale_factor = dataset.res[1] / yres 973 974# transform = dataset.transform 975# height = dataset.height 976# width = dataset.width 977# crs = dataset.crs 978 979# # resampling first to avoid spatial shifting of the parameters 980# data = dataset.read( 981# out_shape=( 982# dataset.count, 983# int(dataset.height * y_scale_factor), 984# int(dataset.width * x_scale_factor), 985# ), 986# resampling=Resampling.nearest, 987# ) 988 989# # Use a memory dataset 990# with rasterio.io.MemoryFile() as memfile: 991 992# with memfile.open( 993# driver="GTiff", 994# height=height, 995# width=width, 996# count=1, 997# dtype=data.dtype, 998# transform=transform, 999# crs=crs, 1000# ) as dataset: 1001# dataset.write(data[0, :, :], 1) 1002 1003# new_width = int((input_bbox["right"] - input_bbox["left"]) / yres) 1004# new_height = int((input_bbox["top"] - input_bbox["bottom"]) / xres) 1005# new_transform = rasterio.transform.from_bounds( 1006# west=input_bbox["left"], 1007# south=input_bbox["bottom"], 1008# east=input_bbox["right"], 1009# north=input_bbox["top"], 1010# width=new_width, 1011# height=new_height, 1012# ) 1013 1014# # Target array 1015# new_array = np.empty((new_height, new_width), dtype=np.float32) 1016 1017# # reproject dataset 1018# rasterio.warp.reproject( 1019# source=rasterio.band(dataset, 1), 1020# destination=new_array, 1021# src_transform=transform, 1022# src_crs=crs, 1023# dst_transform=new_transform, 1024# dst_crs=output_crs, 1025# resampling=Resampling.nearest, 1026# ) 1027 1028# return new_array
21def get_bbox_from_smash_mesh(mesh): 22 """ 23 Description 24 ----------- 25 Compute the bbox from a Smash mesh dictionary 26 Parameters 27 ---------- 28 mesh: dict 29 dict of smash mesh 30 return 31 ------ 32 dict() 33 the bounding box of the smash mesh 34 """ 35 36 if "xres" in mesh and "yres" in mesh: 37 dx = mesh["xres"] 38 dy = mesh["yres"] 39 else: 40 dx = np.mean(mesh["dx"]) 41 dy = np.mean(mesh["dy"]) 42 43 if "ncol" in mesh: 44 ncol = mesh["ncol"] 45 nrow = mesh["nrow"] 46 else: 47 nrow = mesh["active_cell"].shape[0] 48 ncol = mesh["active_cell"].shape[1] 49 50 left = mesh["xmin"] 51 right = mesh["xmin"] + ncol * dx 52 bottom = mesh["ymax"] - nrow * dy 53 top = mesh["ymax"] 54 bbox = {"left": left, "bottom": bottom, "right": right, "top": top} 55 56 return bbox
Description
Compute the bbox from a Smash mesh dictionary
Parameters
mesh: dict dict of smash mesh
return
dict() the bounding box of the smash mesh
59def get_bbox_from_ascii_data(ascii_data): 60 """ 61 62 Description 63 ----------- 64 65 Compute the boundingbox from ascii-data stored in a dictionnary (must contain the header) 66 67 Parameters 68 ---------- 69 70 ascii_data: dict() 71 Un dictionnaire contenant un format ascii: {ascii_data,xllcorner,yllcorner,ncol,nrows,cellsize}, la clé ascii_data contient un sous dictionnaire contenant des clés associés a des sources de données {clé:numpy_array} 72 73 return 74 ------ 75 76 dict() 77 Un dictionnaire contenant la boundingbox (coordonnées): {left, bottom, right, top} 78 79 """ 80 ascii_data_l = {} 81 for key, value in ascii_data.items(): 82 ascii_data_l.update({key.lower(): value}) 83 84 bbox = { 85 "left": ascii_data_l["xllcorner"], 86 "bottom": ascii_data_l["yllcorner"], 87 "right": ascii_data_l["xllcorner"] 88 + ascii_data_l["ncols"] * ascii_data_l["cellsize"], 89 "top": ascii_data_l["yllcorner"] 90 + ascii_data_l["nrows"] * ascii_data_l["cellsize"], 91 } 92 93 return bbox
Description
Compute the boundingbox from ascii-data stored in a dictionnary (must contain the header)
Parameters
ascii_data: dict() Un dictionnaire contenant un format ascii: {ascii_data,xllcorner,yllcorner,ncol,nrows,cellsize}, la clé ascii_data contient un sous dictionnaire contenant des clés associés a des sources de données {clé:numpy_array}
return
dict() Un dictionnaire contenant la boundingbox (coordonnées): {left, bottom, right, top}
96def check_bbox_consistency(bbox_model_active_cell, bbox_param): 97 98 if bbox_model_active_cell["left"] < bbox_param["left"]: 99 print( 100 f"Warning: Model domain is larger than the domain of the parameter. {bbox_model_active_cell['left']}<{bbox_param['left']} (bbox model left < bbox param left). Expect lacuna (-99.) in model parameters" 101 ) 102 103 if bbox_model_active_cell["right"] > bbox_param["right"]: 104 print( 105 f"Warning: Model domain is larger than the domain of the parameter. {bbox_model_active_cell['right']}>{bbox_param['right']} (bbox model left < bbox param left). Expect lacuna (-99.) in model parameters" 106 ) 107 108 if bbox_model_active_cell["bottom"] < bbox_param["bottom"]: 109 print( 110 f"Warning: Model domain is larger than the domain of the parameter. {bbox_model_active_cell['bottom']}<{bbox_param['bottom']} (bbox model left < bbox param left). Expect lacuna (-99.) in model parameters" 111 ) 112 113 if bbox_model_active_cell["top"] < bbox_param["top"]: 114 print( 115 f"Warning: Model domain is larger than the domain of the parameter. {bbox_model_active_cell['top']}>{bbox_param['top']} (bbox model left < bbox param left). Expect lacuna (-99.) in model parameters" 116 )
119def intersection_bbox(bbox1, bbox2): 120 """ 121 122 Description 123 ----------- 124 125 Function which compute the bounding boxes intersection of 2 input bbox. It return the working bbox 126 127 Parameters 128 ---------- 129 130 bbox1: dict() 131 containing the first bbox informations 132 bbox2 : dict() 133 containing the second bbox informations 134 135 returns 136 ---------- 137 138 dict() 139 containing the bbox union 140 141 Examples 142 ---------- 143 144 dataset=gdal_raster_open(filename) 145 possible_bbox=intersection_bbox(bbox,bbox_dataset) 146 147 """ 148 left = max(bbox1["left"], bbox2["left"]) 149 bottom = max(bbox1["bottom"], bbox2["bottom"]) 150 right = min(bbox1["right"], bbox2["right"]) 151 top = min(bbox1["top"], bbox2["top"]) 152 if (left < right) and (bottom < top): 153 bbox_intersection = {"left": left, "bottom": bottom, "right": right, "top": top} 154 return bbox_intersection 155 else: 156 print("Impossible bounding boxes intersection") 157 return {"left": 0, "bottom": 0, "right": 0, "top": 0}
Description
Function which compute the bounding boxes intersection of 2 input bbox. It return the working bbox
Parameters
bbox1: dict() containing the first bbox informations bbox2 : dict() containing the second bbox informations
returns
dict() containing the bbox union
Examples
dataset=gdal_raster_open(filename) possible_bbox=intersection_bbox(bbox,bbox_dataset)
160def get_window_from_bbox(mesh, bbox): 161 """ 162 Function to get the mesh window from a defined bbox 163 164 Parameters 165 ---------- 166 dataset: gdal object 167 bbox : dict containing the bbox 168 ---------- 169 returns 170 dic containing the computed windows 171 172 Examples 173 ---------- 174 dataset=gdal_raster_open(filename) 175 bbox_dataset=get_bbox(dataset) 176 window=get_window_from_bbox(dataset,bbox_dataset) 177 178 """ 179 180 if "xres" in mesh and "yres" in mesh: 181 dx = mesh["xres"] 182 dy = mesh["yres"] 183 else: 184 dx = np.mean(mesh["dx"]) 185 dy = np.mean(mesh["dy"]) 186 187 col_off = (bbox["left"] - mesh["xmin"]) / dx 188 row_off = (mesh["ymax"] - bbox["top"]) / dy 189 ncols = (bbox["right"] - bbox["left"]) / dx 190 nrows = (bbox["top"] - bbox["bottom"]) / dy 191 192 if (col_off < 0) or (row_off < 0): 193 raise Exception( 194 "The requested bounding box exceeds the limits of the raster domain." 195 ) 196 197 window = { 198 "row_off": int(row_off), 199 "col_off": int(col_off), 200 "nrows": int(nrows), 201 "ncols": int(ncols), 202 } 203 204 return window
Function to get the mesh window from a defined bbox
Parameters
dataset: gdal object
bbox : dict containing the bbox
returns dic containing the computed windows
Examples
dataset=gdal_raster_open(filename) bbox_dataset=get_bbox(dataset) window=get_window_from_bbox(dataset,bbox_dataset)
207def get_cropped_window_from_bbox_intersection(bbox_intersection, bbox_origin, dx, dy): 208 """ 209 210 Description 211 ----------- 212 213 Function to compute the domain to crop between a bbox intersection (included into bbox_origin) and the origin bbox. This function return a window such as the domain with bbox_intersection can be cropped using the retruned window according the bbox_origin 214 215 Parameters 216 ---------- 217 218 bbox_intersection: dict 219 A bbox that intersect bbox_origin 220 221 bbox_origin: dict 222 a bbox from which we want to extract data 223 224 dx: float 225 size of the grid in the x direction 226 227 dy: float 228 size of the grid in the y direction 229 230 Return 231 ------ 232 233 dict() 234 a window dictionnary containing information to crop a matrix: {row_off, col_off, nrows, ncols} 235 236 237 """ 238 if ( 239 (bbox_intersection["left"] < bbox_origin["left"]) 240 or (bbox_intersection["bottom"] < bbox_origin["bottom"]) 241 or (bbox_intersection["right"] > bbox_origin["right"]) 242 or (bbox_intersection["top"] > bbox_origin["top"]) 243 ): 244 print("The domain of bbox_intersection is not included in the domain of bbox_out") 245 window = {"row_off": 0, "col_off": 0, "nrows": 0, "ncols": 0} 246 return window 247 248 col_off = (bbox_intersection["left"] - bbox_origin["left"]) / dx 249 row_off = (bbox_origin["top"] - bbox_intersection["top"]) / dy 250 251 ncols = (bbox_intersection["right"] - bbox_intersection["left"]) / dx 252 nrows = (bbox_intersection["top"] - bbox_intersection["bottom"]) / dy 253 254 window = { 255 "row_off": int(row_off), 256 "col_off": int(col_off), 257 "nrows": int(nrows), 258 "ncols": int(ncols), 259 } 260 261 return window
Description
Function to compute the domain to crop between a bbox intersection (included into bbox_origin) and the origin bbox. This function return a window such as the domain with bbox_intersection can be cropped using the retruned window according the bbox_origin
Parameters
bbox_intersection: dict A bbox that intersect bbox_origin
bbox_origin: dict a bbox from which we want to extract data
dx: float size of the grid in the x direction
dy: float size of the grid in the y direction
Return
dict() a window dictionnary containing information to crop a matrix: {row_off, col_off, nrows, ncols}
264def write_array_to_geotiff(filename, array, xmin, ymax, xres, yres): 265 266 metadata = { 267 "driver": "GTiff", 268 "dtype": "float64", 269 "nodata": None, 270 "width": array.shape[1], 271 "height": array.shape[0], 272 "count": 1, 273 "crs": None, 274 "transform": rasterio.Affine(xres, 0.0, xmin, 0.0, -yres, ymax), 275 } 276 277 rasterio_write_tiff(filename=filename, matrix=array, metadata=metadata)
287def crop_array( 288 array, 289 bbox_in, 290 res_in, 291 bbox_out, 292 res_out, 293 order=0, 294 cval=-99.0, 295 grid_mode=True, 296): 297 """ 298 299 Description 300 -------------- 301 302 Crop a part of a numpy array with an input bbox and resolution to a new bbox with a new resolution 303 304 Parameters 305 ---------- 306 307 array : numpy.array() 308 Input gridded numpy array shape=(n,m) 309 310 bbox_in : dict() 311 bounding box of the input array. Dictionnary {"left":,"top":,"right":,"bottom":} 312 313 res_in : dict() 314 resolution of the input array in x and y direction. Disctionnary {"dx":, "dy":} 315 316 bbox_out : dict() 317 bounding box of the output array. Dictionnary {"left":,"top":,"right":,"bottom":} 318 319 res_out : dict() 320 resolution of the output array in x and y direction. Disctionnary {"dx":, "dy":} 321 322 order : int() 323 order of the resampling cubic interpolation 324 325 cval : float() | np.nan 326 fill value for the extended boundaries 327 328 grid_mode : bool() 329 True | False. if True coordinate start from the edge of the cell. If False coordinate starts from the center of the cell. 330 331 Return 332 ------ 333 334 numpy.array() 335 Cropped and resampled array according bbox_out and res_out 336 337 """ 338 339 # intersection bbox 340 bbox_intersection = intersection_bbox(bbox_in, bbox_out) 341 342 # ---------------------- fait une découpe grossière du domaine ------- 343 344 # 1- crop array on bbox_intersection+-res_in at res in: shrink the domain, speed up futur resampling on large domain ? 345 if res_in["dx"] >= res_out["dx"] and res_in["dy"] >= res_out["dy"]: 346 res_shrinked = {"dx": res_in["dx"], "dy": res_in["dy"]} 347 elif res_in["dx"] < res_out["dx"] and res_in["dy"] < res_out["dy"]: 348 res_shrinked = {"dx": res_out["dy"], "dy": res_out["dy"]} 349 elif res_in["dx"] < res_out["dx"] and res_in["dy"] >= res_out["dy"]: 350 res_shrinked = {"dx": res_out["dx"], "dy": res_in["dy"]} 351 elif res_in["dx"] >= res_out["dx"] and res_in["dy"] < res_out["dy"]: 352 res_shrinked = {"dx": res_in["dx"], "dy": res_out["dy"]} 353 354 bbox_in_shrinked = { 355 "left": bbox_in["left"] 356 + int(max(bbox_intersection["left"] - bbox_in["left"], 0) / res_shrinked["dx"]) 357 * res_shrinked["dx"], 358 "right": bbox_in["right"] 359 - int(max(bbox_in["right"] - bbox_intersection["right"], 0) / res_shrinked["dx"]) 360 * res_shrinked["dx"], 361 "bottom": bbox_in["bottom"] 362 + int( 363 max(bbox_intersection["bottom"] - bbox_in["bottom"], 0) / res_shrinked["dy"] 364 ) 365 * res_shrinked["dy"], 366 "top": bbox_in["top"] 367 - int(max(bbox_in["top"] - bbox_intersection["top"], 0) / res_shrinked["dy"]) 368 * res_shrinked["dy"], 369 } 370 bbox_intersection_shrinked = intersection_bbox(bbox_in, bbox_in_shrinked) 371 372 windows_wrap = get_window_from_bbox( 373 mesh={ 374 "xmin": bbox_in["left"], 375 "ymax": bbox_in["top"], 376 "xres": res_shrinked["dx"], 377 "yres": res_shrinked["dy"], 378 }, 379 bbox=bbox_intersection_shrinked, 380 ) 381 382 # Erase input array and bbox_in 383 array = array[ 384 windows_wrap["row_off"] : windows_wrap["row_off"] + windows_wrap["nrows"], 385 windows_wrap["col_off"] : windows_wrap["col_off"] + windows_wrap["ncols"], 386 ] 387 388 bbox_in = bbox_intersection_shrinked 389 390 # --------------------------------------------------------------------------------------- 391 392 # 2- resample the array to res_out 393 resampled_array = resample_array( 394 array, 395 res_in=res_in, 396 res_out=res_out, 397 order=order, 398 cval=cval, 399 grid_mode=grid_mode, 400 ) 401 402 # 3- crop the array on the intersection of bbox_in and bbox_out 403 # window of bbox_intersection in the domain of bbox_in (bbox_prcp, matrix to read) 404 window_intersection = get_cropped_window_from_bbox_intersection( 405 bbox_intersection, bbox_in, res_out["dx"], res_out["dy"] 406 ) 407 408 # reading the part of the matrix (array_in) 409 cropped_array = resampled_array[ 410 window_intersection["row_off"] : window_intersection["row_off"] 411 + window_intersection["nrows"], 412 window_intersection["col_off"] : window_intersection["col_off"] 413 + window_intersection["ncols"], 414 ] 415 416 # allocate out array: shape of bbox_out 417 array_out = ( 418 np.zeros( 419 shape=( 420 int((bbox_out["top"] - bbox_out["bottom"]) / res_out["dx"]), 421 int((bbox_out["right"] - bbox_out["left"]) / res_out["dy"]), 422 ) 423 ) 424 - 99.0 425 ) 426 427 # window of bbox_intersection in the domain of bbox_smash 428 window_intersection_out = get_cropped_window_from_bbox_intersection( 429 bbox_intersection, bbox_out, res_out["dx"], res_out["dy"] 430 ) 431 432 # copy crop_array (input matrix cropped) in array_out 433 array_out[ 434 window_intersection_out["row_off"] : window_intersection_out["row_off"] 435 + window_intersection_out["nrows"], 436 window_intersection_out["col_off"] : window_intersection_out["col_off"] 437 + window_intersection_out["ncols"], 438 ] = cropped_array 439 440 return array_out
Description
Crop a part of a numpy array with an input bbox and resolution to a new bbox with a new resolution
Parameters
array : numpy.array() Input gridded numpy array shape=(n,m)
bbox_in : dict() bounding box of the input array. Dictionnary {"left":,"top":,"right":,"bottom":}
res_in : dict() resolution of the input array in x and y direction. Disctionnary {"dx":, "dy":}
bbox_out : dict() bounding box of the output array. Dictionnary {"left":,"top":,"right":,"bottom":}
res_out : dict() resolution of the output array in x and y direction. Disctionnary {"dx":, "dy":}
order : int() order of the resampling cubic interpolation
cval : float() | np.nan fill value for the extended boundaries
grid_mode : bool() True | False. if True coordinate start from the edge of the cell. If False coordinate starts from the center of the cell.
Return
numpy.array() Cropped and resampled array according bbox_out and res_out
443def resample_array( 444 array, 445 res_in={"dx": 1, "dy": 1}, 446 res_out={"dx": 1, "dy": 1}, 447 order=0, 448 cval=-99.0, 449 grid_mode=True, 450): 451 """ 452 453 Parameters 454 ---------- 455 456 array: numpy.array() 457 Input gridded numpy array shape=(n,m) 458 459 res_in: dict() 460 resolution of the input array in x and y direction. Disctionnary {"dx":, "dy":} 461 462 res_out: dict() 463 resolution of the output array in x and y direction. Disctionnary {"dx":, "dy":} 464 465 order: int() 466 order of the resampling cubic interpolation 467 468 cval: float() | np.nan 469 fill value for the extended boundaries 470 471 grid_mode: bool() 472 True | False. if True coordinate start from the edge of the cell. If False coordinate starts from the center of the cell. 473 474 Return 475 ------ 476 477 numpy.array() 478 Cropped and resampled array according bbox_out and res_out 479 480 """ 481 482 ratio_x = res_in["dx"] / res_out["dx"] 483 ratio_y = res_in["dy"] / res_out["dy"] 484 resampled_array = zoom( 485 array, 486 (ratio_y, ratio_x), 487 order=order, 488 mode="grid-constant", 489 cval=-99.0, 490 grid_mode=True, 491 ) 492 493 return resampled_array
Parameters
array: numpy.array() Input gridded numpy array shape=(n,m)
res_in: dict() resolution of the input array in x and y direction. Disctionnary {"dx":, "dy":}
res_out: dict() resolution of the output array in x and y direction. Disctionnary {"dx":, "dy":}
order: int() order of the resampling cubic interpolation
cval: float() | np.nan fill value for the extended boundaries
grid_mode: bool() True | False. if True coordinate start from the edge of the cell. If False coordinate starts from the center of the cell.
Return
numpy.array() Cropped and resampled array according bbox_out and res_out