wolfhece 2.1.98__py3-none-any.whl → 2.1.100__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
wolfhece/PyDraw.py CHANGED
@@ -24,6 +24,7 @@ try:
24
24
  import json
25
25
  import glob
26
26
  import traceback
27
+ from datetime import datetime, timedelta
27
28
  except ImportError as e:
28
29
  print(e)
29
30
  raise ImportError("Error importing wxPython, numpy, PIL, json, glob, traceback. Please check your installation.")
@@ -731,6 +732,372 @@ class DragdropFileTarget(wx.FileDropTarget):
731
732
 
732
733
  return True
733
734
 
735
+
736
+ class Sim_Explorer(wx.Frame):
737
+
738
+ def __init__(self, parent, title, mapviewer:"WolfMapViewer", sim:Wolfresults_2D):
739
+
740
+ super(Sim_Explorer, self).__init__(parent, title=title, size=(150, 250), style = wx.DEFAULT_FRAME_STYLE & ~ (wx.MAXIMIZE_BOX | wx.MINIMIZE_BOX))
741
+
742
+ self._panel = wx.Panel(self)
743
+
744
+ self.mapviewer = mapviewer
745
+ self.active_res2d:Wolfresults_2D = sim
746
+
747
+ main_sizer = wx.BoxSizer(wx.HORIZONTAL)
748
+
749
+ left_bar = wx.BoxSizer(wx.VERTICAL)
750
+ right_bar = wx.BoxSizer(wx.VERTICAL)
751
+
752
+ self._all_times_steps = self.active_res2d.get_times_steps()
753
+
754
+ # Right bar
755
+ # ---------
756
+
757
+ # Slider
758
+ self._slider_steps = wx.Slider(self._panel, minValue=1, maxValue=sim.get_nbresults(), style=wx.SL_HORIZONTAL | wx.SL_AUTOTICKS | wx.SL_MIN_MAX_LABELS | wx.SL_LABELS)
759
+ self._slider_steps.Bind(wx.EVT_SLIDER, self.OnSliderSteps)
760
+ right_bar.Add(self._slider_steps, 1, wx.EXPAND | wx.ALL, 2)
761
+
762
+ # Explore by index
763
+ self._label_idx = wx.StaticText(self._panel, label=_('Index'))
764
+ right_bar.Add(self._label_idx, 1, wx.EXPAND | wx.ALL, 2)
765
+
766
+ self._step_idx = wx.ListBox(self._panel, choices=[str(i) for i in range(1, sim.get_nbresults()+1)], style=wx.LB_SINGLE)
767
+ self._step_idx.Bind(wx.EVT_LISTBOX, self.OnSelectIdxStep)
768
+ right_bar.Add(self._step_idx, 1, wx.EXPAND | wx.ALL, 5)
769
+
770
+ # Explore by time
771
+ self._label_time = wx.StaticText(self._panel, label=_('Time [s]'))
772
+ right_bar.Add(self._label_time, 1, wx.EXPAND | wx.ALL, 2)
773
+
774
+ _now = datetime.now()
775
+ self._starting_date = datetime(year=_now.year, month=_now.month, day=_now.day, hour=0, minute=0, second=0)
776
+ self._texttime = wx.TextCtrl(self._panel, value=self._starting_date.strftime('%Y-%m-%d %H:%M:%S'))
777
+ right_bar.Add(self._texttime, 1, wx.EXPAND | wx.ALL, 5)
778
+ self._texttime.Bind(wx.EVT_TEXT, self.OnTextTime)
779
+
780
+ self._step_time = wx.ListBox(self._panel, choices=['{:.3f} - {}'.format(i, datetime.strftime(self._starting_date + timedelta(seconds=i), '%Y-%m-%d %H:%M:%S')) for i in self._all_times_steps[0]], style=wx.LB_SINGLE)
781
+ self._step_time.Bind(wx.EVT_LISTBOX, self.OnSelectNumStep)
782
+ right_bar.Add(self._step_time, 1, wx.EXPAND | wx.ALL, 5)
783
+
784
+ # Explore by time step
785
+ self._label_steps = wx.StaticText(self._panel, label=_('Time step [-]'))
786
+ right_bar.Add(self._label_steps, 1, wx.EXPAND | wx.ALL, 2)
787
+
788
+ self._step_num = wx.ListBox(self._panel, choices=[str(i) for i in self._all_times_steps[1]], style=wx.LB_SINGLE)
789
+ self._step_num.Bind(wx.EVT_LISTBOX, self.OnSelectCurTime)
790
+ right_bar.Add(self._step_num, 1, wx.EXPAND | wx.ALL, 5)
791
+
792
+ # Left bar
793
+ # --------
794
+
795
+ # Apply selected step
796
+ self._cmd_apply = wx.Button(self._panel, wx.ID_APPLY, _('Apply'))
797
+ self._cmd_apply.SetToolTip(_('Apply the selected parameters to the map'))
798
+ self._cmd_apply.Bind(wx.EVT_BUTTON, self.OnApply)
799
+ left_bar.Add(self._cmd_apply, 1, wx.EXPAND | wx.ALL, 5)
800
+
801
+ # Update listbox from files on disk
802
+ self._cmd_update = wx.Button(self._panel, wx.ID_REFRESH, _('Update'))
803
+ self._cmd_update.SetToolTip(_('Update the list of available results based on the files on disk'))
804
+ self._cmd_update.Bind(wx.EVT_BUTTON, self.OnUpdate)
805
+ left_bar.Add(self._cmd_update, 1, wx.EXPAND | wx.ALL, 5)
806
+
807
+ #Plot
808
+ self._cmd_plot = wx.Button(self._panel, wx.ID_PREVIEW, _('Plot simulation informations'))
809
+ self._cmd_plot.SetToolTip(_('Plot synthesis of the simulation (computation time, time step, clock time, mostly dry mesh...)'))
810
+ self._cmd_plot.Bind(wx.EVT_BUTTON, self.OnPlot)
811
+ left_bar.Add(self._cmd_plot, 1, wx.EXPAND | wx.ALL, 5)
812
+
813
+ # Next step
814
+ self._cmd_next = wx.Button(self._panel, wx.ID_FORWARD, _('Next'))
815
+ self._cmd_next.SetToolTip(_('Go to the next step -- using the selected mode'))
816
+ self._cmd_next.Bind(wx.EVT_BUTTON, self.OnNext)
817
+ left_bar.Add(self._cmd_next, 1, wx.EXPAND | wx.ALL, 5)
818
+
819
+ # Previous step
820
+ self._cmd_prev = wx.Button(self._panel, wx.ID_BACKWARD, _('Previous'))
821
+ self._cmd_prev.SetToolTip(_('Go to the previous step -- using the selected mode'))
822
+ self._cmd_prev.Bind(wx.EVT_BUTTON, self.OnPrev)
823
+ left_bar.Add(self._cmd_prev, 1, wx.EXPAND | wx.ALL, 5)
824
+
825
+ # Check Mode movement
826
+ self._mode = wx.ListBox(self._panel, choices=['by time [s]', 'by time [hour]', 'by index', 'by time step'], style=wx.LB_SINGLE)
827
+ self._mode.SetToolTip(_('Select the mode to move through the simulation'))
828
+ self._mode.SetSelection(2)
829
+ self._interval = wx.TextCtrl(self._panel, value='1', style=wx.ALIGN_CENTER_HORIZONTAL)
830
+ self._interval.SetToolTip(_('Interval for the mode selected -- unit depends on the mode'))
831
+ self._interval.Bind(wx.EVT_TEXT, self.OnInterval)
832
+
833
+ left_bar.Add(self._mode, 1, wx.EXPAND | wx.ALL, 5)
834
+ left_bar.Add(self._interval, 0, wx.EXPAND | wx.ALL, 5)
835
+
836
+ self.Bind(wx.EVT_CLOSE, self.OnClose)
837
+
838
+ main_sizer.Add(left_bar, 1, wx.EXPAND | wx.ALL, 2)
839
+ main_sizer.Add(right_bar, 1, wx.EXPAND | wx.ALL, 2)
840
+
841
+ self._panel.SetSizer(main_sizer)
842
+ self._panel.SetAutoLayout(True)
843
+
844
+ self.MinSize = (450, 500)
845
+
846
+ self.Fit()
847
+ self.Show()
848
+
849
+ self.SetIcon(wx.Icon(str(Path(__file__).parent / "apps/wolf_logo2.bmp")))
850
+
851
+ self._set_all(0)
852
+
853
+ def OnPlot(self, event):
854
+ """ Create a scatter plot of all steps.
855
+
856
+ Major x_axis is time in seconds, Minor X-axis is time by date.
857
+
858
+ Plots:
859
+ - Computation time step (Dt)
860
+ - Computation steps (N)
861
+ - Clock time (s)
862
+ - Mostly dry mesh (N)
863
+
864
+ """
865
+
866
+ main_x = self._all_times_steps[0]
867
+ second_x = [self._starting_date + timedelta(seconds=i) for i in main_x]
868
+
869
+ if isinstance(self.active_res2d, wolfres2DGPU):
870
+
871
+ ax:list[Axes]
872
+ fig, ax= plt.subplots(5, 1, figsize=(10, 8))
873
+
874
+ ax[0].plot(main_x, self._all_times_steps[1], 'o-')
875
+ ax[0].set_ylabel(_('Computation\ntime step (N)'), fontsize=8)
876
+ ax[0].ticklabel_format(axis='y', style='sci', scilimits=(0,0))
877
+
878
+ ax[0].grid(which='both')
879
+ ax[0].set_xticks(main_x)
880
+ ax[0].set_xticklabels([])
881
+
882
+ secax:Axes = ax[0].secondary_xaxis('top')
883
+ secax.set_xlabel(_('Real date\n[Y-M-D H:M:S]'), fontsize=8)
884
+ secax.set_xticks(main_x)
885
+ secax.set_xticklabels([datetime.strftime(i, '%Y-%m-%d %H:%M') for i in second_x], fontsize=8)
886
+ secax.tick_params(axis='x', rotation=30)
887
+
888
+ ax[1].plot(main_x, self.active_res2d.all_dt, 'o-')
889
+ ax[1].set_ylabel(_('$\Delta t$ [s]'), fontsize=8)
890
+ ax[1].grid(which='both')
891
+ ax[1].set_xticks(main_x)
892
+ ax[1].set_xticklabels([])
893
+ ax[1].ticklabel_format(axis='y', style='sci', scilimits=(0,0))
894
+
895
+ ctime = self.active_res2d.all_clock_time
896
+ ax[2].plot(main_x, self.active_res2d.all_clock_time, 'o-')
897
+ ax[2].set_ylabel(_('Clock time [s]'), fontsize=8)
898
+ ax[2].grid(which='both')
899
+ ax[2].set_xticks([])
900
+ ax[2].set_xticks(main_x)
901
+ ax[2].set_xticklabels([])
902
+ ax[2].ticklabel_format(axis='y', style='sci', scilimits=(0,0))
903
+
904
+ # Fit a line on the (main_x - clock time) plot
905
+ # This will give a mean acceleration factor
906
+ # The inverse of the slope of the line is the accelaration factor
907
+ # The line is y = slope * x + intercept
908
+ from scipy.stats import linregress
909
+ slope, intercept, r_value, p_value, std_err = linregress(main_x, ctime)
910
+
911
+ # Plot the info on the ax[2]
912
+ msg = _('Acceleration factor:')
913
+ ax[2].text(0.5, 0.5, f'{msg} {1/slope:.2f}', transform=ax[2].transAxes, fontsize=12, verticalalignment='top')
914
+
915
+ ax[3].plot(main_x, self.active_res2d.all_wet_meshes, 'o-', color='blue')
916
+ ax[3].plot(main_x, self.active_res2d.all_mostly_dry_mesh, 'o-', color='green')
917
+ ax[3].set_ylabel(_('Wet and Mostly dry\nmeshes [N]'), fontsize=8)
918
+ ax[3].grid(which='both')
919
+ ax[3].set_xticks(main_x)
920
+ ax[3].set_xlabel([])
921
+ ax[3].ticklabel_format(axis='y', style='sci', scilimits=(0,0))
922
+
923
+ ax[4].plot(main_x, [i/j*100 if j>0 else 0 for i, j in zip(self.active_res2d.all_mostly_dry_mesh, self.active_res2d.all_wet_meshes)], 'o-', color='red')
924
+ ax[4].set_ylabel(_('Wet/Mostly dry\nmeshes [%]'), fontsize=8)
925
+ ax[4].grid(which='both')
926
+ ax[4].set_xticks(main_x)
927
+ ax[4].set_xlabel(_('Simulated time [s]'), fontsize=8)
928
+ ax[4].ticklabel_format(axis='y', style='sci', scilimits=(0,0))
929
+
930
+ fig.suptitle('Simulation {}'.format(self.active_res2d.idx), fontsize=10)
931
+
932
+ fig.tight_layout()
933
+ fig.show()
934
+
935
+ def OnInterval(self, event):
936
+ """ Change the interval """
937
+
938
+ try:
939
+ interv = float(self._interval.GetValue())
940
+ if interv <= 0:
941
+ interv = 1.
942
+ self._interval.SetValue('1')
943
+ except:
944
+ interv = 1
945
+ self._interval.SetValue('1')
946
+
947
+ def _find_next(self, idx:int):
948
+ """ Find the next step based on the mode and interval """
949
+
950
+ mode = int(self._mode.GetSelection())
951
+
952
+ if mode == 0:
953
+ # By time [s]
954
+ next_time = self._all_times_steps[0][idx] + float(self._interval.GetValue())
955
+ diff = [abs(next_time - i) for i in self._all_times_steps[0][idx:]]
956
+ next_idx = diff.index(min(diff)) + idx
957
+
958
+ return next_idx
959
+
960
+ elif mode == 1:
961
+ # By time [hour]
962
+ next_time = self._all_times_steps[0][idx] + float(self._interval.GetValue())*3600
963
+ diff = [abs(next_time - i) for i in self._all_times_steps[0][idx:]]
964
+ next_idx = diff.index(min(diff)) + idx
965
+
966
+ return next_idx
967
+
968
+ elif mode == 2:
969
+ # By index
970
+ next_idx = min(idx + int(self._interval.GetValue()), len(self._all_times_steps[0])-1)
971
+
972
+ return next_idx
973
+
974
+ elif mode == 3:
975
+ # By time step
976
+ next_idx = self._all_times_steps[1].index(self._all_times_steps[1][idx] + int(self._interval.GetValue()))
977
+ diff = [abs(next_idx - i) for i in self._all_times_steps[1][idx:]]
978
+ next_idx = diff.index(min(diff)) + idx
979
+
980
+ return next_idx
981
+
982
+ def _find_prev(self, idx:int):
983
+ """ Find the previous step based on the mode and interval """
984
+
985
+ mode = int(self._mode.GetSelection())
986
+
987
+ if mode == 0:
988
+ # By time [s]
989
+ prev_time = self._all_times_steps[0][idx] - float(self._interval.GetValue())
990
+ diff = [abs(prev_time - i) for i in self._all_times_steps[0][:idx]]
991
+ prev_idx = diff.index(min(diff))
992
+
993
+ return prev_idx
994
+
995
+ elif mode == 1:
996
+ # By time [hour]
997
+ prev_time = self._all_times_steps[0][idx] - float(self._interval.GetValue())*3600
998
+ diff = [abs(prev_time - i) for i in self._all_times_steps[0][:idx]]
999
+ prev_idx = diff.index(min(diff))
1000
+
1001
+ return prev_idx
1002
+
1003
+ elif mode == 2:
1004
+ # By index
1005
+ prev_idx = max(idx - int(self._interval.GetValue()), 0)
1006
+
1007
+ return prev_idx
1008
+
1009
+ elif mode == 3:
1010
+ # By time step
1011
+ prev_idx = self._all_times_steps[1].index(self._all_times_steps[1][idx] - int(self._interval.GetValue()))
1012
+ diff = [abs(prev_idx - i) for i in self._all_times_steps[1][:idx]]
1013
+ prev_idx = diff.index(min(diff))
1014
+
1015
+ return prev_idx
1016
+
1017
+ def OnNext(self, event):
1018
+ """ Go to the next step """
1019
+
1020
+ selected_step = self._slider_steps.GetValue()-1
1021
+ next_idx = self._find_next(selected_step)
1022
+
1023
+ if next_idx != selected_step:
1024
+ self._set_all(next_idx)
1025
+ self.Refresh(next_idx)
1026
+
1027
+ def OnPrev(self, event):
1028
+ """ Go to the previous step """
1029
+
1030
+ selected_step = self._slider_steps.GetValue()-1
1031
+ prev_idx = self._find_prev(selected_step)
1032
+
1033
+ if prev_idx != selected_step:
1034
+ self._set_all(prev_idx)
1035
+ self.Refresh(prev_idx)
1036
+
1037
+ def OnTextTime(self, event):
1038
+ try:
1039
+ self._starting_date = datetime.strptime(self._texttime.GetValue(), '%Y-%m-%d %H:%M:%S')
1040
+ self._step_time.Set(['{:.3f} - {}'.format(i, datetime.strftime(self._starting_date + timedelta(seconds=i), '%Y-%m-%d %H:%M:%S')) for i in self._all_times_steps[0]])
1041
+ except:
1042
+ logging.info('Error while parsing the date')
1043
+ pass
1044
+
1045
+ def OnClose(self, event):
1046
+ """ Close the simulation explorer """
1047
+
1048
+ self.mapviewer._pop_sim_explorer(self.active_res2d)
1049
+ self.Destroy()
1050
+
1051
+ def OnUpdate(self, event):
1052
+ self._update()
1053
+
1054
+ def OnApply(self, event):
1055
+ selected_step = self._slider_steps.GetValue()-1
1056
+
1057
+ self._cmd_apply.SetBackgroundColour(wx.Colour(255, 0, 0)) # Set button color to red
1058
+ self._cmd_apply.Refresh() # Refresh the button to apply the color change
1059
+
1060
+ self.Refresh(selected_step)
1061
+
1062
+ self._cmd_apply.SetBackgroundColour(wx.NullColour) # Reset button color to default
1063
+ self._cmd_apply.Refresh() # Refresh the button to apply the color change
1064
+
1065
+ def _set_all(self, idx:int):
1066
+ self._slider_steps.SetValue(idx+1)
1067
+ self._step_idx.SetSelection(idx)
1068
+ self._step_time.SetSelection(idx)
1069
+ self._step_num.SetSelection(idx)
1070
+
1071
+ def Refresh(self, idx:int):
1072
+ self.active_res2d.read_oneresult(idx)
1073
+ self.active_res2d.set_currentview()
1074
+ self.mapviewer.Refresh()
1075
+
1076
+ def OnSliderSteps(self, event):
1077
+ selected_step = self._slider_steps.GetValue()
1078
+ self._set_all(selected_step-1)
1079
+
1080
+ def OnSelectCurTime(self, event):
1081
+ selected_time = self._step_num.GetSelection()
1082
+ self._set_all(selected_time)
1083
+
1084
+ def OnSelectNumStep(self, event):
1085
+ selected_step = self._step_time.GetSelection()
1086
+ self._set_all(selected_step)
1087
+
1088
+ def OnSelectIdxStep(self, event):
1089
+ selected_step = self._step_idx.GetSelection()
1090
+ self._set_all(selected_step)
1091
+
1092
+ def _update(self):
1093
+ nb = self.active_res2d.get_nbresults()
1094
+ self._all_times_steps = self.active_res2d.get_times_steps()
1095
+
1096
+ self._slider_steps.SetMax(nb)
1097
+ self._step_idx.Set([str(i) for i in range(1,nb+1)])
1098
+ self._step_time.Set(['{:.3f} - {}'.format(i, datetime.strftime(self._starting_date + timedelta(seconds=i), '%Y-%m-%d %H:%M:%S')) for i in self._all_times_steps[0]])
1099
+ self._step_num.Set([str(i) for i in self._all_times_steps[1]])
1100
+
734
1101
  class WolfMapViewer(wx.Frame):
