wolfhece 2.2.29__py3-none-any.whl → 2.2.30__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.
@@ -1759,8 +1759,9 @@ class crosssections(Element_To_Draw):
1759
1759
  f=open(myfile,'r')
1760
1760
  lines=f.read().splitlines()
1761
1761
  f.close()
1762
- else:
1763
- lines=[]
1762
+ # For other formats (e.g. vecz)
1763
+ else:
1764
+ lines=[]
1764
1765
 
1765
1766
  self.myprofiles={}
1766
1767
  self.mygenprofiles={}
@@ -1880,36 +1881,6 @@ class crosssections(Element_To_Draw):
1880
1881
  logging.debug(name)
1881
1882
 
1882
1883
  nameprev=name
1883
- elif format=='vecz' or format=='zones':
1884
-
1885
- if isinstance(myfile, Zones):
1886
- self.filename=myfile.filename
1887
- tmpzones=myfile
1888
- elif isinstance(myfile, str):
1889
- self.filename=myfile
1890
- tmpzones=Zones(myfile, find_minmax=False)
1891
-
1892
- curzone:zone
1893
- curvec:vector
1894
- curzone=tmpzones.myzones[0]
1895
- index=0
1896
- for curvec in curzone.myvectors:
1897
-
1898
- self.myprofiles[curvec.myname]={}
1899
- curdict=self.myprofiles[curvec.myname]
1900
-
1901
- curdict['index']=index
1902
- curdict['left']=None
1903
- curdict['bed']=None
1904
- curdict['right']=None
1905
-
1906
- index+=1
1907
- curdict['cs']=profile(name=curvec.myname,parent=self)
1908
- cursect:profile
1909
- cursect=curdict['cs']
1910
-
1911
- cursect.myvertices = curvec.myvertices
1912
-
1913
1884
  elif format=='sxy':
1914
1885
  self.format='sxy'
1915
1886
  nbpotsect = int(lines[0])
@@ -1982,6 +1953,38 @@ class crosssections(Element_To_Draw):
1982
1953
  cursect.bankright=wolfvertex(rbs,rbz)
1983
1954
  curdict['right']=cursect.bankright
1984
1955
 
1956
+ # To make a distinction between cases for vecz
1957
+ elif len(lines)==0:
1958
+ if format=='vecz' or format=='zones':
1959
+
1960
+ if isinstance(myfile, Zones):
1961
+ self.filename=myfile.filename
1962
+ tmpzones=myfile
1963
+ elif isinstance(myfile, str):
1964
+ self.filename=myfile
1965
+ tmpzones=Zones(myfile, find_minmax=False)
1966
+
1967
+ curzone:zone
1968
+ curvec:vector
1969
+ curzone=tmpzones.myzones[0]
1970
+ index=0
1971
+ for curvec in curzone.myvectors:
1972
+
1973
+ self.myprofiles[curvec.myname]={}
1974
+ curdict=self.myprofiles[curvec.myname]
1975
+
1976
+ curdict['index']=index
1977
+ curdict['left']=None
1978
+ curdict['bed']=None
1979
+ curdict['right']=None
1980
+
1981
+ index+=1
1982
+ curdict['cs']=profile(name=curvec.myname,parent=self)
1983
+ cursect:profile
1984
+ cursect=curdict['cs']
1985
+
1986
+ cursect.myvertices = curvec.myvertices
1987
+
1985
1988
  self.verif_bed()
1986
1989
  self.find_minmax(True)
1987
1990
  self.init_cloud()
@@ -2506,7 +2509,7 @@ class crosssections(Element_To_Draw):
2506
2509
  self.xmax = 0
2507
2510
  self.ymax = 0
2508
2511
  return
2509
-
2512
+
2510
2513
  if update:
2511
2514
  for idx,vect in self.myprofiles.items():
2512
2515
  vect['cs'].find_minmax(only_firstlast = True)
wolfhece/PyDraw.py CHANGED
@@ -4208,6 +4208,15 @@ class WolfMapViewer(wx.Frame):
4208
4208
  else:
4209
4209
  return config[ConfigurationKeys.ACTIVE_VECTOR_COLOR]
4210
4210
 
4211
+ @property
4212
+ def active_vector_square_size(self) -> list[int]:
4213
+ """ Return the active vector square size from configs """
4214
+ config = self.get_configuration()
4215
+ if config is None:
4216
+ return 0
4217
+ else:
4218
+ return config[ConfigurationKeys.ACTIVE_VECTOR_SIZE_SQUARE]
4219
+
4211
4220
  @property
4212
4221
  def default_dem(self) -> Path:
4213
4222
  """ Return the default DEM file from configs """
@@ -15081,8 +15090,10 @@ class WolfMapViewer(wx.Frame):
15081
15090
  old = self.active_vector.myprop.color
15082
15091
  self.active_vector.myprop.color = getIfromRGB(self.active_vector_color)
15083
15092
  self.active_vector.plot()
15084
- self.active_vector._plot_square_at_vertices()
15093
+ self.active_vector._plot_square_at_vertices(size = self.active_vector_square_size)
15085
15094
  self.active_vector.myprop.color = old
15095
+ else:
15096
+ self.active_vector._plot_square_at_vertices(size = self.active_vector_square_size)
15086
15097
 
15087
15098
  if self.active_vector.myprop.plot_indices:
