wolfhece 2.2.20__py3-none-any.whl → 2.2.24__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.
Files changed (62) hide show
  1. wolfhece/Coordinates_operations.py +3 -1
  2. wolfhece/PyDraw.py +247 -3
  3. wolfhece/Results2DGPU.py +157 -39
  4. wolfhece/__init__.py +1 -0
  5. wolfhece/_add_path.py +9 -0
  6. wolfhece/apps/check_install.py +134 -1
  7. wolfhece/apps/splashscreen.py +1 -1
  8. wolfhece/apps/version.py +1 -1
  9. wolfhece/cli.py +96 -1
  10. wolfhece/hydrology/Optimisation.py +30 -25
  11. wolfhece/irm_qdf.py +67 -1
  12. wolfhece/mesh2d/wolf2dprev.py +4 -2
  13. wolfhece/report/pdf.py +55 -0
  14. wolfhece/report/simplesimgpu.py +1409 -0
  15. wolfhece/tools2d_dll.py +7 -2
  16. wolfhece/wolf_array.py +51 -5
  17. wolfhece/wolf_hist.py +21 -16
  18. wolfhece/wolfresults_2D.py +124 -25
  19. {wolfhece-2.2.20.dist-info → wolfhece-2.2.24.dist-info}/METADATA +3 -1
  20. {wolfhece-2.2.20.dist-info → wolfhece-2.2.24.dist-info}/RECORD +23 -60
  21. {wolfhece-2.2.20.dist-info → wolfhece-2.2.24.dist-info}/entry_points.txt +3 -0
  22. wolfhece/libs/GL/gl.h +0 -1044
  23. wolfhece/libs/GL/glaux.h +0 -272
  24. wolfhece/libs/GL/glcorearb.h +0 -3597
  25. wolfhece/libs/GL/glext.h +0 -11771
  26. wolfhece/libs/GL/glu.h +0 -255
  27. wolfhece/libs/GL/glxext.h +0 -926
  28. wolfhece/libs/GL/wglext.h +0 -840
  29. wolfhece/libs/MSVCP140.dll +0 -0
  30. wolfhece/libs/WolfDll.dll +0 -0
  31. wolfhece/libs/Wolf_tools.dll +0 -0
  32. wolfhece/libs/api-ms-win-crt-heap-l1-1-0.dll +0 -0
  33. wolfhece/libs/api-ms-win-crt-math-l1-1-0.dll +0 -0
  34. wolfhece/libs/api-ms-win-crt-runtime-l1-1-0.dll +0 -0
  35. wolfhece/libs/fribidi-0.dll +0 -0
  36. wolfhece/libs/get_infos.cp310-win_amd64.pyd +0 -0
  37. wolfhece/libs/get_infos.cp311-win_amd64.pyd +0 -0
  38. wolfhece/libs/get_infos.cp312-win_amd64.pyd +0 -0
  39. wolfhece/libs/get_infos.cp313-win_amd64.pyd +0 -0
  40. wolfhece/libs/glu32.dll +0 -0
  41. wolfhece/libs/hdf5.dll +0 -0
  42. wolfhece/libs/hdf5_hl.dll +0 -0
  43. wolfhece/libs/libcurl.dll +0 -0
  44. wolfhece/libs/libpardiso600-WIN-X86-64.dll +0 -0
  45. wolfhece/libs/libraqm.dll +0 -0
  46. wolfhece/libs/msvcr100.dll +0 -0
  47. wolfhece/libs/netcdf.dll +0 -0
  48. wolfhece/libs/paho-mqtt3cs.dll +0 -0
  49. wolfhece/libs/vcomp100.dll +0 -0
  50. wolfhece/libs/vcruntime140.dll +0 -0
  51. wolfhece/libs/vcruntime140_1.dll +0 -0
  52. wolfhece/libs/verify_wolf.cp310-win_amd64.pyd +0 -0
  53. wolfhece/libs/verify_wolf.cp311-win_amd64.pyd +0 -0
  54. wolfhece/libs/verify_wolf.cp312-win_amd64.pyd +0 -0
  55. wolfhece/libs/verify_wolf.cp313-win_amd64.pyd +0 -0
  56. wolfhece/libs/wolfogl.cp310-win_amd64.pyd +0 -0
  57. wolfhece/libs/wolfogl.cp311-win_amd64.pyd +0 -0
  58. wolfhece/libs/wolfogl.cp312-win_amd64.pyd +0 -0
  59. wolfhece/libs/wolfogl.cp313-win_amd64.pyd +0 -0
  60. wolfhece/libs/zlib1.dll +0 -0
  61. {wolfhece-2.2.20.dist-info → wolfhece-2.2.24.dist-info}/WHEEL +0 -0
  62. {wolfhece-2.2.20.dist-info → wolfhece-2.2.24.dist-info}/top_level.txt +0 -0
