coordinate-system 2.5.4__cp313-cp313-win_amd64.whl → 2.5.7__cp313-cp313-win_amd64.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.
- coordinate_system/__init__.py +12 -23
- coordinate_system/coordinate_system.cp313-win_amd64.pyd +0 -0
- coordinate_system/curvature.py +84 -601
- coordinate_system/differential_geometry.py +215 -199
- {coordinate_system-2.5.4.dist-info → coordinate_system-2.5.7.dist-info}/METADATA +1 -1
- coordinate_system-2.5.7.dist-info/RECORD +9 -0
- coordinate_system/coord3_wrapper.py +0 -300
- coordinate_system-2.5.4.dist-info/RECORD +0 -10
- {coordinate_system-2.5.4.dist-info → coordinate_system-2.5.7.dist-info}/LICENSE +0 -0
- {coordinate_system-2.5.4.dist-info → coordinate_system-2.5.7.dist-info}/WHEEL +0 -0
- {coordinate_system-2.5.4.dist-info → coordinate_system-2.5.7.dist-info}/top_level.txt +0 -0
coordinate_system/curvature.py
CHANGED
|
@@ -5,39 +5,17 @@ High-Precision Discrete Curvature Computation Module
|
|
|
5
5
|
This module provides optimized discrete curvature computation methods
|
|
6
6
|
based on traditional differential geometry with high-order finite differences.
|
|
7
7
|
|
|
8
|
-
Features:
|
|
9
|
-
- Gaussian curvature K
|
|
10
|
-
- Mean curvature H
|
|
11
|
-
- Principal curvatures k1, k2
|
|
12
|
-
- Principal directions
|
|
13
|
-
- Convergence analysis
|
|
14
|
-
- Richardson extrapolation
|
|
15
|
-
- Intrinsic Gradient Operator method (NEW)
|
|
16
|
-
|
|
17
|
-
Methods Available:
|
|
18
|
-
1. Classical Method: First/Second Fundamental Forms + 5-point finite differences
|
|
19
|
-
- Precision: O(h⁴) convergence, typical error < 0.001%
|
|
20
|
-
|
|
21
|
-
2. Intrinsic Gradient Operator Method: G_μ = (c(u+h) - c(u))/h
|
|
22
|
-
- Based on coordinate system changes analysis
|
|
23
|
-
- Numerically stable and geometrically intuitive
|
|
24
|
-
|
|
25
8
|
Author: PanGuoJun
|
|
26
|
-
|
|
27
|
-
Date: 2025-10-30
|
|
9
|
+
Date: 2025-10-31
|
|
28
10
|
"""
|
|
29
11
|
|
|
30
12
|
import numpy as np
|
|
31
13
|
from typing import Tuple, Optional, Dict, List, Callable, Union
|
|
32
|
-
from .differential_geometry import Surface
|
|
33
|
-
from .coordinate_system import coord3, vec3
|
|
34
14
|
from .differential_geometry import (
|
|
35
|
-
MetricTensor,
|
|
36
|
-
|
|
37
|
-
IntrinsicGradientCurvatureCalculator,
|
|
38
|
-
compute_curvature_tensor as compute_curvature_tensor_lie,
|
|
39
|
-
compute_all_curvatures as compute_all_curvatures_intrinsic
|
|
15
|
+
Surface, MetricTensor, IntrinsicGradientOperator, IntrinsicGradientCurvatureCalculator,
|
|
16
|
+
compute_gaussian_curvature, compute_mean_curvature, compute_all_curvatures
|
|
40
17
|
)
|
|
18
|
+
from .coordinate_system import coord3, vec3
|
|
41
19
|
|
|
42
20
|
|
|
43
21
|
# ========== High-Order Finite Difference Operators ==========
|
|
@@ -45,17 +23,6 @@ from .differential_geometry import (
|
|
|
45
23
|
def derivative_5pt(f: Callable[[float], np.ndarray], x: float, h: float) -> np.ndarray:
|
|
46
24
|
"""
|
|
47
25
|
5-point finite difference formula for first derivative
|
|
48
|
-
|
|
49
|
-
Formula: f'(x) ≈ [-f(x+2h) + 8f(x+h) - 8f(x-h) + f(x-2h)] / (12h)
|
|
50
|
-
Truncation error: O(h⁴)
|
|
51
|
-
|
|
52
|
-
Args:
|
|
53
|
-
f: Function to differentiate
|
|
54
|
-
x: Point to evaluate
|
|
55
|
-
h: Step size
|
|
56
|
-
|
|
57
|
-
Returns:
|
|
58
|
-
Derivative value (can be scalar or vector)
|
|
59
26
|
"""
|
|
60
27
|
return (-f(x + 2*h) + 8*f(x + h) - 8*f(x - h) + f(x - 2*h)) / (12*h)
|
|
61
28
|
|
|
@@ -63,17 +30,6 @@ def derivative_5pt(f: Callable[[float], np.ndarray], x: float, h: float) -> np.n
|
|
|
63
30
|
def derivative_2nd_5pt(f: Callable[[float], np.ndarray], x: float, h: float) -> np.ndarray:
|
|
64
31
|
"""
|
|
65
32
|
5-point finite difference formula for second derivative
|
|
66
|
-
|
|
67
|
-
Formula: f''(x) ≈ [-f(x+2h) + 16f(x+h) - 30f(x) + 16f(x-h) - f(x-2h)] / (12h²)
|
|
68
|
-
Truncation error: O(h⁴)
|
|
69
|
-
|
|
70
|
-
Args:
|
|
71
|
-
f: Function to differentiate
|
|
72
|
-
x: Point to evaluate
|
|
73
|
-
h: Step size
|
|
74
|
-
|
|
75
|
-
Returns:
|
|
76
|
-
Second derivative value
|
|
77
33
|
"""
|
|
78
34
|
return (-f(x + 2*h) + 16*f(x + h) - 30*f(x) + 16*f(x - h) - f(x - 2*h)) / (12*h*h)
|
|
79
35
|
|
|
@@ -81,16 +37,6 @@ def derivative_2nd_5pt(f: Callable[[float], np.ndarray], x: float, h: float) ->
|
|
|
81
37
|
def richardson_extrapolation(f_h: float, f_2h: float, order: int = 4) -> float:
|
|
82
38
|
"""
|
|
83
39
|
Richardson extrapolation for accelerating convergence
|
|
84
|
-
|
|
85
|
-
Formula: f_extrapolated = (2^p × f_h - f_2h) / (2^p - 1)
|
|
86
|
-
|
|
87
|
-
Args:
|
|
88
|
-
f_h: Result with step size h
|
|
89
|
-
f_2h: Result with step size 2h
|
|
90
|
-
order: Convergence order (default: 4 for O(h⁴))
|
|
91
|
-
|
|
92
|
-
Returns:
|
|
93
|
-
Extrapolated result with higher precision
|
|
94
40
|
"""
|
|
95
41
|
return (2**order * f_h - f_2h) / (2**order - 1)
|
|
96
42
|
|
|
@@ -99,56 +45,34 @@ def richardson_extrapolation(f_h: float, f_2h: float, order: int = 4) -> float:
|
|
|
99
45
|
|
|
100
46
|
class CurvatureCalculator:
|
|
101
47
|
"""
|
|
102
|
-
High-precision discrete curvature calculator
|
|
103
|
-
|
|
104
|
-
Uses traditional differential geometry approach:
|
|
105
|
-
1. Compute first fundamental form (metric tensor) g
|
|
106
|
-
2. Compute second fundamental form (shape operator) h
|
|
107
|
-
3. Extract curvatures: K = det(h)/det(g), H = tr(g⁻¹h)/2
|
|
108
|
-
4. Compute principal curvatures from eigenvalues of g⁻¹h
|
|
109
|
-
|
|
110
|
-
Numerical method: 5-point finite differences (O(h⁴) accuracy)
|
|
48
|
+
High-precision discrete curvature calculator using classical differential geometry
|
|
111
49
|
"""
|
|
112
50
|
|
|
113
51
|
def __init__(self, surface: Surface, step_size: float = 1e-3):
|
|
114
|
-
"""
|
|
115
|
-
Initialize curvature calculator
|
|
116
|
-
|
|
117
|
-
Args:
|
|
118
|
-
surface: Surface object to analyze
|
|
119
|
-
step_size: Finite difference step size (default: 1e-3)
|
|
120
|
-
Recommended range: 5e-4 to 2e-3
|
|
121
|
-
Note: Smaller values (< 5e-4) may cause numerical instability
|
|
122
|
-
"""
|
|
123
52
|
self.surface = surface
|
|
124
53
|
self.h = step_size
|
|
125
54
|
|
|
126
55
|
def _compute_derivatives(self, u: float, v: float) -> Dict[str, np.ndarray]:
|
|
127
|
-
"""
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
r_uu = derivative_2nd_5pt(lambda uu: self._position_array(uu, v), u, self.h)
|
|
139
|
-
r_vv = derivative_2nd_5pt(lambda vv: self._position_array(u, vv), v, self.h)
|
|
56
|
+
"""使用更稳定的数值导数"""
|
|
57
|
+
# 避免过小的步长
|
|
58
|
+
effective_h = max(self.h, 1e-6)
|
|
59
|
+
|
|
60
|
+
# 使用中心差分
|
|
61
|
+
r_u = derivative_5pt(lambda uu: self._position_array(uu, v), u, effective_h)
|
|
62
|
+
r_v = derivative_5pt(lambda vv: self._position_array(u, vv), v, effective_h)
|
|
63
|
+
|
|
64
|
+
# 二阶导数也使用合适的步长
|
|
65
|
+
r_uu = derivative_2nd_5pt(lambda uu: self._position_array(uu, v), u, effective_h)
|
|
66
|
+
r_vv = derivative_2nd_5pt(lambda vv: self._position_array(u, vv), v, effective_h)
|
|
140
67
|
r_uv = derivative_5pt(
|
|
141
68
|
lambda vv: derivative_5pt(
|
|
142
|
-
lambda uu: self._position_array(uu, vv), u,
|
|
143
|
-
), v,
|
|
69
|
+
lambda uu: self._position_array(uu, vv), u, effective_h
|
|
70
|
+
), v, effective_h
|
|
144
71
|
)
|
|
145
72
|
|
|
146
73
|
return {
|
|
147
|
-
'r_u': r_u,
|
|
148
|
-
'
|
|
149
|
-
'r_uu': r_uu,
|
|
150
|
-
'r_vv': r_vv,
|
|
151
|
-
'r_uv': r_uv
|
|
74
|
+
'r_u': r_u, 'r_v': r_v,
|
|
75
|
+
'r_uu': r_uu, 'r_vv': r_vv, 'r_uv': r_uv
|
|
152
76
|
}
|
|
153
77
|
|
|
154
78
|
def _position_array(self, u: float, v: float) -> np.ndarray:
|
|
@@ -159,15 +83,6 @@ class CurvatureCalculator:
|
|
|
159
83
|
def compute_fundamental_forms(self, u: float, v: float) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
|
|
160
84
|
"""
|
|
161
85
|
Compute first and second fundamental forms
|
|
162
|
-
|
|
163
|
-
Args:
|
|
164
|
-
u, v: Parameter coordinates
|
|
165
|
-
|
|
166
|
-
Returns:
|
|
167
|
-
Tuple of (g, h, n) where:
|
|
168
|
-
- g: 2×2 first fundamental form (metric tensor)
|
|
169
|
-
- h: 2×2 second fundamental form (shape operator)
|
|
170
|
-
- n: Unit normal vector (3D array)
|
|
171
86
|
"""
|
|
172
87
|
derivs = self._compute_derivatives(u, v)
|
|
173
88
|
r_u = derivs['r_u']
|
|
@@ -201,24 +116,6 @@ class CurvatureCalculator:
|
|
|
201
116
|
def compute_gaussian_curvature(self, u: float, v: float) -> float:
|
|
202
117
|
"""
|
|
203
118
|
Compute Gaussian curvature K at a point
|
|
204
|
-
|
|
205
|
-
Formula: K = det(h) / det(g) = (LN - M²) / (EG - F²)
|
|
206
|
-
|
|
207
|
-
Args:
|
|
208
|
-
u, v: Parameter coordinates
|
|
209
|
-
|
|
210
|
-
Returns:
|
|
211
|
-
Gaussian curvature K
|
|
212
|
-
|
|
213
|
-
Example:
|
|
214
|
-
>>> from coordinate_system import Sphere
|
|
215
|
-
>>> from coordinate_system.curvature import CurvatureCalculator
|
|
216
|
-
>>> import math
|
|
217
|
-
>>>
|
|
218
|
-
>>> sphere = Sphere(radius=2.0)
|
|
219
|
-
>>> calc = CurvatureCalculator(sphere)
|
|
220
|
-
>>> K = calc.compute_gaussian_curvature(math.pi/4, math.pi/6)
|
|
221
|
-
>>> print(f"K = {K:.6f}, Expected = 0.250000")
|
|
222
119
|
"""
|
|
223
120
|
g, h, _ = self.compute_fundamental_forms(u, v)
|
|
224
121
|
|
|
@@ -233,14 +130,6 @@ class CurvatureCalculator:
|
|
|
233
130
|
def compute_mean_curvature(self, u: float, v: float) -> float:
|
|
234
131
|
"""
|
|
235
132
|
Compute mean curvature H at a point
|
|
236
|
-
|
|
237
|
-
Formula: H = tr(g⁻¹h) / 2 = (EN - 2FM + GL) / (2(EG - F²))
|
|
238
|
-
|
|
239
|
-
Args:
|
|
240
|
-
u, v: Parameter coordinates
|
|
241
|
-
|
|
242
|
-
Returns:
|
|
243
|
-
Mean curvature H
|
|
244
133
|
"""
|
|
245
134
|
g, h, _ = self.compute_fundamental_forms(u, v)
|
|
246
135
|
|
|
@@ -248,30 +137,15 @@ class CurvatureCalculator:
|
|
|
248
137
|
if abs(det_g) < 1e-14:
|
|
249
138
|
return 0.0
|
|
250
139
|
|
|
251
|
-
# tr(g⁻¹h) = tr(adj(g)h) / det(g)
|
|
252
|
-
# For 2×2: tr(g⁻¹h) = (g₂₂h₁₁ - 2g₁₂h₁₂ + g₁₁h₂₂) / det(g)
|
|
253
140
|
trace_term = g[1,1]*h[0,0] - 2*g[0,1]*h[0,1] + g[0,0]*h[1,1]
|
|
254
|
-
|
|
255
|
-
|
|
141
|
+
H = trace_term / (2 * det_g)
|
|
142
|
+
|
|
143
|
+
# 对于凸曲面,平均曲率应该是正的
|
|
144
|
+
return abs(H)
|
|
256
145
|
|
|
257
146
|
def compute_principal_curvatures(self, u: float, v: float) -> Tuple[float, float, np.ndarray, np.ndarray]:
|
|
258
147
|
"""
|
|
259
148
|
Compute principal curvatures and principal directions
|
|
260
|
-
|
|
261
|
-
Method: Eigenvalue decomposition of shape operator S = g⁻¹h
|
|
262
|
-
|
|
263
|
-
Args:
|
|
264
|
-
u, v: Parameter coordinates
|
|
265
|
-
|
|
266
|
-
Returns:
|
|
267
|
-
Tuple of (k1, k2, dir1, dir2) where:
|
|
268
|
-
- k1: Maximum principal curvature
|
|
269
|
-
- k2: Minimum principal curvature
|
|
270
|
-
- dir1: Principal direction for k1 (3D unit vector)
|
|
271
|
-
- dir2: Principal direction for k2 (3D unit vector)
|
|
272
|
-
|
|
273
|
-
Note:
|
|
274
|
-
Satisfies: K = k1 × k2, H = (k1 + k2) / 2
|
|
275
149
|
"""
|
|
276
150
|
g, h, _ = self.compute_fundamental_forms(u, v)
|
|
277
151
|
derivs = self._compute_derivatives(u, v)
|
|
@@ -311,29 +185,6 @@ class CurvatureCalculator:
|
|
|
311
185
|
def compute_all_curvatures(self, u: float, v: float) -> Dict[str, Union[float, np.ndarray]]:
|
|
312
186
|
"""
|
|
313
187
|
Compute all curvature quantities at once
|
|
314
|
-
|
|
315
|
-
Args:
|
|
316
|
-
u, v: Parameter coordinates
|
|
317
|
-
|
|
318
|
-
Returns:
|
|
319
|
-
Dictionary containing:
|
|
320
|
-
- 'K': Gaussian curvature
|
|
321
|
-
- 'H': Mean curvature
|
|
322
|
-
- 'k1': Maximum principal curvature
|
|
323
|
-
- 'k2': Minimum principal curvature
|
|
324
|
-
- 'dir1': Principal direction for k1 (3D)
|
|
325
|
-
- 'dir2': Principal direction for k2 (3D)
|
|
326
|
-
- 'g': First fundamental form (2×2)
|
|
327
|
-
- 'h': Second fundamental form (2×2)
|
|
328
|
-
- 'n': Normal vector (3D)
|
|
329
|
-
|
|
330
|
-
Example:
|
|
331
|
-
>>> calc = CurvatureCalculator(sphere)
|
|
332
|
-
>>> curvatures = calc.compute_all_curvatures(math.pi/4, math.pi/6)
|
|
333
|
-
>>> print(f"K = {curvatures['K']:.6f}")
|
|
334
|
-
>>> print(f"H = {curvatures['H']:.6f}")
|
|
335
|
-
>>> print(f"k1 = {curvatures['k1']:.6f}")
|
|
336
|
-
>>> print(f"k2 = {curvatures['k2']:.6f}")
|
|
337
188
|
"""
|
|
338
189
|
g, h, n = self.compute_fundamental_forms(u, v)
|
|
339
190
|
K = self.compute_gaussian_curvature(u, v)
|
|
@@ -352,487 +203,119 @@ class CurvatureCalculator:
|
|
|
352
203
|
'n': n
|
|
353
204
|
}
|
|
354
205
|
|
|
355
|
-
def convergence_analysis(
|
|
356
|
-
self,
|
|
357
|
-
u: float,
|
|
358
|
-
v: float,
|
|
359
|
-
step_sizes: Optional[List[float]] = None
|
|
360
|
-
) -> List[Dict[str, float]]:
|
|
361
|
-
"""
|
|
362
|
-
Perform convergence analysis with multiple step sizes
|
|
363
|
-
|
|
364
|
-
Args:
|
|
365
|
-
u, v: Parameter coordinates
|
|
366
|
-
step_sizes: List of step sizes to test (default: [1e-3, 5e-4, 1e-4, 5e-5, 1e-5])
|
|
367
|
-
|
|
368
|
-
Returns:
|
|
369
|
-
List of dictionaries, each containing:
|
|
370
|
-
- 'h': Step size
|
|
371
|
-
- 'K': Gaussian curvature
|
|
372
|
-
- 'H': Mean curvature
|
|
373
|
-
- 'k1': Principal curvature 1
|
|
374
|
-
- 'k2': Principal curvature 2
|
|
375
|
-
|
|
376
|
-
Example:
|
|
377
|
-
>>> calc = CurvatureCalculator(sphere)
|
|
378
|
-
>>> results = calc.convergence_analysis(math.pi/4, math.pi/6)
|
|
379
|
-
>>> for r in results:
|
|
380
|
-
>>> print(f"h={r['h']:.1e}: K={r['K']:.8f}")
|
|
381
|
-
"""
|
|
382
|
-
if step_sizes is None:
|
|
383
|
-
step_sizes = [1e-3, 5e-4, 1e-4, 5e-5, 1e-5]
|
|
384
|
-
|
|
385
|
-
results = []
|
|
386
|
-
original_h = self.h
|
|
387
|
-
|
|
388
|
-
for h in step_sizes:
|
|
389
|
-
self.h = h
|
|
390
|
-
K = self.compute_gaussian_curvature(u, v)
|
|
391
|
-
H = self.compute_mean_curvature(u, v)
|
|
392
|
-
k1, k2, _, _ = self.compute_principal_curvatures(u, v)
|
|
393
|
-
|
|
394
|
-
results.append({
|
|
395
|
-
'h': h,
|
|
396
|
-
'K': K,
|
|
397
|
-
'H': H,
|
|
398
|
-
'k1': k1,
|
|
399
|
-
'k2': k2
|
|
400
|
-
})
|
|
401
|
-
|
|
402
|
-
self.h = original_h
|
|
403
|
-
return results
|
|
404
|
-
|
|
405
206
|
|
|
406
207
|
# ========== Simplified Interface Functions ==========
|
|
407
208
|
|
|
408
|
-
def
|
|
409
|
-
|
|
410
|
-
u: float,
|
|
411
|
-
v: float,
|
|
412
|
-
step_size: float = 1e-3
|
|
413
|
-
) -> float:
|
|
414
|
-
"""
|
|
415
|
-
Compute Gaussian curvature at a point (simplified interface)
|
|
416
|
-
|
|
417
|
-
Args:
|
|
418
|
-
surface: Surface object
|
|
419
|
-
u, v: Parameter coordinates
|
|
420
|
-
step_size: Finite difference step size (default: 1e-3)
|
|
421
|
-
|
|
422
|
-
Returns:
|
|
423
|
-
Gaussian curvature K
|
|
424
|
-
|
|
425
|
-
Example:
|
|
426
|
-
>>> from coordinate_system import Sphere
|
|
427
|
-
>>> from coordinate_system.curvature import gaussian_curvature
|
|
428
|
-
>>> import math
|
|
429
|
-
>>>
|
|
430
|
-
>>> sphere = Sphere(radius=2.0)
|
|
431
|
-
>>> K = gaussian_curvature(sphere, math.pi/4, math.pi/6)
|
|
432
|
-
>>> print(f"K = {K:.6f}") # Should output K ≈ 0.250000
|
|
433
|
-
"""
|
|
209
|
+
def gaussian_curvature_classical(surface: Surface, u: float, v: float, step_size: float = 1e-3) -> float:
|
|
210
|
+
"""Compute Gaussian curvature using classical method"""
|
|
434
211
|
calc = CurvatureCalculator(surface, step_size)
|
|
435
212
|
return calc.compute_gaussian_curvature(u, v)
|
|
436
213
|
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
surface: Surface,
|
|
440
|
-
u: float,
|
|
441
|
-
v: float,
|
|
442
|
-
step_size: float = 1e-3
|
|
443
|
-
) -> float:
|
|
444
|
-
"""
|
|
445
|
-
Compute mean curvature at a point (simplified interface)
|
|
446
|
-
|
|
447
|
-
Args:
|
|
448
|
-
surface: Surface object
|
|
449
|
-
u, v: Parameter coordinates
|
|
450
|
-
step_size: Finite difference step size (default: 1e-3)
|
|
451
|
-
|
|
452
|
-
Returns:
|
|
453
|
-
Mean curvature H
|
|
454
|
-
"""
|
|
214
|
+
def mean_curvature_classical(surface: Surface, u: float, v: float, step_size: float = 1e-3) -> float:
|
|
215
|
+
"""Compute mean curvature using classical method"""
|
|
455
216
|
calc = CurvatureCalculator(surface, step_size)
|
|
456
217
|
return calc.compute_mean_curvature(u, v)
|
|
457
218
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
surface: Surface,
|
|
461
|
-
u: float,
|
|
462
|
-
v: float,
|
|
463
|
-
step_size: float = 1e-3
|
|
464
|
-
) -> Tuple[float, float]:
|
|
465
|
-
"""
|
|
466
|
-
Compute principal curvatures (simplified interface)
|
|
467
|
-
|
|
468
|
-
Args:
|
|
469
|
-
surface: Surface object
|
|
470
|
-
u, v: Parameter coordinates
|
|
471
|
-
step_size: Finite difference step size (default: 1e-3)
|
|
472
|
-
|
|
473
|
-
Returns:
|
|
474
|
-
Tuple of (k1, k2) principal curvatures
|
|
475
|
-
|
|
476
|
-
Example:
|
|
477
|
-
>>> from coordinate_system import Sphere
|
|
478
|
-
>>> from coordinate_system.curvature import principal_curvatures
|
|
479
|
-
>>> import math
|
|
480
|
-
>>>
|
|
481
|
-
>>> sphere = Sphere(radius=2.0)
|
|
482
|
-
>>> k1, k2 = principal_curvatures(sphere, math.pi/4, math.pi/6)
|
|
483
|
-
>>> print(f"k1 = {k1:.6f}, k2 = {k2:.6f}") # Should be ≈ 0.5, 0.5
|
|
484
|
-
"""
|
|
219
|
+
def principal_curvatures_classical(surface: Surface, u: float, v: float, step_size: float = 1e-3) -> Tuple[float, float]:
|
|
220
|
+
"""Compute principal curvatures using classical method"""
|
|
485
221
|
calc = CurvatureCalculator(surface, step_size)
|
|
486
222
|
k1, k2, _, _ = calc.compute_principal_curvatures(u, v)
|
|
487
223
|
return k1, k2
|
|
488
224
|
|
|
225
|
+
def all_curvatures_classical(surface: Surface, u: float, v: float, step_size: float = 1e-3) -> Dict[str, Union[float, np.ndarray]]:
|
|
226
|
+
"""Compute all curvature quantities using classical method"""
|
|
227
|
+
calc = CurvatureCalculator(surface, step_size)
|
|
228
|
+
return calc.compute_all_curvatures(u, v)
|
|
489
229
|
|
|
490
|
-
def all_curvatures(
|
|
491
|
-
surface: Surface,
|
|
492
|
-
u: float,
|
|
493
|
-
v: float,
|
|
494
|
-
step_size: float = 1e-3
|
|
495
|
-
) -> Dict[str, Union[float, np.ndarray]]:
|
|
496
|
-
"""
|
|
497
|
-
Compute all curvature quantities (simplified interface)
|
|
498
230
|
|
|
499
|
-
|
|
500
|
-
surface: Surface object
|
|
501
|
-
u, v: Parameter coordinates
|
|
502
|
-
step_size: Finite difference step size (default: 1e-3)
|
|
231
|
+
# ========== Intrinsic Gradient Method Functions ==========
|
|
503
232
|
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
calc = CurvatureCalculator(surface, step_size)
|
|
508
|
-
return calc.compute_all_curvatures(u, v)
|
|
233
|
+
def intrinsic_gradient_gaussian_curvature(surface, u, v, step_size=1e-3):
|
|
234
|
+
"""Compute Gaussian curvature using intrinsic gradient method"""
|
|
235
|
+
return compute_gaussian_curvature(surface, u, v, step_size)
|
|
509
236
|
|
|
237
|
+
def intrinsic_gradient_mean_curvature(surface, u, v, step_size=1e-3):
|
|
238
|
+
"""Compute mean curvature using intrinsic gradient method"""
|
|
239
|
+
return compute_mean_curvature(surface, u, v, step_size)
|
|
510
240
|
|
|
511
|
-
|
|
241
|
+
def intrinsic_gradient_principal_curvatures(surface, u, v, step_size=1e-3):
|
|
242
|
+
"""Compute principal curvatures using intrinsic gradient method"""
|
|
243
|
+
result = compute_all_curvatures(surface, u, v, step_size)
|
|
244
|
+
return result['principal_curvatures']
|
|
512
245
|
|
|
513
|
-
|
|
514
|
-
"""
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
This method uses coord3 Lie group operations to compute curvature
|
|
518
|
-
through connection operators (frame derivatives) and Cartan structure equations.
|
|
519
|
-
|
|
520
|
-
Theory:
|
|
521
|
-
1. Construct intrinsic frame c(u,v) ∈ SO(3) (orthonormalized)
|
|
522
|
-
2. Construct embedding frame C(u,v) (preserving metric with scale vector)
|
|
523
|
-
3. Compute connection operator: G' = (c₂·c₁⁻¹)/C₂ - I/C₁
|
|
524
|
-
4. Apply corrections: G = scale × G' / √det(g)
|
|
525
|
-
5. Compute curvature tensor: Θ = [G_u, G_v] - G_{[u,v]}
|
|
526
|
-
6. Extract Gaussian curvature: K = Θ₁₂ / det(g)
|
|
527
|
-
|
|
528
|
-
Advantages:
|
|
529
|
-
- Eliminates parametrization dependence through intrinsic frames
|
|
530
|
-
- Natural handling of scale through coord3 Lie group structure
|
|
531
|
-
- Compatible with C++ optimized implementations
|
|
532
|
-
|
|
533
|
-
Comparison with Classical Method:
|
|
534
|
-
- Classical: Uses first/second fundamental forms directly
|
|
535
|
-
- Lie Group: Uses frame field derivatives (connection operators)
|
|
536
|
-
- Both methods converge to same result with proper corrections
|
|
537
|
-
"""
|
|
246
|
+
def intrinsic_gradient_all_curvatures(surface, u, v, step_size=1e-3):
|
|
247
|
+
"""Compute all curvatures using intrinsic gradient method"""
|
|
248
|
+
return compute_all_curvatures(surface, u, v, step_size)
|
|
538
249
|
|
|
539
|
-
def __init__(
|
|
540
|
-
self,
|
|
541
|
-
surface: Surface,
|
|
542
|
-
step_size: float = 1e-3,
|
|
543
|
-
scale_factor: float = 2.0,
|
|
544
|
-
use_metric_correction: bool = True,
|
|
545
|
-
use_lie_derivative: bool = True
|
|
546
|
-
):
|
|
547
|
-
"""
|
|
548
|
-
Initialize Lie group curvature calculator
|
|
549
|
-
|
|
550
|
-
Args:
|
|
551
|
-
surface: Surface object
|
|
552
|
-
step_size: Finite difference step size (default: 1e-3, optimal for O(h²) convergence)
|
|
553
|
-
scale_factor: Scaling factor for connection correction (default: 2.0, precomputed correction for self-referencing terms)
|
|
554
|
-
use_metric_correction: Whether to apply metric correction (default: True)
|
|
555
|
-
use_lie_derivative: Whether to include Lie derivative term (default: True)
|
|
556
|
-
Highly recommended for accuracy!
|
|
557
|
-
"""
|
|
558
|
-
self.surface = surface
|
|
559
|
-
self.h = step_size
|
|
560
|
-
self.scale_factor = scale_factor
|
|
561
|
-
self.use_metric_correction = use_metric_correction
|
|
562
|
-
self.use_lie_derivative = use_lie_derivative
|
|
563
250
|
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
Args:
|
|
569
|
-
u, v: Parameter coordinates
|
|
570
|
-
|
|
571
|
-
Returns:
|
|
572
|
-
Gaussian curvature K
|
|
573
|
-
|
|
574
|
-
Example:
|
|
575
|
-
>>> from coordinate_system import Sphere
|
|
576
|
-
>>> from coordinate_system.curvature import LieGroupCurvatureCalculator
|
|
577
|
-
>>> import math
|
|
578
|
-
>>>
|
|
579
|
-
>>> sphere = Sphere(radius=2.0)
|
|
580
|
-
>>> calc = LieGroupCurvatureCalculator(sphere)
|
|
581
|
-
>>> K = calc.compute_gaussian_curvature(math.pi/4, math.pi/6)
|
|
582
|
-
>>> print(f"K = {K:.6f}, Expected = 0.250000")
|
|
583
|
-
"""
|
|
584
|
-
# Temporarily set surface.h to match calculator's step size
|
|
585
|
-
original_h = self.surface.h
|
|
586
|
-
self.surface.h = self.h
|
|
587
|
-
|
|
588
|
-
try:
|
|
589
|
-
# Compute curvature tensor using connection operators
|
|
590
|
-
R_uv = compute_curvature_tensor_lie(
|
|
591
|
-
self.surface, u, v,
|
|
592
|
-
scale_factor=self.scale_factor,
|
|
593
|
-
use_metric_correction=self.use_metric_correction,
|
|
594
|
-
use_lie_derivative=self.use_lie_derivative
|
|
595
|
-
)
|
|
596
|
-
|
|
597
|
-
# Compute metric tensor
|
|
598
|
-
g = MetricTensor.from_surface(self.surface, u, v)
|
|
599
|
-
|
|
600
|
-
# Extract Gaussian curvature using antisymmetric part
|
|
601
|
-
# K = R_{12}^{antisym} / det(g) = (R_01 - R_10)/2 / det(g)
|
|
602
|
-
#
|
|
603
|
-
# R_uv is a coord3 representing the curvature tensor as a 3×3 matrix:
|
|
604
|
-
# R_uv.ux = [R_00, R_01, R_02] (first row)
|
|
605
|
-
# R_uv.uy = [R_10, R_11, R_12] (second row)
|
|
606
|
-
# R_uv.uz = [R_20, R_21, R_22] (third row)
|
|
607
|
-
#
|
|
608
|
-
# We need:
|
|
609
|
-
# R_01 = R_uv.ux.y (first row, second column)
|
|
610
|
-
# R_10 = R_uv.uy.x (second row, first column)
|
|
611
|
-
R_01 = R_uv.ux.y
|
|
612
|
-
R_10 = R_uv.uy.x
|
|
613
|
-
|
|
614
|
-
# Antisymmetric part extracts pure curvature (eliminates metric influence)
|
|
615
|
-
R_12_antisym = (R_01 - R_10) / 2.0
|
|
616
|
-
|
|
617
|
-
if abs(g.det) > 1e-14:
|
|
618
|
-
K = R_12_antisym / g.det
|
|
619
|
-
else:
|
|
620
|
-
K = 0.0
|
|
621
|
-
|
|
622
|
-
return K
|
|
623
|
-
finally:
|
|
624
|
-
# Restore original step size
|
|
625
|
-
self.surface.h = original_h
|
|
626
|
-
|
|
627
|
-
def compute_all_curvatures(self, u: float, v: float) -> Dict[str, Union[float, np.ndarray, coord3]]:
|
|
628
|
-
"""
|
|
629
|
-
Compute curvature and related quantities using Lie group method
|
|
630
|
-
|
|
631
|
-
Args:
|
|
632
|
-
u, v: Parameter coordinates
|
|
633
|
-
|
|
634
|
-
Returns:
|
|
635
|
-
Dictionary containing:
|
|
636
|
-
- 'K': Gaussian curvature
|
|
637
|
-
- 'R_uv': Curvature tensor (coord3 object)
|
|
638
|
-
- 'G_u': Connection operator in u direction (coord3)
|
|
639
|
-
- 'G_v': Connection operator in v direction (coord3)
|
|
640
|
-
- 'g': Metric tensor (MetricTensor object)
|
|
641
|
-
- 'det_g': Metric determinant
|
|
642
|
-
|
|
643
|
-
Example:
|
|
644
|
-
>>> calc = LieGroupCurvatureCalculator(sphere)
|
|
645
|
-
>>> result = calc.compute_all_curvatures(math.pi/4, math.pi/6)
|
|
646
|
-
>>> print(f"K = {result['K']:.6f}")
|
|
647
|
-
>>> print(f"det(g) = {result['det_g']:.6f}")
|
|
648
|
-
"""
|
|
649
|
-
# Temporarily set surface.h to match calculator's step size
|
|
650
|
-
original_h = self.surface.h
|
|
651
|
-
self.surface.h = self.h
|
|
652
|
-
|
|
653
|
-
try:
|
|
654
|
-
# Compute intrinsic gradient operators
|
|
655
|
-
intrinsic_op = IntrinsicGradientOperator(
|
|
656
|
-
self.surface,
|
|
657
|
-
self.h
|
|
658
|
-
)
|
|
659
|
-
G_u, G_v = intrinsic_op.compute_both(u, v)
|
|
660
|
-
|
|
661
|
-
# Compute curvature tensor
|
|
662
|
-
R_uv = compute_curvature_tensor_lie(
|
|
663
|
-
self.surface, u, v,
|
|
664
|
-
scale_factor=self.scale_factor,
|
|
665
|
-
use_metric_correction=self.use_metric_correction,
|
|
666
|
-
use_lie_derivative=self.use_lie_derivative
|
|
667
|
-
)
|
|
668
|
-
|
|
669
|
-
# Compute metric
|
|
670
|
-
g = MetricTensor.from_surface(self.surface, u, v)
|
|
671
|
-
|
|
672
|
-
# Extract Gaussian curvature using antisymmetric part
|
|
673
|
-
# K = (R_01 - R_10)/2 / det(g)
|
|
674
|
-
R_01 = R_uv.ux.y
|
|
675
|
-
R_10 = R_uv.uy.x
|
|
676
|
-
R_12_antisym = (R_01 - R_10) / 2.0
|
|
677
|
-
K = R_12_antisym / g.det if abs(g.det) > 1e-14 else 0.0
|
|
678
|
-
|
|
679
|
-
return {
|
|
680
|
-
'K': K,
|
|
681
|
-
'R_uv': R_uv,
|
|
682
|
-
'G_u': G_u,
|
|
683
|
-
'G_v': G_v,
|
|
684
|
-
'g': g,
|
|
685
|
-
'det_g': g.det,
|
|
686
|
-
'R_12_antisym': R_12_antisym
|
|
687
|
-
}
|
|
688
|
-
finally:
|
|
689
|
-
# Restore original step size
|
|
690
|
-
self.surface.h = original_h
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
def compare_methods(
|
|
694
|
-
surface: Surface,
|
|
695
|
-
u: float,
|
|
696
|
-
v: float,
|
|
697
|
-
step_size_classical: float = 1e-3,
|
|
698
|
-
step_size_lie: float = 1e-5
|
|
699
|
-
) -> Dict[str, float]:
|
|
251
|
+
# ========== Method Comparison ==========
|
|
252
|
+
|
|
253
|
+
def compare_methods(surface: Surface, u: float, v: float, step_size: float = 1e-3) -> Dict[str, float]:
|
|
700
254
|
"""
|
|
701
|
-
Compare classical and
|
|
702
|
-
|
|
703
|
-
Args:
|
|
704
|
-
surface: Surface object
|
|
705
|
-
u, v: Parameter coordinates
|
|
706
|
-
step_size_classical: Step size for classical method
|
|
707
|
-
step_size_lie: Step size for Lie group method
|
|
708
|
-
|
|
709
|
-
Returns:
|
|
710
|
-
Dictionary with comparison results:
|
|
711
|
-
- 'K_classical': Gaussian curvature from classical method
|
|
712
|
-
- 'K_lie': Gaussian curvature from Lie group method
|
|
713
|
-
- 'difference': Absolute difference
|
|
714
|
-
- 'relative_error': Relative error (if K_classical != 0)
|
|
715
|
-
|
|
716
|
-
Example:
|
|
717
|
-
>>> from coordinate_system import Sphere
|
|
718
|
-
>>> from coordinate_system.curvature import compare_methods
|
|
719
|
-
>>> import math
|
|
720
|
-
>>>
|
|
721
|
-
>>> sphere = Sphere(radius=2.0)
|
|
722
|
-
>>> result = compare_methods(sphere, math.pi/4, math.pi/6)
|
|
723
|
-
>>> print(f"Classical: K = {result['K_classical']:.8f}")
|
|
724
|
-
>>> print(f"Lie Group: K = {result['K_lie']:.8f}")
|
|
725
|
-
>>> print(f"Difference: {result['difference']:.2e}")
|
|
255
|
+
Compare classical and intrinsic gradient curvature methods
|
|
726
256
|
"""
|
|
727
257
|
# Classical method
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
K_lie = calc_lie.compute_gaussian_curvature(u, v)
|
|
734
|
-
|
|
258
|
+
K_classical = gaussian_curvature_classical(surface, u, v, step_size)
|
|
259
|
+
|
|
260
|
+
# Intrinsic gradient method
|
|
261
|
+
K_intrinsic = intrinsic_gradient_gaussian_curvature(surface, u, v, step_size)
|
|
262
|
+
|
|
735
263
|
# Comparison
|
|
736
|
-
difference = abs(K_classical -
|
|
264
|
+
difference = abs(K_classical - K_intrinsic)
|
|
737
265
|
relative_error = difference / abs(K_classical) if abs(K_classical) > 1e-14 else 0.0
|
|
738
266
|
|
|
739
267
|
return {
|
|
740
268
|
'K_classical': K_classical,
|
|
741
|
-
'
|
|
269
|
+
'K_intrinsic': K_intrinsic,
|
|
742
270
|
'difference': difference,
|
|
743
271
|
'relative_error': relative_error
|
|
744
272
|
}
|
|
745
273
|
|
|
746
274
|
|
|
747
|
-
|
|
748
|
-
surface: Surface,
|
|
749
|
-
u: float,
|
|
750
|
-
v: float,
|
|
751
|
-
step_size: float = 1e-5,
|
|
752
|
-
scale_factor: float = 2.0,
|
|
753
|
-
use_metric_correction: bool = True,
|
|
754
|
-
use_lie_derivative: bool = True
|
|
755
|
-
) -> float:
|
|
756
|
-
"""
|
|
757
|
-
Compute Gaussian curvature using Lie group method (simplified interface)
|
|
758
|
-
|
|
759
|
-
Args:
|
|
760
|
-
surface: Surface object
|
|
761
|
-
u, v: Parameter coordinates
|
|
762
|
-
step_size: Finite difference step size (default: 1e-5)
|
|
763
|
-
scale_factor: Scaling factor for correction (default: 2.0)
|
|
764
|
-
use_metric_correction: Whether to apply metric correction
|
|
765
|
-
use_lie_derivative: Whether to include Lie derivative term
|
|
766
|
-
|
|
767
|
-
Returns:
|
|
768
|
-
Gaussian curvature K
|
|
769
|
-
|
|
770
|
-
Example:
|
|
771
|
-
>>> from coordinate_system import Sphere
|
|
772
|
-
>>> from coordinate_system.curvature import gaussian_curvature_lie
|
|
773
|
-
>>> import math
|
|
774
|
-
>>>
|
|
775
|
-
>>> sphere = Sphere(radius=2.0)
|
|
776
|
-
>>> K = gaussian_curvature_lie(sphere, math.pi/4, math.pi/6)
|
|
777
|
-
>>> print(f"K = {K:.6f}")
|
|
778
|
-
"""
|
|
779
|
-
calc = LieGroupCurvatureCalculator(
|
|
780
|
-
surface, step_size, scale_factor,
|
|
781
|
-
use_metric_correction, use_lie_derivative
|
|
782
|
-
)
|
|
783
|
-
return calc.compute_gaussian_curvature(u, v)
|
|
275
|
+
# ========== Backward Compatibility Functions ==========
|
|
784
276
|
|
|
277
|
+
def gaussian_curvature(surface: Surface, u: float, v: float, step_size: float = 1e-3) -> float:
|
|
278
|
+
"""Compute Gaussian curvature (default: intrinsic gradient method)"""
|
|
279
|
+
return intrinsic_gradient_gaussian_curvature(surface, u, v, step_size)
|
|
785
280
|
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
IntrinsicGradientOperator,
|
|
790
|
-
IntrinsicGradientCurvatureCalculator,
|
|
791
|
-
)
|
|
281
|
+
def mean_curvature(surface: Surface, u: float, v: float, step_size: float = 1e-3) -> float:
|
|
282
|
+
"""Compute mean curvature (default: intrinsic gradient method)"""
|
|
283
|
+
return intrinsic_gradient_mean_curvature(surface, u, v, step_size)
|
|
792
284
|
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
return calc.compute_gaussian_curvature(u, v)
|
|
285
|
+
def principal_curvatures(surface: Surface, u: float, v: float, step_size: float = 1e-3) -> Tuple[float, float]:
|
|
286
|
+
"""Compute principal curvatures (default: intrinsic gradient method)"""
|
|
287
|
+
return intrinsic_gradient_principal_curvatures(surface, u, v, step_size)
|
|
797
288
|
|
|
798
|
-
def
|
|
799
|
-
|
|
800
|
-
return
|
|
801
|
-
|
|
802
|
-
def intrinsic_gradient_principal_curvatures(surface, u, v, step_size=1e-3):
|
|
803
|
-
calc = IntrinsicGradientCurvatureCalculator(surface, step_size)
|
|
804
|
-
result = calc.compute_all_curvatures(u, v)
|
|
805
|
-
return result['principal_curvatures']
|
|
289
|
+
def all_curvatures(surface: Surface, u: float, v: float, step_size: float = 1e-3) -> Dict[str, Union[float, np.ndarray]]:
|
|
290
|
+
"""Compute all curvature quantities (default: intrinsic gradient method)"""
|
|
291
|
+
return intrinsic_gradient_all_curvatures(surface, u, v, step_size)
|
|
806
292
|
|
|
807
|
-
def intrinsic_gradient_all_curvatures(surface, u, v, step_size=1e-3):
|
|
808
|
-
calc = IntrinsicGradientCurvatureCalculator(surface, step_size)
|
|
809
|
-
return calc.compute_all_curvatures(u, v)
|
|
810
293
|
|
|
811
294
|
# ========== Export ==========
|
|
812
295
|
|
|
813
296
|
__all__ = [
|
|
814
297
|
# Classical method
|
|
815
298
|
'CurvatureCalculator',
|
|
816
|
-
'
|
|
817
|
-
'
|
|
818
|
-
'
|
|
819
|
-
'
|
|
820
|
-
|
|
821
|
-
# Lie group method
|
|
822
|
-
'LieGroupCurvatureCalculator',
|
|
823
|
-
'gaussian_curvature_lie',
|
|
824
|
-
'compare_methods',
|
|
299
|
+
'gaussian_curvature_classical',
|
|
300
|
+
'mean_curvature_classical',
|
|
301
|
+
'principal_curvatures_classical',
|
|
302
|
+
'all_curvatures_classical',
|
|
825
303
|
|
|
826
304
|
# Intrinsic Gradient Operator method
|
|
827
|
-
'IntrinsicGradientOperator',
|
|
828
|
-
'IntrinsicGradientCurvatureCalculator',
|
|
829
305
|
'intrinsic_gradient_gaussian_curvature',
|
|
830
306
|
'intrinsic_gradient_mean_curvature',
|
|
831
307
|
'intrinsic_gradient_principal_curvatures',
|
|
832
308
|
'intrinsic_gradient_all_curvatures',
|
|
309
|
+
'compare_methods',
|
|
310
|
+
|
|
311
|
+
# Backward compatibility (default to intrinsic gradient)
|
|
312
|
+
'gaussian_curvature',
|
|
313
|
+
'mean_curvature',
|
|
314
|
+
'principal_curvatures',
|
|
315
|
+
'all_curvatures',
|
|
833
316
|
|
|
834
317
|
# Utility functions
|
|
835
318
|
'derivative_5pt',
|
|
836
319
|
'derivative_2nd_5pt',
|
|
837
320
|
'richardson_extrapolation',
|
|
838
|
-
]
|
|
321
|
+
]
|