Files
JuliaFEM.jl/test/reference/test_analytical_heat.jl

78 lines
2.6 KiB
Julia

# SPDX-FileCopyrightText: 2015-2026 Jukka Aho
# SPDX-License-Identifier: MIT
"""
Steady heat conduction on a `Hex8` box with Dirichlet temperatures on two opposing faces
and natural (insulating) conditions elsewhere.
Exact solution (piecewise-linear in z): `T(z) = T1 * (z - z_min) / (z_max - z_min)`, which
satisfies Laplace's equation and the boundary data. Diffusion analogues appear alongside
mechanical cases in Code_Aster validation manual V (table of contents:
https://biba1632.gitlab.io/code-aster-manuals/docs/validation/v_toc.html).
"""
using Test
using LinearAlgebra
using JuliaFEM
using JuliaFEM: ContinuumFormulation, FullThreeD, Temperature, Vertex
using JuliaFEM: @DOFSet, DOF, HeatConductivity, HeatKernel
using JuliaFEM: DOFBasedCOOAssembler, DOFBasedCOOCache, assemble!, extract_system
using JuliaFEM: EliminatedDirichlet, apply_constraint!
using JuliaFEM: create_elements!, create_structured_box_mesh, Element, Lagrange, Hex8
using JuliaFEM: get_nodes_in_set, get_node_dofs
@testset "Reference heat: linear profile T(z) between zmin and zmax" begin
zmin_v = 0.1
zmax_v = 0.65
T1 = 57.0
kcond = 45.0
nx = 4
ny = 5
nz = 12
mesh = create_structured_box_mesh(Hex8;
xmin = 0.0, xmax = 2.3, nx = nx,
ymin = 0.0, ymax = 1.7, ny = ny,
zmin = zmin_v, zmax = zmax_v, nz = nz,
)
S = @DOFSet{T::DOF{Temperature, Vertex}}
elements, handler = create_elements!(mesh, Element{Hex8, Lagrange{1}, S})
kernel = HeatKernel(ContinuumFormulation{FullThreeD}(), HeatConductivity(k = kcond))
asm = DOFBasedCOOAssembler()
cache = DOFBasedCOOCache(elements, handler, mesh, kernel)
assemble!(cache, asm, kernel, mesh)
K, f = extract_system(cache)
fill!(f, 0.0)
n_zmin = sort!(collect(get_nodes_in_set(mesh, :zmin)))
n_zmax = sort!(collect(get_nodes_in_set(mesh, :zmax)))
dof_fix = Int[]
val_fix = Float64[]
for nid in n_zmin
push!(dof_fix, Int(only(get_node_dofs(handler, Int(nid)))))
push!(val_fix, 0.0)
end
for nid in n_zmax
push!(dof_fix, Int(only(get_node_dofs(handler, Int(nid)))))
push!(val_fix, T1)
end
bc = EliminatedDirichlet(dof_fix, val_fix)
Kc = copy(K)
apply_constraint!(Kc, f, bc)
Tvec = Kc \ f
@test all(isfinite, Tvec)
ru = norm(Kc * Tvec - f) / max(norm(f), 1.0)
@test ru < 1.0e-10
denom = zmax_v - zmin_v
err_max = 0.0
for k in 1:length(mesh.nodes)
z = mesh.nodes[k][3]
d = Int(only(get_node_dofs(handler, k)))
Tex = T1 * (z - zmin_v) / denom
err_max = max(err_max, abs(Tvec[d] - Tex))
end
@test err_max < 1.0e-9 * max(abs(T1), 1.0)
end