Files
JuliaFEM.jl/test/assemblers/test_partitioning_helpers.jl
T

130 lines
4.9 KiB
Julia
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# This file is a part of JuliaFEM.
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
"""
Pure partitioning helpers (`brick_hex_partition_slabs`, `referenced_global_dofs`,
`element_counts_by_part`) — correctness vs structured Hex8 ordering and DOF overlap
at slab interfaces.
"""
using Test
using JuliaFEM
using JuliaFEM: DOFBasedCOOAssembler, DOFBasedCOOCache
using JuliaFEM: apply_K!, apply_K_contributions!
using JuliaFEM: create_elements!, @DOFSet, DOF, Displacement, Vertex
using JuliaFEM: element_indices_for_part, validate_partition
using JuliaFEM: brick_hex_slab_upper, brick_hex_partition_slabs
using JuliaFEM: element_counts_by_part, referenced_global_dofs
using JuliaFEM: sum_element_dof_slots, mark_referenced_dofs!, collect_true_indices!
using JuliaFEM: fill_referenced_dof_indices!, ghost_dof_mask!, node_partition_owner_min!
using JuliaFEM: mark_owned_vertex_field_dofs!
using Random
using Tensors
@testset "brick_hex_partition_slabs rejects nparts > ncells on axis" begin
@test_throws ArgumentError brick_hex_partition_slabs(1, 1, 1, 4; axis = :x)
@test_throws ArgumentError brick_hex_partition_slabs(3, 2, 2, 4; axis = :y)
end
@testset "brick_hex_slab_upper widths" begin
@test brick_hex_slab_upper(5, 3) == [2, 4, 5]
@test brick_hex_slab_upper(6, 3) == [2, 4, 6]
@test brick_hex_slab_upper(1, 4) == [1, 1, 1, 1]
end
@testset "brick_hex_partition_slabs counts + ids" begin
nx, ny, nz = 4, 2, 2
ne = nx * ny * nz
layout = brick_hex_partition_slabs(nx, ny, nz, 3; axis = :x)
validate_partition(layout, ne)
d = element_counts_by_part(layout)
@test sort!(collect(keys(d))) == [1, 2, 3]
@test sum(values(d)) == ne
# x-slab: part widths along i ≈ 2+1+1 on nx=4
@test d[1] == 2 * ny * nz
@test d[2] == d[3] == 1 * ny * nz
end
@testset "referenced_global_dofs overlap at x-slabs" begin
nx, ny, nz = 4, 2, 2
mesh = create_structured_box_mesh(Hex8; nx = nx, ny = ny, nz = nz)
S = @DOFSet{u::DOF{Displacement{3}, Vertex}}
elements, _handler = create_elements!(mesh, Element{Hex8, Lagrange{1}, S})
layout = brick_hex_partition_slabs(nx, ny, nz, 2; axis = :x)
e1 = element_indices_for_part(layout, 1)
e2 = element_indices_for_part(layout, 2)
@assert isempty(intersect(e1, e2))
d1 = referenced_global_dofs(elements, e1)
d2 = referenced_global_dofs(elements, e2)
overlap = intersect(Set(d1), Set(d2))
@test !isempty(overlap)
end
@testset "slab-partitioned contributions sum to apply_K!" begin
Random.seed!(20260510)
nx, ny, nz = 3, 4, 2
mesh = create_structured_box_mesh(Hex8; nx = nx, ny = ny, nz = nz)
material = LinearElastic(E = 210e9, ν = 0.3)
kernel = ContinuumKernel(ContinuumFormulation{FullThreeD}(),
material, Displacement{3}())
S = @DOFSet{u::DOF{Displacement{3}, Vertex}}
elements, dof_mgr = create_elements!(mesh, Element{Hex8, Lagrange{1}, S})
asm = DOFBasedCOOAssembler()
cache = DOFBasedCOOCache(elements, dof_mgr, mesh, kernel)
layout = brick_hex_partition_slabs(nx, ny, nz, 3; axis = :y) # ny ≥ nparts
validate_partition(layout, length(elements))
n = cache.ndofs
x = randn(n)
y_full = zeros(n)
apply_K!(y_full, cache, asm, kernel, mesh, x)
y_sum = zeros(n)
for part in 1:3
ep = element_indices_for_part(layout, part)
apply_K_contributions!(y_sum, cache, asm, kernel, mesh, x, ep)
end
@test y_sum y_full rtol = 1e-11 atol = 1e-11
end
@testset "fill_referenced_dof_indices! agrees with referenced_global_dofs" begin
nx, ny, nz = 3, 2, 2
mesh = create_structured_box_mesh(Hex8; nx = nx, ny = ny, nz = nz)
S = @DOFSet{u::DOF{Displacement{3}, Vertex}}
elements, handler = create_elements!(mesh, Element{Hex8, Lagrange{1}, S})
layout = brick_hex_partition_slabs(nx, ny, nz, 2; axis = :x)
ep = element_indices_for_part(layout, 1)
ndof = handler.total_dofs
ref_alloc = referenced_global_dofs(elements, ep)
mask = falses(ndof)
buf = Vector{Int}(undef, ndof)
n = fill_referenced_dof_indices!(buf, mask, elements, ep, ndof)
@test sort(buf[1:n]) == ref_alloc
end
@testset "ghost mask nonempty for higher partition (min-node ownership)" begin
nx, ny, nz = 4, 2, 2
mesh = create_structured_box_mesh(Hex8; nx = nx, ny = ny, nz = nz)
S = @DOFSet{u::DOF{Displacement{3}, Vertex}}
elements, handler = create_elements!(mesh, Element{Hex8, Lagrange{1}, S})
layout = brick_hex_partition_slabs(nx, ny, nz, 2; axis = :x)
ndof = handler.total_dofs
nnodes = length(mesh.nodes)
node_own = Vector{Int}(undef, nnodes)
node_partition_owner_min!(node_own, layout, mesh)
ep2 = element_indices_for_part(layout, 2)
refm = falses(ndof)
ownm = falses(ndof)
gh = falses(ndof)
mark_referenced_dofs!(refm, elements, ep2, ndof)
mark_owned_vertex_field_dofs!(ownm, handler, node_own, 2)
ghost_dof_mask!(gh, refm, ownm)
@test any(gh)
end