From 6bbda5333877dab4528e428c9319cb1366c70ff4 Mon Sep 17 00:00:00 2001 From: Jukka Aho Date: Thu, 20 Nov 2025 16:56:39 +0200 Subject: [PATCH] feat(assemblers): Add scatter_blocks_to_force! for force vector assembly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New file: src/assemblers/scatter_blocks_to_force.jl (54 lines) Features: - scatter_blocks_to_force!(f_global, f_blocks, dofs, N) - Scatters element force blocks to global force vector - Handles 3 DOFs per node (displacement field) - Uses @inbounds and @inline for performance Implementation: - Double loop over nodes (N × 3 DOFs) - Direct vector indexing f_global[dof] += f_i[component] - Zero allocations, zero dispatch Part of the direct scatter strategy that achieved zero-allocation assembly. Critical for 500K elem/s performance. --- src/assemblers/scatter_blocks_to_force.jl | 54 +++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 src/assemblers/scatter_blocks_to_force.jl diff --git a/src/assemblers/scatter_blocks_to_force.jl b/src/assemblers/scatter_blocks_to_force.jl new file mode 100644 index 0000000..ea00ce5 --- /dev/null +++ b/src/assemblers/scatter_blocks_to_force.jl @@ -0,0 +1,54 @@ +# This file is a part of JuliaFEM. +# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md + +""" + scatter_blocks_to_force!( + f::Vector{Float64}, + f_blocks::AbstractVector{Vec{3,Float64}}, + dofs::AbstractVector{Int}, + N::Int + ) + +Scatter blocked force vector to global force vector **in-place**. + +Accumulates element contributions from blocked structure. + +# Arguments +- `f`: Global force vector (modified in-place) +- `f_blocks`: Element force as [N] vector of Vec{3} blocks +- `dofs`: Global DOF indices [3*N] +- `N`: Number of nodes in element + +# Zero-Allocation Guarantee + +No allocations - modifies `f` in-place. + +# Algorithm + +```julia +for k in 1:N + block = f_blocks[k] + k_offset = 3(k - 1) + for α in 1:3 + i_global = dofs[k_offset + α] + f[i_global] += block[α] + end +end +``` +""" +@inline function scatter_blocks_to_force!( + f::Vector{Float64}, + f_blocks::Vector{Vec{3,Float64}}, + dofs::Vector{Int}, + N::Int +) + @inbounds for k in 1:N + block = f_blocks[k] + k_offset = 3(k - 1) + for α in 1:3 + i_global = dofs[k_offset+α] + f[i_global] += block[α] + end + end + return nothing +end