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

Initialisation of the attributes of class smashboxparam. All attributes have a default value.

enhanced_smash_input_data
703    @property
704    def enhanced_smash_input_data(self):
705        """
706        type:
707        ----
708        Property/Setter: bool
709
710        Description:
711        ------------
712        Use an enhanced version of the smash.model() method. The reading of the input
713        atmospheric data functions used by smash have been rewritten in a different way
714        provide more options and flexibility.
715        - read same type of data like SMASH: precipitation, snow, temperature and
716        evapotranspration.
717        Support Geotiff format only.
718        - Merge all reading function in one.
719        - Configure the pattern of the date to search in the filename. Use common date
720        formatters. Handle the occurence number (starting from 0) with %n at the end of
721        the date pattern. ex: %Y%m%d%H%1.
722        - Improve logs: new log clearly warn user about which files have been read and
723        which files are missing.
724        - Fix a mistake during the reading of the evapotranspration. In SMASH the
725        evapotranspiration from the previous day is read instead of the current one.
726        - Read several data source by priority: each kind of data may have different source.
727        If one is missing, the model will read the second one, ect...
728        - Partially handle the reading of the continuous evapotranspiration in an
729        operationnal context. To do that, a sim-link of the etp data (delayed by 1 day)
730        is created named with the date
731        of the current day.
732        - Handle time zone to shift the desagregation curve of the PET during the day.
733        - Improve the speed of the reading. Technically, an index of the dates and the
734        corresponding data files is created. To eficiency run through the long list of data files
735        and performs a regex search to match a date, a simple searh algorithm is build on top of
736        the main loop to avoid performing a regex on thousand files.
737        This improvement is noticable for model running on few time-step. It is particulary
738        important when running smash in an operationnal context.
739
740        new setup options:
741        ------------------
742        prcp_date_pattern=%Y%m%d%H%0
743        prcp_directories:
744            1 : '/home/maxime/DATA/REUNION/PLUIE_REUNION/tests_tr/ANTILOPE_J1'
745            2 : '/home/maxime/DATA/REUNION/PLUIE_REUNION/tests_tr/ANTILOPE_TR'
746            3 : '/home/maxime/DATA/REUNION/PLUIE_REUNION/tests_tr/GRID_LESOL_500m'
747        pet_directories:
748            1 : "/home/maxime/DATA/REUNION/ETPJ_continue"
749            2 : "/home/maxime/DATA/REUNION/ETPJ_interannuelle_250_lnZ"
750        continuous_pet:
751            1: true
752            2: false
753        timezone: "UTC"
754
755        """
756        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
256    @property
257    def asset_dir(self):
258        """
259        Type:
260        -----
261        Property/Setter: str | os.PathLike
262
263        Description:
264        ------------
265        Path to the asset directory. Default value is the asset directory of
266        SmashBox copied in the user space.
267
268        exemple
269        -------
270        self.asset_dir = "path/to/my/asset/dir"
271
272        """
273        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
291    @property
292    def outlets_database(self):
293        """
294        Type:
295        -----
296        Property/Setter: str | os.PathLike.
297
298        Description:
299        ------------
300        Path to the outlet database formatted in csv. Field name,
301        coordinates (X and Y) and the surface of the catchment must exists.
302        Field name can be configure with attribute outlets_database_fields.
303
304        exemple
305        -------
306        self.outlets_database = "path/to/my/database.csv"
307
308        """
309        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
328    @property
329    def setup_file(self):
330        """
331        Type:
332        -----
333        Property/Setter: str | os.PathLike.
334
335        Description:
336        ------------
337        Path to the smash setup file formatted in yaml. If only the name
338            of the file is given, the infered path will be the asset directory.
339
340        exemple
341        -------
342        self.setup_file = "path/to/my/setup.yaml"
343
344        """
345        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
361    @property
362    def flowdir(self):
363        """
364        Type:
365        -----
366        Property/Setter: str | os.PathLike.
367
368        Description:
369        ------------
370        The path to the flowdir (flow direction) file formatted in Geotif. Refer to the Smash
371        documentation for more details: `https://smash.recover.inrae.fr/user_guide/
372        data_and_format_description/cance.html#flow-direction`
373
374        """
375        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
390    @property
391    def bbox(self):
392        """
393        Type:
394        -----
395        Property/Setter: dict
396
397        Description:
398        ------------
399        The Bounding box of the area to be modeled. dict | None, Optional.
400        bbox is a dictionary with the following convention:
401        bbox={"left": c_weast, "bottom": y_south, "right": x_east, "top": x_north}
402
403        exemple
404        -------
405        self.bbox = {'left': 0, 'bottom': 0, 'right': 10, 'top': 10}
406
407        """
408        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
432    @property
433    def epsg(self):
434        """
435        Type:
436        -----
437        Property/Setter: int
438
439        Descripion:
440        -----------
441        EPSG code of the coordinate system used.
442
443        exemple
444        -------
445        self.epsg = 2154
446
447        """
448        return self._epsg

Type:

Property/Setter: int

Descripion:

EPSG code of the coordinate system used.

exemple

self.epsg = 2154

outletsID
463    @property
464    def outletsID(self):
465        """
466        Type:
467        -----
468        Property/Setter : list
469
470        Descripion:
471        -----------
472        List of the outlets (key or name) to include in the mesh.
473        If the list is left empty, all outlets found in the area
474        defined by bbox will be included. If None, no outlet will be added.
475        The outlet name must be chosen
476        among the list of the outlet_database file in the column defined
477        by the attribute outlets_database_fields ('id')
478
479        exemple
480        -------
481        self.outletsID = ['V156730', 'V200820']
482
483        """
484        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
505    @property
506    def outlets_shapefile(self):
507        """
508        Type:
509        -----
510        Property/Setter: str | os.PathLike.
511
512        Descripion:
513        -----------
514        Path of the shapefile used to position the outlets.
515
516        exemple
517        -------
518        self.outlets_shapefile = 'path/to/the/shapefile.shp'
519        """
520        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
541    @property
542    def smash_parameters(self):
543        """
544        Type:
545        -----
546        Property/Setter: str | os.PathLike.
547
548        Path to a directory which contain the calibrated smash parameters.
549        Each parameter must be stored separetly in a geotiff file
550
551        exemple
552        -------
553        self.smash_parameters = 'path/to/the/directory/'
554
555        """
556        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
589    @property
590    def smash_parameters_dt(self):
591        """
592        Type:
593        -----
594        Property/Setter: int | float.
595
596        Time-step for which the smash_parameters has been originaly calibrated.
597        int | float.If not None and if the model parameters is different, the parameters
598        "ct", "kexc", "llr" will be transformed according the relation
599        described in A.Ficchi, 2017.
600
601        exemple
602        -------
603        self.smash_parameters_dt = 900
604
605        """
606        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
625    @property
626    def outlets_database_fields(self):
627        """
628        type:
629        ----
630        Property/Setter: dict
631
632        Description:
633        ------------
634        A dictionary with a corresponding `key` - `column name`. The 'key' of the dictionary
635        must match with desired 'column name' in the selected `outlet_database`.
636        Needed keys are:
637
638            - coord_x : X coordinate of the outlet
639
640            - coord_y : Y coordinate of the outlet
641
642            - area : Surface of the catchment
643
644            - id : Name or label of the outlet
645
646            - id_shapefile : optionaly the corresponding id in the contour shapefile
647
648        exemple
649        -------
650        self.outlets_database_fields = '{
651            "coord_x": "X_L93",
652            "coord_y": "Y_L93",
653            "area": "SURF",
654            "id": "ID_EX",
655        }
656
657        """
658        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", }