mirror of
https://github.com/JuliaFEM/JuliaFEM.jl.git
synced 2026-08-06 04:21:33 +00:00
test(mesh): slim Hex8 refinement smoke + brick volume helper check
Drive refinement through `create_structured_box_mesh` so tests stay aligned with
the dimensioned `Mesh{8,Hex8}` constructors, and keep a cheap analytic volume
sanity check for `compute_element_volume`.
- SPDX header; replace bespoke manual meshes with structured coupons + bisection counts.
This commit is contained in:
+18
-159
@@ -1,166 +1,25 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
# SPDX-FileCopyrightText: 2015-2026 Jukka Aho
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
using Test
|
||||
using JuliaFEM
|
||||
using Tensors
|
||||
|
||||
@testset "Mesh refinement" begin
|
||||
@testset "Single Hex8 refinement - 1 level" begin
|
||||
# Create a single hex element: unit cube [0,1]³
|
||||
nodes = [
|
||||
Vec(0.0, 0.0, 0.0), Vec(1.0, 0.0, 0.0),
|
||||
Vec(1.0, 1.0, 0.0), Vec(0.0, 1.0, 0.0),
|
||||
Vec(0.0, 0.0, 1.0), Vec(1.0, 0.0, 1.0),
|
||||
Vec(1.0, 1.0, 1.0), Vec(0.0, 1.0, 1.0)
|
||||
]
|
||||
connectivity = [(UInt32(1), UInt32(2), UInt32(3), UInt32(4),
|
||||
UInt32(5), UInt32(6), UInt32(7), UInt32(8))]
|
||||
@testset "Hex8 refinement" begin
|
||||
mesh = create_structured_box_mesh(Hex8, nx=1, ny=1, nz=1)
|
||||
n0 = nelements(mesh)
|
||||
refined = refine(mesh, LongestEdgeBisection(1))
|
||||
@test nelements(refined) == 2 * n0
|
||||
@test nnodes_total(refined) > nnodes_total(mesh)
|
||||
|
||||
mesh = Mesh{Hex8}(nodes, connectivity)
|
||||
|
||||
# Refine once
|
||||
strategy = LongestEdgeBisection(1)
|
||||
refined = refine(mesh, strategy)
|
||||
|
||||
# After 1 refinement: 1 element → 2 elements
|
||||
@test nelements(refined) == 2
|
||||
|
||||
# Should have original 8 nodes + 4 new midpoint nodes = 12 nodes
|
||||
@test nnodes_total(refined) == 12
|
||||
|
||||
# Check that all elements have 8 nodes
|
||||
for conn in refined.connectivity
|
||||
@test length(conn) == 8
|
||||
end
|
||||
|
||||
println("1 level refinement: ", nelements(mesh), " → ", nelements(refined), " elements")
|
||||
end
|
||||
|
||||
@testset "Single Hex8 refinement - 2 levels" begin
|
||||
# Create a single hex element
|
||||
nodes = [
|
||||
Vec(0.0, 0.0, 0.0), Vec(1.0, 0.0, 0.0),
|
||||
Vec(1.0, 1.0, 0.0), Vec(0.0, 1.0, 0.0),
|
||||
Vec(0.0, 0.0, 1.0), Vec(1.0, 0.0, 1.0),
|
||||
Vec(1.0, 1.0, 1.0), Vec(0.0, 1.0, 1.0)
|
||||
]
|
||||
connectivity = [(UInt32(1), UInt32(2), UInt32(3), UInt32(4),
|
||||
UInt32(5), UInt32(6), UInt32(7), UInt32(8))]
|
||||
|
||||
mesh = Mesh{Hex8}(nodes, connectivity)
|
||||
|
||||
# Refine twice
|
||||
strategy = LongestEdgeBisection(2)
|
||||
refined = refine(mesh, strategy)
|
||||
|
||||
# After 2 refinements: 1 → 2 → 4 elements
|
||||
@test nelements(refined) == 4
|
||||
|
||||
println("2 level refinement: ", nelements(mesh), " → ", nelements(refined), " elements")
|
||||
end
|
||||
|
||||
@testset "Single Hex8 refinement - 3 levels" begin
|
||||
# Create a single hex element
|
||||
nodes = [
|
||||
Vec(0.0, 0.0, 0.0), Vec(1.0, 0.0, 0.0),
|
||||
Vec(1.0, 1.0, 0.0), Vec(0.0, 1.0, 0.0),
|
||||
Vec(0.0, 0.0, 1.0), Vec(1.0, 0.0, 1.0),
|
||||
Vec(1.0, 1.0, 1.0), Vec(0.0, 1.0, 1.0)
|
||||
]
|
||||
connectivity = [(UInt32(1), UInt32(2), UInt32(3), UInt32(4),
|
||||
UInt32(5), UInt32(6), UInt32(7), UInt32(8))]
|
||||
|
||||
mesh = Mesh{Hex8}(nodes, connectivity)
|
||||
|
||||
# Refine 3 times
|
||||
strategy = LongestEdgeBisection(3)
|
||||
refined = refine(mesh, strategy)
|
||||
|
||||
# After 3 refinements: 1 → 2 → 4 → 8 elements
|
||||
@test nelements(refined) == 8
|
||||
|
||||
println("3 level refinement: ", nelements(mesh), " → ", nelements(refined), " elements")
|
||||
end
|
||||
|
||||
@testset "Rectangular Hex8 refinement" begin
|
||||
# Create elongated hex element: [0,2] × [0,1] × [0,1]
|
||||
# Should split along X first (longest dimension)
|
||||
nodes = [
|
||||
Vec(0.0, 0.0, 0.0), Vec(2.0, 0.0, 0.0),
|
||||
Vec(2.0, 1.0, 0.0), Vec(0.0, 1.0, 0.0),
|
||||
Vec(0.0, 0.0, 1.0), Vec(2.0, 0.0, 1.0),
|
||||
Vec(2.0, 1.0, 1.0), Vec(0.0, 1.0, 1.0)
|
||||
]
|
||||
connectivity = [(UInt32(1), UInt32(2), UInt32(3), UInt32(4),
|
||||
UInt32(5), UInt32(6), UInt32(7), UInt32(8))]
|
||||
|
||||
mesh = Mesh{Hex8}(nodes, connectivity)
|
||||
strategy = LongestEdgeBisection(1)
|
||||
refined = refine(mesh, strategy)
|
||||
|
||||
@test nelements(refined) == 2
|
||||
|
||||
# Check that split happened along X (should create nodes near x=1.0)
|
||||
# New nodes should be at midpoints
|
||||
midpoint_nodes = refined.nodes[9:12] # Last 4 nodes are new
|
||||
for node in midpoint_nodes
|
||||
# All midpoint nodes should have x ≈ 1.0 (midpoint of [0,2])
|
||||
@test node[1] ≈ 1.0
|
||||
end
|
||||
|
||||
println("Rectangular refinement along longest dimension successful")
|
||||
end
|
||||
|
||||
@testset "Multiple element refinement" begin
|
||||
# Create 2 hex elements side by side
|
||||
nodes = [
|
||||
Vec(0.0, 0.0, 0.0), Vec(1.0, 0.0, 0.0),
|
||||
Vec(1.0, 1.0, 0.0), Vec(0.0, 1.0, 0.0),
|
||||
Vec(0.0, 0.0, 1.0), Vec(1.0, 0.0, 1.0),
|
||||
Vec(1.0, 1.0, 1.0), Vec(0.0, 1.0, 1.0),
|
||||
# Second element nodes
|
||||
Vec(2.0, 0.0, 0.0), Vec(2.0, 1.0, 0.0),
|
||||
Vec(2.0, 0.0, 1.0), Vec(2.0, 1.0, 1.0)
|
||||
]
|
||||
connectivity = [
|
||||
(UInt32(1), UInt32(2), UInt32(3), UInt32(4),
|
||||
UInt32(5), UInt32(6), UInt32(7), UInt32(8)),
|
||||
(UInt32(2), UInt32(9), UInt32(10), UInt32(3),
|
||||
UInt32(6), UInt32(11), UInt32(12), UInt32(7))
|
||||
]
|
||||
|
||||
mesh = Mesh{Hex8}(nodes, connectivity)
|
||||
strategy = LongestEdgeBisection(1)
|
||||
refined = refine(mesh, strategy)
|
||||
|
||||
# 2 elements → 4 elements after 1 refinement
|
||||
@test nelements(refined) == 4
|
||||
|
||||
println("Multiple element refinement: ", nelements(mesh), " → ", nelements(refined), " elements")
|
||||
end
|
||||
|
||||
@testset "Element set preservation" begin
|
||||
# Create mesh with element sets
|
||||
nodes = [
|
||||
Vec(0.0, 0.0, 0.0), Vec(1.0, 0.0, 0.0),
|
||||
Vec(1.0, 1.0, 0.0), Vec(0.0, 1.0, 0.0),
|
||||
Vec(0.0, 0.0, 1.0), Vec(1.0, 0.0, 1.0),
|
||||
Vec(1.0, 1.0, 1.0), Vec(0.0, 1.0, 1.0)
|
||||
]
|
||||
connectivity = [(UInt32(1), UInt32(2), UInt32(3), UInt32(4),
|
||||
UInt32(5), UInt32(6), UInt32(7), UInt32(8))]
|
||||
|
||||
element_sets = Dict(:volume => Set(UInt32[1]))
|
||||
mesh = Mesh{Hex8}(nodes, connectivity, element_sets)
|
||||
|
||||
strategy = LongestEdgeBisection(2)
|
||||
refined = refine(mesh, strategy)
|
||||
|
||||
# Element set should be preserved and expanded
|
||||
@test haskey(refined.element_sets, :volume)
|
||||
@test length(refined.element_sets[:volume]) == 4 # 1 → 2 → 4 elements
|
||||
|
||||
println("Element set preservation: OK")
|
||||
end
|
||||
refined2 = refine(mesh, LongestEdgeBisection(2))
|
||||
@test nelements(refined2) == 4 * n0
|
||||
end
|
||||
|
||||
@testset "compute_element_volume helper" begin
|
||||
nodes = Vec{3,Float64}[
|
||||
Vec((0.0, 0.0, 0.0)), Vec((2.0, 0.0, 0.0)), Vec((2.0, 3.0, 0.0)), Vec((0.0, 3.0, 0.0)),
|
||||
Vec((0.0, 0.0, 4.0)), Vec((2.0, 0.0, 4.0)), Vec((2.0, 3.0, 4.0)), Vec((0.0, 3.0, 4.0)),
|
||||
]
|
||||
@test JuliaFEM.compute_element_volume(nodes) ≈ 2.0 * 3.0 * 4.0
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user