735
1102
  """
736
1103
  Fenêtre de visualisation de données WOLF grâce aux WxWidgets
@@ -751,6 +1118,7 @@ class WolfMapViewer(wx.Frame):
751
1118
  mytiles: list[Tiles]
752
1119
  mypartsystems: list[Particle_system]
753
1120
  myviewers3d:list[Wolf_Viewer3D]
1121
+ sim_explorers: dict[Wolfresults_2D:Sim_Explorer]
754
1122
 
755
1123
  canvas: GLCanvas # canvas OpenGL
756
1124
  context: GLContext # context OpenGL
@@ -1450,6 +1818,10 @@ class WolfMapViewer(wx.Frame):
1450
1818
  if self.menuwolf2d is None:
1451
1819
  self.menuwolf2d = wx.Menu()
1452
1820
 
1821
+ self.menu2d_explore_results = self.menuwolf2d.Append(wx.ID_ANY, _("Explore time/index results"), _("Open a dialog to explore time/index results"))
1822
+
1823
+ self.menuwolf2d.AppendSeparator()
1824
+
1453
1825
  self.menu2d_curentview = self.menuwolf2d.Append(wx.ID_ANY, _("Change current view"), _("Current view"))
1454
1826
  self.menu2d_lastres = self.menuwolf2d.Append(wx.ID_ANY, _("Read last result"), _("Current view"))
1455
1827
  self.menu2d_epsilon = self.menuwolf2d.Append(wx.ID_ANY, _("Set epsilon water depth"), _("Set the epsilon used in the mask"))
@@ -1462,11 +1834,11 @@ class WolfMapViewer(wx.Frame):
1462
1834
  self.menuwolf2d.AppendSeparator()
1463
1835
 
1464
1836
  self.menu2d_dangermap = self.menuwolf2d.Append(wx.ID_ANY, _("Danger map"), _("Compute the danger map"))
1465
- self.menu2d_dangermaph = self.menuwolf2d.Append(wx.ID_ANY, _("Danger map - only h"), _("Compute the danger map"))
1837
+ self.menu2d_dangermaph = self.menuwolf2d.Append(wx.ID_ANY, _("Danger map - only h"), _("Compute the danger map - only waterdepth"))
1466
1838
 
1467
1839
  self.menuwolf2d.AppendSeparator()
1468
1840
 
1469
- self.menu2d_export_as = self.menuwolf2d.Append(wx.ID_ANY, _("Export results as..."), _("Export results as Geotif or Shapefile"))
1841
+ self.menu2d_export_as = self.menuwolf2d.Append(wx.ID_ANY, _("Export results as..."), _("Export results as Geotif, Shapefile or Numpy arrays"))
1470
1842
 
1471
1843
  self.menuwolf2d.AppendSeparator()
1472
1844
  # Possible cache entries will be added after this separator
@@ -1659,6 +2031,41 @@ class WolfMapViewer(wx.Frame):
1659
2031
 
1660
2032
  self.active_array.reset_plot()
1661
2033
 
2034
+ def _add_sim_explorer(self, which:Wolfresults_2D):
2035
+ """ Add a step chooser """
2036
+
2037
+ if which in self.sim_explorers:
2038
+ logging.warning(_('Step chooser already exists for this result'))
2039
+ self.sim_explorers[which].Show()
2040
+ self.sim_explorers[which].Raise()
2041
+ self.sim_explorers[which].SetFocus()
2042
+ self.sim_explorers[which].Center()
2043
+ return
2044
+
2045
+ self.sim_explorers[which] = Sim_Explorer(self, which.idx, self, which)
2046
+ self.sim_explorers[which]._set_all(which.current_result)
2047
+
2048
+ def _pop_sim_explorer(self, which:Wolfresults_2D):
2049
+ """ Pop a step chooser """
2050
+
2051
+ if which in self.sim_explorers:
2052
+ self.sim_explorers.pop(which)
2053
+ logging.debug(_('Pop step chooser for result {}'.format(which.idx)))
2054
+ else:
2055
+ logging.warning(_('No step chooser for this result'))
2056
+
2057
+ def _update_sim_explorer(self, which:Wolfresults_2D = None):
2058
+
2059
+ if which is None:
2060
+ if self.active_res2d is None:
2061
+ logging.warning(_('No active 2D result -- Please activate a 2D result first'))
2062
+ return
2063
+
2064
+ which = self.active_res2d
2065
+
2066
+ if which in self.sim_explorers:
2067
+ self.sim_explorers[which]._set_all(which.current_result)
2068
+
1662
2069
  def Onmenuwolf2d(self, event: wx.MenuEvent):
1663
2070
 
1664
2071
  id = event.GetId()
@@ -1678,6 +2085,13 @@ class WolfMapViewer(wx.Frame):
1678
2085
 
1679
2086
  self.export_results_as()
1680
2087
 
2088
+ elif itemlabel == _("Explore time/index results"):
2089
+ if self.active_res2d is None:
2090
+ logging.warning(_('No active 2D result ! -- Please activate a 2D result first'))
2091
+ return
2092
+
2093
+ self._add_sim_explorer(self.active_res2d)
2094
+
1681
2095
  elif itemlabel == _("Change current view"):
1682
2096
 
1683
2097
  # Change view for results
@@ -3278,6 +3692,7 @@ class WolfMapViewer(wx.Frame):
3278
3692
  self.mywmsfore = []
3279
3693
  self.myres2D = []
3280
3694
  self.myviewers3d = []
3695
+ self.sim_explorers = {}
3281
3696
 
3282
3697
  # liste des éléments modifiable dans l'arbre
3283
3698
  self.all_lists = [self.myarrays, self.myvectors, self.myclouds, self.mytri, self.myothers, self.myviews, self.myres2D, self.mytiles, self.mypartsystems, self.myviewers3d]
@@ -4683,6 +5098,8 @@ class WolfMapViewer(wx.Frame):
4683
5098
  else:
4684
5099
  return
4685
5100
 
5101
+ logging.info(_('This could take some time for large area...\n Take a coffee and relax!'))
5102
+
4686
5103
  bounds = array.get_bounds()
4687
5104
 
4688
5105
  # align bounds on chunk_size
@@ -4776,7 +5193,7 @@ class WolfMapViewer(wx.Frame):
4776
5193
  array.reset_plot()
4777
5194
  self.Paint()
4778
5195
 
4779
- logging.info(_('Filling done'))
5196
+ logging.info(_('Filling done !'))
4780
5197
 
4781
5198
  def count_active_array_from_laz(self, array:WolfArray = None, used_codes:list = [], chunk_size:float = 500.):
4782
5199
  """ Fill active array with laz data
