wolfhece 2.2.23__py3-none-any.whl → 2.2.25__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.
@@ -1,4 +1,5 @@
1
1
  from pyproj import Transformer
2
+ from pyproj.transformer import TransformerGroup
2
3
  from concurrent.futures import ProcessPoolExecutor
3
4
  import numpy as np
4
5
  from osgeo import gdal
@@ -19,7 +20,8 @@ def transform_chunk_coordinates(inputEPSG:str, outputEPSG:str, chunk:np.ndarray)
19
20
  :type chunk: np.ndarray
20
21
  """
21
22
  COO_TRANSFORMER = Transformer.from_crs(inputEPSG, outputEPSG, always_xy=True)
22
- return COO_TRANSFORMER.transform(chunk[:, 0], chunk[:, 1])
23
+ ret = COO_TRANSFORMER.transform(chunk[:, 0], chunk[:, 1])
24
+ return ret
23
25
 
24
26
  def transform_coordinates(points:np.ndarray, inputEPSG:str="EPSG:3812", outputEPSG:str="EPSG:31370", chunk_size:int=1000):
25
27
  """
wolfhece/PyDraw.py CHANGED
@@ -4914,7 +4914,8 @@ class WolfMapViewer(wx.Frame):
4914
4914
  dpi:int= 300,
4915
4915
  add_title:bool = False,
4916
4916
  figsizes= [10.,10.],
4917
- arrayid_as_title:bool = False):
4917
+ arrayid_as_title:bool = False,
4918
+ resid_as_title:bool = False):
4918
4919
  """
4919
4920
  Sauvegarde de la fenêtre d'affichage dans un fichier
4920
4921
 
@@ -4970,6 +4971,8 @@ class WolfMapViewer(wx.Frame):
4970
4971
  pot_title = self.viewer_name
4971
4972
  if arrayid_as_title:
4972
4973
  pot_title = self.active_array.idx
4974
+ if resid_as_title:
4975
+ pot_title = self.active_res2d.idx
4973
4976
 
4974
4977
  self.display_canvasogl(fig=fig,
4975
4978
  ax=ax,
@@ -9919,16 +9922,21 @@ class WolfMapViewer(wx.Frame):
9919
9922
 
9920
9923
  # Get all checked arrays
9921
9924
  checked_arrays = self.get_list_keys(drawing_type= draw_type.ARRAYS, checked_state= True)
9925
+ checked_results = self.get_list_keys(drawing_type= draw_type.RES2D, checked_state= True)
9926
+
9922
9927
  old_active = self.active_array
9928
+ old_res2d = self.active_res2d
9923
9929
 
9924
- if len(checked_arrays) == 0:
9930
+ if len(checked_arrays) + len(checked_results) == 0:
9925
9931
  logging.warning(_('No arrays checked for export'))
9926
- return
9932
+ return []
9927
9933
 
9928
9934
  def uncheck_all():
9929
9935
  # uncheck arrays
9930
9936
  for curarray in checked_arrays:
9931
9937
  self.uncheck_id(curarray, unload= False, forceresetOGL= False)
9938
+ for curres in checked_results:
9939
+ self.uncheck_id(curres, unload= False, forceresetOGL= False)
9932
9940
 
9933
9941
  fn = str(fn)
9934
9942
  ret = []
@@ -9938,10 +9946,21 @@ class WolfMapViewer(wx.Frame):
9938
9946
  self.active_array = self.get_obj_from_id(curel, drawtype= draw_type.ARRAYS)
9939
9947
  ret.append((self.save_canvasogl(fn + '_' + str(idx) + '.png', mpl, ds, add_title= add_title, arrayid_as_title=True), curel))
9940
9948
 
9949
+ for idx, curel in enumerate(checked_results):
9950
+ uncheck_all()
9951
+ self.check_id(curel)
9952
+ self.active_res2d = self.get_obj_from_id(curel, drawtype= draw_type.RES2D)
9953
+ ret.append((self.save_canvasogl(fn + '_' + str(idx + len(checked_arrays)) + '.png', mpl, ds, add_title= add_title, resid_as_title=True), curel))
9954
+
9941
9955
  self.active_array = old_active
9956
+ self.active_res2d = old_res2d
9957
+
9942
9958
  for curarray in checked_arrays:
9943
9959
  self.check_id(curarray)
9944
9960
 
9961
+ for curres in checked_results:
9962
+ self.check_id(curres)
9963
+
9945
9964
  self.Refresh()
9946
9965
 
9947
9966
  return ret
@@ -11757,6 +11776,97 @@ class WolfMapViewer(wx.Frame):
11757
11776
  else:
11758
11777
  logging.warning(_('Reload not yet implemented for this type of object'))
11759
11778
 
11779
+ elif _('Rasterize active zone') in text:
11780
+
11781
+ if self.active_array is None and self.active_res2d is None:
11782
+ logging.warning(_('No active array selected'))
11783
+ return
11784
+
11785
+ if self.active_array is not None and self.active_res2d is not None:
11786
+ # Show a dialog to choose between array or res2d
11787
+ dlg = wx.SingleChoiceDialog(None, _('Choose the type of rasterization'), _('Rasterization Type'), ['Array', 'Res2D'], style=wx.CHOICEDLG_STYLE)
11788
+ ret = dlg.ShowModal()
11789
+ if ret != wx.ID_OK:
11790
+ dlg.Destroy()
11791
+ return
11792
+ choice = dlg.GetSelection()
11793
+ dlg.Destroy()
11794
+ if choice == 0:
11795
+ based_array = self.active_array
11796
+ else:
11797
+ if self.active_res2d.nb_blocks == 1:
11798
+ based_array = self.active_res2d.get_header_block(1)
11799
+ elif self.active_res2d.nb_blocks > 1:
11800
+ logging.error(_('Rasterization not implemented for multi-blocks res2d -- Convert to mono-blocks first'))
11801
+ return
11802
+
11803
+ elif self.active_array is not None:
11804
+ based_array = self.active_array
11805
+ elif self.active_res2d is not None:
11806
+ if self.active_res2d.nb_blocks == 1:
11807
+ based_array = self.active_res2d.get_header_block(1)
11808
+ elif self.active_res2d.nb_blocks > 1:
11809
+ logging.error(_('Rasterization not implemented for multi-blocks res2d -- Convert to mono-blocks first'))
11810
+ return
11811
+
11812
+ if isinstance(self.selected_object, Zones):
11813
+ if self.selected_object.active_zone is None:
11814
+ logging.warning(_('No active zone selected'))
11815
+ return
11816
+ if self.selected_object.active_zone.parent is None:
11817
+ logging.warning(_('No parent object for the active zone'))
11818
+ else:
11819
+ new_zone = based_array.rasterize_zone_along_grid(self.selected_object.active_zone, outformat= zone)
11820
+ if new_zone is not None:
11821
+ new_zone.myname = self.selected_object.active_zone.myname + '_rasterized'
11822
+ self.selected_object.active_zone.parent.add_zone(new_zone, forceparent=True)
11823
+ self.selected_object.active_zone.parent.fill_structure()
11824
+ self.selected_object.active_zone.reset_listogl()
11825
+
11826
+ elif _('Rasterize active vector') in text:
11827
+
11828
+ if self.active_array is None and self.active_res2d is None:
11829
+ logging.warning(_('No active array selected'))
11830
+ return
11831
+
11832
+ if self.active_array is not None and self.active_res2d is not None:
11833
+ # Show a dialog to choose between array or res2d
11834
+ dlg = wx.SingleChoiceDialog(None, _('Choose the type of rasterization'), _('Rasterization Type'), ['Array', 'Res2D'], style=wx.CHOICEDLG_STYLE)
11835
+ ret = dlg.ShowModal()
11836
+ if ret != wx.ID_OK:
11837
+ dlg.Destroy()
11838
+ return
11839
+ choice = dlg.GetSelection()
11840
+ dlg.Destroy()
11841
+ if choice == 0:
11842
+ based_array = self.active_array
11843
+ else:
11844
+ if self.active_res2d.nb_blocks == 1:
11845
+ based_array = self.active_res2d.get_header_block(1)
11846
+ elif self.active_res2d.nb_blocks > 1:
11847
+ logging.error(_('Rasterization not implemented for multi-blocks res2d -- Convert to mono-blocks first'))
11848
+ return
11849
+
11850
+ elif self.active_array is not None:
11851
+ based_array = self.active_array
11852
+ elif self.active_res2d is not None:
11853
+ if self.active_res2d.nb_blocks == 1:
11854
+ based_array = self.active_res2d.get_header_block(1)
11855
+ elif self.active_res2d.nb_blocks > 1:
11856
+ logging.error(_('Rasterization not implemented for multi-blocks res2d -- Convert to mono-blocks first'))
11857
+ return
11858
+
11859
+ if isinstance(self.selected_object, Zones):
11860
+ if self.selected_object.active_vector is None:
11861
+ logging.warning(_('No active vector selected'))
11862
+ return
11863
+
11864
+ vec_raster = based_array.rasterize_vector_along_grid(self.selected_object.active_vector)
11865
+ if vec_raster is not None:
11866
+ vec_raster.myname = self.selected_object.active_vector.myname + '_rasterized'
11867
+ self.selected_object.active_vector.parentzone.add_vector(vec_raster, forceparent=True, update_struct=True)
11868
+ self.selected_object.active_vector.parentzone.reset_listogl()
11869
+
11760
11870
  def OnClose(self, event):
11761
11871
  """ Close the application """
11762
11872
 
@@ -14546,6 +14656,9 @@ class WolfMapViewer(wx.Frame):
14546
14656
  tracks.append(_('Load flight'))
14547
14657
  tracks.append(_('Save flight'))
14548
14658
 
14659
+ tracks.append(_('Rasterize active zone'))
14660
+ tracks.append(_('Rasterize active vector'))
14661
+
14549
14662
  # Récupération des items du menu contextuel
14550
14663
  menuitems = self.popupmenu.GetMenuItems()
14551
14664
  text = [cur.GetItemLabelText() for cur in menuitems]
@@ -14583,6 +14696,10 @@ class WolfMapViewer(wx.Frame):
14583
14696
  self.popupmenu.Append(wx.ID_ANY, _('Convert to multi-blocks (result)'), _('Convert to multi-blocks'))
14584
14697
  self.popupmenu.Append(wx.ID_ANY, _('Extract current step as IC (result)'), _('Extract current step as IC'))
14585
14698
 
14699
+ if isinstance(self.selected_object, Zones):
14700
+ self.popupmenu.Append(wx.ID_ANY, _('Rasterize active zone'), _('Rasterize active zone'))
14701
+ self.popupmenu.Append(wx.ID_ANY, _('Rasterize active vector'), _('Rasterize active vector'))
14702
+
14586
14703
  if isinstance(self.selected_object, Zones | Bridge | Weir):
14587
14704
  self.popupmenu.Append(wx.ID_ANY, _('Export to Shape file'), _('Export to Shape file'))
14588
14705
  self.popupmenu.Append(wx.ID_ANY, _('Export active zone to Shape file'), _('Export active zone to Shape file'))
wolfhece/PyVertex.py CHANGED
@@ -36,7 +36,6 @@ from .drawing_obj import Element_To_Draw
36
36
  from .textpillow import Text_Image, Text_Infos, Font_Priority
37
37
  from .wolf_texture import Text_Image_Texture
38
38
 
39
-
40
39
  def getRGBfromI(rgbint:int):
41
40
  """ Convert integer to RGB """
42
41
 
@@ -731,6 +730,20 @@ class cloud_vertices(Element_To_Draw):
731
730
  curval = curline.split(sep)
732
731
  nbcols = len(curval)
733
732
 
733
+ if not header:
734
+ try:
735
+ x = float(curval[0])
736
+ y = float(curval[1])
737
+ z = 0.
738
+ if nbcols > 2:
739
+ z = float(curval[2])
740
+ except ValueError as e:
741
+ logging.error(_('Error converting first row to float as "header" is set to False.'))
742
+ logging.error(_('Check your input file : ')+fname)
743
+ logging.info(_('Using the first row as header.'))
744
+ header = True
745
+ headers = curhead.split(sep)
746
+
734
747
  if nbcols < 2:
735
748
  logging.warning(_('Not enough values on one line -- Retry !!'))
736
749
  return
@@ -1799,7 +1799,7 @@ class vector:
1799
1799
 
1800
1800
  myls = self.asshapely_ls()
1801
1801
 
1802
- mypar = myls.parallel_offset(distance=abs(distance),side=side,join_style=JOIN_STYLE.round)
1802
+ mypar = myls.parallel_offset(distance=abs(distance), side=side, join_style=JOIN_STYLE.round)
1803
1803
 
1804
1804
  if mypar.geom_type=='MultiLineString':
1805
1805
  return None
@@ -1810,7 +1810,7 @@ class vector:
1810
1810
  # #On souhaite garder une même orientation pour les vecteurs
1811
1811
  # mypar = substring(mypar, 1., 0., normalized=True)
1812
1812
 
1813
- newvec = vector(name='par'+str(distance), parentzone=self.parentzone)
1813
+ newvec = vector(name='par' + str(distance) +'_'+ self.myname, parentzone= self.parentzone)
1814
1814
 
1815
1815
  for x,y in mypar.coords:
1816
1816
  xy = Point(x,y)
@@ -4133,8 +4133,8 @@ class zone:
4133
4133
  if mypl is None or mypr is None:
4134
4134
  return
4135
4135
 
4136
- self.add_vector(mypl,0)
4137
- self.add_vector(mypr,2)
4136
+ self.add_vector(mypl, 0)
4137
+ self.add_vector(mypr, 2)
4138
4138
 
4139
4139
  def create_multibin(self, nb:int = None, nb2:int = 0) -> Triangulation:
4140
4140
  """
