# Seastead Parametric CAD Workflow Below is a complete, self-contained HTML document answering all your questions — the short version is: **yes, a single OpenSCAD ground truth is the right architecture**, with STL as your interchange format, **Capytaine (BEM) as your primary wave-response tool** (much cheaper than CFD at this stage), and **CalculiX or Code_Aster for FEA** via a gmsh mesh conversion step. The 1:50 plastic structural model question has a genuinely encouraging answer — the numbers happen to work out — with important caveats about FDM printing. ```html
One ground-truth model → printed scale models, wave simulations, FEA & CFD — all open source
| Task | Primary Tool | Input Format | Notes |
|---|---|---|---|
| Parametric ground truth | OpenSCAD | .scad | Keep as-is. Your existing investment pays off. |
| Scale model printing | PrusaSlicer or Cura | .stl | OpenSCAD CLI can batch-export scaled STLs. |
| Wave response (hydrodynamics) | Capytaine (BEM, successor to Nemoh) | .stl (via meshio) or Nemoh .inp | Python; gives RAOs, added mass, damping, wave loads vs. period. This should be your workhorse. |
| FEA (structure strength) | CalculiX (with PrePoMax GUI) or Code_Aster (Salome-Meca), or Elmer | .inp / .med (volume mesh) | All accept Abaqus-style .inp from gmsh. CalculiX + PrePoMax has the gentlest learning curve. |
| CFD (waves, viscous effects) | OpenFOAM + waves2Foam (or overWave / olaFlow) | .stl for snappyHexMesh | Use sparingly — 100× the cost of BEM for this stage. Perfect STL consumption though. |
| Format conversion hub | meshio (Python) + MeshLab | everything → everything | STL ↔ Nemoh, STL repair, decimation. |
| Mesh → volume mesh for FEA | gmsh | .stl → .inp/.med | The one unavoidable conversion step (see §5). |
| Version control | git | .scad + everything | Every design variant is a commit; exports are regenerable artifacts. |
| Bridge / escape hatch | FreeCAD (has an OpenSCAD workbench) | .scad → STEP | When you eventually need STEP files for the naval architect or a machine shop. |
Yes — this is exactly how professional engineering pipelines are built: a single parametric master model from which every derived artifact is generated. The rules that make it work:
OpenSCAD is unitless; software downstream isn't. The single most important convention: 1 OpenSCAD unit = 1 meter, full-scale. Capytaine, OpenFOAM, and FEA solvers all work in meters by default, so the ground truth needs no scaling for simulation. Only the 3D-printing exports get scaled (slicers assume 1 unit = 1 mm).
// ============ params.scad — THE single source of truth ============
// All lengths in meters, FULL SCALE. Nothing else in the project
// defines a dimension; every other file reads from here.
$fn = 64; // global mesh resolution (tune per export)
// --- Hull / spar ---
spar_diameter = 2.4;
spar_length = 12.0;
ballast_draft = 8.0;
hull_diameter = 6.0;
hull_freeboard = 3.0;
// --- Structure ---
plate_thickness = 0.012; // aluminum plate
bulkhead_spacing = 1.5;
// --- Joinery (printed model assembly) ---
pin_diameter = 0.008; // full-scale equiv. of registration pins
print_clearance = 0.0002; // slip-fit tolerance for printed parts
// --- Exports ---
print_scale = 1/50; // Froude model scale factor
seastead/
├── params.scad # all constants — the only place numbers live
├── parts/
│ ├── spar.scad # module spar() — geometry only, no dimensions
│ ├── hull.scad # module hull()
│ ├── deck.scad
│ └── joinery.scad # registration pins/holes for printed parts
├── assembly.scad # the full seastead = the ground truth of "how it fits"
├── exports/
│ ├── export_print.scad # scaled STLs for the printer
│ ├── export_sim.scad # full-size closed STL for Capytaine/CFD
│ └── export_fea.scad # exterior + internal bulkheads as surfaces
└── analysis/
├── capytaine/ (python scripts, results)
├── fea/ (gmsh .geo scripts, CalculiX runs)
└── cfd/ (OpenFOAM cases)
OpenSCAD has no assembly-constraint system like real CAD, but you can get 90% of the benefit with two conventions:
assembly.scad places parts with transforms computed only from params.scad. If two parts don't
collide in assembly.scad, they fit at every scale.joinery.scad, sized from pin_diameter and print_clearance. Every printable
part automatically gets its pin holes cut and its pins added. Because both come from the same module, they mate at
any scale.// joinery.scad — every printed part calls these
module pin() { cylinder(d = spar_diameter*0 + pin_diameter, h = pin_diameter*3); }
module pin_hole() { cylinder(d = pin_diameter + 2*print_clearance, h = pin_diameter*4); }
// export_print.scad — scale happens ONLY here
module export_spar_section_1() {
scale(1000 * print_scale) // meters → mm, scaled 1:50
spar_section_1();
}
spar_section_1(); // selected via CLI -D part=...
Whenever you change a parameter, regenerate all artifacts. OpenSCAD's CLI makes this a script:
#!/bin/bash
# regenerate.sh — run after every design change
for p in spar_sec1 spar_sec2 hull deck flange; do
openscad -o exports/STL/$p.stl -D "part=\"$p\"" exports/export_print.scad
done
openscad -o exports/STL/seastead_full.stl exports/export_sim.scad # 1 unit = 1 m
openscad -o exports/STL/hull_surfaces.stl exports/export_fea.scad
# then: python analysis/capytaine/run_bem.py
# gmsh analysis/fea/mesh.geo -3 -format inp
For tow-tank-style wave testing, remember the Froude scaling rules for interpreting your printed model (λ = 50):
| Quantity | Model / Full scale |
|---|---|
| Length | 1 / 50 |
| Time, wave period | 1 / √50 ≈ 1 / 7.07 |
| Velocity | 1 / √50 |
| Frequency | √50 × |
| Force (hydrodynamic) | 1 / 50³ = 1 / 125,000 |
| Mass (for ballast & CG match!) | 1 / 125,000 — you must add ballast to the printed model to match full-scale displacement, center of gravity, and (ideally) roll/pitch inertia. Printing alone will never get this right. |
At the design-screening stage you almost never need CFD. Capytaine is a boundary-element method (BEM) code: it computes, for each wave period and heading, the motions (RAOs — response amplitude operators), added mass, damping, and wave excitation forces. A run that would take OpenFOAM a day takes Capytaine seconds-to-minutes, so you can sweep dozens of design variants. It's the right tool for "how does it work in waves" at this stage.
It consumes exactly what you have: a closed triangular surface mesh, via meshio:
# pip install capytaine meshio matplotlib
import capytaine as cpt
from capytaine.io.meshio import load_from_meshio
# Full-scale closed hull (meters). Capytaine clips it at the waterline itself.
mesh = load_from_meshio("exports/STL/seastead_full.stl")
body = cpt.FloatingBody(mesh, name="seastead")
body.add_all_rigid_body_dofs()
body.center_of_mass = (0, 0, -1.5) # from your params
body.inertia_matrix = ... # scaled from your design
test_matrix = cpt.matrix_like(...) # periods 2–20 s, headings
solver = cpt.BEMSolver()
rbs = solver.fill_dataset(test_matrix, body)
# Then plot RAOs: heave/pitch vs wave period, for each wave height,
# i.e. exactly "visualize different wave sizes and periods"
import matplotlib.pyplot as plt
rabs = rbs["RAO"] # motion per wave amplitude
Mesh rules for BEM: panel size should be smaller than ~1/8 of the shortest wavelength you care
about, and small enough to resolve hull curvature. Tune OpenSCAD's $fn up for the sim export
(it's fine for the sim export to have 50k+ triangles; decimate in MeshLab only if runs get slow). Capytaine wants
the wetted body — but since it can cut the mesh at the waterline itself, just export one closed solid of
the whole exterior hull and set the draft via the body's position.
OpenFOAM + a wave-generation library (waves2Foam, olaFlow) is the open
source standard, and its mesher snappyHexMesh consumes STL directly — again, zero format friction with
OpenSCAD. But:
For most design screening, the Capytaine RAO plots — heave/pitch response vs. wave period, with wave height scaling linearly — are your "visualize different wave sizes and periods" answer.
The honest catch: OpenSCAD gives you a surface mesh (STL); solid FEA needs a volume mesh. The open-source bridge is gmsh:
STL (watertight, from OpenSCAD)
→ MeshLab (optional: cleanup, decimate)
→ gmsh (.geo script: import surface, remesh, generate 3D tetrahedra)
→ export .inp (Abaqus format)
→ CalculiX (PrePoMax GUI) — apply aluminum, boundary conditions, wave loads
// analysis/fea/mesh.geo (gmsh)
Merge "hull_surfaces.stl";
Surface Loop 1 = Surface{:};
Volume(1) = {1}; // creates solid from closed shell
Mesh.CharacteristicLengthMin = 0.05; // meters — from params!
Mesh.CharacteristicLengthMax = 0.30;
Mesh.Algorithm3D = 1;
Mesh 3;
Save "hull_solid.inp";
Solver options, in order of friendliness:
| Tool | GUI | Why / why not |
|---|---|---|
| CalculiX + PrePoMax | PrePoMax (excellent, free, Windows/Linux) | Abaqus-compatible .inp from gmsh loads directly. Best starting point. Open source (CalculiX) + free GUI. |
| Code_Aster (in Salome-Meca) | Salome-Meca | Very powerful, fully open source, French nuclear-grade. Steeper learning curve; documentation largely in French. |
| Elmer** | ElmerGUI | Fully open source, general multiphysics, decent for linear statics. |
This is the best question in your list, because the numbers actually work out surprisingly well — with caveats.
Wave loading is gravity-driven, so hydrodynamics follow Froude scaling (time/velocity scale as √λ). Structural response follows Cauchy scaling: the ratio of inertial load to elastic stiffness must match, which requires:
Ca = ρ·v²/E must be equal in model and prototype
→ E_model = E_aluminum / 50 × (ρ_model / ρ_aluminum)
With E_aluminum ≈ 69 GPa, ρ = 2700:
E_model ≈ 69/50 × (1200/2700) ≈ 0.6 GPa
(or ≈ 1.4 GPa if you ignore the density correction)
| Material | E (GPa) | Verdict for 1:50 Cauchy model of aluminum |
|---|---|---|
| Target | 0.6 – 1.4 | — |
| SLA resin (cured) | 1 – 3 | ✅ Best match, and isotropic |
| PETG | ~2.0 | ✅ Close |
| ABS | ~2.2 | ✅ Close |
| PLA | ~3.5 | ⚠️ ~2–5× too stiff (results conservative in deflection) |
So yes — an ordinary plastic 1:50 model is in the right elastic ballpark for aluminum. That's a lucky coincidence worth exploiting. If similitude holds, then at corresponding points: strain is equal in model and prototype, deflection scales 1/λ, and if the model yields or cracks at load X, the full aluminum structure is in trouble at the Froude-scaled equivalent load.
params.scad (single source of truth, meters, full scale)
│
assembly.scad (fit/position ground truth)
│
┌─────────────┬────┴──────────┬────────────────┐
▼ ▼ ▼ ▼
export_print export_sim export_fea export_sim
(1:50, mm) (1:1, STL) (shells/solid) (1:1, STL)
│ │ │ │
PrusaSlicer Capytaine gmsh → .inp OpenFOAM
Froude model (BEM: RAOs, → CalculiX/ (targeted CFD:
in waves wave loads) Code_Aster slamming, viscous)
│ │ │
└────── physical test ─── validates ──┐
▼
FEA validated at model scale →
FEA trusted at full scale (aluminum)
│
naval architect hands off:
params.scad + STEP (via FreeCAD)
| Tool | Role | Comment |
|---|---|---|
| FreeCAD (OpenSCAD workbench) | .scad → solid → STEP | The bridge when the naval architect or a fabricator asks for STEP. Conversion of complex CSG is imperfect; test early. |
| CadQuery / Build123D (Python) | Alternative parametric core | Exports true STEP/BREP solids, which feed FEA without the mesh conversion step. Consider migrating here if gmsh pain becomes excessive — but it means rebuilding your library. OpenSCAD is fine for now. |
| meshio | Format swiss-army knife | STL ↔ Nemoh ↔ .inp ↔ .med etc. in one Python call. |
| MeshLab | Repair, decimate, inspect | Decimate high-$fn meshes for Capytaine speed. |
| Python + Jupyter + matplotlib | Results analysis | Capytaine results are xarray datasets — plot RAO families, compare variants, save every design iteration's curves. |
| Paraview | CFD/FEA results visualization | The standard open-source post-processor. |
| git + GitHub/GitLab | Everything | Commit .scad and analysis scripts; don't commit big result files. Every design variant is reproducible from history. |
The one structural weakness of a pure-OpenSCAD pipeline is that STL is a faceted approximation, and FEA of stress concentrations at faceted edges is meaningless at the local level. For screening-level global structure ("does the spar-to-hull joint have 3× margin against design wave loads?") it's fine. Fine detail (weld details, penetrations, ring stiffener sizing) is exactly what your naval architect will do in a real CAD/FEA package later — and this pipeline's job is to hand them a design where those details are worth refining.