smashbox.init.smashbox

  1from smashbox.init import param
  2from smashbox.model import model
  3from smashbox.stats import mystats
  4from smashbox.plot import myplot
  5from smashbox.init import multimodel_statistics
  6import smashbox
  7
  8import os
  9import shutil
 10import copy
 11import pyhdf5_handler
 12import smash
 13import glob
 14import pickle
 15
 16
 17class SmashBox:
 18    """
 19    Main class which store main parameters 'myparam' and functions to create or delete
 20     models.
 21    """
 22
 23    def __init__(self):
 24
 25        if not os.path.exists(
 26            os.path.join(os.path.expanduser("~"), ".smashbox", "asset")
 27        ):
 28            shutil.copytree(
 29                os.path.join(smashbox.__path__[0], "asset"),
 30                os.path.join(os.path.expanduser("~"), ".smashbox", "asset"),
 31            )
 32
 33        self.myparam = param.param()
 34        if os.path.exists(
 35            os.path.join(os.path.expanduser("~"), ".smashbox", "param.yaml")
 36        ):
 37            self.myparam.load_param(
 38                os.path.join(
 39                    os.path.expanduser("~"), ".smashbox", "default_param.yaml"
 40                )
 41            )
 42        else:
 43            self.myparam.write_param(
 44                os.path.join(
 45                    os.path.expanduser("~"), ".smashbox", "default_param.yaml"
 46                )
 47            )
 48
 49    def help(self):
 50        """Display help..."""
 51
 52        print("! Welcome to SmashBox !")
 53        print(
 54            "First of all, you must configure main parameters stored in 'myparam' attribute."
 55        )
 56        print(
 57            " - self.myparam.list_param() : list all parameters to configure in self.myparam.param."
 58        )
 59        print(
 60            " - self.myparam.set_param(attr, value) : set value to attribute attr."
 61        )
 62        print(
 63            " - self.myparam.get_param(attr) : get the value of attribute attr."
 64        )
 65        print(
 66            " - self.myparam.list_asset_files() : list data available with SmashBox."
 67        )
 68        print(
 69            " - self.myparam.param : attribute which contains all parameters."
 70        )
 71        print("")
 72        print("When ready, you will able to create a new model attribute:")
 73        print(" - self.newmodel('mymodel')")
 74        print("")
 75        print(
 76            "After the model 'mymodel' has been created, you can adjust the model setup 'self.mymodel.mysetup':"
 77        )
 78        print(
 79            " - self.mymodel.mysetup.setup: dictionnary which contain the setup"
 80        )
 81        print(
 82            " - self.mymodel.mysetup.list_available_setup(): list preconfigured and ready to use setup in SmashBox"
 83        )
 84        print(
 85            " - self.mymodel.mysetup.update_setup(dict): update the smash setup with the input dictionary dict."
 86        )
 87        print("")
 88        print(
 89            "When ready, you will be able to create the mesh, the Smash model and run a simulation:"
 90        )
 91        print(" - self.mymodel.make_mesh()")
 92        print(" - self.mymodel.make_model()")
 93
 94    def newmodel(self, name="mymodel"):
 95        """
 96        Create a new model attribute. This attribute will handle meshing, hydrological modelisation, plot and stattistics.
 97
 98        Parameters
 99        ----------
100
101        name : str
102            The name of the attribute.
103
104        Examples
105        --------
106
107        >>> es=smashbox.SmashBox()
108        >>> sb.newmodel("RealCollobrier")
109
110        """
111
112        name = name.replace(" ", "_")
113
114        if not hasattr(self, name):
115
116            setattr(self, name, model.model(name, self.myparam))
117
118        else:
119            raise ValueError(
120                f"Error: Cannot create model '{name}', model attribute '{name}' already exist"
121            )
122
123        if not hasattr(self, "multimodel_statistics"):
124
125            setattr(
126                self,
127                "multimodel_statistics",
128                multimodel_statistics.multimodel_statistics(self),
129            )
130
131    def import_smash_model(
132        self, name="mymodel", model=None, load_catchment_polygon=False
133    ):
134        """Import a smash model inside a smashbox container to use plot and stats capabilities.
135
136        :param name: name of the smabox model, defaults to "mymodel"
137        :type name: str
138        :param model: A smash model from smash.Model(), defaults to None
139        :type model: smash.Model()
140        :param load_catchment_polygon: load polygon data, defaults to False
141        :type load_catchment_polygon: bool
142
143        :rtype: None
144        """
145        self.newmodel(name)
146        sb_model = getattr(self, name)
147        sb_model.mysetup.update_setup(
148            pyhdf5_handler.read_object_as_dict(model.setup)
149        )
150        sb_model.mymesh.mesh = pyhdf5_handler.read_object_as_dict(model.mesh)
151        if load_catchment_polygon:
152            sb_model.mymesh.load_catchment_polygon(self.myparam.param)
153        sb_model.mysmashmodel.smash = model
154
155    def delmodel(self, modelname):
156        """
157        Delete a model attribute.
158
159        Parameters
160        ----------
161
162        modelname : str
163            The name of the attribute to delete.
164
165        Examples
166        --------
167
168        >>> es=smashbox.SmashBox()
169        >>> sb.newmodel("RealCollobrier")
170        >>> sb.delmodel("RealCollobrier")
171
172        """
173        if hasattr(self, modelname) and isinstance(
174            getattr(self, modelname), model.model
175        ):
176            delattr(self, modelname)
177
178        else:
179
180            raise ValueError(f"Error: {modelname} is not a valid model name.")
181
182    def copymodel(
183        self, modelsource, modelname, copy_smash_model=True, only=None
184    ):
185        """
186        Copy a model container
187
188        Parameters
189        ----------
190
191        modelsource : str
192            The name of the source model attribute
193        modelname : str
194            The name of the new model attribute.
195
196        Examples
197        --------
198
199        >>> es=smashbox.SmashBox()
200        >>> sb.newmodel("RealCollobrier")
201        >>> sb.copymodel("RealCollobrier", RealCollobrier2")
202        """
203
204        if only is None:
205            only = [
206                "mysmashmodel",
207                "warmup_model",
208                "optimize_model",
209                "validation_model",
210            ]
211
212        if not hasattr(self, modelsource):
213            raise ValueError(
214                f"Error: Source model '{modelsource}' does not exist"
215            )
216
217        if not hasattr(self, modelname):
218
219            self.newmodel(modelname)
220
221            source = getattr(self, modelsource)
222            destination = getattr(self, modelname)
223
224            setattr(
225                destination,
226                "_myparam",
227                copy.deepcopy(getattr(source, "_myparam")),
228            )
229            setattr(
230                destination, "mymesh", copy.deepcopy(getattr(source, "mymesh"))
231            )
232            setattr(
233                destination,
234                "mysetup",
235                copy.deepcopy(getattr(source, "mysetup")),
236            )
237
238            if copy_smash_model:
239
240                setup_update = {
241                    "read_prcp": False,
242                    "read_pet": False,
243                    "read_snow": False,
244                    "read_qobs": False,
245                    "read_temp": False,
246                }
247                destination.mysetup.update_setup(setup_update)
248
249                if (
250                    "mysmashmodel" in only
251                    and source.mysmashmodel.smash is not None
252                ):
253                    setattr(
254                        destination.mysmashmodel,
255                        "smash",
256                        source.mysmashmodel.smash.copy(),
257                    )
258                    for key, value in setup_update.items():
259                        setattr(
260                            destination.mysmashmodel.smash.setup, key, value
261                        )
262
263                if (
264                    "warmup_model" in only
265                    and source.warmup_model.smash is not None
266                ):
267                    setattr(
268                        destination.warmup_model,
269                        "smash",
270                        source.warmup_model.smash.copy(),
271                    )
272                    for key, value in setup_update.items():
273                        setattr(
274                            destination.warmup_model.smash.setup, key, value
275                        )
276
277                if (
278                    "optimize_model" in only
279                    and source.optimize_model.smash is not None
280                ):
281                    setattr(
282                        destination.optimize_model,
283                        "smash",
284                        source.optimize_model.smash.copy(),
285                    )
286                    for key, value in setup_update.items():
287                        setattr(
288                            destination.optimize_model.smash.setup, key, value
289                        )
290
291                if (
292                    "validation_model" in only
293                    and source.validation_model.smash is not None
294                ):
295                    setattr(
296                        destination,
297                        "validation_model",
298                        source.validation_model.smash.copy(),
299                    )
300                    for key, value in setup_update.items():
301                        setattr(
302                            destination.validation_model.smash.setup,
303                            key,
304                            value,
305                        )
306
307                if hasattr(source, "_fstates"):
308                    setattr(
309                        destination,
310                        "_fstates",
311                        copy.deepcopy(getattr(source, "_fstates")),
312                    )
313                if hasattr(source, "_istates"):
314                    setattr(
315                        destination,
316                        "_istates",
317                        copy.deepcopy(getattr(source, "_istates")),
318                    )
319                if hasattr(source, "_myatmos_data_connector"):
320                    setattr(
321                        destination,
322                        "_myatmos_data_connector",
323                        copy.deepcopy(
324                            getattr(source, "_myatmos_data_connector")
325                        ),
326                    )
327
328        else:
329            raise ValueError(
330                f"Error: Cannot copy model '{modelsource}', model attribute '{modelname}' already exist"
331            )
332
333        # get new model object
334        # mynewmodel = getattr(self, modelname)
335
336        # reset attributes
337        # mynewmodel.mysmashmodel = None
338        # mynewmodel.extra_smash_results = None
339        # mynewmodel._fstates = None
340        # mynewmodel._istates = None
341        # mynewmodel._myatmos_data_connector = None
342        # mynewmodel.warmup_model = None
343        # mynewmodel.mystats = mystats.mystats(self)
344        # mynewmodel.myplot = myplot.myplot(self)
345
346    def copymodeldata(self, modelsource, modelname):
347        """
348        Copy a model data
349
350        Parameters
351        ----------
352
353        modelsource : str
354            The name of the source model attribute
355        modelname : str
356            The name of the new model attribute.
357
358        Examples
359        --------
360
361        >>> es=smashbox.SmashBox()
362        >>> sb.newmodel("RealCollobrier")
363        >>> sb.copymodeldata("RealCollobrier", RealCollobrier2")
364        """
365        if not hasattr(self, modelsource):
366            raise ValueError(
367                f"Error: Source model '{modelsource}' does not exist"
368            )
369
370        if not hasattr(self, modelname):
371            raise ValueError(
372                f"Error: destination model '{modelname}' does not exist"
373            )
374
375        source = getattr(self, modelsource)
376        destination = getattr(self, modelname)
377
378        if (
379            source.mysmashmodel is not None
380            and destination.mysmashmodel is not None
381        ):
382            destination.mysmashmodel.smash.atmos_data = (
383                source.mysmashmodel.smash.atmos_data.copy()
384            )
385            destination.mysmashmodel.smash.response_data = (
386                source.mysmashmodel.smash.response_data.copy()
387            )
388        if (
389            source.warmup_model is not None
390            and destination.warmup_model is not None
391        ):
392            destination.warmup_model.smash.atmos_data = (
393                source.warmup_model.smash.atmos_data.copy()
394            )
395            destination.warmup_model.smash.response_data = (
396                source.warmup_model.smash.response_data.copy()
397            )
398        if (
399            source.optimize_model is not None
400            and destination.optimize_model is not None
401        ):
402            destination.optimize_model.smash.atmos_data = (
403                source.optimize_model.smash.atmos_data.copy()
404            )
405            destination.optimize_model.smash.response_data = (
406                source.optimize_model.smash.response_data.copy()
407            )
408        if (
409            source.validation_model is not None
410            and destination.validation_model is not None
411        ):
412            destination.validation_model.smash.atmos_data = (
413                source.validation_model.smash.atmos_data.copy()
414            )
415            destination.validation_model.smash.response_data = (
416                source.validation_model.smash.response_data.copy()
417            )
418
419    def load_containers(
420        self, path, only=None, exclude=None, load_catchment_polygon=True
421    ):
422
423        subdir_list = os.listdir(path)
424
425        if only is not None:
426            for d in only:
427                if not d in subdir_list:
428                    raise ValueError(f"{d} does not exist in {path}")
429
430            subdir_list = only
431
432        if exclude is not None:
433            for d in exclude:
434                if d in subdir_list:
435                    subdir_list.remove(d)
436
437        for subdir in subdir_list:
438            box = pyhdf5_handler.read_hdf5file_as_dict(
439                os.path.join(path, subdir, "smashbox.hdf5")
440            )
441
442            mysmashmodel = None
443            warmup_model = None
444            optimize_model = None
445            validation_model = None
446
447            if os.path.exists(os.path.join(path, subdir, "mysmashmodel.hdf5")):
448                mysmashmodel = smash.io.read_model(
449                    os.path.join(path, subdir, "mysmashmodel.hdf5")
450                )
451            if os.path.exists(os.path.join(path, subdir, "warmup_model.hdf5")):
452                warmup_model = smash.io.read_model(
453                    os.path.join(path, subdir, "warmup_model.hdf5")
454                )
455            if os.path.exists(
456                os.path.join(path, subdir, "optimize_model.hdf5")
457            ):
458                optimize_model = smash.io.read_model(
459                    os.path.join(path, subdir, "optimize_model.hdf5")
460                )
461            if os.path.exists(
462                os.path.join(path, subdir, "validation_model.hdf5")
463            ):
464                validation_model = smash.io.read_model(
465                    os.path.join(path, subdir, "validation_model.hdf5")
466                )
467
468            for key, value in box["param"].items():
469                if getattr(self.myparam.param, key) is None:
470                    self.myparam.set_param(key, value)
471                else:
472                    dtype = type(getattr(self.myparam.param, key))
473                    try:
474                        converted_value = dtype(value)
475                        self.myparam.set_param(key, converted_value)
476                    except (ValueError, TypeError) as e:
477                        try:
478                            self.myparam.set_param(key, value)
479                        except (ValueError, TypeError) as ee:
480                            print(
481                                f"Type error for {key}: {dtype}/{type(value)} - {e}"
482                            )
483                            print(
484                                f"Can't import {key}: {dtype}/{type(value)} - {ee}"
485                            )
486
487            self.newmodel(subdir)
488
489            container = getattr(self, subdir)
490
491            for key, value in box["mysetup"]["setup"].items():
492                container.mysetup.set_setup(key, value)
493
494            container.mymesh.mesh = box["mymesh"]["mesh"]
495
496            # getting models extra result and stats
497            for model in [
498                "mysmashmodel",
499                "warmup_model",
500                "optimize_model",
501                "validation_model",
502            ]:
503
504                if model in box:
505                    structure = pyhdf5_handler.src.object_handler.generate_dict_structure(
506                        box[model], include_method=False
507                    )
508                    pyhdf5_handler.src.object_handler.map_dict_to_object(
509                        structure,
510                        box[model],
511                        getattr(container, model),
512                    )
513
514            setattr(container.mysmashmodel, "smash", mysmashmodel)
515            setattr(container.warmup_model, "smash", warmup_model)
516            setattr(container.optimize_model, "smash", optimize_model)
517            setattr(container.validation_model, "smash", validation_model)
518
519            container._myparam = copy.deepcopy(self.myparam)
520            if load_catchment_polygon:
521                container.mymesh.load_catchment_polygon(
522                    param=container._myparam.param
523                )
524
525    # def load_pickle_containers(self, path, only=None, exclude=None):
526
527    #     subdir_list = os.listdir(path)
528
529    #     if only is not None:
530    #         for d in only:
531    #             if not os.path.isdir(d):
532    #                 raise ValueError()
533
534    #         subdir_list = only
535    #     if exclude is not None:
536    #         for d in exclude:
537    #             if os.path.isdir(d):
538    #                 subdir_list.remove(d)
539
540    #     for subdir in subdir_list:
541
542    #         mysmashmodel = None
543    #         warmup_model = None
544    #         optimize_model = None
545
546    #         if os.path.exists(os.path.join(path, subdir, "mysmashmodel.hdf5")):
547    #             mysmashmodel = smash.io.read_model(
548    #                 os.path.join(path, subdir, "mysmashmodel.hdf5")
549    #             )
550    #         if os.path.exists(os.path.join(path, subdir, "warmup_model.hdf5")):
551    #             warmup_model = smash.io.read_model(
552    #                 os.path.join(path, subdir, "warmup_model.hdf5")
553    #             )
554    #         if os.path.exists(os.path.join(path, subdir, "optimize_model.hdf5")):
555    #             optimize_model = smash.io.read_model(
556    #                 os.path.join(path, subdir, "optimize_model.hdf5")
557    #             )
558
559    #         self.newmodel(subdir)
560    #         container = getattr(self, subdir)
561
562    #         for file in glob.glob("*.pkl"):
563    #             key = os.path.basename(file).split(".")[0]
564    #             obj = pickle.load(file)
565    #             setattr(container, key, obj)
566
567    #         container.mysmashmodel = mysmashmodel
568    #         container.warmup_model = warmup_model
569    #         container.optimize_model = optimize_model
class SmashBox:
 18class SmashBox:
 19    """
 20    Main class which store main parameters 'myparam' and functions to create or delete
 21     models.
 22    """
 23
 24    def __init__(self):
 25
 26        if not os.path.exists(
 27            os.path.join(os.path.expanduser("~"), ".smashbox", "asset")
 28        ):
 29            shutil.copytree(
 30                os.path.join(smashbox.__path__[0], "asset"),
 31                os.path.join(os.path.expanduser("~"), ".smashbox", "asset"),
 32            )
 33
 34        self.myparam = param.param()
 35        if os.path.exists(
 36            os.path.join(os.path.expanduser("~"), ".smashbox", "param.yaml")
 37        ):
 38            self.myparam.load_param(
 39                os.path.join(
 40                    os.path.expanduser("~"), ".smashbox", "default_param.yaml"
 41                )
 42            )
 43        else:
 44            self.myparam.write_param(
 45                os.path.join(
 46                    os.path.expanduser("~"), ".smashbox", "default_param.yaml"
 47                )
 48            )
 49
 50    def help(self):
 51        """Display help..."""
 52
 53        print("! Welcome to SmashBox !")
 54        print(
 55            "First of all, you must configure main parameters stored in 'myparam' attribute."
 56        )
 57        print(
 58            " - self.myparam.list_param() : list all parameters to configure in self.myparam.param."
 59        )
 60        print(
 61            " - self.myparam.set_param(attr, value) : set value to attribute attr."
 62        )
 63        print(
 64            " - self.myparam.get_param(attr) : get the value of attribute attr."
 65        )
 66        print(
 67            " - self.myparam.list_asset_files() : list data available with SmashBox."
 68        )
 69        print(
 70            " - self.myparam.param : attribute which contains all parameters."
 71        )
 72        print("")
 73        print("When ready, you will able to create a new model attribute:")
 74        print(" - self.newmodel('mymodel')")
 75        print("")
 76        print(
 77            "After the model 'mymodel' has been created, you can adjust the model setup 'self.mymodel.mysetup':"
 78        )
 79        print(
 80            " - self.mymodel.mysetup.setup: dictionnary which contain the setup"
 81        )
 82        print(
 83            " - self.mymodel.mysetup.list_available_setup(): list preconfigured and ready to use setup in SmashBox"
 84        )
 85        print(
 86            " - self.mymodel.mysetup.update_setup(dict): update the smash setup with the input dictionary dict."
 87        )
 88        print("")
 89        print(
 90            "When ready, you will be able to create the mesh, the Smash model and run a simulation:"
 91        )
 92        print(" - self.mymodel.make_mesh()")
 93        print(" - self.mymodel.make_model()")
 94
 95    def newmodel(self, name="mymodel"):
 96        """
 97        Create a new model attribute. This attribute will handle meshing, hydrological modelisation, plot and stattistics.
 98
 99        Parameters
100        ----------
101
102        name : str
103            The name of the attribute.
104
105        Examples
106        --------
107
108        >>> es=smashbox.SmashBox()
109        >>> sb.newmodel("RealCollobrier")
110
111        """
112
113        name = name.replace(" ", "_")
114
115        if not hasattr(self, name):
116
117            setattr(self, name, model.model(name, self.myparam))
118
119        else:
120            raise ValueError(
121                f"Error: Cannot create model '{name}', model attribute '{name}' already exist"
122            )
123
124        if not hasattr(self, "multimodel_statistics"):
125
126            setattr(
127                self,
128                "multimodel_statistics",
129                multimodel_statistics.multimodel_statistics(self),
130            )
131
132    def import_smash_model(
133        self, name="mymodel", model=None, load_catchment_polygon=False
134    ):
135        """Import a smash model inside a smashbox container to use plot and stats capabilities.
136
137        :param name: name of the smabox model, defaults to "mymodel"
138        :type name: str
139        :param model: A smash model from smash.Model(), defaults to None
140        :type model: smash.Model()
141        :param load_catchment_polygon: load polygon data, defaults to False
142        :type load_catchment_polygon: bool
143
144        :rtype: None
145        """
146        self.newmodel(name)
147        sb_model = getattr(self, name)
148        sb_model.mysetup.update_setup(
149            pyhdf5_handler.read_object_as_dict(model.setup)
150        )
151        sb_model.mymesh.mesh = pyhdf5_handler.read_object_as_dict(model.mesh)
152        if load_catchment_polygon:
153            sb_model.mymesh.load_catchment_polygon(self.myparam.param)
154        sb_model.mysmashmodel.smash = model
155
156    def delmodel(self, modelname):
157        """
158        Delete a model attribute.
159
160        Parameters
161        ----------
162
163        modelname : str
164            The name of the attribute to delete.
165
166        Examples
167        --------
168
169        >>> es=smashbox.SmashBox()
170        >>> sb.newmodel("RealCollobrier")
171        >>> sb.delmodel("RealCollobrier")
172
173        """
174        if hasattr(self, modelname) and isinstance(
175            getattr(self, modelname), model.model
176        ):
177            delattr(self, modelname)
178
179        else:
180
181            raise ValueError(f"Error: {modelname} is not a valid model name.")
182
183    def copymodel(
184        self, modelsource, modelname, copy_smash_model=True, only=None
185    ):
186        """
187        Copy a model container
188
189        Parameters
190        ----------
191
192        modelsource : str
193            The name of the source model attribute
194        modelname : str
195            The name of the new model attribute.
196
197        Examples
198        --------
199
200        >>> es=smashbox.SmashBox()
201        >>> sb.newmodel("RealCollobrier")
202        >>> sb.copymodel("RealCollobrier", RealCollobrier2")
203        """
204
205        if only is None:
206            only = [
207                "mysmashmodel",
208                "warmup_model",
209                "optimize_model",
210                "validation_model",
211            ]
212
213        if not hasattr(self, modelsource):
214            raise ValueError(
215                f"Error: Source model '{modelsource}' does not exist"
216            )
217
218        if not hasattr(self, modelname):
219
220            self.newmodel(modelname)
221
222            source = getattr(self, modelsource)
223            destination = getattr(self, modelname)
224
225            setattr(
226                destination,
227                "_myparam",
228                copy.deepcopy(getattr(source, "_myparam")),
229            )
230            setattr(
231                destination, "mymesh", copy.deepcopy(getattr(source, "mymesh"))
232            )
233            setattr(
234                destination,
235                "mysetup",
236                copy.deepcopy(getattr(source, "mysetup")),
237            )
238
239            if copy_smash_model:
240
241                setup_update = {
242                    "read_prcp": False,
243                    "read_pet": False,
244                    "read_snow": False,
245                    "read_qobs": False,
246                    "read_temp": False,
247                }
248                destination.mysetup.update_setup(setup_update)
249
250                if (
251                    "mysmashmodel" in only
252                    and source.mysmashmodel.smash is not None
253                ):
254                    setattr(
255                        destination.mysmashmodel,
256                        "smash",
257                        source.mysmashmodel.smash.copy(),
258                    )
259                    for key, value in setup_update.items():
260                        setattr(
261                            destination.mysmashmodel.smash.setup, key, value
262                        )
263
264                if (
265                    "warmup_model" in only
266                    and source.warmup_model.smash is not None
267                ):
268                    setattr(
269                        destination.warmup_model,
270                        "smash",
271                        source.warmup_model.smash.copy(),
272                    )
273                    for key, value in setup_update.items():
274                        setattr(
275                            destination.warmup_model.smash.setup, key, value
276                        )
277
278                if (
279                    "optimize_model" in only
280                    and source.optimize_model.smash is not None
281                ):
282                    setattr(
283                        destination.optimize_model,
284                        "smash",
285                        source.optimize_model.smash.copy(),
286                    )
287                    for key, value in setup_update.items():
288                        setattr(
289                            destination.optimize_model.smash.setup, key, value
290                        )
291
292                if (
293                    "validation_model" in only
294                    and source.validation_model.smash is not None
295                ):
296                    setattr(
297                        destination,
298                        "validation_model",
299                        source.validation_model.smash.copy(),
300                    )
301                    for key, value in setup_update.items():
302                        setattr(
303                            destination.validation_model.smash.setup,
304                            key,
305                            value,
306                        )
307
308                if hasattr(source, "_fstates"):
309                    setattr(
310                        destination,
311                        "_fstates",
312                        copy.deepcopy(getattr(source, "_fstates")),
313                    )
314                if hasattr(source, "_istates"):
315                    setattr(
316                        destination,
317                        "_istates",
318                        copy.deepcopy(getattr(source, "_istates")),
319                    )
320                if hasattr(source, "_myatmos_data_connector"):
321                    setattr(
322                        destination,
323                        "_myatmos_data_connector",
324                        copy.deepcopy(
325                            getattr(source, "_myatmos_data_connector")
326                        ),
327                    )
328
329        else:
330            raise ValueError(
331                f"Error: Cannot copy model '{modelsource}', model attribute '{modelname}' already exist"
332            )
333
334        # get new model object
335        # mynewmodel = getattr(self, modelname)
336
337        # reset attributes
338        # mynewmodel.mysmashmodel = None
339        # mynewmodel.extra_smash_results = None
340        # mynewmodel._fstates = None
341        # mynewmodel._istates = None
342        # mynewmodel._myatmos_data_connector = None
343        # mynewmodel.warmup_model = None
344        # mynewmodel.mystats = mystats.mystats(self)
345        # mynewmodel.myplot = myplot.myplot(self)
346
347    def copymodeldata(self, modelsource, modelname):
348        """
349        Copy a model data
350
351        Parameters
352        ----------
353
354        modelsource : str
355            The name of the source model attribute
356        modelname : str
357            The name of the new model attribute.
358
359        Examples
360        --------
361
362        >>> es=smashbox.SmashBox()
363        >>> sb.newmodel("RealCollobrier")
364        >>> sb.copymodeldata("RealCollobrier", RealCollobrier2")
365        """
366        if not hasattr(self, modelsource):
367            raise ValueError(
368                f"Error: Source model '{modelsource}' does not exist"
369            )
370
371        if not hasattr(self, modelname):
372            raise ValueError(
373                f"Error: destination model '{modelname}' does not exist"
374            )
375
376        source = getattr(self, modelsource)
377        destination = getattr(self, modelname)
378
379        if (
380            source.mysmashmodel is not None
381            and destination.mysmashmodel is not None
382        ):
383            destination.mysmashmodel.smash.atmos_data = (
384                source.mysmashmodel.smash.atmos_data.copy()
385            )
386            destination.mysmashmodel.smash.response_data = (
387                source.mysmashmodel.smash.response_data.copy()
388            )
389        if (
390            source.warmup_model is not None
391            and destination.warmup_model is not None
392        ):
393            destination.warmup_model.smash.atmos_data = (
394                source.warmup_model.smash.atmos_data.copy()
395            )
396            destination.warmup_model.smash.response_data = (
397                source.warmup_model.smash.response_data.copy()
398            )
399        if (
400            source.optimize_model is not None
401            and destination.optimize_model is not None
402        ):
403            destination.optimize_model.smash.atmos_data = (
404                source.optimize_model.smash.atmos_data.copy()
405            )
406            destination.optimize_model.smash.response_data = (
407                source.optimize_model.smash.response_data.copy()
408            )
409        if (
410            source.validation_model is not None
411            and destination.validation_model is not None
412        ):
413            destination.validation_model.smash.atmos_data = (
414                source.validation_model.smash.atmos_data.copy()
415            )
416            destination.validation_model.smash.response_data = (
417                source.validation_model.smash.response_data.copy()
418            )
419
420    def load_containers(
421        self, path, only=None, exclude=None, load_catchment_polygon=True
422    ):
423
424        subdir_list = os.listdir(path)
425
426        if only is not None:
427            for d in only:
428                if not d in subdir_list:
429                    raise ValueError(f"{d} does not exist in {path}")
430
431            subdir_list = only
432
433        if exclude is not None:
434            for d in exclude:
435                if d in subdir_list:
436                    subdir_list.remove(d)
437
438        for subdir in subdir_list:
439            box = pyhdf5_handler.read_hdf5file_as_dict(
440                os.path.join(path, subdir, "smashbox.hdf5")
441            )
442
443            mysmashmodel = None
444            warmup_model = None
445            optimize_model = None
446            validation_model = None
447
448            if os.path.exists(os.path.join(path, subdir, "mysmashmodel.hdf5")):
449                mysmashmodel = smash.io.read_model(
450                    os.path.join(path, subdir, "mysmashmodel.hdf5")
451                )
452            if os.path.exists(os.path.join(path, subdir, "warmup_model.hdf5")):
453                warmup_model = smash.io.read_model(
454                    os.path.join(path, subdir, "warmup_model.hdf5")
455                )
456            if os.path.exists(
457                os.path.join(path, subdir, "optimize_model.hdf5")
458            ):
459                optimize_model = smash.io.read_model(
460                    os.path.join(path, subdir, "optimize_model.hdf5")
461                )
462            if os.path.exists(
463                os.path.join(path, subdir, "validation_model.hdf5")
464            ):
465                validation_model = smash.io.read_model(
466                    os.path.join(path, subdir, "validation_model.hdf5")
467                )
468
469            for key, value in box["param"].items():
470                if getattr(self.myparam.param, key) is None:
471                    self.myparam.set_param(key, value)
472                else:
473                    dtype = type(getattr(self.myparam.param, key))
474                    try:
475                        converted_value = dtype(value)
476                        self.myparam.set_param(key, converted_value)
477                    except (ValueError, TypeError) as e:
478                        try:
479                            self.myparam.set_param(key, value)
480                        except (ValueError, TypeError) as ee:
481                            print(
482                                f"Type error for {key}: {dtype}/{type(value)} - {e}"
483                            )
484                            print(
485                                f"Can't import {key}: {dtype}/{type(value)} - {ee}"
486                            )
487
488            self.newmodel(subdir)
489
490            container = getattr(self, subdir)
491
492            for key, value in box["mysetup"]["setup"].items():
493                container.mysetup.set_setup(key, value)
494
495            container.mymesh.mesh = box["mymesh"]["mesh"]
496
497            # getting models extra result and stats
498            for model in [
499                "mysmashmodel",
500                "warmup_model",
501                "optimize_model",
502                "validation_model",
503            ]:
504
505                if model in box:
506                    structure = pyhdf5_handler.src.object_handler.generate_dict_structure(
507                        box[model], include_method=False
508                    )
509                    pyhdf5_handler.src.object_handler.map_dict_to_object(
510                        structure,
511                        box[model],
512                        getattr(container, model),
513                    )
514
515            setattr(container.mysmashmodel, "smash", mysmashmodel)
516            setattr(container.warmup_model, "smash", warmup_model)
517            setattr(container.optimize_model, "smash", optimize_model)
518            setattr(container.validation_model, "smash", validation_model)
519
520            container._myparam = copy.deepcopy(self.myparam)
521            if load_catchment_polygon:
522                container.mymesh.load_catchment_polygon(
523                    param=container._myparam.param
524                )
525
526    # def load_pickle_containers(self, path, only=None, exclude=None):
527
528    #     subdir_list = os.listdir(path)
529
530    #     if only is not None:
531    #         for d in only:
532    #             if not os.path.isdir(d):
533    #                 raise ValueError()
534
535    #         subdir_list = only
536    #     if exclude is not None:
537    #         for d in exclude:
538    #             if os.path.isdir(d):
539    #                 subdir_list.remove(d)
540
541    #     for subdir in subdir_list:
542
543    #         mysmashmodel = None
544    #         warmup_model = None
545    #         optimize_model = None
546
547    #         if os.path.exists(os.path.join(path, subdir, "mysmashmodel.hdf5")):
548    #             mysmashmodel = smash.io.read_model(
549    #                 os.path.join(path, subdir, "mysmashmodel.hdf5")
550    #             )
551    #         if os.path.exists(os.path.join(path, subdir, "warmup_model.hdf5")):
552    #             warmup_model = smash.io.read_model(
553    #                 os.path.join(path, subdir, "warmup_model.hdf5")
554    #             )
555    #         if os.path.exists(os.path.join(path, subdir, "optimize_model.hdf5")):
556    #             optimize_model = smash.io.read_model(
557    #                 os.path.join(path, subdir, "optimize_model.hdf5")
558    #             )
559
560    #         self.newmodel(subdir)
561    #         container = getattr(self, subdir)
562
563    #         for file in glob.glob("*.pkl"):
564    #             key = os.path.basename(file).split(".")[0]
565    #             obj = pickle.load(file)
566    #             setattr(container, key, obj)
567
568    #         container.mysmashmodel = mysmashmodel
569    #         container.warmup_model = warmup_model
570    #         container.optimize_model = optimize_model

