wolfhece 2.0.55__py3-none-any.whl → 2.1.1__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/PyVertex.py CHANGED
@@ -169,6 +169,19 @@ class wolfvertex:
169
169
  self.y = max(self.y, bounds[1][0])
170
170
  self.y = min(self.y, bounds[1][1])
171
171
 
172
+ def is_like(self, v:"wolfvertex", tol:float=1.e-6):
173
+ """
174
+ Return True if the vertex is close to another one
175
+
176
+ :param v: vertex to compare
177
+ :param tol: tolerance
178
+ """
179
+
180
+ if abs(self.x - v.x) < tol and abs(self.y - v.y) < tol and abs(self.z - v.z) < tol:
181
+ return True
182
+ else:
183
+ return False
184
+
172
185
  class cloudproperties:
173
186
  """
174
187
  Properties of a cloud of vertices
@@ -854,7 +867,7 @@ class cloud_vertices(Element_To_Draw):
854
867
  curvert = self.myvertices[item]['vertex']
855
868
 
856
869
  if curvert.x > xmin and curvert.x < xmax and curvert.y > ymin and curvert.y < ymax:
857
-
870
+
858
871
  r,g,b = getRGBfromI(self.myprop.legendcolor)
859
872
 
860
873
  curtxt_infos = Text_Infos(self.myprop.legendpriority,
@@ -887,6 +887,7 @@ if :\n \
887
887
  return 'SanSerif'
888
888
  else:
889
889
  return 'Arial'
890
+
890
891
  class vector:
891
892
  """
892
893
  Objet de gestion d'informations vectorielles
@@ -911,11 +912,14 @@ class vector:
911
912
 
912
913
  def __init__(self, lines:list=[], is2D=True, name='NoName', parentzone:"zone"=None, fromshapely=None) -> None:
913
914
  """
914
- lines : utile pour lecture de fichier
915
- is2D : on interprète les 'vertices' comme 2D même si chaque 'wolfvertex' contient toujours x, y et z
916
- name : nom du vecteur
917
- parentzone : instance de type 'zone' qui contient le 'vector'
915
+
916
+ :param lines: utile pour lecture de fichier
917
+ :param is2D: on interprète les 'vertices' comme 2D même si chaque 'wolfvertex' contient toujours x, y et z
918
+ :param name: nom du vecteur
919
+ :param parentzone: instance de type 'zone' qui contient le 'vector'
920
+
918
921
  """
922
+
919
923
  self.myname=''
920
924
  self.is2D = is2D
921
925
  self.closed=False
@@ -1047,6 +1051,9 @@ class vector:
1047
1051
  """
1048
1052
  Return tuple with :
1049
1053
  - (lower-left corner), (upper-right corner)
1054
+
1055
+ If you want [[xmin,xmax],[ymin,ymax]], use get_bounds_xx_yy() instead.
1056
+
1050
1057
  """
1051
1058
  if grid is None:
1052
1059
  return ((self.xmin, self.ymin), (self.xmax, self.ymax))
@@ -1062,6 +1069,9 @@ class vector:
1062
1069
  """
1063
1070
  Return tuple with :
1064
1071
  - (xmin,xmax), (ymin, ymax)
1072
+
1073
+ If you want [[lower-left corner],[upper-right corner]], use get_bounds() instead.
1074
+
1065
1075
  """
1066
1076
  if grid is None:
1067
1077
  return ((self.xmin, self.xmax), (self.ymin, self.ymax))
@@ -1095,6 +1105,7 @@ class vector:
1095
1105
  """
1096
1106
  Mise en évidence
1097
1107
  """
1108
+
1098
1109
  self._oldcolor = self.myprop.color
1099
1110
  self._oldwidth = self.myprop.color
1100
1111
 
@@ -1105,6 +1116,7 @@ class vector:
1105
1116
  """
1106
1117
  Mise en retrait
1107
1118
  """
1119
+
1108
1120
  try:
1109
1121
  self.myprop.color = self._oldcolor
1110
1122
  self.myprop.width = self._oldwidth
@@ -1367,12 +1379,12 @@ class vector:
1367
1379
  # again checks that the vector is not closed; in the case where
