Skip to content

Commit 864c4ef

Browse files
committed
pv backend
1 parent 848c3c9 commit 864c4ef

17 files changed

+905
-5707
lines changed

examples/ansys/bars_mesh.vtk

0 Bytes
Binary file not shown.

examples/ansys/gf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
images = []
44

5-
for i in range(30):
5+
for i in range(10):
66
filename = f"tmp_img/mesh_optim_{i:03d}.png"
77
images.append(imageio.imread(filename))
88
print(f"Added {filename} to gif.")

examples/ansys/mesh_optim.gif

-769 KB
Loading

examples/ansys/optim_bars.ipynb

Lines changed: 718 additions & 2812 deletions
Large diffs are not rendered by default.

examples/ansys/optim_grid.ipynb

Lines changed: 103 additions & 2874 deletions
Large diffs are not rendered by default.

examples/ansys/rho_bars_optim.gif

-994 KB
Loading

examples/ansys/sdf_fd_tess/tesseract_api.py

Lines changed: 83 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from typing import Any
44

55
import numpy as np
6+
import pyvista as pv
67
import trimesh
78
from pydantic import BaseModel, Field
89
from pysdf import SDF
@@ -94,6 +95,10 @@ class InputSchema(BaseModel):
9495
default=2000,
9596
description=("Maximum number of faces in the output mesh."),
9697
)
98+
sdf_backend: str = Field(
99+
default="pysdf",
100+
description=("Backend used to compute the SDF. Can be either pysdf or pyvista"),
101+
)
97102

98103

