Changed Point from 'mutable struct' to 'struct'.
The Dict for fields remains a reference type, so field updates via setindex!
and update! still work correctly. This change improves type stability and
enables better compiler optimizations.
Benefits:
- Better compiler optimizations (immutable types)
- Type stability improvements
- Stack allocation when possible
- No breaking changes (Dict fields still mutable)
Tests: All 157 tests passing
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
Gmsh returns node and element IDs as UInt64, so we should use unsigned
integers consistently throughout JuliaFEM to avoid unnecessary conversions.
Changes:
- Point.id: Int → UInt
- Element.id: Int → UInt
- Element.connectivity: Vector{Int} → Vector{UInt}
- Element constructors: Accept Integer (converts to UInt internally)
- Default element_id: -1 → 0 (UInt has no negative values)
Benefits:
- Direct compatibility with Gmsh.jl (no Int/UInt conversions)
- Semantically correct (node/element IDs are never negative)
- Slightly more efficient (no sign checks)
Tests: All 156 tests passing
Closes#267
Major architectural decision: Use Tensors.jl consistently everywhere
for geometric vectors, integration points, and coordinates.
Changes to src/elements/elements.jl:
- get_basis(): Convert ip to Vec, use Vector (not Matrix) for eval_basis!
- get_dbasis(): Convert ip to Vec
- jacobian evaluation: Convert geometry and ip.coords to Vec properly
- Handle both raw coordinates (Tuple) and IP struct transparently
New Tutorial 3: Numerical Integration and Jacobian (49 tests)
- Integration point structure and weights
- Jacobian determinant and matrix evaluation
- Numerical integration (constant, linear, quadratic functions)
- Multiple element types (Quad4, Seg2, Tri3)
Tests: 107 → 156 passing (49 new)
Runtime: ~7 seconds
Closes architectural standardization on Tensors.jl.
Related to Issue #250 (merge conflict resolution).
Why Tensors.jl:
- Type stability (100× performance vs Dict-based)
- Material science compatibility (stress tensors)
- Zero-cost abstractions
- Consistent API across all geometric calculations