1368
1380
  # two vertices are not the same one but have the same coordinates)
1369
1381
 
1370
- is_open = self.myvertices[-1] is not self.myvertices[0] or \
1371
- (self.myvertices[-1].x!=self.myvertices[0].x or \
1372
- self.myvertices[-1].y!=self.myvertices[0].y)
1382
+ is_open = not((self.myvertices[-1] is self.myvertices[0]) or \
1383
+ (self.myvertices[-1].x==self.myvertices[0].x and \
1384
+ self.myvertices[-1].y==self.myvertices[0].y))
1373
1385
 
1374
1386
  if not self.is2D :
1375
- is_open = is_open and self.myvertices[-1].z!=self.myvertices[0].z
1387
+ is_open = is_open or self.myvertices[-1].z!=self.myvertices[0].z
1376
1388
 
1377
1389
  if is_open:
1378
1390
  self.add_vertex(self.myvertices[0])
@@ -1800,10 +1812,10 @@ class vector:
1800
1812
 
1801
1813
  if length<1:
1802
1814
  length*=1000.
1803
- alls = np.linspace(0,int(length),nb)
1815
+ alls = np.linspace(0, length, nb)
1804
1816
  alls/=1000.
1805
1817
  else:
1806
- alls = np.linspace(0,int(length),nb,endpoint=True)
1818
+ alls = np.linspace(0, length, nb, endpoint=True)
1807
1819
 
1808
1820
  pts = [myls.interpolate(curs) for curs in alls]
1809
1821
  # pts = [(curpt.x, curpt.y) for curpt in pts]
@@ -2147,16 +2159,28 @@ class vector:
2147
2159
 
2148
2160
  if name is None:
2149
2161
  name = self.myname + "_copy"
2150
- if parentzone:
2151
- copied_vector = vector(name=name,parentzone=parentzone)
2152
- else:
2153
- copied_vector = vector(name=name)
2154
2162
 
2155
- copied_vector.myvertices = copy.deepcopy(self.myvertices)
2156
- # copied_vector.nbvertices = copy.deepcopy(self.nbvertices)
2163
+ if parentzone:
2164
+ copied_vector = vector(name=name,parentzone=parentzone)
2165
+ else:
2166
+ copied_vector = vector(name=name)
2157
2167
 
2158
- return copied_vector
2168
+ copied_vector.myvertices = copy.deepcopy(self.myvertices)
2159
2169
 
2170
+ return copied_vector
2171
+
2172
+ def set_legend_to_centroid(self, text:str='', visible:bool=True):
2173
+ """
2174
+ Positionne la légende au centre du vecteur
2175
+ """
2176
+ self.myprop.legendvisible = visible
2177
+
2178
+ ls = self.asshapely_pol()
2179
+ centroid = ls.centroid
2180
+
2181
+ self.myprop.legendx = centroid.x
2182
+ self.myprop.legendy = centroid.y
2183
+ self.myprop.legendtext = text if text else self.myname
2160
2184
 
2161
2185
  class zone:
2162
2186
  """
@@ -2369,8 +2393,13 @@ class zone:
2369
2393
  def add_vector(self, addedvect:vector, index=-99999, forceparent=False):
2370
2394
  """
2371
2395
  Ajout d'une instance 'vector'
2372
- Le compteur est incrémenté
2396
+
2397
+ :param addedvect: instance 'vector' à ajouter
2398
+ :param index: position d'insertion
2399
+ :param forceparent: True = forcer le parent à être la zone dans lequel le vecteur est ajouté
2400
+
2373
2401
  """
2402
+
2374
2403
  if index==-99999 or index >self.nbvectors:
2375
2404
  self.myvectors.append(addedvect)
2376
2405
  else:
@@ -2474,8 +2503,13 @@ class zone:
2474
2503
  if self.idgllist!=-99999:
2475
2504
  glCallList(self.idgllist)
2476
2505
  else:
2506
+ self.has_legend = False
2507
+ self.has_image = False
2508
+
2477
2509
  for curvect in self.myvectors:
2478
2510
  curvect.plot()
2511
+ self.has_legend |= curvect.myprop.legendvisible
2512
+ self.has_image |= curvect.myprop.imagevisible
2479
2513
 
2480
2514
  if self.has_legend:
2481
2515
  for curvect in self.myvectors:
@@ -3657,6 +3691,14 @@ class zone:
3657
3691
  if self.parent.mapviewer is not None:
3658
3692
  self.prep_listogl()
3659
3693
  self.parent.mapviewer.Refresh()
3694
+
3695
+ def set_legend_to_centroid(self):
3696
+ """
3697
+ Set the legend to the centroid of the zone
3698
+ """
3699
+ for curvec in self.myvectors:
3700
+ curvec.set_legend_to_centroid()
3701
+
3660
3702
  class Zones(wx.Frame, Element_To_Draw):
3661
3703
  """