99104
class TriangularMesh(BaseModel):
@@ -199,7 +204,33 @@ def grid_points(
199204
return np.vstack((x.ravel(), y.ravel(), z.ravel())).T
200205

201206

202-
def compute_sdf(
207+
def compute_sdf_pyvista(
208+
geometry: trimesh.Trimesh,
209+
grid_center: list[float],
210+
Lx: float,
211+
Ly: float,
212+
Lz: float,
213+
Nx: int,
214+
Ny: int,
215+
Nz: int,
216+
) -> np.ndarray:
217+
pv_mesh = pv.wrap(geometry)
218+
grid = pv.ImageData(
219+
dimensions=(Nx, Ny, Nz),
220+
spacing=(Lx / Nx, Ly / Ny, Lz / Nz),
221+
origin=(
222+
grid_center[0] - Lx / 2,
223+
grid_center[1] - Ly / 2,
224+
grid_center[2] - Lz / 2,
225+
),
226+
)
227+
228+
sdf = grid.compute_implicit_distance(pv_mesh)
229+
230+
return sdf["implicit_distance"].reshape(Nx, Ny, Nz, order="F")
231+
232+
233+
def compute_sdf_pysdf(
203234
geometry: trimesh.Trimesh,
204235
grid_center: list[float],
205236
Lx: float,
@@ -243,6 +274,7 @@ def geometries_and_sdf(
243274
grid_size: np.ndarray,
244275
grid_elements: np.ndarray,
245276
grid_center: np.ndarray,
277+
sdf_backend: str,
246278
) -> tuple[list[np.ndarray], list[trimesh.Trimesh]]:
247279
"""Get the sdf values of a the geometry defined by the parameters as a 2D array."""
248280
geos = get_geometries(
@@ -258,7 +290,18 @@ def geometries_and_sdf(
258290
geos = [geo.apply_scale(scale_mesh) for geo in geos]
259291

260292
sd_fields = [
261-
compute_sdf(
293+
compute_sdf_pysdf(
294+
geo,
295+
grid_center=grid_center,
296+
Lx=grid_size[0],
297+
Ly=grid_size[1],
298+
Lz=grid_size[2],
299+
Nx=grid_elements[0],
300+
Ny=grid_elements[1],
301+
Nz=grid_elements[2],
302+
)
303+
if sdf_backend == "pysdf"
304+
else compute_sdf_pyvista(
262305
geo,
263306
grid_center=grid_center,
264307
Lx=grid_size[0],
@@ -302,6 +345,7 @@ def apply(inputs: InputSchema) -> OutputSchema:
302345
scale_mesh=inputs.scale_mesh,
303346
grid_elements=inputs.grid_elements,
304347
grid_center=inputs.grid_center,
348+
sdf_backend=inputs.sdf_backend,
305349
)
306350

307351
sdf = sdfs[0] # only one geometry
@@ -331,6 +375,7 @@ def apply(inputs: InputSchema) -> OutputSchema:
331375
grid_elements=inputs.grid_elements,
332376
grid_center=inputs.grid_center,
333377
epsilon=inputs.epsilon,
378+
sdf_backend=inputs.sdf_backend,
334379
)
335380

336381
global jacobian_future
@@ -360,6 +405,7 @@ def jac_sdf_wrt_params(
360405
grid_elements: np.ndarray,
361406
grid_center: np.ndarray,
362407
epsilon: float,
408+
sdf_backend: str,
363409
) -> np.ndarray:
364410
"""Compute the Jacobian of the SDF values with respect to the parameters.
365411
@@ -398,6 +444,7 @@ def jac_sdf_wrt_params(
398444
grid_elements=grid_elements,
399445
grid_size=grid_size,
400446
grid_center=grid_center,
447+
sdf_backend=sdf_backend,
401448
)
402449

403450
for i in range(n_params):
@@ -406,25 +453,13 @@ def jac_sdf_wrt_params(
406453
return jac.astype(np.float32)
407454

408455

409-
def vector_jacobian_product(
456+
def jacobian(
410457
inputs: InputSchema,
411-
vjp_inputs: set[str],
412-
vjp_outputs: set[str],
413-
cotangent_vector: dict[str, Any],
414-
) -> dict[str, Any]:
415-
"""Compute vector-Jacobian product for backpropagation.
416-
417-
Args:
418-
inputs: Input schema containing bar geometry parameters.
419-
vjp_inputs: Set of input variable names for gradient computation.
420-
vjp_outputs: Set of output variable names for gradient computation.
421-
cotangent_vector: Cotangent vectors for the specified outputs.
422-
423-
Returns:
424-
Dictionary containing VJP for the specified inputs.
425-
"""
426-
assert vjp_inputs == {"differentiable_parameters"}
427-
assert vjp_outputs == {"sdf"}
458+
jac_inputs: set[str],
459+
jac_outputs: set[str],
460+
):
461+
assert jac_inputs == {"differentiable_parameters"}
462+
assert jac_outputs == {"sdf"}
428463

429464
# lets also check if the thread is still running
430465
if jacobian_future is not None:
@@ -450,12 +485,40 @@ def vector_jacobian_product(
450485
grid_elements=inputs.grid_elements,
451486
epsilon=inputs.epsilon,
452487
grid_center=inputs.grid_center,
488+
sdf_backend=inputs.sdf_backend,
453489
)
454490
if inputs.normalize_jacobian:
455491
n_elements = (
456492
inputs.grid_elements[0] * inputs.grid_elements[1] * inputs.grid_elements[2]
457493
)
458494
jac = jac / n_elements
495+
496+
jacobian = {"sdf": {"differentiable_parameters": jac}}
497+
498+
return jacobian
499+
500+
501+
def vector_jacobian_product(
502+
inputs: InputSchema,
503+
vjp_inputs: set[str],
504+
vjp_outputs: set[str],
505+
cotangent_vector: dict[str, Any],
506+
) -> dict[str, Any]:
507+
"""Compute vector-Jacobian product for backpropagation.
508+
509+
Args:
510+
inputs: Input schema containing bar geometry parameters.
511+
vjp_inputs: Set of input variable names for gradient computation.
512+
vjp_outputs: Set of output variable names for gradient computation.
513+
cotangent_vector: Cotangent vectors for the specified outputs.
514+
515+
Returns:
516+
Dictionary containing VJP for the specified inputs.
517+
"""
518+
assert vjp_inputs == {"differentiable_parameters"}
519+
assert vjp_outputs == {"sdf"}
520+
521+
jac = jacobian(inputs, vjp_inputs, vjp_outputs)["sdf"]["differentiable_parameters"]
459522
# Reduce the cotangent vector to the shape of the Jacobian, to compute VJP by hand
460523
vjp = np.einsum("klmn,lmn->k", jac, cotangent_vector["sdf"])
461524

-92.1 KB
Binary file not shown.
-81.9 KB
Binary file not shown.
-93.6 KB
Binary file not shown.

0 commit comments

Comments
 (0)