wolfhece 2.2.27__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.
@@ -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
- nb = hydro[0].data.shape[1]
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'))
563
596
 
564
- logging.info(_('Number of hydrographs : {}'.format(len(hydro))))
565
- for curhydro in hydro:
566
- if curhydro.data.shape[1] != nb:
567
- loclog = _('Bad number of columns for {} !'.format(curhydro[0]._filename))
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')
619
+
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
@@ -671,7 +832,13 @@ class Config_Manager_2D_GPU:
671
832
  ok &= (GPU_2D_file.PARAMETERS.value.name+GPU_2D_file.PARAMETERS.value.extension).lower() in [cur.name.lower() for cur in curdict[GPU_2D_file_extensions.JSON.value]]
672
833
 
673
834
  if ok:
674
- json_data = json.load(open(curdict['path'] / (GPU_2D_file.PARAMETERS.value.name+GPU_2D_file.PARAMETERS.value.extension), 'r'))
835
+ try:
836
+ json_data = json.load(open(curdict['path'] / (GPU_2D_file.PARAMETERS.value.name+GPU_2D_file.PARAMETERS.value.extension), 'r'))
837
+ except json.JSONDecodeError as e:
838
+ logging.error(_('Error decoding JSON file: {}').format(e))
839
+ curdict['missing'].append(GPU_2D_file_extensions.JSON.value)
840
+ ok = False
841
+ return
675
842
 
676
843
  else:
677
844
  curdict['missing'].append(GPU_2D_file_extensions.JSON.value)
@@ -1182,6 +1349,22 @@ class Config_Manager_2D_GPU:
1182
1349
  else:
1183
1350
  logging.error(_("No 'bathymetry.tif' file found in the root directory !"))
1184
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
+
1185
1368
  def create_void_roof(self):
1186
1369
  """ create void roof file """
1187
1370
 
@@ -1382,6 +1565,7 @@ class Config_Manager_2D_GPU:
1382
1565
  logging.error(_('Infiltration .tif must be a full integer array ! -- The array will be ignored !'))
1383
1566
  infiltration = WolfArray(srcheader=bat.get_header(), whichtype= WOLF_ARRAY_FULL_INTEGER)
1384
1567
  infiltration.array.data[:,:] = 0
1568
+
1385
1569
  else:
1386
1570
  infiltration = WolfArray(srcheader=bat.get_header(), whichtype= WOLF_ARRAY_FULL_INTEGER)
1387
1571
  infiltration.array.data[:,:] = 0
@@ -1494,6 +1678,20 @@ class Config_Manager_2D_GPU:
1494
1678
  else:
1495
1679
  cursim.qy = np.zeros((self._header.nbx, self._header.nby), dtype=np.float32)
1496
1680
 
1681
+
1682
+ # check if infiltration array is strictly inside nap
1683
+ if not np.all(cursim.nap[infiltration.array.data[infiltration.array.data > 0]] == 1):
1684
+ logging.warning(_('Infiltration zones must be strictly inside the NAP !'))
1685
+ logging.warning(_('Infiltration zones outside NAP will be set to 0 !'))
1686
+
1687
+ #count number of infiltration zones outside NAP
1688
+ nb_outside = np.sum(infiltration.array.data[(infiltration.array.data > 0) & (cursim.nap == 0)])
1689
+ logging.warning(_('Number of infiltration zones outside NAP: {}').format(nb_outside))
1690
+ # index infiltration zones outside NAP
1691
+ indices = list(set(infiltration.array.data[(infiltration.array.data > 0) & (cursim.nap == 0)]))
1692
+ logging.warning(_('Indices of infiltration zones outside NAP: {}').format(indices))
1693
+ infiltration.array.data[(infiltration.array.data > 0) & (cursim.nap == 0)] = 0
1694
+
1497
1695
  cursim.infiltration_zones = np.asarray(infiltration.array.data, dtype=np.int32)
1498
1696
 
1499
1697
  if roof.nbnotnull == 0:
@@ -1753,10 +1951,18 @@ class UI_Manager_2D_GPU():
1753
1951
  self._reload.Bind(wx.EVT_BUTTON,self.onupdate_structure)
1754
1952
  self._reload.SetToolTip(_('reScan the directory and reload the entire structure'))