3662
3704
  Objet de gestion d'informations vectorielles
@@ -4398,6 +4440,7 @@ class Zones(wx.Frame, Element_To_Draw):
4398
4440
  boxright.Add(self.capturevertices,0,wx.EXPAND)
4399
4441
  boxright.Add(self.dynapar,0,wx.EXPAND)
4400
4442
  boxright.Add(self.createapar,0,wx.EXPAND)
4443
+ boxright.Add(self.reverseorder,0,wx.EXPAND)
4401
4444
  boxright.Add(self.modifyvertices,0,wx.EXPAND)
4402
4445
  boxright.Add(self.insertvertices,0,wx.EXPAND)
4403
4446
  boxright.Add(self.splitvertices,0,wx.EXPAND)
@@ -4699,8 +4742,56 @@ class Zones(wx.Frame, Element_To_Draw):
4699
4742
  """
4700
4743
  Remplissage de la structure wx
4701
4744
  """
4745
+
4746
+ def store_tree_state(tree:TreeListCtrl):
4747
+
4748
+ expended_items = []
4749
+ root = tree.GetRootItem()
4750
+
4751
+ if root is None:
4752
+ return
4753
+
4754
+ def traverse_and_store(item):
4755
+ if not item.IsOk():
4756
+ return
4757
+ if tree.IsExpanded(item):
4758
+ expended_items.append(tree.GetItemData(item))
4759
+
4760
+ child = tree.GetFirstChild(item)
4761
+ while child.IsOk():
4762
+ traverse_and_store(child)
4763
+ child = tree.GetNextItem(child)
4764
+
4765
+ traverse_and_store(root)
4766
+
4767
+ return expended_items
4768
+
4769
+ def restore_tree_state(tree:TreeListCtrl, expended_items):
4770
+
4771
+ root = tree.GetRootItem()
4772
+
4773
+ if root is None:
4774
+ return
4775
+
4776
+ def traverse_and_restore(item):
4777
+ if not item.IsOk():
4778
+ return
4779
+
4780
+ if tree.GetItemData(item) in expended_items:
4781
+ tree.Expand(item)
4782
+
4783
+ child = tree.GetFirstChild(item)
4784
+ while child.IsOk():
4785
+ traverse_and_restore(child)
4786
+ child = tree.GetNextItem(child)
4787
+
4788
+ traverse_and_restore(root)
4789
+
4702
4790
  if self.wx_exists:
4703
4791
  if self.xls is not None:
4792
+
4793
+ expanded = store_tree_state(self.treelist)
4794
+
4704
4795
  self.treelist.DeleteAllItems()
4705
4796
 
4706
4797
  root = self.treelist.GetRootItem()
@@ -4712,6 +4803,8 @@ class Zones(wx.Frame, Element_To_Draw):
4712
4803
 
4713
4804
  self.treelist.Expand(mynode)
4714
4805
 
4806
+ restore_tree_state(self.treelist, expanded)
4807
+
4715
4808
  def expand_tree(self, objzone=None):
