wolfhece 2.2.28__py3-none-any.whl → 2.2.29__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/PyConfig.py +27 -3
- wolfhece/PyDraw.py +192 -20
- wolfhece/PyVertexvectors.py +155 -21
- wolfhece/PyWMS.py +6 -3
- wolfhece/__init__.py +27 -0
- wolfhece/acceptability/acceptability.py +25 -20
- wolfhece/acceptability/acceptability_gui.py +150 -92
- wolfhece/acceptability/func.py +169 -82
- wolfhece/apps/version.py +1 -1
- wolfhece/irm_qdf.py +71 -7
- wolfhece/lb7208_ntv2/__init__.py +0 -0
- wolfhece/lb7208_ntv2/be_ign_README.txt +36 -0
- wolfhece/lb7208_ntv2/be_ign_bd72lb72_etrs89lb08.tif +0 -0
- wolfhece/lb7208_ntv2/be_ign_hBG18.tif +0 -0
- wolfhece/mesh2d/gpu_2d.py +11 -2
- wolfhece/report/compare_arrays.py +268 -58
- wolfhece/report/simplesimgpu.py +25 -6
- wolfhece/scenario/config_manager.py +243 -7
- wolfhece/ui/wolf_multiselection_collapsiblepane.py +153 -1
- wolfhece/wolf_array.py +67 -62
- wolfhece/wolf_texture.py +4 -0
- {wolfhece-2.2.28.dist-info → wolfhece-2.2.29.dist-info}/METADATA +1 -1
- {wolfhece-2.2.28.dist-info → wolfhece-2.2.29.dist-info}/RECORD +26 -22
- {wolfhece-2.2.28.dist-info → wolfhece-2.2.29.dist-info}/WHEEL +0 -0
- {wolfhece-2.2.28.dist-info → wolfhece-2.2.29.dist-info}/entry_points.txt +0 -0
- {wolfhece-2.2.28.dist-info → wolfhece-2.2.29.dist-info}/top_level.txt +0 -0
wolfhece/report/simplesimgpu.py
CHANGED
@@ -11,6 +11,7 @@ from tempfile import NamedTemporaryFile
|
|
11
11
|
from datetime import datetime as dt
|
12
12
|
|
13
13
|
import matplotlib.pyplot as plt
|
14
|
+
import matplotlib as mpl
|
14
15
|
import seaborn as sns
|
15
16
|
|
16
17
|
import pymupdf as pdf
|
@@ -30,6 +31,7 @@ class SimpleSimGPU_Report():
|
|
30
31
|
def __init__(self, sim:SimpleSimulation | Path | str, **kwargs):
|
31
32
|
""" Initialize the Simple Simulation GPU Report Viewer """
|
32
33
|
|
34
|
+
self._summary = {}
|
33
35
|
self._doc = None
|
34
36
|
|
35
37
|
if isinstance(sim, Path):
|
@@ -38,6 +40,7 @@ class SimpleSimGPU_Report():
|
|
38
40
|
except Exception as e:
|
39
41
|
logging.error(f"Failed to load simulation from path {sim}: {e}")
|
40
42
|
self._sim = None
|
43
|
+
self._summary['errors'] = e
|
41
44
|
return
|
42
45
|
elif isinstance(sim, str):
|
43
46
|
try:
|
@@ -45,6 +48,7 @@ class SimpleSimGPU_Report():
|
|
45
48
|
except Exception as e:
|
46
49
|
logging.error(f"Failed to load simulation from string path {sim}: {e}")
|
47
50
|
self._sim = None
|
51
|
+
self._summary['errors'] = e
|
48
52
|
return
|
49
53
|
elif not isinstance(sim, SimpleSimulation):
|
50
54
|
try:
|
@@ -52,12 +56,12 @@ class SimpleSimGPU_Report():
|
|
52
56
|
except Exception as e:
|
53
57
|
logging.error(f"Failed to set simulation: {e}")
|
54
58
|
self._sim = None
|
59
|
+
self._summary['errors'] = e
|
55
60
|
return
|
56
61
|
else:
|
57
62
|
logging.error("Invalid type for simulation. Must be SimpleSimulation, Path, or str.")
|
58
63
|
return
|
59
64
|
|
60
|
-
self._summary = {}
|
61
65
|
self._summary['warnings'] = self._summary_warnings()
|
62
66
|
self._summary['errors'] = self._summary_errors()
|
63
67
|
|
@@ -272,9 +276,13 @@ class SimpleSimGPU_Report():
|
|
272
276
|
# Plot the histogram of waterdepth adn add it to the PDF
|
273
277
|
fig, ax = plt.subplots(figsize=(8, 6))
|
274
278
|
# Plot the histogram of water depth
|
275
|
-
|
276
|
-
|
277
|
-
|
279
|
+
|
280
|
+
h_min = np.min(sim.h[sim.nap == 1])
|
281
|
+
h_max = np.max(sim.h[sim.nap == 1])
|
282
|
+
|
283
|
+
if h_max > h_min:
|
284
|
+
ax.hist(sim.h[sim.h > 0.], bins=100, density=True)
|
285
|
+
ax.set_xlim(0, h_max) # Set xlim to 110% of max value
|
278
286
|
ax.set_xlabel('Water Depth [m]')
|
279
287
|
ax.set_ylabel('Frequency')
|
280
288
|
|
@@ -301,7 +309,7 @@ class SimpleSimGPU_Report():
|
|
301
309
|
ax.hist(sim.manning[sim.nap == 1], bins=100, density = True)
|
302
310
|
# ax.set_title('Histogram of Manning Coefficient')
|
303
311
|
ax.set_xlabel('Manning [$\\frac {s} {m^{1/3}} $]')
|
304
|
-
ax.set_xlim(0, np.max(sim.manning[sim.nap == 1]) * 1.
|
312
|
+
ax.set_xlim(0, np.max(sim.manning[sim.nap == 1]) * 1.1) # Set xlim to 110% of max value
|
305
313
|
ax.set_ylabel('Frequency')
|
306
314
|
|
307
315
|
# set font size of the labels
|
@@ -771,15 +779,21 @@ class SimpleSimGPU_Report():
|
|
771
779
|
|
772
780
|
class SimpleSimGPU_Report_wx(PDFViewer):
|
773
781
|
|
774
|
-
def __init__(self, sim:SimpleSimulation | Path | str, **kwargs):
|
782
|
+
def __init__(self, sim:SimpleSimulation | Path | str, show:bool=False, **kwargs):
|
775
783
|
""" Initialize the Simple Simulation GPU Report Viewer """
|
776
784
|
|
785
|
+
mpl.use('Agg') # Use a non-interactive backend for matplotlib
|
786
|
+
|
777
787
|
super(SimpleSimGPU_Report_wx, self).__init__(None, **kwargs)
|
778
788
|
|
779
789
|
self._report = SimpleSimGPU_Report(sim, **kwargs)
|
780
790
|
|
781
791
|
if self._report._sim is None:
|
782
792
|
logging.error("No simulation data available to create report.")
|
793
|
+
dlg = wx.MessageDialog(self, "No simulation data available to create report.\n\nPlease check the errors in the logs.",
|
794
|
+
"Error", wx.OK | wx.ICON_ERROR)
|
795
|
+
dlg.ShowModal()
|
796
|
+
dlg.Destroy()
|
783
797
|
return
|
784
798
|
|
785
799
|
self._report.create_report()
|
@@ -798,6 +812,11 @@ class SimpleSimGPU_Report_wx(PDFViewer):
|
|
798
812
|
|
799
813
|
self.Bind(wx.EVT_CLOSE, self.on_close)
|
800
814
|
|
815
|
+
if show:
|
816
|
+
self.Show()
|
817
|
+
|
818
|
+
mpl.use('WxAgg') # Reset matplotlib to use the WxAgg backend for other plots
|
819
|
+
|
801
820
|
def on_close(self, event):
|
802
821
|
""" Handle the close event of the frame """
|
803
822
|
|
@@ -110,6 +110,8 @@ class GPU_2D_file(Enum):
|
|
110
110
|
MANNING = _gpu_file('manning' , np.float32, GPU_2D_file_extensions.NPY.value)
|
111
111
|
COMPUTATION_MASK = _gpu_file('nap' , np.uint8 , GPU_2D_file_extensions.NPY.value)
|
112
112
|
INFILTRATION = _gpu_file('infiltration_zones', np.int32, GPU_2D_file_extensions.NPY.value)
|
113
|
+
ROOF = _gpu_file('bridge_roof' , np.float32, GPU_2D_file_extensions.NPY.value)
|
114
|
+
# DECK = _gpu_file('bridge_deck' , np.float32, GPU_2D_file_extensions.NPY.value)
|
113
115
|
|
114
116
|
# répertoire de sortie des simulations GPU
|
115
117
|
RESULT_DIR = 'simul_gpu_results'
|
@@ -240,6 +242,8 @@ class Config_Manager_2D_GPU:
|
|
240
242
|
self._epsilon = 0.01
|
241
243
|
self._filter_independent = True
|
242
244
|
|
245
|
+
self._active_simulation = None
|
246
|
+
|
243
247
|
self.load_data()
|
244
248
|
|
245
249
|
def find_wolfgpu(self):
|
@@ -559,15 +563,172 @@ class Config_Manager_2D_GPU:
|
|
559
563
|
|
560
564
|
logging.info(_('Hydrographs...'))
|
561
565
|
hydro = self.get_hydrographs()
|
562
|
-
|
566
|
+
if len(hydro) == 0:
|
567
|
+
logging.info(_('No hydrographs found !'))
|
568
|
+
log += _('No hydrographs found !') + '\n'
|
569
|
+
else:
|
570
|
+
try:
|
571
|
+
nb = hydro[0].data.shape[1]
|
572
|
+
|
573
|
+
logging.info(_('Number of hydrographs : {}'.format(len(hydro))))
|
574
|
+
for curhydro in hydro:
|
575
|
+
if curhydro.data.shape[1] != nb:
|
576
|
+
loclog = _('Bad number of columns for {} !'.format(curhydro[0]._filename))
|
577
|
+
log += loclog + '\n'
|
578
|
+
logging.warning(loclog)
|
579
|
+
except Exception as e:
|
580
|
+
logging.error(_('Error while checking hydrographs: {}').format(e))
|
581
|
+
log += _('Error while checking hydrographs: {}').format(e) + '\n'
|
582
|
+
|
583
|
+
return log
|
584
|
+
|
585
|
+
def check_one_simulation(self) -> str:
|
586
|
+
"""
|
587
|
+
Check consistency of one simulation
|
588
|
+
|
589
|
+
"""
|
590
|
+
|
591
|
+
if self._active_simulation is None:
|
592
|
+
logging.error(_('No active simulation !'))
|
593
|
+
return _('No active simulation !')
|
594
|
+
|
595
|
+
logging.info(_('Checking consistency of one simulation...\n'))
|
596
|
+
|
597
|
+
logging.info(_('NPY files...'))
|
598
|
+
numpyfiles = self._active_simulation[GPU_2D_file_extensions.NPY.value]
|
599
|
+
numpynames = [file.name.lower() for file in numpyfiles]
|
600
|
+
|
601
|
+
logging.info(_('Number of numpy files : {}'.format(len(numpyfiles))))
|
602
|
+
|
603
|
+
if self._header.nbx == 0 or self._header.nby == 0:
|
604
|
+
logging.error(_('No header found !'))
|
605
|
+
logging.info(_('Trying to get header from first numpy file...'))
|
606
|
+
try:
|
607
|
+
wa = WolfArray(numpyfiles[0])
|
608
|
+
self._header = wa.get_header()
|
609
|
+
except Exception as e:
|
610
|
+
logging.error(_('Error while getting header from first numpy file: {}').format(e))
|
611
|
+
return _('Error while getting header from first numpy file: {}').format(e)
|
612
|
+
|
613
|
+
log = ''
|
614
|
+
for curnpy in numpyfiles:
|
615
|
+
|
616
|
+
# test if the shape of the numpy file is the same as the tif file
|
617
|
+
# using memmap to avoid loading the whole array in memory -> faster
|
618
|
+
arr = np.lib.format.open_memmap(curnpy, mode='r')
|
563
619
|
|
564
|
-
|
565
|
-
|
566
|
-
if curhydro.data.shape[1] != nb:
|
567
|
-
loclog = _('Bad number of columns for {} !'.format(curhydro[0]._filename))
|
620
|
+
if arr.shape != (self._header.nbx, self._header.nby):
|
621
|
+
loclog = _('Bad shape for {} !'.format(curnpy))
|
568
622
|
log += loclog + '\n'
|
569
623
|
logging.warning(loclog)
|
570
624
|
|
625
|
+
del(arr)
|
626
|
+
|
627
|
+
logging.info(_('Hydrographs...'))
|
628
|
+
hydro = self.get_hydrographs()
|
629
|
+
if len(hydro) == 0:
|
630
|
+
logging.info(_('No hydrographs found !'))
|
631
|
+
log += _('No hydrographs found !') + '\n'
|
632
|
+
else:
|
633
|
+
try:
|
634
|
+
nb = hydro[0].data.shape[1]
|
635
|
+
|
636
|
+
logging.info(_('Number of hydrographs : {}'.format(len(hydro))))
|
637
|
+
for curhydro in hydro:
|
638
|
+
if curhydro.data.shape[1] != nb:
|
639
|
+
loclog = _('Bad number of columns for {} !'.format(curhydro[0]._filename))
|
640
|
+
log += loclog + '\n'
|
641
|
+
logging.warning(loclog)
|
642
|
+
except Exception as e:
|
643
|
+
logging.error(_('Error while checking hydrographs: {}').format(e))
|
644
|
+
log += _('Error while checking hydrographs: {}').format(e) + '\n'
|
645
|
+
|
646
|
+
for curfile in GPU_2D_file:
|
647
|
+
if curfile.value.extension == '.npy':
|
648
|
+
if curfile.value.name + curfile.value.extension not in numpynames:
|
649
|
+
loclog = _('Missing file {} !').format(curfile.value.name + curfile.value.extension)
|
650
|
+
log += loclog + '\n'
|
651
|
+
logging.warning(loclog)
|
652
|
+
else:
|
653
|
+
try:
|
654
|
+
wa = WolfArray(numpyfiles[numpynames.index(curfile.value.name + curfile.value.extension)])
|
655
|
+
if wa.dtype != curfile.value.type:
|
656
|
+
loclog = _('Bad dtype for {} ! Expected {}, got {}').format(
|
657
|
+
curfile.value.name + curfile.value.extension,
|
658
|
+
curfile.value.type, wa.dtype)
|
659
|
+
log += loclog + '\n'
|
660
|
+
logging.warning(loclog)
|
661
|
+
del(wa)
|
662
|
+
except Exception as e:
|
663
|
+
loclog = _('Error while checking {}: {}').format(
|
664
|
+
curfile.value.name + curfile.value.extension, e)
|
665
|
+
log += loclog + '\n'
|
666
|
+
logging.error(loclog)
|
667
|
+
|
668
|
+
if 'nap.npy' in numpynames:
|
669
|
+
nap = WolfArray(numpyfiles[numpynames.index('nap.npy')])
|
670
|
+
else:
|
671
|
+
nap = None
|
672
|
+
logging.error(_('No nap file found !'))
|
673
|
+
log += _('No nap file found !') + '\n'
|
674
|
+
|
675
|
+
if nap is not None:
|
676
|
+
if 'infiltration_zones.npy' in numpynames:
|
677
|
+
# Check if infiltration zones are consistent
|
678
|
+
infil_zones = WolfArray(numpyfiles[numpynames.index('infiltration_zones.npy')])
|
679
|
+
|
680
|
+
if np.any(infil_zones.array[nap.array == 0] != 0):
|
681
|
+
loclog = _('Infiltration zones are not consistent with the nap file !')
|
682
|
+
log += loclog + '\n'
|
683
|
+
|
684
|
+
# find all non zero infiltration zones
|
685
|
+
non_zero_infil_zones = list(set(np.unique(infil_zones.array[nap.array == 1])))
|
686
|
+
if len(non_zero_infil_zones) == 0:
|
687
|
+
loclog = _('No infiltration zones found !')
|
688
|
+
log += loclog + '\n'
|
689
|
+
else:
|
690
|
+
if non_zero_infil_zones[0] == 0:
|
691
|
+
#pop
|
692
|
+
non_zero_infil_zones.pop(0)
|
693
|
+
if len(non_zero_infil_zones) == 0:
|
694
|
+
loclog = _('No infiltration zones found !')
|
695
|
+
log += loclog + '\n'
|
696
|
+
|
697
|
+
elif non_zero_infil_zones[0] !=1:
|
698
|
+
loclog = _('Infiltration zones should start at 1 ! Found {} instead.').format(non_zero_infil_zones[0])
|
699
|
+
log += loclog + '\n'
|
700
|
+
logging.warning(loclog)
|
701
|
+
|
702
|
+
# increments
|
703
|
+
if not all([non_zero_infil_zones[i] - non_zero_infil_zones[i-1] == 1 for i in range(1, len(non_zero_infil_zones))]):
|
704
|
+
loclog = _('Infiltration zones are not consecutive !')
|
705
|
+
log += loclog + '\n'
|
706
|
+
logging.warning(loclog)
|
707
|
+
del(infil_zones)
|
708
|
+
|
709
|
+
if 'bathymetry.npy' in numpynames:
|
710
|
+
# Check if infiltration zones are consistent
|
711
|
+
bath = WolfArray(numpyfiles[numpynames.index('bathymetry.npy')])
|
712
|
+
|
713
|
+
if np.any(bath.array[nap.array == 0] != 99999.):
|
714
|
+
loclog = _("Some bathymetry's cells are different of 99999 outside the computation domain !\n")
|
715
|
+
loclog += _('This may lead to unexpected results !')
|
716
|
+
log += loclog + '\n'
|
717
|
+
|
718
|
+
del(bath)
|
719
|
+
|
720
|
+
for file in ['h.npy', 'qx.npy', 'qy.npy']:
|
721
|
+
if file in numpynames:
|
722
|
+
# Check if infiltration zones are consistent
|
723
|
+
bath = WolfArray(numpyfiles[numpynames.index(file)])
|
724
|
+
|
725
|
+
if np.any(bath.array[nap.array == 0] != 0.):
|
726
|
+
loclog = _("Some cells are different of 0.0 outside the computation domain in {}!\n").format(file)
|
727
|
+
loclog += _('This may lead to unexpected results !')
|
728
|
+
log += loclog + '\n'
|
729
|
+
|
730
|
+
del(bath)
|
731
|
+
|
571
732
|
return log
|
572
733
|
|
573
734
|
# Analyze files
|
@@ -1188,6 +1349,22 @@ class Config_Manager_2D_GPU:
|
|
1188
1349
|
else:
|
1189
1350
|
logging.error(_("No 'bathymetry.tif' file found in the root directory !"))
|
1190
1351
|
|
1352
|
+
def create_void_dtm(self):
|
1353
|
+
""" create void dtm file """
|
1354
|
+
if (self.workingdir / 'bathymetry.tif').exists():
|
1355
|
+
locheader = self.get_header()
|
1356
|
+
dtm = WolfArray(srcheader=locheader, whichtype= WOLF_ARRAY_FULL_SINGLE)
|
1357
|
+
dtm.array.data[:,:] = 99999.
|
1358
|
+
dtm.nullvalue = 99999.
|
1359
|
+
dtm.write_all(str(self.workingdir / 'dtm.tif'))
|
1360
|
+
|
1361
|
+
if (self.workingdir / 'dtm.tif').exists():
|
1362
|
+
logging.info(_('dtm.tif created and set to 99999. ! -- Please edit it !'))
|
1363
|
+
else:
|
1364
|
+
logging.error(_("dtm.tif not created ! -- Does 'bathymetry.tif' or any '.tif' file exist in the root directory ?"))
|
1365
|
+
else:
|
1366
|
+
logging.error(_("No 'bathymetry.tif' file found in the root directory !"))
|
1367
|
+
|
1191
1368
|
def create_void_roof(self):
|
1192
1369
|
""" create void roof file """
|
1193
1370
|
|
@@ -1774,10 +1951,18 @@ class UI_Manager_2D_GPU():
|
|
1774
1951
|
self._reload.Bind(wx.EVT_BUTTON,self.onupdate_structure)
|
1775
1952
|
self._reload.SetToolTip(_('reScan the directory and reload the entire structure'))
|
1776
1953
|
|
1954
|
+
tif_sizer = wx.BoxSizer(wx.HORIZONTAL)
|
1777
1955
|
self._create_void_infil = wx.Button(self._frame,label = _('Create .tif infiltration zones'))
|
1778
1956
|
self._create_void_infil.Bind(wx.EVT_BUTTON,self.oncreate_void_infil)
|
1779
1957
|
self._create_void_infil.SetToolTip(_('Create a void infiltration zones file based on bathymetry.tif'))
|
1780
1958
|
|
1959
|
+
self._create_dtm = wx.Button(self._frame,label = _('Create .tif DTM'))
|
1960
|
+
self._create_dtm.Bind(wx.EVT_BUTTON,self.oncreate_dtm)
|
1961
|
+
self._create_dtm.SetToolTip(_('Create a DTM file based on bathymetry.tif\n\n - bathymetry.tif must be present in the root directory'))
|
1962
|
+
|
1963
|
+
tif_sizer.Add(self._create_void_infil, 1, wx.EXPAND)
|
1964
|
+
tif_sizer.Add(self._create_dtm, 1, wx.EXPAND)
|
1965
|
+
|
1781
1966
|
bridge_sizer = wx.BoxSizer(wx.HORIZONTAL)
|
1782
1967
|
self._create_void_roof = wx.Button(self._frame,label = _('Create .tif bridge/culvert roof elevation'))
|
1783
1968
|
self._create_void_roof.Bind(wx.EVT_BUTTON,self.oncreate_void_roof)
|
@@ -1818,6 +2003,10 @@ class UI_Manager_2D_GPU():
|
|
1818
2003
|
self._checkconsistency.Bind(wx.EVT_BUTTON,self.oncheck_consistency)
|
1819
2004
|
self._checkconsistency.SetToolTip(_('Check consistency of the scenario\n\n - bathymetry.tif\n - manning.tif\n - infiltration.tif\n - hydrographs\n - initial conditions\n - boundary conditions\n - scripts'))
|
1820
2005
|
|
2006
|
+
self._checkonesimulation = wx.Button(self._frame,label = _('Check one simulation'))
|
2007
|
+
self._checkonesimulation.Bind(wx.EVT_BUTTON,self.oncheck_one_simulation)
|
2008
|
+
self._checkonesimulation.SetToolTip(_('Check consistency of one simulation'))
|
2009
|
+
|
1821
2010
|
self._createsim = wx.Button(self._frame,label = _('Create simulation(s)'))
|
1822
2011
|
self._createsim.Bind(wx.EVT_BUTTON,self.oncreate_simulation)
|
1823
2012
|
self._createsim.SetToolTip(_('Create simulation(s) from selected hydrographs'))
|
@@ -1861,14 +2050,19 @@ class UI_Manager_2D_GPU():
|
|
1861
2050
|
|
1862
2051
|
# buttons -> sizer
|
1863
2052
|
sizer_buttons.Add(self._reload,1,wx.EXPAND)
|
1864
|
-
sizer_buttons.Add(
|
2053
|
+
sizer_buttons.Add(tif_sizer,1,wx.EXPAND)
|
1865
2054
|
sizer_buttons.Add(bridge_sizer,1,wx.EXPAND)
|
1866
2055
|
sizer_buttons.Add(self._create_void_scripts,1,wx.EXPAND)
|
1867
2056
|
sizer_buttons.Add(self._check_prefix,1,wx.EXPAND)
|
1868
2057
|
sizer_buttons.Add(self._create_vrt,1,wx.EXPAND)
|
1869
2058
|
sizer_buttons.Add(self._translate_vrt,1,wx.EXPAND)
|
1870
2059
|
sizer_buttons.Add(self._apply_scripts,1,wx.EXPAND)
|
1871
|
-
|
2060
|
+
|
2061
|
+
_sizer_check = wx.BoxSizer(wx.HORIZONTAL)
|
2062
|
+
_sizer_check.Add(self._checkconsistency, 1, wx.EXPAND)
|
2063
|
+
_sizer_check.Add(self._checkonesimulation, 1, wx.EXPAND)
|
2064
|
+
|
2065
|
+
sizer_buttons.Add(_sizer_check,1,wx.EXPAND)
|
1872
2066
|
sizer_buttons.Add(self._create_vec,1,wx.EXPAND)
|
1873
2067
|
sizer_buttons.Add(self.listsims,1,wx.EXPAND)
|
1874
2068
|
sizer_buttons.Add(self._createsim,1,wx.EXPAND)
|
@@ -1931,6 +2125,12 @@ class UI_Manager_2D_GPU():
|
|
1931
2125
|
self._parent.create_void_infil()
|
1932
2126
|
self.reload()
|
1933
2127
|
|
2128
|
+
def oncreate_dtm(self, e:wx.MouseEvent):
|
2129
|
+
""" Création d'un fichier DTM vide """
|
2130
|
+
|
2131
|
+
self._parent.create_void_dtm()
|
2132
|
+
self.reload()
|
2133
|
+
|
1934
2134
|
def oncreate_void_roof(self, e:wx.MouseEvent):
|
1935
2135
|
""" Création d'un fichier de toit de pont vide """
|
1936
2136
|
|
@@ -2122,6 +2322,40 @@ class UI_Manager_2D_GPU():
|
|
2122
2322
|
else:
|
2123
2323
|
self._txtctrl.WriteText(log)
|
2124
2324
|
|
2325
|
+
def oncheck_one_simulation(self, e:wx.MouseEvent):
|
2326
|
+
""" Vérification de la cohérence d'une simulation
|
2327
|
+
"""
|
2328
|
+
self._txtctrl.Clear()
|
2329
|
+
log = self._parent.check_one_simulation()
|
2330
|
+
if log == '':
|
2331
|
+
self._txtctrl.WriteText("\n\n".join([_("All seems fine !")]))
|
2332
|
+
else:
|
2333
|
+
self._txtctrl.WriteText("\n\n".join([log]))
|
2334
|
+
|
2335
|
+
# Info on Python Environment and wolfgpu Path and version
|
2336
|
+
# -------------------------------------------------------
|
2337
|
+
|
2338
|
+
import sys
|
2339
|
+
# Python Environment
|
2340
|
+
self._txtctrl.write(_('\nPython Environment\n'))
|
2341
|
+
self._txtctrl.write('-------------------\n')
|
2342
|
+
self._txtctrl.write('Python version : {}\n'.format(sys.version))
|
2343
|
+
self._txtctrl.write('Python path : {}\n'.format(sys.executable))
|
2344
|
+
self._txtctrl.write('Python version info : {}\n'.format(sys.version_info))
|
2345
|
+
|
2346
|
+
# Test if wolfgpu.exe exists in script directory
|
2347
|
+
# wolfgpu Path and version
|
2348
|
+
self._txtctrl.write('\nWolfgpu Path and version\n')
|
2349
|
+
self._txtctrl.write('------------------------\n')
|
2350
|
+
|
2351
|
+
wolfgpu = self._parent.wolfgpu
|
2352
|
+
if wolfgpu.exists():
|
2353
|
+
self._txtctrl.write('Wolfgpu.exe found in : {}\n'.format(self._parent.wolfgpu.parent))
|
2354
|
+
else:
|
2355
|
+
self._txtctrl.write('Wolfgpu.exe not found !\n')
|
2356
|
+
self._parent.wolfgpu = None
|
2357
|
+
|
2358
|
+
|
2125
2359
|
def oncheck_consistency(self,e:wx.MouseEvent):
|
2126
2360
|
""" Vérification de la cohérence des fichiers """
|
2127
2361
|
|
@@ -2422,10 +2656,12 @@ class UI_Manager_2D_GPU():
|
|
2422
2656
|
self._txtctrl.SetBackgroundColour(wx.WHITE)
|
2423
2657
|
self._txtctrl.SetForegroundColour(wx.BLACK)
|
2424
2658
|
|
2659
|
+
self._parent._active_simulation = None
|
2425
2660
|
if isinstance(mydata, dict):
|
2426
2661
|
self._txtctrl.write(_('Yous have selected : {}\n\n'.format(str(mydata['path']))))
|
2427
2662
|
|
2428
2663
|
if mydata[IS_SIMUL]:
|
2664
|
+
self._parent._active_simulation = mydata
|
2429
2665
|
self._txtctrl.write(_('GPU SIMULATION\n\n'))
|
2430
2666
|
|
2431
2667
|
if ctrl and not shift and not alt:
|
@@ -211,6 +211,8 @@ class Wolf_MultipleSelection(wx.Dialog):
|
|
211
211
|
assert len(self.delete_if_transfer) == len(values_dict), "delete_if_transfer must be a list of len(values_dict)"
|
212
212
|
for i, values in enumerate(values_dict.values()):
|
213
213
|
assert isinstance(self.delete_if_transfer[i], bool), "delete_if_transfer must be a list of boolean"
|
214
|
+
else:
|
215
|
+
self.delete_if_transfer = None
|
214
216
|
|
215
217
|
super().__init__(parent, title=title)
|
216
218
|
|
@@ -339,6 +341,145 @@ class Wolf_MultipleSelection(wx.Dialog):
|
|
339
341
|
if self.callback is not None:
|
340
342
|
self.callback(self)
|
341
343
|
|
344
|
+
class Wolf_CompareArrays_Selection(Wolf_MultipleSelection):
|
345
|
+
"""
|
346
|
+
Dialog with multiple 'collapsiblepanes' containing 2 lists to select multiple items
|
347
|
+
This class is a specific case of Wolf_MultipleSelection for comparing arrays
|
348
|
+
"""
|
349
|
+
def __init__(self,
|
350
|
+
parent,
|
351
|
+
title,
|
352
|
+
values_dict:dict,
|
353
|
+
callback = None,
|
354
|
+
info:str='',
|
355
|
+
cmdApply:bool=False,
|
356
|
+
styles = wx.LB_EXTENDED,
|
357
|
+
destroyOK = False,
|
358
|
+
**kwargs):
|
359
|
+
"""
|
360
|
+
:param parent : wx.Window
|
361
|
+
:param title : str - title of the frame
|
362
|
+
:param values_dict : dict - {'label1':[item1, item2, ...], 'label2':[item1, item2, ...], ...}
|
363
|
+
:param callback : function - callback function when OK or Apply button is pressed
|
364
|
+
:param info : str - information to display upper the collapsiblepanes
|
365
|
+
:param cmdApply : bool - if True, Apply button is displayed
|
366
|
+
:param styles : wx.ListBox styles - wx constant or list of wx constants
|
367
|
+
:param kwargs : dict - other arguments for wx.Frame (example : max_selected_items=[1, 2, 3], delete_if_transfer=[True, False, True])
|
368
|
+
"""
|
369
|
+
super().__init__(parent=parent,
|
370
|
+
title=title,
|
371
|
+
values_dict=values_dict,
|
372
|
+
callback=callback,
|
373
|
+
info=info,
|
374
|
+
cmdApply=cmdApply,
|
375
|
+
styles=styles,
|
376
|
+
destroyOK=destroyOK,
|
377
|
+
max_selected_items=[1]*len(values_dict),
|
378
|
+
delete_if_transfer=[True]*len(values_dict),
|
379
|
+
**kwargs)
|
380
|
+
|
381
|
+
# add some UI specific to the compare arrays selection
|
382
|
+
|
383
|
+
# textbox for a threshold value
|
384
|
+
self.threshold_label = wx.StaticText(self, label="Threshold value [m]:")
|
385
|
+
self.threshold_value = wx.TextCtrl(self, value="0.01", style=wx.TE_PROCESS_ENTER | wx.TE_CENTER)
|
386
|
+
self.threshold_value.Bind(wx.EVT_TEXT_ENTER, self._on_threshold_enter)
|
387
|
+
self.threshold_value.Bind(wx.EVT_KILL_FOCUS, self._on_threshold_enter)
|
388
|
+
self.threshold_value.SetToolTip("Enter a threshold value - All differences below this threshold will be considered as equal")
|
389
|
+
# add the threshold label and value to the sizer
|
390
|
+
sizer = self.GetSizer()
|
391
|
+
|
392
|
+
sizer_threshold = wx.BoxSizer(wx.HORIZONTAL)
|
393
|
+
sizer_threshold.Add(self.threshold_label, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5)
|
394
|
+
sizer_threshold.Add(self.threshold_value, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
|
395
|
+
sizer.Add(sizer_threshold, proportion=0, flag=wx.EXPAND | wx.ALL, border=5)
|
396
|
+
|
397
|
+
# textbox for a minimal area value
|
398
|
+
self.min_area_label = wx.StaticText(self, label="Minimal area value [m²]:")
|
399
|
+
self.min_area_value = wx.TextCtrl(self, value="2.0", style=wx.TE_PROCESS_ENTER | wx.TE_CENTER)
|
400
|
+
self.min_area_value.Bind(wx.EVT_TEXT_ENTER, self._on_min_area_enter)
|
401
|
+
self.min_area_value.Bind(wx.EVT_KILL_FOCUS, self._on_min_area_enter)
|
402
|
+
self.min_area_value.SetToolTip("Enter a minimal area value - All patches below this area will be ignored")
|
403
|
+
# add the minimal area label and value to the sizer
|
404
|
+
sizer_min_area = wx.BoxSizer(wx.HORIZONTAL)
|
405
|
+
sizer_min_area.Add(self.min_area_label, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5)
|
406
|
+
sizer_min_area.Add(self.min_area_value, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
|
407
|
+
sizer.Add(sizer_min_area, proportion=0, flag=wx.EXPAND | wx.ALL, border=5)
|
408
|
+
# Maximum patches to include in the report
|
409
|
+
self.max_patches_label = wx.StaticText(self, label="Maximum patches to include in the report:")
|
410
|
+
self.max_patches_value = wx.TextCtrl(self, value="10", style=wx.TE_PROCESS_ENTER | wx.TE_CENTER)
|
411
|
+
self.max_patches_value.Bind(wx.EVT_TEXT_ENTER, self._on_max_patches_enter)
|
412
|
+
self.max_patches_value.Bind(wx.EVT_KILL_FOCUS, self._on_max_patches_enter)
|
413
|
+
self.max_patches_value.SetToolTip("Enter a maximum number of patches to include in the report - If more patches are found, only the first ones will be included")
|
414
|
+
# add the maximum patches label and value to the sizer
|
415
|
+
sizer_max_patches = wx.BoxSizer(wx.HORIZONTAL)
|
416
|
+
sizer_max_patches.Add(self.max_patches_label, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5)
|
417
|
+
sizer_max_patches.Add(self.max_patches_value, proportion=1, flag= wx.EXPAND | wx.ALL, border=5)
|
418
|
+
sizer.Add(sizer_max_patches, proportion=0, flag=wx.EXPAND | wx.ALL, border=5)
|
419
|
+
# add the sizer to the main sizer
|
420
|
+
self.SetSizer(sizer)
|
421
|
+
self.Fit()
|
422
|
+
self.Layout()
|
423
|
+
|
424
|
+
|
425
|
+
def _on_threshold_enter(self, event):
|
426
|
+
""" Callback when the threshold value is changed """
|
427
|
+
try:
|
428
|
+
value = float(self.threshold_value.GetValue())
|
429
|
+
if value < 0:
|
430
|
+
self.threshold_value.SetValue("0.01")
|
431
|
+
except ValueError as e:
|
432
|
+
wx.MessageBox(f"Invalid threshold value: {e}", "Error", wx.OK | wx.ICON_ERROR)
|
433
|
+
self.threshold_value.SetValue("0.01")
|
434
|
+
event.Skip()
|
435
|
+
|
436
|
+
def _on_min_area_enter(self, event):
|
437
|
+
""" Callback when the minimal area value is changed """
|
438
|
+
try:
|
439
|
+
value = float(self.min_area_value.GetValue())
|
440
|
+
if value < 0:
|
441
|
+
self.min_area_value.SetValue("2.0")
|
442
|
+
except ValueError as e:
|
443
|
+
wx.MessageBox(f"Invalid minimal area value: {e}", "Error", wx.OK | wx.ICON_ERROR)
|
444
|
+
self.min_area_value.SetValue("2.0")
|
445
|
+
event.Skip()
|
446
|
+
|
447
|
+
def _on_max_patches_enter(self, event):
|
448
|
+
""" Callback when the maximum patches value is changed """
|
449
|
+
try:
|
450
|
+
value = int(self.max_patches_value.GetValue())
|
451
|
+
if value < 1:
|
452
|
+
self.max_patches_value.SetValue("10")
|
453
|
+
except ValueError as e:
|
454
|
+
wx.MessageBox(f"Invalid maximum patches value: {e}", "Error", wx.OK | wx.ICON_ERROR)
|
455
|
+
self.max_patches_value.SetValue("10")
|
456
|
+
event.Skip()
|
457
|
+
|
458
|
+
def get_threshold(self):
|
459
|
+
""" Get the threshold value """
|
460
|
+
try:
|
461
|
+
return float(self.threshold_value.GetValue())
|
462
|
+
except ValueError:
|
463
|
+
wx.MessageBox("Invalid threshold value", "Error", wx.OK | wx.ICON_ERROR)
|
464
|
+
return 0.01
|
465
|
+
|
466
|
+
def get_min_area(self):
|
467
|
+
""" Get the minimal area value """
|
468
|
+
try:
|
469
|
+
return float(self.min_area_value.GetValue())
|
470
|
+
except ValueError:
|
471
|
+
wx.MessageBox("Invalid minimal area value", "Error", wx.OK | wx.ICON_ERROR)
|
472
|
+
return 2.0
|
473
|
+
|
474
|
+
def get_max_patches(self):
|
475
|
+
""" Get the maximum patches value """
|
476
|
+
try:
|
477
|
+
return int(self.max_patches_value.GetValue())
|
478
|
+
except ValueError:
|
479
|
+
wx.MessageBox("Invalid maximum patches value", "Error", wx.OK | wx.ICON_ERROR)
|
480
|
+
return 10
|
481
|
+
|
482
|
+
|
342
483
|
if __name__ == "__main__":
|
343
484
|
# Utilisation de la classe Wolf_MultipleSelection
|
344
485
|
app = wx.App()
|
@@ -351,6 +492,17 @@ if __name__ == "__main__":
|
|
351
492
|
callback=None,
|
352
493
|
styles=[wx.LB_SINGLE, wx.LB_EXTENDED, wx.LB_EXTENDED],
|
353
494
|
max_selected_items=[1, -1, -1],)
|
354
|
-
|
495
|
+
|
496
|
+
fram2 = Wolf_CompareArrays_Selection(None,
|
497
|
+
title="Exemple de Wolf_CompareArrays_Selection",
|
498
|
+
values_dict={'domain':["Item 1", "Item 2", "Item 3", "Item 4"],
|
499
|
+
'u':["Item 3", "Item 4", "Item 5", "Item 6"],
|
500
|
+
'v':["Item v1", "Item v2", "Item v3", "Item v4"]},
|
501
|
+
info="You can define : \n - the domain\n - u\n -v",
|
502
|
+
callback=None,
|
503
|
+
styles=[wx.LB_SINGLE, wx.LB_SINGLE, wx.LB_SINGLE],
|
504
|
+
destroyOK=True)
|
505
|
+
|
506
|
+
fram2.ShowModal()
|
355
507
|
pass
|
356
508
|
app.MainLoop()
|