@@ -5043,6 +5460,7 @@ class WolfMapViewer(wx.Frame):
5043
5460
 
5044
5461
  curmodel.read_oneresult()
5045
5462
  curmodel.set_currentview()
5463
+ self._update_sim_explorer(curmodel)
5046
5464
 
5047
5465
  self.Refresh()
5048
5466
  self.currently_readresults = False
@@ -5061,6 +5479,8 @@ class WolfMapViewer(wx.Frame):
5061
5479
 
5062
5480
  curmodel.read_oneresult(which)
5063
5481
  curmodel.set_currentview()
5482
+ self._update_sim_explorer(curmodel)
5483
+
5064
5484
 
5065
5485
  self.Refresh()
5066
5486
  self.currently_readresults = False
@@ -5079,6 +5499,7 @@ class WolfMapViewer(wx.Frame):
5079
5499
 
5080
5500
  curmodel.read_previous()
5081
5501
  curmodel.set_currentview()
5502
+ self._update_sim_explorer(curmodel)
5082
5503
 
5083
5504
  self.Refresh()
5084
5505
  self.currently_readresults = False
@@ -5120,6 +5541,8 @@ class WolfMapViewer(wx.Frame):
5120
5541
 
5121
5542
  curmodel.read_next()
5122
5543
  curmodel.set_currentview()