4716
4809
  """
4717
4810
  Développe la structure pour un objet spécifique stocké dans la self.treelist
@@ -5594,17 +5687,54 @@ class Zones(wx.Frame, Element_To_Draw):
5594
5687
  else:
5595
5688
  myitemdata.unuse()
5596
5689
 
5690
+ def _callback_destroy_props(self):
5691
+
5692
+ self.myprops = None
5693
+
5694
+ def _callback_prop(self):
5695
+
5696
+ if self._myprops is None:
5697
+ logging.warning(_('No properties available'))
5698
+ return
5699
+
5700
+ for curzone in self.myzones:
5701
+ for curvec in curzone.myvectors:
5702
+ curvec.myprop.fill_property(self._myprops, updateOGL = False)
5703
+
5704
+ if self.mapviewer is not None:
5705
+ self.prep_listogl()
5706
+ self.mapviewer.Refresh()
5707
+
5708
+
5709
+ def _edit_all_properties(self):
5710
+ """ Show properties of the zone --> will be applied to all vectors int he zone """
5711
+
5712
+ locvec = vector()
5713
+ locvec.myprop.show()
5714
+
5715
+ self._myprops = locvec.myprop.myprops
5716
+
5717
+ self._myprops[('Legend','X')] = 99999.
5718
+ self._myprops[('Legend','Y')] = 99999.
5719
+ self._myprops[('Legend','Text')] = _('Not used')
5720
+ self._myprops.Populate()
5721
+ self._myprops.set_callbacks(self._callback_prop, self._callback_destroy_props)
5722
+
5723
+
5597
5724
  def OnRDown(self, event:TreeListEvent):
5598
5725
  """
5599
5726
  Affiche les propriétés du vecteur courant
5600
5727
  Clicl-droit
5601
5728
  """
5602
5729
  if self.wx_exists:
5603
- if self.verify_activevec() and self.verify_activezone():
5604
- return
5730
+ if self.active_zone is None and self.active_zone is None:
5731
+
5732
+ logging.info(_('You will edit the properties of the entire instance (all zones and all vectors)'))
5733
+ self._edit_all_properties()
5605
5734
 
5606
- if isinstance(self.last_active, vector):
5735
+ elif isinstance(self.last_active, vector):
5607
5736
  self.active_vector.myprop.show()
5737
+
5608
5738
  elif isinstance(self.last_active, zone):
5609
5739
  self.active_zone.show_properties()
5610
5740
 
@@ -5620,6 +5750,9 @@ class Zones(wx.Frame, Element_To_Draw):
5620
5750
  self.Activate_vector(myitemdata)
5621
5751
  elif isinstance(myitemdata,zone):
5622
5752
  self.Activate_zone(myitemdata)
5753
+ else:
5754
+ self.Activate_vector(None)
5755
+ self.Activate_zone(None)
5623
5756
 
5624
5757
  self.last_active = myitemdata
5625
5758
 
@@ -5631,6 +5764,12 @@ class Zones(wx.Frame, Element_To_Draw):
5631
5764
  """
5632
5765
  if self.wx_exists:
5633
5766
  self.active_vector = object
5767
+
5768
+ if self.active_vector is None:
5769
+ logging.info(_('Active vector is now set to None'))
5770
+ self.xls.ClearGrid()
5771
+ return
5772
+
5634
5773
  self.xls_active_vector()
5635
5774
 
5636
5775
  if object.parentzone is not None:
@@ -5656,12 +5795,22 @@ class Zones(wx.Frame, Element_To_Draw):
5656
5795
  """
5657
5796
  if self.wx_exists:
5658
5797
  self.active_zone = object
5798
+
5799
+ if self.active_zone is None:
5800
+ logging.info(_('Active zone is now set to None'))
5801
+ self.xls.ClearGrid()
5802
+ return
5803
+
5659
5804
  if object.active_vector is not None:
5660
5805
  self.active_vector = object.active_vector
5661
5806
  elif object.nbvectors>0:
5662
5807
  self.Activate_vector(object.myvectors[0])
5663
5808
 
5664
- self.labelactvect.SetLabel(self.active_vector.myname)
5809
+ if self.active_vector is None:
5810
+ logging.warning(_('No vector in the active zone'))
5811
+ else:
5812
+ self.labelactvect.SetLabel(self.active_vector.myname)
5813
+
5665
5814
  self.labelactzone.SetLabel(self.active_zone.myname)
5666
5815
  self.Layout()
5667
5816
 
wolfhece/Results2DGPU.py CHANGED
@@ -500,8 +500,7 @@ class Sim_2D_GPU():
500
500
  self.loaded = False
501
501
 
502
502
  if self.filename.exists():
503
- self.sim = SimpleSimulation()
504
- self.sim.load(self.filename)
503
+ self.sim = SimpleSimulation.load(self.filename)
505
504
  self.loaded = True
506
505
 
507
506
  pass
wolfhece/apps/version.py CHANGED
@@ -4,8 +4,8 @@ class WolfVersion():
4
4
  def __init__(self):
5
5
 
6
6
  self.major = 2
7
- self.minor = 0
8
- self.patch = 55
7
+ self.minor = 1
8
+ self.patch = 1
9
9
 
10
10
  def __str__(self):
11
11
 
File without changes
@@ -0,0 +1,93 @@
1
+ import numpy as np
2
+ from math import pi
3
+
4
+ class chamber():
5
+
6
+ def __init__(self) -> None:
7
+
8
+ self.area = 10. # m^2
9
+ self.elevation = 0. # m
10
+ self._volume = 100. # m^3
11
+ self._height = 10. # m
12
+
13
+ self.q_in = []
14
+ self.q_out = []
15
+
16
+ self.is_bc = False
17
+ self.bc_value = 0.
18
+
19
+ def reset_q(self):
20
+ self.q_in = []
21
+ self.q_out = []
22
+
23
+ def add_qin(self, q):
24
+ self.q_in.append(q)
25
+
26
+ def add_qout(self, q):
27
+ self.q_out.append(q)
28
+
29
+ @property
30
+ def volume(self):
31
+ return self._volume
32
+
33
+ @volume.setter
34
+ def volume(self, value):
35
+ self._volume = value
36
+ self.solve_height()
37
+
38
+ @property
39
+ def height(self):
40
+ return self._height
41
+
42
+ @height.setter
43
+ def height(self, value):
44
+ self._height = value
45
+ self.solve_volume()
46
+
47
+ def solve_volume(self):
48
+ self._volume = self.area * self.height
49
+ return self._volume
50
+
51
+ def solve_height(self):
52
+ self._height = self.volume / self.area
53
+ return self._height
54
+
55
+ def update(self, dt:float):
56
+
57
+ if self.is_bc:
58
+ self.head = self.bc_value
59
+ else:
60
+ self.volume += (np.sum(np.asarray(self.q_in)) - np.sum(np.asarray(self.q_out))) * dt
61
+ self.solve_height()
62
+
63
+ @property
64
+ def head(self):
65
+ return self.elevation + self.height
66
+
67
+ @head.setter
68
+ def head(self, value):
69
+ self.height = value - self.elevation
70
+ self.solve_volume()
71
+
72
+ class junction(chamber):
73
+
74
+ def __init__(self) -> None:
75
+ super().__init__()
76
+ self.area = 1.e-2
77
+ self.volume = 0.
78
+ self.height = 0.
79
+ self.elevation = 0.
80
+
81
+ self._head = 0.
82
+
83
+ @property
84
+ def head(self):
85
+ return self._head
86
+
87
+ @head.setter
88
+ def head(self, value):
89
+ self._head = value
90
+
91
+ def update(self, dt:float):
92
+
93
+ self.head += (np.sum(np.asarray(self.q_in)) - np.sum(np.asarray(self.q_out))) * dt
@@ -0,0 +1,10 @@
1
+ from enum import Enum
2
+
3
+ class Water():
4
+
5
+ rho:float = 1000.
6
+ mu:float = 1e-3
7
+
8
+ @property
9
+ def nu(self) -> float:
10
+ return self.mu / self.rho
@@ -0,0 +1,100 @@
1
+ import numpy as np
2
+ from math import pi
3
+ from scipy.optimize import fsolve, newton, root, root_scalar
4
+ import matplotlib.pyplot as plt
5
+ from jax import grad, jit, numpy as jnp
6
+ import timeit
7
+
8
+ @jit
9
+ def _colebrook_white(f, k, diameter, reynolds):
10
+ """
11
+ Colebrook-White equation for friction factor
12
+
13
+ @param f: float, friction factor [-]
14
+ @param k: float, roughness of the pipe [m]
15
+ @param diameter: float, diameter of the pipe [m]
16
+ @param reynolds: float, Reynolds number [-]
17
+ """
18
+ return 1. / jnp.sqrt(f) + 2. * jnp.log10(k / (3.7 * diameter) + 2.51 / (reynolds * jnp.sqrt(f)))
19
+
20
+ """ Gradient of the Colebrook-White equation """
21
+ grad_colebrook_white = jit(grad(_colebrook_white))
22
+ """ Second derivative of the Colebrook-White equation """
23
+ grad2_colebrook_white = jit(grad(grad(_colebrook_white)))
24
+
25
+ def f_colebrook_white(f, k, diameter, reynolds):
26
+ """
27
+ Solve the Colebrook-White equation using Newton's method
28
+
29
+ @param f: float, initial guess for the friction factor [-]
30
+ @param k: float, roughness of the pipe [m]
31
+ @param diameter: float, diameter of the pipe [m]
32
+ @param reynolds: float, Reynolds number [-]
33
+ """
34
+ f_sol = newton(_colebrook_white, f, grad_colebrook_white, args=(k, diameter, reynolds), rtol=1e-6)
35
+ return f_sol.item()
36
+
37
+
38
+ # Test multiple solvers
39
+ def test_colebrook_fsolve():
40
+ """ Test the Colebrook-White equation using Scipy fsolve """
41
+
42
+ k= 1.e-4
43
+ diam = .5
44
+ viscosity = 1.e-6
45
+ area = pi * (diam/2.)**2.
46
+ discharge = 1.
47
+ velocity = discharge / area
48
+ reynolds = velocity * diam / viscosity
49
+
50
+ f_guess = 0.02 # Initial guess for the friction factor
51
+ f_sol = fsolve(_colebrook_white, f_guess, args=(k, diam, reynolds), xtol=1e-14)
52
+ return f_sol[0]
53
+
54
+ def test_colebrook_root_scalar():
55
+ """ Test the Colebrook-White equation using Scipy root_scalar """
56
+
57
+ k= 1.e-4
58
+ diam = .5
59
+ viscosity = 1.e-6
60
+ area = pi * (diam/2.)**2.
61
+ discharge = 1.
62
+ velocity = discharge / area
63
+ reynolds = velocity * diam / viscosity
64
+
65
+ f_guess = 0.02 # Initial guess for the friction factor
66
+ f_sol = root_scalar(_colebrook_white, method='brentq', bracket=[0.,10.], x0 = f_guess, args=(k, diam, reynolds)) #, fprime = grad_colebrook_white, fprime2 = grad2_colebrook_white, xtol=1e-6)
67
+ return f_sol.root
68
+
69
+ def test_colebrook_newton():
70
+ """ Test the Colebrook-White equation using Scipy newton """
71
+
72
+ k= 1.e-4
73
+ diam = .5
74
+ viscosity = 1.e-6
75
+ area = pi * (diam/2.)**2.
76
+ discharge = 1.
77
+ velocity = discharge / area
78
+ reynolds = velocity * diam / viscosity
79
+
80
+ f_guess = 0.02 # Initial guess for the friction factor
81
+
82
+ f_sol = newton(_colebrook_white, f_guess, grad_colebrook_white, args=(k, diam, reynolds), rtol=1e-6)
83
+ return f_sol.item()
84
+
85
+
86
+ if __name__ == '__main__':
87
+
88
+ trootscalar = timeit.timeit(test_colebrook_root_scalar, number = 1000)
89
+ tfsolve = timeit.timeit(test_colebrook_fsolve, number = 1000)
90
+ tnewton = timeit.timeit(test_colebrook_newton, number = 1000)
91
+
92
+ trootscalar = test_colebrook_root_scalar()
93
+ tfsolve = test_colebrook_fsolve()
94
+ tnewton = test_colebrook_newton()
95
+
96
+ sol_newton = f_colebrook_white(.02, 1.e-4, .5, 1/(pi*(.5/2.)**2.)*.5/1.e-6)
97
+
98
+ assert sol_newton == tnewton
99
+
100
+ pass