1755
1953
 
1954
+ tif_sizer = wx.BoxSizer(wx.HORIZONTAL)
1756
1955
  self._create_void_infil = wx.Button(self._frame,label = _('Create .tif infiltration zones'))
1757
1956
  self._create_void_infil.Bind(wx.EVT_BUTTON,self.oncreate_void_infil)
1758
1957
  self._create_void_infil.SetToolTip(_('Create a void infiltration zones file based on bathymetry.tif'))
1759
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
+
1760
1966
  bridge_sizer = wx.BoxSizer(wx.HORIZONTAL)
1761
1967
  self._create_void_roof = wx.Button(self._frame,label = _('Create .tif bridge/culvert roof elevation'))
1762
1968
  self._create_void_roof.Bind(wx.EVT_BUTTON,self.oncreate_void_roof)
@@ -1797,6 +2003,10 @@ class UI_Manager_2D_GPU():
1797
2003
  self._checkconsistency.Bind(wx.EVT_BUTTON,self.oncheck_consistency)
1798
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'))
1799
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
+
1800
2010
  self._createsim = wx.Button(self._frame,label = _('Create simulation(s)'))
1801
2011
  self._createsim.Bind(wx.EVT_BUTTON,self.oncreate_simulation)
1802
2012
  self._createsim.SetToolTip(_('Create simulation(s) from selected hydrographs'))
@@ -1840,14 +2050,19 @@ class UI_Manager_2D_GPU():
1840
2050
 
1841
2051
  # buttons -> sizer
1842
2052
  sizer_buttons.Add(self._reload,1,wx.EXPAND)
1843
- sizer_buttons.Add(self._create_void_infil,1,wx.EXPAND)
2053
+ sizer_buttons.Add(tif_sizer,1,wx.EXPAND)
1844
2054
  sizer_buttons.Add(bridge_sizer,1,wx.EXPAND)
1845
2055
  sizer_buttons.Add(self._create_void_scripts,1,wx.EXPAND)
1846
2056
  sizer_buttons.Add(self._check_prefix,1,wx.EXPAND)
1847
2057
  sizer_buttons.Add(self._create_vrt,1,wx.EXPAND)
1848
2058
  sizer_buttons.Add(self._translate_vrt,1,wx.EXPAND)
1849
2059
  sizer_buttons.Add(self._apply_scripts,1,wx.EXPAND)
1850
- sizer_buttons.Add(self._checkconsistency,1,wx.EXPAND)
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)
1851
2066
  sizer_buttons.Add(self._create_vec,1,wx.EXPAND)
1852
2067
  sizer_buttons.Add(self.listsims,1,wx.EXPAND)
1853
2068
  sizer_buttons.Add(self._createsim,1,wx.EXPAND)
@@ -1910,6 +2125,12 @@ class UI_Manager_2D_GPU():
1910
2125
  self._parent.create_void_infil()
1911
2126
  self.reload()
1912
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
+
1913
2134
  def oncreate_void_roof(self, e:wx.MouseEvent):
1914
2135
  """ Création d'un fichier de toit de pont vide """
1915
2136
 
@@ -2101,6 +2322,40 @@ class UI_Manager_2D_GPU():
2101
2322
  else:
2102
2323
  self._txtctrl.WriteText(log)
2103
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
+
2104
2359
  def oncheck_consistency(self,e:wx.MouseEvent):
2105
2360
  """ Vérification de la cohérence des fichiers """
2106
2361
 
@@ -2401,10 +2656,12 @@ class UI_Manager_2D_GPU():
2401
2656
  self._txtctrl.SetBackgroundColour(wx.WHITE)
2402
2657
  self._txtctrl.SetForegroundColour(wx.BLACK)
2403
2658
 
2659
+ self._parent._active_simulation = None
2404
2660
  if isinstance(mydata, dict):
2405
2661
  self._txtctrl.write(_('Yous have selected : {}\n\n'.format(str(mydata['path']))))
2406
2662
 
2407
2663
  if mydata[IS_SIMUL]:
2664
+ self._parent._active_simulation = mydata
2408
2665
  self._txtctrl.write(_('GPU SIMULATION\n\n'))
2409
2666
 
2410
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
- frame.ShowModal()
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()