wolfhece 2.1.13__py3-none-any.whl → 2.1.15__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.
- wolfhece/PyDraw.py +28 -11
- wolfhece/PyGui.py +27 -4
- wolfhece/PyParams.py +1 -1
- wolfhece/PyVertexvectors.py +14 -0
- wolfhece/apps/version.py +1 -1
- wolfhece/fonts/arial.ttf +0 -0
- wolfhece/hydrology/Catchment.py +87 -3
- wolfhece/hydrology/Comparison.py +46 -7
- wolfhece/hydrology/Optimisation.py +63 -4
- wolfhece/hydrology/PyWatershed.py +552 -14
- wolfhece/hydrology/RetentionBasin.py +246 -41
- wolfhece/hydrology/SubBasin.py +42 -9
- wolfhece/hydrology/plot_hydrology.py +58 -0
- wolfhece/libs/WolfDll.dll +0 -0
- wolfhece/picc.py +35 -4
- wolfhece/wolf_array.py +156 -31
- {wolfhece-2.1.13.dist-info → wolfhece-2.1.15.dist-info}/METADATA +1 -1
- {wolfhece-2.1.13.dist-info → wolfhece-2.1.15.dist-info}/RECORD +21 -21
- {wolfhece-2.1.13.dist-info → wolfhece-2.1.15.dist-info}/WHEEL +1 -1
- {wolfhece-2.1.13.dist-info → wolfhece-2.1.15.dist-info}/entry_points.txt +0 -0
- {wolfhece-2.1.13.dist-info → wolfhece-2.1.15.dist-info}/top_level.txt +0 -0
@@ -14,6 +14,7 @@ from .Outlet import *
|
|
14
14
|
from .Dumping import *
|
15
15
|
from ..PyTranslate import _
|
16
16
|
from . import constant as cst
|
17
|
+
from ..PyVertexvectors import getIfromRGB, getRGBfromI
|
17
18
|
|
18
19
|
class RetentionBasin():
|
19
20
|
## @var outFlow
|
@@ -29,7 +30,7 @@ class RetentionBasin():
|
|
29
30
|
intletsObj:dict
|
30
31
|
directFluxObj:dict
|
31
32
|
|
32
|
-
def __init__(self, _dateBegin=None, _dateEnd=None, _deltaT:int=None, _time=None, _id='J1', _name='Default name', _type='',
|
33
|
+
def __init__(self, _dateBegin=None, _dateEnd=None, _deltaT:int=None, _time=None, _id='J1', _name='Default name', _type='',
|
33
34
|
_dictRB={}, _directDictRB={}, _tz=0, _outletNames=[], withRBDict=True, _workingDir=""):
|
34
35
|
print('Creation of a RetentionBasin!')
|
35
36
|
self.iD = _id
|
@@ -47,11 +48,15 @@ class RetentionBasin():
|
|
47
48
|
self.fileNameRead = _workingDir # //
|
48
49
|
self.fileNameWrite = self.fileNameRead
|
49
50
|
if(_time is None):
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
51
|
+
if(_dateBegin is None or _dateEnd is None or _deltaT is None):
|
52
|
+
self.time = None
|
53
|
+
self.filledVolume = None
|
54
|
+
else:
|
55
|
+
tzDelta = datetime.timedelta(hours=self.tz)
|
56
|
+
ti = datetime.datetime.timestamp(self.dateBegin-tzDelta)
|
57
|
+
tf = datetime.datetime.timestamp(self.dateEnd-tzDelta)
|
58
|
+
self.time = np.arange(ti,tf+self.deltaT,self.deltaT)
|
59
|
+
self.filledVolume = np.zeros(len(self.time), dtype=np.float64)
|
55
60
|
|
56
61
|
self.x = 0.0
|
57
62
|
self.y = 0.0
|
@@ -85,7 +90,6 @@ class RetentionBasin():
|
|
85
90
|
|
86
91
|
self.rain = []
|
87
92
|
|
88
|
-
self.filledVolume = np.zeros(len(self.time), dtype=np.float64)
|
89
93
|
self.qLim = None # object to compute "l'ecretage"
|
90
94
|
|
91
95
|
self.outletObj = None # object to compute the outlet
|
@@ -107,13 +111,13 @@ class RetentionBasin():
|
|
107
111
|
for element in _dictRB:
|
108
112
|
if(_dictRB[element]['from'][key_Param.VALUE] == self.iD):
|
109
113
|
if(tmpCounter>0):
|
110
|
-
|
111
|
-
|
114
|
+
logging.error("ERROR: the same RB associated to two different caracteristics. Please check the RetentionBasin.postPro file.")
|
115
|
+
raise ValueError("The same RB associated to two different caracteristics. Please check the RetentionBasin.postPro file.")
|
112
116
|
self.dictRB = _dictRB[element]
|
113
117
|
tmpCounter +=1
|
114
118
|
if(tmpCounter == 0):
|
115
|
-
|
116
|
-
|
119
|
+
logging.error("Error: no RB associated! Please check the RetentionBasin.postPro file.")
|
120
|
+
raise ValueError("No RB associated! Please check the RetentionBasin.postPro file.")
|
117
121
|
elif(_directDictRB!={}):
|
118
122
|
self.dictRB = _directDictRB
|
119
123
|
elif(withRBDict):
|
@@ -127,7 +131,7 @@ class RetentionBasin():
|
|
127
131
|
self.dictRB['type'] = {}
|
128
132
|
self.dictRB['type'][key_Param.VALUE] = ""
|
129
133
|
elif(myAnswer=="N" or myAnswer=="n"):
|
130
|
-
|
134
|
+
raise ValueError("No answer given!")
|
131
135
|
else:
|
132
136
|
self.dictRB['type'] = {}
|
133
137
|
self.dictRB['type'][key_Param.VALUE] = ""
|
@@ -243,9 +247,9 @@ class RetentionBasin():
|
|
243
247
|
if(name in self.downstreamObj):
|
244
248
|
self.downstreamObj[name] = toPoint
|
245
249
|
else:
|
246
|
-
|
247
|
-
|
248
|
-
|
250
|
+
logging.error("ERROR: this outlet name is not recognised!")
|
251
|
+
logging.error("Name = ", name)
|
252
|
+
raise ValueError("This outlet name is not recognised!")
|
249
253
|
|
250
254
|
self._outFlow[name] = {}
|
251
255
|
self._outFlow[name]["Net"] = []
|
@@ -353,6 +357,81 @@ class RetentionBasin():
|
|
353
357
|
return self._outFlow
|
354
358
|
|
355
359
|
|
360
|
+
def compute_one_step_hydro(self, i, givenDirectFluxIn:float=None, givenInlet:float=None):
|
361
|
+
""" This function computes the raw and real hydrographs for one time step.
|
362
|
+
|
363
|
+
The volume filled and then the water height in the RB at time $t$ will be evaluated will depend of the flows
|
364
|
+
at time $t-1$ exept if the
|
365
|
+
|
366
|
+
Internal variables modified : self.inlets, self.inletsRaw,
|
367
|
+
self.directFluxInRB, self.directFluxInRB_Raw,
|
368
|
+
self._outFlowRaw, self._outFlow, self.filledVolume
|
369
|
+
CAUTION: - Discussion about the ceil or the floor for the timeDelay indice!!!
|
370
|
+
- UPDATE 2023.1 now the outFlow are not delayed anymore !!!! -> IMPORTANT UPDATE
|
371
|
+
"""
|
372
|
+
self.sum_one_step_directFluxInRB(i, givenDirectFluxIn)
|
373
|
+
self.sum_one_step_inlets(i, givenInlet)
|
374
|
+
|
375
|
+
mainNameOut = list(self._outFlow.items())[0][0]
|
376
|
+
# In the Raw hydrograph the first outlet is considered to be the main one. Therefore the exit where the flux would go if the structure were to present
|
377
|
+
self._outFlow[mainNameOut]["Raw"][i] = self.inletsRaw[i] + self.directFluxInRB_Raw[i]
|
378
|
+
for iOutFlow in range(1,len(list(self._outFlow.items()))):
|
379
|
+
nameOut = list(self._outFlow.items())[iOutFlow][0]
|
380
|
+
self._outFlow[nameOut]["Raw"][i] = 0.0
|
381
|
+
|
382
|
+
# Compute
|
383
|
+
h = self.volume_to_h(self.filledVolume[i])
|
384
|
+
# Qout = self.outletObj.compute(h,self.time[self.convert_index_global_to_local(i)])
|
385
|
+
Qout = self.outletObj.compute(h,self.time[i+1], index=i+1)
|
386
|
+
qLim = self.qLim.compute(h,self.time[i+1])
|
387
|
+
Qin = self.directFluxInRB[i-1]+max(self.inlets[i]-qLim,0.)
|
388
|
+
rhs = Qin - Qout
|
389
|
+
outFlowReservoir = Qout
|
390
|
+
# If the volume increase => the outflow is kept (Maybe to improve!! The height can go to the upper threshold)
|
391
|
+
if rhs>0:
|
392
|
+
self.filledVolume[i+1] = self.filledVolume[i] + rhs*(self.time[i+1]-self.time[i])
|
393
|
+
# If the volume is decreasing but is not enough to empty it at this time step
|
394
|
+
elif self.filledVolume[i]>abs(rhs*(self.time[i+1]-self.time[i])):
|
395
|
+
self.filledVolume[i+1] = self.filledVolume[i] + rhs*(self.time[i+1]-self.time[i])
|
396
|
+
# if(self.surface == 0.0):
|
397
|
+
# h = 0.0
|
398
|
+
# else:
|
399
|
+
# h = self.filledVolume[i]/self.surface
|
400
|
+
h = self.volume_to_h(self.filledVolume[i+1])
|
401
|
+
# All the values:
|
402
|
+
# -outlet,
|
403
|
+
# -ecretage,
|
404
|
+
# -volume,
|
405
|
+
# will be reevaluated. Because we can go to the lower threshold.
|
406
|
+
# Qout = self.outletObj.compute(h,self.time[self.convert_index_global_to_local(i)])
|
407
|
+
Qout = self.outletObj.compute(h,self.time[i+1], index=i+1)
|
408
|
+
qLim = self.qLim.compute(h,self.time[i+1])
|
409
|
+
rhs = self.directFluxInRB[i]+max(self.inlets[i]-qLim,0.)-Qout
|
410
|
+
outFlowReservoir = Qout
|
411
|
+
self.filledVolume[i+1] = self.filledVolume[i] + rhs*(self.time[i+1]-self.time[i])
|
412
|
+
|
413
|
+
else:
|
414
|
+
self.filledVolume[i+1] =0
|
415
|
+
outFlowReservoir = self.filledVolume[i]/((self.time[i+1]-self.time[i]))+self.directFluxInRB[i]+max(self.inlets[i]-qLim,0.)
|
416
|
+
|
417
|
+
if self.filledVolume[i+1]>self.volume:
|
418
|
+
outFlowReservoir += (self.filledVolume[i+1]-self.volume)/((self.time[i+1]-self.time[i]))
|
419
|
+
self.filledVolume[i+1] = self.volume
|
420
|
+
|
421
|
+
self._outFlow = self.compute_final(outFlowReservoir,min(self.inlets[i],qLim),i)
|
422
|
+
|
423
|
+
|
424
|
+
def init_all_inlets(self):
|
425
|
+
""" This function initializes the inlets and directFluxInRB of the RB
|
426
|
+
Internal variables modified: self.inlets, self.inletsRaw, self.directFluxInRB, self.directFluxInRB_Raw
|
427
|
+
"""
|
428
|
+
self.inlets = np.zeros(len(self.time),dtype=ct.c_double, order='F')
|
429
|
+
self.inletsRaw = np.zeros(len(self.time),dtype=ct.c_double, order='F')
|
430
|
+
|
431
|
+
self.directFluxInRB = np.zeros(len(self.time),dtype=ct.c_double, order='F')
|
432
|
+
self.directFluxInRB_Raw = np.zeros(len(self.time),dtype=ct.c_double, order='F')
|
433
|
+
|
434
|
+
|
356
435
|
def sum_inlets(self, givenInlet=[]):
|
357
436
|
""" This procedure sum all the inlets of the RB
|
358
437
|
Caution: inlets variable is different from directFluxIn !!
|
@@ -383,15 +462,15 @@ class RetentionBasin():
|
|
383
462
|
# Assumption the transfer time between the 2 RB is ambiguous
|
384
463
|
# Therefore, the transfer time is set to 0.0
|
385
464
|
deltaTr = 0.0
|
386
|
-
|
465
|
+
|
387
466
|
self.inlets += curObj.get_outFlow(typeOutFlow="Net", whichOutFlow=nameOutFlow, lag=deltaTr)
|
388
467
|
self.inletsRaw += curObj.get_outFlow(typeOutFlow="Raw", whichOutFlow=nameOutFlow, lag=deltaTr)
|
389
468
|
elif(givenInlet != []):
|
390
469
|
if(len(givenInlet)!=len(self.time)):
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
470
|
+
logging.error("The dimension of the time array and the given inlet are not the same!")
|
471
|
+
logging.error(f"Length obtained = {len(givenInlet)}")
|
472
|
+
logging.error(f"Length expected = {len(self.time)}")
|
473
|
+
raise ValueError("The dimension of the time array and the given inlet are not the same!")
|
395
474
|
self.inlets = givenInlet
|
396
475
|
self.inletsRaw = givenInlet
|
397
476
|
else:
|
@@ -469,10 +548,10 @@ class RetentionBasin():
|
|
469
548
|
elif(givenDirectFluxIn != []):
|
470
549
|
# FIXME The following line to potentially change !!!
|
471
550
|
if(len(givenDirectFluxIn)!=len(self.time)):
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
551
|
+
logging.error("The dimension of the time array and the given inlet are not the same!")
|
552
|
+
logging.error("Length optained = ", len(givenDirectFluxIn))
|
553
|
+
logging.error("Length expected = ", len(self.time))
|
554
|
+
raise ValueError("The dimension of the time array and the given inlet are not the same!")
|
476
555
|
self.directFluxInRB = givenDirectFluxIn
|
477
556
|
self.directFluxInRB_Raw = givenDirectFluxIn
|
478
557
|
else:
|
@@ -482,6 +561,78 @@ class RetentionBasin():
|
|
482
561
|
self.directFluxInRB_Raw = np.zeros(len(self.time), dtype=ct.c_double, order='F')
|
483
562
|
|
484
563
|
|
564
|
+
def sum_one_step_inlets(self, i, givenInlet:float=None):
|
565
|
+
if self.intletsObj != {}:
|
566
|
+
nameOutFlow = list(self.intletsObj.items())[0][0]
|
567
|
+
curObj = self.intletsObj[nameOutFlow]
|
568
|
+
# Compute the transfer time between modules
|
569
|
+
if type(curObj) is SubBasin:
|
570
|
+
timeInlet = curObj.timeDelay
|
571
|
+
deltaTr = timeInlet - self.timeDelay
|
572
|
+
else:
|
573
|
+
# Assumption the transfer time between the 2 RB is ambiguous
|
574
|
+
# Therefore, the transfer time is set to 0.0
|
575
|
+
deltaTr = 0.0
|
576
|
+
self.inlets[i] = curObj.get_outFlow(typeOutFlow="Net", whichOutFlow=nameOutFlow, lag=deltaTr)[i]
|
577
|
+
self.inletsRaw[i] = curObj.get_outFlow(typeOutFlow="Raw", whichOutFlow=nameOutFlow, lag=deltaTr)[i]
|
578
|
+
for i in range(1,len(list(self.intletsObj.items()))):
|
579
|
+
nameOutFlow = list(self.intletsObj.items())[i][0]
|
580
|
+
curObj = self.intletsObj[nameOutFlow]
|
581
|
+
timeInlet = curObj.timeDelay
|
582
|
+
if type(curObj) is SubBasin:
|
583
|
+
timeInlet = curObj.timeDelay
|
584
|
+
deltaTr = timeInlet - self.timeDelay
|
585
|
+
else:
|
586
|
+
# Assumption the transfer time between the 2 RB is ambiguous
|
587
|
+
# Therefore, the transfer time is set to 0.0
|
588
|
+
deltaTr = 0.0
|
589
|
+
|
590
|
+
self.inlets[i] += curObj.get_outFlow(typeOutFlow="Net", whichOutFlow=nameOutFlow, lag=deltaTr)[i]
|
591
|
+
self.inletsRaw[i] += curObj.get_outFlow(typeOutFlow="Raw", whichOutFlow=nameOutFlow, lag=deltaTr)[i]
|
592
|
+
elif(givenInlet is not None):
|
593
|
+
self.inlets[i] = givenInlet
|
594
|
+
self.inletsRaw[i] = givenInlet
|
595
|
+
else:
|
596
|
+
self.inlets[i] = 0.0
|
597
|
+
self.inletsRaw[i] = 0.0
|
598
|
+
|
599
|
+
|
600
|
+
def sum_one_step_directFluxInRB(self, i, givenDirectFluxIn:float=None):
|
601
|
+
"""This procedure computes the flux going directly inside the RB
|
602
|
+
|
603
|
+
Internal variables modified: self.directFluxInRB, self.directFluxInRB_Raw
|
604
|
+
"""
|
605
|
+
if(self.directFluxObj != {}):
|
606
|
+
nameOutFlow = list(self.directFluxObj.items())[0][0]
|
607
|
+
curObj = self.directFluxObj[nameOutFlow]
|
608
|
+
timeInlet = curObj.timeDelay
|
609
|
+
if type(curObj) is SubBasin:
|
610
|
+
timeInlet = curObj.timeDelay
|
611
|
+
deltaTr = timeInlet - self.timeDelay
|
612
|
+
else:
|
613
|
+
# Assumption the transfer time between the 2 RB is ambiguous
|
614
|
+
# Therefore, the transfer time is set to 0.0
|
615
|
+
deltaTr = 0.0
|
616
|
+
deltaTr = timeInlet - self.timeDelay
|
617
|
+
self.directFluxInRB[i] = curObj.get_outFlow(typeOutFlow="Net", whichOutFlow=nameOutFlow, lag=deltaTr)[i]
|
618
|
+
self.directFluxInRB_Raw[i] = curObj.get_outFlow(typeOutFlow="Raw", whichOutFlow=nameOutFlow, lag=deltaTr)[i]
|
619
|
+
for i in range(1,len(list(self.directFluxObj.items()))):
|
620
|
+
nameOutFlow = list(self.directFluxObj.items())[i][0]
|
621
|
+
curObj = self.directFluxObj[nameOutFlow]
|
622
|
+
timeInlet = curObj.timeDelay
|
623
|
+
if type(curObj) is SubBasin:
|
624
|
+
timeInlet = curObj.timeDelay
|
625
|
+
deltaTr = timeInlet - self.timeDelay
|
626
|
+
else:
|
627
|
+
# Assumption the transfer time between the 2 RB is ambiguous
|
628
|
+
# Therefore, the transfer time is set to 0.0
|
629
|
+
deltaTr = 0.0
|
630
|
+
|
631
|
+
self.directFluxInRB[i] += curObj.get_outFlow(typeOutFlow="Net", whichOutFlow=nameOutFlow, lag=deltaTr)[i]
|
632
|
+
self.directFluxInRB_Raw[i] += curObj.get_outFlow(typeOutFlow="Raw", whichOutFlow=nameOutFlow, lag=deltaTr)[i]
|
633
|
+
|
634
|
+
|
635
|
+
|
485
636
|
def plot(self, workingDir, plotRaw=True, axis="Hours",rangeData=[], deltaMajorTicks=24.0*3600.0, deltaMinorTicks=3600.0, tzPlot=0, unitReservoir="[m^3]"):
|
486
637
|
""" This procedure plots:
|
487
638
|
- the inlets: in color chosen randomly by matplotlib
|
@@ -782,8 +933,8 @@ class RetentionBasin():
|
|
782
933
|
elif(myIndex<len(dataLoc)):
|
783
934
|
dataLoc[:-myIndex] = dataGlob[myIndex:]
|
784
935
|
else:
|
785
|
-
|
786
|
-
|
936
|
+
logging.error("ERROR: the simulation time is not long enough for this subbasin to be taken into account")
|
937
|
+
raise ValueError("The simulation time is not long enough for this subbasin to be taken into account")
|
787
938
|
|
788
939
|
return dataLoc
|
789
940
|
|
@@ -817,8 +968,7 @@ class RetentionBasin():
|
|
817
968
|
else:
|
818
969
|
result[myIndex:] = vector[:-myIndex]
|
819
970
|
else:
|
820
|
-
|
821
|
-
sys.exit()
|
971
|
+
raise ValueError("The simulation time is not long enough for this subbasin to be taken into account")
|
822
972
|
|
823
973
|
return result
|
824
974
|
|
@@ -874,7 +1024,7 @@ class RetentionBasin():
|
|
874
1024
|
if unit=='mm/h':
|
875
1025
|
if self.surfaceDrainedHydro==0.0:
|
876
1026
|
logging.error("ERROR: the surface drained = 0! Not possible to express the outFlow in mm/s!")
|
877
|
-
|
1027
|
+
raise ValueError("ERROR: the surface drained = 0! Not possible to express the outFlow in mm/s!")
|
878
1028
|
myOutFlow *= 3.6/self.surfaceDrainedHydro
|
879
1029
|
|
880
1030
|
|
@@ -1221,7 +1371,7 @@ class RetentionBasin():
|
|
1221
1371
|
# Verification
|
1222
1372
|
if(datetime.datetime.timestamp(prevDate)>datetime.datetime.timestamp(self.dateBegin)):
|
1223
1373
|
logging.error("ERROR: the first hydro data element is posterior to dateBegin!")
|
1224
|
-
|
1374
|
+
raise ValueError("ERROR: the first hydro data element is posterior to dateBegin!")
|
1225
1375
|
|
1226
1376
|
if(nbCl==5):
|
1227
1377
|
# Caution : the index of the loop start at 24 because the timestamp function
|
@@ -1270,15 +1420,15 @@ class RetentionBasin():
|
|
1270
1420
|
# Add the last element in the time matrix as its size is 1 element bigger than outlet
|
1271
1421
|
timeArray[-1] = timeArray[-2] + diffTimeInSeconds
|
1272
1422
|
if(self.deltaT!=diffDate.seconds):
|
1273
|
-
|
1274
|
-
|
1423
|
+
logging.error("ERROR: The last timestep in hydro data does not coincide with the one expected!")
|
1424
|
+
raise ValueError("ERROR: The last timestep in hydro data does not coincide with the one expected!")
|
1275
1425
|
# Save time array if it does not exist yet
|
1276
1426
|
# Otherwise, check the consistency of the array with the time array of the object
|
1277
1427
|
if(self.time is None):
|
1278
1428
|
self.time=timeArray
|
1279
1429
|
elif(self.time.all()!=timeArray.all()):
|
1280
|
-
|
1281
|
-
|
1430
|
+
logging.error("ERROR: the dates read are not consitent with the dates already recored in this subbasin!")
|
1431
|
+
raise ValueError("ERROR: the dates read are not consitent with the dates already recored in this subbasin!")
|
1282
1432
|
|
1283
1433
|
volume = np.array([self.h_to_volume(i) for i in height])
|
1284
1434
|
|
@@ -1465,6 +1615,40 @@ class RetentionBasin():
|
|
1465
1615
|
|
1466
1616
|
return allInlets
|
1467
1617
|
|
1618
|
+
|
1619
|
+
def get_inletCoords(self):
|
1620
|
+
|
1621
|
+
allCoords = []
|
1622
|
+
|
1623
|
+
for element in self.intletsObj:
|
1624
|
+
allCoords.append([self.intletsObj[element].x, self.intletsObj[element].y])
|
1625
|
+
|
1626
|
+
for element in self.directFluxObj:
|
1627
|
+
allCoords.append([self.directFluxObj[element].x, self.directFluxObj[element].y])
|
1628
|
+
|
1629
|
+
return allCoords
|
1630
|
+
|
1631
|
+
def get_zone(self) -> zone:
|
1632
|
+
""" Return a zone instance to insert in viewer """
|
1633
|
+
|
1634
|
+
myzone = zone(name = self.name)
|
1635
|
+
|
1636
|
+
x,y = self.x, self.y
|
1637
|
+
|
1638
|
+
xy_inlets = self.get_inletCoords()
|
1639
|
+
names = self.get_inletsName()
|
1640
|
+
for xy, curname in zip(xy_inlets, names):
|
1641
|
+
locx, locy = xy
|
1642
|
+
newvec = vector(name = curname)
|
1643
|
+
newvec.add_vertex(wolfvertex(locx,locy))
|
1644
|
+
newvec.add_vertex(wolfvertex(x,y))
|
1645
|
+
|
1646
|
+
newvec.myprop.color = getIfromRGB([255,100,0])
|
1647
|
+
newvec.myprop.width = 3
|
1648
|
+
|
1649
|
+
myzone.add_vector(newvec, forceparent=True)
|
1650
|
+
|
1651
|
+
return myzone
|
1468
1652
|
|
1469
1653
|
|
1470
1654
|
def get_timeDelays(self, timeDelays={}):
|
@@ -1480,12 +1664,12 @@ class RetentionBasin():
|
|
1480
1664
|
|
1481
1665
|
def get_timeDelays_inlets(self):
|
1482
1666
|
|
1483
|
-
|
1667
|
+
|
1484
1668
|
all_timeDelays = {el.timeDelay-self.timeDelay for el in self.intletsObj.values()}
|
1485
1669
|
all_timeDelays.update({el.timeDelay-self.timeDelay for el in self.directFluxObj.values()})
|
1486
1670
|
|
1487
1671
|
return all_timeDelays
|
1488
|
-
|
1672
|
+
|
1489
1673
|
|
1490
1674
|
## This procedure save in a "transfer.param" file the timeDelay of the SubBasin and all its upstream elements
|
1491
1675
|
def save_timeDelays(self):
|
@@ -1511,7 +1695,7 @@ class RetentionBasin():
|
|
1511
1695
|
return self.timeDelayObj.get_iDSorted()
|
1512
1696
|
|
1513
1697
|
|
1514
|
-
def get_outFlow_names(self)->list:
|
1698
|
+
def get_outFlow_names(self)->list:
|
1515
1699
|
|
1516
1700
|
return list(self._outFlow.keys())
|
1517
1701
|
|
@@ -1537,7 +1721,7 @@ class RetentionBasin():
|
|
1537
1721
|
# @var update_upstream boolean that specify whether the upstream elements should also be updated
|
1538
1722
|
# @var level_min integer that specify the potential level at which the update should be stopped.
|
1539
1723
|
def update_hydro(self, update_upstream:bool=True, level_min:int=1):
|
1540
|
-
|
1724
|
+
|
1541
1725
|
# !!! (ALERT) : So far, we consider that a RB object will always need to update its upstream elements
|
1542
1726
|
# TODO : a potiential future need will require only an optimisation of the RB and fixed upstream elements!
|
1543
1727
|
# if update_upstream:
|
@@ -1618,11 +1802,11 @@ class RetentionBasin():
|
|
1618
1802
|
self.filledVolume = volume[imin:imax+1]
|
1619
1803
|
|
1620
1804
|
return
|
1621
|
-
|
1805
|
+
|
1622
1806
|
|
1623
1807
|
def evaluate_objective_function(self, unit="mm/h")->np.ndarray:
|
1624
1808
|
# unit = "m3/s"
|
1625
|
-
|
1809
|
+
|
1626
1810
|
return self.get_direct_insideRB_inlets(unit=unit)
|
1627
1811
|
|
1628
1812
|
|
@@ -1684,4 +1868,25 @@ class RetentionBasin():
|
|
1684
1868
|
else:
|
1685
1869
|
print("WARNING: This type RB was not recognised! Please check the RetentionBasin.postPro file.")
|
1686
1870
|
|
1687
|
-
|
1871
|
+
|
1872
|
+
def init_time_simulation(self, dateBegin:datetime.datetime, dateEnd:datetime.datetime, deltaT:float, tz:int=0):
|
1873
|
+
|
1874
|
+
tzDelta = datetime.timedelta(hours=self.tz)
|
1875
|
+
self.dateBegin = dateBegin
|
1876
|
+
self.dateEnd = dateEnd
|
1877
|
+
self.deltaT = deltaT
|
1878
|
+
ti = datetime.datetime.timestamp(self.dateBegin-tzDelta)
|
1879
|
+
tf = datetime.datetime.timestamp(self.dateEnd-tzDelta)
|
1880
|
+
self.time = np.arange(ti,tf+self.deltaT,self.deltaT)
|
1881
|
+
|
1882
|
+
return self.time
|
1883
|
+
|
1884
|
+
|
1885
|
+
def init_internal_variable(self):
|
1886
|
+
|
1887
|
+
for iOutFlow in range(len(list(self._outFlow.items()))):
|
1888
|
+
nameOut = list(self._outFlow.items())[iOutFlow][0]
|
1889
|
+
self._outFlow[nameOut]["Net"] = np.zeros(len(self.time), dtype=np.float64)
|
1890
|
+
self._outFlow[nameOut]["Raw"] = np.zeros(len(self.time), dtype=np.float64)
|
1891
|
+
|
1892
|
+
self.filledVolume = np.zeros(len(self.time), dtype=np.float64)
|
wolfhece/hydrology/SubBasin.py
CHANGED
@@ -17,6 +17,7 @@ from matplotlib.font_manager import FontProperties
|
|
17
17
|
from dbfread import DBF
|
18
18
|
import ctypes as ct
|
19
19
|
import pandas as pd
|
20
|
+
from pathlib import Path
|
20
21
|
|
21
22
|
from ..PyTranslate import _
|
22
23
|
from . import plot_hydrology as ph
|
@@ -248,7 +249,7 @@ class SubBasin:
|
|
248
249
|
file_exists = os.path.exists(fileName)
|
249
250
|
if(not(file_exists)):
|
250
251
|
typeOfFileName = 'simul_net_trans_rain.txt'
|
251
|
-
fileName = join(workingDir,
|
252
|
+
fileName = os.path.join(workingDir,subBasinName, typeOfFileName)
|
252
253
|
file_exists = os.path.exists(fileName)
|
253
254
|
if(file_exists):
|
254
255
|
print("ERROR : the file simul_net_trans_rain.txt is not used yet in this version! Please check version of the code before 05/11/2021 !")
|
@@ -1422,17 +1423,17 @@ class SubBasin:
|
|
1422
1423
|
"""Add hyetographs to the subbasin
|
1423
1424
|
TO DO: Adapt the code to find automatically the .dbf files. E.G. when data are read in NetCDF files.
|
1424
1425
|
"""
|
1425
|
-
fileName
|
1426
|
-
fileName2 = workingDir
|
1426
|
+
fileName = Path(workingDir) / ('Subbasin_' +str(self.iDSorted)) / 'simul_rain_geom.vec.dbf'
|
1427
|
+
fileName2 = Path(workingDir) / ('Subbasin_' +str(self.iDSorted)) /'/simul_geom.vec.dbf'
|
1427
1428
|
|
1428
|
-
if(
|
1429
|
-
dbDict = self.read_dbfFile(fileName)
|
1429
|
+
if(fileName.exists()):
|
1430
|
+
dbDict = self.read_dbfFile(str(fileName))
|
1430
1431
|
for i in range(len(dbDict.records)):
|
1431
1432
|
idHyeto = int(dbDict.records[i]['data'])
|
1432
1433
|
# idMyHyeto = hyetoDict['Ordered To Nb'][idHyeto]
|
1433
1434
|
self.myHyetoDict[idHyeto] = hyetoDict['Hyetos'][idHyeto]
|
1434
|
-
elif(
|
1435
|
-
dbDict = self.read_dbfFile(fileName2)
|
1435
|
+
elif(fileName2.exists()):
|
1436
|
+
dbDict = self.read_dbfFile(str(fileName2))
|
1436
1437
|
for i in range(len(dbDict.records)):
|
1437
1438
|
idHyeto = int(dbDict.records[i]['data'])
|
1438
1439
|
# idMyHyeto = hyetoDict['Ordered To Nb'][idHyeto]
|
@@ -3451,12 +3452,43 @@ class SubBasin:
|
|
3451
3452
|
elif summary == "min":
|
3452
3453
|
return {key: np.nanmin(all_f[key], where=interv) for key in all_f}
|
3453
3454
|
elif summary == "max":
|
3454
|
-
return {key: np.nanmax(all_f[key], where=interv) for key in all_f}
|
3455
|
+
return {key: np.nanmax(all_f[key], where=interv, initial=0.0) for key in all_f}
|
3455
3456
|
else:
|
3456
3457
|
logging.error("The summary type is not recognised!")
|
3457
3458
|
return []
|
3458
3459
|
|
3459
|
-
|
3460
|
+
|
3461
|
+
def get_volume_fractions(self, all_f:dict={},
|
3462
|
+
interval:list[tuple[datetime.datetime, datetime.datetime]]=None) -> dict[str, np.array]:
|
3463
|
+
"""
|
3464
|
+
This procedure is returning a summary of the fractions of the current module.
|
3465
|
+
|
3466
|
+
Parameters:
|
3467
|
+
- summary (str): The type of summary to return.
|
3468
|
+
- interval (list[datetime.datetime], optional): The interval of time to consider. Default is None.
|
3469
|
+
|
3470
|
+
Returns:
|
3471
|
+
- dict: A dictionary containing the summary of the fractions of the current module.
|
3472
|
+
"""
|
3473
|
+
|
3474
|
+
if all_f == {}:
|
3475
|
+
all_f = self.collect_fractions()
|
3476
|
+
|
3477
|
+
all_v = {key: val/100.0*self.myRain for key, val in all_f.items()}
|
3478
|
+
|
3479
|
+
if interval is not None:
|
3480
|
+
interv = np.zeros(len(self.time), dtype=bool)
|
3481
|
+
for el in interval:
|
3482
|
+
date_i = datetime.datetime.timestamp(el[0])
|
3483
|
+
date_f = datetime.datetime.timestamp(el[1])
|
3484
|
+
interv += (self.time>=date_i) & (self.time<=date_f)
|
3485
|
+
else:
|
3486
|
+
interv = np.ones(len(self.time), dtype=bool)
|
3487
|
+
|
3488
|
+
tot_rain = np.nansum(self.myRain[interv])*self.deltaT/3600
|
3489
|
+
|
3490
|
+
return {key+" volume": (np.nansum(all_v[key][interv])*self.deltaT/3600)/tot_rain*100 for key in all_v}
|
3491
|
+
|
3460
3492
|
|
3461
3493
|
def check_presence_of_iv(self):
|
3462
3494
|
"""
|
@@ -3514,6 +3546,7 @@ class SubBasin:
|
|
3514
3546
|
|
3515
3547
|
return q_test
|
3516
3548
|
|
3549
|
+
|
3517
3550
|
def plot_all_fractions(self, all_fractions:dict[str:np.array]={},figure=None, to_show:bool=False, writeDir:str="", range_data:list[datetime.datetime]=[]) -> None:
|
3518
3551
|
|
3519
3552
|
if writeDir == "":
|
@@ -824,4 +824,62 @@ def bar_Nash_n_other(all_data:list[dict], all_colors:list[dict], nb_x, nb_data,
|
|
824
824
|
|
825
825
|
|
826
826
|
if toShow :
|
827
|
+
plt.show()
|
828
|
+
|
829
|
+
|
830
|
+
def table_Nash_n_other(data:np.ndarray,
|
831
|
+
type_of_data:str="Nash", color_map:str=None,
|
832
|
+
row_names:list[str]=[], column_names:list[str]=[], title:str="",
|
833
|
+
writeFile:str="", toShow:bool=False, nan_color:str="white", nan_value:float=0.0):
|
834
|
+
|
835
|
+
if nan_value is not None:
|
836
|
+
data[data == nan_value] = np.nan
|
837
|
+
|
838
|
+
# Heat map definition
|
839
|
+
fig_tmp, ax_tmp = plt.subplots()
|
840
|
+
if type_of_data == "Nash":
|
841
|
+
heatmap = ax_tmp.imshow(data[:, 0:1], cmap='RdYlGn', aspect='auto', vmin=0, vmax=1)
|
842
|
+
if type_of_data == "Exceedance":
|
843
|
+
heatmap = ax_tmp.imshow(data[:, 1:2], cmap='bwr_r', aspect='auto', vmin=-1, vmax=1, origin='lower')
|
844
|
+
|
845
|
+
heat_rgb = heatmap.to_rgba(data)
|
846
|
+
plt.close(fig_tmp)
|
847
|
+
|
848
|
+
vfunc = np.vectorize(lambda x: '' if np.isnan(x) else f'{x:.2f}')
|
849
|
+
ndata = vfunc(data)
|
850
|
+
|
851
|
+
# plot the table
|
852
|
+
fig, ax = plt.subplots()
|
853
|
+
table = ax.table(cellText=ndata, loc='center',
|
854
|
+
cellColours= heat_rgb,
|
855
|
+
colLabels=column_names,
|
856
|
+
rowLabels=row_names,
|
857
|
+
cellLoc='center',
|
858
|
+
rowLoc='center',
|
859
|
+
colLoc='center')
|
860
|
+
|
861
|
+
# Make the column fit with around their name
|
862
|
+
for i in range(len(row_names)):
|
863
|
+
table.auto_set_column_width(i)
|
864
|
+
# Change the text color based on the brightness of the cell color
|
865
|
+
for i, cell in table.get_celld().items():
|
866
|
+
cell.set_edgecolor('black')
|
867
|
+
if cell.get_facecolor()[0] < 0.5: # if the cell color is dark
|
868
|
+
cell.get_text().set_color('white')
|
869
|
+
else:
|
870
|
+
cell.get_text().set_color('black')
|
871
|
+
|
872
|
+
table.scale(1.0, 3.0)
|
873
|
+
# table.auto
|
874
|
+
|
875
|
+
# Hide axes
|
876
|
+
ax.axis('off')
|
877
|
+
# Set the title
|
878
|
+
if title != "":
|
879
|
+
ax.set_title(title)
|
880
|
+
|
881
|
+
if writeFile != "":
|
882
|
+
plt.savefig(writeFile, transparent=True, bbox_inches='tight')
|
883
|
+
|
884
|
+
if toShow:
|
827
885
|
plt.show()
|
wolfhece/libs/WolfDll.dll
CHANGED
Binary file
|