@@ -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
@@ -2287,6 +2287,7 @@ class WolfMapViewer(wx.Frame):
2287
2287
  self.analyzeplot = wx.Menu()
2288
2288
  self.analyzeexport = wx.Menu()
2289
2289
  self.analyzeinpaint = wx.Menu()
2290
+ self.analyzesimsheet = wx.Menu()
2290
2291
 
2291
2292
  plotvect = self.analyzeplot.Append(wx.ID_ANY, _("Plot active vector..."),
2292
2293
  _("Plot the active vector and linked arrays"))
@@ -2299,6 +2300,17 @@ class WolfMapViewer(wx.Frame):
2299
2300
  self.analyzemenu.Append(wx.ID_ANY,_('Export...'), self.analyzeexport)
2300
2301
  self.analyzemenu.Append(wx.ID_ANY,_('Inpaint...'), self.analyzeinpaint)
2301
2302
 
2303
+ self.analyzemenu.AppendSeparator()
2304
+
2305
+ self.analyzemenu.Append(wx.ID_ANY,_('Report...'), self.analyzesimsheet)
2306
+
2307
+ self.analyzesimsheet.Append(wx.ID_ANY, _("Active simulation..."), _("Generate a summary PDF report for the active simulation"))
2308
+ self.analyzesimsheet.Append(wx.ID_ANY, _("All checked simulations..."), _("Generate a summary PDF report for all checked simulations"))
2309
+ self.analyzesimsheet.Append(wx.ID_ANY, _("All simulations in directory..."), _("Generate a summary PDF report for all simulations in the current directory"))
2310
+ self.analyzesimsheet.AppendSeparator()
2311
+ self.analyzesimsheet.Append(wx.ID_ANY, _("Compare checked simulations..."), _("Generate a summary PDF report for all the loaded simulations"))
2312
+ self.analyzesimsheet.Append(wx.ID_ANY, _("Compare all simulations in a directory..."), _("Generate a summary PDF report for all the simulations in a directory"))
2313
+
2302
2314
 
2303
2315
  self.analyzeinpaint.Append(wx.ID_ANY, _("Inpaint active array..."), _("Inpaint active array"))
2304
2316
  self.analyzeinpaint.Append(wx.ID_ANY, _("Inpaint waterlevel..."), _("Inpaint a waterlevel result array based on sepcified dem and dtm data"))
@@ -4902,7 +4914,8 @@ class WolfMapViewer(wx.Frame):
4902
4914
  dpi:int= 300,
4903
4915
  add_title:bool = False,
4904
4916
  figsizes= [10.,10.],
