/
pcr_rout_dynfloodplain_v3_forsubsample.py
executable file
·431 lines (419 loc) · 22.4 KB
/
pcr_rout_dynfloodplain_v3_forsubsample.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
#-PCR-GLOBWB Routing scheme: basic implementation for python version
# with the following characteristics:
# * total water storage [m3] of which volume in excess of channel storage is used as flood volume
# and distributed over the surrounding area using smooth floodplain transitions based on Kavetski and Kuczera (2007)
# * flood wave propagation can be described by means of the kinematic wave or a simpler traveltime function
# * lakes and reservoirs are included by means of the waterbodies class
import os, datetime, calendar
import pcraster as pcr
import pcraster.framework as pcrm
#############################################################################
#-start of model script #######################################################
################################################################################
class pcrglobRoutingDynFloodPlains(pcrm.DynamicModel):
def __init__(self,startDate,endDate,nrIterDefault= 12.):
pcrm.DynamicModel.__init__(self)
##############
# * __init__ #
##############
#-echo to screen
print 'PCR-GLOBWB dynamic floodplain model - version 3.0 June 2012'
print '\tbeta version with smoothed floodplain elevations'
print '\tincluding lakes and reservoirs'
#-constants: duration of time step (day) in seconds
self.timeSec= duration*timeSec
#-passing global variables to local ones
#-cloone and cell area
self.clone= clone
self.cellArea= cellArea
#-model settings
self.nrIterDefault= nrIterDefault
self.duration= duration
self.currentDate= startDate
self.endDate= endDate
self.areaFractions= areaFractions
self.relZFileName= os.path.join(mapsDir,relZFileName)
self.reductionKK= reductionKK
self.criterionKK= criterionKK
#-number of entries in list and derived slopes and volumes
self.nrEntries= len(self.areaFractions)
self.relZ= [0.]*self.nrEntries
self.floodVolume= [0.]*(self.nrEntries)
#-flood plain and channel characteristics
self.channelGradient= pcr.max(1.e-7,channelGradient)
self.LDD= LDD
self.channelWidth= channelWidth
self.channelLength= channelLength
self.channelDepth= channelDepth
self.channelManN= channelManN
self.floodplainManN= floodplainManN
self.floodplainMask= floodplainMask
self.waterFractionMask= fractionWater
#-waterBodies
self.waterBodies= waterBodies
self.waterBodies.actualArea= self.waterBodies.retrieveMapValue(pcr.areatotal(self.waterFractionMask*\
self.cellArea,self.waterBodies.distribution))
#self.reservoirDemandTSS= readTSS(reservoirDemandTSS)
#-map names: initial maps of discharge and storage
self.QIniMap= pcrm.generateNameT(QFileName,0).replace('.000','.ini')
self.actualStorageIniMap= pcrm.generateNameT(actualStorageFileName,0).replace('.000','.ini')
self.averageQ= averageQ
self.bankfulQ= bankfulQ
#-patch elevations: those that are part of sills are updated on the basis of the floodplain gradient
# using local distances deltaX per increment upto z[N] and the sum over sills
#-fill all lists including smoothing interval and slopes
for iCnt in range(1,self.nrEntries):
self.relZ[iCnt]= clippedRead.get(self.relZFileName %\
(self.areaFractions[iCnt]*100))
#-minimum slope of floodplain, being defined as the longest sill, first used to retrieve
# longest cumulative distance
deltaX= [self.cellArea**0.5]*self.nrEntries
deltaX[0]= 0.
sumX= deltaX[:]
minSlope= 0.
for iCnt in range(self.nrEntries):
if iCnt < self.nrEntries-1:
deltaX[iCnt]= (self.areaFractions[iCnt+1]**0.5-self.areaFractions[iCnt]**0.5)*deltaX[iCnt]
else:
deltaX[iCnt]= (1.-self.areaFractions[iCnt-1]**0.5)*deltaX[iCnt]
if iCnt > 0:
sumX[iCnt]= pcr.ifthenelse(self.relZ[iCnt] == self.relZ[iCnt-1],sumX[iCnt-1]+deltaX[iCnt],0.)
minSlope= pcr.ifthenelse(self.relZ[iCnt] == self.relZ[iCnt-1],\
pcr.max(sumX[iCnt],minSlope),minSlope)
minSlope= pcr.min(self.channelGradient,0.5*pcr.max(deltaX[1],minSlope)**-1.)
#-add small increment to elevations to each sill except in the case of lakes
for iCnt in range(self.nrEntries):
self.relZ[iCnt]= self.relZ[iCnt]+sumX[iCnt]*pcr.ifthenelse(self.relZ[self.nrEntries-1] > 0.,\
minSlope,0.)
#-set slope and smoothing interval between dy= y(i+1)-y(i) and dx= x(i+1)-x(i)
# on the basis of volume
#-slope and smoothing interval
self.kSlope= [0.]*(self.nrEntries)
self.mInterval= [0.]*(self.nrEntries)
for iCnt in range(1,self.nrEntries):
self.floodVolume[iCnt]= self.floodVolume[iCnt-1]+\
0.5*(self.areaFractions[iCnt]+self.areaFractions[iCnt-1])*\
(self.relZ[iCnt]-self.relZ[iCnt-1])*self.cellArea
self.kSlope[iCnt-1]= (self.areaFractions[iCnt]-self.areaFractions[iCnt-1])/\
pcr.max(0.001,self.floodVolume[iCnt]-self.floodVolume[iCnt-1])
for iCnt in range(1,self.nrEntries):
if iCnt < (self.nrEntries-1):
self.mInterval[iCnt]= 0.5*self.reductionKK*pcr.min(self.floodVolume[iCnt+1]-self.floodVolume[iCnt],\
self.floodVolume[iCnt]-self.floodVolume[iCnt-1])
else:
self.mInterval[iCnt]= 0.5*self.reductionKK*(self.floodVolume[iCnt]-self.floodVolume[iCnt-1])
def integralLogisticFunction(self,x):
#-returns a tupple of two values holding the integral of the logistic functions
# of (x) and (-x)
logInt=pcr.ln(pcr.exp(-x)+1)
return logInt,x+logInt
def returnFloodedFraction(self,volume):
#-returns the flooded fraction given the flood volume and the associated water height
# using a logistic smoother near intersections (K&K, 2007)
#-find the match on the basis of the shortest distance to the available intersections or steps
deltaXMin= self.floodVolume[self.nrEntries-1]
y_i= pcr.scalar(1.)
k= [pcr.scalar(0.)]*2
mInt= pcr.scalar(0.)
for iCnt in range(self.nrEntries-1,0,-1):
#-find x_i for current volume and update match if applicable
# also update slope and intercept
deltaX= volume-self.floodVolume[iCnt]
mask= pcr.abs(deltaX) < pcr.abs(deltaXMin)
deltaXMin= pcr.ifthenelse(mask,deltaX,deltaXMin)
y_i= pcr.ifthenelse(mask,self.areaFractions[iCnt],y_i)
k[0]= pcr.ifthenelse(mask,self.kSlope[iCnt-1],k[0])
k[1]= pcr.ifthenelse(mask,self.kSlope[iCnt],k[1])
mInt= pcr.ifthenelse(mask,self.mInterval[iCnt],mInt)
#-all values returned, process data: calculate scaled deltaX and smoothed function
# on the basis of the integrated logistic functions PHI(x) and 1-PHI(x)
deltaX= deltaXMin
deltaXScaled= pcr.ifthenelse(deltaX < 0.,pcr.scalar(-1.),1.)*\
pcr.min(criterionKK,pcr.abs(deltaX/pcr.max(1.,mInt)))
logInt= self.integralLogisticFunction(deltaXScaled)
#-compute fractional flooded area and flooded depth
floodedFraction= pcr.ifthenelse(volume > 0.,\
pcr.ifthenelse(pcr.abs(deltaXScaled) < criterionKK,\
y_i-k[0]*mInt*logInt[0]+k[1]*mInt*logInt[1],\
y_i+pcr.ifthenelse(deltaX < 0.,k[0],k[1])*deltaX),0.)
floodedFraction= pcr.max(0.,pcr.min(1.,floodedFraction))
floodDepth= pcr.ifthenelse(floodedFraction > 0.,volume/(floodedFraction*self.cellArea),0.)
return floodedFraction, floodDepth
def kinAlphaStatic(self,watStor):
#-given the total water storage in the cell, returns the Q-A relationship
# for the kinematic wave and required parameters using a static floodplain extent
wetA= watStor/self.channelLength
wetP= 2.*wetA/self.channelWidth+self.channelWidth
alphaQ= (self.channelManN*wetP**(2./3.)*self.channelGradient**-0.5)**self.betaQ
#-returning variable of interest: flooded fraction, cross-sectional area
# and alphaQ
return wetA,alphaQ
def kinAlphaDynamic(self,watStor):
#-given the total water storage in the cell, returns the Q-A relationship
# for the kinematic wave and required parameters
floodVol= pcr.max(0,watStor-self.channelStorageCapacity)
floodFrac, floodZ= self.returnFloodedFraction(floodVol)
#-wetted perimeter, cross-sectional area and
# corresponding mannings' n
wetA= watStor/self.channelLength
#-wetted perimeter, alpha and composite manning's n
wetPFld= pcr.max(0.,floodFrac*self.cellArea/self.channelLength-\
self.channelWidth)+2.*floodZ
wetPCh= self.channelWidth+\
2.*pcr.min(self.channelDepth,watStor/self.channelArea)
wetP= wetPFld+wetPCh
manQ= (wetPCh/wetP*self.channelManN**1.5+\
wetPFld/wetP*self.floodplainManN**1.5)**(2./3.)
alphaQ= (manQ*wetP**(2./3.)*self.channelGradient**-0.5)**self.betaQ
#-returning variables of interest: flooded fraction, cross-sectional area
# and alphaQ
return floodFrac,floodZ,wetA,alphaQ
def kinAlphaComposite(self,watStor,mask):
#-given the total water storage and the mask specifying the occurrence of
# floodplain conditions, retrns the Q-A relationship for the kinematic
# wave and the associated parameters
floodplainStorage= pcr.ifthen(mask,watStor)
floodFrac, floodZ, dynamicWetA, dynamicAlphaQ= self.kinAlphaDynamic(floodplainStorage)
staticWetA, staticAlphaQ= self.kinAlphaStatic(watStor)
floodFrac= pcr.ifthenelse(mask,floodFrac,0.)
floodZ= pcr.ifthenelse(mask,floodZ,0.)
wetA= pcr.ifthenelse(mask,dynamicWetA,staticWetA)
alphaQ= pcr.ifthenelse(mask,dynamicAlphaQ,staticAlphaQ)
return floodFrac,floodZ,wetA,alphaQ
def initial(self):
#####################
# * initial section #
#####################
#-constants
# betaQ [-]: constant of kinematic wave momentum equation
self.betaQ= 0.6
#-channel LDD
self.channelLDD= pcr.ifthenelse(self.waterBodies.distribution != 0,\
pcr.ldd(5),self.LDD)
#-channel area and storage
self.channelArea= self.channelWidth*self.channelLength
self.channelStorageCapacity= pcr.ifthenelse(self.waterBodies.distribution == 0,\
self.channelArea*self.channelDepth,pcr.scalar(0.))
#-basin outlets
self.basinOutlet= pcr.pit(self.LDD) != 0
#-read initial conditions
self.Q= clippedRead.get(self.QIniMap)
self.actualStorage= clippedRead.get(self.actualStorageIniMap)
self.actualStorage= pcr.ifthenelse(self.waterBodies.distribution != 0,\
pcr.ifthenelse(self.waterBodies.location != 0,\
pcr.areatotal(self.actualStorage,self.waterBodies.distribution),0),\
self.actualStorage)
self.waterBodies.actualStorage= self.waterBodies.retrieveMapValue(self.actualStorage)
#-update targets of average and bankful discharge
self.waterBodies.averageQ= self.waterBodies.retrieveMapValue(self.averageQ)
self.waterBodies.bankfulQ= self.waterBodies.retrieveMapValue(self.bankfulQ)
#-return the parameters for the kinematic wave,
# including alpha, wetted area, flood fraction, flood volume and depth
# and the corresponding land area
floodedFraction,floodedDepth,\
self.wettedArea,self.alphaQ= self.kinAlphaComposite(self.actualStorage,self.floodplainMask)
self.wettedArea= self.waterBodies.returnMapValue(self.wettedArea,\
self.waterBodies.channelWidth+2.*self.waterBodies.updateWaterHeight())
self.waterFraction= pcr.ifthenelse(self.waterBodies.distribution == 0,\
pcr.max(self.waterFractionMask,floodedFraction),self.waterFractionMask)
self.landFraction= pcr.max(0.,1.-self.waterFraction)
#-update on velocity and check on Q - NOTE: does not work in case of reservoirs!
self.flowVelocity= pcr.ifthenelse(self.wettedArea > 0,self.Q/self.wettedArea,0.)
pcr.report(self.flowVelocity,pcrm.generateNameT(flowVelocityFileName,0).replace('.000','.ini'))
#-setting initial values for specific runoff and surface water extraction
self.landSurfaceQ= pcr.scalar(0.)
self.potWaterSurfaceQ= pcr.scalar(0.)
self.surfaceWaterExtraction= pcr.scalar(0.)
#-budget check: setting initial values for cumulative discharge and
# net cumulative input, including initial storage [m3]
self.totalDischarge= pcr.scalar(0.)
self.cumulativeDeltaStorage= pcr.catchmenttotal(self.actualStorage,self.LDD)
def dynamic(self):
#####################
# * dynamic section #
#####################
#-evaluation of the current date: return current month and the time step used
#-reading in fluxes over land and water area for current time step [m/d]
# and read in reservoir demand and surface water extraction [m3]
try:
self.landSurfaceQ= clippedRead.get(pcrm.generateNameT(landSurfaceQFileName,self.currentTimeStep()))
except:
pass
try:
self.potWaterSurfaceQ= clippedRead.get(pcrm.generateNameT(waterSurfaceQFileName,self.currentTimeStep()))
except:
pass
#-surface water extraction and reservoir demand currently set to zero, should
# be computed automatically and updated to reservoirs
self.potSurfaceWaterExtraction= pcr.spatial(pcr.scalar(0.))
#self.waterBodies.demand= #self.reservoirDemandTSS.assignID(self.waterBodies.ID,self.currentTimeStep(),0.)*self.timeSec
#-initialization of cumulative values of actual water extractions
self.actWaterSurfaceQ= pcr.spatial(pcr.scalar(0.))
self.actSurfaceWaterExtraction= pcr.spatial(pcr.scalar(0.))
#-definition of sub-loop for routing scheme - explicit scheme has to satisfy Courant condition
timeLimit= pcr.cellvalue(pcr.mapminimum((pcr.cover(pcr.ifthen(self.waterBodies.distribution == 0,\
self.channelLength/self.flowVelocity),\
self.timeSec/self.nrIterDefault)*self.timeSec/self.nrIterDefault)**0.5),1)[0]
nrIter= int(self.timeSec/timeLimit)
nrIter= min(nrIter,int(self.timeSec/300.))
while float(self.timeSec/nrIter) % 1 <> 0:
nrIter+= 1
deltaTime= self.timeSec/nrIter
#-sub-loop for current time step
if self.currentDate.day == 1 or nrIter >= 24:
print '\n*\tprocessing %s, currently using %d substeps of %d seconds\n' % \
(self.currentDate.date(),nrIter,deltaTime)
#-update discharge and storage
for nrICur in range(nrIter):
#-initializing discharge for the current sub-timestep and fill in values
# for channels and at outlets of waterbodies
# * channels *
estQ= pcr.ifthenelse((self.actualStorage > 0.) & (self.waterBodies.distribution == 0) ,\
(self.wettedArea/self.alphaQ)**(1./self.betaQ),0.)
#estQ= pcr.ifthenelse((self.actualStorage > 0.) & (self.waterBodies.distribution == 0) ,\
#0.5*(self.Q+(self.wettedArea/self.alphaQ)**(1./self.betaQ)),0.)
#estQ= pcr.min(estQ,self.actualStorage/deltaTime)
self.report(estQ,'results/qest')
self.Q= pcr.spatial(pcr.scalar(0.))
self.Q= pcr.ifthenelse(self.waterBodies.distribution == 0,\
pcr.kinematic(self.channelLDD,estQ,0.,self.alphaQ,\
self.betaQ,1,deltaTime,self.channelLength),self.Q)
# * water bodies *
self.waterBodies.dischargeUpdate()
self.Q= self.waterBodies.returnMapValue(self.Q,self.waterBodies.actualQ)
#-fluxes and resulting change in storage: first the local fluxes are evaluated
# and aggregated over the water bodies where applicable; this includes the specific runoff [m/day/m2]
# from input and the estimated extraction from surface water as volume per day [m3/day];
# specific runoff from the land surface is always positive whereas the fluxes over the water surface
# are potential, including discharge, and are adjusted to match the availabe storage; to this end,
# surface water storage and fluxes over water bodies are totalized and assigned to the outlet;
# discharge is updated in a separate step, after vertical fluxes are compared to the actual storage
deltaActualStorage= ((self.landFraction*self.landSurfaceQ+\
self.waterFraction*self.potWaterSurfaceQ)*self.cellArea-\
self.potSurfaceWaterExtraction)*float(self.duration)/nrIter
deltaActualStorage= pcr.ifthenelse(self.waterBodies.distribution != 0,\
pcr.ifthenelse(self.waterBodies.location != 0,\
pcr.areatotal(deltaActualStorage,self.waterBodies.distribution),0),\
deltaActualStorage)
adjustmentRatio= pcr.ifthenelse(deltaActualStorage < 0.,\
pcr.min(1.,-self.actualStorage/deltaActualStorage),1.)
self.actWaterSurfaceQ+= adjustmentRatio*self.potWaterSurfaceQ
self.actSurfaceWaterExtraction+= adjustmentRatio*self.actSurfaceWaterExtraction
deltaActualStorage*= adjustmentRatio
#-local water balance check
if testLocalWaterBalance:
differenceActualStorage= self.actualStorage
differenceActualStorage+= deltaActualStorage
#-overall water balance check: net input
self.cumulativeDeltaStorage+= pcr.catchmenttotal(deltaActualStorage,self.LDD)
#-update storage first with local changes, then balance discharge with storage and update storage
# with lateral flow and return value to water bodies
self.actualStorage+= deltaActualStorage
self.actualStorage= pcr.max(0.,self.actualStorage)
self.Q= pcr.min(self.Q,self.actualStorage/deltaTime)
deltaActualStorage= (-self.Q+pcr.upstream(self.LDD,self.Q))*deltaTime
deltaActualStorage= pcr.ifthenelse(self.waterBodies.distribution != 0,\
pcr.ifthenelse(self.waterBodies.location != 0,\
pcr.areatotal(deltaActualStorage,self.waterBodies.distribution),0),\
deltaActualStorage)
self.actualStorage+= deltaActualStorage
self.actualStorage= pcr.max(0.,self.actualStorage)
self.waterBodies.actualStorage= self.waterBodies.retrieveMapValue(self.actualStorage)
#-flooded fraction returned
floodedFraction,floodedDepth,\
self.wettedArea,self.alphaQ= self.kinAlphaComposite(self.actualStorage,self.floodplainMask)
self.wettedArea= self.waterBodies.returnMapValue(self.wettedArea,\
self.waterBodies.channelWidth+2.*self.waterBodies.updateWaterHeight())
self.waterFraction= pcr.ifthenelse(self.waterBodies.distribution == 0,\
pcr.max(self.waterFractionMask,floodedFraction),self.waterFractionMask)
self.landFraction= pcr.max(0.,1.-self.waterFraction)
self.flowVelocity= pcr.ifthenelse(self.wettedArea > 0,self.Q/self.wettedArea,0.)
#-local water balance check
if testLocalWaterBalance:
differenceActualStorage+= deltaActualStorage
differenceActualStorage-= self.actualStorage
totalDifference= pcr.cellvalue(pcr.maptotal(differenceActualStorage),1)[0]
minimumDifference= pcr.cellvalue(pcr.mapminimum(differenceActualStorage),1)[0]
maximumDifference= pcr.cellvalue(pcr.mapmaximum(differenceActualStorage),1)[0]
if abs(totalDifference) > 1.e-3:
print 'water balance error: total %e; min %e; max %e' %\
(totalDifference,minimumDifference,maximumDifference)
if reportLocalWaterBalance:
pcr.report(differenceActualStorage,'mbe_%s.map' % self.currentDate.date())
#-overall water balance check: updating cumulative discharge and total storage [m3]
self.totalDischarge+= self.Q*deltaTime
self.totalStorage= pcr.catchmenttotal(self.actualStorage,self.LDD)
#-check on occurrence of last day and report mass balance
if self.currentDate == self.endDate:
#-report initial maps
pcr.report(self.Q,self.QIniMap)
pcr.report(self.actualStorage,self.actualStorageIniMap)
#-return relative and absolute water balance error per cell and
# as total at basin outlets
self.totalDischarge= pcr.ifthen((self.waterBodies.distribution == 0) | \
(self.waterBodies.location != 0),self.totalDischarge)
self.cumulativeDeltaStorage= pcr.ifthen((self.waterBodies.distribution == 0) | \
(self.waterBodies.location != 0),self.cumulativeDeltaStorage)
massBalanceError= self.totalStorage+self.totalDischarge-\
self.cumulativeDeltaStorage
relMassBalanceError= 1.+pcr.ifthenelse(self.cumulativeDeltaStorage <> 0.,
massBalanceError/self.cumulativeDeltaStorage,0.)
totalMassBalanceError= pcr.cellvalue(pcr.maptotal(pcr.ifthen(self.basinOutlet,\
massBalanceError)),1)[0]
totalCumulativeDeltaStorage= pcr.cellvalue(pcr.maptotal(pcr.ifthen(self.basinOutlet,\
self.cumulativeDeltaStorage)),1)[0]
if totalCumulativeDeltaStorage > 0:
totalRelativeMassBalanceError= 1.+totalMassBalanceError/totalCumulativeDeltaStorage
else:
totalRelativeMassBalanceError= 1.
#-report maps and echo value
pcr.report(massBalanceError,mbeFileName)
pcr.report(relMassBalanceError,mbrFileName)
print '\n*\ttotal global mass balance error [m3]: %8.3g' % totalMassBalanceError
print '\n*\trelative global mass balance error [-]: %5.3f' % totalRelativeMassBalanceError
#-echo to screen: total mass balance error and completion of run
print '\trun completed'
#-end of day: return states and fluxes
#-get surface water attributes?
if getSurfaceWaterAttributes:
#-compute the following secondary variables:
# surface water area [m2]: area given dynamic surface water fraction
# residence time [days]: volume over discharge, assigned -1 in case discharge is zero
# surface water depth [m], weighed by channel and floodplain volume
surfaceWaterArea= self.waterFraction*self.cellArea
surfaceWaterArea= pcr.ifthenelse(self.waterBodies.distribution != 0,\
pcr.ifthenelse(self.waterBodies.location != 0,\
pcr.areatotal(surfaceWaterArea,self.waterBodies.distribution),0),\
surfaceWaterArea)
surfaceWaterResidenceTime= pcr.ifthenelse(self.Q > 0.,self.actualStorage/(self.Q*self.timeSec),-1)
surfaceWaterDepth= pcr.ifthenelse(self.actualStorage > 0.,\
pcr.max(0.,self.actualStorage-self.channelStorageCapacity)**2/\
(self.actualStorage*surfaceWaterArea),0.)
surfaceWaterDepth+= pcr.ifthenelse(self.actualStorage > 0.,\
pcr.min(self.channelStorageCapacity,self.actualStorage)**2/(self.waterFractionMask*\
self.cellArea*self.actualStorage),0.)
#-reports: values at outlet of lakes or reservoirs are assigned to their full extent
self.report(pcr.ifthenelse(self.waterBodies.distribution != 0,\
pcr.areamaximum(surfaceWaterArea,self.waterBodies.distribution),surfaceWaterArea),\
surfaceWaterAreaFileName)
self.report(pcr.ifthenelse(self.waterBodies.distribution != 0,\
pcr.areamaximum(surfaceWaterResidenceTime,self.waterBodies.distribution),surfaceWaterResidenceTime),\
surfaceWaterResidenceTimeFileName)
self.report(pcr.ifthenelse(self.waterBodies.distribution != 0,\
pcr.areamaximum(surfaceWaterDepth,self.waterBodies.distribution),surfaceWaterDepth),\
surfaceWaterDepthFileName)
#-reports on standard output: values at outlet of lakes or reservoirs are assigned to their full extent
self.report(pcr.ifthenelse(self.waterBodies.distribution != 0,
pcr.areamaximum(self.flowVelocity,self.waterBodies.distribution),self.flowVelocity),flowVelocityFileName)
self.report(pcr.ifthenelse(self.waterBodies.distribution != 0,
pcr.areamaximum(self.Q,self.waterBodies.distribution),self.Q),QFileName)
self.report(pcr.ifthenelse(self.waterBodies.distribution == 0,\
floodedFraction,0.),floodedFractionFileName)
self.report(pcr.ifthenelse(self.waterBodies.distribution == 0,\
floodedDepth,0.),floodedDepthFileName)
self.report(self.actualStorage,actualStorageFileName)
#-update date for time step and report relevant daily output
self.currentDate= self.currentDate+datetime.timedelta(self.duration)
############################################################################
#-end of model script ######################################################
############################################################################