-
GPU Element Structure (
GpuBeamElement) - src/analysis/gpu/matrix_free.rs:14-33- Material properties (E, G, A, Iy, Iz, J)
- Element geometry (length, direction cosines)
- DOF mapping (12 DOFs per element)
-
Metal Shaders - src/analysis/gpu/shaders/element_ops.metal
- Element stiffness computation (3D beam, dense 12×12)
- Local-to-global transformation
- Dense matrix-vector operations
- Buffer clearing kernel (for atomic operations)
-
Matrix-Free Solver (
MatrixFreeGPU) - src/analysis/gpu/matrix_free.rs:79-92- Element-by-element matvec operation
- PCG solver framework
- GPU buffer management
-
Integration
- Module exports
- Test infrastructure
- Benchmark harness
Root Cause: Architectural mismatch between matrix-free approach and traditional FEA boundary condition handling.
Traditional FEA (used by CPU solver and sparse GPU solver):
1. Assemble global K matrix (n × n)
2. Assemble force vector f (n × 1)
3. Apply boundary conditions:
- Remove rows/columns for constrained DOFs
- Reduced system: K_red (m × m), f_red (m × 1) where m < n
4. Solve K_red · u_red = f_red
5. Expand solution back to n DOFs
Matrix-Free approach (current implementation):
1. Store element data on GPU
2. Receive f_red (m × 1) from pipeline
3. Try to compute K · x using ALL n DOFs
4. ❌ MISMATCH: matvec expects n DOFs, but only has m DOFs!
Test Case: Simple beam with 2 nodes
- Total DOFs: 12 (6 per node)
- Node 0: Fixed (6 DOFs constrained)
- Node 1: Free (6 DOFs)
- After BCs: m = 6 DOFs
What Happens:
// In solve():
let n = f.len(); // n = 6 (reduced system)
// In matvec():
let buf_y = self.create_zero_buffer(self.num_dofs); // size = 12!
// ❌ Size mismatch: trying to work with 6-DOF vector in 12-DOF space###Solution 1: Full-System Matrix-Free (Recommended)
Modify the solver to work with the FULL system (all n DOFs):
Advantages:
- True matrix-free approach
- No DOF reduction needed
- More efficient for GPU
- Matches commercial FEA solvers
Implementation:
- Handle boundary conditions via penalty method or Lagrange multipliers
- Keep all n DOFs in the system
- Matvec operates on full n-dimensional vectors
- Constrained DOFs are zeroed in the solution
Changes Needed:
- Modify
LinearSolvertrait to accept boundary conditions - Implement penalty-based BC enforcement in matvec
- Update pipeline to pass full system to solver
Adapt elements to work only with free DOFs:
Advantages:
- Compatible with existing pipeline
- Minimal API changes
Disadvantages:
- More complex implementation
- Need to map element DOFs to reduced system
- Less efficient (additional indirection)
Implementation:
- Create DOF mapping: global → reduced
- Modify element assembly to use reduced DOFs
- Matvec operates on reduced m-dimensional vectors
Changes Needed:
- Add DOF reduction mapping to
MatrixFreeGPU::new() - Update Metal shader to use mapped DOFs
- Rebuild element buffers after BC application
- ✅ Element data conversion (CPU → GPU)
- ✅ Metal shader compilation
- ✅ Buffer management
- ✅ Atomic buffer clearing
- ✅ 3D beam stiffness computation
- ✅ Coordinate transformation
- ✅ Dense matrix operations
- ❌ DOF dimension mismatch (12 vs 6)
- ❌ Boundary condition handling
- ❌ PCG convergence (diverges due to wrong dimensions)
=== Matrix-Free GPU Solver ===
Total DOFs: 12 (model)
Free DOFs: 6 (after BCs) ← MISMATCH!
Force norm: 1.000e3
f[0..6] = [0.0, 0.0, -1000.0, 0.0, 0.0, 0.0]
matvec input x[0..5] = [0, 0, 0, 0, 0, 0] (size 6)
matvec output y[0..5] = [0, 0, 1.68e8, ...] (size 12!)
-
Week 1: Modify
LinearSolvertrait- Add boundary conditions parameter
- Update all existing solvers to new interface
-
Week 2: Implement penalty-based BCs in matrix-free
- Add penalty parameter (e.g., 1e10 × max(K))
- Modify matvec to enforce constrained DOFs
-
Week 3: Testing and validation
- Verify solutions match CPU solver
- Benchmark performance
-
Days 1-2: Implement DOF mapping
- Create global → reduced mapping
- Store in
MatrixFreeGPU
-
Days 3-4: Update Metal shader
- Pass DOF mapping to GPU
- Modify element assembly to use mapped indices
-
Day 5: Testing
- Verify numerical correctness
- Basic benchmarks
Expected performance for Option B (reduced-system):
- Small models (<1K DOF): 0.5-1× CPU (overhead dominates)
- Medium models (1-10K DOF): 2-5× CPU
- Large models (>10K DOF): 8-15× CPU
Expected performance for Option A:
- Small models: 1-2× CPU
- Medium models: 5-10× CPU
- Large models: 15-25× CPU
Full-system is faster because:
- No DOF mapping overhead
- Better memory access patterns
- Simpler GPU kernel
src/analysis/gpu/matrix_free.rs- Core solver implementationsrc/analysis/gpu/shaders/element_ops.metal- GPU kernelssrc/analysis/gpu/mod.rs- Module exportstests/benchmarks/matrix_free_bench.rs- Test harnessCargo.toml- Test configuration
MATRIX_FREE_GPU_IMPLEMENTATION.md- Architecture and designMATRIX_FREE_DEBUGGING_SUMMARY.md- This file- Inline code documentation (Rustdoc comments)
Immediate (choose one):
- Implement Solution 1 (full-system, recommended)
- Implement Solution 2 (reduced-system, quick fix)
After fixing:
- Remove debug eprintln! statements
- Add comprehensive unit tests
- Run full benchmark suite
- Update README with matrix-free solver info
- Performance profiling and optimization
Date: 2025-10-26 Status: Architectural issue identified, solutions proposed Lines of Code: ~800 (matrix_free.rs + element_ops.metal) Test Coverage: Infrastructure in place, pending bug fix