Files
JuliaFEM.jl/src/equations.jl
T

159 lines
5.8 KiB
Julia
Raw Normal View History

2015-08-31 20:15:28 +03:00
# This file is a part of JuliaFEM.
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
2015-10-28 04:29:14 +02:00
# Functions to handle element level things -- integration, assembly, ...
type Assembly
mass_matrix :: SparseMatrixIJV
stiffness_matrix :: SparseMatrixIJV
force_vector :: SparseMatrixIJV
end
2015-08-31 20:15:28 +03:00
function Assembly()
return Assembly(
SparseMatrixIJV(),
SparseMatrixIJV(),
SparseMatrixIJV())
2015-10-28 04:29:14 +02:00
end
function Base.empty!(assembly::Assembly)
empty!(assembly.mass_matrix)
empty!(assembly.stiffness_matrix)
empty!(assembly.force_vector)
2015-10-28 04:29:14 +02:00
end
function get_mass_matrix
2015-10-28 04:29:14 +02:00
end
function get_stiffness_matrix
2015-10-28 04:29:14 +02:00
end
function get_force_vector
2015-10-28 04:29:14 +02:00
end
function get_potential_energy
2015-10-28 04:29:14 +02:00
end
function get_residual_vector
2015-10-28 04:29:14 +02:00
end
2015-11-27 10:10:00 +02:00
function has_mass_matrix(problem::Problem, element::Element)
default_args = Tuple{typeof(problem), typeof(element), IntegrationPoint, Float64}
return method_exists(get_mass_matrix, default_args)
2015-10-28 04:29:14 +02:00
end
2015-11-27 10:10:00 +02:00
function has_stiffness_matrix(problem::Problem, element::Element)
default_args = Tuple{typeof(problem), typeof(element), IntegrationPoint, Float64}
return method_exists(get_stiffness_matrix, default_args)
2015-10-28 04:29:14 +02:00
end
2015-11-27 10:10:00 +02:00
function has_force_vector(problem::Problem, element::Element)
default_args = Tuple{typeof(problem), typeof(element), IntegrationPoint, Float64}
return method_exists(get_force_vector, default_args)
2015-10-28 04:29:14 +02:00
end
2015-11-27 10:10:00 +02:00
function has_potential_energy(problem::Problem, element::Element)
default_args = Tuple{typeof(problem), typeof(element), IntegrationPoint, Float64}
return method_exists(get_potential_energy, default_args)
2015-10-28 04:29:14 +02:00
end
2015-11-27 10:10:00 +02:00
function has_residual_vector(problem::Problem, element::Element)
default_args = Tuple{typeof(problem), typeof(element), IntegrationPoint, Float64}
return method_exists(get_residual_vector, default_args)
2015-10-28 04:29:14 +02:00
end
2015-11-18 01:19:04 +02:00
function get_gdofs(element::Element, dim::Int)
conn = get_connectivity(element)
gdofs = vec(vcat([dim*conn'-i for i=dim-1:-1:0]...))
return gdofs
end
""" Assemble element. """
2015-11-27 10:10:00 +02:00
function assemble!(assembly::Assembly, problem::Problem, element::Element, time::Number)
2015-11-27 10:10:00 +02:00
gdofs = get_gdofs(element, problem.dim)
unknown_field_name = get_unknown_field_name(problem)
# 1. if equations are defined we just integrate them, without caring how they are done
2015-11-27 10:10:00 +02:00
if has_mass_matrix(problem, element) || has_stiffness_matrix(problem, element) || has_force_vector(problem, element)
for ip in get_integration_points(element)
w = ip.weight*det(J)
2015-11-27 10:10:00 +02:00
if has_mass_matrix(element)
add!(assembly.mass_matrix, gdofs, gdofs, w*get_mass_matrix(problem, element, ip, time))
end
2015-11-27 10:10:00 +02:00
if has_stiffness_matrix(element)
add!(assembly.stiffness_matrix, gdofs, gdofs, w*get_stiffness_matrix(problem, element, ip, time))
end
2015-11-27 10:10:00 +02:00
if has_force_vector(element)
add!(assembly.force_vector, gdofs, w*get_force_vector(problem, element, ip, time))
end
end
2015-10-28 04:29:14 +02:00
# external loads -- if any nodal loads is defined add to force vector
if haskey(element, "$unknown_field_name nodal load")
add!(assembly.force_vector, gdofs, vec(element["$unknown_field_name nodal load"](time)))
2015-10-28 04:29:14 +02:00
end
end
# 2. energy form -- user has defined potential energy W -> min!
if has_potential_energy(problem, element) && haskey(element, unknown_field_name)
2015-10-27 06:37:58 +02:00
field = element[unknown_field_name](time)
""" Wrapper for potential energy for ForwardDiff. """
function calc_W(data::Vector)
W = 0.0
df = similar(field, data)
# integrate potential energy
2015-11-27 10:10:00 +02:00
for ip in get_integration_points(element)
dw = get_potential_energy(problem, element, ip, time; variation=df)
W += ip.weight*dw
end
# external energy -- if any nodal loads is defined, decrease from potential energy
2015-10-27 06:37:58 +02:00
if haskey(element, "$unknown_field_name nodal load")
P = element["$unknown_field_name nodal load"](time)
W -= dot(vec(P), vec(df))
end
return W[1]
end
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))
2015-08-31 20:15:28 +03:00
end
# 3. virtual work -- user has defined some residual r = p - f = 0
if has_residual_vector(problem, element) && haskey(element, unknown_field_name)
2015-11-21 18:23:41 +02:00
field = DVTI(last(element[unknown_field_name]).data)
""" Wrapper for virtual work for ForwardDiff. """
function calc_R(data::Vector)
R = zeros(length(data))
df = similar(field, data)
gauss_fields = IntegrationPoint[]
# integrate residual vector
2015-11-27 10:10:00 +02:00
for ip in get_integration_points(element)
dr = get_residual_vector(problem, element, ip, time; variation=df)
R += ip.weight*dr
if ip.changed
push!(gauss_fields, ip)
end
end
# external loads -- if any nodal loads is defined, decrease from residual
2015-10-27 06:37:58 +02:00
if haskey(element, "$unknown_field_name nodal load")
R -= vec(element["$unknown_field_name nodal load"](time))
end
2015-11-21 18:23:41 +02:00
#info("return = $R")
if length(gauss_fields) != 0
update_gauss_fields!(element, gauss_fields, time)
end
return R
end
2015-11-21 18:23:41 +02:00
jacobian, allresults = ForwardDiff.jacobian(calc_R, vec(field), AllResults, cache=autodiffcache)
2015-12-04 07:27:40 +02:00
residual_vector = -ForwardDiff.value(allresults)
add!(assembly.stiffness_matrix, gdofs, gdofs, jacobian)
2015-12-04 07:27:40 +02:00
add!(assembly.force_vector, gdofs, residual_vector)
end
2015-08-31 20:15:28 +03:00
end
2015-11-27 10:10:00 +02:00