diff --git a/test/mesh/test_refine.jl b/test/mesh/test_refine.jl index 32dad48..5735f96 100644 --- a/test/mesh/test_refine.jl +++ b/test/mesh/test_refine.jl @@ -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