4905
- arrayid_as_title:bool = False):
4917
+ arrayid_as_title:bool = False,
4918
+ resid_as_title:bool = False):
4906
4919
  """
4907
4920
  Sauvegarde de la fenêtre d'affichage dans un fichier
4908
4921
 
@@ -4958,6 +4971,8 @@ class WolfMapViewer(wx.Frame):
4958
4971
  pot_title = self.viewer_name
4959
4972
  if arrayid_as_title:
4960
4973
  pot_title = self.active_array.idx
4974
+ if resid_as_title:
4975
+ pot_title = self.active_res2d.idx
4961
4976
 
4962
4977
  self.display_canvasogl(fig=fig,
4963
4978
  ax=ax,
@@ -8301,6 +8316,121 @@ class WolfMapViewer(wx.Frame):
8301
8316
  elif itemlabel == _("Load and apply mask (nap)..."):
8302
8317
  self.loadnap_and_apply()
8303
8318
 
8319
+ elif itemlabel == _("Active simulation..."):
8320
+ if self.active_res2d is None:
8321
+ logging.warning(_('No active simulation !'))
8322
+ return
8323
+
8324
+ from .report.simplesimgpu import SimpleSimGPU_Report_wx
8325
+
8326
+ if isinstance(self.active_res2d, wolfres2DGPU):
8327
+ newsheet = SimpleSimGPU_Report_wx(Path(self.active_res2d.filename).parent, size=(800, 600))
8328
+ newsheet.Show()
8329
+ else:
8330
+ logging.warning(_('Active simulation is not a GPU simulation - Not yet implemented for CPU simulations !'))
8331
+
8332
+ elif itemlabel == _("All checked simulations..."):
8333
+
8334
+ sims = self.get_list_keys(draw_type.RES2D, checked_state=True)
8335
+ if len(sims) == 0:
8336
+ logging.warning(_('No checked simulation !'))
8337
+ return
8338
+
8339
+ from .report.simplesimgpu import SimpleSimGPU_Report_wx
8340
+
8341
+ for curkey in sims:
8342
+ curmodel = self.get_obj_from_id(curkey, draw_type.RES2D)
8343
+ if isinstance(curmodel, wolfres2DGPU):
8344
+ newsheet = SimpleSimGPU_Report_wx(Path(curmodel.filename).parent, size=(800, 600))
8345
+ newsheet.Show()
8346
+ else:
8347
+ logging.warning(_('Simulation {} is not a GPU simulation - Not yet implemented for CPU simulations !').format(curmodel.idx))
8348
+
8349
+ elif itemlabel == _("All simulations in directory..."):
8350
+ dlg = wx.DirDialog(None, _('Choose the directory containing the simulations'), style=wx.DD_DEFAULT_STYLE)
8351
+ ret = dlg.ShowModal()
8352
+ if ret == wx.ID_CANCEL:
8353
+ dlg.Destroy()
8354
+ return
8355
+ directory = Path(dlg.GetPath())
8356
+ dlg.Destroy()
8357
+ if not directory.exists():
8358
+ logging.error(_('Directory {} does not exist !').format(directory))
8359
+ wx.MessageBox(_('Directory {} does not exist !').format(directory), _('Error'), wx.OK | wx.ICON_ERROR)
8360
+ return
8361
+ if not directory.is_dir():
8362
+ logging.error(_('Path {} is not a directory !').format(directory))
8363
+ wx.MessageBox(_('Path {} is not a directory !').format(directory), _('Error'), wx.OK | wx.ICON_ERROR)
8364
+ return
8365
+ from .report.simplesimgpu import SimpleSimGPU_Reports_wx
8366
+
8367
+
8368
+ # check if we want to show all wx reports
8369
+ dlg = wx.MessageDialog(None, _('Do you want to show all reports ?'), _('Show all reports'), style=wx.YES_NO | wx.YES_DEFAULT)
8370
+ ret = dlg.ShowModal()
8371
+ dlg.Destroy()
8372
+
8373
+ newsheets = SimpleSimGPU_Reports_wx(directory, show = ret == wx.ID_YES, size=(800, 600))
8374
+
8375
+ elif itemlabel == _("Compare checked simulations..."):
8376
+
8377
+ sims = self.get_list_keys(draw_type.RES2D, checked_state=True)
8378
+ if len(sims) == 0:
8379
+ logging.warning(_('No checked simulation !'))
8380
+ return
8381
+
8382
+ elif len(sims) == 1:
8383
+ logging.warning(_('Only one checked simulation - Nothing to compare !'))
8384
+ return
8385
+
8386
+ from .report.simplesimgpu import SimpleSimGPU_Report_Compare_wx
8387
+
8388
+ sims = [self.get_obj_from_id(curkey, draw_type.RES2D) for curkey in sims]
8389
+ # conserve only GPU simulations
8390
+ sims = [Path(curmodel.filename) for curmodel in sims if isinstance(curmodel, wolfres2DGPU)]
8391
+
8392
+ # take parent if "simul_gpu_results" in sims
8393
+ sims = [sim.parent for sim in sims if 'simul_gpu_results' in str(sim)]
8394
+
8395
+ if len(sims) == 0:
8396
+ logging.warning(_('No GPU simulation to compare !'))
8397
+ return
8398
+ elif len(sims) == 1:
8399
+ logging.warning(_('Only one GPU simulation - Nothing to compare !'))
8400
+ return
8401
+ elif len(sims) > 1:
8402
+ try:
8403
+ newsheet = SimpleSimGPU_Report_Compare_wx(sims, size=(800, 600))
8404
+ newsheet.Show()
8405
+ except Exception as e:
8406
+ logging.error(_('Error in comparing simulations\n{}'.format(e)))
8407
+
8408
+ elif itemlabel == _("Compare all simulations in a directory..."):
8409
+
8410
+ dlg = wx.DirDialog(None, _('Choose the directory containing the simulations'), style=wx.DD_DEFAULT_STYLE)
8411
+ ret = dlg.ShowModal()
8412
+ if ret == wx.ID_CANCEL:
8413
+ dlg.Destroy()
8414
+ return
8415
+
8416
+ directory = Path(dlg.GetPath())
8417
+ dlg.Destroy()
8418
+
8419
+ if not directory.exists():
8420
+ logging.error(_('Directory {} does not exist !').format(directory))
8421
+ wx.MessageBox(_('Directory {} does not exist !').format(directory), _('Error'), wx.OK | wx.ICON_ERROR)
8422
+ return
8423
+ if not directory.is_dir():
8424
+ logging.error(_('Path {} is not a directory !').format(directory))
8425
+ wx.MessageBox(_('Path {} is not a directory !').format(directory), _('Error'), wx.OK | wx.ICON_ERROR)
8426
+ return
8427
+ from .report.simplesimgpu import SimpleSimGPU_Report_Compare_wx
8428
+ try:
8429
+ newsheet = SimpleSimGPU_Report_Compare_wx(directory, size= (800,600))
8430
+ newsheet.Show()
8431
+ except Exception as e:
8432
+ logging.error(_('Error in comparing simulations in directory\n{}'.format(e)))
8433
+
8304
8434
  elif itemlabel == _("Inpaint active array..."):
8305
8435
 
8306
8436
  if self.active_array is None:
@@ -9792,16 +9922,21 @@ class WolfMapViewer(wx.Frame):
9792
9922
 
9793
9923
  # Get all checked arrays
9794
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
+
9795
9927
  old_active = self.active_array
9928
+ old_res2d = self.active_res2d
9796
9929
 
9797
- if len(checked_arrays) == 0:
9930
+ if len(checked_arrays) + len(checked_results) == 0:
9798
9931
  logging.warning(_('No arrays checked for export'))
9799
- return
9932
+ return []
9800
9933
 
9801
9934
  def uncheck_all():
9802
9935
  # uncheck arrays
9803
9936
  for curarray in checked_arrays:
9804
9937
  self.uncheck_id(curarray, unload= False, forceresetOGL= False)
9938
+ for curres in checked_results:
9939
+ self.uncheck_id(curres, unload= False, forceresetOGL= False)
9805
9940
 
9806
9941
  fn = str(fn)
9807
9942
  ret = []
@@ -9811,10 +9946,21 @@ class WolfMapViewer(wx.Frame):
9811
9946
  self.active_array = self.get_obj_from_id(curel, drawtype= draw_type.ARRAYS)
9812
9947
  ret.append((self.save_canvasogl(fn + '_' + str(idx) + '.png', mpl, ds, add_title= add_title, arrayid_as_title=True), curel))
9813
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
+
9814
9955
  self.active_array = old_active
9956
+ self.active_res2d = old_res2d
9957
+
9815
9958
  for curarray in checked_arrays:
9816
9959
  self.check_id(curarray)
9817
9960
 
9961
+ for curres in checked_results:
9962
+ self.check_id(curres)
9963
+
9818
9964
  self.Refresh()
9819
9965
 
9820
9966
  return ret
@@ -11630,6 +11776,97 @@ class WolfMapViewer(wx.Frame):
11630
11776
  else:
11631
11777
  logging.warning(_('Reload not yet implemented for this type of object'))
11632
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
+
11633
11870
  def OnClose(self, event):
11634
11871
  """ Close the application """
11635
11872
 
@@ -14419,6 +14656,9 @@ class WolfMapViewer(wx.Frame):
14419
14656
  tracks.append(_('Load flight'))
14420
14657
  tracks.append(_('Save flight'))
14421
14658
 
14659
+ tracks.append(_('Rasterize active zone'))
14660
+ tracks.append(_('Rasterize active vector'))
14661
+
14422
14662
  # Récupération des items du menu contextuel
14423
14663
  menuitems = self.popupmenu.GetMenuItems()
14424
14664
  text = [cur.GetItemLabelText() for cur in menuitems]
@@ -14456,6 +14696,10 @@ class WolfMapViewer(wx.Frame):
14456
14696
  self.popupmenu.Append(wx.ID_ANY, _('Convert to multi-blocks (result)'), _('Convert to multi-blocks'))
14457
14697
  self.popupmenu.Append(wx.ID_ANY, _('Extract current step as IC (result)'), _('Extract current step as IC'))
14458
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
+
14459
14703
  if isinstance(self.selected_object, Zones | Bridge | Weir):
14460
14704
  self.popupmenu.Append(wx.ID_ANY, _('Export to Shape file'), _('Export to Shape file'))
14461
14705
  self.popupmenu.Append(wx.ID_ANY, _('Export active zone to Shape file'), _('Export active zone to Shape file'))
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
 
wolfhece/__init__.py CHANGED
@@ -1,4 +1,5 @@
1
1
  from . import _add_path
2
+ from .libs import *
2
3
  from .PyTranslate import _
3
4
 
4
5
  try: