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/PyDraw.py +19 -6
- wolfhece/acceptability/acceptability_gui.py +243 -243
- wolfhece/apps/version.py +1 -1
- wolfhece/lazviewer/laz_viewer.py +31 -18
- wolfhece/matplotlib_fig.py +4 -4
- wolfhece/scenario/update_void.py +1 -1
- wolfhece/sigmoid/__init__.py +0 -0
- wolfhece/sigmoid/circle_jax.py +118 -0
- wolfhece/sigmoid/circle_jax_copilot.py +169 -0
- wolfhece/sigmoid/sigmoid.py +776 -0
- wolfhece/wolfresults_2D.py +16 -6
- {wolfhece-2.1.123.dist-info → wolfhece-2.1.125.dist-info}/METADATA +1 -1
- {wolfhece-2.1.123.dist-info → wolfhece-2.1.125.dist-info}/RECORD +16 -12
- {wolfhece-2.1.123.dist-info → wolfhece-2.1.125.dist-info}/WHEEL +1 -1
- {wolfhece-2.1.123.dist-info → wolfhece-2.1.125.dist-info}/entry_points.txt +0 -0
- {wolfhece-2.1.123.dist-info → wolfhece-2.1.125.dist-info}/top_level.txt +0 -0
wolfhece/apps/version.py
CHANGED
wolfhece/lazviewer/laz_viewer.py
CHANGED
@@ -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
|
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.
|
703
|
-
figmpl.
|
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
|
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
|
-
|
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] =
|
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()
|
wolfhece/matplotlib_fig.py
CHANGED
@@ -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
|
-
|
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:
|
wolfhece/scenario/update_void.py
CHANGED
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
|