From e5b80fd1710abbd5a4b3a309835429dfff393566 Mon Sep 17 00:00:00 2001 From: Jukka Aho Date: Sat, 9 May 2026 16:30:31 +0300 Subject: [PATCH] refactor(src): remove csc_cache.jl src/assemblers/csc_cache.jl | 193 -------------------------------------------- 1 file changed, 193 deletions(-) --- src/assemblers/csc_cache.jl | 193 ------------------------------------ 1 file changed, 193 deletions(-) delete mode 100644 src/assemblers/csc_cache.jl diff --git a/src/assemblers/csc_cache.jl b/src/assemblers/csc_cache.jl deleted file mode 100644 index 30aa5d4..0000000 --- a/src/assemblers/csc_cache.jl +++ /dev/null @@ -1,193 +0,0 @@ -# This file is a part of JuliaFEM. -# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md - -""" -CSC (Compressed Sparse Column) cache for element-based assembly. - -CSC format stores sparse matrices with pre-built structure: -- `colptr[j]` = starting index in nzval/rowval for column j -- `rowval[k]` = row index of k-th nonzero -- `nzval[k]` = value of k-th nonzero - -Structure is built once, values are updated in-place during assembly. - -# Performance -- Fast assembly with pre-built structure (direct indexing) -- Fast sparse matrix operations (standard format) -- Minimal memory overhead (no duplicates) - -# Use case -Best for problems with fixed sparsity pattern (most structural FEM problems). -""" - -using SparseArrays - -""" - CSCCache <: AbstractAssemblerCache - -Cache for CSC (compressed sparse column) assembly with pre-built structure. - -Pre-allocates CSC sparse matrix with correct sparsity pattern. During assembly, -element contributions are merged directly into CSC arrays using two-pointer -algorithm. **4.1x faster than COO**, **16.6x less memory**. - -# Fields -- `K::SparseMatrixCSC{Float64,Int}`: Sparse matrix with pre-built structure -- `f::Vector{Float64}`: Global force vector -- `element_cache::ElementCache`: Per-element workspace -- `colptr_cache::Vector{Int}`: Column pointer positions (for in-place merge) - -# Zero-Allocation Usage - -```julia -cache = CSCCache(mesh, kernel) # Builds sparsity pattern (one-time cost) -fill!(cache) # Zero values, keep structure -assemble!(cache, assembler, kernel, mesh) # No allocations, in-place merge -K, f = extract_system(cache) # Just returns references -``` -""" -mutable struct CSCCache <: AbstractAssemblerCache - K::SparseMatrixCSC{Float64,Int} # Pre-built sparse matrix - f::Vector{Float64} # Force vector - element_cache::ElementCache # Element workspace - colptr_cache::Vector{Int} # Working column pointers -end - -""" - CSCCache(mesh::AbstractMesh, kernel::AbstractKernel) -> CSCCache - -Create pre-allocated CSC cache with pre-built sparsity pattern. - -Builds sparse matrix structure by: -1. Collecting all (i,j) pairs from element connectivity -2. Removing duplicates -3. Creating CSC structure with `sparse(I, J, zeros, m, n)` - -Structure is reused across all subsequent assemblies (nonlinear iterations). - -# Arguments -- `mesh`: Finite element mesh -- `kernel`: Domain kernel defining DOF structure - -# Returns -- `CSCCache` with pre-built sparse matrix structure -""" -function CSCCache(mesh::AbstractMesh, kernel::AbstractKernel) - ndofs_per_node = dofs_per_node(kernel) - nnodes_mesh = nnodes_total(mesh) - ndofs = nnodes_mesh * ndofs_per_node - - # Build sparsity pattern from mesh connectivity - K = build_sparsity_pattern(mesh, kernel) - f = zeros(Float64, ndofs) - element_cache = create_element_cache(mesh, kernel) - - # Cache working column pointers (for two-pointer merge) - colptr_cache = copy(K.colptr) - - return CSCCache(K, f, element_cache, colptr_cache) -end - -""" - build_sparsity_pattern(mesh::AbstractMesh, kernel::AbstractKernel) -> SparseMatrixCSC - -Build sparse matrix structure from mesh connectivity. - -Collects all (i,j) DOF pairs from element connectivity, creates CSC structure -with zero values. Structure is reused for all subsequent assemblies. - -# Algorithm -1. Loop over elements -2. For each element, get DOF mapping -3. For all DOF pairs (i,j) in element, record (i,j) -4. Remove duplicates -5. Create `sparse(I, J, zeros, ndofs, ndofs)` - -# Arguments -- `mesh`: Finite element mesh -- `kernel`: Domain kernel defining DOF structure - -# Returns -- Sparse matrix with correct structure, zero values -""" -function build_sparsity_pattern(mesh::AbstractMesh, kernel::AbstractKernel) - ndofs_per_node = dofs_per_node(kernel) - nnodes_mesh = nnodes_total(mesh) - ndofs = nnodes_mesh * ndofs_per_node - nelems = nelements(mesh) - - # Estimate triplet count for pre-allocation - MeshType = typeof(mesh) - nnodes_elem = MeshType.parameters[1]::Int - avg_ndofs_per_elem = Int(ceil(nnodes_elem * ndofs_per_node)) - estimated_triplets = Int(ceil(1.2 * nelems * avg_ndofs_per_elem^2)) - - I = Vector{Int}() - J = Vector{Int}() - sizehint!(I, estimated_triplets) - sizehint!(J, estimated_triplets) - - # Temporary DOF buffer - dof_buffer = zeros(Int, avg_ndofs_per_elem) - - # Collect all (i,j) pairs from connectivity - for elem_id in 1:nelems - # Get element nodes - nodes = mesh.connectivity[elem_id] - nnodes_elem = length(nodes) - ndofs_elem = nnodes_elem * ndofs_per_node - - # Get global DOF indices - resize!(dof_buffer, ndofs_elem) - get_dof_mapping!(dof_buffer, kernel, elem_id, mesh) - - # Record all (i,j) pairs - for i_local in 1:ndofs_elem - i_global = dof_buffer[i_local] - for j_local in 1:ndofs_elem - j_global = dof_buffer[j_local] - push!(I, i_global) - push!(J, j_global) - end - end - end - - # Build CSC structure (sparse automatically removes duplicates) - K = sparse(I, J, zeros(Float64, length(I)), ndofs, ndofs) - - return K -end - -""" - reset!(cache::CSCCache) - -Reset CSC cache for new assembly. - -Zeros out matrix values and force vector, keeps structure. -**Zero allocations** - reuses existing arrays. -""" -function reset!(cache::CSCCache) - fill!(cache.K.nzval, 0.0) # Zero values, keep structure - fill!(cache.f, 0.0) - copy!(cache.colptr_cache, cache.K.colptr) # Reset column pointers - return nothing -end - -""" - extract_system(cache::CSCCache) -> (K, f) - -Extract global system from CSC cache. - -Returns references to pre-built sparse matrix and force vector. -**Zero allocations** - no copying. - -# Arguments -- `cache`: CSC cache after assembly - -# Returns -- `K`: Sparse matrix (reference, no copy) -- `f`: Force vector (reference, no copy) -""" -function extract_system(cache::CSCCache) - return cache.K, cache.f -end