wolfhece 2.1.98__py3-none-any.whl → 2.1.100__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/wolf_vrt.py CHANGED
@@ -38,7 +38,24 @@ def create_vrt(wdir:str, fout:str='out.vrt', format:str='tif'):
38
38
  myvrt = None
39
39
 
40
40
  os.chdir(curdir)
41
-
41
+ def _get_diverged_relative_path(path: Path, base: Path) -> Path:
42
+ """
43
+ Get relative path from base to path, even if they only share part of their paths.
44
+ More general than the next function "_get_relative_path", especially for not "child/parents paths"
45
+ """
46
+
47
+ # Parts of the paths
48
+ relative_path_parts = path.parts
49
+ base_parts = base.parts
50
+ # Where do they diverge ?
51
+ i = 0
52
+ while i < min(len(relative_path_parts), len(base_parts)) and relative_path_parts[i] == base_parts[i]:
53
+ i += 1
54
+
55
+ # Building of the relative path, by adding ".." from the divergence point
56
+ return Path(*(['..'] * (len(base_parts) - i) + list(relative_path_parts[i:])))
57
+
58
+
42
59
  def _get_relative_path(path:Path, base:Path):
43
60
  """
44
61
  Get relative path from base to path
@@ -47,7 +64,6 @@ def _get_relative_path(path:Path, base:Path):
47
64
  :type path: Path
48
65
  :param base: base path
49
66
  :type base: Path
50
-
51
67
  """
52
68
 
53
69
  if base in path.parents:
@@ -79,7 +95,8 @@ def create_vrt_from_files(files:list[Path]=[], fout:Path='assembly.vrt'):
79
95
  # change working directory to the parent of the output file
80
96
  os.chdir(fout.parent)
81
97
  # work with relative paths
82
- myvrt = gdal.BuildVRT(str(fout.with_suffix('.vrt').name) , [str(_get_relative_path(file, fout.parent)) for file in files])
98
+
99
+ myvrt = gdal.BuildVRT(str(fout.with_suffix('.vrt').name) , [str(_get_diverged_relative_path(file, fout.parent)) for file in files])
83
100
  # close the dataset -- force to write on disk
84
101
  myvrt = None
85
102
  # restore working directory
