Skip to content

Add matrix-free mode to SparseMatrixAssembler; drop dead H/D buffers#295

Open
lxmota wants to merge 1 commit intomainfrom
lazy-matrix-storage
Open

Add matrix-free mode to SparseMatrixAssembler; drop dead H/D buffers#295
lxmota wants to merge 1 commit intomainfrom
lazy-matrix-storage

Conversation

@lxmota
Copy link
Copy Markdown
Contributor

@lxmota lxmota commented Apr 28, 2026

Summary

  • Drop damping_storage and hessian_storage from SparseMatrixAssembler — both were preallocated but never written. hessian(asm) now aliases stiffness(asm).
  • Add matrix_free::Bool=false to SparseMatrixAssembler(dof; ...). When true, the sparse pattern is empty and the mass/stiffness value buffers are zero-length. assemble_matrix!/assemble_mass!/assemble_stiffness! error with a clear message; mass(asm)/stiffness(asm) return a zero sparse matrix of the right shape.
  • update_dofs! skips the matrix-pattern rebuild on matrix-free assemblers; without the guard _update_dofs! would silently flip the assembler back into matrix-bearing mode.

Why

For a downstream solver (Carina.jl) running an explicit central-difference integrator on a 530 k-DOF mesh, profiling showed the assembler preallocating ~7.4 GB it never touches:

Field Size Used by central-difference?
matrix_pattern 4226 MiB No
damping_storage 703 MiB No (no writer anywhere)
hessian_storage 703 MiB No (no writer anywhere)
mass_storage 703 MiB No
stiffness_storage 703 MiB No
vector_pattern 87 MiB No
residual_storage 4 MiB Yes

After this change a matrix-free assembler costs ~few MB instead. Implicit/Newton paths keep the existing eager allocation by default and recover ~1.4 GB from the dropped damping/hessian fields.

GPU compatibility

Default matrix_free=false is bit-for-bit unchanged — every existing GPU path stays on that default and was not touched. The matrix-free branch only allocates empty CPU vectors at construction and survives Adapt.adapt_structure cleanly (empty CuArray/ROCArray after adapt).

API change

hessian(asm) previously returned a sparse matrix backed by an independent hessian_storage. After this PR it returns whatever stiffness(asm) returns. No code in this repository writes a separate Hessian; if a future caller needs H ≠ K, add the field back and specialize the accessor.

The default path is unchanged.  Two changes reduce memory:

1. Drop `damping_storage` and `hessian_storage` from the struct.  No code
   in this repository wrote either; both sat preallocated as ~700 MB
   each on a 530 k-DOF mesh.  `hessian(asm)` now aliases `stiffness(asm)`;
   if a future caller needs `H ≠ K`, add the field back and specialize.

2. Add `matrix_free::Bool=false` to `SparseMatrixAssembler(dof; ...)`.
   When true, the sparse pattern is constructed empty and the mass /
   stiffness value buffers are zero-length, saving the full ~7 GB of
   matrix-side preallocation that an integrator like central difference
   never touches.  `assemble_matrix!`/`assemble_mass!`/`assemble_stiffness!`
   error with a clear message on a matrix-free assembler;
   `mass(asm)`/`stiffness(asm)` return a zero sparse matrix of the
   correct shape.  GPU paths use the default `matrix_free=false` and are
   bit-for-bit unchanged.

`update_dofs!` now skips the matrix-pattern rebuild on matrix-free
assemblers; without the guard, `_update_dofs!` would silently reconstruct
the pattern from scratch, flipping the assembler back into the
matrix-bearing mode.

All 18065 FEC tests pass.
@lxmota lxmota requested a review from cmhamel April 28, 2026 22:54
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 28, 2026

Codecov Report

❌ Patch coverage is 48.14815% with 14 lines in your changes missing coverage. Please review.
✅ Project coverage is 66.63%. Comparing base (0ca244a) to head (1e1b796).
⚠️ Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
src/assemblers/Assemblers.jl 20.00% 8 Missing ⚠️
src/assemblers/SparseMatrixAssembler.jl 58.33% 5 Missing ⚠️
src/assemblers/Matrix.jl 80.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #295      +/-   ##
==========================================
- Coverage   66.77%   66.63%   -0.14%     
==========================================
  Files          55       55              
  Lines        4758     4888     +130     
==========================================
+ Hits         3177     3257      +80     
- Misses       1581     1631      +50     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant