Three-stage modification to support both Lagrange and Serendipity basis types:
1. Added basis_type parameter (default :Lagrange) to all create_basis() functions
- Propagated through all three overloads with keyword argument
- Used in code generation for method signatures
2. Updated ELEMENT_TO_LAGRANGE mapping:
- Quad8: Changed to tuple (:Serendipity, :Quadrilateral) for 8-node serendipity
- Quad9: Remains :Quadrilateral for 9-node full Lagrange
- Added documentation explaining tuple format for serendipity elements
3. Enhanced generation loop to handle three topology cases:
- Simple symbols (e.g., :Triangle) → Lagrange{Triangle, P}
- Parametric functions (N -> Hexahedron{N}) → Lagrange{Hexahedron{N}, P}
- Serendipity tuples (:Serendipity, :Topology) → Serendipity{Topology, P}
Removed 3 duplicate function stub declarations (defined in basis_api.jl):
- get_reference_element_coordinates
- eval_basis!
- eval_dbasis!
This enables clean separation of Quad8 (Serendipity, 8 nodes) from Quad9 (Lagrange, 9 nodes).
Regenerated by lagrange_generator.jl on 2025-11-20 18:14:22.
Changed Quad8 (8-node quadrilateral) from Lagrange{Quadrilateral, 2} to Serendipity{Quadrilateral, 2}. This distinguishes 8-node serendipity (no center node) from 9-node Lagrange (with center node), eliminating method overwrite warnings.
All 6 method definitions updated:
- get_reference_element_coordinates (type and instance)
- get_basis_functions (type and instance)
- get_basis_derivatives (type and instance)
Quad9 remains Lagrange{Quadrilateral, 2} with 9 nodes including center.
Add Serendipity{T,P} basis type for quadrilateral and hexahedral elements with reduced nodes:
- Struct definition with comprehensive documentation
- ndims methods delegating to topology dimension
- nnodes methods: Quad8 (8 nodes), Hex20 (20 nodes)
- Comparison with Lagrange documented (Quad8 vs Quad9)
Replace 4 function stub declarations with comments pointing to basis_api.jl:
- eval_basis!
- eval_dbasis!
- get_basis_functions
- get_basis_derivatives
This eliminates method overwrite warnings when Quad8 uses Serendipity and Quad9 uses Lagrange.
- Add `ndofs(::AbstractBasis)` / `ndofs(::Type{<:AbstractBasis})` with docstring and examples
- Default implementation: `ndofs == nnodes` for standard Lagrange bases
- Export `ndofs` alongside `Lagrange` and `nnodes`
This provides a stable API for callers to preallocate element-local buffers and supports plate elements that have multiple DOFs per node.
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).
- Mark eval_basis!() and eval_dbasis!() as DEPRECATED
- Document why deprecated: topology/basis separation, unclear naming
- Add docstrings for get_basis_functions() and get_basis_derivatives()
- Provide migration examples: OLD vs NEW API side-by-side
- Reference basis_api.jl for full documentation
- Explain topology and basis should be passed separately
- New API: get_basis_functions() returns tuple of functions
- New API: get_basis_derivatives() returns tuple of gradient functions
- basis_api.jl: 210 lines implementing modern functional API
- Re-generated lagrange_generated.jl with 242 new lines
- abstract.jl: Add nnodes() method for Lagrange type
- Backward compatible: old eval_basis! API unchanged
- See ADR-003 for design rationale
Generated by: julia --project=. src/basis/lagrange_generator.jl
Changes:
- All 15 element types now use Lagrange{T,P} parametric type
- Functions: get_reference_element_coordinates(), eval_basis!(), eval_dbasis!()
- Reference coordinates now return tuples (zero-allocation)
- Removed old Seg2Basis, Tri3Basis, Quad4Basis, etc. struct definitions
- All methods work with both Type{Lagrange{T,P}} and Lagrange{T,P} instances
Validated:
- Triangle: Kronecker delta property holds (N_i(x_j) = δ_ij)
- Quadrilateral, Tetrahedron, Hexahedron: First node evaluates to (1,0,0,...)
- Derivatives: Correct gradients at reference coordinates
Consolidates scripts/generate_lagrange_basis.jl into src/basis/lagrange_generator.jl
Changes:
- Added Vecish type alias handling for standalone/included execution
- Added vandermonde_matrix() function (~40 lines) for polynomial basis construction
- Added ElementDescription struct with keyword constructor for readability
- Added 15 element definitions with reference coordinates and polynomial ansatz:
* 1D: Seg2, Seg3
* 2D triangles: Tri3, Tri6
* 2D quads: Quad4, Quad8, Quad9
* 3D tets: Tet4, Tet10
* 3D hexes: Hex8, Hex20, Hex27
* 3D pyramid: Pyr5
* 3D wedges: Wedge6, Wedge15
- Added generation script block (~550 lines) that runs when file executed directly
- Generator now appends "Basis" suffix to all types (Tri3Basis, Quad4Basis, etc.)
- Outputs to src/basis/lagrange_generated.jl with clean formatting
- Includes progress reporting and next steps guidance
Total: 254 → 813 lines (+559 lines)
Run as: julia --project=. src/basis/lagrange_generator.jl
**Three Manuals for Three Audiences:**
1. **User Manual** (docs/user/) - "Just Get It Done"
- For end users, engineers, students
- Simple, practical, step-by-step
- Quick start, tutorials, examples, troubleshooting
- Philosophy: Show me how to solve my problem
2. **Contributor Manual** (docs/contributor/) - "Show Me the Code"
- For developers, contributors, advanced users
- Technical, detailed, design rationale
- Testing, architecture, performance, CI/CD
- Philosophy: Explain HOW and WHY
3. **The JuliaFEM Book** (docs/book/) - "Let Me Show You How I Think"
- For researchers, theory nerds, and Jukka
- Comprehensive, educational, opinionated, personal
- Math foundations, design philosophy, history, research
- Philosophy: Mix theory, code, and personal experience
**Reorganization:**
- Moved: TESTING_PHILOSOPHY.md → contributor/testing_philosophy.md
- Moved: STATUS.md → contributor/status.md
- Moved: TEST_FIXES_NEEDED.md → contributor/test_fixes_needed.md
- Moved: lagrange_basis_functions.md → book/lagrange_basis_functions.md
- Moved: benchmarks/ → book/benchmarks/
- Created: docs/README.md (main index explaining structure)
- Created: README.md in each section explaining audience and contents
- Updated: All references in scripts and source files
**Naming:** All docs now lowercase (testing_philosophy not TESTING_PHILOSOPHY)
**Benefits:**
- Clear separation of concerns
- Users don't get overwhelmed with implementation details
- Contributors get technical depth
- Book preserves deep theory and personal insights
- Each manual optimized for its audience
**Next:** Populate each section with appropriate content
- Moved docs/theory/lagrange_basis_functions.md → src/lagrange_basis_functions.md
- Updated all references in scripts and source files
- Using lowercase for consistency (no uppercase in filenames)
- Documentation now under src/ for automated doc generation
Rationale: Documentation should be close to implementation and follow
consistent naming conventions (lowercase).
MAJOR PERFORMANCE REFACTORING:
1. Shape functions return tuples instead of allocating vectors:
- eval_basis!(): Returns NTuple{N,T} directly (zero allocations)
- eval_dbasis!(): Returns NTuple{N,Vec{D}} directly (zero allocations)
- API boundary (get_basis/get_dbasis) still returns vectors for compat
2. Element is now immutable with compile-time known structure:
- connectivity: Vector{UInt} → NTuple{N,UInt}
- integration_points: Vector{IP} → NTuple{NIP,IP}
- Element{N,NIP,M,B} parametrized by connectivity/IP count
- Changed from 'mutable struct' to 'struct'
3. Helper function for immutability:
- with_integration_points(element, ips) returns new element
- get_integration_points() returns tuple directly
Benefits:
- Zero allocations in hot paths (basis evaluation)
- Compile-time sizes enable better optimization
- Type stability improvements
- Stack allocation instead of heap
Breaking changes:
- Element.connectivity is now tuple (use collect() for vector)
- Element is immutable (use with_integration_points for updates)
Tests: All 157 tests passing
Integrated minimal symbolic differentiation from SymDiff.jl by Jukka Aho:
- differentiate(): Symbolic derivatives for polynomials (+, -, *, /, ^)
- simplify(): Expression simplification with numeric evaluation
- Zero external dependencies for basis function generation!
Changes:
- src/basis/create_basis.jl: Added differentiate() and simplify()
- src/basis/subs.jl: Added local simplify with numeric evaluation
- src/basis/abstract.jl: Removed Calculus import
This replaces the Calculus.jl dependency with ~100 lines of pure Julia
code specifically designed for polynomial basis functions.
- Add Tensors and Calculus to Project.toml dependencies
- Add basis includes to src/JuliaFEM.jl (Phase 1 integration)
- Fix FEMBasis. namespace references → use JuliaFEM namespace
- Update create_basis.jl: AbstractBasis (not FEMBasis.AbstractBasis)
Status: Basis files load, but conflict with FEMBase expectations
Next: Need to consolidate FEMBase or work around AbstractElement type constraints
This is expected during consolidation - we're bridging two systems.