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)
Update src/basis/lagrange_generator.jl to stop generating deprecated
Changes:
- Remove code generation for eval_basis!() (4 function variants)
- Remove code generation for eval_dbasis!() (2 function variants)
- Rename parameter: topology_type::Symbol → topology_type_expr (clearer)
- Update comments: "Generate code for NEW API only"
- Keep NEW API: get_basis_functions(), get_basis_derivatives()
This generator produces src/basis/lagrange_generated.jl (already
committed with updated output).
The OLD API is no longer needed - all code uses NEW API with
Topology + Basis separation architecture.
Regenerate src/basis/lagrange_generated.jl with updated generator.
Changes:
- Remove deprecated eval_basis!() and eval_dbasis!() functions (OLD API)
- Keep NEW API: get_basis_functions() and get_basis_derivatives()
- Add node count to element comments (e.g., "Seg2, 2 nodes")
- Update generation timestamp: 2025-11-13 02:42:16
This is auto-generated code from src/basis/lagrange_generator.jl.
The old API functions are no longer needed as all code now uses
the NEW API (Topology + Basis separation).
Generated: 594 line changes across all 15 Lagrange element types
(Seg2, Seg3, Tri3, Tri6, Tri7, Quad4, Quad8, Quad9, Tet4, Tet10,
Hex8, Hex20, Hex27, Wedge6, Wedge15).
Add elasticity_tensor(material::LinearElastic) function that returns
the 4th-order elasticity tensor C_{ijkl} for assembly.
Formula: C_{ijkl} = λ δ_{ij} δ_{kl} + μ (δ_{ik} δ_{jl} + δ_{il} δ_{jk})
Returns Tensor{4,3,Float64} for direct use in stiffness assembly:
K_ij^{αβ} = ∫ (∂N_i/∂x_γ) C_{αβγδ} (∂N_j/∂x_δ) dV
This eliminates need for Voigt notation and B-matrices in assembly,
enabling pure tensor mathematics (Tensors.jl).
Used by CPU backend (src/backend/cpu.jl) in compute_element_stiffness().
Foundation for GPU implementation (same tensor approach).
Comment out AbstractMaterial, AbstractElasticMaterial, and
AbstractPlasticMaterial definitions in abstract_material.jl.
These types are now defined in src/api.jl which is included first,
avoiding forward reference and circular dependency issues.
Documentation and concrete implementations remain in this file.
This fixes include order problems where materials needed to be defined
before physics_api.jl but physics_api.jl needed the abstract types.
Major API refactoring: replace mutable ElasticityPhysicsType with
type-parametric Physics struct for compile-time dispatch.
New type hierarchy:
- AbstractField: What we solve (Displacement{3}, Temperature, etc.)
- AbstractFormulation: How we discretize (ContinuumFormulation, BeamFormulation)
- AbstractMaterial: Material behavior (LinearElastic, NeoHookean)
- AbstractMesh: Mesh container
Physics{Formulation, Field, Mesh, Material} enables natural dispatch:
assemble(::Physics{ContinuumFormulation{FullThreeD}, Displacement{3}, M, Mat})
assemble(::Physics{BeamFormulation{Timoshenko}, DisplacementRotation{3}, M, Mat})
Type parameter order prioritizes Formulation for dispatch hierarchy.
Breaking changes:
- Old: Physics(Elasticity, "name", 3)
- New: Physics(name=..., mesh=..., field=Displacement{3}(),
formulation=ContinuumFormulation{FullThreeD}(), material=...)
- Deprecate: add_elements!() - Physics references Mesh, doesn't own elements
Benefits:
- Type stability: All types known at compile time
- Dispatch: Specialized methods for formulation/field combinations
- Extensibility: New formulations/fields without modifying core
- Performance: No runtime type checks, optimal codegen
This is foundation for the NEW API (TDD tests, Nov 14 2025).
Add alias IntegrationPointNEW to capture NEW API type before it's
shadowed by legacy core_types.jl definitions.
Update integration_points() to explicitly use IntegrationPointNEW{D}
with dimension parameter, avoiding ambiguity between old and new API
types.
This is a temporary workaround during the old→new API migration phase.
Once legacy code is removed, IntegrationPoint will be the canonical type.
Implement full 4th-order elasticity tensor approach in CPU backend:
- Fix topology extraction: extract_topology_type() returns type, then
instantiate with node count N (was causing crashes)
- Implement basis derivative evaluation: get_basis_derivatives() call
now works (BLOCKER resolved)
- Complete Jacobian transformation: J = ∑ X_k ⊗ dN_k/dξ using proper
tensor outer products (Tensors.jl)
- Implement stiffness assembly: K_ij^{αβ} = ∫ (∂N_i/∂x_γ) C_{αβγδ}
(∂N_j/∂x_δ) detJ dξ with double contractions
- Add basevec() helper for constructing unit vectors
NO B-matrix, NO Voigt notation - pure tensor mathematics following
golden standard (docs/src/book/multigpu_nodal_assembly.md).
This is the foundation for GPU implementation (same math, different backend).
Add LinearOperators dependency (v2.11.0) to support matrix-free
Krylov subspace methods (GMRES) in Newton-Krylov solver framework.
Also reorganize Project.toml sections: move [weakdeps] and [extensions]
after [compat] for better readability.
- Implement compute_strain() for small strain tensor calculation
- Zero allocation with NTuple inputs and Tensors.jl
- Type stable (@inferred passes)
- Complete test suite with 4 test cases (uniaxial, shear, rigid body, performance)
- Performance validated: 0 allocations, ~110ns median
- Add to test suite in runtests.jl
- Export from JuliaFEM module
Resolves user story #0001
- Replace update!(element, field, value) with fields=(field=value)
- Create elements with all fields from start (immutable pattern)
- Two tests updated: Seg2 and Seg3 elements
- Fix spacing in Dict initialization
- Note: Other tests still use old API (will be updated later)
- Remove unnecessary initialization for Dirichlet problems
- Dirichlet BCs don't require unknown field (optional)
- Assembly checks haskey() before processing elements
- Fix spacing and formatting (Dict{K,V}, for i=1:n)
- Update comments to explain optional field behavior