mirror of
https://github.com/JuliaFEM/JuliaFEM.jl.git
synced 2026-09-21 18:33:36 +00:00
rewrite assembly, see #69. a lot of tests probably fail but the most important ones pass
This commit is contained in:
@@ -63,6 +63,7 @@ include("lagrange.jl") # Lagrange elements
|
||||
|
||||
### EQUATIONS ###
|
||||
include("integrate.jl") # default integration points for elements
|
||||
include("sparse.jl")
|
||||
include("equations.jl")
|
||||
include("problems.jl")
|
||||
|
||||
|
||||
+4
-56
@@ -3,61 +3,9 @@
|
||||
|
||||
# Functions to handle global assembly of problem
|
||||
|
||||
""" Global assembly. """
|
||||
type GlobalAssembly <: Assembly
|
||||
ndofs :: Int
|
||||
mass_matrix :: SparseMatrixCSC
|
||||
stiffness_matrix :: SparseMatrixCSC
|
||||
force_vector :: SparseMatrixCSC
|
||||
end
|
||||
|
||||
""" Initialize global assembly of size ndofs. """
|
||||
function initialize_global_assembly(ndofs::Int=1)
|
||||
mass_matrix = spzeros(ndofs, ndofs)
|
||||
stiffness_matrix = spzeros(ndofs, ndofs)
|
||||
force_vector = spzeros(ndofs, 1)
|
||||
return GlobalAssembly(ndofs, mass_matrix, stiffness_matrix, force_vector)
|
||||
end
|
||||
|
||||
""" Initialize global assembly, get dimension from problem. """
|
||||
function initialize_global_assembly(problem::Problem)
|
||||
dim, ndofs = size(problem)
|
||||
return initialize_global_assembly(ndofs)
|
||||
end
|
||||
|
||||
""" Initialize or empty workspace for global assembly. """
|
||||
function initialize_global_assembly!(assembly::GlobalAssembly, problem::Problem)
|
||||
ndofs = prod(size(problem))
|
||||
if ndofs != assembly.ndofs
|
||||
# if problem size changes, automatically initialize new work space
|
||||
assembly.ndofs = ndofs
|
||||
assembly.mass_matrix = spzeros(ndofs, ndofs)
|
||||
assembly.stiffness_matrix = spzeros(ndofs, ndofs)
|
||||
assembly.force_vector = spzeros(ndofs, 1)
|
||||
return
|
||||
end
|
||||
# otherwise, empty workspace ready for next iteration
|
||||
fill!(assembly.mass_matrix, 0.0)
|
||||
fill!(assembly.stiffness_matrix, 0.0)
|
||||
fill!(assembly.force_vector, 0.0)
|
||||
return
|
||||
end
|
||||
|
||||
""" Calculate global assembly for a problem. """
|
||||
function calculate_global_assembly!(assembly::GlobalAssembly, problem::Problem, time::Number=Inf)
|
||||
|
||||
unknown_field_name = get_unknown_field_name(problem)
|
||||
initialize_global_assembly!(assembly, problem) # zero all
|
||||
dim, ndofs = size(problem)
|
||||
info("assembling problem for $unknown_field_name")
|
||||
info("dimension of unknown field: $dim, problem dofs: $ndofs")
|
||||
local_assembly = initialize_local_assembly()
|
||||
for (i, equation) in enumerate(get_equations(problem))
|
||||
calculate_local_assembly!(local_assembly, equation, unknown_field_name, time)
|
||||
conn = get_connectivity(get_element(equation))
|
||||
gdofs = get_gdofs(problem, equation)
|
||||
assembly.mass_matrix[gdofs, gdofs] += local_assembly.mass_matrix
|
||||
assembly.stiffness_matrix[gdofs, gdofs] += local_assembly.stiffness_matrix
|
||||
assembly.force_vector[gdofs] += local_assembly.force_vector
|
||||
function assemble!(assembly::Assembly, problem::Problem, time::Number=0.0)
|
||||
empty!(assembly)
|
||||
for equation in get_equations(problem)
|
||||
assemble!(assembly, equation, time, problem)
|
||||
end
|
||||
end
|
||||
|
||||
+8
-4
@@ -5,6 +5,10 @@
|
||||
|
||||
abstract DirichletEquation <: Equation
|
||||
|
||||
function get_unknown_field_name(equation::DirichletEquation)
|
||||
return "reaction force"
|
||||
end
|
||||
|
||||
### Dirichlet problem + equations
|
||||
|
||||
type DirichletProblem <: BoundaryProblem
|
||||
@@ -56,19 +60,19 @@ function DBC2D2(element::Seg2)
|
||||
end
|
||||
Base.size(equation::DBC2D2) = (1, 2)
|
||||
|
||||
function calculate_local_assembly!(assembly::LocalAssembly, equation::DirichletEquation, unknown_field_name::ASCIIString, time::Number=0.0, problem=nothing)
|
||||
initialize_local_assembly!(assembly, equation)
|
||||
function assemble!(assembly::Assembly, equation::DirichletEquation, time::Number=0.0, problem=nothing)
|
||||
gdofs = get_gdofs(equation)
|
||||
element = get_element(equation)
|
||||
basis = get_basis(element)
|
||||
detJ = det(basis)
|
||||
for ip in get_integration_points(equation)
|
||||
w = ip.weight * detJ(ip)
|
||||
N = basis(ip, time)
|
||||
assembly.stiffness_matrix += w * N'*N
|
||||
add!(assembly.stiffness_matrix, gdofs, gdofs, w*N'*N)
|
||||
if !isa(problem, Void)
|
||||
X = basis("geometry", ip, time)
|
||||
u = problem.field_value(X)
|
||||
assembly.force_vector += w * N'*u
|
||||
add!(assembly.force_vector, gdofs, w*N'*u)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
abstract ElasticityProblem <: Problem
|
||||
abstract ElasticityEquation <: Equation
|
||||
|
||||
function get_unknown_field_name(equation::ElasticityEquation)
|
||||
return "displacement"
|
||||
end
|
||||
|
||||
### Formulation ###
|
||||
|
||||
""" Calculate internal energy for elasticity equation.
|
||||
|
||||
+115
-141
@@ -5,203 +5,177 @@
|
||||
|
||||
abstract Equation
|
||||
|
||||
abstract Assembly
|
||||
|
||||
""" Local element assembly. """
|
||||
type LocalAssembly <: Assembly
|
||||
ndofs :: Int
|
||||
mass_matrix :: Matrix
|
||||
stiffness_matrix :: Matrix
|
||||
force_vector :: Matrix
|
||||
potential_energy
|
||||
residual_vector :: Vector
|
||||
type Assembly
|
||||
mass_matrix :: SparseMatrixIJV
|
||||
stiffness_matrix :: SparseMatrixIJV
|
||||
force_vector :: SparseMatrixIJV
|
||||
lhs :: SparseMatrixIJV
|
||||
rhs :: SparseMatrixIJV
|
||||
end
|
||||
|
||||
""" Initialize workspace for local matrices for dimension ndofs. """
|
||||
function initialize_local_assembly(ndofs::Int=1)
|
||||
mass_matrix = zeros(ndofs, ndofs)
|
||||
stiffness_matrix = zeros(ndofs, ndofs)
|
||||
force_vector = zeros(ndofs, 1)
|
||||
potential_energy = 0.0
|
||||
residual_vector = zeros(ndofs)
|
||||
return LocalAssembly(ndofs, mass_matrix, stiffness_matrix, force_vector,
|
||||
potential_energy, residual_vector)
|
||||
function Assembly()
|
||||
return Assembly(
|
||||
SparseMatrixIJV(),
|
||||
SparseMatrixIJV(),
|
||||
SparseMatrixIJV(),
|
||||
SparseMatrixIJV(),
|
||||
SparseMatrixIJV())
|
||||
end
|
||||
|
||||
""" Initialize workspace for local matrices, get dimension from equation. """
|
||||
function initialize_local_assembly(equation::Equation)
|
||||
ndofs = prod(size(equation))
|
||||
return initialize_local_assembly(ndofs)
|
||||
function Base.empty!(assembly::Assembly)
|
||||
empty!(assembly.mass_matrix)
|
||||
empty!(assembly.stiffness_matrix)
|
||||
empty!(assembly.force_vector)
|
||||
empty!(assembly.lhs)
|
||||
empty!(assembly.rhs)
|
||||
end
|
||||
|
||||
""" Initialize or zero workspace. """
|
||||
function initialize_local_assembly!(assembly::LocalAssembly, equation::Equation)
|
||||
ndofs = prod(size(equation))
|
||||
if ndofs != assembly.ndofs
|
||||
# if problem size changes, automatically initialize new work space
|
||||
assembly.ndofs = ndofs
|
||||
assembly.mass_matrix = zeros(ndofs, ndofs)
|
||||
assembly.stiffness_matrix = zeros(ndofs, ndofs)
|
||||
assembly.force_vector = zeros(ndofs, 1)
|
||||
assembly.potential_energy = 0.0
|
||||
assembly.residual_vector = zeros(ndofs)
|
||||
return
|
||||
end
|
||||
# otherwise, empty workspace ready for next iteration
|
||||
fill!(assembly.mass_matrix, 0.0)
|
||||
fill!(assembly.stiffness_matrix, 0.0)
|
||||
fill!(assembly.force_vector, 0.0)
|
||||
assembly.potential_energy = 0.0
|
||||
fill!(assembly.residual_vector, 0.0)
|
||||
return
|
||||
function get_mass_matrix
|
||||
end
|
||||
|
||||
has_mass_matrix(equation::Equation) = false
|
||||
function get_mass_matrix(equation::Equation, ip, time=0.0, problem=nothing)
|
||||
get_mass_matrix(equation, ip, time)
|
||||
end
|
||||
function get_mass_matrix(equation::Equation, ip, time=0.0)
|
||||
get_mass_matrix(equation, ip)
|
||||
end
|
||||
function get_mass_matrix(equation::Equation, ip)
|
||||
nothing
|
||||
function get_stiffness_matrix
|
||||
end
|
||||
|
||||
has_stiffness_matrix(equation::Equation) = false
|
||||
function get_stiffness_matrix(equation::Equation, ip, time=0.0, problem=nothing)
|
||||
get_stiffness_matrix(equation, ip, time)
|
||||
end
|
||||
function get_stiffness_matrix(equation::Equation, ip, time=0.0)
|
||||
get_stiffness_matrix(equation, ip)
|
||||
end
|
||||
function get_stiffness_matrix(equation::Equation, ip)
|
||||
nothing
|
||||
function get_force_vector
|
||||
end
|
||||
|
||||
has_force_vector(equation::Equation) = false
|
||||
function get_force_vector(equation::Equation, ip, time=0.0, problem=nothing)
|
||||
get_force_vector(equation, ip, time)
|
||||
end
|
||||
function get_force_vector(equation::Equation, ip, time=0.0)
|
||||
get_force_vector(equation, ip)
|
||||
end
|
||||
function get_force_vector(equation::Equation, ip)
|
||||
nothing
|
||||
function get_potential_energy
|
||||
end
|
||||
|
||||
has_residual_vector(equation::Equation) = false
|
||||
function get_residual_vector(equation::Equation, ip, time=0.0, problem=nothing)
|
||||
get_residual_vector(equation, ip, time)
|
||||
end
|
||||
function get_residual_vector(equation::Equation, ip, time=0.0)
|
||||
get_residual_vector(equation, ip)
|
||||
end
|
||||
function get_residual_vector(equation::Equation, ip)
|
||||
nothing
|
||||
function get_residual_vector
|
||||
end
|
||||
|
||||
has_potential_energy(equation::Equation) = false
|
||||
function get_potential_energy(equation::Equation, ip, time=0.0, problem=nothing)
|
||||
get_potential_energy(equation, ip, time)
|
||||
end
|
||||
function get_potential_energy(equation::Equation, ip, time=0.0)
|
||||
get_potential_energy(equation, ip)
|
||||
end
|
||||
function get_potential_energy(equation::Equation, ip)
|
||||
nothing
|
||||
function has_mass_matrix(equation::Equation)
|
||||
default_args = Tuple{typeof(equation), IntegrationPoint, Float64}
|
||||
return method_exists(get_mass_matrix, default_args)
|
||||
end
|
||||
|
||||
get_element(equation::Equation) = equation.element
|
||||
get_integration_points(equation::Equation) = equation.integration_points
|
||||
function has_stiffness_matrix(equation::Equation)
|
||||
default_args = Tuple{typeof(equation), IntegrationPoint, Float64}
|
||||
return method_exists(get_stiffness_matrix, default_args)
|
||||
end
|
||||
|
||||
function has_force_vector(equation::Equation)
|
||||
default_args = Tuple{typeof(equation), IntegrationPoint, Float64}
|
||||
return method_exists(get_force_vector, default_args)
|
||||
end
|
||||
|
||||
""" Return a local assembly for element. """
|
||||
function calculate_local_assembly!(assembly::LocalAssembly, equation::Equation,
|
||||
unknown_field_name::ASCIIString, time::Number=0.0,
|
||||
problem=nothing)
|
||||
function has_potential_energy(equation::Equation)
|
||||
default_args = Tuple{typeof(equation), IntegrationPoint, Float64}
|
||||
return method_exists(get_potential_energy, default_args)
|
||||
end
|
||||
|
||||
initialize_local_assembly!(assembly, equation) # zero all
|
||||
function has_residual_vector(equation::Equation)
|
||||
default_args = Tuple{typeof(equation), IntegrationPoint, Float64}
|
||||
return method_exists(get_residual_vector, default_args)
|
||||
end
|
||||
|
||||
function get_element(equation::Equation)
|
||||
return equation.element
|
||||
end
|
||||
|
||||
function get_integration_points(equation::Equation)
|
||||
return equation.integration_points
|
||||
end
|
||||
|
||||
function Base.size(equation::Equation, i::Int)
|
||||
return size(equation)[i]
|
||||
end
|
||||
|
||||
""" Return global degrees of freedom of element in matrix level.
|
||||
|
||||
Notes
|
||||
-----
|
||||
This is calculated from connectivity and equation dimension.
|
||||
"""
|
||||
|
||||
function get_gdofs(equation::Equation)
|
||||
element = get_element(equation)
|
||||
conn = get_connectivity(element)
|
||||
dim = size(equation, 1)
|
||||
gdofs = vec(vcat([dim*conn'-i for i=dim-1:-1:0]...))
|
||||
return gdofs
|
||||
end
|
||||
|
||||
""" Assemble element. """
|
||||
function assemble!(assembly::Assembly, equation::Equation, time::Number=0.0, problem=nothing)
|
||||
|
||||
element = get_element(equation)
|
||||
gdofs = get_gdofs(equation)
|
||||
basis = get_basis(element)
|
||||
detJ = det(basis)
|
||||
unknown_field_name = get_unknown_field_name(equation)
|
||||
|
||||
# 1. if equations are defined we just integrate them
|
||||
# 1. if equations are defined we just integrate them, without caring how they are done
|
||||
if has_mass_matrix(equation) || has_stiffness_matrix(equation) || has_force_vector(equation)
|
||||
for ip in get_integration_points(equation)
|
||||
s = ip.weight*detJ(ip)
|
||||
if has_mass_matrix(equation)
|
||||
assembly.mass_matrix += s*get_mass_matrix(equation, ip, time, problem)
|
||||
add!(assembly.mass_matrix, gdofs, gdofs, s*get_mass_matrix(equation, ip, time))
|
||||
end
|
||||
if has_stiffness_matrix(equation)
|
||||
assembly.stiffness_matrix += s*get_stiffness_matrix(equation, ip, time, problem)
|
||||
add!(assembly.stiffness_matrix, gdofs, gdofs, s*get_stiffness_matrix(equation, ip, time))
|
||||
end
|
||||
if has_force_vector(equation)
|
||||
assembly.force_vector += s*get_force_vector(equation, ip, time, problem)
|
||||
add!(assembly.force_vector, gdofs, s*get_force_vector(equation, ip, time))
|
||||
end
|
||||
end
|
||||
# external loads -- if any nodal loads is defined add to force vector
|
||||
if haskey(element, "$unknown_field_name nodal load")
|
||||
assembly.force_vector += vec(element["$unknown_field_name nodal load"](time))
|
||||
add!(assembly.force_vector, gdofs, vec(element["$unknown_field_name nodal load"](time)))
|
||||
end
|
||||
end
|
||||
|
||||
# 2. variational / energy form - user has defined some potential energy / variational form
|
||||
# 2. energy form -- user has defined potential energy W -> min!
|
||||
if has_potential_energy(equation)
|
||||
element = get_element(equation)
|
||||
field = element[unknown_field_name](time)
|
||||
function potential_energy(data::Vector)
|
||||
# calculate potential energy for some setting. this is needed by forwarddiff
|
||||
assembly.potential_energy = 0.0
|
||||
|
||||
""" Wrapper for potential energy for ForwardDiff. """
|
||||
function calc_W(data::Vector)
|
||||
W = 0.0
|
||||
df = similar(field, data)
|
||||
# integrate potential energy
|
||||
for ip in get_integration_points(equation)
|
||||
s = ip.weight*detJ(ip)
|
||||
dw = get_potential_energy(equation, ip, time; variation=df)
|
||||
assembly.potential_energy += ip.weight * dw * detJ(ip)
|
||||
W += s*dw
|
||||
end
|
||||
# external energy -- if any nodal loads is defined, decrease from potential energy
|
||||
if haskey(element, "$unknown_field_name nodal load")
|
||||
P = element["$unknown_field_name nodal load"](time)
|
||||
assembly.potential_energy -= dot(vec(P), vec(df))
|
||||
W -= dot(vec(P), vec(df))
|
||||
end
|
||||
if isa(assembly.potential_energy, Array)
|
||||
return assembly.potential_energy[1]
|
||||
end
|
||||
return assembly.potential_energy
|
||||
return isa(W, Array) ? W[1] : W
|
||||
end
|
||||
hessian, allresults = ForwardDiff.hessian(potential_energy, vec(field),
|
||||
AllResults, cache=autodiffcache)
|
||||
assembly.stiffness_matrix += hessian
|
||||
assembly.force_vector -= ForwardDiff.gradient(allresults) # <--- minus explained in tutorial
|
||||
assembly.potential_energy = ForwardDiff.value(allresults)
|
||||
#info("potential energy of system: $(assembly.potential_energy)")
|
||||
|
||||
hessian, allresults = ForwardDiff.hessian(calc_W, vec(field), AllResults, cache=autodiffcache)
|
||||
add!(assembly.stiffness_matrix, gdofs, gdofs, hessian)
|
||||
add!(assembly.force_vector, gdofs, -ForwardDiff.gradient(allresults))
|
||||
end
|
||||
|
||||
# 3. virtual work form - user has defined residual vector δW_int(u,δu) + δW_ext(u,δu) = 0 ∀ v
|
||||
# 3. virtual work -- user has defined some residual r = p - f = 0
|
||||
if has_residual_vector(equation)
|
||||
element = get_element(equation)
|
||||
field = element[unknown_field_name](time)
|
||||
function residual_vector(data::Vector)
|
||||
fill!(assembly.residual_vector, 0.0)
|
||||
#@debug("field: $field, length = $(size(field))")
|
||||
#@debug("data: $data, size = $(size(data))")
|
||||
#df = similar(field, data)
|
||||
df = Increment(reshape(data, size(equation)...))
|
||||
# integrate W
|
||||
for ip in get_integration_points(equation)
|
||||
dr = get_residual_vector(equation, ip, time; variation=df)
|
||||
assembly.residual_vector += ip.weight*dr*detJ(ip)
|
||||
end
|
||||
# external loads -- if any nodal loads is defined, remove from residual
|
||||
if haskey(element, "$unknown_field_name nodal load")
|
||||
assembly.residual_vector -= vec(element["$unknown_field_name nodal load"](time))
|
||||
end
|
||||
return assembly.residual_vector
|
||||
end
|
||||
jacobian, allresults = ForwardDiff.jacobian(residual_vector, vec(field),
|
||||
AllResults, cache=autodiffcache)
|
||||
assembly.stiffness_matrix += jacobian
|
||||
assembly.force_vector -= ForwardDiff.value(allresults) # <-- minus explained in tutorial
|
||||
end
|
||||
|
||||
""" Wrapper for virtual work for ForwardDiff. """
|
||||
function calc_R(data::Vector)
|
||||
R = zeros(length(data))
|
||||
df = similar(field, data)
|
||||
# integrate residual vector
|
||||
for ip in get_integration_points(equation)
|
||||
s = ip.weight*detJ(ip)
|
||||
dr = get_residual_vector(equation, ip, time; variation=df)
|
||||
R += s*dr
|
||||
end
|
||||
# external loads -- if any nodal loads is defined, decrease from residual
|
||||
if haskey(element, "$unknown_field_name nodal load")
|
||||
R -= vec(element["$unknown_field_name nodal load"](time))
|
||||
end
|
||||
return R
|
||||
end
|
||||
|
||||
jacobian, allresults = ForwardDiff.jacobian(calc_R, vec(field), AllResults, cache=autodiffcache)
|
||||
add!(assembly.stiffness_matrix, gdofs, gdofs, jacobian)
|
||||
add!(assembly.force_vector, gdofs, -ForwardDiff.value(allresults))
|
||||
end
|
||||
end
|
||||
|
||||
+30
-27
@@ -6,6 +6,10 @@
|
||||
abstract HeatProblem <: Problem
|
||||
abstract HeatEquation <: Equation
|
||||
|
||||
function get_unknown_field_name(equation::HeatEquation)
|
||||
return "temperature"
|
||||
end
|
||||
|
||||
### Formulation ###
|
||||
|
||||
""" Heat equations.
|
||||
@@ -32,55 +36,36 @@ References
|
||||
https://en.wikipedia.org/wiki/Heat_equation
|
||||
|
||||
"""
|
||||
function calculate_local_assembly!(assembly::LocalAssembly, equation::HeatEquation,
|
||||
unknown_field_name::ASCIIString, time::Number=Inf,
|
||||
problem=nothing)
|
||||
|
||||
initialize_local_assembly!(assembly, equation)
|
||||
function assemble!(assembly::Assembly, equation::HeatEquation, time::Number=0.0, problem=nothing)
|
||||
|
||||
element = get_element(equation)
|
||||
gdofs = get_gdofs(equation)
|
||||
basis = get_basis(element)
|
||||
dbasis = grad(basis)
|
||||
detJ = det(basis)
|
||||
for ip in get_integration_points(equation)
|
||||
w = ip.weight * detJ(ip)
|
||||
w = ip.weight*detJ(ip)
|
||||
N = basis(ip, time)
|
||||
if haskey(element, "density")
|
||||
rho = basis("density", ip, time)
|
||||
assembly.mass_matrix += w * rho*N'*N
|
||||
add!(assembly.mass_matrix, gdofs, gdofs, w*rho*N'*N)
|
||||
end
|
||||
if haskey(element, "temperature thermal conductivity")
|
||||
dN = dbasis(ip, time)
|
||||
k = basis("temperature thermal conductivity", ip, time)
|
||||
assembly.stiffness_matrix += w * k*dN'*dN
|
||||
add!(assembly.stiffness_matrix, gdofs, gdofs, w*k*dN'*dN)
|
||||
end
|
||||
if haskey(element, "temperature load")
|
||||
f = basis("temperature load", ip, time)
|
||||
assembly.force_vector += w * N'*f
|
||||
add!(assembly.force_vector, gdofs, w*N'*f)
|
||||
end
|
||||
if haskey(element, "temperature flux")
|
||||
g = basis("temperature flux", ip, time)
|
||||
assembly.force_vector += w * N'*g
|
||||
add!(assembly.force_vector, gdofs, w*N'*g)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
### Problems ###
|
||||
|
||||
type PlaneHeatProblem <: HeatProblem
|
||||
unknown_field_name :: ASCIIString
|
||||
unknown_field_dimension :: Int
|
||||
equations :: Array{HeatEquation, 1}
|
||||
element_mapping :: Dict{DataType, DataType}
|
||||
end
|
||||
|
||||
""" Default constructor for problem takes no arguments. """
|
||||
function PlaneHeatProblem()
|
||||
element_mapping = Dict(
|
||||
Quad4 => DC2D4,
|
||||
Seg2 => DC2D2)
|
||||
return PlaneHeatProblem("temperature", 1, [], element_mapping)
|
||||
end
|
||||
|
||||
### Equations ###
|
||||
|
||||
@@ -101,7 +86,7 @@ Base.size(equation::DC2D4) = (1, 4)
|
||||
""" Diffusive heat transfer for 2-node linear segment. """
|
||||
type DC2D2 <: HeatEquation
|
||||
element :: Seg2
|
||||
integration_points :: Array{IntegrationPoint, 1}
|
||||
integration_points :: Vector{IntegrationPoint}
|
||||
end
|
||||
function DC2D2(element::Seg2)
|
||||
integration_points = get_default_integration_points(element)
|
||||
@@ -112,3 +97,21 @@ function DC2D2(element::Seg2)
|
||||
end
|
||||
Base.size(equation::DC2D2) = (1, 2)
|
||||
|
||||
### Problems ###
|
||||
|
||||
type PlaneHeatProblem <: HeatProblem
|
||||
unknown_field_name :: ASCIIString
|
||||
unknown_field_dimension :: Int
|
||||
equations :: Vector{Equation}
|
||||
#element_mapping :: Dict{Element, Equation}
|
||||
# FIXME: Why is not working ^
|
||||
element_mapping :: Dict{Any, Any}
|
||||
end
|
||||
|
||||
""" Default constructor for problem takes no arguments. """
|
||||
function PlaneHeatProblem()
|
||||
element_mapping = Dict(
|
||||
Quad4 => DC2D4,
|
||||
Seg2 => DC2D2)
|
||||
return PlaneHeatProblem("temperature", 1, [], element_mapping)
|
||||
end
|
||||
|
||||
+23
-18
@@ -9,18 +9,19 @@ abstract Solver
|
||||
Solve field equations for single element with some dofs fixed. This can be used
|
||||
to test nonlinear element formulations.
|
||||
"""
|
||||
function solve!(equation::Equation, unknown_field_name::ASCIIString,
|
||||
free_dofs::Array{Int, 1}, time::Number=0.0;
|
||||
function solve!(equation::Equation, free_dofs::Vector{Int}, time::Number=0.0;
|
||||
max_iterations::Int=10, tolerance::Float64=1.0e-12, dump_matrices::Bool=false)
|
||||
unknown_field_name = get_unknown_field_name(equation)
|
||||
element = get_element(equation)
|
||||
x0 = element[unknown_field_name](0.0)
|
||||
x = zeros(prod(size(equation)))
|
||||
dx = fill!(similar(x), 0.0)
|
||||
la = initialize_local_assembly()
|
||||
ass = Assembly()
|
||||
for i=1:max_iterations
|
||||
calculate_local_assembly!(la, equation, unknown_field_name)
|
||||
A = la.stiffness_matrix[free_dofs, free_dofs]
|
||||
b = la.force_vector[free_dofs]
|
||||
empty!(ass)
|
||||
assemble!(ass, equation)
|
||||
A = full(ass.stiffness_matrix)[free_dofs, free_dofs]
|
||||
b = full(ass.force_vector)[free_dofs]
|
||||
if dump_matrices
|
||||
dump(full(A))
|
||||
dump(full(b)')
|
||||
@@ -39,30 +40,34 @@ to test nonlinear element formulations. Dirichlet boundary is assumed to be homo
|
||||
and degrees of freedom are eliminated. So if boundary condition is known in nodal
|
||||
points and everything is zero this should be quite good.
|
||||
"""
|
||||
function solve!(problem::Problem, free_dofs::Array{Int, 1}, time::Number=1.0;
|
||||
max_iterations::Int=10, tolerance::Float64=1.0e-12, dump_matrices::Bool=false)
|
||||
function solve!(problem::Problem, free_dofs::Vector{Int}, time::Number=1.0; max_iterations::Int=10, tolerance::Float64=1.0e-12, dump_matrices::Bool=false)
|
||||
info("start solver")
|
||||
ga = initialize_global_assembly(problem)
|
||||
x = zeros(ga.ndofs)
|
||||
dx = fill!(similar(x), 0.0)
|
||||
assembly = Assembly()
|
||||
# x = zeros(ga.ndofs)
|
||||
# dx = fill!(similar(x), 0.0)
|
||||
# FIXME: better.
|
||||
x = nothing
|
||||
dx = nothing
|
||||
field_name = get_unknown_field_name(problem)
|
||||
dim = get_unknown_field_dimension(problem)
|
||||
for i=1:max_iterations
|
||||
info("calculate global assembly")
|
||||
calculate_global_assembly!(ga, problem)
|
||||
info("done")
|
||||
A = ga.stiffness_matrix[free_dofs, free_dofs]
|
||||
b = ga.force_vector[free_dofs]
|
||||
assemble!(assembly, problem, time)
|
||||
A = sparse(assembly.stiffness_matrix)
|
||||
b = sparse(assembly.force_vector)
|
||||
if dump_matrices
|
||||
dump(full(A))
|
||||
dump(full(b)')
|
||||
end
|
||||
dx[free_dofs] = lufact(A) \ full(b)
|
||||
if isa(dx, Void)
|
||||
x = zeros(length(b))
|
||||
dx = zeros(length(b))
|
||||
end
|
||||
dx[free_dofs] = lufact(A[free_dofs,free_dofs]) \ full(b)[free_dofs]
|
||||
info("Difference in solution norm: $(norm(dx))")
|
||||
x += dx
|
||||
for equation in get_equations(problem)
|
||||
element = get_element(equation)
|
||||
gdofs = get_gdofs(problem, equation)
|
||||
gdofs = get_gdofs(equation)
|
||||
data = reshape(full(x[gdofs]), size(equation))
|
||||
push!(element[field_name], data)
|
||||
end
|
||||
|
||||
@@ -14,6 +14,10 @@ function SparseMatrixIJV()
|
||||
SparseMatrixIJV([], [], [])
|
||||
end
|
||||
|
||||
function Base.sparse(A::SparseMatrixIJV)
|
||||
return sparse(A.I, A.J, A.V)
|
||||
end
|
||||
|
||||
function Base.push!(A::SparseMatrixIJV, I::Int, J::Int, V::Float64)
|
||||
push!(A.I, I)
|
||||
push!(A.J, J)
|
||||
@@ -63,3 +67,10 @@ function add!(A::SparseMatrixIJV, dofs1::Vector{Int}, dofs2::Vector{Int}, data::
|
||||
append!(A.V, vec(data))
|
||||
end
|
||||
|
||||
""" Sparse vector version. """
|
||||
function add!(A::SparseMatrixIJV, dofs::Vector{Int}, data::Array{Float64})
|
||||
append!(A.I, dofs)
|
||||
append!(A.J, ones(Int, length(dofs)))
|
||||
append!(A.V, vec(data))
|
||||
end
|
||||
|
||||
|
||||
@@ -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