mirror of
https://github.com/JuliaFEM/JuliaFEM.jl.git
synced 2026-10-03 06:41:30 +00:00
rewrite assembly, see #69. a lot of tests probably fail but the most important ones pass
This commit is contained in:
@@ -1,37 +1,42 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
module GlobalAssemblyTests
|
||||
module AssemblyTests
|
||||
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM: Quad4, Seg2, FieldSet, Field, PlaneHeatProblem
|
||||
using JuliaFEM: initialize_global_assembly, calculate_global_assembly!
|
||||
using JuliaFEM: Assembly, assemble!
|
||||
|
||||
"""assemble a simple two element problem and solve"""
|
||||
function test_asssembly()
|
||||
function test_assembly()
|
||||
info("create elements")
|
||||
el1 = Quad4([1, 2, 3, 4])
|
||||
el1["geometry"] = Vector[[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0]]
|
||||
el1["temperature thermal conductivity"] = 6.0
|
||||
el1["temperature load"] = [12.0, 12.0, 12.0, 12.0]
|
||||
el1["density"] = 10
|
||||
|
||||
el1["temperature load"] = 12.0
|
||||
el1["density"] = 36.0
|
||||
el2 = Seg2([1, 2])
|
||||
el2["geometry"] = Vector[[0.0, 0.0], [1.0, 0.0]]
|
||||
|
||||
# Boundary load, linear ramp 0 -> 600 at time 0 -> 1
|
||||
el2["temperature flux"] = FieldSet(Field[Field(0.0, 0.0), Field(1.0, 600.0)])
|
||||
el2["temperature flux"] = ((0.0 => 0.0), (1.0 => 600.0))
|
||||
info("element created")
|
||||
|
||||
problem = PlaneHeatProblem()
|
||||
info("problem created. pushing elements")
|
||||
push!(problem, el1)
|
||||
push!(problem, el2)
|
||||
|
||||
global_assembly = initialize_global_assembly(problem)
|
||||
calculate_global_assembly!(global_assembly, problem)
|
||||
info("creating assembly from equations")
|
||||
assembly = Assembly()
|
||||
assemble!(assembly, problem, 1.0)
|
||||
info("solving")
|
||||
|
||||
free_dofs = [1, 2]
|
||||
A = lufact(global_assembly.stiffness_matrix[free_dofs, free_dofs])
|
||||
b = full(global_assembly.force_vector)[free_dofs]
|
||||
A = full(assembly.stiffness_matrix)[free_dofs, free_dofs]
|
||||
b = full(assembly.force_vector)[free_dofs]
|
||||
u = A \ b
|
||||
@test isapprox(u, roughly([101.0, 101.0]))
|
||||
info("solution u=$u")
|
||||
@test isapprox(u, [101.0, 101.0])
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
+23
-14
@@ -6,13 +6,8 @@
|
||||
module HeatTests # always wrap tests to module ending with "Tests"
|
||||
|
||||
using JuliaFEM.Test # always use JuliaFEM.Test, not Base.Test
|
||||
using JuliaFEM: Seg2, Quad4, DC2D4, DC2D2, Assembly, assemble!
|
||||
|
||||
using JuliaFEM: Seg2, Quad4, Field, FieldSet, DC2D4,
|
||||
initialize_local_assembly, calculate_local_assembly!,
|
||||
DC2D2
|
||||
|
||||
|
||||
"tests on [0x1]x[0x1] domain"
|
||||
function test_one_element() # always start test function with name test_
|
||||
|
||||
# volume element
|
||||
@@ -31,20 +26,34 @@ function test_one_element() # always start test function with name test_
|
||||
# Set constant source f=12 with k=6. Accurate solution is
|
||||
# T=1 on free boundary, u(x,y) = -1/6*(1/2*f*x^2 - f*x)
|
||||
equation = DC2D4(element)
|
||||
la = initialize_local_assembly()
|
||||
calculate_local_assembly!(la, equation, "temperature")
|
||||
#la = initialize_local_assembly()
|
||||
#calculate_local_assembly!(la, equation, "temperature")
|
||||
assembly = Assembly()
|
||||
assemble!(assembly, equation)
|
||||
fdofs = [1, 2]
|
||||
A = la.stiffness_matrix
|
||||
b = la.force_vector
|
||||
A = full(assembly.stiffness_matrix)
|
||||
b = full(assembly.force_vector)
|
||||
@test isapprox(A[fdofs, fdofs] \ b[fdofs], [1.0, 1.0])
|
||||
|
||||
# Set constant flux g=6 on boundary. Accurate solution is
|
||||
# u(x,y) = x which equals T=1 on boundary.
|
||||
boundary_equation = DC2D2(boundary_element);
|
||||
boundary_equation = DC2D2(boundary_element)
|
||||
empty!(assembly)
|
||||
|
||||
calculate_local_assembly!(la, boundary_equation, "temperature")
|
||||
b = la.force_vector
|
||||
@test isapprox(A[fdofs, fdofs] \ b[fdofs], [1.0, 1.0]) # always use @test to test things.
|
||||
time = 1.0
|
||||
assemble!(assembly, equation, time)
|
||||
info("after first element: $(length(assembly.force_vector.V))")
|
||||
info(full(assembly.force_vector)')
|
||||
assemble!(assembly, boundary_equation, time)
|
||||
info("after second element: $(length(assembly.force_vector.V))")
|
||||
info(full(assembly.force_vector)')
|
||||
#calculate_local_assembly!(la, boundary_equation, "temperature")
|
||||
#b = la.force_vector
|
||||
A = full(assembly.stiffness_matrix)
|
||||
b = full(assembly.force_vector)
|
||||
T = A[fdofs, fdofs] \ b[fdofs]
|
||||
info("T = $T")
|
||||
@test isapprox(T, [2.0, 2.0]) # always use @test to test things.
|
||||
|
||||
end
|
||||
|
||||
|
||||
@@ -6,25 +6,27 @@ module ElementTests
|
||||
using JuliaFEM.Test
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM: Equation, Quad4, IntegrationPoint, initialize_local_assembly,
|
||||
get_element, get_basis, grad, calculate_local_assembly!,
|
||||
PlaneHeatProblem, Seg2, HeatEquation, Problem, solve!
|
||||
using JuliaFEM: Equation, Quad4, IntegrationPoint, Assembly, assemble!,
|
||||
get_element, get_basis, grad, get_unknown_field_name,
|
||||
PlaneHeatProblem, Seg2, Problem, solve!,
|
||||
get_default_integration_points, Equation
|
||||
|
||||
abstract MyEquation <: Equation
|
||||
|
||||
""" Diffusive heat transfer for 4-node bilinear element, with a nonlinear source term. """
|
||||
type DC2D4NL <: Equation
|
||||
element :: Quad4
|
||||
integration_points :: Array{IntegrationPoint, 1}
|
||||
function JuliaFEM.get_unknown_field_name(equation::MyEquation)
|
||||
return "temperature"
|
||||
end
|
||||
|
||||
function DC2D4NL(element::Quad4, initial_temperature=zeros(4))
|
||||
integration_points = [
|
||||
IntegrationPoint(1.0/sqrt(3.0)*[-1, -1], 1.0),
|
||||
IntegrationPoint(1.0/sqrt(3.0)*[ 1, -1], 1.0),
|
||||
IntegrationPoint(1.0/sqrt(3.0)*[ 1, 1], 1.0),
|
||||
IntegrationPoint(1.0/sqrt(3.0)*[-1, 1], 1.0)]
|
||||
""" Diffusive heat transfer for 4-node bilinear element, with a nonlinear source term. """
|
||||
type DC2D4NL <: MyEquation
|
||||
element :: Quad4
|
||||
integration_points :: Vector{IntegrationPoint}
|
||||
end
|
||||
|
||||
function DC2D4NL(element::Quad4)
|
||||
integration_points = get_default_integration_points(element)
|
||||
if !haskey(element, "temperature")
|
||||
element["temperature"] = initial_temperature
|
||||
element["temperature"] = zeros(4)
|
||||
end
|
||||
DC2D4NL(element, integration_points)
|
||||
end
|
||||
@@ -34,17 +36,15 @@ function Base.size(equation::DC2D4NL)
|
||||
end
|
||||
|
||||
""" Nonlinear flux term. """
|
||||
type DC2D2NL <: Equation
|
||||
type DC2D2NL <: MyEquation
|
||||
element :: Seg2
|
||||
integration_points :: Array{IntegrationPoint, 1}
|
||||
integration_points :: Vector{IntegrationPoint}
|
||||
end
|
||||
|
||||
function DC2D2NL(element::Seg2, initial_temperature=zeros(2))
|
||||
#integration_points = [
|
||||
# IntegrationPoint([0.0], 2.0)]
|
||||
function DC2D2NL(element::Seg2)
|
||||
integration_points = JuliaFEM.line5()
|
||||
if !haskey(element, "temperature")
|
||||
element["temperature"] = initial_temperature
|
||||
element["temperature"] = zeros(2)
|
||||
end
|
||||
DC2D2NL(element, integration_points)
|
||||
end
|
||||
@@ -63,34 +63,23 @@ function JuliaFEM.get_potential_energy(equation::DC2D4NL, ip, time; variation=no
|
||||
c = basis("temperature nonlinearity coefficient", ip, time)
|
||||
gradT = grad(basis)("temperature", ip, time, variation)
|
||||
Wint = (k + c*T) * 1/2*vecdot(gradT, gradT)
|
||||
#Wint = k*1/2*vecdot(gradT, gradT)
|
||||
Wext = f*T
|
||||
#Wext = 0.0
|
||||
return Wint - Wext
|
||||
end
|
||||
|
||||
function JuliaFEM.has_potential_energy(eq::DC2D4NL)
|
||||
return true
|
||||
end
|
||||
|
||||
function JuliaFEM.get_potential_energy(equation::DC2D2NL, ip, time; variation=nothing)
|
||||
element = get_element(equation)
|
||||
basis = get_basis(element)
|
||||
T = basis("temperature", ip, time, variation)[1]
|
||||
Wint = 0.0
|
||||
sig = 5.7e-8
|
||||
eps = basis("emissivity", ip, time)[1]
|
||||
T_ext = basis("temperature external", ip, time)[1]
|
||||
q0 = eps*sig*((T_ext+273.15)^4 - (T+273.15)^4)
|
||||
coeff = basis("temperature coefficient", ip, time)[1]
|
||||
q0 = coeff*(T_ext^4 - T^4)
|
||||
Wint = 0.0
|
||||
Wext = q0*T
|
||||
W = Wint - Wext
|
||||
return W
|
||||
end
|
||||
|
||||
function JuliaFEM.has_potential_energy(eq::DC2D2NL)
|
||||
return true
|
||||
end
|
||||
|
||||
function test_potential_energy_method()
|
||||
|
||||
# create model -- start
|
||||
@@ -99,36 +88,37 @@ function test_potential_energy_method()
|
||||
element["temperature thermal conductivity"] = 6.0
|
||||
element["temperature load"] = [0.0, 0.0, 0.0, 0.0]
|
||||
element["temperature nodal load"] = [3.0, 3.0, 0.0, 0.0]
|
||||
element["temperature nonlinearity coefficient"] = [6.0, 6.0, 6.0, 6.0]
|
||||
element["temperature nonlinearity coefficient"] = 6.0
|
||||
equation = DC2D4NL(element)
|
||||
# create model -- end
|
||||
|
||||
la = initialize_local_assembly() # create workspace for local matrices
|
||||
ass = Assembly()
|
||||
info("unknown field name: $(get_unknown_field_name(equation))")
|
||||
|
||||
T = zeros(4) # create workspace for solution vector
|
||||
dT = zeros(4) #
|
||||
fd = [1, 2] # free dofs
|
||||
tic()
|
||||
# start loops, in principle solve ∂r(u)/∂uΔu = -r(u) and update.
|
||||
for i=1:10
|
||||
calculate_local_assembly!(la, equation, "temperature") # calculate local matrices
|
||||
dT[fd] = la.stiffness_matrix[fd,fd] \ la.force_vector[fd]
|
||||
empty!(ass)
|
||||
assemble!(ass, equation) # calculate local matrices
|
||||
dT[fd] = full(ass.stiffness_matrix)[fd,fd] \ full(ass.force_vector)[fd]
|
||||
T += dT
|
||||
push!(element["temperature"], T) # add new increment to model
|
||||
info("T = $T")
|
||||
@printf("increment %2d, |du| = %8.5f\n", i, norm(dT))
|
||||
err = last(element["temperature"])[1] - 2/3
|
||||
isapprox(err, 0.0) && break
|
||||
end
|
||||
toc()
|
||||
err = last(element["temperature"])[1] - 2/3
|
||||
info("error: $err")
|
||||
@test isapprox(err, 0.0)
|
||||
end
|
||||
|
||||
|
||||
type TestProblem <: Problem
|
||||
unknown_field_name :: ASCIIString
|
||||
unknown_field_dimension :: Int
|
||||
equations :: Array{Equation, 1}
|
||||
equations :: Vector{Equation}
|
||||
element_mapping :: Dict{DataType, DataType}
|
||||
end
|
||||
|
||||
@@ -143,55 +133,48 @@ function test_potential_energy_method_2()
|
||||
|
||||
# create model -- start
|
||||
N = Vector[[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0]]
|
||||
element = Quad4([1, 2, 3, 4])
|
||||
element["geometry"] = Vector[N[1], N[2], N[3], N[4]]
|
||||
element["temperature thermal conductivity"] = 6.0
|
||||
element["temperature load"] = [0.0, 0.0, 0.0, 0.0]
|
||||
element["temperature nonlinearity coefficient"] = [0.0, 0.0, 0.0, 0.0]
|
||||
#equation1 = DC2D4NL(element, initial_temperature=ones(4))
|
||||
equation1 = DC2D4NL(element)
|
||||
element1 = Quad4([1, 2, 3, 4])
|
||||
element1["geometry"] = Vector[N[1], N[2], N[3], N[4]]
|
||||
element1["temperature thermal conductivity"] = 6.0
|
||||
element1["temperature load"] = [0.0, 0.0, 0.0, 0.0]
|
||||
element1["temperature nonlinearity coefficient"] = [0.0, 0.0, 0.0, 0.0]
|
||||
element1["temperature"] = ones(4)
|
||||
|
||||
boundary_element = Seg2([1, 2])
|
||||
boundary_element["geometry"] = Vector[N[1], N[2]]
|
||||
boundary_element["emissivity"] = 0.5
|
||||
boundary_element["temperature external"] = 10.0
|
||||
#equation2 = DC2D2NL(boundary_element, initial_temperature=ones(4))
|
||||
equation2 = DC2D2NL(boundary_element)
|
||||
element2 = Seg2([1, 2])
|
||||
element2["geometry"] = Vector[N[1], N[2]]
|
||||
element2["temperature coefficient"] = 3.0e-8 # ~ 5.7e-8 * 0.5
|
||||
element2["temperature external"] = 100.0
|
||||
element2["temperature"] = ones(2)
|
||||
# create model -- end
|
||||
|
||||
equation1 = DC2D4NL(element1)
|
||||
equation2 = DC2D2NL(element2)
|
||||
|
||||
ass = Assembly()
|
||||
info("unknown field name: $(get_unknown_field_name(equation1))")
|
||||
|
||||
element["temperature"] = ones(4)
|
||||
boundary_element["temperature"] = ones(2)
|
||||
|
||||
equations = [equation1, equation2]
|
||||
la = initialize_local_assembly() # create workspace for local matrices
|
||||
T = zeros(4) # create workspace for solution vector
|
||||
dT = zeros(4) #
|
||||
fd = [1, 2] # free dofs
|
||||
info("equation 1")
|
||||
calculate_local_assembly!(la, equation1, "temperature")
|
||||
info("stiffness matrix: $(la.stiffness_matrix)")
|
||||
# info("force vector: $(la.force_vector)")
|
||||
info("equation 2")
|
||||
calculate_local_assembly!(la, equation2, "temperature")
|
||||
# info("stiffness matrix: $(la.stiffness_matrix)")
|
||||
info("force vector: $(la.force_vector)")
|
||||
# start loops, in principle solve ∂r(u)/∂uΔu = -r(u) and update.
|
||||
for i=1:10
|
||||
empty!(ass)
|
||||
assemble!(ass, equation1)
|
||||
assemble!(ass, equation2)
|
||||
dT[fd] = full(ass.stiffness_matrix)[fd,fd] \ full(ass.force_vector)[fd]
|
||||
T += dT
|
||||
push!(element1["temperature"], T)
|
||||
push!(element2["temperature"], T[fd])
|
||||
@printf("increment %2d, |du| = %8.5f\n", i, norm(dT))
|
||||
err = last(element1["temperature"])[1] - 0.5
|
||||
isapprox(err, 0.0) && break
|
||||
end
|
||||
|
||||
info("Creating problem")
|
||||
#problem = PlaneHeatProblem("temperature", 1, equations, Dict())
|
||||
problem = TestProblem(equations)
|
||||
|
||||
free_dofs = [1, 2]
|
||||
tic()
|
||||
solve!(problem, free_dofs; max_iterations=10)
|
||||
toc()
|
||||
temp = get_basis(boundary_element)("temperature", [0.0])[1]
|
||||
info("temperature = $temp")
|
||||
#err = last(element["temperature"])[1] - 2/3
|
||||
#info("error: $err")
|
||||
# 0.3888756709834147 tulee jostakin syysta...
|
||||
# tai -0.39411350336960116
|
||||
info(boundary_element["temperature"])
|
||||
@test isapprox(temp, 2.93509690572300E+00) # tested using Code Aster
|
||||
err = last(element1["temperature"])[1] - 0.5
|
||||
info("error: $err")
|
||||
@test isapprox(err, 0.0)
|
||||
|
||||
# @test isapprox(temp, 2.93509690572300E+00) # tested using Code Aster
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
+13
-13
@@ -5,30 +5,32 @@ module TestAutoDiffWeakForm
|
||||
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM
|
||||
using JuliaFEM: Quad4, Equation, IntegrationPoint,
|
||||
using JuliaFEM: Quad4, Equation, IntegrationPoint, assemble!,
|
||||
Assembly,
|
||||
solve!, get_field, get_element, get_basis,
|
||||
grad
|
||||
grad, get_default_integration_points
|
||||
|
||||
""" Plane stress formulation for 4-node bilinear element. """
|
||||
type CPS4 <: Equation
|
||||
element :: Quad4
|
||||
integration_points :: Array{IntegrationPoint, 1}
|
||||
integration_points :: Vector{IntegrationPoint}
|
||||
end
|
||||
|
||||
function JuliaFEM.get_unknown_field_name(equation::CPS4)
|
||||
return "displacement"
|
||||
end
|
||||
|
||||
function CPS4(element::Quad4)
|
||||
integration_points = [
|
||||
IntegrationPoint(1.0/sqrt(3.0)*[-1, -1], 1.0),
|
||||
IntegrationPoint(1.0/sqrt(3.0)*[ 1, -1], 1.0),
|
||||
IntegrationPoint(1.0/sqrt(3.0)*[ 1, 1], 1.0),
|
||||
IntegrationPoint(1.0/sqrt(3.0)*[-1, 1], 1.0)]
|
||||
integration_points = get_default_integration_points(element)
|
||||
if !haskey(element, "displacement")
|
||||
# initial field must be defined if using autodiff
|
||||
element["displacement"] = zeros(2, 4)
|
||||
end
|
||||
CPS4(element, integration_points)
|
||||
end
|
||||
|
||||
JuliaFEM.size(eq::CPS4) = (2, 4)
|
||||
function Base.size(eq::CPS4)
|
||||
return (2, 4)
|
||||
end
|
||||
|
||||
function JuliaFEM.get_residual_vector(equation::CPS4, ip, time; variation=nothing)
|
||||
element = get_element(equation)
|
||||
@@ -58,8 +60,6 @@ function JuliaFEM.get_residual_vector(equation::CPS4, ip, time; variation=nothin
|
||||
return vec(r)
|
||||
end
|
||||
|
||||
JuliaFEM.has_residual_vector(equation::CPS4) = true
|
||||
|
||||
function test_residual_form()
|
||||
# create model -- start
|
||||
element = Quad4([1, 2, 3, 4])
|
||||
@@ -71,7 +71,7 @@ function test_residual_form()
|
||||
# create model -- end
|
||||
|
||||
free_dofs = [3, 4, 5, 6]
|
||||
solve!(equation, "displacement", free_dofs) # launch a newton solver for single element
|
||||
solve!(equation, free_dofs) # launch a newton solver for single element
|
||||
disp = get_basis(element)("displacement", [1.0, 1.0])[2]
|
||||
println("displacement at tip: $disp")
|
||||
# verified using Code Aster.
|
||||
|
||||
Reference in New Issue
Block a user