5544
+ self._update_sim_explorer(curmodel)
5545
+
5123
5546
 
5124
5547
  self.Refresh()
5125
5548
  self.currently_readresults = False
@@ -5402,6 +5825,8 @@ class WolfMapViewer(wx.Frame):
5402
5825
  linkedarrays = self.get_linked_arrays()
5403
5826
 
5404
5827
  with wx.MultiChoiceDialog(None, _('Choose the arrays to plot'), _('Arrays'), [curarray for curarray in list(linkedarrays.keys())]) as dlg:
5828
+ dlg.SetSelections(range(len(linkedarrays)))
5829
+
5405
5830
  if dlg.ShowModal() == wx.ID_CANCEL:
5406
5831
  dlg.Destroy()
5407
5832
  return
@@ -6443,31 +6868,40 @@ class WolfMapViewer(wx.Frame):
6443
6868
 
6444
6869
  logging.info(_('Filtering done !'))
6445
6870
 
6446
- def export_results_as(self, which:Literal['geotiff','shape'] = None, multiband:bool = None):
6871
+ def export_results_as(self, which:Literal['geotiff','shape','numpy'] = None, multiband:bool = None):
6447
6872
  """
6448
- Export des résultats WOLF2D vers le format GeoTiff
6449
- On attend que les matrices ".hbin" aient été chargées dans l'interface
6873
+ Export des résultats WOLF2D vers différents formats.
6874
+ Au moins un résultat doit être chargé pour pouvoir être exporté.
6450
6875
  """
