A modular framework for dynamic FEM simulation, symbolic differentiation, and IPOPT-based material calibration.
This repository provides a full pipeline for:
- Finite Element simulation of deformable objects
- Symbolic differentiation of the full dynamic model (via CasADi)
- Nonlinear optimization of material parameters (Young’s modulus E and Poisson ratio ν)
- Trajectory-based material calibration to match a target deformation sequence
This enables a new strategy for calibrating elastic materials:
Tune FEM material parameters so a simulated object behaves like a reference object — either another FEM simulator, a physics engine, or real-world measured motion.
This lets you:
- Match simulation models across engines
- Fit physical materials from recorded motion data
- Validate differentiable simulators
- Perform inverse elasticity estimation
- Build data-driven soft robotics models
.
├── optimize_material_modular.py # Main FEM + optimizer module
├── plots_optimization.py # Plotting & visualization tools
├── fem_comparison_animation.mp4 # Example animation of results
├── README.md # This file
└── data/ # (optional) target trajectories, etc.
- Tetrahedral mesh
- Linear elasticity
- Computes element stiffness matrices
- Computes volumes, masses, B‐matrices
- Assembles global matrices (K, M, C)
- Applies boundary constraints
-
Runs a dynamic FEM simulation
-
Unrolls time steps symbolically using CasADi
-
Computes internal/external forces at each step
-
Provides symbolic objective:
$$ J(E,\nu) = \tfrac12 \sum_t |u_t^{sim}(E,\nu) - u_t^{target}|^2 $$
Runs IPOPT once on the full nonlinear program:
-
Uses reparameterizations:
$E = \exp(\log E)$ $\nu = 0.1\tanh(t_\nu) + 0.4$
-
Ensures stable variables during optimization
-
Returns optimal material parameters
-
IPOPT runs in one-iteration increments
-
Prints detailed logs:
- Objective value per iteration
- Gradients
- Parameter evolution
- Convergence diagnostics
-
Useful for diagnosing:
- vanishing/exploding gradients
- long trajectory horizon
- ill-conditioning
The governing equation solved at each timestep:
Integrated using:
Given target displacements
Ensures valid domains and stable optimization:
E = exp(logE)
nu = 0.1 * tanh(t_nu) + 0.4
Thus:
$E > 0$ $\nu \in (0.3, 0.5)$
- Entire simulation graph is symbolic
- CasADi provides exact gradients/Hessians
- IPOPT solves the nonlinear program
- Convergence detected by KKT satisfaction
from optimize_material_modular import FEMModel, FEMSimulator, MaterialOptimizer
import numpy as np
# Load mesh + target trajectory
nodes = np.load("nodes.npy")
tets = np.load("tets.npy")
target_us = np.load("target_us.npy")
model = FEMModel(nodes, tets)
sim = FEMSimulator(model, dt=1e-3, n_steps=len(target_us))
opt = MaterialOptimizer(sim, target_us)
E_opt, nu_opt = opt.solve(E_guess=5e4, nu_guess=0.45)
print("Optimal E:", E_opt)
print("Optimal ν:", nu_opt)The script plots_optimization.py provides convenience functions for:
It expects to find in the directory:
nodes_ref = np.load("nodes_ref.npy")
u_target_series = np.load("u_target_series.npy")
u_series_opt = np.load("u_series_opt.npy")
tets = np.load("tets.npy")
F_ext_series = np.load("F_ext_series.npy")This repository includes an example animation that compares:
- the target FEM trajectory
- the optimized FEM trajectory
Embed inside README:
(Actual animation included in repo)
From simulation, real data, motion capture, etc.
Choose optimizer type:
MaterialOptimizer→ fast, production useMaterialOptimizer_Verbose→ debug mode
Both optimizers save:
- optimized parameters
- simulated trajectories
- intermediate files
- error curves
Call functions in plots_optimization.py.
Likely cause: vanishing gradients in long time horizons.
Fixes:
- Subsample timesteps
- Increase damping
- Use
MaterialOptimizer_Verbose - Use shorter “windows” of simulation
- Normalize objective by number of time steps
Reason: Jacobian product through many timesteps becomes ill-conditioned.
Fixes:
- multiple-shooting optimization
- windowed optimization
- adjoint-based backward integration (coming soon)
- reduce timestep count
- regularize J
CasADi graphs grow with number of time steps.
Fixes:
- reduce
n_steps - enable CasADi JIT compilation
- run in verbose mode to see memory growth
PRs are welcome, especially for:
- new materials (Neo-Hookean, corotated, etc.)
- adjoint-based gradients
- GPU acceleration (planned)
- improved plotting/animation
- integration with PyTorch or JAX
(Choose one and update this section.)
This framework is meant to be:
- research-grade
- explainable
- modular
- extendable
- educational
- practical for real calibration tasks