lsdo-function-spaces 1.0.0__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.
- lsdo_function_spaces/__init__.py +64 -0
- lsdo_function_spaces/core/__init__.py +0 -0
- lsdo_function_spaces/core/function.py +1322 -0
- lsdo_function_spaces/core/function_set.py +1081 -0
- lsdo_function_spaces/core/function_set_space.py +379 -0
- lsdo_function_spaces/core/function_space.py +482 -0
- lsdo_function_spaces/core/operations/__init__.py +0 -0
- lsdo_function_spaces/core/operations/basic_ops.py +85 -0
- lsdo_function_spaces/core/operations/operations.py +5 -0
- lsdo_function_spaces/core/optimization.py +183 -0
- lsdo_function_spaces/core/spaces/__init__.py +0 -0
- lsdo_function_spaces/core/spaces/b_spline_space.py +418 -0
- lsdo_function_spaces/core/spaces/conditional_space.py +65 -0
- lsdo_function_spaces/core/spaces/constant_space.py +57 -0
- lsdo_function_spaces/core/spaces/idw_space.py +271 -0
- lsdo_function_spaces/core/spaces/non_cython_bsplines/__init__.py +0 -0
- lsdo_function_spaces/core/spaces/non_cython_bsplines/b_spline_csdl_custom_ops.py +420 -0
- lsdo_function_spaces/core/spaces/non_cython_bsplines/b_spline_patch_projection.py +1022 -0
- lsdo_function_spaces/core/spaces/non_cython_bsplines/b_spline_patch_projection_non_differentiable.py +186 -0
- lsdo_function_spaces/core/spaces/non_cython_bsplines/b_spline_patch_projection_optimized.py +594 -0
- lsdo_function_spaces/core/spaces/non_cython_bsplines/b_spline_space_new.py +6 -0
- lsdo_function_spaces/core/spaces/non_cython_bsplines/compute_basis_matrix_jax.py +172 -0
- lsdo_function_spaces/core/spaces/non_cython_bsplines/compute_basis_matrix_jax_factory.py +382 -0
- lsdo_function_spaces/core/spaces/non_cython_bsplines/compute_basis_matrix_jax_stencil.py +451 -0
- lsdo_function_spaces/core/spaces/non_cython_bsplines/compute_basis_matrix_numpy.py +249 -0
- lsdo_function_spaces/core/spaces/non_cython_bsplines/compute_basis_matrix_numpy_factory.py +391 -0
- lsdo_function_spaces/core/spaces/operation_space.py +64 -0
- lsdo_function_spaces/core/spaces/polynomial_space.py +79 -0
- lsdo_function_spaces/core/spaces/rbf_space.py +136 -0
- lsdo_function_spaces/core/spaces/tri_space.py +256 -0
- lsdo_function_spaces/utils/__init__.py +0 -0
- lsdo_function_spaces/utils/file_io.py +484 -0
- lsdo_function_spaces/utils/internal_utilities.py +11 -0
- lsdo_function_spaces/utils/plotting_functions.py +357 -0
- lsdo_function_spaces/utils/utility_functions.py +148 -0
- lsdo_function_spaces-1.0.0.dist-info/METADATA +189 -0
- lsdo_function_spaces-1.0.0.dist-info/RECORD +40 -0
- lsdo_function_spaces-1.0.0.dist-info/WHEEL +5 -0
- lsdo_function_spaces-1.0.0.dist-info/licenses/LICENSE.txt +165 -0
- lsdo_function_spaces-1.0.0.dist-info/top_level.txt +1 -0
lsdo_function_spaces/core/spaces/non_cython_bsplines/b_spline_patch_projection_non_differentiable.py
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import jax
|
|
2
|
+
import jax.numpy as jnp
|
|
3
|
+
from lsdo_function_spaces.core.spaces.non_cython_bsplines.compute_basis_matrix_jax import evaluate_b_spline_jax
|
|
4
|
+
|
|
5
|
+
def compute_projection_residual(
|
|
6
|
+
point_in_space,
|
|
7
|
+
para_coords,
|
|
8
|
+
degrees,
|
|
9
|
+
coefficients,
|
|
10
|
+
knot_vectors,
|
|
11
|
+
):
|
|
12
|
+
"""
|
|
13
|
+
Compute the residual of the projection of a point in space onto a B-spline surface.
|
|
14
|
+
|
|
15
|
+
Parameters:
|
|
16
|
+
-----------
|
|
17
|
+
point_in_space : jnp.ndarray, shape (d,)
|
|
18
|
+
The point in space to project.
|
|
19
|
+
para_coords : jnp.ndarray, shape (M, d)
|
|
20
|
+
Parameter coordinates for the B-spline surface.
|
|
21
|
+
degrees : tuple of int
|
|
22
|
+
Degrees of the B-spline in each dimension.
|
|
23
|
+
coefficients : jnp.ndarray, shape (N, num_phys_dims)
|
|
24
|
+
Coefficients of the B-spline basis functions.
|
|
25
|
+
knot_vectors : tuple of jnp.ndarray
|
|
26
|
+
Knot vectors for each dimension.
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
--------
|
|
30
|
+
residual : jnp.ndarray, shape (M,)
|
|
31
|
+
The residuals of the projection.
|
|
32
|
+
"""
|
|
33
|
+
n_dims = len(degrees)
|
|
34
|
+
n_phys_dims = coefficients.shape[-1]
|
|
35
|
+
point_in_space = point_in_space.reshape(-1, n_phys_dims)
|
|
36
|
+
|
|
37
|
+
bsp_eval = evaluate_b_spline_jax(
|
|
38
|
+
us=para_coords,
|
|
39
|
+
degrees=degrees,
|
|
40
|
+
knot_vectors=knot_vectors,
|
|
41
|
+
coeffs=coefficients,
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
surface_jacobian = [
|
|
45
|
+
evaluate_b_spline_jax(
|
|
46
|
+
us=para_coords,
|
|
47
|
+
degrees=degrees,
|
|
48
|
+
knot_vectors=knot_vectors,
|
|
49
|
+
coeffs=coefficients,
|
|
50
|
+
der_orders=tuple(
|
|
51
|
+
int(i == j) for j in range(n_dims)
|
|
52
|
+
)
|
|
53
|
+
) for i in range(n_dims)
|
|
54
|
+
]
|
|
55
|
+
surface_jacobian_array = jnp.array(surface_jacobian).squeeze().T
|
|
56
|
+
|
|
57
|
+
diff = bsp_eval - point_in_space
|
|
58
|
+
|
|
59
|
+
residuals = [jnp.sum(diff * d, axis=1) for d in surface_jacobian] # shape: (num_pts,) for each
|
|
60
|
+
res = jnp.array(residuals).reshape(n_dims, )
|
|
61
|
+
|
|
62
|
+
return res, bsp_eval, surface_jacobian, surface_jacobian_array
|
|
63
|
+
|
|
64
|
+
def compute_projection_jacobian(
|
|
65
|
+
point_in_space,
|
|
66
|
+
para_coords,
|
|
67
|
+
degrees,
|
|
68
|
+
coefficients,
|
|
69
|
+
knot_vectors,
|
|
70
|
+
bsp_eval,
|
|
71
|
+
surface_jacobian,
|
|
72
|
+
):
|
|
73
|
+
"""
|
|
74
|
+
Compute the Jacobian of the projection of a point in space onto a B-spline surface.
|
|
75
|
+
|
|
76
|
+
Parameters:
|
|
77
|
+
-----------
|
|
78
|
+
point_in_space : jnp.ndarray, shape (d,)
|
|
79
|
+
The point in space to project.
|
|
80
|
+
para_coords : jnp.ndarray, shape (M, d)
|
|
81
|
+
Parameter coordinates for the B-spline surface.
|
|
82
|
+
degrees : tuple of int
|
|
83
|
+
Degrees of the B-spline in each dimension.
|
|
84
|
+
coefficients : jnp.ndarray, shape (N, num_phys_dims)
|
|
85
|
+
Coefficients of the B-spline basis functions.
|
|
86
|
+
knot_vectors : tuple of jnp.ndarray
|
|
87
|
+
Knot vectors for each dimension.
|
|
88
|
+
bsp_eval : jnp.ndarray, shape (M, num_phys_dims)
|
|
89
|
+
B-spline evaluation at the parameter coordinates.
|
|
90
|
+
surface_jacobian : list of jnp.ndarray, shape (M, num_phys_dims)
|
|
91
|
+
Jacobian of the B-spline surface at the parameter coordinates.
|
|
92
|
+
|
|
93
|
+
Returns:
|
|
94
|
+
--------
|
|
95
|
+
jacobian : jnp.ndarray, shape (M, d)
|
|
96
|
+
The Jacobian of the projection.
|
|
97
|
+
"""
|
|
98
|
+
n_dims = len(degrees)
|
|
99
|
+
|
|
100
|
+
diff = (bsp_eval - point_in_space).flatten()
|
|
101
|
+
|
|
102
|
+
surface_hessian_tensor = [
|
|
103
|
+
[evaluate_b_spline_jax(
|
|
104
|
+
us=para_coords,
|
|
105
|
+
degrees=degrees,
|
|
106
|
+
knot_vectors=knot_vectors,
|
|
107
|
+
coeffs=coefficients,
|
|
108
|
+
der_orders=tuple((i == k) + (j == k) for k in range(n_dims))
|
|
109
|
+
) for j in range(n_dims)
|
|
110
|
+
] for i in range(n_dims)
|
|
111
|
+
]
|
|
112
|
+
|
|
113
|
+
projection_jacobian = jnp.zeros((n_dims, n_dims), dtype=bsp_eval.dtype)
|
|
114
|
+
|
|
115
|
+
for i in range(n_dims):
|
|
116
|
+
for j in range(n_dims):
|
|
117
|
+
inner = jnp.sum(surface_jacobian[i] * surface_jacobian[j], axis=1) + jnp.sum(diff * surface_hessian_tensor[i][j], axis=1)
|
|
118
|
+
projection_jacobian = projection_jacobian.at[i, j].set(inner[0])
|
|
119
|
+
|
|
120
|
+
return projection_jacobian
|
|
121
|
+
|
|
122
|
+
def compute_point_to_bspline_projection(
|
|
123
|
+
point,
|
|
124
|
+
degrees,
|
|
125
|
+
coefficients,
|
|
126
|
+
para_coords,
|
|
127
|
+
knots,
|
|
128
|
+
max_iter=100,
|
|
129
|
+
tol=1e-12,
|
|
130
|
+
):
|
|
131
|
+
"""Project a point onto an n-dimensional B-spline using Newton iteration."""
|
|
132
|
+
n_dims = len(degrees) # parametric dimensions
|
|
133
|
+
|
|
134
|
+
para_coords = para_coords.reshape(n_dims, )
|
|
135
|
+
|
|
136
|
+
# knots = tuple([knots[i] for i in range(n_dims)])
|
|
137
|
+
|
|
138
|
+
def body(state):
|
|
139
|
+
i, para_coords, _, _, _, _, _ = state
|
|
140
|
+
|
|
141
|
+
res, bsp_eval, surface_jacobian, surface_jacobian_array = compute_projection_residual(
|
|
142
|
+
point, para_coords, degrees, coefficients, knots
|
|
143
|
+
)
|
|
144
|
+
J = compute_projection_jacobian(
|
|
145
|
+
point, para_coords, degrees, coefficients, knots, bsp_eval, surface_jacobian,
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
grad = res
|
|
149
|
+
# Applying active-set like approach
|
|
150
|
+
# Inactive directions are those where the gradient is zero or the parameter is at the boundary
|
|
151
|
+
inactive_mask = jnp.logical_or(
|
|
152
|
+
jnp.logical_and(para_coords <= 0.0, grad > 0.0),
|
|
153
|
+
jnp.logical_and(para_coords >= 1.0, grad < 0.0),
|
|
154
|
+
)
|
|
155
|
+
inactive_mask = jnp.logical_or(inactive_mask, grad == 0.0)
|
|
156
|
+
active_mask = ~inactive_mask
|
|
157
|
+
|
|
158
|
+
# Mask Jacobian and residual using active_mask
|
|
159
|
+
J_masked = J * (active_mask[:, None] & active_mask[None, :])
|
|
160
|
+
res_masked = res * active_mask
|
|
161
|
+
|
|
162
|
+
res_norm = jnp.linalg.norm(res_masked)
|
|
163
|
+
|
|
164
|
+
# NOTE: we are solving an augmented system (always 2x2)
|
|
165
|
+
# Ideally we would remove the inactive directions from the system
|
|
166
|
+
# However, for JAX, the dimensions must be fixed for jit compilation
|
|
167
|
+
step = -jnp.linalg.solve(J_masked + jnp.eye(n_dims) * (~active_mask), res_masked)
|
|
168
|
+
step = step * active_mask # zero out inactive directions
|
|
169
|
+
|
|
170
|
+
para_coords_new = jnp.clip(para_coords + step, 0.0, 1.0)
|
|
171
|
+
converged_new = res_norm < tol
|
|
172
|
+
|
|
173
|
+
return (i + 1, para_coords_new, res_masked, converged_new, J, active_mask, surface_jacobian_array)
|
|
174
|
+
|
|
175
|
+
def cond(state):
|
|
176
|
+
i, _, _, converged, _, _, _ = state
|
|
177
|
+
return (i < max_iter) & (~converged)
|
|
178
|
+
|
|
179
|
+
dim = len(degrees)
|
|
180
|
+
bool_init = jnp.zeros_like(para_coords, dtype=jnp.bool_)
|
|
181
|
+
dS_dxi_init = jnp.zeros((3, dim))
|
|
182
|
+
init_state = (0, para_coords, jnp.zeros_like(para_coords), False, jnp.zeros((dim, dim)), bool_init, dS_dxi_init)
|
|
183
|
+
final_i, final_coords, final_res, final_converged, J, mask, surface_jacobian = jax.lax.while_loop(cond, body, init_state)
|
|
184
|
+
|
|
185
|
+
return final_coords, final_res, final_converged, final_i, J, mask, surface_jacobian
|
|
186
|
+
|