6451
6876
 
6452
6877
  dlg = wx.DirDialog(self,_('Choose output directory'), style = wx.DD_DIR_MUST_EXIST)
6453
6878
  ret=dlg.ShowModal()
6454
6879
 
6455
6880
  if ret == wx.ID_CANCEL:
6881
+ logging.warning(_('Abort!'))
6456
6882
  dlg.Destroy()
6457
6883
  return
6458
6884
 
6459
6885
  outdir = dlg.GetPath()
6460
6886
  dlg.Destroy()
6461
6887
 
6462
- if which not in ['geotiff','shape']:
6463
- dlg = wx.SingleChoiceDialog(self,_('Choose output format'), _('Format'), ['Geotiff','Shape file'])
6464
- dlg.ShowModal()
6888
+ if which not in ['geotiff','shape','numpy']:
6889
+ dlg = wx.SingleChoiceDialog(self,_('Choose output format'), _('Format'), ['Geotiff','Shape file','Numpy array'])
6890
+ ret = dlg.ShowModal()
6891
+
6892
+ if ret == wx.ID_CANCEL:
6893
+ logging.warning(_('Abort!'))
6894
+ dlg.Destroy()
6895
+ return
6896
+
6465
6897
  sel = dlg.GetSelection()
6466
6898
 
