wolfhece 2.1.123__py3-none-any.whl → 2.1.125__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/apps/version.py CHANGED
@@ -5,7 +5,7 @@ class WolfVersion():
5
5
 
6
6
  self.major = 2
7
7
  self.minor = 1
8
- self.patch = 123
8
+ self.patch = 125
9
9
 
10
10
  def __str__(self):
11
11
 
@@ -123,7 +123,7 @@ class Classification_LAZ():
123
123
  def choices_laz_colormap() -> list[str]:
124
124
 
125
125
  choices = [cur.name for cur in Colors_Lazviewer]
126
- values = [cur.value for cur in Colors_Lazviewer]
126
+ values = [cur for cur in Colors_Lazviewer]
127
127
 
128
128
  return choices, values
129
129
 
@@ -699,8 +699,8 @@ class xyz_laz_grids():
699
699
  figmpl = MplFig(PRESET_LAYOUTS.DEFAULT)
700
700
 
701
701
  logging.info(_('Plotting'))
702
- figmpl.plot(up_s, up_z, c=up_color ,marker='.')
703
- figmpl.plot(down_s, down_z,c=down_color,marker='+')
702
+ figmpl.scatter(up_s, up_z, c=up_color ,marker='.')
703
+ figmpl.scatter(down_s, down_z,c=down_color,marker='+')
704
704
 
705
705
  if show:
706
706
  figmpl.Show()
@@ -764,7 +764,7 @@ class Wolf_LAZ_Data(Element_To_Draw):
764
764
  self.classification = Classification_LAZ() # Classification of LAZ data --> defining colors if codification is used
765
765
  self.classification.init_2023() # Default classification for LAZ data
766
766
 
767
- self._associated_color:int = Colors_Lazviewer.CODE_2023.value # Associated color type for LAZ data
767
+ self._associated_color:int = Colors_Lazviewer.CODE_2023 # Associated color type for LAZ data
768
768
 
769
769
  self.viewer:viewer = None # PPTK viewer
770
770
 
@@ -792,7 +792,7 @@ class Wolf_LAZ_Data(Element_To_Draw):
792
792
 
793
793
  def serialize(self):
794
794
  """ Serialize class : data and attributes """