@@ -91,7 +108,7 @@ def create_vrt_from_files_first_based(files:list[Path]=[], fout:Path='assembly.v
91
108
 
92
109
  Restreint l'emprise et force la résolution sur le premier fichier listé
93
110
  """
94
-
111
+
95
112
  if isinstance(fout, str):
96
113
  fout = Path(fout)
97
114
 
@@ -119,6 +136,7 @@ def create_vrt_from_files_first_based(files:list[Path]=[], fout:Path='assembly.v
119
136
 
120
137
  locNoData = raster.GetRasterBand(1).GetNoDataValue()
121
138
 
139
+ # options of BuildVRT defined on properties of "files[0]"
122
140
  options = gdal.BuildVRTOptions(resolution='user',
123
141
  xRes=abs(geotr[1]),
124
142
  yRes=abs(geotr[5]),
@@ -128,11 +146,94 @@ def create_vrt_from_files_first_based(files:list[Path]=[], fout:Path='assembly.v
128
146
 
129
147
  # retain current working directory
130
148
  oldcwd = os.getcwd()
131
- # change working directory to the parent of the output file
132
- os.chdir(fout.parent.absolute())
149
+ # change working directory to the parent of the output file
150
+ os.chdir(fout.parent.absolute())
151
+ # work with relative paths
152
+ myvrt = gdal.BuildVRT(str(fout.with_suffix('.vrt').name),[str(_get_diverged_relative_path(file, fout.parent)) for file in files], options=options) #str(_get_diverged_relative_path(file, fout.parent)) for file in files
153
+
154
+ # close the dataset -- force to write on disk
155
+ myvrt = None
156
+ # restore working directory
157
+ os.chdir(oldcwd)
158
+
159
+
160
+ def create_vrt_from_diverged_files(files:list[Path]=[], fout:Path='assembly.vrt'):
161
+ """
162
+ Agglomération de tous les fichiers énumérés dans files dans un layer virtuel .vrt
133
163
 
164
+ :param files: list of files to process
165
+ :type files: list[Path]
166
+ :param fout: output file
167
+ :type fout: Path
168
+ """
169
+
170
+ if isinstance(fout, str):
171
+ fout = Path(fout)
172
+
173
+ if isinstance(files[0], str):
174
+ files = [Path(file) for file in files]
175
+
176
+ # retain current working directory
177
+ oldcwd = os.getcwd()
178
+ # change working directory to the parent of the output file
179
+ os.chdir(fout.parent)
134
180
  # work with relative paths
135
- myvrt = gdal.BuildVRT(str(fout.with_suffix('.vrt').name) , [str(_get_relative_path(file, fout.parent)) for file in files], options=options)
181
+
182
+ myvrt = gdal.BuildVRT(str(fout.with_suffix('.vrt').name) , [str(_get_diverged_relative_path(file, fout.parent)) for file in files])
183
+ # close the dataset -- force to write on disk
184
+ myvrt = None
185
+ # restore working directory
186
+ os.chdir(oldcwd)
187
+
188
+ def create_vrt_from_diverged_files_first_based(files:list[Path]=[], fout:Path='assembly.vrt', Nodata:float=99999.):
189
+ """
190
+ Agglomération de tous les fichiers énumérés dans files dans un layer virtuel .vrt
191
+
192
+ Restreint l'emprise et force la résolution sur le premier fichier listé
193
+ """
194
+
195
+ if isinstance(fout, str):
196
+ fout = Path(fout)
197
+
198
+ if isinstance(files[0], str):
199
+ files = [Path(file) for file in files]
200
+
201
+ first = files[0]
202
+ raster:gdal.Dataset
203
+ raster = gdal.Open(str(first))
204
+ geotr = raster.GetGeoTransform()
205
+
206
+ # Dimensions
207
+ nbx = raster.RasterXSize
208
+ nby = raster.RasterYSize
209
+
210
+ xmin = geotr[0]
211
+ xmax = geotr[0]+geotr[1]*float(nbx)
212
+
213
+ if geotr[5]>0:
214
+ ymin = geotr[3]
215
+ ymax = geotr[3]+geotr[5]*float(nby)
216
+ else:
217
+ ymin = geotr[3]+geotr[5]*float(nby)
218
+ ymax = geotr[3]
219
+
220
+ locNoData = raster.GetRasterBand(1).GetNoDataValue()
221
+
222
+ # options of BuildVRT defined on properties of "files[0]"
223
+ options = gdal.BuildVRTOptions(resolution='user',
224
+ xRes=abs(geotr[1]),
225
+ yRes=abs(geotr[5]),
226
+ outputBounds=[xmin,ymin,xmax,ymax],
227
+ resampleAlg='bilinear',
228
+ srcNodata=Nodata)
229
+
230
+ # retain current working directory
231
+ oldcwd = os.getcwd()
232
+ # change working directory to the parent of the output file
233
+ os.chdir(fout.parent.absolute())
234
+ # work with relative paths
235
+ myvrt = gdal.BuildVRT(str(fout.with_suffix('.vrt').name),[str(_get_diverged_relative_path(file, fout.parent)) for file in files], options=options) #str(_get_diverged_relative_path(file, fout.parent)) for file in files
236
+
136
237
  # close the dataset -- force to write on disk
137
238
  myvrt = None
138
239
  # restore working directory
@@ -12,6 +12,7 @@ import sys
12
12
  import wx
13
13
  from os.path import dirname, exists, join, splitext
14
14
  from math import floor
15
+ from pathlib import Path
15
16
 
16
17
  import numpy.ma as ma
17
18
  import numpy as np
@@ -51,7 +52,6 @@ except Exception as ex:
51
52
 
52
53
  from importlib.util import find_spec
53
54
  s = find_spec('wolfhece.libs.wolfpy')
54
- from pathlib import Path
55
55
 
56
56
  # Not too sure about this find_spec. If the root
57
57
  # directory is not the good one, the import search may
@@ -747,7 +747,6 @@ class Props_Res_2D(wx.Frame):
747
747
  """ Load default palette """
748
748
 
749
749
  import glob
750
- from pathlib import Path
751
750
 
752
751
  # list of all .pal file in model directory
753
752
 
@@ -2303,6 +2302,25 @@ class Wolfresults_2D(Element_To_Draw):
2303
2302
  self.myops = None
2304
2303
  self._active_blocks = 0
2305
2304
 
2305
+ @property
2306
+ def all_dt(self):
2307
+ #FIXME : defined in GPU version --> to be implemented for CPU version
2308
+ pass
2309
+
2310
+ @property
2311
+ def all_mostly_dry_mesh(self):
2312
+ #FIXME : defined in GPU version --> to be implemented for CPU version
2313
+ pass
2314
+
2315
+ @property
2316
+ def all_clock_time(self):
2317
+ #FIXME : defined in GPU version --> to be implemented for CPU version
2318
+ pass
2319
+
2320
+ @property
2321
+ def all_wet_meshes(self):
2322
+ #FIXME : defined in GPU version --> to be implemented for CPU version
2323
+ pass
2306
2324
 
2307
2325
  def set_opacity(self, alpha:float):
2308
2326
  """ Set the transparency of the array """
@@ -3691,6 +3709,80 @@ class Wolfresults_2D(Element_To_Draw):
3691
3709
  """
3692
3710
  self._cache = None
3693
3711
 
3712
+ def get_hydrographs(self, vect:Union[vector, list[vector], zone]):
3713
+ """ Get hydrograph accross a vector
3714
+
3715
+ :param vect: wolf polyline or list of wolf polylines or zone
3716
+ """
3717
+
3718
+ assert isinstance(vect, vector | list | zone), 'Expected a vector'
3719
+
3720
+ if isinstance(vect, zone):
3721
+ vect = vect.myvectors
3722
+
3723
+ nb = self.get_nbresults()
3724
+ times, steps = self.times, self.timesteps
3725
+
3726
+ if isinstance(vect, vector):
3727
+ q=[]
3728
+ for i in tqdm(range(nb)):
3729
+ if i==0:
3730
+ myhead = self.get_header_block(1)
3731
+ vect_raster = myhead.rasterize_vector(vect)
3732
+ self.read_oneresult(i)
3733
+ q.append(self._plot_one_q_raster_splitting(vect_raster, True, to_rasterize = False))
3734
+
3735
+ elif isinstance(vect, list):
3736
+ q={str:list}
3737
+ vect_raster = []
3738
+ myhead = self.get_header_block(1)
3739
+
3740
+ for i in range(len(vect)):
3741
+ q[vect[i].myname]= []
3742
+ vect_raster.append(myhead.rasterize_vector(vect[i]))
3743
+
3744
+ for i in tqdm(range(nb)):
3745
+ self.read_oneresult(i)
3746
+
3747
+ for curvec, cur_vect_raster in zip(vect, vect_raster):
3748
+ q[curvec.myname].append(self._plot_one_q_raster_splitting(cur_vect_raster, True, to_rasterize = False))
3749
+
3750
+ return times, q
3751
+
3752
+ def export_hydrographs(self, vect:Union[vector, list[vector], zone], filename:str|Path):
3753
+ """ Export hydrograph accross a vector as CSV file
3754
+
3755
+ :param vect: wolf polyline or list of wolf polylines or zone
3756
+ :param filename: output filename
3757
+ """
3758
+
3759
+ assert isinstance(vect, vector | list | zone), 'Expected a vector'
3760
+
3761
+ filename = Path(filename)
3762
+ filename = filename.with_suffix('.csv')
3763
+
3764
+ if isinstance(vect, zone):
3765
+ vect = vect.myvectors
3766
+
3767
+ times, q = self.get_hydrographs(vect)
3768
+
3769
+ with open(filename, 'w') as f:
3770
+ f.write('Time [s],')
3771
+ if isinstance(vect, vector):
3772
+ f.write(vect.myname)
3773
+ elif isinstance(vect, list):
3774
+ f.write(','.join([cur.myname for cur in vect]))
3775
+ f.write('\n')
3776
+
3777
+ for i in range(len(times)):
3778
+ f.write(f'{times[i]},')
3779
+ if isinstance(vect, vector):
3780
+ f.write(f'{q[i]}')
3781
+ elif isinstance(vect, list):
3782
+ f.write(','.join([str(q[cur.myname][i]) for cur in vect]))
3783
+ f.write('\n')
3784
+
3785
+
3694
3786
  #FIXME : rename 'x_or_y' to be more explicit
3695
3787
  def plot_q(self,
3696
3788
  vect:Union[vector, list[vector]],
@@ -4435,9 +4527,9 @@ class Wolfresults_2D(Element_To_Draw):
4435
4527
  def export_as(self,
4436
4528
  outdir:str,
4437
4529
  fields:list[views_2D],
4438
- which:Literal['geotiff', 'shape'],
4530
+ which:Literal['geotiff', 'shape', 'numpy'],
4439
4531
  multiband:bool=True):
4440
- """ Export as geotiff or shapefile """
4532
+ """ Export as geotiff or shapefile or numpy """
4441
4533
 
4442
4534
  oldview = self.get_currentview()
4443
4535
  old_plotted = self.plotted
@@ -4470,6 +4562,19 @@ class Wolfresults_2D(Element_To_Draw):
4470
4562
  [key.value for key,arr in arrays.items()],
4471
4563
  shape_mask)
4472
4564
 
4565
+ elif which=='numpy':
4566
+ for curfield, curarray in arrays.items():
4567
+ if curfield == views_2D.TOPOGRAPHY:
4568
+ curarray.write_all(Path(outdir) / 'bathymetry.npy')
4569
+ elif curfield == views_2D.WATERDEPTH:
4570
+ curarray.write_all(Path(outdir) / 'h.npy')
4571
+ elif curfield == views_2D.QX:
4572
+ curarray.write_all(Path(outdir) / 'qx.npy')
4573
+ elif curfield == views_2D.QY:
4574
+ curarray.write_all(Path(outdir) / 'qy.npy')
4575
+ else:
4576
+ curarray.write_all(Path(outdir) / (curfield.value + '.npy'))
4577
+
4473
4578
  self.plotted = old_plotted
4474
4579
  self.set_currentview(oldview)
4475
4580
 
wolfhece/xyz_file.py CHANGED
@@ -13,106 +13,130 @@ import numpy as np
13
13
  import matplotlib.pyplot as plt
14
14
  from os.path import normpath,exists,join,basename
15
15
  from os import listdir,scandir
16
+ import logging
16
17
 
17
18
  from .PyTranslate import _
18
19
 
19
20
  class XYZFile:
20
21
  """ Classe pour la gestion des fichiers xyz """
21
- nblines:int
22
22
  x:np.array
23
23
  y:np.array
24
24
  z:np.array
25
25
  filename:str
26
26
 
27
- def __init__(self, fname,toread=True):
27
+ def __init__(self, fname:str, toread:bool= True,
28
+ folder:str= None, bounds:list= None,
29
+ delimiter:str=','):
28
30
  """ Initialisation du nom du fichier """
31
+
29
32
  self.filename = fname
30
- self.nblines=0
31
-
33
+
32
34
  self.x = None
33
35
  self.y = None
34
36
  self.z = None
35
37
  self.xyz = None
36
-
38
+
37
39
  if toread:
38
- self.read_from_file()
40
+ self.read_from_file(folder=folder, bounds=bounds, delimiter=delimiter)
41
+
42
+ @property
43
+ def nblines(self):
44
+ if self.x is None:
45
+ return 0
46
+ else:
47
+ return len(self.x)
48
+
49
+ def reset(self):
50
+ """ Reset des données """
51
+ self.x = None
52
+ self.y = None
53
+ self.z = None
54
+ self.xyz = None
39
55
 
40
56
  def test_bounds(self,bounds):
41
-
57
+
42
58
  if bounds is None:
43
59
  return True
44
-
60
+
45
61
  x1=bounds[0][0]
46
62
  x2=bounds[0][1]
47
63
  y1=bounds[1][0]
48
64
  y2=bounds[1][1]
49
-
65
+
50
66
  mybounds = self.get_extent()
51
67
 
52
68
  test = not(x2 < mybounds[0][0] or x1 > mybounds[0][1] or y2 < mybounds[1][0] or y1 > mybounds[1][1])
53
-
69
+
54
70
  return test
55
71
 
56
- def read_from_file(self):
72
+ def read_from_file(self, folder:str=None, bounds:list=None, delimiter=','):
57
73
  """ Lecture d'un fichier xyz et remplissage de l'objet """
58
-
59
- self.xyz = np.genfromtxt(self.filename, delimiter=',',dtype=np.float32)
74
+
75
+ try:
76
+ if folder is None:
77
+ self.xyz = np.genfromtxt(self.filename, delimiter=delimiter, dtype=np.float32)
78
+ else:
79
+ if bounds is None:
80
+ self.reset()
81
+ logging.error(_('Bounds must be defined when reading a directory'))
82
+ return
83
+
84
+ self.xyz = xyz_scandir(folder,bounds=bounds,delimiter=delimiter)
85
+ # check if self.xyz is an empty array
86
+ if len(self.xyz) == 0:
87
+ self.xyz = None
88
+ return
89
+ except:
90
+ self.reset()
91
+ logging.error(_('Error reading file: {self.filename}'))
92
+ return
93
+
60
94
  self.x = self.xyz[:,0]
61
95
  self.y = self.xyz[:,1]
62
96
  self.z = self.xyz[:,2]
63
- self.nblines = len(self.xyz)
64
-
65
- # with open(self.filename, 'r') as f:
66
- # self.nblines = sum(1 for line in f)
67
- # self.x = np.zeros(self.nblines)
68
- # self.y = np.zeros(self.nblines)
69
- # self.z = np.zeros(self.nblines)
70
- # f.seek(0)
71
- # self.nblines = 0
72
- # for line in f:
73
- # tmp = line.split()
74
- # if tmp:
75
- # if is_float(tmp[0]):
76
- # self.x[self.nblines] = float(tmp[0])
77
- # self.y[self.nblines] = float(tmp[1])
78
- # self.z[self.nblines] = float(tmp[2])
79
- # self.nblines += 1
80
97
 
81
98
  def fill_from_wolf_array(self, myarray,nullvalue=0.):
82
99
  """ Création d'un fichier xyz depuis les données d'un WOLF array """
83
- self.nblines = myarray.nbx * myarray.nby
84
- self.x = np.zeros(self.nblines)
85
- self.y = np.zeros(self.nblines)
86
- self.z = np.zeros(self.nblines)
87
- self.nblines = 0
100
+
101
+ nbmaxlines = myarray.nbx * myarray.nby
102
+ self.x = np.zeros(nbmaxlines)
103
+ self.y = np.zeros(nbmaxlines)
104
+ self.z = np.zeros(nbmaxlines)
105
+
106
+ k=0
88
107
  for cury in range(myarray.nby):
89
108
  y = cury * myarray.dy + 0.5 * myarray.dy + myarray.origy + myarray.transly
90
109
  for curx in range(myarray.nbx):
91
110
  z = myarray.array[curx, cury]
92
111
  if z != nullvalue:
93
112
  x = curx * myarray.dx + 0.5 * myarray.dx + myarray.origx + myarray.translx
94
- self.x[self.nblines] = x
95
- self.y[self.nblines] = y
96
- self.z[self.nblines] = z
97
- self.nblines += 1
113
+ self.x[k] = x
114
+ self.y[k] = y
115
+ self.z[k] = z
116
+ k+=1
117
+
118
+ # crop the arrays
119
+ self.x = self.x[:k]
120
+ self.y = self.y[:k]
121
+ self.z = self.z[:k]
98
122
 
99
123
  def write_to_file(self):
100
124
  """ Ecriture des informations dans un fichier """
125
+
101
126
  with open(self.filename, 'w') as f:
102
127
  for i in range(self.nblines):
103
128
  f.write('{:.3f},{:.3f},{:.3f}\n'.format(self.x[i], self.y[i], self.z[i]))
104
129
 
105
130
  def get_extent(self):
106
131
  """ Retourne les limites du rectangle qui encadre le nuage de points """
132
+
107
133
  xlim = [np.min(self.x), np.max(self.x)]
108
134
  ylim = [np.min(self.y), np.max(self.y)]
109
135
  return (xlim, ylim)
110
136
 
111
- def merge(self, xyz_list):
137
+ def merge(self, xyz_list:list["XYZFile"]):
112
138
  """ Merge des fichiers xyz en 1 seul """
113
- for cur_xyz in xyz_list:
114
- self.nblines += cur_xyz.nblines
115
-
139
+
116
140
  newxyz = np.concatenate([cur.xyz for cur in xyz_list])
117
141
 
118
142
  if self.xyz is not None:
@@ -126,6 +150,7 @@ class XYZFile:
126
150
 
127
151
  def plot(self):
128
152
  """ Représentation graphique des points """
153
+
129
154
  plt.scatter(self.x, self.y, c=self.z, marker='.', cmap='viridis', edgecolors='none')
130
155
  plt.xlabel('x [m]')
131
156
  plt.ylabel('y [m]')
@@ -137,16 +162,17 @@ class XYZFile:
137
162
  plt.pause(0.1)
138
163
 
139
164
  def find_points(self,bounds):
140
-
165
+
141
166
  if bounds is None:
142
167
  return self.xyz
143
-
168
+
144
169
  xb=bounds[0]
145
170
  yb=bounds[1]
171
+
146
172
  # Get arrays which indicate invalid X, Y, or Z values.
147
173
  X_valid = (xb[0] <= self.x) & (xb[1] > self.x)
148
174
  Y_valid = (yb[0] <= self.y) & (yb[1] > self.y)
149
- good_indices = np.where(X_valid & Y_valid)[0]
175
+ good_indices = np.where(X_valid & Y_valid)[0]
150
176
  return self.xyz[good_indices]
151
177
 
152
178
  def is_float(s):
@@ -156,19 +182,33 @@ def is_float(s):
156
182
  except ValueError:
157
183
  return False
158
184
 
159
- def xyz_scandir(mydir,bounds):
160
-
185
+ def xyz_scandir(mydir:str, bounds:list, delimiter:str=',') -> np.ndarray:
186
+ """
187
+ Function that reads all the xyz files in a directory and its subdirectories
188
+
189
+ :param mydir: directory to scan
190
+ :dtype mydir: str
191
+ :param bounds: bounds of the area to consider [[x1,x2],[y1,y2]]
192
+ :dtype bounds: list
193
+ :return: list of points
194
+ """
195
+
161
196
  first=[]
162
197
  for curfile in listdir(mydir):
163
198
  if curfile.endswith('.xyz'):
164
- mydata = XYZFile(join(mydir,curfile))
199
+ mydata = XYZFile(join(mydir,curfile), delimiter=delimiter)
165
200
  if mydata.test_bounds(bounds):
166
- print(curfile)
201
+ if isinstance(mydir,str):
202
+ logging.info(mydir)
203
+ else:
204
+ logging.info(mydir.path)
205
+ logging.info(curfile)
167
206
  first.append(mydata.find_points(bounds))
168
207
 
208
+ # if there is a subdirectory, we go deeper
169
209
  for entry in scandir(mydir):
170
210
  if entry.is_dir():
171
- locf=xyz_scandir(entry,bounds)
211
+ locf=xyz_scandir(entry, bounds, delimiter)
172
212
  if len(locf)>0:
173
213
  first.append(locf)
174
214
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: wolfhece
3
- Version: 2.1.98
3
+ Version: 2.1.100
4
4
  Author-email: Pierre Archambeau <pierre.archambeau@uliege.be>
5
5
  License: Copyright (c) 2024 University of Liege. All rights reserved.
6
6
  Project-URL: Homepage, https://uee.uliege.be/hece