Add extensive documentation for the basis module covering:
1. Architecture and design philosophy
- Separation of topology and basis
- Zero-cost abstraction principles
- SVector return types and dual-vector design
2. API overview and usage examples
- get_basis_functions() and get_basis_derivatives()
- nbasis() for compile-time basis function count
- Integration with topology and quadrature modules
3. Code generation system
- Vandermonde approach explained
- Symbolic differentiation and simplification
- Why offline generation vs runtime symbolic math
4. Extension guide
- Adding higher-order elements (step-by-step)
- Hierarchical and specialized bases
- When to use generator vs direct implementation
5. Performance characteristics
- Benchmarks: 100-1000× speedup over v0.5.1
- Zero allocations, subnanosecond evaluations
- Scaling with element order
6. Advanced topics
- Numerical precision and ill-conditioned Vandermonde
- Jacobian and physical derivatives
- Partition of unity and reproduction
- Integration accuracy requirements
Total: ~1800 lines of documentation with complete examples,
mathematical foundations, and practical guidance.
Extend basis_generator.jl to automatically emit nbasis() functions alongside
get_basis_functions() and get_basis_derivatives():
1. Add canonical_type_name() helper to convert type aliases to full forms
(Quad9 → Quadrilateral{9}, Tri3 → Triangle{3})
2. Generate @inline nbasis(::Topology, ::Basis) = N for each basis family
This provides zero-cost compile-time basis function count
3. Use instance-based dispatch (::Triangle{3}, not ::Type{Triangle{3}})
for consistency with get_basis_* functions
4. Enhanced pretty-printer to handle both function definitions and simple
assignments, properly unwrapping begin...end blocks
Generated code now uses canonical topology names throughout, avoiding
historical type aliases for better clarity and API consistency.
Add zero-cost nbasis(topology, basis) -> Int function that returns the number
of basis functions at compile time. This is essential for validating Ciarlet
triplet (K, P, Σ) consistency and enables type-stable pre-allocations.
Key features:
- Zero-cost: compiles to single constant return (ret i64 N)
- Instance-based dispatch: nbasis(Triangle{3}(), Lagrange{1}())
- Comprehensive documentation with compile-time verification examples
- Replaces removed ndofs() function with clearer semantics
The function is generated automatically by basis_generator.jl alongside
basis function implementations, ensuring consistency.
- Deleted: src/quadrature/FEMQuad.jl (48 lines, old module wrapper)
- Created: src/quadrature/api.jl (365 lines, comprehensive quadrature API)
Key improvements:
- AbstractQuadratureRule type hierarchy (GaussLegendre, GaussLobatto)
- QuadraturePoint{D,T} struct with Vec{D} coordinates and Float64 weight
- Zero-allocation get_quadrature_points() returning SVector
- Multi-level default_quadrature() dispatch (4 levels: order → topology+order → topology+basis → topology only)
- Comprehensive documentation with examples and performance notes
- Integration with Tensors.jl (Vec) and StaticArrays (SVector)
Replaced:
- Old Val{:symbol} dispatch → Modern type parameters
- Old integrate_1d/2d/3d functions → Removed (not used in codebase)
- Module wrapper → Direct include (quadrature rules now in separate files)
Net: +317 lines (FEMQuad was minimal wrapper, api.jl is complete interface)
Deleted files:
- src/basis/abstract.jl (374 lines) - Old abstract type definitions
- src/basis/basis_api.jl (210 lines) - Old API documentation
New file:
- src/basis/api.jl (164 lines) - Consolidated basis API
Changes:
- Merged AbstractBasis type definition from abstract.jl
- Merged basis evaluation API (get_basis_functions, get_basis_derivatives) from basis_api.jl
- Added AbstractBasisDescription and VandermondeBasisDescription types
- Removed old Lagrange{T,P} (topology in type parameter) - now Lagrange{P} only
- Removed old nnodes formulas (now live in topology module)
- Simplified to clean separation: topology passed separately, not in basis type
- Kept deprecation stubs for eval_basis! and eval_dbasis! for backward compatibility
Net result: 584 lines removed, 164 lines added (420 line reduction)
- Changed Segment{2}: tuple of tuples → SVector of Vec{1,Float64}
- Changed Segment{3}: tuple of tuples → SVector of Vec{1,Float64}
- Both now return SVector(Vec{1}(...), Vec{1}(...), ...) format
- Changed reference_coordinates return type docs: tuple of tuples → SVector of Vec
- Added Base.ndims alias function for Base API interoperability
- Updated docstring examples to use SVector(Vec{D}(...)) syntax
- Updated design philosophy examples: removed old Lagrange{Topology,Order} syntax, now Lagrange{Order}
- Clarified topology defines shape+nodes, basis defines interpolation
- Updated backward compatibility notes: Tri3 → Triangle{3}, etc.
- Added DEPRECATED header comment explaining migration to new API (api.jl)
- Added deprecation notices to AbstractIntegration and IntegrationPoint docstrings
- Added migration example showing old vs new syntax (IntegrationPoint → QuadraturePoint)
- Documented field name changes: ip.ξ → qp.coords
- Changed struct field from 'basis::Lagrange{T,1}' to 'basis::Lagrange{1}' (line 91)
- Changed constructor from 'Lagrange{T,1}()' to 'Lagrange{1}()' (line 211)
- Added comments explaining new API: basis order only, topology passed separately
- Changed Element(::Type{T}, connectivity) to use Lagrange{order} instead of Lagrange{base_topo,order}
- Commented out old API functions using Lagrange{T,P}: _create_topology_instance, jacobian, get_basis, get_dbasis (lines 680-761)
- Commented out get_integration_points_from_basis (lines 854-883)
- Restored get_base_topology function (needed by Element constructor)
- Updated comment explaining new API: topology passed separately, not in type parameter
Replace include statement with comment noting that test_helpers.jl is included by parent runtests.jl. This eliminates method overwrite warnings for create_test_mesh() and create_test_kernel().
The parent test suite (runtests.jl) includes test_helpers.jl once, making it available to all sub-tests.
Replace abstract type definition with comment pointing to canonical definition in mesh/api.jl.
Eliminates documentation replacement warning while preserving single source of truth for refinement strategy hierarchy.
Remove positional argument constructor that duplicated keyword constructor functionality. This eliminates method overwrite warning.
Kept only the keyword constructor which provides clearer API:
- mesh = Mesh{Hex8}(nodes, conn; element_sets=..., node_sets=...)
The keyword version is more explicit and prevents accidental parameter ordering mistakes.
Replace function stub declaration with comment pointing to canonical definition in materials/api.jl. Preserves comprehensive documentation about stress computation interface.
Eliminates documentation replacement warning while maintaining API contract documentation.
Replace abstract type definition and documentation with comment pointing to canonical definition in fields/api.jl. Added note about Displacement{Dim} location.
Eliminates documentation replacement warning from legacy physics API file.
Replace abstract type definition with comment pointing to canonical definition in fields/api.jl.
Eliminates documentation replacement warning while keeping single source of truth for AbstractField supertype.
Replace function stub declaration with comment pointing to canonical definition in physics/api.jl. Added note that plate formulations should implement specific methods.
Eliminates documentation replacement warning while preserving API documentation context.
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.
Replace function stub declaration with comment pointing to canonical definition in fields/api.jl. This eliminates documentation replacement warning while preserving documentation context.
- Changed 'ξ = Vec{3}(ip.ξ)' to 'ξ = ip.ξ' in two test locations
- First occurrence in warm-up loop
- Second occurrence in allocation measurement loop
- No conversions needed since ip.ξ is now already Vec{3}
- Changed 'ξ = Vec{3}(ip.ξ)' to 'ξ = ip.ξ' in two locations
- First occurrence in ∇N_data_tuple computation
- Second occurrence in detJ_w_tuple computation
- No conversions needed since ip.ξ is now already Vec{3}
- Added Vec{D}(point) conversion before IntegrationPoint construction
- Converts tuple from quadrature rules to Vec for tensor operations
- Eliminates need for Vec{N}(ip.ξ) conversions throughout codebase
- Changed ξ field type from NTuple{D,Float64} to Vec{D,Float64}
- Updated docstring to reflect Vec type instead of tuple
- Updated example to show Vec construction
- Enables direct use in tensor operations without conversion
Changed verification from counter-only to extracting and checking matrix:
- Added SparseArrays import for nnz()
- Verify nnz(K) > 0 after assembly (triplets exist)
- Verify nnz(K) == 0 after reset (triplets cleared)
- More robust test than checking counter alone
Counter is implementation detail, matrix content is the guarantee.
Updated compute_block! call to pass arrays directly from caches:
- geometry_cache.∇N_data
- geometry_cache.detJ_w
- material_cache.𝔻
Maintains test comparison between manual and automatic integration.
Replaced cache-based test setup with direct array construction:
- ∇N_data: Matrix{Vec{3,Float64}} with realistic gradient values
- detJ_w: Vector{Float64} with typical integration weights
- D_array: Vector{SymmetricTensor{4,3}} with elasticity tensor
Simplified allocation test to single call (removed loop test).
Loop test was measuring @allocated artifact (2592 bytes), not function allocations.
Single-call test accurately verifies zero-allocation guarantee.
Updated all compute_block! calls to new interface signature.