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.
@@ -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
@@ -203,6 +203,7 @@ class Calculator(wx.Frame):
203
203
  while id in ids:
204
204
  id += '_'
205
205
 
206
+ res.set_nullvalue_in_mask()
206
207
  self._mapviewer.add_object('array', newobj=res, id = id)
207
208
  self.command = ''
208
209
 
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, poly:vector)->list:
1012
+ def find_inside_poly(self, vec:vector)->list:
1013
1013
  """
1014
1014
  Find bridges inside polygon/vector
1015
1015
  """
1016
- polyls = poly.asshapely_pol()
1016
+ polyls = vec.polygon
1017
1017
  bridges = list(self.myelts.values())
1018
1018
 
1019
1019
  mysel=[]
@@ -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.asshapely_pol().centroid
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.asshapely_pol().centroid
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]):
@@ -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
- # Prefix for dates
78
- dt_str = "{:.0f}d".format(deltaT.days)*(deltaT.days>0) \
79
- + "{:.0f}h".format(floor(deltaT.seconds)/3600)*(floor(deltaT.seconds/3600)>0) \
80
- + "{:.0f}m".format(floor(deltaT.seconds%3600)/60)*(floor(deltaT.seconds%3600)/60>0)
81
- suffix = "".join([".radclim.accum", dt_str, ".hdf"])
82
- all_files = [os.path.join(dirIn,"".join([t.strftime("%Y%m%d%H%M%S"),suffix])) for t in time]
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
- return
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
- hdf_ds = gdal.Open(cur_file, gdal.GA_ReadOnly)
186
- values, coord, proj = wrl.georef.raster.extract_raster_dataset(hdf_ds, mode="edge", nodata=0.0)
187
- vec_values = values.reshape(-1)
188
- all_values[i,:] = np.nan_to_num([vec_values[i] for i in zones_indices], copy=False, nan=0.0)
189
- # FIXME this following line -> to check !!!! -> Convert [mm/h] to accumulated rain [mm] at each time step
190
- all_values[i,:] = all_values[i,:]*(dt/3600.0)
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