Main class which store main parameters 'myparam' and functions to create or delete models.

myparam
def help(self):
50    def help(self):
51        """Display help..."""
52
53        print("! Welcome to SmashBox !")
54        print(
55            "First of all, you must configure main parameters stored in 'myparam' attribute."
56        )
57        print(
58            " - self.myparam.list_param() : list all parameters to configure in self.myparam.param."
59        )
60        print(
61            " - self.myparam.set_param(attr, value) : set value to attribute attr."
62        )
63        print(
64            " - self.myparam.get_param(attr) : get the value of attribute attr."
65        )
66        print(
67            " - self.myparam.list_asset_files() : list data available with SmashBox."
68        )
69        print(
70            " - self.myparam.param : attribute which contains all parameters."
71        )
72        print("")
73        print("When ready, you will able to create a new model attribute:")
74        print(" - self.newmodel('mymodel')")
75        print("")
76        print(
77            "After the model 'mymodel' has been created, you can adjust the model setup 'self.mymodel.mysetup':"
78        )
79        print(
80            " - self.mymodel.mysetup.setup: dictionnary which contain the setup"
81        )
82        print(
83            " - self.mymodel.mysetup.list_available_setup(): list preconfigured and ready to use setup in SmashBox"
84        )
85        print(
86            " - self.mymodel.mysetup.update_setup(dict): update the smash setup with the input dictionary dict."
87        )
88        print("")
89        print(
90            "When ready, you will be able to create the mesh, the Smash model and run a simulation:"
91        )
92        print(" - self.mymodel.make_mesh()")
93        print(" - self.mymodel.make_model()")

