18
18
from __future__ import absolute_import , print_function
19
19
20
20
import numpy as np
21
+ import warnings
22
+ import xarray as xr
23
+ import numpy as np
24
+ import scipy
21
25
22
26
from ..global_modules .settings import MaskInfo , LisSettings
23
27
from ..global_modules .add1 import loadmap , defsoil
24
28
from . import HydroModule
29
+ from ..global_modules .errors import LisfloodWarning , LisfloodError
25
30
from collections import OrderedDict
26
31
#from global_modules.add1 import *
27
- import xarray as xr
28
- import numpy as np ##### 2024
29
- import scipy ##### 2024
30
- from scipy .optimize import least_squares ##### 2024
31
32
32
- def function_estimate (satdegrthetastart ,* data ): ##### 2024
33
- SeepTopToSubBPixelAv , KSat2 ,GenuInvM2 , GenuM2 = data
34
- return SeepTopToSubBPixelAv - KSat2 * np .sqrt (satdegrthetastart ) * (1. - (1. - satdegrthetastart ** GenuInvM2 ) ** GenuM2 ) ** 2
33
+ from scipy .optimize import least_squares
34
+
35
+ def function_estimate (satdegrthetastart ,* data ):
36
+ SeepTopToSubBAv , KSat2 ,GenuInvM2 , GenuM2 = data
37
+ return SeepTopToSubBAv - KSat2 * np .sqrt (satdegrthetastart ) * (1. - (1. - satdegrthetastart ** GenuInvM2 ) ** GenuM2 ) ** 2
35
38
36
39
def pressure2SoilMoistureFun (residual_sm , sat_sm , GenuA , GenuN , GenuM ):
37
40
"""Generate a function to compute soil moisture values corresponding to characteristic pressure head levels [cm].
@@ -78,8 +81,8 @@ def initial(self):
78
81
""" initial part of the soil module
79
82
"""
80
83
maskinfo = MaskInfo .instance ()
81
- self .var .cumSeepTopToSubBAv = self .var .allocateVariableAllVegetation () #######2024
82
- self .var .SeepTopToSubBAv = self .var .allocateVariableAllVegetation () #######2024
84
+ self .var .cumSeepTopToSubBAv = self .var .allocateVariableAllVegetation ()
85
+ self .var .SeepTopToSubBAv = self .var .allocateVariableAllVegetation ()
83
86
84
87
def splitlanduse (array1 , array2 = None , array3 = None ):
85
88
""" splits maps into the 3 different land use types - other , forest, irrigation
@@ -273,7 +276,7 @@ def splitlanduse(array1, array2=None, array3=None):
273
276
# Set to zero if soil depth is zero.
274
277
# IMPORTANT: WInit1 and WInit2 represent the soil moisture in the *permeable* fraction of the pixel *only*
275
278
# (since all soil moisture-related calculations are done for permeable fraction only!).
276
- if not option ['InitLisflood' ]:
279
+ if not option ['InitLisflood' ] and not option [ 'WarmStart' ] :
277
280
self .var .SeepTopToSubBAv [0 ] = loadmap ('SeepTopToSubBAverageOtherMap' )
278
281
self .var .SeepTopToSubBAv [1 ] = loadmap ('SeepTopToSubBAverageForestMap' )
279
282
self .var .SeepTopToSubBAv [2 ] = loadmap ('SeepTopToSubBAverageIrrigationMap' )
@@ -290,19 +293,20 @@ def splitlanduse(array1, array2=None, array3=None):
290
293
self .var .W2 [iveg ] = np .where (self .var .PoreSpaceNotZero2 [iluse ], ini_2 , 0 )
291
294
292
295
293
- if not option ['InitLisflood' ] and not option ['WarmStart' ]: ## 2024
294
-
295
- check_var_coldstart = np .min (self .var .SeepTopToSubBAv [0 ]) ######################### TO BE CORRECTED!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
296
-
297
- if check_var_coldstart < 0.0 :
298
- warnings .warn (LisfloodWarning ('WARNING: soil moisture end states OR average fluxes not provided/erroneous. Soil moisture states are initialized at field capacity' ))
296
+ if not option ['InitLisflood' ] and not option ['WarmStart' ]:
297
+ check_prerun_results1 = np .min (ThetaInit2Value [iveg ])
298
+ check_prerun_results2 = np .min (self .var .SeepTopToSubBAv [iluse ])
299
+ check_prerun_results = np .min ([check_prerun_results1 ,check_prerun_results2 ])
300
+
301
+ if check_prerun_results < 0.0 :
302
+ warnings .warn (LisfloodWarning ('WARNING: soil moisture end state for bottom layer OR average fluxes not provided/erroneous. Soil moisture states are initialized at field capacity' ))
299
303
else :
300
- SOLVED = ((ThetaInit2Value [iveg ] * self .var .SoilDepth2 [iluse ])- self .var .WRes2 [iluse ])/ (self .var .WS2 [iluse ]- self .var .WRes2 [iluse ]) #### for extra safety - stef
304
+ SOLVED = ((ThetaInit2Value [iveg ] * self .var .SoilDepth2 [iluse ])- self .var .WRes2 [iluse ])/ (self .var .WS2 [iluse ]- self .var .WRes2 [iluse ])
301
305
for ii in np .arange (len (ThetaInit2Value [iveg ])):
302
306
data = []
303
307
analyticalcheckzero = []
304
308
data = (self .var .SeepTopToSubBAv [iluse ][ii ], self .var .KSat2 [iluse ][ii ], self .var .GenuInvM2 [iluse ][ii ], self .var .GenuM2 [iluse ][ii ])
305
- analyticalcheckzero = least_squares (function_estimate ,((ThetaInit2Value [iveg ][ii ] * self .var .SoilDepth2 [iluse ][ii ])- self .var .WRes2 [iluse ][ii ])/ (self .var .WS2 [iluse ][ii ]- self .var .WRes2 [iluse ][ii ]),bounds = (self .var .WFC2 [iluse ][ii ]* 0 ,self .var .WFC2 [iluse ][ii ]* 0 + 1.0 ), args = data )
309
+ analyticalcheckzero = least_squares (function_estimate ,((ThetaInit2Value [iveg ][ii ] * self .var .SoilDepth2 [iluse ][ii ])- self .var .WRes2 [iluse ][ii ])/ (self .var .WS2 [iluse ][ii ]- self .var .WRes2 [iluse ][ii ]),bounds = (self .var .WFC2 [iluse ][ii ]* 0 ,self .var .WFC2 [iluse ][ii ]* 0 + 1.0 ), gtol = 10e-12 , args = data )
306
310
SOLVED [ii ]= analyticalcheckzero .x
307
311
ini_2 = SOLVED * (self .var .WS2 [iluse ]- self .var .WRes2 [iluse ])+ self .var .WRes2 [iluse ]
308
312
self .var .W2 [iveg ] = np .where (self .var .PoreSpaceNotZero2 [iluse ], ini_2 , 0 )
@@ -504,6 +508,10 @@ def dynamic_perpixel(self):
504
508
""" dynamic part of the soil module
505
509
Calculation per Pixel
506
510
"""
511
+ settings = LisSettings .instance ()
512
+ option = settings .options
513
+ binding = settings .binding
514
+
507
515
self .var .TaInterceptionAll = self .var .deffraction (self .var .TaInterception ) + self .var .DirectRunoffFraction * self .var .TASealed
508
516
self .var .TaInterceptionCUM += self .var .TaInterceptionAll
509
517
self .var .TaInterceptionWB = self .var .TaInterceptionAll
@@ -540,12 +548,15 @@ def dynamic_perpixel(self):
540
548
# Pixel-average seepage values in [mm] per timestep
541
549
# (no seepage from direct runoff fraction)
542
550
543
- self .var .cumSeepTopToSubBAv [0 ] += self .var .SeepTopToSubB [0 ] #### 2024
544
- self .var .SeepTopToSubBAv [0 ] = (self .var .cumSeepTopToSubBAv [0 ] * self .var .InvDtDay ) / (self .var .TimeSinceStart ) #### 2024
545
- self .var .cumSeepTopToSubBAv [1 ] += self .var .SeepTopToSubB [1 ] #### 2024
546
- self .var .SeepTopToSubBAv [1 ] = (self .var .cumSeepTopToSubBAv [1 ] * self .var .InvDtDay ) / (self .var .TimeSinceStart ) #### 2024
547
- self .var .cumSeepTopToSubBAv [2 ] += self .var .SeepTopToSubB [2 ] #### 2024
548
- self .var .SeepTopToSubBAv [2 ] = (self .var .cumSeepTopToSubBAv [2 ] * self .var .InvDtDay ) / (self .var .TimeSinceStart ) #### 2024
551
+ if option ['InitLisflood' ]:
552
+ NumDaysSpinUp = float (binding ['NumDaysSpinUp' ])
553
+ if (self .var .TimeSinceStart > np .round (NumDaysSpinUp / self .var .DtDay )) :
554
+ self .var .cumSeepTopToSubBAv [0 ] += self .var .SeepTopToSubB [0 ]
555
+ self .var .SeepTopToSubBAv [0 ] = (self .var .cumSeepTopToSubBAv [0 ] * self .var .InvDtDay ) / (self .var .TimeSinceStart - np .round (NumDaysSpinUp / self .var .DtDay ))
556
+ self .var .cumSeepTopToSubBAv [1 ] += self .var .SeepTopToSubB [1 ]
557
+ self .var .SeepTopToSubBAv [1 ] = (self .var .cumSeepTopToSubBAv [1 ] * self .var .InvDtDay ) / (self .var .TimeSinceStart - np .round (NumDaysSpinUp / self .var .DtDay ))
558
+ self .var .cumSeepTopToSubBAv [2 ] += self .var .SeepTopToSubB [2 ]
559
+ self .var .SeepTopToSubBAv [2 ] = (self .var .cumSeepTopToSubBAv [2 ] * self .var .InvDtDay ) / (self .var .TimeSinceStart - np .round (NumDaysSpinUp / self .var .DtDay ))
549
560
550
561
551
562
# the variables below were added to report catchment-averaged soil moisture profiles
0 commit comments