@@ -7468,6 +7468,15 @@ class Zones(wx.Frame, Element_To_Draw):
7468
7468
  if self.verify_activevec():
7469
7469
  return
7470
7470
 
7471
+ if self.active_zone.nbvectors > 1:
7472
+ dlg = wx.MessageDialog(None, _('You already have more than one vector in the active zone. This action will conserve only the active vector.\nDo you want to continue?'), _('Warning'), style=wx.YES_NO | wx.ICON_WARNING)
7473
+ ret = dlg.ShowModal()
7474
+ if ret == wx.ID_NO:
7475
+ dlg.Destroy()
7476
+ return
7477
+ logging.warning(_('You already have more than one vector in the active zone. This action will conserve only the active vector and you want it.'))
7478
+ dlg.Destroy()
7479
+
7471
7480
  self.mapviewer.start_action('dynamic parallel', _('Dynamic parallel'))
7472
7481
 
7473
7482
  firstvert=wolfvertex(0.,0.)
wolfhece/Results2DGPU.py CHANGED
@@ -14,7 +14,7 @@ from os import path
14
14
  from pathlib import Path
15
15
  from scipy.sparse import csr_array
16
16
  from multiprocessing import Pool
17
- from typing import Union
17
+ from typing import Union, Literal
18
18
  from tqdm import tqdm