Display help...

def newmodel(self, name='mymodel'):
 95    def newmodel(self, name="mymodel"):
 96        """
 97        Create a new model attribute. This attribute will handle meshing, hydrological modelisation, plot and stattistics.
 98
 99        Parameters
100        ----------
101
102        name : str
103            The name of the attribute.
104
105        Examples
106        --------
107
108        >>> es=smashbox.SmashBox()
109        >>> sb.newmodel("RealCollobrier")
110
111        """
112
113        name = name.replace(" ", "_")
114
115        if not hasattr(self, name):
116
117            setattr(self, name, model.model(name, self.myparam))
118
119        else:
120            raise ValueError(
121                f"Error: Cannot create model '{name}', model attribute '{name}' already exist"
122            )
123
124        if not hasattr(self, "multimodel_statistics"):
125
126            setattr(
127                self,
128                "multimodel_statistics",
129                multimodel_statistics.multimodel_statistics(self),
130            )

Create a new model attribute. This attribute will handle meshing, hydrological modelisation, plot and stattistics.

Parameters

name : str The name of the attribute.

Examples

>>> es=smashbox.SmashBox()
>>> sb.newmodel("RealCollobrier")
def import_smash_model(self, name='mymodel', model=None, load_catchment_polygon=False):
132    def import_smash_model(
133        self, name="mymodel", model=None, load_catchment_polygon=False
134    ):
135        """Import a smash model inside a smashbox container to use plot and stats capabilities.
136
137        :param name: name of the smabox model, defaults to "mymodel"
138        :type name: str
139        :param model: A smash model from smash.Model(), defaults to None
140        :type model: smash.Model()
141        :param load_catchment_polygon: load polygon data, defaults to False
142        :type load_catchment_polygon: bool
143
144        :rtype: None
145        """
146        self.newmodel(name)
147        sb_model = getattr(self, name)
148        sb_model.mysetup.update_setup(
149            pyhdf5_handler.read_object_as_dict(model.setup)
150        )
151        sb_model.mymesh.mesh = pyhdf5_handler.read_object_as_dict(model.mesh)
152        if load_catchment_polygon:
153            sb_model.mymesh.load_catchment_polygon(self.myparam.param)
154        sb_model.mysmashmodel.smash = model

