smashbox 1.0__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- smashbox/.spyproject/config/backups/codestyle.ini.bak +8 -0
- smashbox/.spyproject/config/backups/encoding.ini.bak +6 -0
- smashbox/.spyproject/config/backups/vcs.ini.bak +7 -0
- smashbox/.spyproject/config/backups/workspace.ini.bak +12 -0
- smashbox/.spyproject/config/codestyle.ini +8 -0
- smashbox/.spyproject/config/defaults/defaults-codestyle-0.2.0.ini +5 -0
- smashbox/.spyproject/config/defaults/defaults-encoding-0.2.0.ini +3 -0
- smashbox/.spyproject/config/defaults/defaults-vcs-0.2.0.ini +4 -0
- smashbox/.spyproject/config/defaults/defaults-workspace-0.2.0.ini +6 -0
- smashbox/.spyproject/config/encoding.ini +6 -0
- smashbox/.spyproject/config/vcs.ini +7 -0
- smashbox/.spyproject/config/workspace.ini +12 -0
- smashbox/__init__.py +8 -0
- smashbox/asset/flwdir/flowdir_fr_1000m.tif +0 -0
- smashbox/asset/outlets/.Rhistory +0 -0
- smashbox/asset/outlets/db_bnbv_fr.csv +142704 -0
- smashbox/asset/outlets/db_bnbv_light.csv +42084 -0
- smashbox/asset/outlets/db_sites.csv +8700 -0
- smashbox/asset/outlets/db_stations.csv +2916 -0
- smashbox/asset/outlets/db_stations_example.csv +19 -0
- smashbox/asset/outlets/edit_database.py +185 -0
- smashbox/asset/outlets/readme.txt +5 -0
- smashbox/asset/params/ci.tif +0 -0
- smashbox/asset/params/cp.tif +0 -0
- smashbox/asset/params/ct.tif +0 -0
- smashbox/asset/params/kexc.tif +0 -0
- smashbox/asset/params/kmlt.tif +0 -0
- smashbox/asset/params/llr.tif +0 -0
- smashbox/asset/setup/setup_rhax_gr4_dt3600.yaml +15 -0
- smashbox/asset/setup/setup_rhax_gr4_dt900.yaml +15 -0
- smashbox/asset/setup/setup_rhax_gr5_dt3600.yaml +15 -0
- smashbox/asset/setup/setup_rhax_gr5_dt900.yaml +15 -0
- smashbox/init/README.md +3 -0
- smashbox/init/__init__.py +3 -0
- smashbox/init/multimodel_statistics.py +405 -0
- smashbox/init/param.py +799 -0
- smashbox/init/smashbox.py +186 -0
- smashbox/model/__init__.py +1 -0
- smashbox/model/atmos_data_connector.py +518 -0
- smashbox/model/mesh.py +185 -0
- smashbox/model/model.py +829 -0
- smashbox/model/setup.py +109 -0
- smashbox/plot/__init__.py +1 -0
- smashbox/plot/myplot.py +1133 -0
- smashbox/plot/plot.py +1662 -0
- smashbox/read_inputdata/__init__.py +1 -0
- smashbox/read_inputdata/read_data.py +1229 -0
- smashbox/read_inputdata/smashmodel.py +395 -0
- smashbox/stats/__init__.py +1 -0
- smashbox/stats/mystats.py +1632 -0
- smashbox/stats/stats.py +2022 -0
- smashbox/test.py +532 -0
- smashbox/test_average_stats.py +122 -0
- smashbox/test_mesh.r +8 -0
- smashbox/test_mesh_from_graffas.py +69 -0
- smashbox/tools/__init__.py +1 -0
- smashbox/tools/geo_toolbox.py +1028 -0
- smashbox/tools/tools.py +461 -0
- smashbox/tutorial_R.r +182 -0
- smashbox/tutorial_R_graffas.r +88 -0
- smashbox/tutorial_R_graffas_local.r +33 -0
- smashbox/tutorial_python.py +102 -0
- smashbox/tutorial_readme.py +261 -0
- smashbox/tutorial_report.py +58 -0
- smashbox/tutorials/Python_tutorial.md +124 -0
- smashbox/tutorials/R_Graffas_tutorial.md +153 -0
- smashbox/tutorials/R_tutorial.md +121 -0
- smashbox/tutorials/__init__.py +6 -0
- smashbox/tutorials/generate_doc.md +7 -0
- smashbox-1.0.dist-info/METADATA +998 -0
- smashbox-1.0.dist-info/RECORD +73 -0
- smashbox-1.0.dist-info/WHEEL +5 -0
- smashbox-1.0.dist-info/licenses/LICENSE +100 -0
smashbox/model/model.py
ADDED
|
@@ -0,0 +1,829 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import smash
|
|
3
|
+
|
|
4
|
+
# import pyhdf5_handler
|
|
5
|
+
# from pyhdf5_handler.src import hdf5_handler
|
|
6
|
+
import numpy as np
|
|
7
|
+
import pandas as pd
|
|
8
|
+
import datetime
|
|
9
|
+
|
|
10
|
+
# from smashbox.src import param
|
|
11
|
+
from smashbox.model import setup
|
|
12
|
+
from smashbox.model import mesh
|
|
13
|
+
from smashbox.plot import myplot
|
|
14
|
+
from smashbox.tools import geo_toolbox
|
|
15
|
+
from smashbox.tools import tools
|
|
16
|
+
from smashbox.model import atmos_data_connector
|
|
17
|
+
from smashbox.stats import mystats
|
|
18
|
+
from smashbox.read_inputdata import smashmodel
|
|
19
|
+
|
|
20
|
+
import pyhdf5_handler
|
|
21
|
+
import copy
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class model:
|
|
25
|
+
"""Main class model() which has a complete set of functions, class and attributes to
|
|
26
|
+
build, run and manipulate the Smash model, compute statistical criterium and
|
|
27
|
+
plot graphics."""
|
|
28
|
+
|
|
29
|
+
def __init__(self, myparam):
|
|
30
|
+
|
|
31
|
+
self._myparam = copy.deepcopy(myparam)
|
|
32
|
+
"""The attribute _myparam is a copy of the parent class smashbox.myparam.
|
|
33
|
+
This class stores the main parameters used for building the Smash model"""
|
|
34
|
+
|
|
35
|
+
self.mysetup = setup.setup(self._myparam.param)
|
|
36
|
+
"""The attribute mysetup own the class setup.setup(). This class stores the Smash
|
|
37
|
+
setup for the hydrological simulation and some helpers to manipulate these
|
|
38
|
+
parameters."""
|
|
39
|
+
|
|
40
|
+
self.mymesh = mesh.mesh()
|
|
41
|
+
"""The attribute mymesh own the class mesh.mesh(). This class stores the Smash
|
|
42
|
+
mesh used for the hydrological simulation and some helpers to manipulate this mesh.
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
self.mysmashmodel = None
|
|
46
|
+
"""The attribute mysmashmodel stores the Smash model object created with
|
|
47
|
+
attributes mysetup and -mymesh."""
|
|
48
|
+
|
|
49
|
+
self._fstates = None
|
|
50
|
+
self._istates = None
|
|
51
|
+
self._myatmos_data_connector = None
|
|
52
|
+
|
|
53
|
+
self.warmup_model = None
|
|
54
|
+
"""The attribute warmup_model store a smash model used for warmup and compatible
|
|
55
|
+
with the model in attribute mysmashmodel"""
|
|
56
|
+
|
|
57
|
+
self.extra_smash_results = None
|
|
58
|
+
"""The attribute extra_smash_results stores the extra results provided by Smash
|
|
59
|
+
if the parameter return_option is defined."""
|
|
60
|
+
|
|
61
|
+
self.mystats = mystats.mystats(self)
|
|
62
|
+
"""The attribute mystats own the class mystats.mystats(). This class stores
|
|
63
|
+
statistical functions and results which could be applied on the smash model."""
|
|
64
|
+
|
|
65
|
+
self.myplot = myplot.myplot(self)
|
|
66
|
+
"""The attribute myplot own the class myplot.myplot(). This class stores plotting
|
|
67
|
+
capabilities on the smash model object."""
|
|
68
|
+
|
|
69
|
+
def generate_mesh(
|
|
70
|
+
self,
|
|
71
|
+
max_surf: float | None = None,
|
|
72
|
+
min_surf: float | None = None,
|
|
73
|
+
max_depth: float = 1.0,
|
|
74
|
+
query: str | None = None,
|
|
75
|
+
area_error_th: None | float = None,
|
|
76
|
+
):
|
|
77
|
+
"""
|
|
78
|
+
Generate the mesh of the Smash model
|
|
79
|
+
|
|
80
|
+
Parameters
|
|
81
|
+
----------
|
|
82
|
+
|
|
83
|
+
max_depth : `int`, default 1
|
|
84
|
+
The maximum depth accepted by the algorithm to find the catchment outlet.
|
|
85
|
+
A **max_depth** of 1 means that the algorithm will search among the
|
|
86
|
+
combinations in
|
|
87
|
+
(``row - 1``, ``row``, ``row + 1``; ``col - 1``, ``col``, ``col + 1``),
|
|
88
|
+
the coordinates that minimize
|
|
89
|
+
the relative error between the given catchment area and the modeled
|
|
90
|
+
catchment area calculated from the
|
|
91
|
+
flow directions file.
|
|
92
|
+
:param query: Any pandas dataframe query as string: '(SURF>20) & (SURF<100)'. This query
|
|
93
|
+
must be build using the field (column name) in the outlet database.
|
|
94
|
+
https://pandas.pydata.org/docs/user_guide/indexing.html#the-query-method
|
|
95
|
+
:type query: str
|
|
96
|
+
area_error_th: float | None
|
|
97
|
+
The tolerance error for the difference between the observed and simulated
|
|
98
|
+
surface. The error is computed as follow:
|
|
99
|
+
Serror=abs(Ssim-Sobs)/Sobs
|
|
100
|
+
All outlets where `Serror > area_error_th` will be automatically removed from
|
|
101
|
+
the mesh.
|
|
102
|
+
|
|
103
|
+
Examples
|
|
104
|
+
--------
|
|
105
|
+
|
|
106
|
+
>>> es=smashbox.SmashBox()
|
|
107
|
+
>>> sb.newmodel("RealCollobrier")
|
|
108
|
+
>>> sb.RealCollobrier.generate_mesh(min_surf=5, max_surf=100)
|
|
109
|
+
|
|
110
|
+
"""
|
|
111
|
+
self.mymesh.generate_mesh(
|
|
112
|
+
self._myparam.param,
|
|
113
|
+
max_depth=max_depth,
|
|
114
|
+
query=query,
|
|
115
|
+
area_error_th=area_error_th,
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
# @tools.auto_check_int
|
|
119
|
+
# def test(self, a: int = 1):
|
|
120
|
+
# if isinstance(a, int):
|
|
121
|
+
# print(f"a is int: {a}")
|
|
122
|
+
# else:
|
|
123
|
+
# print(f"a is not int: {a}")
|
|
124
|
+
|
|
125
|
+
def model(self, setup: dict | None = None, mesh: dict | None = None):
|
|
126
|
+
"""
|
|
127
|
+
Smash model object creation. This function wrap smash.Model(). Setup and mesh
|
|
128
|
+
argument are optional since these dictionnary are hosted by the smashbox object.
|
|
129
|
+
|
|
130
|
+
Parameters
|
|
131
|
+
----------
|
|
132
|
+
setup: dict | None
|
|
133
|
+
The Smash setup (optionnal), if None the smashbox setup will be used
|
|
134
|
+
mesh: dict | None
|
|
135
|
+
The Smash mesh (optionnal), if None the smashbox mesh will be used
|
|
136
|
+
|
|
137
|
+
Examples
|
|
138
|
+
--------
|
|
139
|
+
|
|
140
|
+
>>> es=smashbox.SmashBox()
|
|
141
|
+
>>> sb.newmodel("RealCollobrier")
|
|
142
|
+
>>> sb.RealCollobrier.generate_mesh(run=False)
|
|
143
|
+
>>> sb.RealCollobrier.model()
|
|
144
|
+
|
|
145
|
+
"""
|
|
146
|
+
if setup is None:
|
|
147
|
+
setup = self.mysetup.setup
|
|
148
|
+
|
|
149
|
+
if mesh is None:
|
|
150
|
+
mesh = self.mymesh.mesh
|
|
151
|
+
|
|
152
|
+
self.mysmashmodel = self._model(setup=setup, mesh=mesh)
|
|
153
|
+
|
|
154
|
+
self._gathering_atmosdata()
|
|
155
|
+
|
|
156
|
+
self._gathering_parameters(self.mysmashmodel)
|
|
157
|
+
|
|
158
|
+
def _model(self, setup=None, mesh=None):
|
|
159
|
+
"""
|
|
160
|
+
Smash model object creation. This function wrap smash.Model()
|
|
161
|
+
|
|
162
|
+
Parameters
|
|
163
|
+
----------
|
|
164
|
+
setup: dict | None
|
|
165
|
+
The Smash setup (optionnal), if None the smashbox setup will be used
|
|
166
|
+
mesh: dict | None
|
|
167
|
+
The Smash mesh (optionnal), if None the smashbox mesh will be used
|
|
168
|
+
|
|
169
|
+
Examples
|
|
170
|
+
--------
|
|
171
|
+
|
|
172
|
+
>>> es=smashbox.SmashBox()
|
|
173
|
+
>>> sb.newmodel("RealCollobrier")
|
|
174
|
+
>>> sb.RealCollobrier.generate_mesh(run=False)
|
|
175
|
+
>>> sb.RealCollobrier.model()
|
|
176
|
+
|
|
177
|
+
"""
|
|
178
|
+
if setup is None:
|
|
179
|
+
print("</> The input setup is None ")
|
|
180
|
+
return None
|
|
181
|
+
|
|
182
|
+
if mesh is None:
|
|
183
|
+
print("</> input mesh is None. use smashbox.model.model.generate_mesh()")
|
|
184
|
+
return None
|
|
185
|
+
|
|
186
|
+
if self._myparam.param.enhanced_smash_input_data:
|
|
187
|
+
model = smashmodel.SmashModel(setup, mesh)
|
|
188
|
+
else:
|
|
189
|
+
model = smash.Model(setup, mesh)
|
|
190
|
+
|
|
191
|
+
return model
|
|
192
|
+
|
|
193
|
+
def _gathering_parameters(self, model):
|
|
194
|
+
|
|
195
|
+
if hasattr(self, "optimize_model") and self.optimize_model is not None:
|
|
196
|
+
print(f"</> Getting parameters from previously optimized model ...")
|
|
197
|
+
model.rr_parameters = self.optimize_model.rr_parameters
|
|
198
|
+
else:
|
|
199
|
+
print(
|
|
200
|
+
f"</> Importing parameters from {self._myparam.param._smash_parameters} ..."
|
|
201
|
+
)
|
|
202
|
+
self.import_parameters(model=model)
|
|
203
|
+
self._transform_parameters(
|
|
204
|
+
model=model, dt_origin=self._myparam.param._smash_parameters_dt
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
def _transform_parameters(self, model=None, dt_origin: None | float = None):
|
|
208
|
+
"""
|
|
209
|
+
Function to transform the parameters according the model time-step and the original
|
|
210
|
+
time-step used for calibrated the parameters.
|
|
211
|
+
:param dt_origin: Original time-step used for generate the calibrated parameter,
|
|
212
|
+
defaults to None
|
|
213
|
+
:type dt_origin: None | float, optional
|
|
214
|
+
|
|
215
|
+
"""
|
|
216
|
+
# if dt_origin is None:
|
|
217
|
+
# raise ValueError(
|
|
218
|
+
# " Argument dt_origin is None. This must be filled with the value "
|
|
219
|
+
# "of the timestep used to calibrate the parameters."
|
|
220
|
+
# )
|
|
221
|
+
|
|
222
|
+
# if not hasattr(self, "mysmashmodel") or self.mysmashmodel is None:
|
|
223
|
+
# raise ValueError(
|
|
224
|
+
# "</> mysmashmodel attribute does not exist or is None. "
|
|
225
|
+
# "The model must be created first..."
|
|
226
|
+
# )
|
|
227
|
+
if model is None:
|
|
228
|
+
return
|
|
229
|
+
|
|
230
|
+
dt_target = model.setup.dt
|
|
231
|
+
|
|
232
|
+
if dt_origin is None:
|
|
233
|
+
return
|
|
234
|
+
|
|
235
|
+
if dt_target == dt_origin:
|
|
236
|
+
return
|
|
237
|
+
|
|
238
|
+
print(
|
|
239
|
+
f"</> Tranforming parameters `ct`, `kexec`, `llr` calibrated with a time-step "
|
|
240
|
+
f"of {dt_origin}s to the modeled time-step {dt_target}s."
|
|
241
|
+
)
|
|
242
|
+
parameters_tranfsorm = ["ct", "kexc", "llr"]
|
|
243
|
+
power_tranform = [1.0 / 4.0, -1.0 / 8.0, 1.0]
|
|
244
|
+
|
|
245
|
+
for i, param in enumerate(parameters_tranfsorm):
|
|
246
|
+
index_param = np.where(param == model.rr_parameters.keys)[0]
|
|
247
|
+
if len(index_param) > 0:
|
|
248
|
+
model.rr_parameters.values[:, :, index_param[0]] = (
|
|
249
|
+
model.rr_parameters.values[:, :, index_param[0]]
|
|
250
|
+
* (dt_origin / dt_target) ** power_tranform[i]
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
def _gathering_atmosdata(self):
|
|
254
|
+
|
|
255
|
+
if self._myatmos_data_connector is not None:
|
|
256
|
+
|
|
257
|
+
print("</> Gathering atmos data ...")
|
|
258
|
+
|
|
259
|
+
if (
|
|
260
|
+
self._myatmos_data_connector.input_ntimestep
|
|
261
|
+
!= self.mysmashmodel.setup.ntime_step
|
|
262
|
+
):
|
|
263
|
+
print(
|
|
264
|
+
"</> Warnings: Inconsistant ntime_step "
|
|
265
|
+
f"{self._myatmos_data_connector.input_ntimestep}"
|
|
266
|
+
f"!={self.mysmashmodel.setup.ntime_step}, "
|
|
267
|
+
"the Smash model will be rebuild."
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
self._model()
|
|
271
|
+
self._gathering_parameters(self.mysmashmodel)
|
|
272
|
+
|
|
273
|
+
if self._myatmos_data_connector.smash_prcp is not None:
|
|
274
|
+
self.mysmashmodel.atmos_data.prcp = (
|
|
275
|
+
self._myatmos_data_connector.smash_prcp
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
if self._myatmos_data_connector.smash_pet is not None:
|
|
279
|
+
self.mysmashmodel.atmos_data.pet = self._myatmos_data_connector.smash_pet
|
|
280
|
+
|
|
281
|
+
if self.mysmashmodel.setup.prcp_partitioning:
|
|
282
|
+
print("</> Compute prcp partitionning ...")
|
|
283
|
+
smash.fcore._mw_atmos_statistic.compute_prcp_partitioning(
|
|
284
|
+
model.setup, model.mesh, model._input_data
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
if self.mysmashmodel.setup.compute_mean_atmos:
|
|
288
|
+
print("</> Computing mean atmospheric data")
|
|
289
|
+
smash.fcore._mw_atmos_statistic.compute_mean_atmos(
|
|
290
|
+
self.mysmashmodel.setup,
|
|
291
|
+
self.mysmashmodel.mesh,
|
|
292
|
+
self.mysmashmodel._input_data,
|
|
293
|
+
)
|
|
294
|
+
|
|
295
|
+
@tools.autocast_args
|
|
296
|
+
def model_warmup(self, warmup: int = 365):
|
|
297
|
+
"""
|
|
298
|
+
Smash model warmup function. This function warm the curent model by creating a new
|
|
299
|
+
on with attribute warmup_model. The final states of warmup_model are copied to the
|
|
300
|
+
initial states of mysmashmodel.
|
|
301
|
+
|
|
302
|
+
Parameters
|
|
303
|
+
----------
|
|
304
|
+
|
|
305
|
+
warmup: None | int
|
|
306
|
+
a integer of the number of days used for warming the model.
|
|
307
|
+
|
|
308
|
+
"""
|
|
309
|
+
print("</> Warmup the Smash-model...")
|
|
310
|
+
|
|
311
|
+
if warmup is not None:
|
|
312
|
+
try:
|
|
313
|
+
timedelta = datetime.timedelta(days=warmup)
|
|
314
|
+
except:
|
|
315
|
+
raise ValueError(f"warmup arg `{warmup}` is not a valid time delta.")
|
|
316
|
+
|
|
317
|
+
w_setup = copy.deepcopy(self.mysetup.setup)
|
|
318
|
+
|
|
319
|
+
w_setup["end_time"] = w_setup["start_time"]
|
|
320
|
+
w_setup["start_time"] = datetime.datetime.strftime(
|
|
321
|
+
datetime.datetime.fromisoformat(w_setup["start_time"]) - timedelta,
|
|
322
|
+
"%Y-%m-%d %H:%M",
|
|
323
|
+
)
|
|
324
|
+
w_setup["read_qobs"] = False
|
|
325
|
+
w_setup["read_prcp"] = True
|
|
326
|
+
w_setup["read_pet"] = True
|
|
327
|
+
|
|
328
|
+
self.warmup_model = self._model(setup=w_setup, mesh=self.mymesh.mesh)
|
|
329
|
+
self._gathering_parameters(self.warmup_model)
|
|
330
|
+
self.warmup_model.forward_run()
|
|
331
|
+
|
|
332
|
+
# TODO FIX BUG IN SMASH when states > 1.0
|
|
333
|
+
mask_sup = np.where(self.warmup_model.rr_final_states.values > 1)
|
|
334
|
+
self.warmup_model.rr_final_states.values[mask_sup] = 0.9999
|
|
335
|
+
|
|
336
|
+
if hasattr(self, "mysmashmodel") and self.mysmashmodel is not None:
|
|
337
|
+
|
|
338
|
+
self.mysmashmodel.rr_initial_states = self.warmup_model.rr_final_states
|
|
339
|
+
|
|
340
|
+
def optimize(
|
|
341
|
+
self,
|
|
342
|
+
start_time: None | str = None,
|
|
343
|
+
end_time: None | str = None,
|
|
344
|
+
mapping: str = "uniform",
|
|
345
|
+
optimizer: None | str = None,
|
|
346
|
+
optimize_options: None | str = None,
|
|
347
|
+
cost_options: None | str = None,
|
|
348
|
+
common_options: None | str = None,
|
|
349
|
+
return_options: None | str = None,
|
|
350
|
+
callback=None,
|
|
351
|
+
):
|
|
352
|
+
"""
|
|
353
|
+
Optimize the current model (with the current setup and mesh),
|
|
354
|
+
store the model in the attribute optimize_model and set the calibrated
|
|
355
|
+
parameters to the model behind the attribute mysmashmodel.
|
|
356
|
+
Start_time and end_time can be specified here to change the period of the
|
|
357
|
+
calibration compare to the current setup. All other arguments are
|
|
358
|
+
equivalent to the smash.model.optimize function
|
|
359
|
+
(see https://smash.recover.inrae.fr/api_reference/principal_methods/smash/smash.optimize.html#smash.optimize).
|
|
360
|
+
One difference from Smash is that gauges with no data are
|
|
361
|
+
automatically removed from the optimization without raising an error.
|
|
362
|
+
This provide a convient way to calibrate quickly the parameters using the current
|
|
363
|
+
mesh which may include gauges with data for calibration
|
|
364
|
+
and location gauge for discharges computation.
|
|
365
|
+
|
|
366
|
+
:param start_time: The start time of the optimization, format "YYYY-mm-dd HH:MM", defaults to None
|
|
367
|
+
:type start_time: None | str, optional
|
|
368
|
+
:param end_time: The end time of the optimization, format "YYYY-mm-dd HH:MM", defaults to None
|
|
369
|
+
:type end_time: None | str, optional
|
|
370
|
+
:param mapping: Type of mapping, see https://smash.recover.inrae.fr/api_reference/principal_methods/smash/smash.optimize.html#smash.optimize, defaults to "uniform"
|
|
371
|
+
:type mapping: str, optional
|
|
372
|
+
:param optimizer: Name of optimizer, see https://smash.recover.inrae.fr/api_reference/principal_methods/smash/smash.optimize.html#smash.optimize, defaults to None
|
|
373
|
+
:type optimizer: None | str, optional
|
|
374
|
+
:param optimize_options: Dictionary containing optimization options for fine-tuning the optimization process, see https://smash.recover.inrae.fr/api_reference/principal_methods/smash/smash.optimize.html#smash.optimize, defaults to None
|
|
375
|
+
:type optimize_options: None | str, optional
|
|
376
|
+
:param cost_options: Dictionary containing computation cost options for simulated and observed responses. see https://smash.recover.inrae.fr/api_reference/principal_methods/smash/smash.optimize.html#smash.optimize, defaults to None
|
|
377
|
+
:type cost_options: None | str, optional
|
|
378
|
+
:param common_options: Dictionary containing common options with two elements: ncpu (int, default 1) and verbose (bool, default is False), defaults to None
|
|
379
|
+
:type common_options: None | str, optional
|
|
380
|
+
:param return_options: Dictionary containing return options to save additional simulation results, see https://smash.recover.inrae.fr/api_reference/principal_methods/smash/smash.optimize.html#smash.optimize, defaults to None
|
|
381
|
+
:type return_options: None | str, optional
|
|
382
|
+
:param callback: A callable called after each iteration with the signature callback(iopt: Optimize), see https://smash.recover.inrae.fr/api_reference/principal_methods/smash/smash.optimize.html#smash.optimize, defaults to None
|
|
383
|
+
:type callback: TYPE, optional
|
|
384
|
+
|
|
385
|
+
"""
|
|
386
|
+
o_setup = copy.deepcopy(self.mysetup.setup)
|
|
387
|
+
|
|
388
|
+
if start_time is not None and end_time is not None:
|
|
389
|
+
o_setup["start_time"] = start_time
|
|
390
|
+
o_setup["end_time"] = end_time
|
|
391
|
+
|
|
392
|
+
o_setup["read_qobs"] = True
|
|
393
|
+
o_setup["read_prcp"] = True
|
|
394
|
+
o_setup["read_pet"] = True
|
|
395
|
+
|
|
396
|
+
self.optimize_model = self._model(setup=o_setup, mesh=self.mymesh.mesh)
|
|
397
|
+
|
|
398
|
+
default_cost_option = {"end_warmup": o_setup["start_time"], "gauge": "all"}
|
|
399
|
+
if cost_options is not None:
|
|
400
|
+
default_cost_option.update(cost_options)
|
|
401
|
+
|
|
402
|
+
# auto remove gauge if no observation
|
|
403
|
+
if isinstance(default_cost_option["gauge"], str):
|
|
404
|
+
if default_cost_option["gauge"] == "dws":
|
|
405
|
+
gauge = np.empty(shape=0)
|
|
406
|
+
|
|
407
|
+
for i, pos in enumerate(model.mesh.gauge_pos):
|
|
408
|
+
if model.mesh.flwdst[tuple(pos)] == 0:
|
|
409
|
+
gauge = np.append(gauge, self.optimize_model.mesh.code[i])
|
|
410
|
+
|
|
411
|
+
elif default_cost_option["gauge"] == "all":
|
|
412
|
+
gauge = np.array(self.optimize_model.mesh.code, ndmin=1)
|
|
413
|
+
|
|
414
|
+
# elif isinstance(gauge, (list, tuple, np.ndarray)):
|
|
415
|
+
# gauge_bak = np.array(gauge, ndmin=1)
|
|
416
|
+
# gauge = np.empty(shape=0)
|
|
417
|
+
|
|
418
|
+
# for ggc in gauge_bak:
|
|
419
|
+
# if ggc in self.optimize_model.mesh.code:
|
|
420
|
+
# gauge = np.append(gauge, ggc)
|
|
421
|
+
# else:
|
|
422
|
+
# raise ValueError(
|
|
423
|
+
# f"Unknown gauge code '{ggc}' in gauge cost_options. Choices: {list(model.mesh.code)}"
|
|
424
|
+
# )
|
|
425
|
+
|
|
426
|
+
st = pd.Timestamp(self.optimize_model.setup.start_time)
|
|
427
|
+
et = pd.Timestamp(self.optimize_model.setup.end_time)
|
|
428
|
+
ew = pd.Timestamp(default_cost_option["end_warmup"])
|
|
429
|
+
start_slice = int((ew - st).total_seconds() / self.optimize_model.setup.dt)
|
|
430
|
+
end_slice = int((et - ew).total_seconds() / self.optimize_model.setup.dt)
|
|
431
|
+
time_slice = slice(start_slice, end_slice)
|
|
432
|
+
|
|
433
|
+
del_gauge = []
|
|
434
|
+
for i in range(len(gauge)):
|
|
435
|
+
|
|
436
|
+
if np.all(self.optimize_model.response_data.q[i, time_slice] < 0):
|
|
437
|
+
del_gauge.append(i)
|
|
438
|
+
|
|
439
|
+
print(
|
|
440
|
+
f"No observed discharge available at gauge '{gauge[i]}' for the selected "
|
|
441
|
+
f"optimization period ['{ew}', '{et}']. This gauge is removed "
|
|
442
|
+
f"from the optimization."
|
|
443
|
+
)
|
|
444
|
+
|
|
445
|
+
gauge = np.delete(gauge, del_gauge)
|
|
446
|
+
default_cost_option.update({"gauge": gauge})
|
|
447
|
+
|
|
448
|
+
self.optimize_model.optimize(
|
|
449
|
+
mapping,
|
|
450
|
+
optimizer,
|
|
451
|
+
optimize_options,
|
|
452
|
+
default_cost_option,
|
|
453
|
+
common_options,
|
|
454
|
+
return_options,
|
|
455
|
+
callback,
|
|
456
|
+
)
|
|
457
|
+
|
|
458
|
+
if hasattr(self, "mysmashmodel") and self.mysmashmodel is not None:
|
|
459
|
+
self.mysmashmodel.rr_parameters = self.optimize_model.rr_parameters.copy()
|
|
460
|
+
|
|
461
|
+
@tools.autocast_args
|
|
462
|
+
def forward_run(
|
|
463
|
+
self,
|
|
464
|
+
warmup: int | None = None,
|
|
465
|
+
invert_states: bool | None = False,
|
|
466
|
+
cost_options: dict | None = None,
|
|
467
|
+
common_options: dict | None = None,
|
|
468
|
+
return_options: dict | None = None,
|
|
469
|
+
):
|
|
470
|
+
"""
|
|
471
|
+
Smash model forward run.This function wrap smash.model.forward_run().
|
|
472
|
+
|
|
473
|
+
Parameters
|
|
474
|
+
----------
|
|
475
|
+
|
|
476
|
+
warmup: None | int
|
|
477
|
+
a integer of the number of days used for warming the model.
|
|
478
|
+
invert_states : bool = False
|
|
479
|
+
invert states of the model, so that the final states are used
|
|
480
|
+
for the initial states.
|
|
481
|
+
cost_options : dict | None,
|
|
482
|
+
Dictionary containing computation cost options for simulated and observed responses (https://smash.recover.inrae.fr/api_reference/principal_methods/smash/smash.Model.forward_run.html).
|
|
483
|
+
common_options: dict| None,
|
|
484
|
+
Dictionary containing common options with two elements, ncpu and verbose (https://smash.recover.inrae.fr/api_reference/principal_methods/smash/smash.Model.forward_run.html)
|
|
485
|
+
return_options : dict | None,
|
|
486
|
+
Dictionary containing return options to save additional simulation results. (https://smash.recover.inrae.fr/api_reference/principal_methods/smash/smash.Model.forward_run.html)
|
|
487
|
+
|
|
488
|
+
Examples
|
|
489
|
+
--------
|
|
490
|
+
|
|
491
|
+
>>> es=smashbox.SmashBox()
|
|
492
|
+
>>> sb.newmodel("RealCollobrier")
|
|
493
|
+
>>> sb.RealCollobrier.generate_mesh(run=False)
|
|
494
|
+
>>> sb.RealCollobrier.model()
|
|
495
|
+
>>> sb.RealCollobrier.forward_run()
|
|
496
|
+
"""
|
|
497
|
+
|
|
498
|
+
if self.mysmashmodel is None:
|
|
499
|
+
self.model()
|
|
500
|
+
|
|
501
|
+
if warmup is not None:
|
|
502
|
+
self.model_warmup(warmup=warmup)
|
|
503
|
+
|
|
504
|
+
if self.warmup_model is not None:
|
|
505
|
+
self.mysmashmodel.rr_initial_states = self.warmup_model.rr_final_states
|
|
506
|
+
|
|
507
|
+
if hasattr(self, "optimize_model"):
|
|
508
|
+
self.mysmashmodel.rr_parameters = self.optimize_model.rr_parameters
|
|
509
|
+
|
|
510
|
+
# needed here inorder to replace the rainfall without rebuild the model
|
|
511
|
+
self._gathering_atmosdata()
|
|
512
|
+
|
|
513
|
+
if invert_states:
|
|
514
|
+
if self._fstates is not None and not np.all(self._fstates == -99.0):
|
|
515
|
+
|
|
516
|
+
# TODO FIX BUG IN SMASH when states > 1.0
|
|
517
|
+
mask_inf = np.where(self.mysmashmodel.mesh.active_cell == 1)
|
|
518
|
+
mask_sup = np.where(self._fstates > 1)
|
|
519
|
+
self._fstates[mask_sup] = 0.9999
|
|
520
|
+
|
|
521
|
+
self.mysmashmodel.rr_initial_states.values[mask_inf] = self._fstates[
|
|
522
|
+
mask_inf
|
|
523
|
+
].copy()
|
|
524
|
+
|
|
525
|
+
else:
|
|
526
|
+
print(
|
|
527
|
+
"</> model final states does not exist."
|
|
528
|
+
" Invert states is not possible."
|
|
529
|
+
" Smash default initial states is used."
|
|
530
|
+
)
|
|
531
|
+
|
|
532
|
+
self.extra_smash_results = self.mysmashmodel.forward_run(
|
|
533
|
+
cost_options=cost_options,
|
|
534
|
+
common_options=common_options,
|
|
535
|
+
return_options=return_options,
|
|
536
|
+
)
|
|
537
|
+
|
|
538
|
+
# states backup
|
|
539
|
+
self._fstates = self.mysmashmodel.rr_final_states.values.copy()
|
|
540
|
+
self._istates = self.mysmashmodel.rr_initial_states.values.copy()
|
|
541
|
+
|
|
542
|
+
@tools.autocast_args
|
|
543
|
+
def atmos_data_connector(
|
|
544
|
+
self,
|
|
545
|
+
input_prcp: np.ndarray | None = None,
|
|
546
|
+
input_pet: np.ndarray | None = None,
|
|
547
|
+
input_dt: float | None = None,
|
|
548
|
+
input_res: tuple | list = (1000.0, 1000.0),
|
|
549
|
+
input_start_time: str = "2050-01-01 01:00",
|
|
550
|
+
input_bbox: dict | None = None,
|
|
551
|
+
input_epsg: int = 2154,
|
|
552
|
+
resampling_method="home_made_with_scipy_zoom",
|
|
553
|
+
):
|
|
554
|
+
"""
|
|
555
|
+
Generate a connector for the external atmos_data comming from
|
|
556
|
+
other model such as Graffas (spatial rainfall generator).
|
|
557
|
+
|
|
558
|
+
Parameters
|
|
559
|
+
----------
|
|
560
|
+
|
|
561
|
+
input_prcp : np.ndarray | None = None
|
|
562
|
+
An np.ndarray with shape (nrow, ncol, npdt) wich stores the spatial rainfall
|
|
563
|
+
which will be used by Smash.Ideally, the extend of this array match
|
|
564
|
+
exactlly the extend of the Smash domain.
|
|
565
|
+
input_pet : np.ndarray | None = None
|
|
566
|
+
An np.ndarray with shape (nrow, ncol, npdt) wich stores the spatial
|
|
567
|
+
evapotranspiration which will be used by Smash.
|
|
568
|
+
input_dt : float = 3600.
|
|
569
|
+
Time step in seconds of the input precipitation
|
|
570
|
+
input_res : tuple | list = (1000., 1000.)
|
|
571
|
+
The resolution of the input precipitation
|
|
572
|
+
input_start_time : str = "2050-01-01 01:00"
|
|
573
|
+
The date of the start_time
|
|
574
|
+
input_bbox : dict | None = None
|
|
575
|
+
The extend of the domain using a bbox.
|
|
576
|
+
The convention used here is a dictionary like
|
|
577
|
+
bbox={"left":xmin, "top": ymax, "right": xmax, "bottom": ymin}.
|
|
578
|
+
If not provided, the extend of the smash domain will be used starting
|
|
579
|
+
from xmin and ymin.
|
|
580
|
+
input_epsg : int = 2154
|
|
581
|
+
The epsg code of the coordinate system. If not provided,
|
|
582
|
+
the coordinate system used in Smash will be used.
|
|
583
|
+
resampling_method: str
|
|
584
|
+
The method to use to resample and crop the input array. Default is
|
|
585
|
+
'home_made_with_scipy_zoom' Choice are:
|
|
586
|
+
['rasterio_1', 'rasterio_2', 'home_made_with_scipy_zoom'].
|
|
587
|
+
'home_made_with_scipy_zoom' is the fastest method. 'rasterio_1'
|
|
588
|
+
is the slowest method. However, 'rasterio' method use much tested and
|
|
589
|
+
reliable method to resample and crop the array.
|
|
590
|
+
|
|
591
|
+
Examples
|
|
592
|
+
--------
|
|
593
|
+
|
|
594
|
+
>>> prcp_array=np.zeros(200,200,20)+1.
|
|
595
|
+
>>> es=smashbox.SmashBox()
|
|
596
|
+
>>> sb.newmodel("RealCollobrier")
|
|
597
|
+
>>> sb.RealCollobrier.generate_mesh()
|
|
598
|
+
>>> sb.RealCollobrier.atmos_data_connector(input_prcp=prcp_array)
|
|
599
|
+
|
|
600
|
+
"""
|
|
601
|
+
if input_prcp is None and input_pet is None:
|
|
602
|
+
raise ValueError(
|
|
603
|
+
"</> input_prcp and input_pet are None. input_prcp or input_pet must be"
|
|
604
|
+
" numpy.ndarray with shape (nrow, ncol, ntimesteps)."
|
|
605
|
+
)
|
|
606
|
+
|
|
607
|
+
if input_dt is None:
|
|
608
|
+
print(
|
|
609
|
+
"</> We suppose the input atmos data time-step equal to the model time-step."
|
|
610
|
+
)
|
|
611
|
+
input_dt = self.mysetup.setup["dt"]
|
|
612
|
+
|
|
613
|
+
if input_dt != self.mysetup.setup["dt"]:
|
|
614
|
+
print(
|
|
615
|
+
"</> Model and input atmos data have different time-step. "
|
|
616
|
+
"Input atmos data will be resampled."
|
|
617
|
+
)
|
|
618
|
+
if input_prcp is not None:
|
|
619
|
+
input_prcp = tools.time_resample_prcp_array(
|
|
620
|
+
input_prcp,
|
|
621
|
+
input_dt,
|
|
622
|
+
self.mysetup.setup["dt"],
|
|
623
|
+
t_axis=2,
|
|
624
|
+
)
|
|
625
|
+
if input_pet is not None:
|
|
626
|
+
input_pet = tools.time_resample_prcp_array(
|
|
627
|
+
input_pet,
|
|
628
|
+
input_dt,
|
|
629
|
+
self.mysetup.setup["dt"],
|
|
630
|
+
t_axis=2,
|
|
631
|
+
)
|
|
632
|
+
input_dt = self.mysetup.setup["dt"]
|
|
633
|
+
|
|
634
|
+
# use conversion factor defined in setup
|
|
635
|
+
if "prcp_conversion_factor" in self.mysetup.setup and input_prcp is not None:
|
|
636
|
+
input_prcp = input_prcp * self.mysetup.setup["prcp_conversion_factor"]
|
|
637
|
+
if "pet_conversion_factor" in self.mysetup.setup and input_pet is not None:
|
|
638
|
+
input_pet = input_pet * self.mysetup.setup["pet_conversion_factor"]
|
|
639
|
+
|
|
640
|
+
self._myatmos_data_connector = atmos_data_connector.atmos_data_connector(
|
|
641
|
+
input_prcp=input_prcp,
|
|
642
|
+
input_pet=input_pet,
|
|
643
|
+
input_dt=input_dt,
|
|
644
|
+
input_res=input_res,
|
|
645
|
+
input_start_time=input_start_time,
|
|
646
|
+
input_bbox=input_bbox,
|
|
647
|
+
input_epsg=input_epsg,
|
|
648
|
+
)
|
|
649
|
+
|
|
650
|
+
smash_bbox = geo_toolbox.get_bbox_from_smash_mesh(self.mymesh.mesh)
|
|
651
|
+
|
|
652
|
+
self._myatmos_data_connector.read_input_atmos_data(
|
|
653
|
+
output_bbox=smash_bbox,
|
|
654
|
+
output_epsg=self._myparam.param.epsg,
|
|
655
|
+
output_res=(self.mymesh.mesh["xres"], self.mymesh.mesh["yres"]),
|
|
656
|
+
output_shape=(self.mymesh.mesh["nrow"], self.mymesh.mesh["ncol"]),
|
|
657
|
+
resampling_method=resampling_method,
|
|
658
|
+
)
|
|
659
|
+
|
|
660
|
+
self._myatmos_data_connector.change_setup(self.mysetup)
|
|
661
|
+
|
|
662
|
+
def import_parameters(self, model=None):
|
|
663
|
+
"""
|
|
664
|
+
Import Geotiff parameter in Smash. This function wrap
|
|
665
|
+
smash.io.import_parameters(). Path to the parameters is defined in
|
|
666
|
+
self._myparam.param.smash_parameters.
|
|
667
|
+
|
|
668
|
+
Parameter
|
|
669
|
+
---------
|
|
670
|
+
|
|
671
|
+
model: smash.Model object
|
|
672
|
+
A Smash model object. If None, the Smash model of smashbox will be used
|
|
673
|
+
|
|
674
|
+
Examples
|
|
675
|
+
--------
|
|
676
|
+
|
|
677
|
+
>>> es=smashbox.SmashBox()
|
|
678
|
+
>>> sb.newmodel("RealCollobrier")
|
|
679
|
+
>>> sb.RealCollobrier.generate_mesh(run=False)
|
|
680
|
+
>>> sb.RealCollobrier.model()
|
|
681
|
+
>>> sb.RealCollobrier.import_parameters()
|
|
682
|
+
>>> sb.RealCollobrier.forward_run()
|
|
683
|
+
"""
|
|
684
|
+
if self._myparam.param.smash_parameters is None:
|
|
685
|
+
print(
|
|
686
|
+
"</> Warning: no calibrated Smash parameters is used, leaving it to"
|
|
687
|
+
" default."
|
|
688
|
+
)
|
|
689
|
+
return
|
|
690
|
+
|
|
691
|
+
if model is None:
|
|
692
|
+
model = self.mysmashmodel
|
|
693
|
+
|
|
694
|
+
smash.io.import_parameters(
|
|
695
|
+
model=model,
|
|
696
|
+
path_to_parameters=self._myparam.param.smash_parameters,
|
|
697
|
+
)
|
|
698
|
+
|
|
699
|
+
def export_parameters(self, path: os.PathLike = "./output_smash_param"):
|
|
700
|
+
"""
|
|
701
|
+
Export Geotiff Smash parameter as Geotiff. This function wrap
|
|
702
|
+
smash.io.export_parameters().
|
|
703
|
+
|
|
704
|
+
Parameters
|
|
705
|
+
----------
|
|
706
|
+
|
|
707
|
+
path : os.PathLike = "./output_smash_param"
|
|
708
|
+
path to a directory where the parameter will be saved.
|
|
709
|
+
|
|
710
|
+
Examples
|
|
711
|
+
--------
|
|
712
|
+
|
|
713
|
+
>>> es=smashbox.SmashBox()
|
|
714
|
+
>>> sb.newmodel("RealCollobrier")
|
|
715
|
+
>>> sb.RealCollobrier.generate_mesh(run=False)
|
|
716
|
+
>>> sb.RealCollobrier.model()
|
|
717
|
+
>>> sb.RealCollobrier.import_parameters()
|
|
718
|
+
>>> sb.RealCollobrier.export_parameters()
|
|
719
|
+
"""
|
|
720
|
+
smash.io.export_parameters(self.mysmashmodel, path)
|
|
721
|
+
|
|
722
|
+
def save_model_container(
|
|
723
|
+
self, path_to_hdf5: str | None = None, save_smash_model: bool = True
|
|
724
|
+
):
|
|
725
|
+
"""
|
|
726
|
+
|
|
727
|
+
:param path_to_hdf5: Path to the hdf5 file, defaults to None. If None,
|
|
728
|
+
the fucntion will return a dictionnary containing all data of the self object.
|
|
729
|
+
:type path_to_hdf5: str | None, optional
|
|
730
|
+
:param save_smash_model: Savec the smash models objects or no, defaults
|
|
731
|
+
to True. If False the Smash models objects are not saved.
|
|
732
|
+
:type save_smash_model: str, optional
|
|
733
|
+
:return: if a path_to_hdf5 is None, a dictionary containing all
|
|
734
|
+
attribute of the input object self is returned.
|
|
735
|
+
:rtype: dict | None
|
|
736
|
+
|
|
737
|
+
"""
|
|
738
|
+
|
|
739
|
+
if path_to_hdf5 is not None:
|
|
740
|
+
|
|
741
|
+
structure = pyhdf5_handler.src.object_handler.generate_object_structure(
|
|
742
|
+
self, include_method=False
|
|
743
|
+
)
|
|
744
|
+
|
|
745
|
+
if not save_smash_model:
|
|
746
|
+
del structure["warmup_model"]
|
|
747
|
+
del structure["mysmashmodel"]
|
|
748
|
+
|
|
749
|
+
pyhdf5_handler.save_object_to_hdf5file(
|
|
750
|
+
path_to_hdf5=path_to_hdf5,
|
|
751
|
+
instance=self,
|
|
752
|
+
keys_data=structure,
|
|
753
|
+
)
|
|
754
|
+
|
|
755
|
+
else:
|
|
756
|
+
dict_results = pyhdf5_handler.src.object_handler.read_object_as_dict(self)
|
|
757
|
+
|
|
758
|
+
if not save_smash_model:
|
|
759
|
+
del dict_results["warmup_model"]
|
|
760
|
+
del dict_results["mysmashmodel"]
|
|
761
|
+
|
|
762
|
+
return dict_results
|
|
763
|
+
|
|
764
|
+
# def import_parameters(self)
|
|
765
|
+
# if os.path.exists(self._myparam.param.smash_parameters) and self._myparam.param.smash_parameters.endswith(".hdf5"):
|
|
766
|
+
|
|
767
|
+
# hdf5= pyhdf5_handler.open_hdf5(self._myparam.param.smash_parameters)
|
|
768
|
+
# hdf5_key=list(hdf5.keys())
|
|
769
|
+
# hdf5.close()
|
|
770
|
+
|
|
771
|
+
# if "model_ddt" in hdf5_key:
|
|
772
|
+
# with_param = pyhdf5_handler.read_hdf5file_as_dict(self._myparam.param.smash_parameters,location="model_ddt/rr_parameters")
|
|
773
|
+
# with_mesh = pyhdf5_handler.get_hdf5file_item(self._myparam.param.smash_parameters,location="model_ddt",item="mesh")
|
|
774
|
+
|
|
775
|
+
# smash_parameters.transfert_params_to_model(
|
|
776
|
+
# from_mesh=
|
|
777
|
+
# with_mesh,
|
|
778
|
+
# with_param=with_param,
|
|
779
|
+
# to_model=self.mysmashmodel)
|
|
780
|
+
|
|
781
|
+
# elif "model" in hdf5_key:
|
|
782
|
+
# with_param = pyhdf5_handler.get_hdf5file_item(self._myparam.param.smash_parameters,location="model",item="rr_parameters")
|
|
783
|
+
# with_mesh = pyhdf5_handler.get_hdf5file_item(self._myparam.param.smash_parameters,location="model",item="mesh")
|
|
784
|
+
|
|
785
|
+
# smash_parameters.transfert_params_to_model(
|
|
786
|
+
# from_mesh=
|
|
787
|
+
# with_mesh,
|
|
788
|
+
# with_param=with_param,
|
|
789
|
+
# to_model=self.mysmashmodel)
|
|
790
|
+
|
|
791
|
+
# elif "rr_parameters" in hdf5.keys() and "mesh" in hdf5.keys():
|
|
792
|
+
# with_param = pyhdf5_handler.get_hdf5file_item(self._myparam.param.smash_parameters,location="./",item="rr_parameters")
|
|
793
|
+
# with_mesh = pyhdf5_handler.get_hdf5file_item(self._myparam.param.smash_parameters,location="./",item="mesh")
|
|
794
|
+
|
|
795
|
+
# smash_parameters.transfert_params_to_model(
|
|
796
|
+
# from_mesh=with_mesh,
|
|
797
|
+
# with_param=with_param,
|
|
798
|
+
# to_model=self.mysmashmodel)
|
|
799
|
+
|
|
800
|
+
# else:
|
|
801
|
+
# raise ValueError("</> Error: cannot load the parameters ... unknown format...")
|
|
802
|
+
|
|
803
|
+
# elif os.path.isdir(self._myparam.param.smash_parameters):
|
|
804
|
+
|
|
805
|
+
# smash_parameters.load_param_from_tiffformat(model=self.mysmashmodel, path_to_parameters=self._myparam.param.smash_parameters)
|
|
806
|
+
|
|
807
|
+
# else:
|
|
808
|
+
# raise ValueError(f"</> Error: cannot load the parameters. Path or file '{self._myparam.param.smash_parameters}' does not exist ... ")
|
|
809
|
+
|
|
810
|
+
# def write_smashparam(self, hdf5file : str | os.PathLike = "output_smash_param.hdf5"):
|
|
811
|
+
|
|
812
|
+
# rr_parameters=pyhdf5_handler.read_object_as_dict(self.mysmashmodel.rr_parameters)
|
|
813
|
+
# pyhdf5_handler.save_dict_to_hdf5(hdf5file, rr_parameters)
|
|
814
|
+
|
|
815
|
+
# def export_parameters(self, path : os.path = "./output_smash_param")
|
|
816
|
+
|
|
817
|
+
# list_param=list(self.mysmashmodel.rr_parameters.keys)
|
|
818
|
+
|
|
819
|
+
# for smparam in list_param:
|
|
820
|
+
|
|
821
|
+
# array=self.mysmashmodel.rr_parameters.values[:,:,list_param.index(smparam)]
|
|
822
|
+
|
|
823
|
+
# smash_parameters.write_array_to_geotiff(os.path.join(path, smparam+".tif"),
|
|
824
|
+
# array,
|
|
825
|
+
# self.mysmashmodel.mesh.xmin,
|
|
826
|
+
# self.mysmashmodel.mesh.ymax,
|
|
827
|
+
# output_res = (self.mymesh.mesh["xres"],
|
|
828
|
+
# self.mymesh.mesh["yres"])
|
|
829
|
+
# )
|