19
19
  import logging
20
20
 
@@ -26,41 +26,38 @@ from .CpGrid import CpGrid
26
26
  from .PyPalette import wolfpalette
27
27
 
28
28
  try:
29
- from wolfgpu.results_store import ResultsStore, ResultType
29
+ from wolfgpu.results_store import ResultsStore, ResultType, PerformancePolicy
30
30
  except ImportError:
31
31
  logging.debug(_("Unable to import wolfgpu.results_store.ResultsStore. Please install wolfgpu package or add a symlink to the wolfgpu package in the wolfhece directory"))
32
32
 
33
- def _load_res(x) -> tuple[csr_array, csr_array, csr_array]:
33
+ def _load_res(x) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
34
34
  store:ResultsStore
35
35
  i:int
36
36
 
37
- store, i = x
38
- _, _, _, _, wd_np, qx_np, qy_np = store.get_result(i+1)
37
+ store, i, mode = x
39
38
 
40
- if isinstance(wd_np, csr_array) and isinstance(qx_np, csr_array) and isinstance(qy_np, csr_array):
41
- return wd_np, qx_np, qy_np
42
- else:
43
- return csr_array(wd_np), csr_array(qx_np), csr_array(qy_np)
39
+ _, _, _, _, wd_np, qx_np, qy_np = store.get_result(i+1, untile= mode == 'UNTILED')
40
+ return wd_np, qx_np, qy_np
44
41
 
