- Define AbstractContinuumTheory abstract type hierarchy
- Implement FullThreeD for general 3D continuum mechanics
- Implement PlaneStress for thin structures (σ_zz = 0)
- Implement PlaneStrain for long structures (ε_zz = 0)
- Implement Axisymmetric for rotationally symmetric problems
- Add Voigt notation helpers for stress/strain tensors
- Document theory assumptions and use cases
- 178 lines with comprehensive documentation
- Export PreparedElement, prepare_element!, compute_block!, compute_block_at_point
- Export apply_neumann_bcs!, apply_dirichlet_bcs! from common location
- Update include path for domains/common/boundary_conditions.jl
- Document that BC functions work with any kernel/domain type
- Remove apply_neumann_bcs! and apply_dirichlet_bcs!
- Functions moved to domains/common/boundary_conditions.jl
- Keeps assemble.jl focused on matrix/vector assembly only
- Move apply_neumann_bcs! and apply_dirichlet_bcs! from continuum/assemble.jl
- Functions are domain-agnostic (work with any AbstractKernel)
- Place in domains/common/ for reuse across continuum/beams/shells/trusses
- Update to use generic dofs_per_node(kernel) instead of hardcoded 3
- Change return type from Tensor{4,3} to SymmetricTensor{4,3}
- Construct full 81-component tensor then convert to symmetric form
- Matches NeoHookean return type for API consistency
- Properly encodes material symmetry (C_ijkl = C_jikl = C_ijlk = C_klij)
Convert elasticity_tensor() to compile-time generation.
Before (672 bytes in test context):
- Runtime array comprehension for 81 tensor components
- Tuple conversion caused allocations
- Type instability from generic Tensor{4,3} constructor
After (0 bytes):
- @generated function pre-computes all 81 components at compile time
- Returns concrete Tensor{4,3,Float64,81} type
- Zero runtime allocations
Algorithm:
- Compute symbolic expressions for C_{ijkl} at compile time
- Generate optimized code with only λ_val, μ_val runtime parameters
- Tensor construction happens entirely at compile time
Result: 672 bytes → 0 bytes (100% reduction)
Note: This was part of the optimization but not the primary fix.
The main issue was ips::Any type instability in ElementCache.
- Refactor assemble!() to use COOAssembler + ContinuumKernel
- Remove 1200+ lines of monolithic assembly code
- Reduce to 176 lines (93% code reduction)
- Use create_cache(), assemble!(), extract_system() from assemblers
- Keep apply_neumann_bcs!() and apply_dirichlet_bcs!() for BC handling
- 176 lines (was 1200+ lines before refactoring)
Before refactoring:
- Monolithic assembly code mixing HOW and WHAT
- Difficult to extend with new assembler strategies
- Difficult to test assembler vs kernel logic separately
- 1200+ lines of tightly coupled code
After refactoring:
- Clean separation: assembler (HOW) vs kernel (WHAT)
- Easy to swap assembler (COO ↔ CSC ↔ Nodal)
- Easy to test components independently
- 93% code reduction (176 lines)
Usage example:
physics = Physics(
ContinuumFormulation{FullThreeD}(),
Displacement{3}(),
mesh,
LinearElastic(E=210e9, ν=0.3)
)
K, f = assemble!(physics)
Validation:
- Cantilever regression test passes (6/6 tests)
- Assembly time: 854.83 ms
- Tip deflection matches baseline within 0.1%
- Zero-allocation assembly confirmed
- Implement NodalAssembler placeholder for future GPU implementation
- Add create_cache() stub for NodalCache creation
- Add assemble!() stub with planned algorithm documentation
- Add compute_node_contributions!() stub for node-level assembly
- Document GPU parallelization strategy (one thread per node)
- 178 lines of placeholder and documentation
Planned GPU algorithm:
1. Launch one thread per node
2. Each thread gets touching elements for its node
3. Compute contributions from all touching elements
4. Atomic add to global K, f (thread-safe on GPU)
Expected performance:
- 2-10x speedup on GPU for large problems (> 100k nodes)
- Better cache locality for nodal DOFs
- Natural parallelization pattern
Status:
- Not yet implemented
- Raises error directing users to COO/CSC assemblers
- Will require CUDA.jl or similar GPU framework
- Implement CSCAssembler using pre-built CSC structure
- Implement create_cache() for CSCCache with sparsity pattern
- Implement assemble!() with in-place merge to CSC arrays
- Implement merge_to_csc!() using two-pointer algorithm
- Implement scatter_to_force!() for force vector assembly
- 298 lines of optimized CSC assembly
Algorithm:
1. Pre-build sparsity pattern once (during cache creation)
2. Loop over elements
3. Compute element stiffness using kernel (in-place)
4. Get DOF mapping (in-place)
5. Merge Ke directly into CSC structure (two-pointer merge)
6. Accumulate fe to global force vector
Performance characteristics:
- 4.1x faster than COO
- 16.6x less memory than COO
- Best for production code and nonlinear problems
Two-pointer merge:
- Efficient in-place insertion into CSC arrays
- No sorting or duplicate removal needed
- Inspired by Ferrite.jl, adapted for JuliaFEM
Critical for performance:
- Structure reused across assembly calls
- Ideal for nonlinear iterations (Newton's method)
- Ideal for time stepping (same topology)
- Implement COOAssembler using coordinate (triplet) format
- Implement create_cache() for COOCache creation
- Implement assemble!() with zero-allocation element traversal
- Implement scatter_to_triplets!() for in-place triplet accumulation
- Implement scatter_to_force!() for force vector assembly
- 247 lines of COO assembly implementation
Algorithm:
1. Loop over elements
2. Compute element stiffness using kernel (in-place)
3. Get DOF mapping (in-place)
4. Scatter Ke to triplet arrays (I, J, V)
5. Scatter fe to global force vector
6. Build sparse matrix at end: sparse(I, J, V)
Performance characteristics:
- Baseline reference implementation (1.0x)
- Simple and robust
- Moderate memory usage
- Best for prototyping and debugging
Zero-allocation assembly:
- All arrays pre-allocated in cache
- Element cache reused for all elements
- No heap allocations during assembly loop
- Define AbstractKernel interface for domain-specific assembly
- Specify required methods: compute_element_stiffness!(), dofs_per_node(), get_dof_mapping!()
- Document zero-allocation requirements for all interface methods
- Provide comprehensive examples for continuum, plate, beam kernels
- Add validation helpers: validate_kernel_implementation()
- Document dispatch strategies for material models
- Changed dofs parameter to AbstractVector{Int} for view compatibility
- 329 lines of interface specification and validation
Interface contract:
- compute_element_stiffness!(): Write Ke, fe to ElementCache in-place
- dofs_per_node(): Return number of DOFs per node (pure function)
- get_dof_mapping!(): Fill global DOF indices to pre-allocated buffer
Design philosophy:
- Assemblers are generic (work with any kernel)
- Kernels are domain-specific (continuum, plate, beam, etc.)
- Interface enforces zero-allocation assembly
- Implement COOCache for coordinate format assembly
- Implement CSCCache for compressed sparse column assembly
- Implement NodalCache for node-based assembly (future GPU)
- Add reset!() methods for cache reuse in nonlinear iterations
- Add extract_system() methods to get K, f from caches
- Implement build_sparsity_pattern() for CSC structure pre-building
- Extract mesh type parameters at runtime for capacity estimation
- 407 lines of cache implementation
Zero-allocation guarantee:
- All arrays pre-allocated during cache creation
- Assembly calls reuse existing arrays
- Critical for nonlinear solvers and time stepping
Memory efficiency:
- COO: Triplet arrays sized for element connectivity
- CSC: Pre-built sparsity pattern, reused structure
- Nodal: Includes node-to-elements inverse connectivity
- Include physics/abstract.jl for AbstractPhysics type
- Include physics/api.jl for interface functions
- Include physics/types.jl for concrete Physics struct
- Include physics/boundary_conditions.jl for BC implementations
- Update exports: AbstractPhysics, Physics, Constraint, DirichletBC, NeumannBC
- Maintain backward compatibility with existing code
- Remove old single-file physics.jl include
- Implement add_dirichlet! for essential BCs (prescribed values)
- Implement add_neumann! for natural BCs (forces/tractions)
- Support multiple nodes and DOF components in single call
- Store BCs in physics.bc_dirichlet and physics.bc_neumann
- Add usage examples for common BC patterns
- 86 lines with complete method implementations
- Define AbstractPhysics abstract type in dedicated file
- Consolidate documentation from previous duplicate definitions
- Document type as coupling of Mesh, Material, Field, and Formulation
- Add comprehensive examples for 3D solid, heat, and beam physics
- Include multiphysics pattern documentation
- Remove duplicate AbstractPhysics definitions across codebase
- 109 lines of documentation and abstract type definition
- Introduce AbstractRefineStrategy and LongestEdgeBisection
- Split Hex8 elements per axis with midpoint deduplication
- Preserve mesh metadata while iterating refinement levels
- Create general box mesher with boundary node/element sets
- Provide convenience wrappers for unit cubes, cantilevers and thin plates
- Document usage examples for convergence and application setups
- Generate Tri3 rings parameterized by radius, radial and angular counts
- Populate connectivity for central fan and radial bands
- Define default node/element sets for center and outer boundary conditions
- Define Mesh{N,T} structure with validated connectivity and sets
- Provide APIs for node/element lookup, colors, ghost ownership and IDs
- Implement permutation, adjacency and utility helpers for assembly workflows
- Replace language-tagged code fences and add proper blank lines to satisfy Markdown lint rules
- Escape `$` in example error string to avoid accidental interpolation (`error("No assembly method for formulation \$Fm with field \$F")`)
Formatting-only changes to improve generated documentation and prevent lint failures; no runtime behavior altered.
- Removed unused imports (`add_node!`, `add_element_to_element_set!`, `add_node_to_node_set!`) from the `using ..JuliaFEM:` line
- Keep `Preprocess` re-exported for convenience
This reduces namespace pollution and lowers the chance of circular import issues; no functional changes expected.
- 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.
- Insert blank lines around headings and list items for better rendering
- Clarify pattern notes: zero-duplication, domain ownership, minimal core
- Improve example spacing so code fences render correctly in generated docs
No code changes; only formatting and readability improvements to the API documentation.
- Replace `include("formulations/api.jl")` with `include("domains/continuum/formulations.jl")`
- Move domain API includes under `domains/*` (beams, shells, trusses, plates)
- Add plate formulations and plate basis includes (DKT, plate elements)
- Rework quadrature includes to load tables from `quadrature/*` and export `get_quadrature_points`
- Consolidate legacy modules under `legacy/` and adjust includes accordingly
- Consolidate mesh readers under `readers/*` and move GMSH reader into `io/gmsh_reader.jl`
- Replace older assembly includes with `assembly/framework.jl` and `assembly/*` structures
- Export new API symbols and add compatibility re-exports where needed
This change reorganizes the package file structure and wiring to make the new modular architecture (domains, quadrature tables, plate elements, and legacy shims) loadable from the top-level `src/JuliaFEM.jl`.