Create src/api.jl as pure documentation (196 lines, NO type definitions):
- Documents the complete modular API architecture
- Lists all 9 domain api.jl files in dependency order
- Explains design philosophy: zero duplication, domain ownership, minimal core
- Shows type hierarchy across all domains
- Demonstrates assembly dispatch pattern (formulation × field)
- Lists 7 advantages of modular architecture
This file is the architectural guide - all actual type definitions live in
domain-specific api.jl files:
- formulations/api.jl (AbstractFormulation, continuum theories)
- fields/api.jl (Displacement, Temperature, DisplacementRotation)
- materials/api.jl (AbstractMaterial, elastic/plastic)
- mesh/api.jl (AbstractMesh, node-to-elements mapping)
- beams/shells/trusses/api.jl (structural formulations)
- topology/api.jl (AbstractTopology{N}, 17 element types)
Completes systematic modular API refactoring - every domain owns its
abstractions, core is documentation-only.
Refactor src/topology/topology.jl from 173 to 12 lines:
- Remove all AbstractTopology{N} interface definitions (161 lines removed)
- Remove nnodes(), dim(), reference_coordinates(), edges(), faces() stubs
- Interface now defined in src/topology/api.jl (included first)
- Keep file as placeholder for future helper functions
- Add note referencing topology/api.jl for interface
This completes separation of interface (api.jl) from implementations.
Topology/topology.jl previously mixed interface and helpers - now
clean separation following systematic modular architecture pattern.
Part of systematic modular API refactoring.
Create src/physics/api.jl defining physics problem abstractions:
- AbstractPhysics base type for all physics problems
- assemble!() interface for building global system (K, f)
- solve!() interface for solving physics problems
- add_dirichlet!() for essential BCs (prescribed displacements/temperatures)
- add_neumann!() for natural BCs (surface tractions/heat flux)
Physics couples four components: Mesh (where), Material (constitutive law),
Field (what we solve), Formulation (how we discretize). Physics references
Mesh (does not own it) enabling multiphysics: multiple Physics can share
one Mesh for memory efficiency and coupling.
Dispatch specialization via formulation × field type parameters:
assemble!(::Physics{ContinuumFormulation{FullThreeD}, Displacement{3}, M, Mat})
assemble!(::Physics{BeamFormulation{Timoshenko}, DisplacementRotation{3}, M, Mat})
Comprehensive documentation with multiphysics examples, dispatch patterns,
and interface contracts. Assembly implementations in src/assembly/.
Part of systematic modular API architecture.
Create src/formulations/api.jl defining discretization strategy abstractions:
- AbstractFormulation base type for all formulation strategies
- AbstractContinuumTheory for continuum mechanics theory variants
- ContinuumFormulation{Theory} parameterized formulation struct
- Four concrete theories:
* FullThreeD - Full 3D (6 stress components, no simplifications)
* PlaneStress - Thin plates (σ_zz=0, thickness << length)
* PlaneStrain - Thick sections (ε_zz=0, no z-variation)
* Axisymmetric - Rotationally symmetric (σ_rr, σ_θθ, σ_zz, σ_rz)
Formulation defines HOW to discretize (math strategy), while Field defines
WHAT to solve (physical quantity). Formulation × Field determines assembly
dispatch: ContinuumFormulation{FullThreeD} + Displacement{3} dispatches to
3D solid mechanics assembly in src/assembly/continuum_3d.jl.
Comprehensive documentation with theory selection guidelines and examples.
Part of systematic modular API architecture.
Create src/mesh/api.jl defining mesh-specific abstractions:
- AbstractMesh base type for all mesh structures
- nnodes_total(), nelements() for mesh sizing
- get_node(node_id) returns Vec{Dim} coordinates
- connectivity_matrix() returns element-to-nodes mapping
- get_elements_for_node(node_id) returns node-to-elements mapping (critical for nodal assembly)
- get_element_set(name), get_node_set(name) for named sets (BCs, materials, postprocessing)
- AbstractRefineStrategy, refine() for adaptive mesh refinement
Meshes own topology (coordinates, connectivity). Multiple Physics can
share one Mesh for multiphysics coupling. Node-to-elements mapping
enables nodal assembly pattern (see docs/book/multigpu_nodal_assembly.md).
Part of systematic modular API architecture.
Create src/fields/api.jl defining field-specific abstractions:
- AbstractField base type for all field variables
- Displacement{Dim} for solid mechanics (Dim DOFs per node: ux, uy, uz)
- Temperature for heat transfer (1 DOF per node: T)
- DisplacementRotation{Dim} for beams/shells (2*Dim DOFs: displacement + rotation)
- dofs_per_node() interface for DOF counting
Field type determines solution vector structure, boundary condition
interpretation, and assembly dispatch. Examples:
- Displacement{3} with ContinuumFormulation{FullThreeD} → 3D elasticity
- Temperature with ContinuumFormulation{FullThreeD} → heat transfer
- DisplacementRotation{3} with BeamFormulation → 6 DOFs (3 trans + 3 rot)
Part of systematic modular API architecture.
Create src/materials/api.jl defining material-specific abstractions:
- AbstractMaterial base type for all material models
- AbstractElasticMaterial for stateless materials (no history)
- AbstractPlasticMaterial for stateful materials (history-dependent)
- compute_stress() interface (strain → stress + tangent + updated state)
- elasticity_tensor() for elastic constitutive relations
Material models use Tensors.jl (no Voigt notation). Elastic materials
are stateless (LinearElastic, NeoHookean). Plastic materials have internal
state (plastic strain εᵖ, backstress α, hardening κ, damage).
Interface returns (σ, 𝔻, state_new) where 𝔻 is the material tangent ∂σ/∂ε.
Part of systematic modular API architecture.
Create src/shells/api.jl defining shell-specific abstractions:
- AbstractShellTheory base type for shell theories
- ReissnerMindlin concrete theory (thick shells, includes shear, h/L > 1/20, 5 DOFs)
- KirchhoffLove concrete theory (thin shells, no shear, h/L < 1/20, 3 DOFs)
- ShellFormulation{Theory} parameterized formulation struct
Reissner-Mindlin has 5 DOFs per node (ux, uy, uz, θx, θy) with explicit
rotations. Kirchhoff-Love has 3 DOFs (ux, uy, uz) with rotations computed
from displacement gradients (normals remain perpendicular).
Part of systematic modular API architecture.
Create src/beams/api.jl defining beam-specific abstractions:
- AbstractBeamTheory base type for beam theories
- EulerBernoulli concrete theory (classical, no shear deformation, L/h > 10)
- Timoshenko concrete theory (includes shear, thick beams)
- BeamFormulation{Theory} parameterized formulation struct
Beam elements have 6 DOFs per node (ux, uy, uz, θx, θy, θz) and work
with DisplacementRotation{3} field. Euler-Bernoulli assumes plane sections
remain perpendicular to neutral axis, while Timoshenko allows shear deformation.
Part of systematic modular API architecture.
Create src/trusses/api.jl defining truss-specific abstractions:
- AbstractTrussTheory base type for truss theories
- SimpleTruss concrete theory (axial force only, pin-jointed)
- TrussFormulation{Theory} parameterized formulation struct
SimpleTruss supports 2D/3D displacement fields with 2 or 3 DOFs per node.
Documented for future extension with CableTruss and PretensionedTruss.
Part of systematic modular API architecture where each structural
element type owns its formulation abstractions.
Major reorganization of main module file to support new architecture.
Changes - Include Order:
- Include api.jl FIRST (all abstract types and interfaces)
- Include physics.jl after api.jl (concrete Physics implementation)
- Material models after physics (LinearElastic, NeoHookean)
- New Mesh{T} infrastructure (mesh.jl, refine.jl, structured.jl)
Changes - Exports:
- Export core API types: AbstractMesh, AbstractTopology, AbstractMaterial, etc.
- Export physics types: AbstractField, AbstractFormulation, Physics, Constraint
- Export boundary conditions: DirichletBC, NeumannBC
- Export mesh operations: Mesh, topology_type, get_elements_for_node, etc.
- Export refinement: AbstractRefineStrategy, LongestEdgeBisection, refine
- Export structured mesh: create_structured_box_mesh, create_cantilever_mesh, etc.
Changes - Removals:
- Remove temporary jacobian() function (now in elements/elements.jl)
- Comment out backend files (need API updates)
- Comment out old Dict-based Mesh (conflicts with new Mesh{T})
Changes - Additions:
- Include assembly/continuum_3d.jl and continuum_3d_v2.jl
- Export compute_element_stiffness for testing
This establishes the foundation for the new type-parametric architecture.
Migrate element basis evaluation functions to use new topology-aware API.
Changes:
- Add _create_topology_instance() helper to construct topology from Lagrange{T,P}
- Update get_basis() to call get_basis_functions(topology, basis, xi)
- Update get_dbasis() to call get_basis_derivatives(topology, basis, xi)
- Add jacobian() function with embedding support (1D element in 2D/3D space)
- Constraint: B <: Lagrange added to method signatures
Migration from OLD API:
- eval_basis!(B, T, xi) → get_basis_functions(topology, basis, xi)
- eval_dbasis!(B, xi) → get_basis_derivatives(topology, basis, xi)
Maintains compatibility: still returns matrices/vectors for old code interface.
Fix method ambiguity by explicitly qualifying Base.isempty calls.
Changes:
- function isempty(assembly::Assembly) → function Base.isempty(assembly::Assembly)
- All internal isempty() calls qualified with Base.isempty()
- Avoids method ambiguity warnings
This is a standard Julia pattern for extending Base methods on custom types.
Add helper to get recommended integration schemes for topology types.
Changes:
- New function: default_integration(::Type{<:AbstractTopology{N}})
- Returns appropriate Gauss{order}() for common topologies
- Rules: linear elements use minimal exact integration, quadratic use higher order
- Implementations for: Tet4/10, Hex8/20/27, Tri3/6, Quad4/8/9
Examples:
- default_integration(Hexahedron{8}) → Gauss{2}() (2×2×2 = 8 points)
- default_integration(Tetrahedron{4}) → Gauss{1}() (1 point)
- default_integration(Hexahedron{27}) → Gauss{3}() (3×3×3 = 27 points)
Simplifies user code: no need to memorize integration order for each element.
Update Wedge to use node count type parameter per ADR-002.
Changes:
- struct Wedge → struct Wedge{N} <: AbstractTopology{N}
- Aliases: Wedge6 = Wedge{6}, Wedge15 = Wedge{15}
- Simplified implementation following same pattern
- Remove old design documentation
Implements ADR-002 (November 13, 2025): node count from mesh, not basis.
Old files removed: wedge6.jl, wedge15.jl
New file: Single wedges.jl handles all variants via {N}
Update Pyramid to use node count type parameter per ADR-002.
Changes:
- struct Pyramid → struct Pyramid{N} <: AbstractTopology{N}
- Alias: Pyr5 = Pyramid{5}
- Simplified implementation following same pattern
- Remove old design documentation
Implements ADR-002 (November 13, 2025): node count from mesh, not basis.
Old file removed: pyr5.jl
New file: Single pyramids.jl handles all variants via {N}
Update Tetrahedron to use node count type parameter per ADR-002.
Changes:
- struct Tetrahedron → struct Tetrahedron{N} <: AbstractTopology{N}
- Aliases: Tet4 = Tetrahedron{4}, Tet10 = Tetrahedron{10}
- Simplified implementation following same pattern
- Remove old design documentation
Implements ADR-002 (November 13, 2025): node count from mesh, not basis.
Old files removed: tet4.jl, tet10.jl
New file: Single tetrahedra.jl handles all variants via {N}
Update Triangle to use node count type parameter per ADR-002.
Changes:
- struct Triangle → struct Triangle{N} <: AbstractTopology{N}
- Aliases: Tri3 = Triangle{3}, Tri6 = Triangle{6}, Tri7 = Triangle{7}, Tri10 = Triangle{10}
- Simplified implementation following same pattern
- Remove old design documentation
Implements ADR-002 (November 13, 2025): node count from mesh, not basis.
Old files removed: tri3.jl, tri6.jl, tri7.jl
New file: Single triangles.jl handles all variants via {N}
Update Quadrilateral to use node count type parameter per ADR-002.
Changes:
- struct Quadrilateral → struct Quadrilateral{N} <: AbstractTopology{N}
- Aliases: Quad4 = Quadrilateral{4}, Quad8 = Quadrilateral{8}, Quad9 = Quadrilateral{9}
- Simplified implementation following same pattern as Hexahedron and Segment
- Remove 140+ lines of old design documentation
Implements ADR-002 (November 13, 2025): node count from mesh, not basis.
Old files removed: quad4.jl, quad8.jl, quad9.jl
New file: Single quadrilaterals.jl handles all variants via {N}
Update Segment to use node count type parameter per ADR-002.
Changes:
- struct Segment → struct Segment{N} <: AbstractTopology{N}
- Aliases: Seg2 = Segment{2}, Seg3 = Segment{3}
- Add nnodes(), dim() implementations
- reference_coordinates() for Segment{2} and Segment{3}
- Generic edges() and faces() for any N
- Remove 100+ lines of old design documentation
Implements ADR-002 (November 13, 2025): node count from mesh, not basis.
Old files removed: seg2.jl, seg3.jl
New file: Single segments.jl handles all variants via {N}
Update Hexahedron to use node count type parameter per ADR-002.
Changes:
- struct Hexahedron → struct Hexahedron{N} <: AbstractTopology{N}
- Aliases now specify node count: Hex8 = Hexahedron{8}
- Add nnodes() implementation: returns N from type parameter
- Simplify documentation: remove 150+ lines explaining old design
- Keep reference_coordinates() for Hexahedron{8} only
- Generic edges() and faces() work for any N
Benefits:
- Type system encodes node count (compile-time)
- Hex8, Hex20, Hex27 are distinct types (better dispatch)
- Matches mesh file reality (mesh specifies node count)
- Implements ADR-002 decision (November 13, 2025)
Old files removed: hex8.jl, hex20.jl, hex27.jl (separate files)
New file: Single hexahedra.jl handles all variants via {N}
Change AbstractTopology to AbstractTopology{N} where N is node count.
This implements ADR-002 (November 13, 2025) decision: node count comes
from mesh connectivity and should be captured in the type for
compile-time optimization.
Benefits:
- Enables Val(N) for zero-allocation ntuple operations
- Allows loop unrolling for small N (8, 20, 27 nodes typical)
- Type-stable operations based on node count
- Node count known from mesh before basis selection
Documentation updates:
- Add Type Parameter section with examples
- Add Rationale section explaining performance benefits
- Reference ADR-002 for design decision details
Concrete types updated in subsequent commits:
Hexahedron{N}, Tetrahedron{N}, Triangle{N}, etc.
Major revision of ADR-002 based on implementation experience.
Decision change:
- OLD (Nov 9): Topology without node count (pure geometry)
- NEW (Nov 13): Topology with node count type parameter
Rationale:
Node count comes from MESH FILES, not from basis choice. When reading
Abaqus .inp, Code Aster .med, or GMSH .msh files, the mesh explicitly
specifies node count in element connectivity:
- Hex element (1,2,...,8) → 8 nodes
- Hex element (1,2,...,20) → 20 nodes
- Hex element (1,2,...,27) → 27 nodes
The mesh reader knows node count BEFORE basis functions are selected.
Therefore, topology must include node count: Hexahedron{N}.
New design:
struct Hexahedron{N} <: AbstractTopology end
const Hex8 = Hexahedron{8}
const Hex20 = Hexahedron{20}
This maintains type stability (N known at compile time) while
acknowledging that N originates from mesh data, not basis choice.
Supersedes: ADR-002 (November 9, 2025)