wolfhece 2.1.127__py3-none-any.whl → 2.1.129__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 +52 -3
- wolfhece/PyPalette.py +36 -0
- wolfhece/PyParams.py +7 -3
- wolfhece/PyVertexvectors.py +579 -70
- wolfhece/apps/version.py +1 -1
- wolfhece/coupling/hydrology_2d.py +295 -192
- wolfhece/eikonal.py +13 -3
- wolfhece/hydrology/Catchment.py +153 -52
- wolfhece/hydrology/Comparison.py +29 -25
- wolfhece/hydrology/Optimisation.py +309 -178
- wolfhece/hydrology/PostProcessHydrology.py +6 -3
- wolfhece/hydrology/PyWatershed.py +93 -93
- wolfhece/hydrology/RetentionBasin.py +21 -14
- wolfhece/hydrology/SubBasin.py +128 -12
- wolfhece/hydrology/constant.py +3 -0
- wolfhece/hydrology/cst_exchanges.py +364 -38
- wolfhece/hydrology/plot_hydrology.py +32 -16
- wolfhece/hydrology/read.py +16 -6
- wolfhece/lagrange_multiplier.py +205 -0
- wolfhece/libs/WolfDll.dll +0 -0
- wolfhece/math_parser/calculator.py +1 -0
- wolfhece/pybridges.py +2 -2
- wolfhece/pypolygons_scen.py +2 -2
- wolfhece/radar/wolfradar.py +75 -22
- wolfhece/shapes/__init__.py +0 -0
- wolfhece/shapes/circle.py +335 -0
- wolfhece/wolf_array.py +834 -40
- wolfhece/wolfresults_2D.py +204 -13
- {wolfhece-2.1.127.dist-info → wolfhece-2.1.129.dist-info}/METADATA +5 -5
- {wolfhece-2.1.127.dist-info → wolfhece-2.1.129.dist-info}/RECORD +33 -30
- {wolfhece-2.1.127.dist-info → wolfhece-2.1.129.dist-info}/WHEEL +1 -1
- {wolfhece-2.1.127.dist-info → wolfhece-2.1.129.dist-info}/entry_points.txt +0 -0
- {wolfhece-2.1.127.dist-info → wolfhece-2.1.129.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,205 @@
|
|
1
|
+
import numpy as np
|
2
|
+
|
3
|
+
def junction_q_lagrangemult(q:np.ndarray):
|
4
|
+
""" Compute the junction flow rate q_junction
|
5
|
+
from the flow rates q of the branches.
|
6
|
+
|
7
|
+
:param q: np.ndarray, estimated signed flow rates of the branches
|
8
|
+
"""
|
9
|
+
|
10
|
+
# Number of incoming branches
|
11
|
+
n = q.size
|
12
|
+
|
13
|
+
# Compute the flow rate ensuring mass conservation
|
14
|
+
# using the Lagrange multiplier method
|
15
|
+
#
|
16
|
+
# We minimize the following function:
|
17
|
+
# sum_{i=1}^{n} 1/2 * (qnew_i - q_i) ** 2
|
18
|
+
# subject to the constraint:
|
19
|
+
# sum_{i=1}^{n} qnew_i
|
20
|
+
#
|
21
|
+
# The solution is given by inversing the matrix A
|
22
|
+
# A = [1 1 1 ... 1 0]
|
23
|
+
# [1 0 0 ... 0 1]
|
24
|
+
# [0 1 0 ... 0 1]
|
25
|
+
# [0 0 1 ... 0 1]
|
26
|
+
# ...
|
27
|
+
# [0 0 0 ... 1 1]
|
28
|
+
#
|
29
|
+
# [lambda qnew] = A^(-1) * [0 q1 q2 ... qn]
|
30
|
+
|
31
|
+
# Create the matrix A
|
32
|
+
A = np.zeros((n+1, n+1))
|
33
|
+
A[0, :-1] = 1
|
34
|
+
A[1:, :-1] = np.eye(n)
|
35
|
+
A[1:, -1] = 1
|
36
|
+
|
37
|
+
# Compute the inverse of A
|
38
|
+
A_inv = np.linalg.inv(A)
|
39
|
+
|
40
|
+
# Compute the new flow rates
|
41
|
+
qnew = A_inv @ np.concatenate(([0], q))
|
42
|
+
|
43
|
+
# Return the junction flow rates and the lambda
|
44
|
+
return qnew[:n], qnew[-1]
|
45
|
+
|
46
|
+
def junction_wse_head_lagrangemult(q:np.ndarray,
|
47
|
+
a:np.ndarray,
|
48
|
+
h_width_froma,
|
49
|
+
z:np.ndarray,
|
50
|
+
epsilon:float=1e-6,
|
51
|
+
energy:bool=False):
|
52
|
+
""" Compute the new area at the junction a_junction
|
53
|
+
from the flow rates q of the branches and the area a.
|
54
|
+
|
55
|
+
We ensure a same water elevation (z+h) at the junction in each branch
|
56
|
+
or a same head if energy is True.
|
57
|
+
|
58
|
+
:param q: np.ndarray, estimated signed flow rates of the branches
|
59
|
+
:param a: np.ndarray, estimated area of the branches
|
60
|
+
:param h_l_froma: function converting area to water height and width
|
61
|
+
:param z: np.ndarray, elevation of the branches
|
62
|
+
:param epsilon: float, tolerance of the method
|
63
|
+
:param energy: bool, if True, ensure the same energy at the junction
|
64
|
+
"""
|
65
|
+
|
66
|
+
n = q.size
|
67
|
+
|
68
|
+
# Compute the area ensuring the same water elevation at the junction
|
69
|
+
# using the Lagrange multiplier method
|
70
|
+
#
|
71
|
+
# We minimize the following function:
|
72
|
+
# sum_{i=1}^{n} 1/2 * (anew_i - a_i) ** 2
|
73
|
+
# subject to the constraint:
|
74
|
+
# (Z_i + h_i) - (Z_i+1 + h_i+1) = 0
|
75
|
+
# or
|
76
|
+
# (Z_i + h_i + 1/2 * (q_i / a_i) ^2 / g) - (Z_i+1 + h_i+1 + 1/2 * (q_i+1 / a_i+1) ^2 / g) = 0
|
77
|
+
#
|
78
|
+
# The problem is generally non-linear, we use the Newton-Raphson method to solve it.
|
79
|
+
#
|
80
|
+
# The Jacobian of the system is:
|
81
|
+
# dH_i / da_i = 1 / width_i
|
82
|
+
# dH_i / da_i+1 = -1 / width_i+1
|
83
|
+
# dZ_i / da_i = 0
|
84
|
+
# dZ_i / da_i+1 = 0
|
85
|
+
# if energy is True:
|
86
|
+
# d1/2 * (q_i / a_i) ^2 / g) / da_i = -q_i^2 / (a_i^3 * g)
|
87
|
+
# d1/2 * (q_i+1 / a_i+1) ^2 / g) / da_i+1 = q_i+1^2 / (a_i+1^3 * g)
|
88
|
+
#
|
89
|
+
# The system is solved iteratively using the Newton-Raphson method.
|
90
|
+
|
91
|
+
|
92
|
+
KITERMAX=100
|
93
|
+
GRAVITY = 9.81
|
94
|
+
|
95
|
+
ncompl = 2*n-1
|
96
|
+
|
97
|
+
# !Mise en correspondance deux par deux des altitudes de surface ou des énérgies
|
98
|
+
kiter = 0
|
99
|
+
error = 1.
|
100
|
+
|
101
|
+
while error > epsilon and kiter<KITERMAX:
|
102
|
+
|
103
|
+
A = np.zeros((ncompl, ncompl))
|
104
|
+
A[:n, :n] = np.eye(n)
|
105
|
+
b = np.zeros(ncompl)
|
106
|
+
|
107
|
+
kiter=kiter+1
|
108
|
+
if kiter>100:
|
109
|
+
print('Max iteration in junction')
|
110
|
+
|
111
|
+
h, width = h_width_froma(a)
|
112
|
+
|
113
|
+
# imposition des contraintes
|
114
|
+
if energy:
|
115
|
+
for i in range(n-1):
|
116
|
+
ipos = n + i
|
117
|
+
jpos = i + 1
|
118
|
+
|
119
|
+
# Termes suppl si égalisation d'énergie
|
120
|
+
v1_carre = (q[i] / a[i])**2. / GRAVITY
|
121
|
+
v2_carre = (q[jpos] / a[jpos])**2. / GRAVITY
|
122
|
+
|
123
|
+
A[ipos,i] = 1./width[i] - v1_carre / a[i]
|
124
|
+
A[ipos,jpos] = -1./width[jpos] + v2_carre / a[jpos]
|
125
|
+
A[i,ipos] = -A[ipos,i]
|
126
|
+
A[jpos,ipos] = -A[ipos,jpos]
|
127
|
+
|
128
|
+
b[ipos] = (v2_carre/2.0 + z[jpos] + h[jpos]) - (v1_carre/2.0 + z[i] + h[i])
|
129
|
+
|
130
|
+
else:
|
131
|
+
for i in range(n-1):
|
132
|
+
ipos = n + i
|
133
|
+
jpos = i + 1
|
134
|
+
|
135
|
+
# !dérivée de H vis-à-vis de la section --> largeur courante
|
136
|
+
A[ipos,i] = 1.0/width[i]
|
137
|
+
A[ipos,jpos] = -1.0/width[jpos]
|
138
|
+
A[i,ipos] = -A[ipos,i]
|
139
|
+
A[jpos,ipos] = -A[ipos,jpos]
|
140
|
+
|
141
|
+
# membre de droite --> delta d'altitude de fond
|
142
|
+
b[ipos] = (z[jpos]+h[jpos]) - (z[i]+h[i])
|
143
|
+
|
144
|
+
# résolution du système
|
145
|
+
incr = np.linalg.solve(A, b)
|
146
|
+
|
147
|
+
# mise à jour de l'inconnue de section sur base des incréments
|
148
|
+
a = a + incr[:n]
|
149
|
+
|
150
|
+
# mise à jour des propriétés indirectes
|
151
|
+
h, width = h_width_froma(a)
|
152
|
+
|
153
|
+
# calcul de l'erreur résiduelle
|
154
|
+
error = np.sum(np.abs(incr[:n]))
|
155
|
+
|
156
|
+
return a
|
157
|
+
|
158
|
+
if __name__ == "__main__":
|
159
|
+
# Test the function
|
160
|
+
q = np.array([-1, 2, 3, -4])
|
161
|
+
q_junction, lambda_ = junction_q_lagrangemult(q)
|
162
|
+
print("q_junction:", q_junction)
|
163
|
+
print("lambda:", lambda_)
|
164
|
+
|
165
|
+
# Test the function
|
166
|
+
q = np.array([-1.1, 2.2, 3.001, -3.99])
|
167
|
+
q_junction, lambda_ = junction_q_lagrangemult(q)
|
168
|
+
print("q_junction:", q_junction)
|
169
|
+
print("lambda:", lambda_)
|
170
|
+
|
171
|
+
def h_width_froma(a:np.ndarray):
|
172
|
+
L = 5.
|
173
|
+
h = a / L
|
174
|
+
dl = np.ones(a.shape) * L
|
175
|
+
return h, dl
|
176
|
+
|
177
|
+
a = np.array([1, 2, 3, 4])
|
178
|
+
z = np.array([0, 0, 0, 0])
|
179
|
+
|
180
|
+
a_junction = junction_wse_head_lagrangemult(q, a, h_width_froma, z, energy=False)
|
181
|
+
print("a_junction:", a_junction + z)
|
182
|
+
|
183
|
+
a = a_junction
|
184
|
+
a_junction = junction_wse_head_lagrangemult(q, a, h_width_froma, z, energy=True)
|
185
|
+
print("a_junction:", a_junction)
|
186
|
+
|
187
|
+
L = 5.
|
188
|
+
z = np.array([0, -1, .5, -.5])
|
189
|
+
a = (1. - z) * L
|
190
|
+
|
191
|
+
a_junction = junction_wse_head_lagrangemult(q, a, h_width_froma, z, energy=False)
|
192
|
+
h, width = h_width_froma(a_junction)
|
193
|
+
print("wse:", h + z)
|
194
|
+
|
195
|
+
z = np.array([0, -1, .5, -.5])
|
196
|
+
a = (1. - z)*5.
|
197
|
+
a[0] += 0.1
|
198
|
+
a[1] += 0.1
|
199
|
+
a[2] -= 0.1
|
200
|
+
a[3] -= 0.1
|
201
|
+
|
202
|
+
a_junction = junction_wse_head_lagrangemult(q, a, h_width_froma, z, energy=False)
|
203
|
+
h, width = h_width_froma(a_junction)
|
204
|
+
print("wse:", h + z)
|
205
|
+
pass
|
wolfhece/libs/WolfDll.dll
CHANGED
Binary file
|
wolfhece/pybridges.py
CHANGED
@@ -1009,11 +1009,11 @@ class Bridges(Element_To_Draw):
|
|
1009
1009
|
|
1010
1010
|
return self.active_elt
|
1011
1011
|
|
1012
|
-
def find_inside_poly(self,
|
1012
|
+
def find_inside_poly(self, vec:vector)->list:
|
1013
1013
|
"""
|
1014
1014
|
Find bridges inside polygon/vector
|
1015
1015
|
"""
|
1016
|
-
polyls =
|
1016
|
+
polyls = vec.polygon
|
1017
1017
|
bridges = list(self.myelts.values())
|
1018
1018
|
|
1019
1019
|
mysel=[]
|
wolfhece/pypolygons_scen.py
CHANGED
@@ -408,7 +408,7 @@ class Polygons_Analyze(Zones):
|
|
408
408
|
self.polygons_meanxy = {}
|
409
409
|
for curvert in self.polygons_zone.myvectors:
|
410
410
|
# Centre du polygone
|
411
|
-
centroid = curvert.
|
411
|
+
centroid = curvert.centroid
|
412
412
|
self.polygons_meanxy[curvert.myname] = (centroid.x, centroid.y)
|
413
413
|
|
414
414
|
for vec in self.polygons_zone.myvectors:
|
@@ -536,7 +536,7 @@ class Polygons_Analyze(Zones):
|
|
536
536
|
|
537
537
|
for curvert in self.polygons_zone.myvectors:
|
538
538
|
# Centre du polygone
|
539
|
-
centroid = curvert.
|
539
|
+
centroid = curvert.centroid
|
540
540
|
self.polygons_curvi[curvert.myname] = poly.project(Point([centroid.x, centroid.y]))
|
541
541
|
|
542
542
|
def find_values_inside_parts(self, linked_arrays:Union[dict,list]):
|
wolfhece/radar/wolfradar.py
CHANGED
@@ -19,7 +19,16 @@ from datetime import timezone
|
|
19
19
|
from os import path
|
20
20
|
from osgeo import gdal, osr
|
21
21
|
from ..drawing_obj import Element_To_Draw
|
22
|
+
from tqdm import tqdm
|
22
23
|
|
24
|
+
RADQPE = 1
|
25
|
+
RADCLIM = 2
|
26
|
+
RADFLOOD = 3
|
27
|
+
|
28
|
+
FILL_NONE = 0
|
29
|
+
FILL_ZERO = 1
|
30
|
+
FILL_NAN = 2
|
31
|
+
FILL_INTERP = 3
|
23
32
|
|
24
33
|
class L08L72:
|
25
34
|
epsgL08:osr.SpatialReference
|
@@ -51,12 +60,13 @@ class RadarIRM(Element_To_Draw):
|
|
51
60
|
|
52
61
|
|
53
62
|
def convert2rain(self, coordMin:tuple, coordMax:tuple, dateBegin:date, dateEnd:date, deltaT:tdelta,
|
54
|
-
dirIn:str="", dirOut:str="",
|
55
|
-
check_all_polygons:bool=False):
|
63
|
+
dirIn:str="", dirOut:str="", file_name_conv:str=".radclim.accum", type_rain:int=RADCLIM, recursive_dir="",
|
64
|
+
check_all_polygons:bool=False, fill_data:int=FILL_NONE):
|
56
65
|
|
57
|
-
from datetime import datetime as date
|
58
66
|
# =================
|
59
67
|
# ALL VERIFICATIONS :
|
68
|
+
logging.info("Starting the conversion of IRM data to rain data ...")
|
69
|
+
logging.info("Verification ongoing ...")
|
60
70
|
|
61
71
|
# Checking the validity of the repository to read and write :
|
62
72
|
isOk, dirIn = check_path(dirIn, applyCWD=True)
|
@@ -74,12 +84,21 @@ class RadarIRM(Element_To_Draw):
|
|
74
84
|
dt = deltaT.total_seconds()
|
75
85
|
nb_intervals = floor((dateEnd - dateBegin).total_seconds() / dt)
|
76
86
|
time = [dateBegin + tdelta(seconds=dt*i) for i in range(nb_intervals + 1)]
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
87
|
+
if recursive_dir == "":
|
88
|
+
# Prefix for dates -> only if it's not a recursive directory
|
89
|
+
dt_str = "{:.0f}d".format(deltaT.days)*(deltaT.days>0) \
|
90
|
+
+ "{:.0f}h".format(floor(deltaT.seconds)/3600)*(floor(deltaT.seconds/3600)>0) \
|
91
|
+
+ "{:.0f}m".format(floor(deltaT.seconds%3600)/60)*(floor(deltaT.seconds%3600)/60>0)
|
92
|
+
suffix = "".join([file_name_conv, dt_str, ".hdf"])
|
93
|
+
all_files = [os.path.join(dirIn,"".join([t.strftime("%Y%m%d%H%M%S"),suffix])) for t in time]
|
94
|
+
else:
|
95
|
+
suffix = "".join([file_name_conv, ".hdf"])
|
96
|
+
all_files = [os.path.join(dirIn,
|
97
|
+
t.strftime("%Y"),
|
98
|
+
t.strftime("%m"),
|
99
|
+
t.strftime("%d"),
|
100
|
+
recursive_dir,
|
101
|
+
"".join([t.strftime("%Y%m%d%H%M%S"),suffix])) for t in time]
|
83
102
|
# are_present = np.all(np.array( \
|
84
103
|
# [os.path.exists(os.path.join(dirIn,"".join([t.strftime("%Y%m%d%H%M%S"),suffix]))) for t in time] \
|
85
104
|
# ))
|
@@ -90,7 +109,14 @@ class RadarIRM(Element_To_Draw):
|
|
90
109
|
|
91
110
|
if not are_present:
|
92
111
|
logging.error("Rain files present in the selected directory are does not contain all the information between the desired interval.")
|
93
|
-
|
112
|
+
i_problem = np.where(np.array([os.path.exists(el) for el in all_files]) == False)[0]
|
113
|
+
logging.error("The following files are missing :")
|
114
|
+
for i in i_problem:
|
115
|
+
logging.error(all_files[i])
|
116
|
+
if fill_data == FILL_NONE:
|
117
|
+
logging.error("The process stops because there are missing files!")
|
118
|
+
logging.error("To make an linear interpolation set to False 'no_missing_files' argument.")
|
119
|
+
return
|
94
120
|
|
95
121
|
# Creating the direcory results
|
96
122
|
# Directory of the shapefile
|
@@ -118,12 +144,15 @@ class RadarIRM(Element_To_Draw):
|
|
118
144
|
else:
|
119
145
|
print ("Successfully created the directory %s" % timeSeriesDir)
|
120
146
|
|
147
|
+
logging.info("Verification validated!")
|
121
148
|
|
122
149
|
# =================
|
123
150
|
# CORE PROCEDURE
|
124
151
|
# After all verifications, the core procedure can now start :
|
125
152
|
# extract all the points in all the .hdf files and their values -> check whether to crop during this process of after
|
126
153
|
|
154
|
+
logging.info("Creation of the shapefile ongoing ...")
|
155
|
+
|
127
156
|
# Definition of the domaine zone
|
128
157
|
limits = vector()
|
129
158
|
limits.add_vertex(wolfvertex(coordMin[0],coordMin[1]))
|
@@ -173,27 +202,52 @@ class RadarIRM(Element_To_Draw):
|
|
173
202
|
|
174
203
|
# save the polygons in .shp shapefile
|
175
204
|
polygons.export_shape(fileOut)
|
205
|
+
logging.info("Creation of the shapefile finished !")
|
176
206
|
|
177
|
-
|
207
|
+
logging.info("Creation of polygon time series ongoing ...")
|
178
208
|
# Create a folder with the time serie for each polygone
|
179
209
|
timeStps = [[str(t.day), str(t.month), str(t.year), str(t.hour), str(t.minute), str(t.second)] for t in time]
|
180
210
|
|
181
211
|
all_values = np.zeros((len(all_files), polygons.nbvectors))
|
182
|
-
for i in range(len(all_files)):
|
212
|
+
for i in tqdm(range(len(all_files))):
|
183
213
|
cur_file = all_files[i]
|
214
|
+
exists = os.path.exists(cur_file)
|
184
215
|
try:
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
216
|
+
if exists:
|
217
|
+
hdf_ds = gdal.Open(cur_file, gdal.GA_ReadOnly)
|
218
|
+
values, coord, proj = wrl.georef.raster.extract_raster_dataset(hdf_ds, mode="edge", nodata=0.0)
|
219
|
+
vec_values = values.reshape(-1)
|
220
|
+
all_values[i,:] = np.nan_to_num([vec_values[i] for i in zones_indices], copy=False, nan=0.0)
|
221
|
+
# FIXME this following line -> to check !!!! -> Convert [mm/h] to accumulated rain [mm] at each time step
|
222
|
+
# radflood
|
223
|
+
if type_rain == RADFLOOD or type_rain == RADCLIM:
|
224
|
+
all_values[i,:] = all_values[i,:]
|
225
|
+
elif type_rain == RADQPE:
|
226
|
+
# radqpe
|
227
|
+
# TODO : check the conversion for radclim
|
228
|
+
all_values[i,:] = all_values[i,:]*(dt/3600.0)
|
229
|
+
# all_values[i,:] = all_values[i,:]*(dt/3600.0)
|
230
|
+
else:
|
231
|
+
if fill_data == FILL_ZERO:
|
232
|
+
all_values[i,:] = 0.0
|
233
|
+
else:
|
234
|
+
all_values[i,:] = np.nan
|
191
235
|
except:
|
192
236
|
logging.error("".join(["Something bad happened while reading hdf file :", cur_file]))
|
193
237
|
all_values[i,:] = 0.0
|
194
|
-
|
238
|
+
logging.info("Creation of polygon time series finished !")
|
239
|
+
|
240
|
+
logging.info("Writing polygon time series ongoing ...")
|
195
241
|
# Writing the file
|
196
|
-
for iVec in range(polygons.nbvectors):
|
242
|
+
for iVec in tqdm(range(polygons.nbvectors)):
|
243
|
+
# Clean the nan value with linear interpolation
|
244
|
+
# FIXME : to check the interpolation
|
245
|
+
if(fill_data == FILL_INTERP):
|
246
|
+
logging.warning('Interpolating missing values in the time series -> Still to test!')
|
247
|
+
valid = ~np.isnan(all_values[:,iVec])
|
248
|
+
invalid = np.isnan(all_values[:,iVec])
|
249
|
+
all_values[invalid,iVec] = np.interp(np.flatnonzero(invalid), np.flatnonzero(valid), all_values[valid,iVec])
|
250
|
+
# write in the file
|
197
251
|
with open(os.path.join(timeSeriesDir,"".join([str(iVec+1),".rain"])), 'w') as f:
|
198
252
|
f.write("".join([str(iVec+1),"\n"]))
|
199
253
|
f.write("".join([str(1),"\n"]))
|
@@ -201,11 +255,10 @@ class RadarIRM(Element_To_Draw):
|
|
201
255
|
f.write("".join([str(len(all_files)),"\n"]))
|
202
256
|
for cur_t in range(len(timeStps)):
|
203
257
|
f.write("\t".join(timeStps[cur_t] + [str(all_values[cur_t,iVec])]) + "\n")
|
204
|
-
|
258
|
+
logging.info("Writing polygon time series finished !")
|
205
259
|
|
206
260
|
print(are_present)
|
207
261
|
|
208
|
-
|
209
262
|
# def plot(self):
|
210
263
|
# pass
|
211
264
|
|
File without changes
|