Import a smash model inside a smashbox container to use plot and stats capabilities.

Parameters
  • name: name of the smabox model, defaults to "mymodel"
  • model: A smash model from smash.Model(), defaults to None
  • load_catchment_polygon: load polygon data, defaults to False
def delmodel(self, modelname):
156    def delmodel(self, modelname):
157        """
158        Delete a model attribute.
159
160        Parameters
161        ----------
162
163        modelname : str
164            The name of the attribute to delete.
165
166        Examples
167        --------
168
169        >>> es=smashbox.SmashBox()
170        >>> sb.newmodel("RealCollobrier")
171        >>> sb.delmodel("RealCollobrier")
172
173        """
174        if hasattr(self, modelname) and isinstance(
175            getattr(self, modelname), model.model
176        ):
177            delattr(self, modelname)
178
179        else:
180
181            raise ValueError(f"Error: {modelname} is not a valid model name.")

Delete a model attribute.

Parameters

modelname : str The name of the attribute to delete.

Examples

>>> es=smashbox.SmashBox()
>>> sb.newmodel("RealCollobrier")
>>> sb.delmodel("RealCollobrier")
def copymodel(self, modelsource, modelname, copy_smash_model=True, only=None):
183    def copymodel(
184        self, modelsource, modelname, copy_smash_model=True, only=None
185    ):
186        """
187        Copy a model container
188
189        Parameters
190        ----------
191
192        modelsource : str
193            The name of the source model attribute
194        modelname : str
195            The name of the new model attribute.
196
197        Examples
198        --------
199
200        >>> es=smashbox.SmashBox()
201        >>> sb.newmodel("RealCollobrier")
202        >>> sb.copymodel("RealCollobrier", RealCollobrier2")
203        """
204
205        if only is None:
206            only = [
207                "mysmashmodel",
208                "warmup_model",
209                "optimize_model",
210                "validation_model",
211            ]
212
213        if not hasattr(self, modelsource):
214            raise ValueError(
215                f"Error: Source model '{modelsource}' does not exist"
216            )
217
218        if not hasattr(self, modelname):
219
220            self.newmodel(modelname)
221
222            source = getattr(self, modelsource)
223            destination = getattr(self, modelname)
224
225            setattr(
226                destination,
227                "_myparam",
228                copy.deepcopy(getattr(source, "_myparam")),
229            )
230            setattr(
231                destination, "mymesh", copy.deepcopy(getattr(source, "mymesh"))
232            )
233            setattr(
234                destination,
235                "mysetup",
236                copy.deepcopy(getattr(source, "mysetup")),
237            )
238
239            if copy_smash_model:
240
241                setup_update = {
242                    "read_prcp": False,
243                    "read_pet": False,
244                    "read_snow": False,
245                    "read_qobs": False,
246                    "read_temp": False,
247                }
248                destination.mysetup.update_setup(setup_update)
249
250                if (
251                    "mysmashmodel" in only
252                    and source.mysmashmodel.smash is not None
253                ):
254                    setattr(
255                        destination.mysmashmodel,
256                        "smash",
257                        source.mysmashmodel.smash.copy(),
258                    )
259                    for key, value in setup_update.items():
260                        setattr(
261                            destination.mysmashmodel.smash.setup, key, value
262                        )
263
264                if (
265                    "warmup_model" in only
266                    and source.warmup_model.smash is not None
267                ):
268                    setattr(
269                        destination.warmup_model,
270                        "smash",
271                        source.warmup_model.smash.copy(),
272                    )
273                    for key, value in setup_update.items():
274                        setattr(
275                            destination.warmup_model.smash.setup, key, value
276                        )
277
278                if (
279                    "optimize_model" in only
280                    and source.optimize_model.smash is not None
281                ):
282                    setattr(
283                        destination.optimize_model,
284                        "smash",
285                        source.optimize_model.smash.copy(),
286                    )
287                    for key, value in setup_update.items():
288                        setattr(
289                            destination.optimize_model.smash.setup, key, value
290                        )
291
292                if (
293                    "validation_model" in only
294                    and source.validation_model.smash is not None
295                ):
296                    setattr(
297                        destination,
298                        "validation_model",
299                        source.validation_model.smash.copy(),
300                    )
301                    for key, value in setup_update.items():
302                        setattr(
303                            destination.validation_model.smash.setup,
304                            key,
305                            value,
306                        )
307
308                if hasattr(source, "_fstates"):
309                    setattr(
310                        destination,
311                        "_fstates",
312                        copy.deepcopy(getattr(source, "_fstates")),
313                    )
314                if hasattr(source, "_istates"):
315                    setattr(
316                        destination,
317                        "_istates",
318                        copy.deepcopy(getattr(source, "_istates")),
319                    )
320                if hasattr(source, "_myatmos_data_connector"):
321                    setattr(
322                        destination,
323                        "_myatmos_data_connector",
324                        copy.deepcopy(
325                            getattr(source, "_myatmos_data_connector")
326                        ),
327                    )
328
329        else:
330            raise ValueError(
331                f"Error: Cannot copy model '{modelsource}', model attribute '{modelname}' already exist"
332            )
333
334        # get new model object
335        # mynewmodel = getattr(self, modelname)
336
337        # reset attributes
338        # mynewmodel.mysmashmodel = None
339        # mynewmodel.extra_smash_results = None
340        # mynewmodel._fstates = None
341        # mynewmodel._istates = None
342        # mynewmodel._myatmos_data_connector = None
343        # mynewmodel.warmup_model = None
344        # mynewmodel.mystats = mystats.mystats(self)
345        # mynewmodel.myplot = myplot.myplot(self)