45
- def _load_res_h(x) -> tuple[csr_array, csr_array, csr_array]:
42
+
43
+ def _load_res_h(x) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
46
44
  store:ResultsStore
47
45
  i:int
48
46
 
49
- store, i = x
50
- wd_np = store.get_named_result('h',i+1)
47
+ store, i, mode = x
51
48
 
52
- if isinstance(wd_np, csr_array):
53
- return wd_np
54
- else:
55
- return csr_array(wd_np)
49
+ wd_np = store.get_named_result('h', i+1, untile= mode == 'UNTILED')
50
+ return wd_np
56
51
 
57
52
  class Cache_Results2DGPU():
58
53
  """
59
54
  Gestion en mémoire de plusieurs résultats GPU
60
- Stockage CSR afin d'économiser la mémoire (Scipy CSR)
55
+ Stockage CSR afin d'économiser la mémoire (Scipy CSR) ou Numpy array dense
61
56
  """
62
57
 
63
- def __init__(self, fname:str, start_idx:int, end_idx:int = -1, only_h=False) -> None:
58
+ def __init__(self, fname:str, start_idx:int, end_idx:int = -1,
59
+ only_h=False, every:int= 1,
60
+ mode:Literal['TILED', 'UNTILED'] = 'TILED', memory_max_size:int = 12 * 1024 * 1024 * 1024) -> None:
64
61
  """
65
62
  Chargement de résultats sur base du répertoire de sauvegarde de la simulation GPU
66
63
 
@@ -72,74 +69,198 @@ class Cache_Results2DGPU():
72
69
  :param start_idx: index de départ (0-based)
73
70
  :param end_idx: index de fin (0-based)
74
71
  :param only_h: lecture de la hauteur d'eau seulement
72
+ :param every: lecture de chaque ième résultat (1 = tous les résultats, 2 = un sur deux, etc.)
73
+ :param mode: 'TILED' pour les résultats en tuiles, 'UNTILED' pour les résultats non-tuilés
74
+ :param memory_max_size: taille mémoire maximale en octets pour le cache (par défaut 12 Go)
75
+
75
76
  """
76
77
 
77
- self._results:Union[dict[str,tuple[csr_array, csr_array, csr_array]], dict[str,csr_array]] # typage
78
+ self._mode = mode
79
+ self._results:Union[dict[str,tuple[np.ndarray, np.ndarray, np.ndarray]], dict[str,np.ndarray]] # typage
78
80
 
79
81
  # ResultsStore unique
80
82
  self._result_store = ResultsStore(Path(fname), mode='r')
81
83
  self._only_h = only_h