6467
6899
  if sel == 0:
6468
6900
  which = 'geotiff'
6469
- else:
6901
+ elif sel == 1:
6470
6902
  which = 'shape'
6903
+ else:
6904
+ which = 'numpy'
6471
6905
 
6472
6906
  dlg.Destroy()
6473
6907
 
@@ -6490,7 +6924,12 @@ class WolfMapViewer(wx.Frame):
6490
6924
 
6491
6925
  dlg = wx.MultiChoiceDialog(self,_('Choose results to export'), _('Results'), choices=loaded_res)
6492
6926
  dlg.SetSelections([idx for idx, res in enumerate(loaded_res) if self.get_obj_from_id(res, drawtype=draw_type.RES2D).plotted])
6493
- dlg.ShowModal()
6927
+ ret = dlg.ShowModal()
6928
+ if ret == wx.ID_CANCEL:
6929
+ logging.warning(_('Abort!'))
6930
+ dlg.Destroy()
6931
+ return
6932
+
6494
6933
  sel = dlg.GetSelections() # Get a list if integers
6495
6934
  sel_res = [self.get_obj_from_id(loaded_res[cursel], drawtype=draw_type.RES2D) for cursel in sel] # convert to list of objects
6496
6935
 
@@ -6516,7 +6955,13 @@ class WolfMapViewer(wx.Frame):
6516
6955
 
