updated developers guide + tests

This commit is contained in:
Jukka Aho
2015-11-11 00:52:16 +02:00
parent d402d27f05
commit 6f8b403019
15 changed files with 1084 additions and 501 deletions
+18
View File
@@ -0,0 +1,18 @@
# This file is a part of JuliaFEM.
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
module TestAutoDiffWeakForm
using JuliaFEM.Test
using JuliaFEM
using JuliaFEM: Seg2, DirichletProblem
function test_dirichlet_problem()
element = Seg2([3, 4])
element["geometry"] = Vector[[1.0, 1.0], [0.0, 1.0]]
problem = DirichletProblem(1)
push!(problem, element)
end
end
+4 -2
View File
@@ -4,7 +4,9 @@
module ElasticityTests
using JuliaFEM.Test
using JuliaFEM: Quad4, Field, FieldSet, CPS4, get_basis, solve!, PlaneStressElasticityProblem
using JuliaFEM: Quad4, Field, FieldSet, CPS4,
get_basis, solve!,
PlaneStressElasticityProblem
function test_elasticity_one_element()
@@ -21,7 +23,7 @@ function test_elasticity_one_element()
disp = get_basis(element)("displacement", [1.0, 1.0])[2]
info("displacement at tip: $disp")
# verified using Code Aster.
@test disp ≈ -8.77303119819776
@test isapprox(disp, -8.77303119819776)
end
+44 -2
View File
@@ -19,7 +19,11 @@ end
function MockElement(connectivity)
h(xi) = 1/4*[(1-xi[1])*(1-xi[2]) (1+xi[1])*(1-xi[2]) (1+xi[1])*(1+xi[2]) (1-xi[1])*(1+xi[2])]
h(xi) = 1/4*[
(1-xi[1])*(1-xi[2])
(1+xi[1])*(1-xi[2])
(1+xi[1])*(1+xi[2])
(1-xi[1])*(1+xi[2])]'
dh(xi) = 1/4*[
-(1-xi[2]) (1-xi[2]) (1+xi[2]) -(1+xi[2])
@@ -39,9 +43,47 @@ end
""" test adding fieldsets and fields to element"""
function test_add_fields_to_element()
el = MockElement([1, 2, 3, 4])
el["geometry"] = [0.0, 0.0, 0.0, 0.0], [1.0, 1.0, 1.0, 1.0]
#geometry = Field([0.0, 0.0, 0.0, 0.0])
el["geometry"] = Field([0.0, 0.0, 0.0, 0.0])
@test el["geometry"][1].time == 0.0
@test last(el["geometry"]) == [0.0, 0.0, 0.0, 0.0]
el["geometry"] = Field(Vector[[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0]])
@test last(el["geometry"])[3] == [1.0, 1.0]
el["geometry"] = Vector[[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0]]
@test last(el["geometry"])[3] == [1.0, 1.0]
el["geometry"] = [0.0 0.0; 1.0 0.0; 1.0 1.0; 0.0 1.0]'
@test last(el["geometry"])[3] == [1.0, 1.0]
el["geometry"] = (0.0, [0.0, 0.0, 0.0, 0.0]), (1.0, [1.0, 1.0, 1.0, 1.0])
field = el["geometry"]
@test length(field) == 2 # two time steps
el["boundary flux"] = (0.0, 0.0), (1.0, 6.0)
end
function test_add_fields_to_element_2()
el = MockElement([1, 2, 3, 4])
el["data"] = (0.0 => [1, 2], 1.0 => [2, 3])
@test length(el["data"]) == 2
@test el["data"][1].time == 0.0
@test el["data"][2].time == 1.0
@test last(el["data"][1]) == [1, 2]
@test last(el["data"][2]) == [2, 3]
end
function test_add_data_to_element_using_push()
el = MockElement([1, 2, 3, 4])
el["data"] = [0, 0, 0, 0]
push!(el["data"], [1, 2, 3, 4])
@test length(el["data"]) == 1
@test length(el["data"][1]) == 2
@test el["data"][1].time == 0.0
push!(el["data"], 1.0 => [2, 3, 4, 5]) # creates new timestep at t=1.0
push!(el["data"], [3, 4, 5, 6]) # adds new increment data to last timestep
@test length(el["data"]) == 2
@test length(el["data"][2]) == 2
@test el["data"][2].time == 1.0
end
#=
+197
View File
@@ -0,0 +1,197 @@
# This file is a part of JuliaFEM.
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
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!
""" Diffusive heat transfer for 4-node bilinear element, with a nonlinear source term. """
type DC2D4NL <: Equation
element :: Quad4
integration_points :: Array{IntegrationPoint, 1}
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)]
if !haskey(element, "temperature")
element["temperature"] = initial_temperature
end
DC2D4NL(element, integration_points)
end
function Base.size(equation::DC2D4NL)
return (1, 4)
end
""" Nonlinear flux term. """
type DC2D2NL <: Equation
element :: Seg2
integration_points :: Array{IntegrationPoint, 1}
end
function DC2D2NL(element::Seg2, initial_temperature=zeros(2))
#integration_points = [
# IntegrationPoint([0.0], 2.0)]
integration_points = JuliaFEM.line5()
if !haskey(element, "temperature")
element["temperature"] = initial_temperature
end
DC2D2NL(element, integration_points)
end
function Base.size(equation::DC2D2NL)
return (1, 2)
end
""" Calculate a potential Π = Wint - Wext of system. """
function JuliaFEM.get_potential_energy(equation::DC2D4NL, ip, time; variation=nothing)
element = get_element(equation)
basis = get_basis(element)
k = basis("temperature thermal conductivity", ip, time)
f = basis("temperature load", ip, time)
T = basis("temperature", ip, time, variation)
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)
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
element = Quad4([1, 2, 3, 4])
element["geometry"] = Vector[[0.0,0.0], [1.0,0.0], [1.0,1.0], [0.0,1.0]]
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]
equation = DC2D4NL(element)
# create model -- end
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
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]
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}
element_mapping :: Dict{DataType, DataType}
end
function TestProblem(equations=[])
element_mapping = Dict(
Quad4 => DC2D4NL,
Seg2 => DC2D2NL)
TestProblem("temperature", 1, equations, element_mapping)
end
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)
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)
# create model -- end
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)")
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
end
end
+34
View File
@@ -0,0 +1,34 @@
# This file is a part of JuliaFEM.
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
module RandomFieldTests
using JuliaFEM
using JuliaFEM: DiscreteField, Field, Increment, Quad4
using JuliaFEM.Test
type RandomField <: DiscreteField
mu :: Float64
std :: Float64
end
Base.first(field::RandomField) = Increment(randn(2, 4).*field.std^2 + field.mu)
function test_interpolate_in_time()
r = RandomField(10.0, 0.0)
f = Increment(ones(2, 4)*10.0)
@test r(0.0) == f
@test r(-Inf) == f
@test r(+Inf) == f
@test r(1.0) == f
end
function test_interpolate_in_spatial_domain()
basis = Quad4([1, 2, 3, 4]).basis
r = RandomField(10.0, 0.0)
feval = basis(r(0.0), [0.0, 0.0])
@test feval == [10.0, 10.0]
end
end
+81
View File
@@ -0,0 +1,81 @@
# This file is a part of JuliaFEM.
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
module TestAutoDiffWeakForm
using JuliaFEM.Test
using JuliaFEM
using JuliaFEM: Quad4, Equation, IntegrationPoint,
solve!, get_field, get_element, get_basis,
grad
""" Plane stress formulation for 4-node bilinear element. """
type CPS4 <: Equation
element :: Quad4
integration_points :: Array{IntegrationPoint, 1}
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)]
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 JuliaFEM.get_residual_vector(equation::CPS4, ip, time; variation=nothing)
element = get_element(equation)
basis = get_basis(element)
dbasis = grad(basis)
# material parameters
E = basis("youngs modulus", ip, time)
nu = basis("poissons ratio", ip, time)
mu = E/(2*(1+nu))
la = E*nu/((1+nu)*(1-2*nu))
la = 2*la*mu/(la + 2*mu) # <- correction for 2d
# elasticity formulation
u = basis("displacement", ip, time, variation)
gradu = dbasis("displacement", ip, time, variation)
F = I + gradu
b = basis("displacement volume load", ip, time)
E = 1/2*(F'*F - I)
S = la*trace(E)*I + 2*mu*E
P = F*S
# residual vector
r_int = P*dbasis(ip,time)
r_ext = b*basis(ip,time)
r = r_int - r_ext
return vec(r)
end
JuliaFEM.has_residual_vector(equation::CPS4) = true
function test_residual_form()
# create model -- start
element = Quad4([1, 2, 3, 4])
element["geometry"] = Vector[[0.0,0.0], [10.0,0.0], [10.0,1.0], [0.0,1.0]]
element["youngs modulus"] = 500.0
element["poissons ratio"] = 0.3
element["displacement volume load"] = Vector[[0.0,-10.0], [0.0,-10.0], [0.0,-10.0], [0.0,-10.0]]
equation = CPS4(element)
# create model -- end
free_dofs = [3, 4, 5, 6]
solve!(equation, "displacement", 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.
@test isapprox(disp, -8.77303119819776E+00)
end
end