Copy a model container

Parameters

modelsource : str The name of the source model attribute modelname : str The name of the new model attribute.

Examples

>>> es=smashbox.SmashBox()
>>> sb.newmodel("RealCollobrier")
>>> sb.copymodel("RealCollobrier", RealCollobrier2")
def copymodeldata(self, modelsource, modelname):
347    def copymodeldata(self, modelsource, modelname):
348        """
349        Copy a model data
350
351        Parameters
352        ----------
353
354        modelsource : str
355            The name of the source model attribute
356        modelname : str
357            The name of the new model attribute.
358
359        Examples
360        --------
361
362        >>> es=smashbox.SmashBox()
363        >>> sb.newmodel("RealCollobrier")
364        >>> sb.copymodeldata("RealCollobrier", RealCollobrier2")
365        """
366        if not hasattr(self, modelsource):
367            raise ValueError(
368                f"Error: Source model '{modelsource}' does not exist"
369            )
370
371        if not hasattr(self, modelname):
372            raise ValueError(
373                f"Error: destination model '{modelname}' does not exist"
374            )
375
376        source = getattr(self, modelsource)
377        destination = getattr(self, modelname)
378
379        if (
380            source.mysmashmodel is not None
381            and destination.mysmashmodel is not None
382        ):
383            destination.mysmashmodel.smash.atmos_data = (
384                source.mysmashmodel.smash.atmos_data.copy()
385            )
386            destination.mysmashmodel.smash.response_data = (
387                source.mysmashmodel.smash.response_data.copy()
388            )
389        if (
390            source.warmup_model is not None
391            and destination.warmup_model is not None
392        ):
393            destination.warmup_model.smash.atmos_data = (
394                source.warmup_model.smash.atmos_data.copy()
395            )
396            destination.warmup_model.smash.response_data = (
397                source.warmup_model.smash.response_data.copy()
398            )
399        if (
400            source.optimize_model is not None
401            and destination.optimize_model is not None
402        ):
403            destination.optimize_model.smash.atmos_data = (
404                source.optimize_model.smash.atmos_data.copy()
405            )
406            destination.optimize_model.smash.response_data = (
407                source.optimize_model.smash.response_data.copy()
408            )
409        if (
410            source.validation_model is not None
411            and destination.validation_model is not None
412        ):
413            destination.validation_model.smash.atmos_data = (
414                source.validation_model.smash.atmos_data.copy()
415            )
416            destination.validation_model.smash.response_data = (
417                source.validation_model.smash.response_data.copy()
418            )

Copy a model data

Parameters

modelsource : str The name of the source model attribute modelname : str The name of the new model attribute.

Examples

>>> es=smashbox.SmashBox()
>>> sb.newmodel("RealCollobrier")
>>> sb.copymodeldata("RealCollobrier", RealCollobrier2")
def load_containers(self, path, only=None, exclude=None, load_catchment_polygon=True):
420    def load_containers(
421        self, path, only=None, exclude=None, load_catchment_polygon=True
422    ):
423
424        subdir_list = os.listdir(path)
425
426        if only is not None:
427            for d in only:
428                if not d in subdir_list:
429                    raise ValueError(f"{d} does not exist in {path}")
430
431            subdir_list = only
432
433        if exclude is not None:
434            for d in exclude:
435                if d in subdir_list:
436                    subdir_list.remove(d)
437
438        for subdir in subdir_list:
439            box = pyhdf5_handler.read_hdf5file_as_dict(
440                os.path.join(path, subdir, "smashbox.hdf5")
441            )
442
443            mysmashmodel = None
444            warmup_model = None
445            optimize_model = None
446            validation_model = None
447
448            if os.path.exists(os.path.join(path, subdir, "mysmashmodel.hdf5")):
449                mysmashmodel = smash.io.read_model(
450                    os.path.join(path, subdir, "mysmashmodel.hdf5")
451                )
452            if os.path.exists(os.path.join(path, subdir, "warmup_model.hdf5")):
453                warmup_model = smash.io.read_model(
454                    os.path.join(path, subdir, "warmup_model.hdf5")
455                )
456            if os.path.exists(
457                os.path.join(path, subdir, "optimize_model.hdf5")
458            ):
459                optimize_model = smash.io.read_model(
460                    os.path.join(path, subdir, "optimize_model.hdf5")
461                )
462            if os.path.exists(
463                os.path.join(path, subdir, "validation_model.hdf5")
464            ):
465                validation_model = smash.io.read_model(
466                    os.path.join(path, subdir, "validation_model.hdf5")
467                )
468
469            for key, value in box["param"].items():
470                if getattr(self.myparam.param, key) is None:
471                    self.myparam.set_param(key, value)
472                else:
473                    dtype = type(getattr(self.myparam.param, key))
474                    try:
475                        converted_value = dtype(value)
476                        self.myparam.set_param(key, converted_value)
477                    except (ValueError, TypeError) as e:
478                        try:
479                            self.myparam.set_param(key, value)
480                        except (ValueError, TypeError) as ee:
481                            print(
482                                f"Type error for {key}: {dtype}/{type(value)} - {e}"
483                            )
484                            print(
485                                f"Can't import {key}: {dtype}/{type(value)} - {ee}"
486                            )
487
488            self.newmodel(subdir)
489
490            container = getattr(self, subdir)
491
492            for key, value in box["mysetup"]["setup"].items():
493                container.mysetup.set_setup(key, value)
494
495            container.mymesh.mesh = box["mymesh"]["mesh"]
496
497            # getting models extra result and stats
498            for model in [
499                "mysmashmodel",
500                "warmup_model",
501                "optimize_model",
502                "validation_model",
503            ]:
504
505                if model in box:
506                    structure = pyhdf5_handler.src.object_handler.generate_dict_structure(
507                        box[model], include_method=False
508                    )
509                    pyhdf5_handler.src.object_handler.map_dict_to_object(
510                        structure,
511                        box[model],
512                        getattr(container, model),
513                    )
514
515            setattr(container.mysmashmodel, "smash", mysmashmodel)
516            setattr(container.warmup_model, "smash", warmup_model)
517            setattr(container.optimize_model, "smash", optimize_model)
518            setattr(container.validation_model, "smash", validation_model)
519
520            container._myparam = copy.deepcopy(self.myparam)
521            if load_catchment_polygon:
522                container.mymesh.load_catchment_polygon(
523                    param=container._myparam.param
524                )