6517
6956
  dlg = wx.MultiChoiceDialog(self,_('Choose fields to export'), _('Fields'), choices= [str(field[0]) for field in fields])
6518
6957
  dlg.SetSelections([idx for idx, field in enumerate(fields) if field[1]])
6519
- dlg.ShowModal()
6958
+ ret = dlg.ShowModal()
6959
+
6960
+ if ret == wx.ID_CANCEL:
6961
+ logging.warning(_('Abort!'))
6962
+ dlg.Destroy()
6963
+ return
6964
+
6520
6965
  sel_fields = dlg.GetSelections() # Get a list if integers
6521
6966
  dlg.Destroy()
6522
6967
 
@@ -7136,16 +7581,27 @@ class WolfMapViewer(wx.Frame):
7136
7581
  # myhead.dy = 1.
7137
7582
 
7138
7583
  else:
7584
+
7585
+ dlg = wx.TextEntryDialog(self,_('Spatial step size (assuming dx == dy) ?'), value='1')
7586
+ ret=dlg.ShowModal()
7587
+
7588
+ if ret == wx.ID_CANCEL:
7589
+ dlg.Destroy()
7590
+ return -1
7591
+
7592
+ tmpdx = float(dlg.GetValue())
7593
+ dlg.Destroy()
7594
+
7595
+ dy = dx
7596
+
7139
7597
  myxyz = xyz_scandir(filename, None)
7140
7598
  myhead = header_wolf()
7141
7599
 
7142
- myhead.origx = np.min(myxyz[:, 0]) - .5
7143
- myhead.origy = np.min(myxyz[:, 1]) - .5
7600
+ myhead.origx = np.min(myxyz[:, 0]) - dx/2.
7601
+ myhead.origy = np.min(myxyz[:, 1]) - dy/2.
7144
7602
 
7145
- myhead.dx = 1.
7146
- myhead.dy = 1.
7147
- tmpdx = 1.
7148
- tmpdy = 1.
7603
+ myhead.dx = dx
7604
+ myhead.dy = dy
7149
7605
 
7150
7606
  myhead.nbx = int(np.max(myxyz[:, 0]) - myhead.origx) + 1
7151
7607
  myhead.nby = int(np.max(myxyz[:, 1]) - myhead.origy) + 1
@@ -7163,10 +7619,6 @@ class WolfMapViewer(wx.Frame):
7163
7619
 
