DeepSDFStruct.optimization#

Structural Optimization Utilities#

This module provides tools for gradient-based optimization of SDF-based geometries, with a focus on structural design problems. It integrates with TorchFEM for finite element analysis and provides optimization algorithms suitable for constrained design problems.

Key Features#

MMA Optimizer

Implementation of the Method of Moving Asymptotes (MMA), a gradient-based algorithm well-suited for structural optimization with nonlinear constraints. MMA is particularly effective for: - Topology optimization - Shape optimization with constraints - Problems with expensive objective evaluations - Highly nonlinear design spaces

Finite Element Integration
  • Conversion between TorchFEM and PyVista mesh formats

  • Support for tetrahedral and hexahedral elements

  • Linear and quadratic element types

  • Integration with gradient computation

Mesh Quality Utilities
  • Signed volume computation for tetrahedra

  • Mesh quality metrics

  • Degeneracy detection

The module is designed to work seamlessly with differentiable SDF representations, enabling gradient-based optimization of complex 3D structures.

Functions

get_mesh_from_torchfem(Solid)

Convert a TorchFEM Solid mesh to PyVista UnstructuredGrid.

tet_signed_vol(vertices, tets)

Compute signed volumes of tetrahedral elements.

Classes

MMA(parameters, bounds[, max_step])

Method of Moving Asymptotes (MMA) optimizer for constrained problems.

class DeepSDFStruct.optimization.MMA(parameters, bounds, max_step=0.1)#

Bases: object

Method of Moving Asymptotes (MMA) optimizer for constrained problems.

MMA is a gradient-based optimization algorithm designed for nonlinear constrained problems. It constructs convex subproblems using moving asymptotes and is particularly effective for structural optimization.

The optimizer handles a single objective function and a single constraint, with box bounds on design variables. It automatically normalizes the objective by its initial value for better numerical behavior.

Parameters:
  • parameters (torch.Tensor) – Initial design variables (will be optimized in-place).

  • bounds (array-like of shape (n, 2)) – Box constraints [[lower_1, upper_1], …, [lower_n, upper_n]] for each design variable.

  • max_step (float, default 0.1) – Maximum allowed change in design variables per iteration, as a fraction of the bound range.

parameters#

Current design variables (updated in-place each iteration).

Type:

torch.Tensor

loop#

Current iteration number.

Type:

int

x#

Current design variables in numpy format.

Type:

ndarray

xold1, xold2

Design variables from previous two iterations (for MMA history).

Type:

ndarray

step(F, dF, G, dG)#

Perform one MMA optimization step given objective, constraint, and their gradients.

Notes

MMA was developed by Krister Svanberg and is widely used in topology optimization. It is particularly effective for problems where: - The objective and constraints are expensive to evaluate - Gradients are available (via automatic differentiation) - The design space is high-dimensional - Strong nonlinearity is present

The implementation uses the mmapy package for the core MMA algorithm.

Examples

>>> import torch
>>> from DeepSDFStruct.optimization import MMA
>>>
>>> # Define design variables
>>> params = torch.ones(10, requires_grad=True)
>>> bounds = [[0.0, 2.0]] * 10
>>>
>>> # Create optimizer
>>> optimizer = MMA(params, bounds, max_step=0.1)
>>>
>>> # Optimization loop
>>> for i in range(100):
...     # Compute objective and constraint
...     objective = (params ** 2).sum()
...     constraint = params.sum() - 5.0
...
...     # Compute gradients
...     dF = torch.autograd.grad(objective, params, create_graph=True)[0]
...     dG = torch.autograd.grad(constraint, params, create_graph=True)[0]
...
...     # MMA step
...     optimizer.step(objective, dF, constraint, dG)
...
...     if optimizer.ch < 1e-3:
...         break

References

step(F, dF, G, dG)#

Perform one MMA optimization step.

Updates design variables by solving a convex subproblem constructed from the objective, constraint, and their gradients.

Parameters:
  • F (torch.Tensor or float) – Objective function value at current design.

  • dF (torch.Tensor) – Gradient of objective w.r.t. design variables, shape (n,).

  • G (torch.Tensor or float) – Constraint function value at current design (≤ 0 is feasible).

  • dG (torch.Tensor) – Gradient of constraint w.r.t. design variables, shape (n,).

Notes

The method automatically: - Normalizes the objective by its initial value - Enforces move limits based on max_step - Updates MMA history (xold1, xold2) - Computes and logs convergence metric (ch) - Updates self.parameters in-place

The convergence metric ch is the relative change in design variables.

DeepSDFStruct.optimization.get_mesh_from_torchfem(Solid)#

Convert a TorchFEM Solid mesh to PyVista UnstructuredGrid.

This function enables visualization and export of TorchFEM finite element meshes using PyVista. It supports both tetrahedral and hexahedral elements with linear and quadratic shape functions.

Parameters:

Solid (torchfem.Solid) – TorchFEM solid mesh object containing nodes, elements, and element type.

Returns:

PyVista mesh representation suitable for visualization and I/O.

Return type:

pyvista.UnstructuredGrid

Raises:

NotImplementedError – If input is not a torchfem.Solid object.

Notes

Supported element types: - Tetra1: 4-node linear tetrahedron - Tetra2: 10-node quadratic tetrahedron - Hexa1: 8-node linear hexahedron - Hexa2: 20-node quadratic hexahedron

Examples

>>> from DeepSDFStruct.optimization import get_mesh_from_torchfem
>>> import torchfem
>>>
>>> # Assume we have a TorchFEM solid mesh
>>> # solid = torchfem.Solid(...)
>>>
>>> # Convert to PyVista for visualization
>>> pv_mesh = get_mesh_from_torchfem(solid)
>>> pv_mesh.plot()
DeepSDFStruct.optimization.tet_signed_vol(vertices, tets)#

Compute signed volumes of tetrahedral elements.

Calculates the signed volume of each tetrahedron, which is positive for correctly oriented elements and negative for inverted elements. This is useful for detecting mesh degeneracies and enforcing mesh quality constraints.

Parameters:
  • vertices (torch.Tensor) – Vertex coordinates of shape (N, 3).

  • tets (torch.Tensor) – Tetrahedral connectivity of shape (M, 4), where each row contains vertex indices [v0, v1, v2, v3].

Returns:

Signed volumes of shape (M,), one per tetrahedron. Positive volumes indicate correctly oriented elements.

Return type:

torch.Tensor

Notes

The signed volume is computed as:

V = (1/6) * ((v1-v0) × (v2-v0)) · (v3-v0)

Examples

>>> import torch
>>> from DeepSDFStruct.optimization import tet_signed_vol
>>>
>>> # Define a simple tetrahedron
>>> vertices = torch.tensor([
...     [0.0, 0.0, 0.0],
...     [1.0, 0.0, 0.0],
...     [0.0, 1.0, 0.0],
...     [0.0, 0.0, 1.0]
... ])
>>> tets = torch.tensor([[0, 1, 2, 3]])
>>> volumes = tet_signed_vol(vertices, tets)
>>> print(f"Volume: {volumes[0]:.3f}")  # Should be 1/6 ≈ 0.167