15088
15099
  self.active_vector._plot_all_indices(sx = self.sx, sy=self.sy,
@@ -15328,6 +15339,7 @@ class WolfMapViewer(wx.Frame):
15328
15339
  self.Active_zone(vect.parentzone)
15329
15340
 
15330
15341
  self.mimicme()
15342
+ self.Paint()
15331
15343
 
15332
15344
  def Active_zone(self, zone: zone):
15333
15345
  """ Active une zone et son parent si existant """
@@ -2594,6 +2594,13 @@ class vector:
2594
2594
  """
2595
2595
  Retrouve le segment associé aux paramètres passés
2596
2596
  """
2597
+
2598
+ if self.length2D is None or self.length3D is None:
2599
+ self.update_lengths()
2600
+ else:
2601
+ if len(self._lengthparts2D) != self.nbvertices-1 or len(self._lengthparts3D) != self.nbvertices-1:
2602
+ self.update_lengths()
2603
+
2597
2604
  if is3D:
2598
2605
  length = self.length3D
2599
2606
  lengthparts = self._lengthparts3D
@@ -2601,15 +2608,6 @@ class vector:
2601
2608
  length = self.length2D
2602
2609
  lengthparts = self._lengthparts2D
2603
2610
 
2604
- if length is None:
2605
- self.update_lengths()
2606
- if is3D:
2607
- length = self.length3D
2608
- lengthparts = self._lengthparts3D
2609
- else:
2610
- length = self.length2D
2611
- lengthparts = self._lengthparts2D
2612
-
2613
2611
  cums = np.cumsum(lengthparts)
2614
2612
 
2615
2613
  if adim:
@@ -2628,7 +2626,7 @@ class vector:
2628
2626
 
2629
2627
  if frombegin:
2630
2628
  k=0
2631
- while s>cums[k]:
2629
+ while s>cums[k] and k < self.nbvertices-2:
2632
2630
  k+=1
2633
2631
  else:
2634
2632
  k=self.nbvertices-2
@@ -4868,19 +4866,23 @@ class zone:
4868
4866
  veccenter = self.myvectors[0]
4869
4867
  veccenter.update_lengths()
4870
4868
 
4869
+ logging.info(_('Length of the center vector: {}').format(veccenter.length2D))
4870
+
4871
4871
  # Returned zone
4872
4872
  myparallels = zone()
4873
4873
 
4874
4874
  if interval_parallel is None :
4875
+ logging.warning(_('Interval between parallels is not defined --> set to farthest_parallel'))
4875
4876
  interval_parallel : farthest_parallel
4876
4877
 
4877
4878
  if interval_parallel > farthest_parallel:
4878
- logging.warning(_('dspar is greater than dpar --> dspar is set to dpar'))
4879
+ logging.warning(_('Interval between parallels is greater than farthest_parallel --> set to farthest_parallel'))
4879
4880
  interval_parallel = farthest_parallel
4880
4881
 
4881
4882
  # All parallel distances
4882
4883
  all_par = np.arange(0, farthest_parallel, interval_parallel)[1:]
4883
4884
  all_par = np.concatenate((all_par,[farthest_parallel]))
4885
+ logging.info(_('All parallel distances: {}').format(all_par))
4884
4886
 
4885
4887
  for curpar in tqdm(all_par):
4886
4888
  # add current parallel to the dicts
@@ -4895,22 +4897,28 @@ class zone:
4895
4897
  #
4896
4898
  # gestion de vecteurs d'intersection
4897
4899
  for curint in intersect.myvectors:
4900
+ if not curint.used:
4901
+ continue
4902
+
4898
4903
  # bouclage sur les vecteurs
4899
- curint2 = curint.parallel_offset(eps_offset, side='right')
4904
+ curint1 = curint.parallel_offset(-eps_offset/2., side='left')
4905
+ curint2 = curint.parallel_offset( eps_offset/2., side='right')
4900
4906
 
4901
4907
  # recherche si une intersection existe
4902
- pt, dist = vecleft[curpar].intersection(curint, eval_dist=True, force_single=True)
4908
+ pt, dist = vecleft[curpar].intersection(curint1, eval_dist=True, force_single=True)
4903
4909
  if pt is not None:
4910
+ logging.debug(_('Intersection found on left parallel at distance {}').format(dist))
4904
4911
  #Une intersection existe --> on ajoute la portion de vecteur
4905
4912
 
4906
4913
  # Projection du point d'intersection sur le vecteur à suivre
4907
- curls = curint.asshapely_ls()
4908
- dist2 = curls.project(pt)
4914
+ dist2 = curint1.linestring.project(pt)
4915
+
4909
4916
  # recherche de la portion de vecteur
4910
4917
  # subs = extrêmité -> intersection
4911
4918
  # subs_inv = intersection -> extrêmité
4912
- subs = curint.substring(0. , dist2, is3D=False, adim=False)
4919
+ subs = curint1.substring(0. , dist2, is3D=False, adim=False)
4913
4920
  subs.reverse()
4921
+
4914
4922
  subs2 = curint2.substring(0., dist2, is3D=False, adim=False)
4915
4923
 
4916
4924
  vec1 = vecleft[curpar].substring(0., dist, is3D=False, adim=False)
@@ -4925,13 +4933,19 @@ class zone:
4925
4933
  # mise à jour des caractéristiques
4926
4934
  vecleft[curpar].find_minmax()
4927
4935
  vecleft[curpar].update_lengths()
4936
+ vecleft[curpar].reset_linestring()
4937
+ curint1.reset_linestring()
4938
+ curint2.reset_linestring()
4928
4939
 
4929
- pt, dist = vecright[curpar].intersection(curint, eval_dist=True, force_single=True)
4940
+ pt, dist = vecright[curpar].intersection(curint1, eval_dist=True, force_single=True)
4930
4941
  if pt is not None:
4931
- curls = curint.asshapely_ls()
4932
- dist2 = curls.project(pt)
4942
+ logging.debug(_('Intersection found on right parallel at distance {}').format(dist))
4943
+
4944
+ dist2 = curint1.linestring.project(pt)
4945
+
4933
4946
  #Une intersection existe --> on ajoute la portion de vecteur
4934
- subs = curint.substring(0., dist2, is3D=False, adim=False)
4947
+ subs = curint1.substring(0., dist2, is3D=False, adim=False)
4948
+
4935
4949
  subs2 = curint2.substring(0., dist2, is3D=False, adim=False)
4936
4950
  subs2.reverse()
4937
4951
 
@@ -4940,8 +4954,11 @@ class zone:
4940
4954
 
4941
4955
  vecright[curpar].myvertices = vec1.myvertices.copy() + subs2.myvertices.copy() + subs.myvertices.copy() + vec2.myvertices.copy()
4942
4956
 
4943
- vecright[curpar].update_lengths()
4944
4957
  vecright[curpar].find_minmax()
4958
+ vecright[curpar].update_lengths()
4959
+ vecright[curpar].reset_linestring()
4960
+ curint1.reset_linestring()
4961
+ curint2.reset_linestring()
4945
4962
 
4946
4963
  #Shapely LineString
4947
4964
  lsl:dict[str,LineString] = {key:vec.asshapely_ls() for key,vec in vecleft.items()}
@@ -4960,7 +4977,7 @@ class zone:
4960
4977
  ptsc = [veccenter.interpolate(curs, is3D=False, adim=False) for curs in sloc]
4961
4978
  ptsc2 = [veccenter.interpolate(curs, is3D=False, adim=False) for curs in sloc2]
4962
4979
 
4963
- sc = [lsc.project(Point(curs.x, curs.y)) for curs in ptsc]
4980
+ sc = [lsc.project(Point(curs.x, curs.y)) for curs in ptsc]
4964
4981
  sc2 = [lsc.project(Point(curs.x, curs.y)) for curs in ptsc2]
4965
4982
 
4966
4983
  #Real distances along left, right and center vector
@@ -5001,9 +5018,9 @@ class zone:
5001
5018
 
5002
5019
  if howmanypoly==1:
5003
5020
  #un seul polygone sur base des // gauche et droite
5004
- zonepoly = zone(name='polygons_'+self.myname,parent=self.parent)
5021
+ zonepoly = zone(name='polygons_'+self.myname, parent=self.parent)
5005
5022
 
5006
- self.parent.add_zone(zonepoly)
5023
+ self.parent.add_zone(zonepoly, forceparent=True)
5007
5024
 
5008
5025
  for i in range(nb):
5009
5026
  ptc1 = sc[i]
@@ -5037,16 +5054,16 @@ class zone:
5037
5054
  #force to close the polygon
5038
5055
  curvec.close_force()
5039
5056
  #add vector to zone
5040
- zonepoly.add_vector(curvec)
5057
+ zonepoly.add_vector(curvec, forceparent=True)
5041
5058
 
5042
5059
  #force to update minmax in the zone --> mandatory to plot
5043
5060
  zonepoly.find_minmax(True)
5044
5061
  else:
5045
5062
  #deux polygones sur base des // gauche et droite
5046
- zonepolyleft = zone(name='polygons_left_'+self.myname,parent=self.parent)
5047
- zonepolyright = zone(name='polygons_right_'+self.myname,parent=self.parent)
5048
- self.parent.add_zone(zonepolyleft)
5049
- self.parent.add_zone(zonepolyright)
5063
+ zonepolyleft = zone(name='polygons_left_'+self.myname, parent=self.parent)
5064
+ zonepolyright = zone(name='polygons_right_'+self.myname, parent=self.parent)
5065
+ self.parent.add_zone(zonepolyleft, forceparent=True)
5066
+ self.parent.add_zone(zonepolyright, forceparent=True)
5050
5067
 
5051
5068
  for i in range(nb):
5052
5069
  ptc1 = sc[i]
@@ -5058,8 +5075,8 @@ class zone:
5058
5075
 
5059
5076
  #mean distance along center will be stored as Z value of each vertex
5060
5077
  smean =(ptc1+ptc2)/2.
5061
- curvecleft=vector(name='poly'+str(i+1),parentzone=zonepolyleft)
5062
- curvecright=vector(name='poly'+str(i+1),parentzone=zonepolyright)
5078
+ curvecleft=vector(name='poly'+str(i+1), parentzone=zonepolyleft)
5079
+ curvecright=vector(name='poly'+str(i+1), parentzone=zonepolyright)
5063
5080
 
5064
5081
  #Substring for Left and Right
5065
5082
  sublsl=vecleft[farthest_parallel].substring(pt1[-1], pt2[-1], is3D=False, adim=False)
@@ -5077,8 +5094,8 @@ class zone:
5077
5094
  downl.reverse()
5078
5095
  downr = [wolfvertex(pt[i].x, pt[i].y) for pt in ptr2.values()]
5079
5096
 
5080
- curvecleft.myvertices = sublsl.myvertices.copy() + downl[1:-1].copy() + [sublscr.myvertices.copy()] + upl[1:-1].copy()
5081
- curvecright.myvertices = sublsc.myvertices.copy() + downr[1:-1].copy() + [sublsr.myvertices.copy()] + upr[1:-1].copy()
5097
+ curvecleft.myvertices = sublsl.myvertices.copy() + downl[1:-1].copy() + sublscr.myvertices.copy() + upl[1:-1].copy()
5098
+ curvecright.myvertices = sublsc.myvertices.copy() + downr[1:-1].copy() + sublsr.myvertices.copy() + upr[1:-1].copy()
5082
5099
 
5083
5100
  for curvert in curvecleft.myvertices:
5084
5101
  curvert.z = smean
@@ -5096,6 +5113,9 @@ class zone:
5096
5113
 
5097
5114
  self._fill_structure()
5098
5115
 
5116
+ if self.get_mapviewer() is not None:
5117
+ self.get_mapviewer().Paint()
5118
+
5099
5119
  return myparallels
5100
5120
 
5101
5121
  def get_values_linked_polygons(self, linked_arrays, stats=True) -> dict:
@@ -7804,6 +7824,7 @@ class Zones(wx.Frame, Element_To_Draw):
7804
7824
  """
7805
7825
 
7806
7826
  if self.active_zone is None:
7827
+ logging.warning(_('No active zone - Nothing to do !'))
7807
7828
  return
7808
7829
 
7809
7830
  if self.wx_exists:
@@ -7813,25 +7834,81 @@ class Zones(wx.Frame, Element_To_Draw):
7813
7834
  logging.warning(_('The active zone must contain 3 vectors and only 3'))
7814
7835
  return
7815
7836
 
7816
- dlg=wx.NumberEntryDialog(None,_('What is the desired longitudinal size [cm] ?'),'ds','ds size',500,1,10000)
7817
- ret=dlg.ShowModal()
7818
- if ret==wx.ID_CANCEL:
7819
- dlg.Destroy()
7820
- return
7837
+ self.active_zone.myvectors[1].update_lengths()
7821
7838
 
7822
- ds=float(dlg.GetValue())/100.
7823
- dlg.Destroy()
7839
+ poly_dlg = wx.Dialog(None, title=_('Polygons from parallels options'), size=(400, 350))
7840
+ poly_dlg.SetBackgroundColour(wx.Colour(240, 240, 240))
7841
+ poly_sizer = wx.BoxSizer(wx.VERTICAL)
7842
+ poly_sizer.Add(wx.StaticText(poly_dlg, label=_('Polygons from parallels options')), 0, wx.ALL | wx.CENTER, 5)
7843
+ poly_sizer.Add(wx.StaticText(poly_dlg, label=_('This will create polygons from the parallels in the active zone')), 0, wx.ALL | wx.CENTER, 5)
7844
+ poly_sizer.Add(wx.StaticText(poly_dlg, label=_('Please enter the parameters below:')), 0, wx.ALL | wx.CENTER, 5)
7845
+ poly_sizer.Add(wx.StaticText(poly_dlg, label=_('Longitudinal size [cm]:')), 0, wx.ALL | wx.LEFT, 5)
7846
+ ds_text = wx.TextCtrl(poly_dlg, value='5000') # Default
7847
+ poly_sizer.Add(ds_text, 0, wx.ALL | wx.EXPAND, 5)
7848
+ poly_sizer.Add(wx.StaticText(poly_dlg, label=_('How many polygons? \n\n 1 = one large polygon from left to right\n 2 = two polygons - one left and one right')), 0, wx.ALL | wx.LEFT, 5)
7849
+ nb_text = wx.TextCtrl(poly_dlg, value='1') # Default
7850
+ poly_sizer.Add(nb_text, 0, wx.ALL | wx.EXPAND, 5)
7851
+ ok_button = wx.Button(poly_dlg, label=_('OK'))
7852
+ ok_button.Bind(wx.EVT_BUTTON, lambda evt: self._OnCreatePolygons(evt, ds_text, nb_text, poly_dlg))
7853
+ poly_sizer.Add(ok_button, 0, wx.ALL | wx.CENTER, 5)
7854
+ poly_dlg.SetSizer(poly_sizer)
7855
+ poly_dlg.Layout()
7856
+ poly_dlg.CentreOnParent()
7857
+ poly_dlg.ShowModal()
7824
7858
 
7825
- dlg=wx.NumberEntryDialog(None,_('How many polygons ? \n\n 1 = one large polygon from left to right\n 2 = two polygons - one left and one right'),'Number','Polygons',1,1,2)
7826
- ret=dlg.ShowModal()
7827
- if ret==wx.ID_CANCEL:
7828
- dlg.Destroy()
7859
+ # dlg=wx.NumberEntryDialog(None,_('What is the desired longitudinal size [cm] ?'),'ds','ds size',500,1,10000)
7860
+ # ret=dlg.ShowModal()
7861
+ # if ret==wx.ID_CANCEL:
7862
+ # dlg.Destroy()
7863
+ # return
7864
+
7865
+ # ds=float(dlg.GetValue())/100.
7866
+ # dlg.Destroy()
7867
+
7868
+ # dlg=wx.NumberEntryDialog(None,_('How many polygons ? \n\n 1 = one large polygon from left to right\n 2 = two polygons - one left and one right'),'Number','Polygons',1,1,2)
7869
+ # ret=dlg.ShowModal()
7870
+ # if ret==wx.ID_CANCEL:
7871
+ # dlg.Destroy()
7872
+ # return
7873
+
7874
+ # nb=int(dlg.GetValue())
7875
+ # dlg.Destroy()
7876
+
7877
+
7878
+ def _OnCreatePolygons(self, event:wx.MouseEvent, ds_text:wx.TextCtrl, nb_text:wx.TextCtrl, option_dialog:wx.Dialog):
7879
+ """
7880
+ Handle the creation of polygons based on user input from the dialog.
7881
+ """
7882
+
7883
+ try:
7884
+ ds = float(ds_text.GetValue()) / 100.0 # Convert cm to
7885
+ nb = int(nb_text.GetValue()) # Number of polygons
7886
+
7887
+ if ds <= 0:
7888
+ wx.MessageBox(_('Please enter a valid distance greater than 0.'), _('Input Error'), wx.OK | wx.ICON_ERROR)
7829
7889
  return
7830
7890
 
7831
- nb=int(dlg.GetValue())
7832
- dlg.Destroy()
7891
+ if ds > self.active_zone.myvectors[1].length2D:
7892
+ wx.MessageBox(_('The distance must be less than the length of the center vector in the active zone.'), _('Input Error'), wx.OK | wx.ICON_ERROR)
7893
+ return
7894
+
7895
+ if nb < 1 or nb > 2:
7896
+ wx.MessageBox(_('Please enter a valid number of polygons (1 or 2).'), _('Input Error'), wx.OK | wx.ICON_ERROR)
7897
+ return
7898
+ except ValueError:
7899
+ wx.MessageBox(_('Please enter valid numeric values for all fields.'), _('Input Error'), wx.OK | wx.ICON_ERROR)
7900
+ return
7833
7901
 
7902
+ try:
7834
7903
  self.active_zone.create_polygon_from_parallel(ds,nb)
7904
+ except Exception as e:
7905
+ logging.error(_('Error during polygon creation: {}').format(str(e)))
7906
+
7907
+ if self.get_mapviewer() is not None:
7908
+ self.get_mapviewer().Paint()
7909
+
7910
+ option_dialog.Destroy()
7911
+
7835
7912
 
7836
7913
  def Oncreateslidingpoly(self, event:wx.MouseEvent):
7837
7914
  """
@@ -7849,71 +7926,145 @@ class Zones(wx.Frame, Element_To_Draw):
7849
7926
  dlg.Destroy()
7850
7927
  return
7851
7928
 
7852
- #dialog box for length, sliding length, farthest parallel and parallel interval
7853
- dlg=wx.NumberEntryDialog(None,_('What is the desired longitudinal size [cm] ?'),'ds','ds size',5000,1,100000)
7854
- ret=dlg.ShowModal()
7855
- if ret==wx.ID_CANCEL:
7856
- dlg.Destroy()
7857
- return
7929
+ option_dialog = wx.Dialog(None, title=_('Sliding polygons options'), size=(450, 520))
7930
+ option_dialog.SetBackgroundColour(wx.Colour(240, 240, 240))
7931
+ option_sizer = wx.BoxSizer(wx.VERTICAL)
7932
+ option_sizer.Add(wx.StaticText(option_dialog, label=_('Sliding polygons options')), 0, wx.ALL | wx.CENTER, 5)
7933
+ option_sizer.Add(wx.StaticText(option_dialog, label=_('This will create sliding polygons from the active vector in the active zone')), 0, wx.ALL | wx.CENTER, 5)
7934
+ option_sizer.Add(wx.StaticText(option_dialog, label=_('Please enter the parameters below:')), 0, wx.ALL | wx.CENTER, 5)
7935
+ option_sizer.Add(wx.StaticText(option_dialog, label=_('Longitudinal size [cm]:')), 0, wx.ALL | wx.LEFT, 5)
7936
+ ds_text = wx.TextCtrl(option_dialog, value='5000') # Default value in cm
7937
+ option_sizer.Add(ds_text, 0, wx.ALL | wx.EXPAND, 5)
7938
+ option_sizer.Add(wx.StaticText(option_dialog, label=_('Sliding length [cm]:')), 0, wx.ALL | wx.LEFT, 5)
7939
+ sliding_text = wx.TextCtrl(option_dialog, value='5000') # Default value
7940
+ option_sizer.Add(sliding_text, 0, wx.ALL | wx.EXPAND, 5)
7941
+ option_sizer.Add(wx.StaticText(option_dialog, label=_('Farthest parallel [cm]:')), 0, wx.ALL | wx.LEFT, 5)
7942
+ farthest_text = wx.TextCtrl(option_dialog, value='10000') # Default
7943
+ option_sizer.Add(farthest_text, 0, wx.ALL | wx.EXPAND, 5)
7944
+ option_sizer.Add(wx.StaticText(option_dialog, label=_('Parallel interval [cm]:')), 0, wx.ALL | wx.LEFT, 5)
7945
+ interval_text = wx.TextCtrl(option_dialog, value='1000') # Default
7946
+ option_sizer.Add(interval_text, 0, wx.ALL | wx.EXPAND, 5)
7947
+
7948
+ intersect_sizer = wx.BoxSizer(wx.HORIZONTAL)
7949
+ inter_checkbox = wx.CheckBox(option_dialog, label=_('Use intersect zone if available'))
7950
+ inter_checkbox.SetValue(True) # Default to True
7951
+ offset_text = wx.TextCtrl(option_dialog, value='10') # Default offset value
7952
+ intersect_sizer.Add(inter_checkbox, 0, wx.ALL | wx.LEFT, 5)
7953
+ intersect_sizer.Add(wx.StaticText(option_dialog, label=_('Offset [cm]:')), 0, wx.ALL | wx.LEFT, 5)
7954
+ intersect_sizer.Add(offset_text, 0, wx.ALL | wx.EXPAND, 5)
7955
+ option_sizer.Add(wx.StaticText(option_dialog, label=_('If you have a zone named "intersect", you can use it to constrain the polygons.\nWhen constraint vectors are present, they cannot intersect the central vector.\nLikewise, they must be drawn moving away from the central vector.')), 0, wx.ALL | wx.CENTER, 5)
7956
+
7957
+ option_sizer.Add(intersect_sizer, 0, wx.ALL | wx.LEFT, 5)
7958
+ separate_checkbox = wx.CheckBox(option_dialog, label=_('Separate left and right polygons'))
7959
+ separate_checkbox.SetValue(False) # Default to False
7960
+ option_sizer.Add(separate_checkbox, 0, wx.ALL | wx.LEFT, 5)
7961
+ ok_button = wx.Button(option_dialog, label=_('OK'))
7962
+ ok_button.Bind(wx.EVT_BUTTON, lambda evt: self._OnCreateSlidingPolygon(evt, ds_text, sliding_text, farthest_text, interval_text, inter_checkbox, offset_text, separate_checkbox, option_dialog))
7963
+ option_sizer.Add(ok_button, 0, wx.ALL | wx.CENTER, 5)
7964
+ option_dialog.SetSizer(option_sizer)
7965
+ option_dialog.Layout()
7966
+ option_dialog.Centre()
7858
7967
 
7859
- ds=float(dlg.GetValue())/100.
7968
+ try:
7969
+ option_dialog.ShowModal()
7970
+ except:
7971
+ logging.error(_('Error during sliding polygons calculation.'))
7860
7972
 
7861
- dlg.Destroy()
7973
+ option_dialog.Destroy()
7862
7974
 
7863
- dlg=wx.NumberEntryDialog(None,_('What is the desired sliding length [cm] ?'),'sliding','sliding size',5000,1,100000)
7864
- ret=dlg.ShowModal()
7865
- if ret==wx.ID_CANCEL:
7866
- dlg.Destroy()
7975
+ def _OnCreateSlidingPolygon(self, event, ds_text, sliding_text, farthest_text, interval_text, inter_checkbox, offset_text, separate_checkbox, option_dialog:wx.Dialog):
7976
+ """
7977
+ Handle the creation of sliding polygons based on user input from the dialog.
7978
+ """
7979
+
7980
+ try:
7981
+ ds = float(ds_text.GetValue()) / 100.0 # Convert cm to m
7982
+ sliding = float(sliding_text.GetValue()) / 100.0 # Convert cm
7983
+ farthest = float(farthest_text.GetValue()) / 100.0 # Convert cm to m
7984
+ interval = float(interval_text.GetValue()) / 100.0 # Convert cm to
7985
+ intersect = inter_checkbox.GetValue() # Boolean value
7986
+ separate = separate_checkbox.GetValue() # Boolean value
7987
+ offset = float(offset_text.GetValue())/100.0 # Offset value in m
7988
+ except ValueError:
7989
+ wx.MessageBox(_('Please enter valid numeric values for all fields.'), _('Input Error'), wx.OK | wx.ICON_ERROR)
7867
7990
  return
7868
7991
 
7869
- sliding=float(dlg.GetValue())/100.
7992
+ if separate:
7993
+ howmany = 2 # Separate left and right polygons
7994
+ else:
7995
+ howmany = 1 # Single polygon
7870
7996
 
7871
- dlg.Destroy()
7997
+ # #dialog box for length, sliding length, farthest parallel and parallel interval
7998
+ # dlg=wx.NumberEntryDialog(None,_('What is the desired longitudinal size [cm] ?'),'ds','ds size',5000,1,100000)
7999
+ # ret=dlg.ShowModal()
8000
+ # if ret==wx.ID_CANCEL:
8001
+ # dlg.Destroy()
8002
+ # return
7872
8003
 
7873
- dlg=wx.NumberEntryDialog(None,_('What is the desired farthest parallel [cm] ?'),'farthest','farthest size',10000,1,100000)
7874
- ret=dlg.ShowModal()
7875
- if ret==wx.ID_CANCEL:
7876
- dlg.Destroy()
7877
- return
8004
+ # ds=float(dlg.GetValue())/100.
7878
8005
 
7879
- farthest=float(dlg.GetValue())/100.
8006
+ # dlg.Destroy()
7880
8007
 
7881
- dlg.Destroy()
8008
+ # dlg=wx.NumberEntryDialog(None,_('What is the desired sliding length [cm] ?'),'sliding','sliding size',5000,1,100000)
8009
+ # ret=dlg.ShowModal()
8010
+ # if ret==wx.ID_CANCEL:
8011
+ # dlg.Destroy()
8012
+ # return
7882
8013
 
7883
- dlg=wx.NumberEntryDialog(None,_('What is the desired parallel interval [cm] ?'),'interval','interval size',int(farthest*10.),1,int(farthest*100.))
7884
- ret=dlg.ShowModal()
7885
- if ret==wx.ID_CANCEL:
7886
- dlg.Destroy()
7887
- return
8014
+ # sliding=float(dlg.GetValue())/100.
7888
8015
 
7889
- interval=float(dlg.GetValue())/100.
8016
+ # dlg.Destroy()
7890
8017
 
7891
- dlg.Destroy()
8018
+ # dlg=wx.NumberEntryDialog(None,_('What is the desired farthest parallel [cm] ?'),'farthest','farthest size',10000,1,100000)
8019
+ # ret=dlg.ShowModal()
8020
+ # if ret==wx.ID_CANCEL:
8021
+ # dlg.Destroy()
8022
+ # return
7892
8023
 
7893
- zones_names=[curz.myname for curz in self.myzones]
7894
- if "intersect" in zones_names:
7895
- dlg = wx.MessageDialog(None,_('Do you want to use the intersect zone ?'),style=wx.YES_NO)
7896
- ret=dlg.ShowModal()
7897
- if ret==wx.ID_YES:
7898
- inter = True
7899
- else:
7900
- inter = False
7901
- dlg.Destroy()
7902
- else:
7903
- inter = False
8024
+ # farthest=float(dlg.GetValue())/100.
8025
+
8026
+ # dlg.Destroy()
8027
+
8028
+ # dlg=wx.NumberEntryDialog(None,_('What is the desired parallel interval [cm] ?'),'interval','interval size',int(farthest*10.),1,int(farthest*100.))
8029
+ # ret=dlg.ShowModal()
8030
+ # if ret==wx.ID_CANCEL:
8031
+ # dlg.Destroy()
8032
+ # return
8033
+
8034
+ # interval=float(dlg.GetValue())/100.
8035
+
8036
+ # dlg.Destroy()
8037
+
8038
+ zones_names=[curz.myname.lower() for curz in self.myzones]
8039
+ # if "intersect" in zones_names:
8040
+ # dlg = wx.MessageDialog(None,_('Do you want to use the intersect zone ?'),style=wx.YES_NO)
8041
+ # ret=dlg.ShowModal()
8042
+ # if ret==wx.ID_YES:
8043
+ # inter = True
8044
+ # else:
8045
+ # inter = False
8046
+ # dlg.Destroy()
8047
+ # else:
8048
+ # inter = False
7904
8049
 
7905
8050
  inter_zone = None
7906
- if inter:
7907
- inter_zone = self.myzones[zones_names.index("intersect")]
8051
+ if intersect:
8052
+ if "intersect" in zones_names:
8053
+ inter_zone = self.myzones[zones_names.index("intersect")]
8054
+
8055
+ # dlg = wx.MessageDialog(None,_('Do you want to separate left and right polygons ?'),style=wx.YES_NO)
8056
+ # ret=dlg.ShowModal()
8057
+ # if ret==wx.ID_YES:
8058
+ # howmany = 2
8059
+ # else:
8060
+ # howmany = 1
7908
8061
 
7909
- dlg = wx.MessageDialog(None,_('Do you want to separate left and right polygons ?'),style=wx.YES_NO)
7910
- ret=dlg.ShowModal()
7911
- if ret==wx.ID_YES:
7912
- howmany = 2
7913
- else:
7914
- howmany = 1
8062
+ try:
8063
+ self.active_zone.create_sliding_polygon_from_parallel(ds, sliding, farthest, interval, inter_zone, howmany, eps_offset=offset)
8064
+ except:
8065
+ logging.error(_('Error during sliding polygons calculation.'))
7915
8066
 
7916
- self.active_zone.create_sliding_polygon_from_parallel(ds, sliding, farthest, interval, inter_zone, howmany)
8067
+ option_dialog.Close()
7917
8068
 
7918
8069
 
7919
8070
  def Oncreatebin(self,event:wx.MouseEvent):
@@ -8605,9 +8756,15 @@ class Zones(wx.Frame, Element_To_Draw):
8605
8756
 
8606
8757
  self.active_zone.reset_listogl()
8607
8758
  self.myzones.pop(int(self.myzones.index(self.active_zone)))
8759
+ self.Activate_vector(None)
8760
+ self.Activate_zone(None)
8761
+
8608
8762
  self.fill_structure()
8609
8763
  self.find_minmax(True)
8610
8764
 
8765
+ if self.get_mapviewer() is not None:
8766
+ self.get_mapviewer().Paint()
8767
+
8611
8768
  def OnClickfindactivate_vector(self, event:wx.MouseEvent):
8612
8769
  """
8613
8770
  Recherche et activation d'un vecteur dans toutes les zones
@@ -8714,11 +8871,7 @@ class Zones(wx.Frame, Element_To_Draw):
8714
8871
  return
8715
8872
 
8716
8873
  curname=self.active_vector.myname
8717
- r = wx.MessageDialog(
8718
- None,
8719
- _('The vector {n} will be deleted. Continue?').format(n=curname),
8720
- style=wx.YES_NO | wx.ICON_QUESTION
8721
- ).ShowModal()
8874
+ r = wx.MessageDialog(None, _('The vector {n} will be deleted. Continue?').format(n=curname), style=wx.YES_NO | wx.ICON_QUESTION).ShowModal()
8722
8875
 
8723
8876
  if r != wx.ID_YES:
8724
8877
  return
@@ -8730,14 +8883,23 @@ class Zones(wx.Frame, Element_To_Draw):
8730
8883
 
8731
8884
  idx = int(actzone.myvectors.index(self.active_vector))
8732
8885
  if idx >= 0 and idx < actzone.nbvectors:
8886
+ actzone.reset_listogl()
8733
8887
  actzone.myvectors.pop(idx)
8734
8888
 
8735
- if actzone.nbvectors==0:
8889
+ if actzone.nbvectors == 0:
8736
8890
  self.Activate_vector(None)
8891
+ elif idx < actzone.nbvectors:
8892
+ self.Activate_vector(actzone.myvectors[idx])
8893
+ else:
8894
+ self.Activate_vector(actzone.myvectors[-1])
8737
8895
 
8738
8896
  self.fill_structure()
8739
8897
  self.find_minmax(True)
8740
8898
 
8899
+ if self.get_mapviewer() is not None:
8900
+ self.get_mapviewer().Paint()
8901
+
8902
+
8741
8903
  def OnClickup_vector(self, event:wx.MouseEvent):
8742
8904
  """Remonte le vecteur actif dans la liste de la zone"""
8743
8905
  if self.verify_activevec():
wolfhece/apps/version.py CHANGED
@@ -5,7 +5,7 @@ class WolfVersion():
5
5
 
6
6
  self.major = 2
7
7
  self.minor = 2
8
- self.patch = 29
8
+ self.patch = 30
9
9
 
10
10
  def __str__(self):
11
11
 
wolfhece/pyshields.py CHANGED
@@ -19,6 +19,7 @@ from .friction_law import f_barr_bathurst, f_colebrook, f_colebrook_pure
19
19
 
20
20
  RHO_PUREWATER = 1000. # kg/m3
21
21
  RHO_SEAWATER = 1025. # kg/m3
22
+ RHO_SEDIMENT = 2650. # kg/m3
22
23
  KIN_VISCOSITY = 1.e-6 # m2/s
23
24
  GRAVITY = 9.81 # m/s2
24
25
 
@@ -90,7 +91,7 @@ Autres :
90
91
 
91
92
  """
92
93
 
93
- def get_sadim(d:float, rhom:float =2650., rho:float =RHO_PUREWATER) -> float:
94
+ def get_sadim(d:float, rhom:float = RHO_SEDIMENT, rho:float =RHO_PUREWATER) -> float:
94
95
  """
95
96
  s_adim = d**(3/2) * ((s-1) * g)**.5 / (4 * nu)
96
97
 
@@ -99,7 +100,7 @@ def get_sadim(d:float, rhom:float =2650., rho:float =RHO_PUREWATER) -> float:
99
100
  s=rhom/rho
100
101
  return d**(3./2.) * ((s-1) * GRAVITY)**.5 / (4 * KIN_VISCOSITY)
101
102
 
102
- def get_dstar(d:float, rhom:float =2650., rho:float=RHO_PUREWATER) -> float:
103
+ def get_dstar(d:float, rhom:float = RHO_SEDIMENT, rho:float=RHO_PUREWATER) -> float:
103
104
  """ compute d* """
104
105
  s = rhom/rho
105
106
  return d*(GRAVITY*(s-1)/KIN_VISCOSITY**2)**(1./3.) #VanRijn Formula
@@ -110,7 +111,7 @@ def sadim2dstar(sadim:float) -> float:
110
111
  def dstar2sadim(dstar:float) -> float:
111
112
  return dstar**(3./2.) / 4
112
113
 
113
- def get_d_from_sadim(sadim:float, rhom:float=2650., rho:float=RHO_PUREWATER) -> float:
114
+ def get_d_from_sadim(sadim:float, rhom:float= RHO_SEDIMENT, rho:float=RHO_PUREWATER) -> float:
114
115
  """
115
116
  s_adim = d**(3/2) * ((s-1) * g)**.5 / (4 * nu)
116
117
 
@@ -119,7 +120,7 @@ def get_d_from_sadim(sadim:float, rhom:float=2650., rho:float=RHO_PUREWATER) ->
119
120
  s=rhom/rho
120
121
  return (sadim*(4*KIN_VISCOSITY)/math.sqrt((s-1)*GRAVITY))**(2/3)
121
122
 
122
- def get_d_from_dstar(dstar:float, rhom:float=2650., rho:float=RHO_PUREWATER) -> float:
123
+ def get_d_from_dstar(dstar:float, rhom:float= RHO_SEDIMENT, rho:float=RHO_PUREWATER) -> float:
123
124
  """
124
125
  d_star = d * (g * (s-1) / nu**2)**(1/3)
125
126
 
@@ -166,26 +167,38 @@ def get_psi_cr3(dstar:float) -> float:
166
167
  psicr = 0.13*dstar**-0.392*math.exp(-0.015*dstar**2.)+0.045*(1-math.exp(-0.068*dstar))
167
168
  return psicr
168
169
 
169
- # def get_shields_cr(d, rhom=2650., rho=RHO_PUREWATER, which=2):
170
- # """
171
- # Example:
172
- # [critical_shear_velocity, tau_cr,xadim_val, psicr] = get_shields_cr(0.2E-3, 2650)
173
- # """
170
+ def get_shields_cr(d, rhom = RHO_SEDIMENT, rho = RHO_PUREWATER, which=2):
171
+ """
172
+ :param d: grain diameter [m]
173
+ :param rhom: sediment density [kg/m3]
174
+ :param rho: water density [kg/m3]
175
+ :param which: which formula to use (default 2) -- see funcs = [(get_sadim, get_psi_cr), (get_dstar, get_psi_cr2), (get_dstar, get_psi_cr3)]
176
+
177
+ :return: [critical_shear_velocity, tau_cr, xadim_val, psicr]
178
+
179
+ Example:
180
+ [critical_shear_velocity, tau_cr, xadim_val, psicr] = get_shields_cr(0.2E-3, 2650)
181
+ """
182
+
183
+ assert which in [0, 1, 2], "which must be 0, 1 or 2"
174
184
 
175
- # funcs = [(get_sadim,get_psi_cr),(get_dstar,get_psi_cr2),(get_dstar,get_psi_cr3)]
176
- # # % Getting the sediment-fluid parameter
177
- # s = rhom/rho # [-]
178
- # denom_shields= (s-1)*GRAVITY*d # [m²/s²] en réalité denom/rho
185
+ funcs = [(get_sadim,get_psi_cr),
186
+ (get_dstar,get_psi_cr2),
187
+ (get_dstar,get_psi_cr3)]
179
188
 
180
- # xadim_val = funcs[which][0](d,rhom,rho)
181
- # psicr = funcs[which][1](xadim_val)
189
+ # % Getting the sediment-fluid parameter
190
+ s = rhom/rho # [-]
191
+ denom_shields= (s-1)*GRAVITY*d # [m²/s²] en réalité denom/rho
182
192
 
183
- # # Using the critical value of Shields parameter
184
- # # Knowing the maximum bottom shear stress
185
- # tau_cr = rho * denom_shields * psicr # Pa
186
- # critical_shear_velocity = math.sqrt(denom_shields * psicr) # m/s
193
+ xadim_val = funcs[which][0](d,rhom,rho)
194
+ psicr = funcs[which][1](xadim_val)
187
195
 
188
- # return [critical_shear_velocity, tau_cr,xadim_val, psicr]
196
+ # Using the critical value of Shields parameter
197
+ # Knowing the maximum bottom shear stress
198
+ tau_cr = rho * denom_shields * psicr # Pa
199
+ critical_shear_velocity = math.sqrt(denom_shields * psicr) # m/s
200
+
201
+ return [critical_shear_velocity, tau_cr, xadim_val, psicr]
189
202
 
190
203
  def _poly(x:float) -> float:
191
204
  return ((0.002235*x**5)-(0.06043*x**4)+(0.20307*x**3)+ \
@@ -204,7 +217,7 @@ def get_tau_from_psiadim(psiadim, d:float, rhom:float=2650, rho:float=RHO_PUREWA
204
217
  denom_shields= (s-1)*GRAVITY*d ## en réalité denom/rho
205
218
  return rho * denom_shields * psiadim
206
219
 
207
- def get_d_min(rhom:float=2650., rho:float=RHO_PUREWATER) -> float:
220
+ def get_d_min(rhom:float = RHO_SEDIMENT, rho:float=RHO_PUREWATER) -> float:
208
221
  return get_d_from_sadim(get_sadim_min(),rhom,rho)
209
222
 
210
223
  def _d_cr(x:float, tau_obj:float, rhom:float, rho:float, xadim:float, yadim:float) -> float:
@@ -215,66 +228,91 @@ def _d_cr(x:float, tau_obj:float, rhom:float, rho:float, xadim:float, yadim:floa
215
228
  psi_cr=yadim(xadim(x,rhom,rho))
216
229
  return psi_obj-psi_cr
217
230
 
218
- # def _get_d_cr(tau_cr,rhom=2650,rho=RHO_PUREWATER):
231
+ def _get_d_cr(tau_cr, rhom = RHO_SEDIMENT, rho=RHO_PUREWATER, which=2) -> float:
232
+ """ Critical diameter d_cr for Shields criterion
233
+
234
+ :param tau_cr: critical shear stress [Pa]
235
+ :param rhom: sediment density [kg/m3]
236
+ :param rho: water density [kg/m3]
237
+ :param which: which formula to use (default 2) -- see funcs = [(get_sadim, get_psi_cr), (get_dstar, get_psi_cr2), (get_dstar, get_psi_cr3)]
238
+ """
239
+
240
+ assert which in [0, 1, 2], "which must be 0, 1 or 2"
241
+
242
+ dminabs = 1.e-100
243
+ dmaxabs = 20
244
+ funcs = [(get_sadim, get_psi_cr),
245
+ (get_dstar, get_psi_cr2),
246
+ (get_dstar, get_psi_cr3)]
219
247
 
220
- # dminabs = 1.e-6
221
- # dmaxabs = .5
222
- # d_cr = root_scalar(_d_cr,(tau_cr,rhom,rho,get_sadim,get_psi_cr),'bisect',bracket=[dminabs, dmaxabs])
248
+ d_cr = root_scalar(_d_cr,(tau_cr, rhom, rho, funcs[which][0],funcs[which][1]), 'bisect', bracket=[dminabs, dmaxabs])
223
249
 
224
- # return d_cr
250
+ return d_cr.root
225
251
 
226
- def get_d_cr(q:float, h:float, K:float, rhom:float=2650., rho:float=RHO_PUREWATER, method='brenth', which=2) -> list[float]:
252
+ def get_d_cr(q:float, h:float, K:float,
253
+ rhom:float = RHO_SEDIMENT, rho:float=RHO_PUREWATER,
254
+ method='brenth', which=2,
255
+ friction_law:Literal['Strickler', 'Colebrook'] = 'Strickler') -> list[float]:
227
256
  """
228
257
  Diamètre critique d'emportement par :
229
258
  - Shields
230
259
  - Izbach
231
260
 
232
- :param q : discharge [m3/s]
233
- :param h : water depth [m]
234
- :param K : Strickler friction coefficient [m1/3/s]
235
- :param rhom : sediment density [kg/m3]
236
- :param rho : water density [kg/m3]
237
- :param method : method to solve the equation (default 'brenth')
238
- :param which : which formula to use (default 2) -- see funcs = [(get_sadim,get_psi_cr),(get_dstar,get_psi_cr2),(get_dstar,get_psi_cr3)]
261
+ :param q: discharge [m3/s]
262
+ :param h: water depth [m]
263
+ :param K: Strickler friction coefficient [m1/3/s]
264
+ :param rhom: sediment density [kg/m3]
265
+ :param rho: water density [kg/m3]
266
+ :param method: method to solve the equation (default 'brenth')
267
+ :param which: which formula to use (default 2) -- see funcs = [(get_sadim,get_psi_cr),(get_dstar,get_psi_cr2),(get_dstar,get_psi_cr3)]
239
268
  """
269
+
270
+ assert which in [0, 1, 2], "which must be 0, 1 or 2"
271
+ assert friction_law in ['Strickler', 'Colebrook'], "friction_law must be 'Strickler' or 'Colebrook'"
272
+
240
273
  if q==0.:
241
274
  return 0.,0.
242
275
 
243
- tau_cr = (q/K)**2 / h**(7/3) * rho * GRAVITY # rho*g*h*J
276
+ # tau_cr = (q/K)**2 / h**(7/3) * rho * GRAVITY # rho*g*h*J
277
+ if friction_law == 'Strickler':
278
+ tau_cr = get_friction_slope_2D_Manning(q, h, 1/K) * rho * GRAVITY * h # rho*g*h*J
279
+ elif friction_law == 'Colebrook':
280
+ tau_cr = get_friction_slope_2D_Colebrook(q, h, K) * rho * GRAVITY * h
281
+
244
282
  dminabs = 1.e-100
245
283
  dmaxabs = 20
246
284
 
247
285
  funcs = [(get_sadim, get_psi_cr),(get_dstar, get_psi_cr2),(get_dstar, get_psi_cr3)]
248
286
 
249
287
  try:
250
- d_cr = root_scalar(_d_cr,(tau_cr,rhom,rho,funcs[which][0],funcs[which][1]),method,bracket=[dminabs, dmaxabs],rtol = 1e-2)
288
+ d_cr = root_scalar(_d_cr,(tau_cr,rhom,rho,funcs[which][0],funcs[which][1]), method, bracket=[dminabs, dmaxabs], rtol = 1e-2)
251
289
  return d_cr.root, izbach_d_cr(q,h,rhom,rho)
252
290
  except:
253
291
  izbach = izbach_d_cr(q,h,rhom,rho)
254
292
  return izbach,izbach
255
293
 
256
- def get_settling_vel(d:float, rhom:float=2650., rho:float=RHO_PUREWATER) -> float:
294
+ def get_settling_vel(d:float, rhom:float= RHO_SEDIMENT, rho:float=RHO_PUREWATER) -> float:
257
295
  """
258
296
  Vitesse de chute
259
297
 
260
- :param d : grain diameter [m]
261
- :param rhom : sediment density [kg/m3]
262
- :param rho : water density [kg/m3]
298
+ :param d: grain diameter [m]
299
+ :param rhom: sediment density [kg/m3]
300
+ :param rho: water density [kg/m3]
263
301
  """
264
302
  dstar = get_dstar(d,rhom,rho)
265
303
  ws = KIN_VISCOSITY/d*(math.sqrt(25+1.2*dstar**2.)-5)**(3./2.)
266
304
  return ws
267
305
 
268
- def get_Rouse(d:float, q:float, h:float, K:float, rhom:float=2650., rho:float=RHO_PUREWATER) -> float:
306
+ def get_Rouse(d:float, q:float, h:float, K:float, rhom:float= RHO_SEDIMENT, rho:float=RHO_PUREWATER) -> float:
269
307
  """
270
308
  Vitesse de chute
271
309
 
272
- :param d : grain diameter [m]
273
- :param q : discharge [m3/s]
274
- :param h : water depth [m]
275
- :param K : Strickler friction coefficient [m1/3/s]
276
- :param rhom : sediment density [kg/m3]
277
- :param rho : water density [kg/m3]
310
+ :param d: grain diameter [m]
311
+ :param q: discharge [m3/s]
312
+ :param h: water depth [m]
313
+ :param K: Strickler friction coefficient [m1/3/s]
314
+ :param rhom: sediment density [kg/m3]
315
+ :param rho: water density [kg/m3]
278
316
  """
279
317
  # tau_cr = (q/K)**2 / h**(7/3) * rho * GRAVITY
280
318
  # shear_vel = math.sqrt(tau_cr/rho)
@@ -285,16 +323,16 @@ def get_Rouse(d:float, q:float, h:float, K:float, rhom:float=2650., rho:float=RH
285
323
 
286
324
  return ws/(k*shear_vel)
287
325
 
288
- def _get_Rouse(d:float, q:float, h:float, K:float, rhom:float=2650., rho:float=RHO_PUREWATER, frac:float=50) -> float:
326
+ def _get_Rouse(d:float, q:float, h:float, K:float, rhom:float= RHO_SEDIMENT, rho:float=RHO_PUREWATER, frac:float=50) -> float:
289
327
  """
290
328
  Settling velocity function -- used in root_scalar
291
329
 
292
- :param d : grain diameter [m]
293
- :param q : discharge [m3/s]
294
- :param h : water depth [m]
295
- :param K : Strickler friction coefficient [m1/3/s]
296
- :param rhom : sediment density [kg/m3]
297
- :param rho : water density [kg/m3]
330
+ :param d: grain diameter [m]
331
+ :param q: discharge [m3/s]
332
+ :param h: water depth [m]
333
+ :param K: Strickler friction coefficient [m1/3/s]
334
+ :param rhom: sediment density [kg/m3]
335
+ :param rho: water density [kg/m3]
298
336
  """
299
337
  # tau_cr = (q/K)**2 / h**(7/3) * rho * GRAVITY
300
338
  # shear_vel = math.sqrt(tau_cr/rho)
@@ -313,18 +351,18 @@ def _get_Rouse(d:float, q:float, h:float, K:float, rhom:float=2650., rho:float=R
313
351
  elif frac==100:
314
352
  return rouse-1.2
315
353
 
316
- def get_transport_mode(d:float, q:float, h:float, K:float, rhom:float=2650., rho:float=RHO_PUREWATER): # -> BED_LOAD | SUSPENDED_LOAD_50 | SUSPENDED_LOAD_100 | WASH_LOAD:
354
+ def get_transport_mode(d:float, q:float, h:float, K:float, rhom:float= RHO_SEDIMENT, rho:float=RHO_PUREWATER): # -> BED_LOAD | SUSPENDED_LOAD_50 | SUSPENDED_LOAD_100 | WASH_LOAD:
317
355
  """
318
356
  Transport mode
319
357
 
320
358
  return in [BED_LOAD, SUSPENDED_LOAD_50, SUSPENDED_LOAD_100, WASH_LOAD]
321
359
 
322
- :param d : grain diameter [m]
323
- :param q : discharge [m3/s]
324
- :param h : water depth [m]
325
- :param K : Strickler friction coefficient [m1/3/s]
326
- :param rhom : sediment density [kg/m3]
327
- :param rho : water density [kg/m3]
360
+ :param d: grain diameter [m]
361
+ :param q: discharge [m3/s]
362
+ :param h: water depth [m]
363
+ :param K: Strickler friction coefficient [m1/3/s]
364
+ :param rhom: sediment density [kg/m3]
365
+ :param rho: water density [kg/m3]
328
366
 
329
367
  """
330
368
 
@@ -338,15 +376,15 @@ def get_transport_mode(d:float, q:float, h:float, K:float, rhom:float=2650., rho
338
376
  else:
339
377
  return WASH_LOAD
340
378
 
341
- def get_d_cr_susp(q:float, h:float, K:float, rhom:float=2650., rho:float=RHO_PUREWATER, method='brenth', which=50) -> float:
379
+ def get_d_cr_susp(q:float, h:float, K:float, rhom:float= RHO_SEDIMENT, rho:float=RHO_PUREWATER, method='brenth', which=50) -> float:
342
380
  """
343
381
  Diamètre critique d'emportement par suspension à 50% --> cf Rouse 1.2
344
382
 
345
- :param q : discharge [m3/s]
346
- :param h : water depth [m]
347
- :param K : Strickler friction coefficient [m1/3/s]
348
- :param rhom : sediment density [kg/m3]
349
- :param rho : water density [kg/m3]
383
+ :param q: discharge [m3/s]
384
+ :param h: water depth [m]
385
+ :param K: Strickler friction coefficient [m1/3/s]
386
+ :param rhom: sediment density [kg/m3]
387
+ :param rho: water density [kg/m3]
350
388
 
351
389
  """
352
390
  if q==0.:
@@ -360,8 +398,13 @@ def get_d_cr_susp(q:float, h:float, K:float, rhom:float=2650., rho:float=RHO_PUR
360
398
  except:
361
399
  return 0.
362
400
 
363
- def shieldsdia_sadim(s_psicr=None, dstar_psicr=None, rhom=2650., rho=RHO_PUREWATER, figax=None) -> tuple[plt.Figure,plt.Axes]:
364
- """ Plot Shields diagram with sadim"""
401
+ def shieldsdia_sadim(s_psicr=None, dstar_psicr=None, figax=None) -> tuple[plt.Figure,plt.Axes]:
402
+ """ Plot Shields diagram with sadim as x-axis
403
+
404
+ :param s_psicr: tuple (S, psicr) for a specific point to plot on the diagram
405
+ :param dstar_psicr: tuple (dstar, psicr) for a specific point to plot on the diagram
406
+ :param figax: tuple (fig, ax) to plot on a specific figure and axes
407
+ """
365
408
 
366
409
  smax = 1000
367
410
  rangoS = np.arange(0.1,smax,0.1)
@@ -416,8 +459,13 @@ def shieldsdia_sadim(s_psicr=None, dstar_psicr=None, rhom=2650., rho=RHO_PUREWAT
416
459
 
417
460
  return fig,ax
418
461
 
419
- def shieldsdia_dstar(s_psicr=None, dstar_psicr=None, rhom=2650., rho=RHO_PUREWATER, figax=None) -> tuple[plt.Figure,plt.Axes]:
420
- """ Plot Shields diagram with dstar"""
462
+ def shieldsdia_dstar(s_psicr=None, dstar_psicr=None, figax=None) -> tuple[plt.Figure,plt.Axes]:
463
+ """ Plot Shields diagram with dstar as x-axis
464
+
465
+ :param s_psicr: tuple (S, psicr) for a specific point to plot on the diagram
466
+ :param dstar_psicr: tuple (dstar, psicr) for a specific point to plot on the diagram
467
+ :param figax: tuple (fig, ax) to plot on a specific figure and axes
468
+ """
421
469
 
422
470
  smax = 1000
423
471
  d_stars = np.arange(0.1,smax,0.1)
@@ -517,9 +565,9 @@ def get_friction_slope_2D_Manning(q:float, h:float, n:float) -> float:
517
565
  """
518
566
  Compute friction slope j for 2D flow with Manning/Strickler friction law
519
567
 
520
- :param q : discharge [m3/s]
521
- :param h : water depth [m]
522
- :param n : Manning friction coefficient [m-1/3.s]
568
+ :param q: discharge [m3/s]
569
+ :param h: water depth [m]
570
+ :param n: Manning friction coefficient [m^{-1/3}.s]
523
571
  """
524
572
 
525
573
  denom = h**(4./3.)
@@ -530,13 +578,24 @@ def get_friction_slope_2D_Manning(q:float, h:float, n:float) -> float:
530
578
 
531
579
  return j
532
580
 
581
+ def get_friction_slope_2D_Strickler(q:float, h:float, K:float) -> float:
582
+ """
583
+ Compute friction slope j for 2D flow with Strickler friction law
584
+
585
+ :param q: discharge [m3/s]
586
+ :param h: water depth [m]
587
+ :param K: Strickler friction coefficient [m^{1/3}/s]
588
+ """
589
+
590
+ return get_friction_slope_2D_Manning(q, h, 1./K) # n = 1/K
591
+
533
592
  def get_friction_slope_2D_Colebrook(q:float, h:float, K:float) -> float:
534
593
  """
535
594
  Compute friction slope j for 2D flow with Colebrook-White friction law
536
595
 
537
- :param q : discharge [m3/s]
538
- :param h : water depth [m]
539
- :param K : Colebrook-White friction coefficient [m]
596
+ :param q: discharge [m3/s]
597
+ :param h: water depth [m]
598
+ :param K: height of roughness [m] - will be used to compute k/D or k/(4h) in 2D flow
540
599
  """
541
600
 
542
601
  four_hydraulic_radius = 4.0 * h
@@ -554,10 +613,10 @@ def get_shear_velocity_2D_Manning(q:float, h:float, n:float) -> float:
554
613
  """
555
614
  Compute shear velocity u_* for 2D flow with Manning/Strickler friction law
556
615
 
557
- :param j : friction slope [-]
558
- :param h : water depth [m]
559
- :param q : discharge [m3/s]
560
- :param n : Manning friction coefficient [m-1/3.s]
616
+ :param j: friction slope [-]
617
+ :param h: water depth [m]
618
+ :param q: discharge [m3/s]
619
+ :param n: Manning friction coefficient [m-1/3.s]
561
620
  """
562
621
 
563
622
  j = get_friction_slope_2D_Manning(q,h,n)
@@ -570,10 +629,10 @@ def get_shear_velocity_2D_Colebrook(q:float, h:float, K:float) -> float:
570
629
  """
571
630
  Compute shear velocity u_* for 2D flow with Colebrook-White friction law
572
631
 
573
- :param j : friction slope [-]
574
- :param h : water depth [m]
575
- :param q : discharge [m3/s]
576
- :param K : Colebrook-White friction coefficient [m]
632
+ :param j: friction slope [-]
633
+ :param h: water depth [m]
634
+ :param q: discharge [m3/s]
635
+ :param K: Colebrook-White friction coefficient [m]
577
636
  """
578
637
 
579
638
  j = get_friction_slope_2D_Colebrook(q,h,K)
@@ -586,11 +645,11 @@ def get_Shields_2D_Manning(s:float, d:float, q:float, h:float, n:float) -> float
586
645
  """
587
646
  Compute Shields dimensionless parameter for 2D flow with Manning/Strickler friction law
588
647
 
589
- :param s : sediment density / water density [-]
590
- :param d : sediment diameter [m]
591
- :param q : discharge [m3/s]
592
- :param h : water depth [m]
593
- :param n : Manning friction coefficient [m-1/3.s]
648
+ :param s: sediment density / water density [-]
649
+ :param d: sediment diameter [m]
650
+ :param q: discharge [m3/s]
651
+ :param h: water depth [m]
652
+ :param n: Manning friction coefficient [m-1/3.s]
594
653
 
595
654
  See also get_Shields_2D_Strickler
596
655
  """
@@ -607,11 +666,11 @@ def get_Shields_2D_Strickler(s:float, d:float, q:float, h:float, K:float) -> flo
607
666
  """
608
667
  Compute Shields dimensionless parameter for 2D flow with Manning/Strickler friction law
609
668
 
610
- :param s : sediment density / water density [-]
611
- :param d : sediment diameter [m]
612
- :param q : discharge [m3/s]
613
- :param h : water depth [m]
614
- :param K : Strickler friction coefficient [m1/3/s]
669
+ :param s: sediment density / water density [-]
670
+ :param d: sediment diameter [m]
671
+ :param q: discharge [m3/s]
672
+ :param h: water depth [m]
673
+ :param K: Strickler friction coefficient [m1/3/s]
615
674
 
616
675
  See also get_Shields_2D_Manning
617
676
  """
@@ -631,21 +690,23 @@ def izbach_d_cr(q:float, h:float, rhom:float=2650, rho:float=RHO_PUREWATER, meth
631
690
  (s-1) = (rho_m - rho) / rho
632
691
  u_c = 85% u_moyen)
633
692
 
634
- --> d = u_c**2 / (s * g) / 1.7**2
693
+ --> d = u_c**2 / ((s-1) * g) / 1.7**2
635
694
 
636
- --> d = (0.85 * q/h)**2 / (s * g) / 1.7**2
695
+ --> d = (0.85 * q/h)**2 / ((s-1) * g) / 1.7**2
637
696
 
638
- :param q : discharge [m3/s]
639
- :param h : water depth [m]
640
- :param rhom : sediment density [kg/m3]
641
- :param rho : water density [kg/m3]
642
- :param method : method to solve the equation (default 'ridder')
697
+ :param q: discharge [m3/s]
698
+ :param h: water depth [m]
699
+ :param rhom: sediment density [kg/m3]
700
+ :param rho: water density [kg/m3]
701
+ :param method: method to solve the equation (default 'ridder')
643
702
  """
644
703
  s = rhom/rho
645
704
  # (0.85 * q/h)**2. / ((s-1.) * GRAVITY) / 1.7**2.
646
- # <=> 0.7 * (0.85*q/h)**2. / (2 * GRAVITY) / (s-1.)
647
- # <=> (q/h)**2. / (2 * GRAVITY) / (s-1.) / .86**2
648
- return (q/h)**2. / (2 * GRAVITY) / (s-1.) / 1.2**2
705
+ # avec (2 / 1.7**2) = 0.692041... = 0.7
706
+ # <=> 0.7 * (0.85 * q/h)**2. / (2 * GRAVITY) / (s-1.)
707
+ # <=> (q/h)**2. / (2 * GRAVITY) / (s-1.) / 1.406**2
708
+
709
+ return (q/h)**2. / (2 * GRAVITY) / (s-1.) / 1.2**2 # We are using 1.2 instead of 1.406 -- see GCIV2035-1 - Hydrodynamique fluviale
649
710
 
650
711
 
651
712
  ## Portage de WOLF2D - Fortran pour Barr-Bathurst
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wolfhece
3
- Version: 2.2.29
3
+ Version: 2.2.30
4
4
  Author-email: Pierre Archambeau <pierre.archambeau@uliege.be>
5
5
  Project-URL: Homepage, https://uee.uliege.be/hece
6
6
  Project-URL: Issues, https://uee.uliege.be/hece
@@ -7,8 +7,8 @@ wolfhece/ManageParams.py,sha256=EeuUI5Vvh9ixCvYf8YShMC1s1Yacc7OxOCN7q81gqiQ,517
7
7
  wolfhece/Model1D.py,sha256=snEmu8Uj2YGcp1ybPnly-4A389XRnuOujGduqInNcgw,477001
8
8
  wolfhece/PandasGrid.py,sha256=YIleVkUkoP2MjtQBZ9Xgwk61zbgMj4Pmjj-clVTfPRs,2353
9
9
  wolfhece/PyConfig.py,sha256=Zs9852UnTMDjiH9RhC_-cQdOowDaS1U5PbmmU9nEpv0,18265
10
- wolfhece/PyCrosssections.py,sha256=igU_ELrg5VrHU6RNbF5tHxPyVImpR3xdpfopJYc7haw,114711
11
- wolfhece/PyDraw.py,sha256=-hPVoASNtB7k9_P7F3uq-4Vqytie4wjEL36OUiqtszQ,671455
10
+ wolfhece/PyCrosssections.py,sha256=iSmuQ1753bWxRLgOkrRLPd3tiMwGRCvfKD2Mim26_8c,114836
11
+ wolfhece/PyDraw.py,sha256=cloYUTYk6tTCuSmBehVcz2DOadkb7J5w9i1ihBilT2Q,671960
12
12
  wolfhece/PyGui.py,sha256=DqMTDsC9GthnMdYOXvkMKfl5pNciExVzxG4ogptWf6g,146010
13
13
  wolfhece/PyGuiHydrology.py,sha256=sKafpOopBg50L5llZCI_fZtbebVTDtxvoRI6-osUwhg,14745
14
14
  wolfhece/PyHydrographs.py,sha256=1P5XAURNqCvtSsMQXhOn1ihjTpr725sRsZdlCEhhk6M,3730
@@ -17,7 +17,7 @@ wolfhece/PyParams.py,sha256=BgTAwxxq831rYEq_KLcFBX_upjiSUpVtfoQnCxCNWUI,100443
17
17
  wolfhece/PyPictures.py,sha256=m1kY0saW6Y9Q0bDCo47lW6XxDkBrbQG-Fd8uVn8G5ic,2514
18
18
  wolfhece/PyTranslate.py,sha256=4appkmNeHHZLFmUtaA_k5_5QL-5ymxnbVN4R2OblmtE,622
19
19
  wolfhece/PyVertex.py,sha256=a56oY1NB45QnwARg96Tbnq-z-mhZKFkYOkFOO1lNtlk,51056
20
- wolfhece/PyVertexvectors.py,sha256=DZpuqfzAEWAtGJ5oSzRY0kRMlkwErogcGMJQOh6niDE,341983
20
+ wolfhece/PyVertexvectors.py,sha256=-MIgo6-PVir2NxQn6RoOdpEkqfrJv8Ts6_FjEZqXJC4,351630
21
21
  wolfhece/PyWMS.py,sha256=XcSlav5icct2UwV7K2r7vpxa5rKZWiHkp732lI94HFI,31534
22
22
  wolfhece/RatingCurve.py,sha256=bUjIrQjvIjkD4V-z8bZmA6pe1ILtYNM0-3fT6YUY1RU,22498
23
23
  wolfhece/RatingCurveData.py,sha256=5UvnIm89BwqjnEbLCcY3CA8WoFd_xHJbooNy62fX5iY,57660
@@ -53,7 +53,7 @@ wolfhece/pybridges.py,sha256=bFAqjL4ColeJtwvyCPGQ8VllWoq1RbVWXxFrdfrvqm8,65954
53
53
  wolfhece/pydike.py,sha256=dRb6qGkqoTXjf107KcajcIk1F_FuMPaOZLSwixT3dgA,11196
54
54
  wolfhece/pylogging.py,sha256=4TI8hgBB65z-zpvU5Rfa2jkPXPhJaqXjHVPwbcdzTNc,4528
55
55
  wolfhece/pypolygons_scen.py,sha256=dG4zyJL_t5wgDqRfe-OqSH-fnxUt-su1H-tM3K3wHnc,46339
56
- wolfhece/pyshields.py,sha256=ymH393EQys2aZmh41ccJnWmmlF7dVa-eTY32jFgwK08,25269
56
+ wolfhece/pyshields.py,sha256=KMtUO5kD0lisKnJD1NsDz-qaY5DpFcmS4O3WkXtUSmo,27898
57
57
  wolfhece/pyviews.py,sha256=zuZjWUptRDm1MTE1PN4Xj_qSITnojgDMG0LlFIBH3SE,13739
58
58
  wolfhece/pywalous.py,sha256=mWB7UxlYMIbPxNUDlONQEjcOOy9VSaRU9aYWZ5IFLu8,19164
59
59
  wolfhece/rain_SPWMI.py,sha256=qCfcmF7LajloOaCwnTrrSMzyME03YyilmRUOqrPrv3U,13846
@@ -88,7 +88,7 @@ wolfhece/apps/curvedigitizer.py,sha256=lEJJwgAfulrrWQc-U6ij6sj59hWN3SZl4Yu1kQxVz
88
88
  wolfhece/apps/hydrometry.py,sha256=lhhJsFeb4zGL4bNQTs0co85OQ_6ssL1Oy0OUJCzhfYE,656
89
89
  wolfhece/apps/isocurrent.py,sha256=dagmGR8ja9QQ1gwz_8fU-N052hIw-W0mWGVkzLu6C7I,4247
90
90
  wolfhece/apps/splashscreen.py,sha256=EdGDN9NhudIiP7c3gVqj7dp4MWFB8ySizM_tpMnsgpE,3091
91
- wolfhece/apps/version.py,sha256=MsRPVPFz_Nd-g9QBhzEMZR5szCY4WxPCUofNwlSWVMA,388
91
+ wolfhece/apps/version.py,sha256=TbVLaOlu0bvthJf8mZ0I5HvlwlTNg4-IrIDSbM0cAAU,388
92
92
  wolfhece/apps/wolf.py,sha256=mRnjYsUu4KIsRuamdQWAINFMuwN4eJgMo9erG-hkZ70,729
93
93
  wolfhece/apps/wolf2D.py,sha256=4z_OPQ3IgaLtjexjMKX9ppvqEYyjFLt1hcfFABy3-jU,703
94
94
  wolfhece/apps/wolf_logo.bmp,sha256=ruJ4MA51CpGO_AYUp_dB4SWKHelvhOvd7Q8NrVOjDJk,3126
@@ -307,8 +307,8 @@ wolfhece/ui/wolf_multiselection_collapsiblepane.py,sha256=u4C7CXe_bUyGKx7c_Bi0x9
307
307
  wolfhece/ui/wolf_times_selection_comparison_models.py,sha256=ORy7fz4dcp691qKzaOZHrRLZ0uXNhL-LIHxmpDGL6BI,5007
308
308
  wolfhece/wintab/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
309
309
  wolfhece/wintab/wintab.py,sha256=8A-JNONV6ujgsgG3lM5Uw-pVgglPATwKs86oBzzljoc,7179
310
- wolfhece-2.2.29.dist-info/METADATA,sha256=35R9m7_Q5LYcKUXvUBBwZ8p1A-JMWrMYn5VtO4ncgNw,2729
311
- wolfhece-2.2.29.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
312
- wolfhece-2.2.29.dist-info/entry_points.txt,sha256=Jr187pyvA3EeJiQLjZK9yo6mJX7IAn6ygZU9T8qF_gQ,658
313
- wolfhece-2.2.29.dist-info/top_level.txt,sha256=EfqZXMVCn7eILUzx9xsEu2oBbSo9liWPFWjIHik0iCI,9
314
- wolfhece-2.2.29.dist-info/RECORD,,
310
+ wolfhece-2.2.30.dist-info/METADATA,sha256=6DgxvLnytFPLyQpPZ2b0ZoyBqOe-rb98b-jm6FTw9Os,2729
311
+ wolfhece-2.2.30.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
312
+ wolfhece-2.2.30.dist-info/entry_points.txt,sha256=Jr187pyvA3EeJiQLjZK9yo6mJX7IAn6ygZU9T8qF_gQ,658
313
+ wolfhece-2.2.30.dist-info/top_level.txt,sha256=EfqZXMVCn7eILUzx9xsEu2oBbSo9liWPFWjIHik0iCI,9
314
+ wolfhece-2.2.30.dist-info/RECORD,,