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
class param:
  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

param

parent variable for class smashboxparam with all main parameters of smashbox.

def list_param(self):
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()
def set_param(self, attr, value):
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")

def set_param_as_dict(self, param_dict):
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})

def get_param(self, attr):
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")

def write_param(self, filename='param.yaml'):
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")

def load_param(self, filename=None):
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")

def list_assets_files(self):
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.

class smashboxparam:
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.

smashboxparam()
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.

enhanced_smash_input_data
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.
asset_dir
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"

outlets_database
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"

setup_file
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"

flowdir
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

bbox
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}

epsg
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

outletsID
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']

outlets_shapefile
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'

smash_parameters
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/'

smash_parameters_dt
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

outlets_database_fields
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" : "" }