Files
JuliaFEM.jl/src/problems.jl
T

196 lines
5.6 KiB
Julia
Raw Normal View History

# This file is a part of JuliaFEM.
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
2015-11-27 10:10:00 +02:00
abstract AbstractProblem
2016-02-03 06:49:42 +02:00
abstract FieldProblem <: AbstractProblem
abstract BoundaryProblem <: AbstractProblem
abstract MixedProblem <: AbstractProblem
2016-02-03 06:49:42 +02:00
"""
General linearized problem to solve
K*u + C1'*la = f
C2*u + D*la = g
"""
type Assembly
# for field assembly
M :: SparseMatrixCOO # mass matrix
K :: SparseMatrixCOO # stiffness matrix
f :: SparseMatrixCOO # force vector
# for boundary assembly
C1 :: SparseMatrixCOO
C2 :: SparseMatrixCOO
D :: SparseMatrixCOO
g :: SparseMatrixCOO
2016-02-03 06:49:42 +02:00
solution :: Vector{Float64} # full solution vector when solving problem Ax = b
previous_solution :: Vector{Float64} # previous solution vector
solution_norm_change :: Real # for convergence studies
prehooks :: Vector{Tuple{Symbol,Any,Any}} # assign possible prehooks before assembly
posthooks :: Vector{Tuple{Symbol,Any,Any}} # assign possible posthooks after assembly
2016-02-01 09:12:41 +02:00
changed :: Bool # flag to control is reassembly needed
end
2016-02-03 06:49:42 +02:00
function Assembly()
return Assembly(
SparseMatrixCOO(),
2016-02-01 09:12:41 +02:00
SparseMatrixCOO(),
SparseMatrixCOO(),
SparseMatrixCOO(),
2016-02-03 06:49:42 +02:00
SparseMatrixCOO(),
SparseMatrixCOO(),
SparseMatrixCOO(),
[], [], Inf,
[], [], true)
2016-02-01 09:12:41 +02:00
end
2016-02-03 06:49:42 +02:00
function Base.empty!(assembly::Assembly)
empty!(assembly.M)
empty!(assembly.K)
empty!(assembly.f)
empty!(assembly.C1)
empty!(assembly.C2)
empty!(assembly.D)
empty!(assembly.g)
2016-02-01 09:12:41 +02:00
assembly.changed = true
end
2016-02-03 06:49:42 +02:00
type Problem{P<:AbstractProblem}
name :: ASCIIString # descriptive name for problem
dimension :: Int # degrees of freedom per node
parent_field_name :: ASCIIString # (optional) name of parent field e.g. "displacement"
elements :: Vector{Element}
assembly :: Assembly
properties :: P
end
2016-02-01 09:12:41 +02:00
""" Construct a new field problem.
Examples
--------
Create vector-valued (dim=3) elasticity problem:
2016-02-03 06:49:42 +02:00
julia> prob = Problem(Elasticity, "this is my problem", 3)
"""
2016-02-03 06:49:42 +02:00
function Problem{P<:FieldProblem}(::Type{P}, name, dimension, elements=[])
Problem{P}(name, dimension, "none", elements, Assembly(), P())
2016-02-01 09:12:41 +02:00
end
2016-02-03 06:49:42 +02:00
""" Construct a new boundary problem.
2016-02-03 06:49:42 +02:00
Examples
--------
Create Dirichlet boundary problem for vector-valued (dim=3) elasticity problem.
2016-02-03 06:49:42 +02:00
julia> bc1 = Problem(Dirichlet, "support", 3, "displacement")
2016-02-01 09:12:41 +02:00
"""
2016-02-03 06:49:42 +02:00
function Problem{P<:BoundaryProblem}(::Type{P}, name, dimension, parent_field_name, elements=[])
Problem{P}(name, dimension, parent_field_name, elements, Assembly(), P())
2016-02-01 09:12:41 +02:00
end
2016-02-03 06:49:42 +02:00
function get_formulation_type{P<:FieldProblem}(problem::Problem{P})
return :total
2016-02-01 09:12:41 +02:00
end
2016-02-03 06:49:42 +02:00
function get_formulation_type{P<:BoundaryProblem}(problem::Problem{P})
return :total
2016-02-01 09:12:41 +02:00
end
2016-02-03 06:49:42 +02:00
function get_assembly(problem)
return problem.assembly
end
2016-02-01 09:12:41 +02:00
2016-02-03 06:49:42 +02:00
""" Update problem solution vector.
"""
2016-02-03 06:49:42 +02:00
function update!(problem::Problem, solution::Vector{Float64})
assembly = get_assembly(problem)
# resize & fill with zeros solution vector if length mismatch with current solution
if length(solution) != length(assembly.solution)
resize!(assembly.solution, length(solution))
fill!(assembly.solution, 0.0)
2016-02-01 09:12:41 +02:00
end
2016-02-03 06:49:42 +02:00
assembly.previous_solution = copy(assembly.solution)
if get_formulation_type(problem) == :incremental
assembly.solution += solution
2016-02-01 09:12:41 +02:00
else
2016-02-03 06:49:42 +02:00
assembly.solution = solution
2016-02-01 09:12:41 +02:00
end
2016-02-03 06:49:42 +02:00
assembly.solution_norm_change = norm(assembly.solution - assembly.previous_solution)
2016-02-01 09:12:41 +02:00
end
2016-02-01 09:12:41 +02:00
#=
function add_postprocessor!(problem::Union{FieldProblem, BoundaryProblem}, postprocessor_name::Symbol, args...; kwargs...)
push!(problem.postprocessors, (postprocessor_name, args, kwargs))
end
2016-01-02 00:17:01 +02:00
function add_preprocessor!(problem::Union{FieldProblem, BoundaryProblem}, preprocessor_name::Symbol, args...; kwargs...)
push!(problem.preprocessors, (preprocessor_name, args, kwargs))
end
2016-02-01 09:12:41 +02:00
=#
2016-02-03 06:49:42 +02:00
function get_elements(problem)
2015-11-27 10:10:00 +02:00
return problem.elements
2015-10-09 23:45:28 +03:00
end
2015-11-27 10:10:00 +02:00
""" Return the dimension of the unknown field of this problem. """
function get_unknown_field_dimension(problem::Problem)
2016-02-03 06:49:42 +02:00
return problem.dimension
2015-10-28 04:29:14 +02:00
end
2015-11-27 10:10:00 +02:00
""" Return the name of the unknown field of this problem. """
2016-02-01 09:12:41 +02:00
function get_unknown_field_name{P}(problem::Problem{P})
2015-11-27 10:10:00 +02:00
return get_unknown_field_name(P)
2015-10-28 04:29:14 +02:00
end
2016-02-03 06:49:42 +02:00
function push!(problem::Problem, element)
2015-11-27 10:10:00 +02:00
push!(problem.elements, element)
2015-10-28 04:29:14 +02:00
end
2015-12-17 15:33:51 +02:00
2016-02-03 06:49:42 +02:00
# TODO: better place for utility functions?
""" Calculate "nodal" vector from set of elements.
For example element 1 with dofs [1, 2, 3, 4] has [1, 1, 1, 1] and
element 2 with dofs [3, 4, 5, 6] has [2, 2, 2, 2] the result will
be sparse matrix with values [1, 1, 3, 3, 2, 2].
Parameters
----------
field_name
name of field, e.g. "geometry"
field_dim
degrees of freedom / node
elements
elements used to calculate vector
time
"""
2015-12-31 12:35:45 +02:00
function calculate_nodal_vector(field_name::ASCIIString, field_dim::Int, elements::Vector{Element}, time::Real)
A = SparseMatrixCOO()
b = SparseMatrixCOO()
for element in elements
haskey(element, field_name) || continue
gdofs = get_gdofs(element, 1)
for ip in get_integration_points(element, Val{2})
J = get_jacobian(element, ip, time)
w = ip.weight*norm(J)
f = element(field_name, ip, time)
N = element(ip, time)
add!(A, gdofs, gdofs, w*kron(N', N))
for dim=1:field_dim
add!(b, gdofs, w*f[dim]*N, dim)
end
end
end
A = sparse(A)
b = sparse(b)
nz = sort(unique(rowvals(A)))
x = zeros(size(b)...)
x[nz, :] = A[nz,nz] \ b[nz, :]
return vec(transpose(x))
end
2016-02-01 09:12:41 +02:00