84
+ self.memory_max_size = memory_max_size
85
+
86
+ mem_one_res = self._estimate_memory_size_one_result()
87
+ logging.info(_("Estimated memory size for one result: {:.2f} MB").format(mem_one_res))
88
+ self._maximum_n_results = int(self.memory_max_size // mem_one_res) if self.memory_max_size is not None else 10_000
82
89
 
83
90
  if end_idx == -1:
84
91
  end_idx = self._result_store.nb_results
85
92
 
86
93
  if end_idx>start_idx:
94
+
87
95
  self.start_idx = int(max(start_idx,0))
88
96
  self.end_idx = int(min(end_idx, self._result_store.nb_results))
97
+ self._every = int(max(every, 1))
98
+
99
+ if (self.end_idx - self.start_idx) // self._every > self._maximum_n_results:
100
+ logging.warning(_("Too many results to cache in memory. "
101
+ "Only the first {} results will be cached.").format(self._maximum_n_results))
102
+ self.end_idx = int(min(int(self.start_idx + self._maximum_n_results * self._every), self._result_store.nb_results))
103
+
104
+ self._range_to_process = list(range(self.start_idx, self.end_idx, self._every))
105
+ if self.end_idx-1 not in self._range_to_process:
106
+ self._range_to_process.append(self.end_idx-1)
89
107
 
90
108
  # Lecture en multiprocess des résultats
91
109
  if only_h:
92
110
  with Pool() as pool:
93
- _results = pool.map(_load_res_h, [(self._result_store,i) for i in range(self.start_idx, self.end_idx)])
111
+ _results = pool.map(_load_res_h, [(self._result_store, i, mode) for i in self._range_to_process])
94
112
  self._results = {i+1:res for i,res in enumerate(_results)}
95
113
  else:
96
114
  with Pool() as pool:
97
- _results = pool.map(_load_res, [(self._result_store,i) for i in range(self.start_idx, self.end_idx)])
115
+ _results = pool.map(_load_res, [(self._result_store, i, mode) for i in self._range_to_process])
98
116
  self._results = {i+1:res for i,res in enumerate(_results)}
99
117
 
118
+ def _estimate_memory_size_one_result(self):
119
+ """ Read one result to estimate memory size """
120
+ res = self._result_store.get_result(1, untile=False)
121
+ if self._only_h:
122
+ return res[4].nbytes / 1024 / 1024
123
+ else:
124
+ return (res[4].nbytes + res[5].nbytes + res[6].nbytes) / 1024 / 1024
125
+
126
+ @property
127
+ def memory_size(self) -> int:
128
+ """
129
+ Estimation de la taille mémoire des résultats en cache
130
+
131
+ :return: taille mémoire en Mega-octets
132
+ """
133
+ if self._only_h:
134
+ return sum(res.nbytes for res in self._results.values()) / 1024 / 1024 # Convert to MB
135
+ else:
136
+ return sum(res[0].nbytes + res[1].nbytes + res[2].nbytes for res in self._results.values()) / 1024 / 1024 # Convert to MB
137
+
100
138
  @property
101
139
  def only_h(self):
102
140
  return self._only_h
103
141
 
104
- def __getitem__(self,i:int):
142
+ @property
143
+ def _tile_packer(self):
144
+ """
145
+ Retourne le tile packer de la simulation
146
+ """
147
+ if self._result_store is not None:
148
+ return self._result_store.tile_packer()
149
+ else:
150
+ return None
151
+
152
+ def __getitem__(self, i:int):
105
153
  """Surcharge de l'opérateur []"""
106
154
  return self._results[i]
107
155
 
156
+ @property
157
+ def list_cached(self) -> list[int]:
158
+ """
159
+ Retourne la liste des indices des résultats en cache
160
+
161
+ :return: liste des indices (1-based)
162
+ """
163
+ return list(set(self._results.keys()))
164
+
165
+ def check_if_cached(self, idx:int) -> bool:
166
+ """
167
+ Vérifie si le résultat idx est dans le cache
168
+
169
+ :param idx: index du résultat (1-based)
170
+ :return: True si le résultat est dans le cache, False sinon
171
+ """
172
+
173
+ if idx not in self._results:
174
+ logging.info(_("Index {} not in cache").format(idx))
175
+ logging.info(_('We cache it now !'))
176
+
177
+ if self.only_h:
178
+ self._results[idx] = _load_res_h((self._result_store, idx-1, self._mode))
179
+ else:
180
+ self._results[idx] = _load_res((self._result_store, idx-1, self._mode))
181
+
182
+ return True
183
+
108
184
  def get_h(self, idx:int, dense:bool=True) -> Union[np.ndarray, csr_array]:
109
185
  """
110
186
  Retourne la matrice de hauteur d'eau de la position idx (0-based)
111
187
  - en CSR (Scipy CSR)
112
188
  - en dense (Numpy array)
189
+
190
+ :param idx: index du résultat (1-based)
191
+ :param dense: si True, retourne un Numpy array dense, sinon retourne un Scipy CSR array
113
192
  """
114
- if not self.only_h:
115
- return self._results[idx][0].toarray() if dense else self._results[idx][0]
193
+
194
+ self.check_if_cached(idx)
195
+
196
+ if self.only_h:
197
+ if self._tile_packer is None:
198
+ untiled = self._results[idx]
199
+ else:
200
+ untiled = self._tile_packer.unpack_array(self._results[idx])
201
+ if dense:
202
+ return untiled
203
+ else:
204
+ return csr_array(untiled)
116
205
  else:
117
- return self._results[idx].toarray() if dense else self._results[idx]
206
+ if self._tile_packer is None:
207
+ untiled = self._results[idx][0]
208
+ else:
209
+ untiled = self._tile_packer.unpack_array(self._results[idx][0])
210
+ if dense:
211
+ return untiled
212
+ else:
213
+ return csr_array(untiled)
118
214
 
119
215
  def get_qx(self,idx:int, dense:bool=True) -> Union[np.ndarray, csr_array]:
120
216
  """
121
217
  Retourne la matrice de débit X d'eau de la position idx (0-based)
122
218
  - en CSR (Scipy CSR)
123
219
  - en dense (Numpy array)
220
+
221
+ :param idx: index du résultat (1-based)
222
+ :param dense: si True, retourne un Numpy array dense, sinon retourne un Scipy CSR array
124
223
  """
125
224
 
126
- if not self.only_h:
127
- return self._results[idx][1].toarray() if dense else self._results[idx][1]
128
- else:
225
+ if self.only_h:
129
226
  return None
227
+ else:
228
+ self.check_if_cached(idx)
229
+
230
+ if self._tile_packer is None:
231
+ untiled = self._results[idx][1]
232
+ else:
233
+ untiled = self._tile_packer.unpack_array(self._results[idx][1])
234
+
235
+ if dense:
236
+ return untiled
237
+ else:
238
+ return csr_array(untiled)
130
239
 
131
240
  def get_qy(self,idx:int, dense:bool=True) -> Union[np.ndarray, csr_array]:
132
241
  """
133
242
  Retourne la matrice de débit Y d'eau de la position idx (0-based)
134
243
  - en CSR (Scipy CSR)
135
244
  - en dense (Numpy array)
245
+
246
+ :param idx: index du résultat (1-based)
247
+ :param dense: si True, retourne un Numpy array dense, sinon retourne un Scipy CSR array
136
248
  """
137
249
 
138
- if not self.only_h:
139
- return self._results[idx][2].toarray() if dense else self._results[idx][2]
140
- else:
250
+ if self.only_h:
141
251
  return None
252
+ else:
253
+ self.check_if_cached(idx)
142
254
 
255
+ if self._tile_packer is None:
256
+ untiled = self._results[idx][2]
257
+ else:
258
+ untiled = self._tile_packer.unpack_array(self._results[idx][2])
259
+
260
+ if dense:
261
+ return untiled
262
+ else:
263
+ return csr_array(untiled)
143
264
 
144
265
  class wolfres2DGPU(Wolfresults_2D):
145
266
  """
@@ -427,7 +548,7 @@ class wolfres2DGPU(Wolfresults_2D):
427
548
 
428
549
  # stored result files are 1-based -> which+1
429
550
  if self._cache is not None:
430
- if (which >= self._cache.start_idx and which < self._cache.end_idx) and (not self._cache.only_h):
551
+ if not self._cache.only_h:
431
552
  wd_np = self._cache.get_h(which+1, True)
432
553
  qx_np = self._cache.get_qx(which+1, True)
433
554
  qy_np = self._cache.get_qy(which+1, True)
@@ -472,9 +593,9 @@ class wolfres2DGPU(Wolfresults_2D):
472
593
  curblock.qx.array.mask[ij] = False
473
594
  curblock.qy.array.mask[ij] = False
474
595
 
475
- curblock.waterdepth.count()
476
- curblock.qx.count()
477
- curblock.qy.count()
596
+ curblock.waterdepth.nbnotnull = len(ij[0])
597
+ curblock.qx.nbnotnull = curblock.waterdepth.nbnotnull
598
+ curblock.qy.nbnotnull = curblock.waterdepth.nbnotnull
478
599
 
479
600
  # curblock.waterdepth.set_nullvalue_in_mask()
480
601
  # curblock.qx.set_nullvalue_in_mask()
@@ -497,10 +618,7 @@ class wolfres2DGPU(Wolfresults_2D):
497
618
 
498
619
  # stored result files are 1-based -> which+1
499
620
  if self._cache is not None:
500
- if (which >= self._cache.start_idx and which < self._cache.end_idx):
501
- wd_np = self._cache.get_h(which+1, True)
502
- else:
503
- _, _, _, _, wd_np, qx_np, qy_np = self._result_store.get_result(which+1)
621
+ wd_np = self._cache.get_h(which+1, True)
504
622
  else:
505
623
  __, __, __, __, wd_np, qx_np, qy_np = self._result_store.get_result(which+1)
506
624