smashbox.init.param
1import smashbox 2import os 3import yaml 4from smashbox.tools.tools import check_asset_path, print_tree 5 6 7class param: 8 """ 9 Class param(): object which own : 10 - one attribute `param` with all necessary parameters fro building 11 an hydrological model with SmashBoxfunctions 12 - Some functions to maniuplate these parameters (stored in attribute param) 13 14 attributes 15 ---------- 16 17 param : class smashboxparam() 18 Class which stores the main parameters 19 20 """ 21 22 def __init__(self): 23 24 # self._parent_class=parent_class 25 self.param = smashboxparam() 26 """parent variable for class smashboxparam with all main parameters 27 of smashbox. 28 """ 29 30 def list_param(self): 31 """ 32 List all parameters in self.param 33 34 Examples 35 -------- 36 37 >>> es=smashbox.SmashBox() 38 >>> sb.newmodel("RealCollobrier") 39 >>> sb.RealCollobrier.list_param() 40 41 """ 42 for name, value in vars(type(self.param)).items(): 43 if isinstance(value, property): 44 print(f"{name}={getattr(self.param, name)}") 45 46 def set_param(self, attr, value): 47 """ 48 Setter for class attribute param(). 49 50 parameters 51 ---------- 52 attr : str 53 name of the attributes 54 55 value: any 56 value of the attribute 57 58 example 59 ------- 60 61 self.set_param("flowdir", "path/to/the/flowdir") 62 """ 63 setattr(self.param, attr, value) 64 65 def set_param_as_dict(self, param_dict): 66 """ 67 Setter for class attribute param() from a dictionary of keys/values. 68 69 parameters 70 ---------- 71 param_dict : dict 72 Dictionary with keys and values 73 74 example 75 ------- 76 77 self.set_param_as_dict({"flowdir": "path/to/the/flowdir","epsg":2154}) 78 """ 79 for key, value in param_dict.items(): 80 self.set_param(key, value) 81 82 def get_param(self, attr): 83 """ 84 Getter for class attribute param(). 85 86 parameters 87 ---------- 88 attr : str 89 name of the attributes 90 91 return: 92 ------- 93 any, the value stored in the attribute `attr`. 94 example 95 96 self.get_param("flowdir", "path/to/the/flowdir") 97 """ 98 getattr(self.param, attr) 99 100 def write_param(self, filename="param.yaml"): 101 """ 102 Dump all param attribute in a yaml file. 103 104 parameters 105 ---------- 106 filename : str 107 name of file to save the parameter formated in yaml 108 109 exemple: 110 -------- 111 112 self.get_param("flowdir", "path/to/the/flowdir") 113 """ 114 with open(filename, "w") as file: 115 yaml.dump(self.param.__dict__, file) 116 117 def load_param(self, filename=None): 118 """ 119 Load the parameters stored in a yaml file. 120 121 parameters 122 ---------- 123 filename : str 124 name of file to save the parameter formated in yaml 125 126 exemple: 127 -------- 128 129 self.get_param("flowdir", "path/to/the/flowdir") 130 """ 131 if os.path.exists(filename): 132 133 with open(filename, "r") as file: 134 135 param = yaml.safe_load(file) 136 137 for key, value in param.items(): 138 self.set_param(key, value) 139 140 def list_assets_files(self): 141 """ 142 List all assets files owned by SmashBox. Thes files are data such as 143 the flow directions and outlets database. 144 145 """ 146 print_tree(os.path.join(smashbox.__path__[0], "asset")) 147 148 149class smashboxparam: 150 """ 151 The class `smashboxparam` contains the main parameters needed to build an 152 SmashBox model. Thes parameters are stored in different attributes. 153 154 """ 155 156 def __init__(self): 157 """ 158 Initialisation of the attributes of class smashboxparam. All attributes 159 have a default value. 160 """ 161 self._assets_dir = None 162 """Path to the asset directory. str""" 163 if not os.path.exists( 164 os.path.join(os.path.expanduser("~"), ".smashbox", "asset") 165 ): 166 self._assets_dir = os.path.join(smashbox.__path__[0], "asset") 167 """Path to the asset directory. str""" 168 else: 169 self._assets_dir = os.path.join( 170 os.path.expanduser("~"), ".smashbox", "asset" 171 ) 172 """Path to the asset directory. str""" 173 174 self._flowdir = os.path.join( 175 self._assets_dir, "flwdir", "flowdir_fr_1000m.tif" 176 ) 177 """Path to the flow direction file formated in geotif. str""" 178 179 self._outlets_database = os.path.join( 180 self._assets_dir, "outlets", "db_sites.csv" 181 ) 182 """ Path to the outlet database iformatted in csv. str.""" 183 184 self._setup_file = os.path.join( 185 self._assets_dir, 186 "setup", 187 "setup_rhax_gr4_dt3600.yaml", 188 ) 189 """Path to a Smash setup file to be used. Format yaml. If only the name 190 of the file is given, the file will be searched in the asset directory. 191 """ 192 self._bbox = None # {"left": 0, "bottom": 0, "right": 0, "top": 0} 193 """Bounding box of the area to be modeled. dict | None, Optional. 194 bbox is a dictionary with 195 the following convention: 196 bbox={"left": c_weast, "bottom": y_south, "right": x_east, "top": x_north} 197 """ 198 199 self._epsg = 2154 200 """EPSG code of the coordinate system used. Integer.""" 201 202 self._outletsID = [] 203 """List of the outlets (key or name) to include in the mesh. 204 If the list is left empty, all outlets found in the area 205 defined by bbox will be included. If None, no outlet will be added. 206 The outlet name must be chosen 207 among the list of the outlet_database file in the column defined 208 by the attribute outlets_database_fields ('id') 209 """ 210 211 self._outlets_shapefile = None 212 """Path to the shape file containing the oultlet boundaries. Optional""" 213 214 self._smash_parameters = os.path.join(self._assets_dir, "params") 215 """Path to a directory with calibrated smash parameters. String | None. 216 All parameters must be stroed separetly in geotiff file. 217 """ 218 219 self._smash_parameters_dt = None 220 """Time-step for which the smash_parameters has been originaly calibrated. 221 int | float. If not None and if the model parameters is different, the parameters 222 "ct", "kexc", "llr" will be transformed according the relation 223 described in A.Ficchi, 2017. 224 """ 225 226 self._outlets_database_fields = { 227 "coord_x": "X_L93", 228 "coord_y": "Y_L93", 229 "area": "SURF", 230 "id": "CODE_SITE", 231 "id_shapefile": "", 232 } 233 """Dictionary with the name of the useful column field {key: field name}. 234 dict. 235 """ 236 237 self.enhanced_smash_input_data = False 238 """ 239 Use an enhanced version of the smash.model() method. The reading of the input atmospheric data functions used by smash have been rewritten in a different way provide more options and flexibility. 240 - read same type of data like SMASH: precipitation, snow, temperature and evapotranspration. 241 Support Geotiff format only. 242 - Merge all reading function in one. 243 - Configure the pattern of the date to search in the filename. Use common date formatters. 244 Handle the occurence number (starting from 0) with %n at the end of the date pattern. ex: %Y%m%d%H%1. 245 - Improve logs: new log clearly warn user about which files have been read and which files are missing. 246 - Fix a mistake during the reading of the evapotranspration. In SMASH the 247 evapotranspiration from the previous day is read instead of the current one. 248 - Read several data source by priority: each kind of data may have different source. 249 If one is missing, the model will read the second one, ect... 250 - Partially handle the reading of the continuous evapotranspiration in an operationnal context. 251 To do that, a sim-link of the etp data (delayed by 1 day) is created named with the date 252 of the current day. 253 - Handle time zone to shift the desagregation curve of the PET during the day. 254 - Improve the speed of the reading. Technically, an index of the dates and the 255 corresponding data files is created. To eficiency run through the long list of data files 256 and performs a regex search to match a date, a simple searh algorithm is build on top of 257 the main loop to avoid performing a regex on thousand files. 258 This improvement is noticable for model running on few time-step. It is particulary 259 important when running smash in an operationnal context. 260 """ 261 262 @property 263 def asset_dir(self): 264 """ 265 Type: 266 ----- 267 Property/Setter: str | os.PathLike 268 269 Description: 270 ------------ 271 Path to the asset directory. Default value is the asset directory of 272 SmashBox copied in the user space. 273 274 exemple 275 ------- 276 self.asset_dir = "path/to/my/asset/dir" 277 278 """ 279 return self._assets_dir 280 281 @asset_dir.setter 282 def asset_dir(self, value: os.PathLike): 283 """ 284 Setter. Path to the asset directory. 285 value : os.PathLike 286 287 exemple 288 ------- 289 self.asset_dir = "path/to/my/asset/dir" 290 291 """ 292 if os.path.isdir(value): 293 self._asset_dir = value 294 else: 295 raise ValueError(f"{value} is not a valid directory.") 296 297 @property 298 def outlets_database(self): 299 """ 300 Type: 301 ----- 302 Property/Setter: str | os.PathLike. 303 304 Description: 305 ------------ 306 Path to the outlet database formatted in csv. Field name, 307 coordinates (X and Y) and the surface of the catchment must exists. 308 Field name can be configure with attribute outlets_database_fields. 309 310 exemple 311 ------- 312 self.outlets_database = "path/to/my/database.csv" 313 314 """ 315 return self._outlets_database 316 317 @outlets_database.setter 318 def outlets_database(self, value: os.PathLike): 319 """ 320 Setter. Path to the outlet database formatted in csv. Field name, 321 coordinates (X and Y) and the surface of the catchment must exists. 322 Field name can be configure with attribute outlets_database_fields. 323 value : os.PathLike 324 325 exemple 326 ------- 327 self.outlets_database = "path/to/my/database.csv" 328 329 """ 330 self._outlets_database = check_asset_path( 331 os.path.join(self.asset_dir, "outlets"), value 332 ) 333 334 @property 335 def setup_file(self): 336 """ 337 Type: 338 ----- 339 Property/Setter: str | os.PathLike. 340 341 Description: 342 ------------ 343 Path to the smash setup file formatted in yaml. If only the name 344 of the file is given, the infered path will be the asset directory. 345 346 exemple 347 ------- 348 self.setup_file = "path/to/my/setup.yaml" 349 350 """ 351 return self._setup_file 352 353 @setup_file.setter 354 def setup_file(self, value: os.PathLike): 355 """ 356 Setter. Path to the smash setup file formatted in yaml. 357 value : os.PathLike 358 359 exemple 360 ------- 361 self.setup_file = "path/to/my/setup.yaml" 362 363 """ 364 self._setup_file = check_asset_path( 365 os.path.join(self.asset_dir, "setup"), value 366 ) 367 # self._parent_class._parent_class.mysetup.load_setup(self._setup_file) 368 369 @property 370 def flowdir(self): 371 """ 372 Type: 373 ----- 374 Property/Setter: str | os.PathLike. 375 376 Description: 377 ------------ 378 The path to the flowdir (flow direction) file formatted in Geotif. Refer to the Smash 379 documentation for more details: `https://smash.recover.inrae.fr/user_guide/ 380 data_and_format_description/cance.html#flow-direction` 381 382 """ 383 return self._flowdir 384 385 @flowdir.setter 386 def flowdir(self, value: os.PathLike): 387 """ 388 Setter. Path to the flowdir file formatted in Geotif. 389 value : os.PathLike 390 391 exemple 392 ------- 393 self.flowdir = "path/to/my/flowdir.tif" 394 395 """ 396 self._flowdir = check_asset_path( 397 os.path.join(self.asset_dir, "flowdir"), value 398 ) 399 400 @property 401 def bbox(self): 402 """ 403 Type: 404 ----- 405 Property/Setter: dict 406 407 Description: 408 ------------ 409 The Bounding box of the area to be modeled. dict | None, Optional. 410 bbox is a dictionary with the following convention: 411 bbox={"left": c_weast, "bottom": y_south, "right": x_east, "top": x_north} 412 413 exemple 414 ------- 415 self.bbox = {'left': 0, 'bottom': 0, 'right': 10, 'top': 10} 416 417 """ 418 return self._bbox 419 420 @bbox.setter 421 def bbox(self, value: dict | None): 422 """ 423 Setter. Set the bounding box of the domain. 424 value : dict | None 425 426 exemple 427 ------- 428 self.bbox = {'left': 0, 'bottom': 0, 'right': 10, 'top': 10} 429 430 """ 431 if value is None: 432 self._bbox = value 433 434 if sorted(["left", "bottom", "right", "top"]) == sorted( 435 list(value.keys()) 436 ): 437 self._bbox = value 438 else: 439 raise ValueError( 440 f"{value} is not a boundingbox. A boundingbox must be a dict" 441 "like {'left': 0, 'bottom': 0, 'right': 0, 'top': 0}" 442 ) 443 444 @property 445 def epsg(self): 446 """ 447 Type: 448 ----- 449 Property/Setter: int 450 451 Descripion: 452 ----------- 453 EPSG code of the coordinate system used. 454 455 exemple 456 ------- 457 self.epsg = 2154 458 459 """ 460 return self._epsg 461 462 @epsg.setter 463 def epsg(self, value: int): 464 """ 465 Setter. Set the epsg code of the coordinate system used. 466 value : int 467 468 exemple 469 ------- 470 self.epsg = 2154 471 472 """ 473 self._epsg = value 474 475 @property 476 def outletsID(self): 477 """ 478 Type: 479 ----- 480 Property/Setter : list 481 482 Descripion: 483 ----------- 484 List of the outlets (key or name) to include in the mesh. 485 If the list is left empty, all outlets found in the area 486 defined by bbox will be included. If None, no outlet will be added. 487 The outlet name must be chosen 488 among the list of the outlet_database file in the column defined 489 by the attribute outlets_database_fields ('id') 490 491 exemple 492 ------- 493 self.outletsID = ['V156730', 'V200820'] 494 495 """ 496 return self._outletsID 497 498 @outletsID.setter 499 def outletsID(self, value: list): 500 """ 501 Setter. Set the list of the outlet code (or name) used to build 502 the mesh. 503 value : list of str 504 505 exemple 506 ------- 507 self.outletsID = ['V156730', 'V200820'] 508 509 """ 510 if not isinstance(value, list): 511 raise ValueError( 512 f"outletsID value is a {type(value)} but it must be a list()" 513 ) 514 515 self._outletsID = value 516 517 @property 518 def outlets_shapefile(self): 519 """ 520 Type: 521 ----- 522 Property/Setter: str | os.PathLike. 523 524 Descripion: 525 ----------- 526 Path of the shapefile used to position the outlets. 527 528 exemple 529 ------- 530 self.outlets_shapefile = 'path/to/the/shapefile.shp' 531 """ 532 return self._outlets_shapefile 533 534 @outlets_shapefile.setter 535 def outlets_shapefile(self, value: None | os.PathLike = None): 536 """ 537 Setter. Set the path of the shapefile used to position the outlets. 538 value : None | os.PathLike 539 540 exemple 541 ------- 542 self.outlets_shapefile = 'path/to/the/shapefile.shp' 543 544 """ 545 if value is None: 546 return 547 548 if os.path.exists(value): 549 self._outlets_shapefile = value 550 else: 551 raise ValueError(f"'{value}' is not a valid path.") 552 553 @property 554 def smash_parameters(self): 555 """ 556 Type: 557 ----- 558 Property/Setter: str | os.PathLike. 559 560 Path to a directory which contain the calibrated smash parameters. 561 Each parameter must be stored separetly in a geotiff file 562 563 exemple 564 ------- 565 self.smash_parameters = 'path/to/the/directory/' 566 567 """ 568 return self._smash_parameters 569 570 @smash_parameters.setter 571 def smash_parameters(self, value: None | os.PathLike = None): 572 """ 573 Setter. Set the path to a directory where the smash parameters are 574 stored. 575 value : None | os.PathLike 576 577 exemple 578 ------- 579 self.smash_parameters = 'path/to/the/directory/' 580 581 """ 582 if value is None: 583 return 584 585 if os.path.isdir(value): 586 587 if len(os.listdir(value)) == 0: 588 raise ValueError(f"'{value}' is an empty directory.") 589 590 for file in os.listdir(value): 591 if not file.endswith(".tif"): 592 raise ValueError( 593 f"'{value}' contains files other than geotiff .tif format." 594 " These files are likely not compatible with SMASH parameters." 595 ) 596 597 self._smash_parameters = value 598 else: 599 raise ValueError(f"'{value}' is not a valid directory.") 600 601 @property 602 def smash_parameters_dt(self): 603 """ 604 Type: 605 ----- 606 Property/Setter: int | float. 607 608 Time-step for which the smash_parameters has been originaly calibrated. 609 int | float.If not None and if the model parameters is different, the parameters 610 "ct", "kexc", "llr" will be transformed according the relation 611 described in A.Ficchi, 2017. 612 613 exemple 614 ------- 615 self.smash_parameters_dt = 900 616 617 """ 618 return self._smash_parameters_dt 619 620 @smash_parameters_dt.setter 621 def smash_parameters_dt(self, value: None | os.PathLike = None): 622 """ 623 Setter. Set the time-step for which the smash_parameters has been originaly calibrated. 624 int | float. If not None and if the model parameters is different, the parameters 625 "ct", "kexc", "llr" will be transformed according the relation 626 described in A.Ficchi, 2017. 627 value : int | float 628 629 exemple 630 ------- 631 self.smash_parameters_dt = 900. 632 633 """ 634 635 self._smash_parameters_dt = value 636 637 @property 638 def outlets_database_fields(self): 639 """ 640 type: 641 ---- 642 Property/Setter: dict 643 644 Description: 645 ------------ 646 A dictionary with a corresponding `key` - `column name`. The 'key' of the dictionary 647 must match with desired 'column name' in the selected `outlet_database`. 648 Needed keys are: 649 650 - coord_x : X coordinate of the outlet 651 652 - coord_y : Y coordinate of the outlet 653 654 - area : Surface of the catchment 655 656 - id : Name or label of the outlet 657 658 - id_shapefile : optionaly the corresponding id in the contour shapefile 659 660 exemple 661 ------- 662 self.outlets_database_fields = '{ 663 "coord_x": "X_L93", 664 "coord_y": "Y_L93", 665 "area": "SURF", 666 "id": "ID_EX", 667 "id_shapefile" : "" 668 } 669 670 """ 671 return self._outlets_database_fields 672 673 @outlets_database_fields.setter 674 def outlets_database_fields(self, value: dict): 675 """ 676 type: 677 ---- 678 Property/Setter: dict 679 680 Description: 681 ------------ 682 A dictionary with a corresponding `key` - `column name`. The 'key' of the dictionary 683 must match with desired 'column name' in the selected `outlet_database`. 684 Needed keys are: 685 - coord_x : X coordinate of the outlet 686 - coord_y : Y coordinate of the outlet 687 -.area : Surface of the catchment 688 - id : Name or label of the outlet 689 690 exemple 691 ------- 692 self.outlets_database_fields = '{ 693 "coord_x": "X_L93", 694 "coord_y": "Y_L93", 695 "area": "SURF", 696 "id": "ID_EX", 697 "id_shapefile" : "" 698 } 699 700 """ 701 if not "id_shapefile" in value.keys(): 702 value.update({"id_shapefile": ""}) 703 704 if sorted( 705 ["coord_x", "coord_y", "area", "id", "id_shapefile"] 706 ) == sorted(list(value.keys())): 707 self._outlets_database_fields = value 708 else: 709 raise ValueError( 710 f"{value} doe not correspond to any outlets_database_fields." 711 " outlets_database_fields must look like" 712 " {'coord_x': 'X_L93','coord_y': 'Y_L93','area':'SURF','id':'ID_EX'}" 713 ) 714 self._outlets_database_fields = value 715 716 @property 717 def enhanced_smash_input_data(self): 718 """ 719 type: 720 ---- 721 Property/Setter: bool 722 723 Description: 724 ------------ 725 Use an enhanced version of the smash.model() method. The reading of the input 726 atmospheric data functions used by smash have been rewritten in a different way 727 provide more options and flexibility. 728 - read same type of data like SMASH: precipitation, snow, temperature and 729 evapotranspration. 730 Support Geotiff format only. 731 - Merge all reading function in one. 732 - Configure the pattern of the date to search in the filename. Use common date 733 formatters. Handle the occurence number (starting from 0) with %n at the end of 734 the date pattern. ex: %Y%m%d%H%1. 735 - Improve logs: new log clearly warn user about which files have been read and 736 which files are missing. 737 - Fix a mistake during the reading of the evapotranspration. In SMASH the 738 evapotranspiration from the previous day is read instead of the current one. 739 - Read several data source by priority: each kind of data may have different source. 740 If one is missing, the model will read the second one, ect... 741 - Partially handle the reading of the continuous evapotranspiration in an 742 operationnal context. To do that, a sim-link of the etp data (delayed by 1 day) 743 is created named with the date 744 of the current day. 745 - Handle time zone to shift the desagregation curve of the PET during the day. 746 - Improve the speed of the reading. Technically, an index of the dates and the 747 corresponding data files is created. To eficiency run through the long list of data files 748 and performs a regex search to match a date, a simple searh algorithm is build on top of 749 the main loop to avoid performing a regex on thousand files. 750 This improvement is noticable for model running on few time-step. It is particulary 751 important when running smash in an operationnal context. 752 753 new setup options: 754 ------------------ 755 prcp_date_pattern=%Y%m%d%H%0 756 prcp_directories: 757 1 : '/home/maxime/DATA/REUNION/PLUIE_REUNION/tests_tr/ANTILOPE_J1' 758 2 : '/home/maxime/DATA/REUNION/PLUIE_REUNION/tests_tr/ANTILOPE_TR' 759 3 : '/home/maxime/DATA/REUNION/PLUIE_REUNION/tests_tr/GRID_LESOL_500m' 760 pet_directories: 761 1 : "/home/maxime/DATA/REUNION/ETPJ_continue" 762 2 : "/home/maxime/DATA/REUNION/ETPJ_interannuelle_250_lnZ" 763 continuous_pet: 764 1: true 765 2: false 766 timezone: "UTC" 767 768 """ 769 return self._enhanced_smash_input_data 770 771 @enhanced_smash_input_data.setter 772 def enhanced_smash_input_data(self, value: bool): 773 """ 774 type: 775 ---- 776 Property/Setter: bool 777 778 Description: 779 ------------ 780 Use an enhanced version of the smash.model() method. The reading of the input 781 atmospheric data functions used by smash have been rewritten in a different way 782 provide more options and flexibility. 783 - read same type of data like SMASH: precipitation, snow, temperature and 784 evapotranspration. 785 Support Geotiff format only. 786 - Merge all reading function in one. 787 - Configure the pattern of the date to search in the filename. Use common date 788 formatters. Handle the occurence number (starting from 0) with %n at the end of 789 the date pattern. ex: %Y%m%d%H%1. 790 - Improve logs: new log clearly warn user about which files have been read and 791 which files are missing. 792 - Fix a mistake during the reading of the evapotranspration. In SMASH the 793 evapotranspiration from the previous day is read instead of the current one. 794 - Read several data source by priority: each kind of data may have different source. 795 If one is missing, the model will read the second one, ect... 796 - Partially handle the reading of the continuous evapotranspiration in an 797 operationnal context. To do that, a sim-link of the etp data (delayed by 1 day) 798 is created named with the date 799 of the current day. 800 - Handle time zone to shift the desagregation curve of the PET during the day. 801 - Improve the speed of the reading. Technically, an index of the dates and the 802 corresponding data files is created. To eficiency run through the long list of data files 803 and performs a regex search to match a date, a simple searh algorithm is build on top of 804 the main loop to avoid performing a regex on thousand files. 805 This improvement is noticable for model running on few time-step. It is particulary 806 important when running smash in an operationnal context. 807 808 new setup options: 809 ------------------ 810 prcp_date_pattern=%Y%m%d%H%0 811 prcp_directories: 812 1 : '/home/maxime/DATA/REUNION/PLUIE_REUNION/tests_tr/ANTILOPE_J1' 813 2 : '/home/maxime/DATA/REUNION/PLUIE_REUNION/tests_tr/ANTILOPE_TR' 814 3 : '/home/maxime/DATA/REUNION/PLUIE_REUNION/tests_tr/GRID_LESOL_500m' 815 pet_directories: 816 1 : "/home/maxime/DATA/REUNION/ETPJ_continue" 817 2 : "/home/maxime/DATA/REUNION/ETPJ_interannuelle_250_lnZ" 818 continuous_pet: 819 1: true 820 2: false 821 timezone: "UTC" 822 823 """ 824 self._enhanced_smash_input_data = value
8class param: 9 """ 10 Class param(): object which own : 11 - one attribute `param` with all necessary parameters fro building 12 an hydrological model with SmashBoxfunctions 13 - Some functions to maniuplate these parameters (stored in attribute param) 14 15 attributes 16 ---------- 17 18 param : class smashboxparam() 19 Class which stores the main parameters 20 21 """ 22 23 def __init__(self): 24 25 # self._parent_class=parent_class 26 self.param = smashboxparam() 27 """parent variable for class smashboxparam with all main parameters 28 of smashbox. 29 """ 30 31 def list_param(self): 32 """ 33 List all parameters in self.param 34 35 Examples 36 -------- 37 38 >>> es=smashbox.SmashBox() 39 >>> sb.newmodel("RealCollobrier") 40 >>> sb.RealCollobrier.list_param() 41 42 """ 43 for name, value in vars(type(self.param)).items(): 44 if isinstance(value, property): 45 print(f"{name}={getattr(self.param, name)}") 46 47 def set_param(self, attr, value): 48 """ 49 Setter for class attribute param(). 50 51 parameters 52 ---------- 53 attr : str 54 name of the attributes 55 56 value: any 57 value of the attribute 58 59 example 60 ------- 61 62 self.set_param("flowdir", "path/to/the/flowdir") 63 """ 64 setattr(self.param, attr, value) 65 66 def set_param_as_dict(self, param_dict): 67 """ 68 Setter for class attribute param() from a dictionary of keys/values. 69 70 parameters 71 ---------- 72 param_dict : dict 73 Dictionary with keys and values 74 75 example 76 ------- 77 78 self.set_param_as_dict({"flowdir": "path/to/the/flowdir","epsg":2154}) 79 """ 80 for key, value in param_dict.items(): 81 self.set_param(key, value) 82 83 def get_param(self, attr): 84 """ 85 Getter for class attribute param(). 86 87 parameters 88 ---------- 89 attr : str 90 name of the attributes 91 92 return: 93 ------- 94 any, the value stored in the attribute `attr`. 95 example 96 97 self.get_param("flowdir", "path/to/the/flowdir") 98 """ 99 getattr(self.param, attr) 100 101 def write_param(self, filename="param.yaml"): 102 """ 103 Dump all param attribute in a yaml file. 104 105 parameters 106 ---------- 107 filename : str 108 name of file to save the parameter formated in yaml 109 110 exemple: 111 -------- 112 113 self.get_param("flowdir", "path/to/the/flowdir") 114 """ 115 with open(filename, "w") as file: 116 yaml.dump(self.param.__dict__, file) 117 118 def load_param(self, filename=None): 119 """ 120 Load the parameters stored in a yaml file. 121 122 parameters 123 ---------- 124 filename : str 125 name of file to save the parameter formated in yaml 126 127 exemple: 128 -------- 129 130 self.get_param("flowdir", "path/to/the/flowdir") 131 """ 132 if os.path.exists(filename): 133 134 with open(filename, "r") as file: 135 136 param = yaml.safe_load(file) 137 138 for key, value in param.items(): 139 self.set_param(key, value) 140 141 def list_assets_files(self): 142 """ 143 List all assets files owned by SmashBox. Thes files are data such as 144 the flow directions and outlets database. 145 146 """ 147 print_tree(os.path.join(smashbox.__path__[0], "asset"))
Class param(): object which own :
- one attribute param with all necessary parameters fro building
an hydrological model with SmashBoxfunctions
- Some functions to maniuplate these parameters (stored in attribute param)
attributes
param : class smashboxparam() Class which stores the main parameters
31 def list_param(self): 32 """ 33 List all parameters in self.param 34 35 Examples 36 -------- 37 38 >>> es=smashbox.SmashBox() 39 >>> sb.newmodel("RealCollobrier") 40 >>> sb.RealCollobrier.list_param() 41 42 """ 43 for name, value in vars(type(self.param)).items(): 44 if isinstance(value, property): 45 print(f"{name}={getattr(self.param, name)}")
List all parameters in self.param
Examples
>>> es=smashbox.SmashBox()
>>> sb.newmodel("RealCollobrier")
>>> sb.RealCollobrier.list_param()
47 def set_param(self, attr, value): 48 """ 49 Setter for class attribute param(). 50 51 parameters 52 ---------- 53 attr : str 54 name of the attributes 55 56 value: any 57 value of the attribute 58 59 example 60 ------- 61 62 self.set_param("flowdir", "path/to/the/flowdir") 63 """ 64 setattr(self.param, attr, value)
Setter for class attribute param().
parameters
attr : str name of the attributes
value: any value of the attribute
example
self.set_param("flowdir", "path/to/the/flowdir")
66 def set_param_as_dict(self, param_dict): 67 """ 68 Setter for class attribute param() from a dictionary of keys/values. 69 70 parameters 71 ---------- 72 param_dict : dict 73 Dictionary with keys and values 74 75 example 76 ------- 77 78 self.set_param_as_dict({"flowdir": "path/to/the/flowdir","epsg":2154}) 79 """ 80 for key, value in param_dict.items(): 81 self.set_param(key, value)
Setter for class attribute param() from a dictionary of keys/values.
parameters
param_dict : dict Dictionary with keys and values
example
self.set_param_as_dict({"flowdir": "path/to/the/flowdir","epsg":2154})
83 def get_param(self, attr): 84 """ 85 Getter for class attribute param(). 86 87 parameters 88 ---------- 89 attr : str 90 name of the attributes 91 92 return: 93 ------- 94 any, the value stored in the attribute `attr`. 95 example 96 97 self.get_param("flowdir", "path/to/the/flowdir") 98 """ 99 getattr(self.param, attr)
Getter for class attribute param().
parameters
attr : str name of the attributes
return:
any, the value stored in the attribute attr.
example
self.get_param("flowdir", "path/to/the/flowdir")
101 def write_param(self, filename="param.yaml"): 102 """ 103 Dump all param attribute in a yaml file. 104 105 parameters 106 ---------- 107 filename : str 108 name of file to save the parameter formated in yaml 109 110 exemple: 111 -------- 112 113 self.get_param("flowdir", "path/to/the/flowdir") 114 """ 115 with open(filename, "w") as file: 116 yaml.dump(self.param.__dict__, file)
Dump all param attribute in a yaml file.
parameters
filename : str name of file to save the parameter formated in yaml
exemple:
self.get_param("flowdir", "path/to/the/flowdir")
118 def load_param(self, filename=None): 119 """ 120 Load the parameters stored in a yaml file. 121 122 parameters 123 ---------- 124 filename : str 125 name of file to save the parameter formated in yaml 126 127 exemple: 128 -------- 129 130 self.get_param("flowdir", "path/to/the/flowdir") 131 """ 132 if os.path.exists(filename): 133 134 with open(filename, "r") as file: 135 136 param = yaml.safe_load(file) 137 138 for key, value in param.items(): 139 self.set_param(key, value)
Load the parameters stored in a yaml file.
parameters
filename : str name of file to save the parameter formated in yaml
exemple:
self.get_param("flowdir", "path/to/the/flowdir")
141 def list_assets_files(self): 142 """ 143 List all assets files owned by SmashBox. Thes files are data such as 144 the flow directions and outlets database. 145 146 """ 147 print_tree(os.path.join(smashbox.__path__[0], "asset"))
List all assets files owned by SmashBox. Thes files are data such as the flow directions and outlets database.
150class smashboxparam: 151 """ 152 The class `smashboxparam` contains the main parameters needed to build an 153 SmashBox model. Thes parameters are stored in different attributes. 154 155 """ 156 157 def __init__(self): 158 """ 159 Initialisation of the attributes of class smashboxparam. All attributes 160 have a default value. 161 """ 162 self._assets_dir = None 163 """Path to the asset directory. str""" 164 if not os.path.exists( 165 os.path.join(os.path.expanduser("~"), ".smashbox", "asset") 166 ): 167 self._assets_dir = os.path.join(smashbox.__path__[0], "asset") 168 """Path to the asset directory. str""" 169 else: 170 self._assets_dir = os.path.join( 171 os.path.expanduser("~"), ".smashbox", "asset" 172 ) 173 """Path to the asset directory. str""" 174 175 self._flowdir = os.path.join( 176 self._assets_dir, "flwdir", "flowdir_fr_1000m.tif" 177 ) 178 """Path to the flow direction file formated in geotif. str""" 179 180 self._outlets_database = os.path.join( 181 self._assets_dir, "outlets", "db_sites.csv" 182 ) 183 """ Path to the outlet database iformatted in csv. str.""" 184 185 self._setup_file = os.path.join( 186 self._assets_dir, 187 "setup", 188 "setup_rhax_gr4_dt3600.yaml", 189 ) 190 """Path to a Smash setup file to be used. Format yaml. If only the name 191 of the file is given, the file will be searched in the asset directory. 192 """ 193 self._bbox = None # {"left": 0, "bottom": 0, "right": 0, "top": 0} 194 """Bounding box of the area to be modeled. dict | None, Optional. 195 bbox is a dictionary with 196 the following convention: 197 bbox={"left": c_weast, "bottom": y_south, "right": x_east, "top": x_north} 198 """ 199 200 self._epsg = 2154 201 """EPSG code of the coordinate system used. Integer.""" 202 203 self._outletsID = [] 204 """List of the outlets (key or name) to include in the mesh. 205 If the list is left empty, all outlets found in the area 206 defined by bbox will be included. If None, no outlet will be added. 207 The outlet name must be chosen 208 among the list of the outlet_database file in the column defined 209 by the attribute outlets_database_fields ('id') 210 """ 211 212 self._outlets_shapefile = None 213 """Path to the shape file containing the oultlet boundaries. Optional""" 214 215 self._smash_parameters = os.path.join(self._assets_dir, "params") 216 """Path to a directory with calibrated smash parameters. String | None. 217 All parameters must be stroed separetly in geotiff file. 218 """ 219 220 self._smash_parameters_dt = None 221 """Time-step for which the smash_parameters has been originaly calibrated. 222 int | float. If not None and if the model parameters is different, the parameters 223 "ct", "kexc", "llr" will be transformed according the relation 224 described in A.Ficchi, 2017. 225 """ 226 227 self._outlets_database_fields = { 228 "coord_x": "X_L93", 229 "coord_y": "Y_L93", 230 "area": "SURF", 231 "id": "CODE_SITE", 232 "id_shapefile": "", 233 } 234 """Dictionary with the name of the useful column field {key: field name}. 235 dict. 236 """ 237 238 self.enhanced_smash_input_data = False 239 """ 240 Use an enhanced version of the smash.model() method. The reading of the input atmospheric data functions used by smash have been rewritten in a different way provide more options and flexibility. 241 - read same type of data like SMASH: precipitation, snow, temperature and evapotranspration. 242 Support Geotiff format only. 243 - Merge all reading function in one. 244 - Configure the pattern of the date to search in the filename. Use common date formatters. 245 Handle the occurence number (starting from 0) with %n at the end of the date pattern. ex: %Y%m%d%H%1. 246 - Improve logs: new log clearly warn user about which files have been read and which files are missing. 247 - Fix a mistake during the reading of the evapotranspration. In SMASH the 248 evapotranspiration from the previous day is read instead of the current one. 249 - Read several data source by priority: each kind of data may have different source. 250 If one is missing, the model will read the second one, ect... 251 - Partially handle the reading of the continuous evapotranspiration in an operationnal context. 252 To do that, a sim-link of the etp data (delayed by 1 day) is created named with the date 253 of the current day. 254 - Handle time zone to shift the desagregation curve of the PET during the day. 255 - Improve the speed of the reading. Technically, an index of the dates and the 256 corresponding data files is created. To eficiency run through the long list of data files 257 and performs a regex search to match a date, a simple searh algorithm is build on top of 258 the main loop to avoid performing a regex on thousand files. 259 This improvement is noticable for model running on few time-step. It is particulary 260 important when running smash in an operationnal context. 261 """ 262 263 @property 264 def asset_dir(self): 265 """ 266 Type: 267 ----- 268 Property/Setter: str | os.PathLike 269 270 Description: 271 ------------ 272 Path to the asset directory. Default value is the asset directory of 273 SmashBox copied in the user space. 274 275 exemple 276 ------- 277 self.asset_dir = "path/to/my/asset/dir" 278 279 """ 280 return self._assets_dir 281 282 @asset_dir.setter 283 def asset_dir(self, value: os.PathLike): 284 """ 285 Setter. Path to the asset directory. 286 value : os.PathLike 287 288 exemple 289 ------- 290 self.asset_dir = "path/to/my/asset/dir" 291 292 """ 293 if os.path.isdir(value): 294 self._asset_dir = value 295 else: 296 raise ValueError(f"{value} is not a valid directory.") 297 298 @property 299 def outlets_database(self): 300 """ 301 Type: 302 ----- 303 Property/Setter: str | os.PathLike. 304 305 Description: 306 ------------ 307 Path to the outlet database formatted in csv. Field name, 308 coordinates (X and Y) and the surface of the catchment must exists. 309 Field name can be configure with attribute outlets_database_fields. 310 311 exemple 312 ------- 313 self.outlets_database = "path/to/my/database.csv" 314 315 """ 316 return self._outlets_database 317 318 @outlets_database.setter 319 def outlets_database(self, value: os.PathLike): 320 """ 321 Setter. Path to the outlet database formatted in csv. Field name, 322 coordinates (X and Y) and the surface of the catchment must exists. 323 Field name can be configure with attribute outlets_database_fields. 324 value : os.PathLike 325 326 exemple 327 ------- 328 self.outlets_database = "path/to/my/database.csv" 329 330 """ 331 self._outlets_database = check_asset_path( 332 os.path.join(self.asset_dir, "outlets"), value 333 ) 334 335 @property 336 def setup_file(self): 337 """ 338 Type: 339 ----- 340 Property/Setter: str | os.PathLike. 341 342 Description: 343 ------------ 344 Path to the smash setup file formatted in yaml. If only the name 345 of the file is given, the infered path will be the asset directory. 346 347 exemple 348 ------- 349 self.setup_file = "path/to/my/setup.yaml" 350 351 """ 352 return self._setup_file 353 354 @setup_file.setter 355 def setup_file(self, value: os.PathLike): 356 """ 357 Setter. Path to the smash setup file formatted in yaml. 358 value : os.PathLike 359 360 exemple 361 ------- 362 self.setup_file = "path/to/my/setup.yaml" 363 364 """ 365 self._setup_file = check_asset_path( 366 os.path.join(self.asset_dir, "setup"), value 367 ) 368 # self._parent_class._parent_class.mysetup.load_setup(self._setup_file) 369 370 @property 371 def flowdir(self): 372 """ 373 Type: 374 ----- 375 Property/Setter: str | os.PathLike. 376 377 Description: 378 ------------ 379 The path to the flowdir (flow direction) file formatted in Geotif. Refer to the Smash 380 documentation for more details: `https://smash.recover.inrae.fr/user_guide/ 381 data_and_format_description/cance.html#flow-direction` 382 383 """ 384 return self._flowdir 385 386 @flowdir.setter 387 def flowdir(self, value: os.PathLike): 388 """ 389 Setter. Path to the flowdir file formatted in Geotif. 390 value : os.PathLike 391 392 exemple 393 ------- 394 self.flowdir = "path/to/my/flowdir.tif" 395 396 """ 397 self._flowdir = check_asset_path( 398 os.path.join(self.asset_dir, "flowdir"), value 399 ) 400 401 @property 402 def bbox(self): 403 """ 404 Type: 405 ----- 406 Property/Setter: dict 407 408 Description: 409 ------------ 410 The Bounding box of the area to be modeled. dict | None, Optional. 411 bbox is a dictionary with the following convention: 412 bbox={"left": c_weast, "bottom": y_south, "right": x_east, "top": x_north} 413 414 exemple 415 ------- 416 self.bbox = {'left': 0, 'bottom': 0, 'right': 10, 'top': 10} 417 418 """ 419 return self._bbox 420 421 @bbox.setter 422 def bbox(self, value: dict | None): 423 """ 424 Setter. Set the bounding box of the domain. 425 value : dict | None 426 427 exemple 428 ------- 429 self.bbox = {'left': 0, 'bottom': 0, 'right': 10, 'top': 10} 430 431 """ 432 if value is None: 433 self._bbox = value 434 435 if sorted(["left", "bottom", "right", "top"]) == sorted( 436 list(value.keys()) 437 ): 438 self._bbox = value 439 else: 440 raise ValueError( 441 f"{value} is not a boundingbox. A boundingbox must be a dict" 442 "like {'left': 0, 'bottom': 0, 'right': 0, 'top': 0}" 443 ) 444 445 @property 446 def epsg(self): 447 """ 448 Type: 449 ----- 450 Property/Setter: int 451 452 Descripion: 453 ----------- 454 EPSG code of the coordinate system used. 455 456 exemple 457 ------- 458 self.epsg = 2154 459 460 """ 461 return self._epsg 462 463 @epsg.setter 464 def epsg(self, value: int): 465 """ 466 Setter. Set the epsg code of the coordinate system used. 467 value : int 468 469 exemple 470 ------- 471 self.epsg = 2154 472 473 """ 474 self._epsg = value 475 476 @property 477 def outletsID(self): 478 """ 479 Type: 480 ----- 481 Property/Setter : list 482 483 Descripion: 484 ----------- 485 List of the outlets (key or name) to include in the mesh. 486 If the list is left empty, all outlets found in the area 487 defined by bbox will be included. If None, no outlet will be added. 488 The outlet name must be chosen 489 among the list of the outlet_database file in the column defined 490 by the attribute outlets_database_fields ('id') 491 492 exemple 493 ------- 494 self.outletsID = ['V156730', 'V200820'] 495 496 """ 497 return self._outletsID 498 499 @outletsID.setter 500 def outletsID(self, value: list): 501 """ 502 Setter. Set the list of the outlet code (or name) used to build 503 the mesh. 504 value : list of str 505 506 exemple 507 ------- 508 self.outletsID = ['V156730', 'V200820'] 509 510 """ 511 if not isinstance(value, list): 512 raise ValueError( 513 f"outletsID value is a {type(value)} but it must be a list()" 514 ) 515 516 self._outletsID = value 517 518 @property 519 def outlets_shapefile(self): 520 """ 521 Type: 522 ----- 523 Property/Setter: str | os.PathLike. 524 525 Descripion: 526 ----------- 527 Path of the shapefile used to position the outlets. 528 529 exemple 530 ------- 531 self.outlets_shapefile = 'path/to/the/shapefile.shp' 532 """ 533 return self._outlets_shapefile 534 535 @outlets_shapefile.setter 536 def outlets_shapefile(self, value: None | os.PathLike = None): 537 """ 538 Setter. Set the path of the shapefile used to position the outlets. 539 value : None | os.PathLike 540 541 exemple 542 ------- 543 self.outlets_shapefile = 'path/to/the/shapefile.shp' 544 545 """ 546 if value is None: 547 return 548 549 if os.path.exists(value): 550 self._outlets_shapefile = value 551 else: 552 raise ValueError(f"'{value}' is not a valid path.") 553 554 @property 555 def smash_parameters(self): 556 """ 557 Type: 558 ----- 559 Property/Setter: str | os.PathLike. 560 561 Path to a directory which contain the calibrated smash parameters. 562 Each parameter must be stored separetly in a geotiff file 563 564 exemple 565 ------- 566 self.smash_parameters = 'path/to/the/directory/' 567 568 """ 569 return self._smash_parameters 570 571 @smash_parameters.setter 572 def smash_parameters(self, value: None | os.PathLike = None): 573 """ 574 Setter. Set the path to a directory where the smash parameters are 575 stored. 576 value : None | os.PathLike 577 578 exemple 579 ------- 580 self.smash_parameters = 'path/to/the/directory/' 581 582 """ 583 if value is None: 584 return 585 586 if os.path.isdir(value): 587 588 if len(os.listdir(value)) == 0: 589 raise ValueError(f"'{value}' is an empty directory.") 590 591 for file in os.listdir(value): 592 if not file.endswith(".tif"): 593 raise ValueError( 594 f"'{value}' contains files other than geotiff .tif format." 595 " These files are likely not compatible with SMASH parameters." 596 ) 597 598 self._smash_parameters = value 599 else: 600 raise ValueError(f"'{value}' is not a valid directory.") 601 602 @property 603 def smash_parameters_dt(self): 604 """ 605 Type: 606 ----- 607 Property/Setter: int | float. 608 609 Time-step for which the smash_parameters has been originaly calibrated. 610 int | float.If not None and if the model parameters is different, the parameters 611 "ct", "kexc", "llr" will be transformed according the relation 612 described in A.Ficchi, 2017. 613 614 exemple 615 ------- 616 self.smash_parameters_dt = 900 617 618 """ 619 return self._smash_parameters_dt 620 621 @smash_parameters_dt.setter 622 def smash_parameters_dt(self, value: None | os.PathLike = None): 623 """ 624 Setter. Set the time-step for which the smash_parameters has been originaly calibrated. 625 int | float. If not None and if the model parameters is different, the parameters 626 "ct", "kexc", "llr" will be transformed according the relation 627 described in A.Ficchi, 2017. 628 value : int | float 629 630 exemple 631 ------- 632 self.smash_parameters_dt = 900. 633 634 """ 635 636 self._smash_parameters_dt = value 637 638 @property 639 def outlets_database_fields(self): 640 """ 641 type: 642 ---- 643 Property/Setter: dict 644 645 Description: 646 ------------ 647 A dictionary with a corresponding `key` - `column name`. The 'key' of the dictionary 648 must match with desired 'column name' in the selected `outlet_database`. 649 Needed keys are: 650 651 - coord_x : X coordinate of the outlet 652 653 - coord_y : Y coordinate of the outlet 654 655 - area : Surface of the catchment 656 657 - id : Name or label of the outlet 658 659 - id_shapefile : optionaly the corresponding id in the contour shapefile 660 661 exemple 662 ------- 663 self.outlets_database_fields = '{ 664 "coord_x": "X_L93", 665 "coord_y": "Y_L93", 666 "area": "SURF", 667 "id": "ID_EX", 668 "id_shapefile" : "" 669 } 670 671 """ 672 return self._outlets_database_fields 673 674 @outlets_database_fields.setter 675 def outlets_database_fields(self, value: dict): 676 """ 677 type: 678 ---- 679 Property/Setter: dict 680 681 Description: 682 ------------ 683 A dictionary with a corresponding `key` - `column name`. The 'key' of the dictionary 684 must match with desired 'column name' in the selected `outlet_database`. 685 Needed keys are: 686 - coord_x : X coordinate of the outlet 687 - coord_y : Y coordinate of the outlet 688 -.area : Surface of the catchment 689 - id : Name or label of the outlet 690 691 exemple 692 ------- 693 self.outlets_database_fields = '{ 694 "coord_x": "X_L93", 695 "coord_y": "Y_L93", 696 "area": "SURF", 697 "id": "ID_EX", 698 "id_shapefile" : "" 699 } 700 701 """ 702 if not "id_shapefile" in value.keys(): 703 value.update({"id_shapefile": ""}) 704 705 if sorted( 706 ["coord_x", "coord_y", "area", "id", "id_shapefile"] 707 ) == sorted(list(value.keys())): 708 self._outlets_database_fields = value 709 else: 710 raise ValueError( 711 f"{value} doe not correspond to any outlets_database_fields." 712 " outlets_database_fields must look like" 713 " {'coord_x': 'X_L93','coord_y': 'Y_L93','area':'SURF','id':'ID_EX'}" 714 ) 715 self._outlets_database_fields = value 716 717 @property 718 def enhanced_smash_input_data(self): 719 """ 720 type: 721 ---- 722 Property/Setter: bool 723 724 Description: 725 ------------ 726 Use an enhanced version of the smash.model() method. The reading of the input 727 atmospheric data functions used by smash have been rewritten in a different way 728 provide more options and flexibility. 729 - read same type of data like SMASH: precipitation, snow, temperature and 730 evapotranspration. 731 Support Geotiff format only. 732 - Merge all reading function in one. 733 - Configure the pattern of the date to search in the filename. Use common date 734 formatters. Handle the occurence number (starting from 0) with %n at the end of 735 the date pattern. ex: %Y%m%d%H%1. 736 - Improve logs: new log clearly warn user about which files have been read and 737 which files are missing. 738 - Fix a mistake during the reading of the evapotranspration. In SMASH the 739 evapotranspiration from the previous day is read instead of the current one. 740 - Read several data source by priority: each kind of data may have different source. 741 If one is missing, the model will read the second one, ect... 742 - Partially handle the reading of the continuous evapotranspiration in an 743 operationnal context. To do that, a sim-link of the etp data (delayed by 1 day) 744 is created named with the date 745 of the current day. 746 - Handle time zone to shift the desagregation curve of the PET during the day. 747 - Improve the speed of the reading. Technically, an index of the dates and the 748 corresponding data files is created. To eficiency run through the long list of data files 749 and performs a regex search to match a date, a simple searh algorithm is build on top of 750 the main loop to avoid performing a regex on thousand files. 751 This improvement is noticable for model running on few time-step. It is particulary 752 important when running smash in an operationnal context. 753 754 new setup options: 755 ------------------ 756 prcp_date_pattern=%Y%m%d%H%0 757 prcp_directories: 758 1 : '/home/maxime/DATA/REUNION/PLUIE_REUNION/tests_tr/ANTILOPE_J1' 759 2 : '/home/maxime/DATA/REUNION/PLUIE_REUNION/tests_tr/ANTILOPE_TR' 760 3 : '/home/maxime/DATA/REUNION/PLUIE_REUNION/tests_tr/GRID_LESOL_500m' 761 pet_directories: 762 1 : "/home/maxime/DATA/REUNION/ETPJ_continue" 763 2 : "/home/maxime/DATA/REUNION/ETPJ_interannuelle_250_lnZ" 764 continuous_pet: 765 1: true 766 2: false 767 timezone: "UTC" 768 769 """ 770 return self._enhanced_smash_input_data 771 772 @enhanced_smash_input_data.setter 773 def enhanced_smash_input_data(self, value: bool): 774 """ 775 type: 776 ---- 777 Property/Setter: bool 778 779 Description: 780 ------------ 781 Use an enhanced version of the smash.model() method. The reading of the input 782 atmospheric data functions used by smash have been rewritten in a different way 783 provide more options and flexibility. 784 - read same type of data like SMASH: precipitation, snow, temperature and 785 evapotranspration. 786 Support Geotiff format only. 787 - Merge all reading function in one. 788 - Configure the pattern of the date to search in the filename. Use common date 789 formatters. Handle the occurence number (starting from 0) with %n at the end of 790 the date pattern. ex: %Y%m%d%H%1. 791 - Improve logs: new log clearly warn user about which files have been read and 792 which files are missing. 793 - Fix a mistake during the reading of the evapotranspration. In SMASH the 794 evapotranspiration from the previous day is read instead of the current one. 795 - Read several data source by priority: each kind of data may have different source. 796 If one is missing, the model will read the second one, ect... 797 - Partially handle the reading of the continuous evapotranspiration in an 798 operationnal context. To do that, a sim-link of the etp data (delayed by 1 day) 799 is created named with the date 800 of the current day. 801 - Handle time zone to shift the desagregation curve of the PET during the day. 802 - Improve the speed of the reading. Technically, an index of the dates and the 803 corresponding data files is created. To eficiency run through the long list of data files 804 and performs a regex search to match a date, a simple searh algorithm is build on top of 805 the main loop to avoid performing a regex on thousand files. 806 This improvement is noticable for model running on few time-step. It is particulary 807 important when running smash in an operationnal context. 808 809 new setup options: 810 ------------------ 811 prcp_date_pattern=%Y%m%d%H%0 812 prcp_directories: 813 1 : '/home/maxime/DATA/REUNION/PLUIE_REUNION/tests_tr/ANTILOPE_J1' 814 2 : '/home/maxime/DATA/REUNION/PLUIE_REUNION/tests_tr/ANTILOPE_TR' 815 3 : '/home/maxime/DATA/REUNION/PLUIE_REUNION/tests_tr/GRID_LESOL_500m' 816 pet_directories: 817 1 : "/home/maxime/DATA/REUNION/ETPJ_continue" 818 2 : "/home/maxime/DATA/REUNION/ETPJ_interannuelle_250_lnZ" 819 continuous_pet: 820 1: true 821 2: false 822 timezone: "UTC" 823 824 """ 825 self._enhanced_smash_input_data = value
The class smashboxparam contains the main parameters needed to build an
SmashBox model. Thes parameters are stored in different attributes.
157 def __init__(self): 158 """ 159 Initialisation of the attributes of class smashboxparam. All attributes 160 have a default value. 161 """ 162 self._assets_dir = None 163 """Path to the asset directory. str""" 164 if not os.path.exists( 165 os.path.join(os.path.expanduser("~"), ".smashbox", "asset") 166 ): 167 self._assets_dir = os.path.join(smashbox.__path__[0], "asset") 168 """Path to the asset directory. str""" 169 else: 170 self._assets_dir = os.path.join( 171 os.path.expanduser("~"), ".smashbox", "asset" 172 ) 173 """Path to the asset directory. str""" 174 175 self._flowdir = os.path.join( 176 self._assets_dir, "flwdir", "flowdir_fr_1000m.tif" 177 ) 178 """Path to the flow direction file formated in geotif. str""" 179 180 self._outlets_database = os.path.join( 181 self._assets_dir, "outlets", "db_sites.csv" 182 ) 183 """ Path to the outlet database iformatted in csv. str.""" 184 185 self._setup_file = os.path.join( 186 self._assets_dir, 187 "setup", 188 "setup_rhax_gr4_dt3600.yaml", 189 ) 190 """Path to a Smash setup file to be used. Format yaml. If only the name 191 of the file is given, the file will be searched in the asset directory. 192 """ 193 self._bbox = None # {"left": 0, "bottom": 0, "right": 0, "top": 0} 194 """Bounding box of the area to be modeled. dict | None, Optional. 195 bbox is a dictionary with 196 the following convention: 197 bbox={"left": c_weast, "bottom": y_south, "right": x_east, "top": x_north} 198 """ 199 200 self._epsg = 2154 201 """EPSG code of the coordinate system used. Integer.""" 202 203 self._outletsID = [] 204 """List of the outlets (key or name) to include in the mesh. 205 If the list is left empty, all outlets found in the area 206 defined by bbox will be included. If None, no outlet will be added. 207 The outlet name must be chosen 208 among the list of the outlet_database file in the column defined 209 by the attribute outlets_database_fields ('id') 210 """ 211 212 self._outlets_shapefile = None 213 """Path to the shape file containing the oultlet boundaries. Optional""" 214 215 self._smash_parameters = os.path.join(self._assets_dir, "params") 216 """Path to a directory with calibrated smash parameters. String | None. 217 All parameters must be stroed separetly in geotiff file. 218 """ 219 220 self._smash_parameters_dt = None 221 """Time-step for which the smash_parameters has been originaly calibrated. 222 int | float. If not None and if the model parameters is different, the parameters 223 "ct", "kexc", "llr" will be transformed according the relation 224 described in A.Ficchi, 2017. 225 """ 226 227 self._outlets_database_fields = { 228 "coord_x": "X_L93", 229 "coord_y": "Y_L93", 230 "area": "SURF", 231 "id": "CODE_SITE", 232 "id_shapefile": "", 233 } 234 """Dictionary with the name of the useful column field {key: field name}. 235 dict. 236 """ 237 238 self.enhanced_smash_input_data = False 239 """ 240 Use an enhanced version of the smash.model() method. The reading of the input atmospheric data functions used by smash have been rewritten in a different way provide more options and flexibility. 241 - read same type of data like SMASH: precipitation, snow, temperature and evapotranspration. 242 Support Geotiff format only. 243 - Merge all reading function in one. 244 - Configure the pattern of the date to search in the filename. Use common date formatters. 245 Handle the occurence number (starting from 0) with %n at the end of the date pattern. ex: %Y%m%d%H%1. 246 - Improve logs: new log clearly warn user about which files have been read and which files are missing. 247 - Fix a mistake during the reading of the evapotranspration. In SMASH the 248 evapotranspiration from the previous day is read instead of the current one. 249 - Read several data source by priority: each kind of data may have different source. 250 If one is missing, the model will read the second one, ect... 251 - Partially handle the reading of the continuous evapotranspiration in an operationnal context. 252 To do that, a sim-link of the etp data (delayed by 1 day) is created named with the date 253 of the current day. 254 - Handle time zone to shift the desagregation curve of the PET during the day. 255 - Improve the speed of the reading. Technically, an index of the dates and the 256 corresponding data files is created. To eficiency run through the long list of data files 257 and performs a regex search to match a date, a simple searh algorithm is build on top of 258 the main loop to avoid performing a regex on thousand files. 259 This improvement is noticable for model running on few time-step. It is particulary 260 important when running smash in an operationnal context. 261 """
Initialisation of the attributes of class smashboxparam. All attributes have a default value.
717 @property 718 def enhanced_smash_input_data(self): 719 """ 720 type: 721 ---- 722 Property/Setter: bool 723 724 Description: 725 ------------ 726 Use an enhanced version of the smash.model() method. The reading of the input 727 atmospheric data functions used by smash have been rewritten in a different way 728 provide more options and flexibility. 729 - read same type of data like SMASH: precipitation, snow, temperature and 730 evapotranspration. 731 Support Geotiff format only. 732 - Merge all reading function in one. 733 - Configure the pattern of the date to search in the filename. Use common date 734 formatters. Handle the occurence number (starting from 0) with %n at the end of 735 the date pattern. ex: %Y%m%d%H%1. 736 - Improve logs: new log clearly warn user about which files have been read and 737 which files are missing. 738 - Fix a mistake during the reading of the evapotranspration. In SMASH the 739 evapotranspiration from the previous day is read instead of the current one. 740 - Read several data source by priority: each kind of data may have different source. 741 If one is missing, the model will read the second one, ect... 742 - Partially handle the reading of the continuous evapotranspiration in an 743 operationnal context. To do that, a sim-link of the etp data (delayed by 1 day) 744 is created named with the date 745 of the current day. 746 - Handle time zone to shift the desagregation curve of the PET during the day. 747 - Improve the speed of the reading. Technically, an index of the dates and the 748 corresponding data files is created. To eficiency run through the long list of data files 749 and performs a regex search to match a date, a simple searh algorithm is build on top of 750 the main loop to avoid performing a regex on thousand files. 751 This improvement is noticable for model running on few time-step. It is particulary 752 important when running smash in an operationnal context. 753 754 new setup options: 755 ------------------ 756 prcp_date_pattern=%Y%m%d%H%0 757 prcp_directories: 758 1 : '/home/maxime/DATA/REUNION/PLUIE_REUNION/tests_tr/ANTILOPE_J1' 759 2 : '/home/maxime/DATA/REUNION/PLUIE_REUNION/tests_tr/ANTILOPE_TR' 760 3 : '/home/maxime/DATA/REUNION/PLUIE_REUNION/tests_tr/GRID_LESOL_500m' 761 pet_directories: 762 1 : "/home/maxime/DATA/REUNION/ETPJ_continue" 763 2 : "/home/maxime/DATA/REUNION/ETPJ_interannuelle_250_lnZ" 764 continuous_pet: 765 1: true 766 2: false 767 timezone: "UTC" 768 769 """ 770 return self._enhanced_smash_input_data
Use an enhanced version of the smash.model() method. The reading of the input atmospheric data functions used by smash have been rewritten in a different way provide more options and flexibility.
- read same type of data like SMASH: precipitation, snow, temperature and evapotranspration. Support Geotiff format only.
- Merge all reading function in one.
- Configure the pattern of the date to search in the filename. Use common date formatters. Handle the occurence number (starting from 0) with %n at the end of the date pattern. ex: %Y%m%d%H%1.
- Improve logs: new log clearly warn user about which files have been read and which files are missing.
- Fix a mistake during the reading of the evapotranspration. In SMASH the evapotranspiration from the previous day is read instead of the current one.
- Read several data source by priority: each kind of data may have different source. If one is missing, the model will read the second one, ect...
- Partially handle the reading of the continuous evapotranspiration in an operationnal context. To do that, a sim-link of the etp data (delayed by 1 day) is created named with the date of the current day.
- Handle time zone to shift the desagregation curve of the PET during the day.
- Improve the speed of the reading. Technically, an index of the dates and the corresponding data files is created. To eficiency run through the long list of data files and performs a regex search to match a date, a simple searh algorithm is build on top of the main loop to avoid performing a regex on thousand files. This improvement is noticable for model running on few time-step. It is particulary important when running smash in an operationnal context.
263 @property 264 def asset_dir(self): 265 """ 266 Type: 267 ----- 268 Property/Setter: str | os.PathLike 269 270 Description: 271 ------------ 272 Path to the asset directory. Default value is the asset directory of 273 SmashBox copied in the user space. 274 275 exemple 276 ------- 277 self.asset_dir = "path/to/my/asset/dir" 278 279 """ 280 return self._assets_dir
Type:
Property/Setter: str | os.PathLike
Description:
Path to the asset directory. Default value is the asset directory of SmashBox copied in the user space.
exemple
self.asset_dir = "path/to/my/asset/dir"
298 @property 299 def outlets_database(self): 300 """ 301 Type: 302 ----- 303 Property/Setter: str | os.PathLike. 304 305 Description: 306 ------------ 307 Path to the outlet database formatted in csv. Field name, 308 coordinates (X and Y) and the surface of the catchment must exists. 309 Field name can be configure with attribute outlets_database_fields. 310 311 exemple 312 ------- 313 self.outlets_database = "path/to/my/database.csv" 314 315 """ 316 return self._outlets_database
Type:
Property/Setter: str | os.PathLike.
Description:
Path to the outlet database formatted in csv. Field name, coordinates (X and Y) and the surface of the catchment must exists. Field name can be configure with attribute outlets_database_fields.
exemple
self.outlets_database = "path/to/my/database.csv"
335 @property 336 def setup_file(self): 337 """ 338 Type: 339 ----- 340 Property/Setter: str | os.PathLike. 341 342 Description: 343 ------------ 344 Path to the smash setup file formatted in yaml. If only the name 345 of the file is given, the infered path will be the asset directory. 346 347 exemple 348 ------- 349 self.setup_file = "path/to/my/setup.yaml" 350 351 """ 352 return self._setup_file
Type:
Property/Setter: str | os.PathLike.
Description:
Path to the smash setup file formatted in yaml. If only the name of the file is given, the infered path will be the asset directory.
exemple
self.setup_file = "path/to/my/setup.yaml"
370 @property 371 def flowdir(self): 372 """ 373 Type: 374 ----- 375 Property/Setter: str | os.PathLike. 376 377 Description: 378 ------------ 379 The path to the flowdir (flow direction) file formatted in Geotif. Refer to the Smash 380 documentation for more details: `https://smash.recover.inrae.fr/user_guide/ 381 data_and_format_description/cance.html#flow-direction` 382 383 """ 384 return self._flowdir
Type:
Property/Setter: str | os.PathLike.
Description:
The path to the flowdir (flow direction) file formatted in Geotif. Refer to the Smash
documentation for more details: https://smash.recover.inrae.fr/user_guide/
data_and_format_description/cance.html#flow-direction
401 @property 402 def bbox(self): 403 """ 404 Type: 405 ----- 406 Property/Setter: dict 407 408 Description: 409 ------------ 410 The Bounding box of the area to be modeled. dict | None, Optional. 411 bbox is a dictionary with the following convention: 412 bbox={"left": c_weast, "bottom": y_south, "right": x_east, "top": x_north} 413 414 exemple 415 ------- 416 self.bbox = {'left': 0, 'bottom': 0, 'right': 10, 'top': 10} 417 418 """ 419 return self._bbox
Type:
Property/Setter: dict
Description:
The Bounding box of the area to be modeled. dict | None, Optional. bbox is a dictionary with the following convention: bbox={"left": c_weast, "bottom": y_south, "right": x_east, "top": x_north}
exemple
self.bbox = {'left': 0, 'bottom': 0, 'right': 10, 'top': 10}
445 @property 446 def epsg(self): 447 """ 448 Type: 449 ----- 450 Property/Setter: int 451 452 Descripion: 453 ----------- 454 EPSG code of the coordinate system used. 455 456 exemple 457 ------- 458 self.epsg = 2154 459 460 """ 461 return self._epsg
Type:
Property/Setter: int
Descripion:
EPSG code of the coordinate system used.
exemple
self.epsg = 2154
476 @property 477 def outletsID(self): 478 """ 479 Type: 480 ----- 481 Property/Setter : list 482 483 Descripion: 484 ----------- 485 List of the outlets (key or name) to include in the mesh. 486 If the list is left empty, all outlets found in the area 487 defined by bbox will be included. If None, no outlet will be added. 488 The outlet name must be chosen 489 among the list of the outlet_database file in the column defined 490 by the attribute outlets_database_fields ('id') 491 492 exemple 493 ------- 494 self.outletsID = ['V156730', 'V200820'] 495 496 """ 497 return self._outletsID
Type:
Property/Setter : list
Descripion:
List of the outlets (key or name) to include in the mesh. If the list is left empty, all outlets found in the area defined by bbox will be included. If None, no outlet will be added. The outlet name must be chosen among the list of the outlet_database file in the column defined by the attribute outlets_database_fields ('id')
exemple
self.outletsID = ['V156730', 'V200820']
518 @property 519 def outlets_shapefile(self): 520 """ 521 Type: 522 ----- 523 Property/Setter: str | os.PathLike. 524 525 Descripion: 526 ----------- 527 Path of the shapefile used to position the outlets. 528 529 exemple 530 ------- 531 self.outlets_shapefile = 'path/to/the/shapefile.shp' 532 """ 533 return self._outlets_shapefile
Type:
Property/Setter: str | os.PathLike.
Descripion:
Path of the shapefile used to position the outlets.
exemple
self.outlets_shapefile = 'path/to/the/shapefile.shp'
554 @property 555 def smash_parameters(self): 556 """ 557 Type: 558 ----- 559 Property/Setter: str | os.PathLike. 560 561 Path to a directory which contain the calibrated smash parameters. 562 Each parameter must be stored separetly in a geotiff file 563 564 exemple 565 ------- 566 self.smash_parameters = 'path/to/the/directory/' 567 568 """ 569 return self._smash_parameters
Type:
Property/Setter: str | os.PathLike.
Path to a directory which contain the calibrated smash parameters. Each parameter must be stored separetly in a geotiff file
exemple
self.smash_parameters = 'path/to/the/directory/'
602 @property 603 def smash_parameters_dt(self): 604 """ 605 Type: 606 ----- 607 Property/Setter: int | float. 608 609 Time-step for which the smash_parameters has been originaly calibrated. 610 int | float.If not None and if the model parameters is different, the parameters 611 "ct", "kexc", "llr" will be transformed according the relation 612 described in A.Ficchi, 2017. 613 614 exemple 615 ------- 616 self.smash_parameters_dt = 900 617 618 """ 619 return self._smash_parameters_dt
Type:
Property/Setter: int | float.
Time-step for which the smash_parameters has been originaly calibrated. int | float.If not None and if the model parameters is different, the parameters "ct", "kexc", "llr" will be transformed according the relation described in A.Ficchi, 2017.
exemple
self.smash_parameters_dt = 900
638 @property 639 def outlets_database_fields(self): 640 """ 641 type: 642 ---- 643 Property/Setter: dict 644 645 Description: 646 ------------ 647 A dictionary with a corresponding `key` - `column name`. The 'key' of the dictionary 648 must match with desired 'column name' in the selected `outlet_database`. 649 Needed keys are: 650 651 - coord_x : X coordinate of the outlet 652 653 - coord_y : Y coordinate of the outlet 654 655 - area : Surface of the catchment 656 657 - id : Name or label of the outlet 658 659 - id_shapefile : optionaly the corresponding id in the contour shapefile 660 661 exemple 662 ------- 663 self.outlets_database_fields = '{ 664 "coord_x": "X_L93", 665 "coord_y": "Y_L93", 666 "area": "SURF", 667 "id": "ID_EX", 668 "id_shapefile" : "" 669 } 670 671 """ 672 return self._outlets_database_fields
type:
Property/Setter: dict
Description:
A dictionary with a corresponding key - column name. The 'key' of the dictionary
must match with desired 'column name' in the selected outlet_database.
Needed keys are:
- coord_x : X coordinate of the outlet
- coord_y : Y coordinate of the outlet
- area : Surface of the catchment
- id : Name or label of the outlet
- id_shapefile : optionaly the corresponding id in the contour shapefile
exemple
self.outlets_database_fields = '{ "coord_x": "X_L93", "coord_y": "Y_L93", "area": "SURF", "id": "ID_EX", "id_shapefile" : "" }