795
- return {'bounds':self._bounds, 'data':str(self._filename) + '.npz', 'associated_color':self._associated_color,
795
+ return {'bounds':self._bounds, 'data':str(self._filename) + '.npz', 'associated_color':self._associated_color.value,
796
796
  'point_size':self._point_size, 'bg_color':self._bg_color, 'bg_color_top':self._bg_color_top,
797
797
  'bg_color_bottom':self._bg_color_bottom, 'floor_level':self._floor_level, 'floor_color':self._floor_color,
798
798
  'show_grid':self._show_grid, 'show_axis':self._show_axis, 'show_info':self._show_info}
@@ -838,8 +838,12 @@ class Wolf_LAZ_Data(Element_To_Draw):
838
838
  return self._associated_color
839
839
 
840
840
  @associated_color.setter
841
- def associated_color(self, value:int):
842
- self._associated_color = value
841
+ def associated_color(self, value:int | Colors_Lazviewer):
842
+
843
+ if isinstance(value, int):
844
+ self._associated_color = Colors_Lazviewer(value)
845
+ else:
846
+ self._associated_color = value
843
847
  self.set_colors()
844
848
 
845
849
  def merge(self, other:"Wolf_LAZ_Data"):
@@ -1331,9 +1335,9 @@ class Wolf_LAZ_Data(Element_To_Draw):
1331
1335
  ret = props.addparam('Floor', 'Level', self._floor_level, Type_Param.Float, 'Floor level')
1332
1336
  ret = props.addparam('Floor', 'Color', self._floor_color, Type_Param.Color, 'Floor color')
1333
1337
 
1334
- ret = props.addparam('Infos', 'Grid', self._show_grid, Type_Param.Logical, 'Show grid')
1335
- ret = props.addparam('Infos', 'Axis', self._show_axis, Type_Param.Logical, 'Show axis')
1336
- ret = props.addparam('Infos', 'values', self._show_info, Type_Param.Logical, 'Show info')
1338
+ # ret = props.addparam('Infos', 'Grid', self._show_grid, Type_Param.Logical, 'Show grid')
1339
+ # ret = props.addparam('Infos', 'Axis', self._show_axis, Type_Param.Logical, 'Show axis')
1340
+ # ret = props.addparam('Infos', 'values', self._show_info, Type_Param.Logical, 'Show info')
1337
1341
 
1338
1342
  ret = props.addparam('Points', 'Size', self._point_size, Type_Param.Float, 'Point size')
1339
1343
 
@@ -1426,7 +1430,7 @@ class Wolf_LAZ_Data(Element_To_Draw):
1426
1430
  xyz[i,0] = float(xls.GetCellValue(i,0))
1427
1431
  xyz[i,1] = float(xls.GetCellValue(i,1))
1428
1432
  xyz[i,2] = float(xls.GetCellValue(i,2))
1429
- codes[i] = int(xls.GetCellValue(i,3))
1433
+ codes[i] = float(xls.GetCellValue(i,3))
1430
1434
  except Exception as e:
1431
1435
  logging.error(e)
1432
1436
  logging.warning(_('Bad values in grid - Check your input'))
@@ -1556,9 +1560,9 @@ class Wolf_LAZ_Data(Element_To_Draw):
1556
1560
  color = np.asarray(props[('Floor', 'Color')])
1557
1561
  self.floor_color(color / 255.)
1558
1562
 
1559
- self.show_grid(props[('Infos', 'Grid')])
1560
- self.show_axis(props[('Infos', 'Axis')])
1561
- self.show_info(props[('Infos', 'values')])
1563
+ # self.show_grid(props[('Infos', 'Grid')])
1564
+ # self.show_axis(props[('Infos', 'Axis')])
1565
+ # self.show_info(props[('Infos', 'values')])
1562
1566
 
1563
1567
  self.point_size = props[('Points', 'Size')]
1564
1568
 
@@ -1568,7 +1572,7 @@ class Wolf_LAZ_Data(Element_To_Draw):
1568
1572
  self._select_only_codes = list(set([int(curcode) for curcode in codes_sel]))
1569
1573
  except Exception as e:
1570
1574
  logging.error(e)
1571
- logging.warning(_('Nullify selection filter - Check your input'))
1575
+ logging.warning(_('Nullify selection filter - Check your input - Must be a list of integers separated by commas'))
1572
1576
  self._select_only_codes = []
1573
1577
 
1574
1578
  def _fill_props(self, full:bool = False):
@@ -1599,9 +1603,9 @@ class Wolf_LAZ_Data(Element_To_Draw):
1599
1603
  props[('Floor', 'Level')] = self._floor_level
1600
1604
  props[('Floor', 'Color')] = self._floor_color
1601
1605
 
1602
- props[('Infos', 'Grid')] = self._show_grid
1603
- props[('Infos', 'Axis')] = self._show_axis
1604
- props[('Infos', 'values')] = self._show_info
1606
+ # props[('Infos', 'Grid')] = self._show_grid
1607
+ # props[('Infos', 'Axis')] = self._show_axis
1608
+ # props[('Infos', 'values')] = self._show_info
1605
1609
 
1606
1610
  props[('Points', 'Size')] = self._point_size
1607
1611
 
@@ -1610,6 +1614,15 @@ class Wolf_LAZ_Data(Element_To_Draw):
1610
1614
  def show_properties(self):
1611
1615
  """ Surcharged method (see Element_To_Draw) to show properties from MapViewer"""
1612
1616
  if self.viewer is None:
1617
+ logging.info(_('No viewer / No properties'))
1618
+ return
1619
+
1620
+ # test if a connexion exists
1621
+ try:
1622
+ lookat = self.viewer.get('lookat')
1623
+ except:
1624
+ self.viewer = None
1625
+ logging.info(_('No viewer / No properties'))
1613
1626
  return
1614
1627
 
1615
1628
  self._create_props()
@@ -2102,13 +2102,13 @@ class Matplotlib_Figure(wx.Frame):
2102
2102
 
2103
2103
  ax.scatter(x, y, **kwargs)
2104
2104
 
2105
- new_props = Matplolib_line_properties(ax.get_lines()[-1], self._axes_properties[idx_ax])
2105
+ # new_props = Matplolib_line_properties(ax.get_lines()[-1], self._axes_properties[idx_ax])
2106
2106
 
2107
- if self.wx_exists:
2108
- new_props.add_props_to_sizer(self._collaps_pane.GetPane(), self._sizer_grid_props)
2107
+ # if self.wx_exists:
2108
+ # new_props.add_props_to_sizer(self._collaps_pane.GetPane(), self._sizer_grid_props)
2109
2109
 
2110
2110
  ax_prop:Matplotlib_ax_properties = self._axes_properties[idx_ax]
2111
- ax_prop._lines.append(new_props)
2111
+ # ax_prop._lines.append(new_props)
2112
2112
  ax_prop.get_properties()
2113
2113
 
2114
2114
  if self.wx_exists:
@@ -150,7 +150,7 @@ class Update_Sim:
150
150
  """
151
151
  pass
152
152
 
153
- def update_deck(self, roof:WolfArray):
153
+ def update_deck(self, deck:WolfArray):
154
154
  """
155
155
  FR
156
156
 
File without changes
@@ -0,0 +1,118 @@
1
+ import jax
2
+ import jax.numpy as jnp
3
+ from jax import jit, vmap
4
+ import matplotlib.pyplot as plt
5
+ import numpy as np
6
+
7
+ # Forcer float32
8
+ jax.config.update("jax_enable_x64", False)
9
+
10
+ # Fonction pour calculer l'aire immergée
11
+ def wet_area(h, R):
12
+ h = jnp.clip(h, 0, 2 * R)
13
+ theta = 2 * jnp.arccos(1 - h / R)
14
+ area = (R**2 / 2) * (theta - jnp.sin(theta))
15
+ return area
16
+
17
+ # Solution "analytique/numérique" classique pour h
18
+ def analytical_h(R, f):
19
+ def solve_theta(theta):
20
+ return (theta - jnp.sin(theta)) / (2 * jnp.pi) - f
21
+ theta_min, theta_max = jnp.float32(0.0), jnp.float32(2 * jnp.pi)
22
+ for _ in range(50):
23
+ theta_mid = (theta_min + theta_max) / 2
24
+ val = solve_theta(theta_mid)
25
+ theta_max = jnp.where(val > 0, theta_mid, theta_max)
26
+ theta_min = jnp.where(val <= 0, theta_mid, theta_min)
27
+ theta = (theta_min + theta_max) / 2
28
+ return R * (1 - jnp.cos(theta / 2))
29
+
30
+ # Fonction objectif avec sigmoïde adaptative aux deux bornes
31
+ def objective(h, R, f):
32
+ total_area = jnp.pi * R**2
33
+ target_area = f * total_area
34
+ diff = wet_area(h, R) - target_area
35
+ # Échelle adaptative : plus kleine pour f près de 0 ou 1
36
+ scale_factor = jnp.minimum(f, 1. - f) # Distance au bord le plus proche
37
+ scale = 0.05 * R**2 * jnp.maximum(scale_factor, 0.01) # Éviter 0
38
+ return 1 / (1 + jnp.exp(-diff / scale))
39
+
40
+ # Dichotomie douce améliorée
41
+ @jit
42
+ def soft_dichotomy(R, f, max_iter=200):
43
+ def body(state, _):
44
+ h_min, h_max = state
45
+ h_mid = (h_min + h_max) / 2
46
+ sigmoid_val = objective(h_mid, R, f)
47
+ h_min_new = h_min + (h_mid - h_min) * (1 - sigmoid_val)
48
+ h_max_new = h_max - (h_max - h_mid) * sigmoid_val
49
+ return (h_min_new, h_max_new), None
50
+
51
+ # Bornes initiales resserrées pour petits/grands f
52
+ h_min_init = jnp.float32(0.0)
53
+ h_max_init = jnp.float32(2 * R)
54
+ initial_state = (h_min_init, h_max_init)
55
+ final_state, _ = jax.lax.scan(body, initial_state, None, length=max_iter)
56
+ h_min, h_max = final_state
57
+ return (h_min + h_max) / 2
58
+
59
+ # Dérivée par rapport à f
60
+ grad_bisection = jax.grad(soft_dichotomy, argnums=1)
61
+
62
+
63
+ if __name__ == "__main__":
64
+ # Paramètres
65
+ R = jnp.float32(1.0)
66
+ f_values = jnp.linspace(jnp.float32(0.001), jnp.float32(0.999), 500) # Plus près des bords
67
+
68
+ # Calculs
69
+ h_numerical = vmap(lambda f: soft_dichotomy(R, f))(f_values)
70
+ h_analytical = vmap(lambda f: analytical_h(R, f))(f_values)
71
+ errors = jnp.abs(h_numerical - h_analytical)
72
+
73
+ grads = vmap(lambda f: grad_bisection(R, f))(f_values)
74
+
75
+ # Graphiques
76
+ plt.figure(figsize=(12, 5))
77
+
78
+ plt.subplot(1, 3, 1)
79
+ plt.plot(f_values, h_numerical, label="Numérique (sigmoïde)", color="blue")
80
+ plt.plot(f_values, h_analytical, "--", label="Analytique", color="orange")
81
+ plt.xlabel("Fraction immergée (f)")
82
+ plt.ylabel("Hauteur (h)")
83
+ plt.title("Hauteur en fonction de f (float32)")
84
+ plt.legend()
85
+ plt.grid(True)
86
+ plt.yscale("log") # Échelle log pour voir les extrêmes
87
+
88
+ plt.subplot(1, 3, 2)
89
+ plt.plot(f_values, errors, color="red")
90
+ plt.xlabel("Fraction immergée (f)")
91
+ plt.ylabel("Erreur absolue (|h_num - h_ana|)")
92
+ plt.title("Erreur par rapport à la solution analytique")
93
+ plt.grid(True)
94
+ plt.yscale("log") # Échelle log pour les erreurs
95
+
96
+ plt.subplot(1, 3, 3)
97
+ plt.plot(f_values, grads, label="Dérivée par rapport à f")
98
+ plt.xlabel("Fraction immergée (f)")
99
+ plt.ylabel("Gradient de f par rapport à h")
100
+ plt.legend()
101
+ plt.grid(True)
102
+
103
+ plt.tight_layout()
104
+ plt.show()
105
+
106
+ # Tests spécifiques aux deux bornes
107
+ for f_test in [0., 0.001, 0.01, 0.5, 0.99, 0.999]:
108
+ f_test = jnp.float32(f_test)
109
+ h_num = soft_dichotomy(R, f_test)
110
+ h_ana = analytical_h(R, f_test)
111
+ grad_h = grad_bisection(R, f_test)
112
+ print(f"f = {f_test:.4f}:")
113
+ print(f" h numérique = {h_num:.6f}")
114
+ print(f" h analytique = {h_ana:.6f}")
115
+ print(f" Gradient de h par rapport à f = {grad_h:.6f}")
116
+ print(f" Erreur = {jnp.abs(h_num - h_ana):.6f}")
117
+ print(f" Erreur relative = {jnp.abs(h_num - h_ana) / h_ana:.6e}")
118
+ pass
@@ -0,0 +1,169 @@
1
+ import jax
2
+ import jax.numpy as jnp
3
+ from jax import jit, vmap
4
+ import matplotlib.pyplot as plt
5
+ import numpy as np
6
+ from scipy.optimize import minimize, root_scalar
7
+
8
+ # Forcer float32
9
+ jax.config.update("jax_enable_x64", False)
10
+
11
+ # Fonction pour calculer l'aire immergée
12
+ def wet_area(h, R):
13
+ h = jnp.clip(h, 0, 2 * R)
14
+ theta = 2 * jnp.arccos(1 - h / R)
15
+ area = (R**2 / 2) * (theta - jnp.sin(theta))
16
+ return area
17
+
18
+ # Solution numérique "classique" pour h
19
+ def analytical_h(R, f):
20
+ def solve_theta(theta):
21
+ return (theta - jnp.sin(theta)) / (2 * jnp.pi) - f
22
+ theta_min, theta_max = jnp.float32(0.0), jnp.float32(2 * jnp.pi)
23
+ for _ in range(50):
24
+ theta_mid = (theta_min + theta_max) / 2
25
+ val = solve_theta(theta_mid)
26
+ theta_max = jnp.where(val > 0, theta_mid, theta_max)
27
+ theta_min = jnp.where(val <= 0, theta_mid, theta_min)
28
+ theta = (theta_min + theta_max) / 2
29
+ return R * (1 - jnp.cos(theta / 2))
30
+
31
+ # # Fonction objectif avec pondération quadratique
32
+ # def objective(h, R, f):
33
+ # total_area = jnp.pi * R**2
34
+ # target_area = f * total_area
35
+ # diff = wet_area(h, R) - target_area
36
+ # scale_factor = jnp.minimum(f, 1. - f)
37
+ # scale = 0.1 * R**2 * (scale_factor**2 + 0.01) # Échelle quadratique
38
+ # return 1 / (1 + jnp.exp(-diff / scale))
39
+
40
+ # def objective(h, R, f):
41
+ # total_area = jnp.pi * R**2
42
+ # target_area = f * total_area
43
+ # diff = wet_area(h, R) - target_area
44
+ # scale_factor = jnp.minimum(f, 1. - f)
45
+ # scale = 0.1 * R**2 * jnp.maximum(scale_factor, 0.01)
46
+ # return 0.5 * (1 + jnp.tanh(diff / scale))
47
+
48
+
49
+ # Fonction objectif avec lissage (inchangée)
50
+ def objective(h, R, f):
51
+ total_area = jnp.pi * R**2
52
+ target_area = f * total_area
53
+ diff = wet_area(h, R) - target_area
54
+ scale_factor = jnp.minimum(f, 1. - f)
55
+ scale = 0.05 * R**2 * jnp.maximum(scale_factor, 0.01)
56
+ return 1 / (1 + jnp.exp(-diff / scale))
57
+
58
+ # Dichotomie douce avec préservation de la racine
59
+ @jit
60
+ def soft_dichotomy(R, f, max_iter=10000):
61
+ f_sym = jnp.minimum(f, 1 - f)
62
+
63
+ def body(state, _):
64
+ h_min, h_max = state
65
+ h_mid = (h_min + h_max) / 2
66
+ sigmoid_val = objective(h_mid, R, f_sym)
67
+
68
+ # Différences pour h_min, h_mid et h_max
69
+ diff_min = wet_area(h_min, R) - f_sym * jnp.pi * R**2
70
+ diff_max = wet_area(h_max, R) - f_sym * jnp.pi * R**2
71
+
72
+ # Facteurs de préservation lisses
73
+ preserve_min = jnp.exp(-jnp.abs(diff_min) / (0.01)) # Proche de 1 si h_min est racine
74
+ preserve_max = jnp.exp(-jnp.abs(diff_max) / (0.01)) # Proche de 1 si h_max est racine
75
+
76
+ # Mise à jour des bornes avec préservation
77
+ h_min_new = h_min + (1. - preserve_min) * (h_mid - h_min) * (1. - sigmoid_val)
78
+ h_max_new = h_max - (1. - preserve_max) * (h_max - h_mid) * sigmoid_val
79
+
80
+ # # Garantie que h_min_new < h_max_new
81
+ # h_min_new = jnp.minimum(h_min_new, h_mid - 0.01 * R)
82
+ # h_max_new = jnp.maximum(h_max_new, h_mid + 0.01 * R)
83
+
84
+ return (h_min_new, h_max_new), None
85
+
86
+ h_min_init = jnp.float32(0.0)
87
+ h_max_init = jnp.float32(2 * R)
88
+ initial_state = (h_min_init, h_max_init)
89
+ final_state, _ = jax.lax.scan(body, initial_state, None, length=max_iter)
90
+ h_min, h_max = final_state
91
+ h_sym = (h_min + h_max) / 2
92
+ return jnp.where(f <= 0.5, h_sym, 2 * R - h_sym)
93
+
94
+ # Dérivée par rapport à f
95
+ grad_bisection = jax.grad(soft_dichotomy, argnums=1)
96
+
97
+ # Fonction objectif avec lissage
98
+ def section(h, R, f):
99
+ total_area = jnp.pi * R**2
100
+ target_area = f * total_area
101
+ return wet_area(jnp.clip(h, 0, 2 * R), R) - target_area
102
+
103
+ grad_section = jax.grad(section, argnums=0)
104
+
105
+ # recherche de la recine de la section
106
+ def find_root(R, f):
107
+ def fun(h):
108
+ return section(h, R, f)
109
+ def grad(h):
110
+ return grad_section(h, R, f)
111
+
112
+ h_root = root_scalar(fun, fprime=grad, x0=R)
113
+ return h_root.root
114
+
115
+ h = find_root(1.,0.5)
116
+ pass
117
+
118
+ if __name__ == "__main__":
119
+ R = jnp.float32(1.0)
120
+ f_values = jnp.linspace(jnp.float32(0.00), jnp.float32(1.), 5000, endpoint=True)
121
+
122
+ h_numerical = vmap(lambda f: soft_dichotomy(R, f))(f_values)
123
+ h_analytical = vmap(lambda f: analytical_h(R, f))(f_values)
124
+ errors = jnp.abs(h_numerical - h_analytical)
125
+
126
+ grads = vmap(lambda f: grad_bisection(R, f))(f_values)
127
+
128
+ plt.figure(figsize=(12, 5))
129
+
130
+ plt.subplot(1, 3, 1)
131
+ plt.plot(f_values, h_numerical, label="Numérique (symétrie centrale)", color="blue")
132
+ plt.plot(f_values, h_analytical, "--", label="Analytique", color="orange")
133
+ plt.xlabel("Fraction immergée (f)")
134
+ plt.ylabel("Hauteur (h)")
135
+ plt.title("Hauteur en fonction de f (float32)")
136
+ plt.legend()
137
+ plt.grid(True)
138
+ # plt.yscale("log")
139
+
140
+ plt.subplot(1, 3, 2)
141
+ plt.plot(f_values, errors, color="red")
142
+ plt.xlabel("Fraction immergée (f)")
143
+ plt.ylabel("Erreur absolue (|h_num - h_ana|)")
144
+ plt.title("Erreur par rapport à la solution analytique")
145
+ plt.grid(True)
146
+ plt.yscale("log")
147
+
148
+ plt.subplot(1, 3, 3)
149
+ plt.plot(f_values, grads, label="Dérivée par rapport à f")
150
+ plt.xlabel("Fraction immergée (f)")
151
+ plt.ylabel("Gradient de f par rapport à h")
152
+ plt.legend()
153
+ plt.grid(True)
154
+
155
+ plt.tight_layout()
156
+ plt.show()
157
+
158
+ for f_test in [0., 0.001, 0.01, 0.5, 0.99, 0.999]:
159
+ f_test = jnp.float32(f_test)
160
+ h_num = soft_dichotomy(R, f_test)
161
+ h_ana = analytical_h(R, f_test)
162
+ grad_h = grad_bisection(R, f_test)
163
+ print(f"f = {f_test:.4f}:")
164
+ print(f" h numérique = {h_num:.6f}")
165
+ print(f" h analytique = {h_ana:.6f}")
166
+ print(f" Gradient de h par rapport à f = {grad_h:.6f}")
167
+ print(f" Erreur = {jnp.abs(h_num - h_ana):.6f}")
168
+ print(f" Erreur relative = {jnp.abs(h_num - h_ana) / h_ana:.6e}")
169
+ pass