Geode is a single C++20 engine running the whole generative-design loop on one machine: SDF geometry voxelized onto one grid, co-simulated across thermal, fluid, structural, electromagnetic and acoustic domains, then topology-optimized under LPBF and CNC manufacturability constraints. No geometry shuttling between tools.
01Spec
- C++20, ~11k LoC, ~300 GoogleTest cases.
- Loop: SDF -> voxelize -> multiphysics -> constraints -> adjoints -> SIMP update -> repeat.
- Domains: thermal (FD), fluid (Stokes / Navier-Stokes / RANS), elasticity (voxel FE), electrostatics, magnetostatics, Helmholtz acoustics. Each carries a sensitivity path, so any drives the optimizer.
- Geometry via PicoGK: voxelization, marching cubes, viewer, OpenVDB export.
Whole drone wing, stiff under lift, quiet at blade-pass:
auto model =
Geode::Engine::GeodeModel::Create("drone_wing")
.Fix (lo, { lo.x + spacing, hi.y, hi.z }) // root face clamped
.Load({ lo.x, lo.y, hi.z - spacing }, hi, { 0, 0, 500.f }) // lift on top skin
.SoundSource(srcLo, srcHi, 1.f, /*blade-pass*/ 500.f)
.AcousticObserver(observer) // ground-facing mic
.Minimize("Structural", "MinCompliance", 1.f)
.Minimize("Acoustic", "MinSPL", 3.f)
.MaxVolumeFraction(0.40f)
.MinFeatureSize(0.005f) // LPBF printability
.Build();02DAG and memory
Voxelize -> Material -> {Thermal, Fluid, Structural, [Electro, Magneto, Acoustic]} -> Objective -> Sensitivity -> Optimize.
Pipeline: name-keyed std::functions, string deps, Kahn validation, lowered onto tf::Taskflow. A cycle fails at build with a name in the log, not a Taskflow assertion. Built once, re-executed per iteration. Unmentioned domains never enter the graph.
FieldBuffer<T>: move-only, 64-byte-aligned, flat SoA. No Eigen, no std::vector<Vec3> hot. Displacement is three scalar arrays, interleaved 3*i + dof only in the FE solver. float throughout: half the traffic, twice the lanes, priced later in conditioning. SIMD::VectorOps dispatches AVX-512 / AVX2 / scalar at compile time; CG aligned loads, 7-point stencils unaligned.
03FE solver: never assemble K
~90% of wall time. 8-node hexes on a regular grid share geometry: one 24x24 unit Ke0, full 2x2x2 Gauss, 576 floats, 2.3 KB, L1-resident. Element contribution (E[e]/Eref) * Ke0. PCG, Jacobi preconditioner from the Ke0 diagonal, operator = gather -> mat-vec -> scatter. Adjacent elements share nodes, so naive parallel scatter races.
// color = (i%2) + 2*(j%2) + 4*(k%2); same-color elements share no nodes.
#pragma omp parallel
{
for (int color = 0; color < 8; ++color) {
#pragma omp for schedule(static) nowait
for (Core::Index idx = 0; idx < colorCount[color]; ++idx) {
/* gather u_e, Ke0*u_e, scatter: no atomics, no locks */
}
#pragma omp barrier // color N scattered before N+1 reads
}
}One parallel region wraps all 8 passes. Per-color fork/join = 8 x ~5k CG iterations = ~40k team spinups per solve.
24 = 3 x 8: three AVX2 FMAs per row, no tail loop, no mask, no padding.
for (int row = 0; row < 24; ++row) {
const float* rp = Ke0_ + row * 24;
__m256 acc = _mm256_mul_ps (_mm256_loadu_ps(rp), _mm256_loadu_ps(u_e));
acc = _mm256_fmadd_ps(_mm256_loadu_ps(rp + 8), _mm256_loadu_ps(u_e + 8), acc);
acc = _mm256_fmadd_ps(_mm256_loadu_ps(rp + 16), _mm256_loadu_ps(u_e + 16), acc);
Ke_u[row] = scale * hsum256(acc);
}04Optimizer
SIMP + Optimality Criteria: E(ρ) = E_min + ρ³(E₀ - E_min), volume constraint by bisecting λ, cone-weighted filter against checkerboards. What made it converge:
- ρ = 0.5 start. A solid start sheds 60% of material before sensitivities mean anything. Locks in boundary-peeled topology.
- Move limit 0.1. Topology changes slower than conditioning degrades.
- *Sensitivity = `u_eᵀKe0u_e
, not‖u‖²`.*‖u‖²scores the free tip highest, the clamped root worthless: inverted physics. - Cold-start CG each iteration. Warm starts compound non-converged error outward.
- Uniform speed of sound. Penalizing
cdrivesk²h² >> 6in void cells, diverging the Helmholtz Jacobi sweep (denominator6 - k²h²). Void fraction controls absorption.
Compliance adjoint dC/dρ = -p*ρ^{p-1}(E₀-E_min)*u_eᵀKe0*u_e: self-adjoint, free once strain energies exist. Thermal, electrostatic, magnetostatic from energy functionals. Fluid and acoustic use dedicated modules. Manufacturing constraints enter the same gradient accumulation, so printability shapes topology instead of rejecting it after.
05Trade-offs
| Chose | Gave up | Why it held |
|---|---|---|
| Voxel grid + matrix-free FE | Body-fitted meshes, boundary accuracy | Regularity is the performance model: shared Ke0, closed-form coloring, no meshing. Staircase washes out in marching cubes |
float everywhere | ~7 significant digits | 2x lanes, half the traffic, memory-bound solver. Conditioning cost manageable once explicit |
One unit Ke0 scaled per element | Per-element ν, non-cubic voxels | 2.3 KB for the whole mesh, cache-hot. SIMP only modulates E, so scaling is exact |
| String-keyed objectives/domains | Compile-time physics names | API had to survive a flat C ABI. RegisterDomain adds domains without touching an enum. Opposite call to Nott: different layer |
| OpenMP in solvers, Taskflow across them | One scheduler | Solver loops want static data parallelism with barriers. The pipeline wants dependency concurrency |
| Jacobi-preconditioned CG | Multigrid convergence | Matrix-free compatible, 30 lines. Iteration counts grow with grid size and SIMP contrast |
| Native C++ fluent builder | C#/PicoGK frontend | Every bug crossed a P/Invoke boundary flattening types to strings and floats. Its string-keyed rule API stayed as a seam |
06Benchmarks
ApplyStiffness dominates. Drone wing, 80x24x6 grid, 11,520 elements, 34,560 DOFs, Ryzen 5 7600X (6C/12T), equal tolerances.
| 30 SIMP iterations | per FE solve | 150-iteration full run | |
|---|---|---|---|
| Before (scalar, single-threaded) | ~210 s | ~7 s | ~17 min |
| After (8-color OpenMP + AVX2) | 26.4 s | 0.75 s | ~2.2 min |
8x wall time at 704% CPU, ~59% parallel efficiency over 12 threads. The FMA block is compute; gather and colored scatter are memory traffic on a shared controller. Same commit, equal payoff: stiffness floor 1e-3 absolute -> 0.1*E₀ cut κ(K) ~6.4x10⁶ -> ~6.4x10⁵. PCG then converges in budget instead of returning MaxIterationsReached garbage.
07Failure modes hit
- NaN as a fake threading bug.
xNew = ρ*sqrt(B),B = -sensitivity/λ. Multi-objective weighting makes sensitivity positive, soB < 0,sqrtNaN. Every NaN compare in the bisection falls one way; the loop runs 150+ iterations instead of ~10. One-line clamp. - Inverted sensitivity.
E*‖u‖²reinforced the free tip, hollowed the clamped root. No profiler finds this class. HenceLogHealth: min/mean/max/NaN per stage per iteration. - The stiffness matrix that wasn't. First "FE solver" was a 6-point Laplacian: a heat operator in elasticity costume. Real hexes at 1-point Gauss then gave 12 hourglass modes, K indefinite, CG answering non-convergence instead of an error. 2x2x2 is exact for trilinear hexes.
- Three Boost sonames from linking prebuilt PicoGK.
justfilestill carriesinit-boost-shims.
08Next
A topology optimizer drives its own linear systems toward ill-conditioning. SIMP sharpens, solid/void contrast explodes, κ(K) climbs, PCG iteration counts set wall time, not FLOPs.
- Geometric multigrid preconditioner. Coarsening is trivial on a structured grid. Fixes grid-size and contrast scaling; the
0.1*E₀floor then retreats toward physical values. - GPU port. gather / 24x24-FMA / colored-scatter maps to CUDA.
CUDABackendstub reserves the seam. - Discrete adjoints. Fluid and acoustic sensitivities are engineered approximations. No trustworthy Pareto front until exact.
09Further reading
- Geode. Engine source, examples, tests. Not public yet.
- PicoGK (LEAP71), Taskflow, OpenVDB.
- Bendsøe (1989). "Optimal shape design as a material distribution problem." Density-based origin.
- Sigmund (2001). "A 99 line topology optimization code written in Matlab." SIMP + OC.
- Andreassen et al. (2011). "Efficient topology optimization in MATLAB using 88 lines of code." Sensitivity filter.
- Bendsøe & Sigmund (2003). Topology Optimization: Theory, Methods, and Applications. Springer.
- Flanagan & Belytschko (1981). "A uniform strain hexahedron with orthogonal hourglass control." Hourglass modes.
- Langelaar (2017). "An additive manufacturing filter for topology optimization of print-ready designs." LPBF overhang, feature size.
- Briggs et al. (2000). A Multigrid Tutorial. SIAM.
- Saad (2003). Iterative Methods for Sparse Linear Systems. SIAM.