7164
7620
  newobj.mask_data(newobj.nullvalue)
7165
7621
 
7166
- # if min(tmpdx, tmpdy) != 1.:
7167
- # newobj.rebin(min(tmpdx, tmpdy))
7168
- # newobj.mask_data(newobj.nullvalue)
7169
-
7170
7622
  newobj.change_gui(self)
7171
7623
  newobj.updatepalette(0)
7172
7624
  self.myarrays.append(newobj)
@@ -9595,7 +10047,25 @@ class WolfMapViewer(wx.Frame):
9595
10047
  logging.debug(_('Alt is down'))
9596
10048
 
9597
10049
  if ctrldown or altdown:
9598
- if key == wx.WXK_F2 and not shiftdown:
10050
+ if key == 60 and shiftdown: #'>'
10051
+ if self.active_array is not None:
10052
+ if self.active_array.SelectionData is not None:
10053
+ self.active_array.SelectionData.dilate_contour_selection(1)
10054
+ self.active_array.reset_plot()
10055
+ elif key == 60 and not shiftdown: #'<'
10056
+ if self.active_array is not None:
10057
+ if self.active_array.SelectionData is not None:
10058
+ self.active_array.SelectionData.erode_contour_selection()
10059
+ self.active_array.reset_plot()
10060
+
10061
+ elif key == wx.WXK_F2 and ctrldown and altdown and shiftdown:
10062
+
10063
+ if self.active_res2d is None:
10064
+ logging.info(_('Please activate a simulation before search a specific result'))
10065
+
10066
+ self._add_sim_explorer(self.active_res2d)
10067
+
10068
+ elif key == wx.WXK_F2 and not shiftdown:
9599
10069
 
9600
10070
  if self.active_res2d is not None:
9601
10071
  nb = self.active_res2d.get_nbresults()
@@ -9609,20 +10079,11 @@ class WolfMapViewer(wx.Frame):
9609
10079
  self.active_res2d.set_currentview()
9610
10080
  self.Refresh()
9611
10081
 
10082
+ self._update_sim_explorer()
10083
+
9612
10084
  else:
9613
10085
  logging.info(_('Please activate a simulation before search a specific result'))
9614
10086
 
9615
- elif key == 60 and shiftdown: #'>'
9616
- if self.active_array is not None:
9617
- if self.active_array.SelectionData is not None:
9618
- self.active_array.SelectionData.dilate_contour_selection(1)
9619
- self.active_array.reset_plot()
9620
- elif key == 60 and not shiftdown: #'<'
9621
- if self.active_array is not None:
9622
- if self.active_array.SelectionData is not None:
9623
- self.active_array.SelectionData.erode_contour_selection()
9624
- self.active_array.reset_plot()
9625
-
9626
10087
  elif key == wx.WXK_F2 and shiftdown:
9627
10088
 
9628
10089
  if self.active_res2d is not None:
@@ -9648,6 +10109,8 @@ class WolfMapViewer(wx.Frame):
9648
10109
  self.active_res2d.set_currentview()
9649
10110
  self.Refresh()
9650
10111
 
10112
+ self._update_sim_explorer()
10113
+
9651
10114
  else:
9652
10115
  logging.info(_('Please activate a simulation before searching a specific result'))
9653
10116
 
@@ -9665,6 +10128,7 @@ class WolfMapViewer(wx.Frame):
9665
10128
  self.active_particle_system.current_step = nb-1
9666
10129
  self.Refresh()
9667
10130
  self._update_mytooltip()
10131
+ self._update_sim_explorer()
9668
10132
 
9669
10133
  else:
9670
10134
  logging.info(_('Please activate a particle system before searching a specific result'))
@@ -9692,6 +10156,7 @@ class WolfMapViewer(wx.Frame):
9692
10156
  self.active_particle_system.current_step = choices.index(keyvalue)
9693
10157
  self.Refresh()
9694
10158
  self._update_mytooltip()
10159
+ self._update_sim_explorer()
9695
10160
 
9696
10161
  else:
9697
10162
  logging.info(_('Please activate a simulation before search a specific result'))
@@ -10062,7 +10527,13 @@ class WolfMapViewer(wx.Frame):
10062
10527
  self.active_array.myops.select_node_by_node()
10063
10528
 
10064
10529
  if self.active_res2d is not None:
10065
- self.active_res2d.properties.select_node_by_node()
10530
+ if self.active_array is not None:
10531
+ msg = wx.MessageDialog(None, _('Do you want to select the nodes of the active result ?'), _('Select nodes'), wx.YES_NO | wx.ICON_QUESTION)
10532
+ ret = msg.ShowModal()
10533
+ if ret == wx.ID_YES:
10534
+ self.active_res2d.properties.select_node_by_node()
10535
+ else:
10536
+ self.active_res2d.properties.select_node_by_node()
10066
10537
 
10067
10538
  if self.active_array is None and self.active_res2d is None:
10068
10539
  logging.warning(_('No active array or result 2D to select node by node !'))