mirror of
https://github.com/JuliaFEM/JuliaFEM.jl.git
synced 2026-09-19 09:54:55 +00:00
test(domains): add primal Darcy potential kernel tests
This commit is contained in:
@@ -0,0 +1,156 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM
|
||||
using Test
|
||||
|
||||
@testset "HydraulicConductivity validation" begin
|
||||
@test_throws ArgumentError HydraulicConductivity(K = 0.0)
|
||||
@test_throws ArgumentError HydraulicConductivity(K = -1.0)
|
||||
m = HydraulicConductivity(K = 1e-3)
|
||||
@test m.K == 1e-3
|
||||
end
|
||||
|
||||
@testset "HeatKernel invalid material–field pairing" begin
|
||||
form = ContinuumFormulation{FullThreeD}()
|
||||
@test_throws ArgumentError HeatKernel(form, HeatConductivity(k = 1.0), PressurePotential())
|
||||
@test_throws ArgumentError HeatKernel(form, HydraulicConductivity(K = 1.0), Temperature())
|
||||
end
|
||||
|
||||
@testset "Primal Darcy stiffness equals thermal diffusion (same K)" begin
|
||||
mesh = create_unit_cube_mesh(Hex8)
|
||||
κ = 12.7
|
||||
|
||||
S_T = @DOFSet{T::DOF{Temperature, Vertex}}
|
||||
S_p = @DOFSet{p::DOF{PressurePotential, Vertex}}
|
||||
|
||||
k_heat = HeatKernel(ContinuumFormulation{FullThreeD}(), HeatConductivity(k = κ))
|
||||
k_darcy = DarcyPotentialKernel(ContinuumFormulation{FullThreeD}(), HydraulicConductivity(K = κ))
|
||||
|
||||
el_T, h_T = create_elements!(mesh, Element{Hex8, Lagrange{1}, S_T})
|
||||
el_p, h_p = create_elements!(mesh, Element{Hex8, Lagrange{1}, S_p})
|
||||
|
||||
asm = DOFBasedCOOAssembler()
|
||||
cache_T = create_cache(asm, el_T, h_T, mesh, k_heat)
|
||||
cache_p = create_cache(asm, el_p, h_p, mesh, k_darcy)
|
||||
|
||||
assemble!(cache_T, asm, k_heat, mesh)
|
||||
assemble!(cache_p, asm, k_darcy, mesh)
|
||||
|
||||
K_T, _ = extract_system(cache_T)
|
||||
K_p, _ = extract_system(cache_p)
|
||||
|
||||
@test Matrix(K_T) ≈ Matrix(K_p)
|
||||
|
||||
x = rand(Float64, h_T.total_dofs)
|
||||
y_T = similar(x)
|
||||
y_p = similar(x)
|
||||
apply_K!(y_T, cache_T, asm, k_heat, mesh, x)
|
||||
apply_K!(y_p, cache_p, asm, k_darcy, mesh, x)
|
||||
@test y_T ≈ y_p
|
||||
end
|
||||
|
||||
@testset "scalar_diffusion_tensor matches tensors" begin
|
||||
κ = 50.0
|
||||
hc = HeatConductivity(k = κ)
|
||||
hyd = HydraulicConductivity(K = κ)
|
||||
@test scalar_diffusion_tensor(hc) ≈ conductivity_tensor(hc)
|
||||
@test scalar_diffusion_tensor(hyd) ≈ hydraulic_conductivity_tensor(hyd)
|
||||
end
|
||||
|
||||
function _box_nidx(nx::Int, ny::Int, nz::Int)
|
||||
return (i::Int, j::Int, k::Int) -> (k - 1) * (nx + 1) * (ny + 1) + (j - 1) * (nx + 1) + i
|
||||
end
|
||||
|
||||
function _top_face_quads_hex_box(nx::Int, ny::Int, nz::Int)
|
||||
nidx = _box_nidx(nx, ny, nz)
|
||||
faces = NTuple{4, Int}[]
|
||||
k = nz + 1
|
||||
for j in 1:ny, i in 1:nx
|
||||
push!(
|
||||
faces,
|
||||
(nidx(i, j, k), nidx(i + 1, j, k), nidx(i + 1, j + 1, k), nidx(i, j + 1, k)),
|
||||
)
|
||||
end
|
||||
return faces
|
||||
end
|
||||
|
||||
function _scalar_dofs_for_nodes(handler, node_ids)
|
||||
return [handler.field_starts[1][Int(n)] for n in node_ids]
|
||||
end
|
||||
|
||||
@testset "SurfaceLoad Neumann flux + Dirichlet (primal Darcy)" begin
|
||||
nx, ny, nz = 1, 1, 6
|
||||
Kcond = 50.0
|
||||
q_flux = 200.0
|
||||
Lz = 1.0
|
||||
mesh = create_unit_cube_mesh(Hex8; nx = nx, ny = ny, nz = nz)
|
||||
S = @DOFSet{p::DOF{PressurePotential, Vertex}}
|
||||
kernel = DarcyPotentialKernel(ContinuumFormulation{FullThreeD}(), HydraulicConductivity(K = Kcond))
|
||||
elements, handler = create_elements!(mesh, Element{Hex8, Lagrange{1}, S})
|
||||
asm = DOFBasedCOOAssembler()
|
||||
cache = create_cache(asm, elements, handler, mesh, kernel)
|
||||
|
||||
assemble!(cache, asm, kernel, mesh)
|
||||
K, f = extract_system(cache)
|
||||
|
||||
faces = _top_face_quads_hex_box(nx, ny, nz)
|
||||
apply_load!(f, SurfaceLoad(faces, q_flux), cache, asm, kernel, mesh)
|
||||
|
||||
# Bottom face z = 0 (same convention as test/assemblers/test_surface_load.jl heat flux case).
|
||||
zmin_nodes = collect(get_node_set(mesh, :zmin))
|
||||
fixed_dofs = _scalar_dofs_for_nodes(handler, zmin_nodes)
|
||||
bc = PenaltyDirichlet(fixed_dofs, zeros(Float64, length(fixed_dofs)); penalty = 1e10 * Kcond)
|
||||
apply_constraint!(K, bc)
|
||||
apply_constraint!(f, bc)
|
||||
|
||||
u = K \ Vector(f)
|
||||
zmax_nodes = collect(get_node_set(mesh, :zmax))
|
||||
p_top = [u[d] for d in _scalar_dofs_for_nodes(handler, zmax_nodes)]
|
||||
p_top_exact = q_flux * Lz / Kcond
|
||||
rel = maximum(abs.(p_top .- p_top_exact)) / abs(p_top_exact)
|
||||
@test rel < 1e-3
|
||||
end
|
||||
|
||||
@testset "ElementWiseScalarDiffusion (two bricks in x)" begin
|
||||
nx, ny, nz = 2, 1, 1
|
||||
K1, K2 = 1.0, 4.0
|
||||
mesh = create_unit_cube_mesh(Hex8; nx = nx, ny = ny, nz = nz)
|
||||
@test nelements(mesh) == 2
|
||||
|
||||
mat = ElementWiseScalarDiffusion([K1, K2])
|
||||
kernel = DarcyPotentialKernel(ContinuumFormulation{FullThreeD}(), mat)
|
||||
S = @DOFSet{p::DOF{PressurePotential, Vertex}}
|
||||
elements, handler = create_elements!(mesh, Element{Hex8, Lagrange{1}, S})
|
||||
asm = DOFBasedCOOAssembler()
|
||||
cache = create_cache(asm, elements, handler, mesh, kernel)
|
||||
|
||||
assemble!(cache, asm, kernel, mesh)
|
||||
K, f = extract_system(cache)
|
||||
|
||||
nidx = _box_nidx(nx, ny, nz)
|
||||
dofs_lo = _scalar_dofs_for_nodes(handler, collect(get_node_set(mesh, :xmin)))
|
||||
dofs_hi = _scalar_dofs_for_nodes(handler, collect(get_node_set(mesh, :xmax)))
|
||||
dof_all = [dofs_lo; dofs_hi]
|
||||
vals = [zeros(Float64, length(dofs_lo)); ones(Float64, length(dofs_hi))]
|
||||
bc = PenaltyDirichlet(dof_all, vals; penalty = 1e10 * max(K1, K2))
|
||||
apply_constraint!(K, bc)
|
||||
apply_constraint!(f, bc)
|
||||
|
||||
u = K \ Vector(f)
|
||||
q = 1.0 / (0.5 / K1 + 0.5 / K2)
|
||||
p_mid_exact = q * 0.5 / K1
|
||||
mid_node = nidx(2, 1, 1)
|
||||
p_mid = u[handler.field_starts[1][mid_node]]
|
||||
@test abs(p_mid - p_mid_exact) / p_mid_exact < 5e-3
|
||||
end
|
||||
|
||||
@testset "ElementWiseScalarDiffusion length must match nelements" begin
|
||||
mesh = create_unit_cube_mesh(Hex8; nx = 2, ny = 1, nz = 1)
|
||||
bad = ElementWiseScalarDiffusion([1.0, 2.0, 99.0])
|
||||
kernel = HeatKernel(ContinuumFormulation{FullThreeD}(), bad, PressurePotential())
|
||||
S = @DOFSet{p::DOF{PressurePotential, Vertex}}
|
||||
elements, handler = create_elements!(mesh, Element{Hex8, Lagrange{1}, S})
|
||||
asm = DOFBasedCOOAssembler()
|
||||
@test_throws ArgumentError create_cache(asm, elements, handler, mesh, kernel)
|
||||
end
|
||||
Reference in New Issue
Block a user