2015-09-24 21:05:04 +03:00
|
|
|
# This file is a part of JuliaFEM.
|
|
|
|
|
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
|
|
|
|
|
2017-07-20 20:46:57 +03:00
|
|
|
abstract type AbstractProblem end
|
|
|
|
|
abstract type FieldProblem<:AbstractProblem end
|
|
|
|
|
abstract type BoundaryProblem<:AbstractProblem end
|
|
|
|
|
abstract type MixedProblem<:AbstractProblem end
|
2015-09-24 21:05:04 +03:00
|
|
|
|
2016-02-03 06:49:42 +02:00
|
|
|
"""
|
|
|
|
|
General linearized problem to solve
|
2017-01-09 08:56:31 +02:00
|
|
|
(K₁+K₂)Δu + C1'*Δλ = f₁+f₂
|
|
|
|
|
C2Δu + D*Δλ = g
|
2016-02-03 06:49:42 +02:00
|
|
|
"""
|
|
|
|
|
type Assembly
|
2016-06-27 16:11:33 +03:00
|
|
|
|
2016-02-03 06:49:42 +02:00
|
|
|
M :: SparseMatrixCOO # mass matrix
|
2016-06-27 16:11:33 +03:00
|
|
|
|
|
|
|
|
# for field assembly
|
|
|
|
|
K :: SparseMatrixCOO # stiffness matrix
|
2016-05-30 01:03:34 +03:00
|
|
|
Kg :: SparseMatrixCOO # geometric stiffness matrix
|
2016-06-27 16:11:33 +03:00
|
|
|
f :: SparseMatrixCOO # force vector
|
2016-08-04 13:15:19 +03:00
|
|
|
fg :: SparseMatrixCOO #
|
2016-06-27 16:11:33 +03:00
|
|
|
|
2016-02-03 06:49:42 +02:00
|
|
|
# for boundary assembly
|
|
|
|
|
C1 :: SparseMatrixCOO
|
|
|
|
|
C2 :: SparseMatrixCOO
|
2016-02-04 17:32:51 +02:00
|
|
|
D :: SparseMatrixCOO
|
2016-02-03 06:49:42 +02:00
|
|
|
g :: SparseMatrixCOO
|
2016-02-06 21:08:35 +02:00
|
|
|
c :: SparseMatrixCOO
|
2015-09-24 21:05:04 +03:00
|
|
|
|
2016-02-03 20:39:03 +02:00
|
|
|
u :: Vector{Float64} # solution vector u
|
|
|
|
|
u_prev :: Vector{Float64} # previous solution vector u
|
|
|
|
|
u_norm_change :: Real # change of norm in u
|
|
|
|
|
|
|
|
|
|
la :: Vector{Float64} # solution vector la
|
|
|
|
|
la_prev :: Vector{Float64} # previous solution vector u
|
|
|
|
|
la_norm_change :: Real # change of norm in la
|
|
|
|
|
|
2017-01-09 08:56:31 +02:00
|
|
|
removed_dofs :: Vector{Int64} # manually remove dofs from assembly
|
2015-09-24 21:05:04 +03:00
|
|
|
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(),
|
2016-02-06 21:08:35 +02:00
|
|
|
SparseMatrixCOO(),
|
2016-05-30 01:03:34 +03:00
|
|
|
SparseMatrixCOO(),
|
2016-06-27 16:11:33 +03:00
|
|
|
SparseMatrixCOO(),
|
2016-02-03 06:49:42 +02:00
|
|
|
[], [], Inf,
|
2017-01-09 08:56:31 +02:00
|
|
|
[], [], Inf,
|
|
|
|
|
[])
|
2016-02-01 09:12:41 +02:00
|
|
|
end
|
|
|
|
|
|
2016-05-30 01:03:34 +03:00
|
|
|
function empty!(assembly::Assembly)
|
2016-02-03 06:49:42 +02:00
|
|
|
empty!(assembly.K)
|
2016-05-30 01:03:34 +03:00
|
|
|
empty!(assembly.Kg)
|
2016-02-03 06:49:42 +02:00
|
|
|
empty!(assembly.f)
|
2016-06-27 16:11:33 +03:00
|
|
|
empty!(assembly.fg)
|
2016-02-03 06:49:42 +02:00
|
|
|
empty!(assembly.C1)
|
|
|
|
|
empty!(assembly.C2)
|
|
|
|
|
empty!(assembly.D)
|
|
|
|
|
empty!(assembly.g)
|
2016-02-06 21:08:35 +02:00
|
|
|
empty!(assembly.c)
|
2016-06-27 16:11:33 +03:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function isempty(assembly::Assembly)
|
|
|
|
|
T = isempty(assembly.K)
|
|
|
|
|
T &= isempty(assembly.Kg)
|
|
|
|
|
T &= isempty(assembly.f)
|
|
|
|
|
T &= isempty(assembly.fg)
|
|
|
|
|
T &= isempty(assembly.C1)
|
|
|
|
|
T &= isempty(assembly.C2)
|
|
|
|
|
T &= isempty(assembly.D)
|
|
|
|
|
T &= isempty(assembly.g)
|
|
|
|
|
T &= isempty(assembly.c)
|
|
|
|
|
return T
|
|
|
|
|
end
|
|
|
|
|
|
2016-02-03 06:49:42 +02:00
|
|
|
type Problem{P<:AbstractProblem}
|
2016-07-10 04:26:21 +03:00
|
|
|
name :: AbstractString # descriptive name for problem
|
2016-02-03 06:49:42 +02:00
|
|
|
dimension :: Int # degrees of freedom per node
|
2016-07-10 04:26:21 +03:00
|
|
|
parent_field_name :: AbstractString # (optional) name of parent field e.g. "displacement"
|
2016-02-03 06:49:42 +02:00
|
|
|
elements :: Vector{Element}
|
2016-05-28 21:39:29 +03:00
|
|
|
dofmap :: Dict{Element, Vector{Int64}} # connects element local dofs to global dofs
|
2016-02-03 06:49:42 +02:00
|
|
|
assembly :: Assembly
|
2016-08-04 13:15:19 +03:00
|
|
|
fields :: Dict{AbstractString, Field}
|
2017-03-21 08:36:18 +02:00
|
|
|
postprocess_fields :: Vector{String}
|
2016-02-03 06:49:42 +02:00
|
|
|
properties :: P
|
|
|
|
|
end
|
2016-02-01 09:12:41 +02:00
|
|
|
|
|
|
|
|
""" Construct a new field problem.
|
2016-01-01 18:52:40 +02:00
|
|
|
|
|
|
|
|
Examples
|
|
|
|
|
--------
|
|
|
|
|
Create vector-valued (dim=3) elasticity problem:
|
|
|
|
|
|
2016-06-27 16:11:33 +03:00
|
|
|
julia> prob1 = Problem(Elasticity, "this is my problem", 3)
|
|
|
|
|
julia> prob2 = Problem(Elasticity, 3)
|
2016-01-01 18:52:40 +02:00
|
|
|
|
|
|
|
|
"""
|
2016-07-10 04:26:21 +03:00
|
|
|
function Problem{P<:FieldProblem}(::Type{P}, name::AbstractString, dimension::Int64)
|
2017-03-21 08:36:18 +02:00
|
|
|
return Problem{P}(name, dimension, "none", [], Dict(), Assembly(), Dict(), Vector(), P())
|
2016-02-01 09:12:41 +02:00
|
|
|
end
|
2016-06-27 16:11:33 +03:00
|
|
|
function Problem{P<:FieldProblem}(::Type{P}, dimension::Int64)
|
2017-03-21 08:36:18 +02:00
|
|
|
return Problem(P, "$P problem", dimension)
|
2016-06-17 02:10:17 +03:00
|
|
|
end
|
2016-02-01 09:12:41 +02:00
|
|
|
|
2016-02-03 06:49:42 +02:00
|
|
|
""" Construct a new boundary problem.
|
2016-01-01 18:52:40 +02:00
|
|
|
|
2016-02-03 06:49:42 +02:00
|
|
|
Examples
|
|
|
|
|
--------
|
|
|
|
|
Create Dirichlet boundary problem for vector-valued (dim=3) elasticity problem.
|
2016-01-01 18:52:40 +02:00
|
|
|
|
2016-02-03 06:49:42 +02:00
|
|
|
julia> bc1 = Problem(Dirichlet, "support", 3, "displacement")
|
2016-08-04 13:15:19 +03:00
|
|
|
solver.
|
2016-02-01 09:12:41 +02:00
|
|
|
"""
|
2016-06-27 16:11:33 +03:00
|
|
|
function Problem{P<:BoundaryProblem}(::Type{P}, name, dimension, parent_field_name)
|
2017-03-21 08:36:18 +02:00
|
|
|
return Problem{P}(name, dimension, parent_field_name, [], Dict(), Assembly(), Dict(), Vector(), P())
|
2016-02-01 09:12:41 +02:00
|
|
|
end
|
2016-06-27 16:11:33 +03:00
|
|
|
function Problem{P<:BoundaryProblem}(::Type{P}, main_problem::Problem)
|
2016-06-17 02:10:17 +03:00
|
|
|
name = "$P problem"
|
|
|
|
|
dimension = get_unknown_field_dimension(main_problem)
|
|
|
|
|
parent_field_name = get_unknown_field_name(main_problem)
|
2017-03-21 08:36:18 +02:00
|
|
|
return Problem{P}(name, dimension, parent_field_name, [], Dict(), Assembly(), Dict(), Vector(), P())
|
2016-06-17 02:10:17 +03:00
|
|
|
end
|
2016-02-01 09:12:41 +02:00
|
|
|
|
2017-03-21 08:36:18 +02:00
|
|
|
function get_formulation_type(problem::Problem)
|
2016-06-19 20:01:37 +03:00
|
|
|
return :incremental
|
2016-02-01 09:12:41 +02:00
|
|
|
end
|
|
|
|
|
|
2017-03-21 08:36:18 +02:00
|
|
|
function get_unknown_field_name{P<:BoundaryProblem}(::Type{P})
|
|
|
|
|
return "lambda"
|
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
|
|
|
|
2017-08-05 13:26:19 +03:00
|
|
|
"""
|
|
|
|
|
update!(problem.properties, attr...)
|
|
|
|
|
|
|
|
|
|
Update properties for a problem.
|
|
|
|
|
|
|
|
|
|
# Example
|
|
|
|
|
|
|
|
|
|
```julia
|
|
|
|
|
update!(body.properties, "finite_strain" => "false")
|
|
|
|
|
```
|
|
|
|
|
"""
|
|
|
|
|
function update!{P<:AbstractProblem}(problem::P, attr::Pair{String, String}...)
|
|
|
|
|
for (name, value) in attr
|
|
|
|
|
debug("$P: set $name to $value")
|
|
|
|
|
setfield!(problem, parse(name), parse(value))
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2016-07-14 12:43:41 +03:00
|
|
|
""" Initialize element ready for calculation. """
|
|
|
|
|
function initialize!(problem::Problem, element::Element, time::Float64)
|
2016-02-03 20:39:03 +02:00
|
|
|
field_name = get_unknown_field_name(problem)
|
|
|
|
|
field_dim = get_unknown_field_dimension(problem)
|
2016-07-14 12:43:41 +03:00
|
|
|
nnodes = length(element)
|
|
|
|
|
|
|
|
|
|
# initialize primary field
|
|
|
|
|
if !haskey(element, field_name)
|
|
|
|
|
if field_dim == 1
|
|
|
|
|
update!(element, field_name, time => zeros(nnodes))
|
|
|
|
|
else
|
|
|
|
|
update!(element, field_name, time => [zeros(field_dim) for i=1:nnodes])
|
2016-02-03 20:39:03 +02:00
|
|
|
end
|
|
|
|
|
end
|
2016-07-14 12:43:41 +03:00
|
|
|
|
|
|
|
|
# if boundary problem, initialize field for main problem too
|
2016-02-04 17:32:51 +02:00
|
|
|
is_boundary_problem(problem) || return
|
|
|
|
|
field_name = get_parent_field_name(problem)
|
2016-07-14 12:43:41 +03:00
|
|
|
if !haskey(element, field_name)
|
|
|
|
|
if field_dim == 1
|
|
|
|
|
update!(element, field_name, time => zeros(nnodes))
|
|
|
|
|
else
|
|
|
|
|
update!(element, field_name, time => [zeros(field_dim) for i=1:nnodes])
|
2016-02-04 17:32:51 +02:00
|
|
|
end
|
|
|
|
|
end
|
2016-02-03 20:39:03 +02:00
|
|
|
end
|
|
|
|
|
|
2016-07-14 12:43:41 +03:00
|
|
|
function initialize!(problem::Problem, time::Float64=0.0)
|
|
|
|
|
for element in get_elements(problem)
|
|
|
|
|
initialize!(problem, element, time)
|
|
|
|
|
end
|
|
|
|
|
end
|
2016-02-03 20:39:03 +02:00
|
|
|
|
2016-07-14 12:43:41 +03:00
|
|
|
""" Update problem solution vector for assembly. """
|
2017-03-21 08:36:18 +02:00
|
|
|
function update!(problem::Problem, assembly::Assembly, u::Vector, la::Vector)
|
2016-02-03 20:39:03 +02:00
|
|
|
|
|
|
|
|
# resize & fill with zeros vectors if length mismatch with current solution
|
2016-07-14 12:43:41 +03:00
|
|
|
|
2016-02-03 20:39:03 +02:00
|
|
|
if length(u) != length(assembly.u)
|
2016-07-14 12:43:41 +03:00
|
|
|
info("resizing solution vector u")
|
2016-02-03 20:39:03 +02:00
|
|
|
resize!(assembly.u, length(u))
|
|
|
|
|
fill!(assembly.u, 0.0)
|
|
|
|
|
end
|
2016-07-14 12:43:41 +03:00
|
|
|
|
2016-02-03 20:39:03 +02:00
|
|
|
if length(la) != length(assembly.la)
|
2017-03-21 08:36:18 +02:00
|
|
|
info("resizing lagrange multiplier vector la")
|
2016-02-03 20:39:03 +02:00
|
|
|
resize!(assembly.la, length(la))
|
|
|
|
|
fill!(assembly.la, 0.0)
|
2016-02-01 09:12:41 +02:00
|
|
|
end
|
2016-02-03 20:39:03 +02:00
|
|
|
|
|
|
|
|
# copy current solutions to previous ones and add/replace new solution
|
2016-07-04 21:47:49 +03:00
|
|
|
# TODO: here we have couple of options and they need to be clarified
|
2016-06-17 02:10:17 +03:00
|
|
|
# for total formulation we are solving total quantity Ku = f while in
|
2016-02-24 01:20:39 +02:00
|
|
|
# incremental formulation we solve KΔu = f and u = u + Δu
|
2016-02-03 20:39:03 +02:00
|
|
|
assembly.u_prev = copy(assembly.u)
|
|
|
|
|
assembly.la_prev = copy(assembly.la)
|
2016-08-04 13:15:19 +03:00
|
|
|
|
2016-02-23 11:32:53 +02:00
|
|
|
if get_formulation_type(problem) == :total
|
|
|
|
|
assembly.u = u
|
|
|
|
|
assembly.la = la
|
|
|
|
|
elseif get_formulation_type(problem) == :incremental
|
2016-02-03 20:39:03 +02:00
|
|
|
assembly.u += u
|
2016-05-27 17:45:12 +03:00
|
|
|
assembly.la = la
|
2016-02-23 11:32:53 +02:00
|
|
|
elseif get_formulation_type(problem) == :forwarddiff
|
|
|
|
|
assembly.u += u
|
2016-02-24 01:20:39 +02:00
|
|
|
assembly.la += la
|
2016-02-03 20:39:03 +02:00
|
|
|
else
|
2016-02-23 11:32:53 +02:00
|
|
|
info("$(problem.name): unknown formulation type, don't know what to do with results")
|
|
|
|
|
error("serious failure with problem formulation: $(get_formulation_type(problem))")
|
2016-02-03 20:39:03 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
# calculate change of norm
|
|
|
|
|
assembly.u_norm_change = norm(assembly.u - assembly.u_prev)
|
|
|
|
|
assembly.la_norm_change = norm(assembly.la - assembly.la_prev)
|
2016-02-11 02:51:27 +02:00
|
|
|
return assembly.u, assembly.la
|
2016-02-03 20:39:03 +02:00
|
|
|
end
|
|
|
|
|
|
2016-07-14 12:43:41 +03:00
|
|
|
""" Return global solution (u, la) for problem.
|
2016-02-03 20:39:03 +02:00
|
|
|
|
|
|
|
|
Notes
|
|
|
|
|
-----
|
2016-08-04 13:15:19 +03:00
|
|
|
If length of solution vector != number of nodes, i.e. field dimension is
|
2016-07-14 12:43:41 +03:00
|
|
|
something other than 1, reshape vectors so it's length matches to the
|
|
|
|
|
number of nodes so that one can easily get nodal results.
|
2016-02-03 20:39:03 +02:00
|
|
|
"""
|
2016-07-14 12:43:41 +03:00
|
|
|
function get_global_solution(problem::Problem, assembly::Assembly)
|
|
|
|
|
u = assembly.u
|
|
|
|
|
la = assembly.la
|
2016-02-03 20:39:03 +02:00
|
|
|
field_dim = get_unknown_field_dimension(problem)
|
2016-07-14 12:43:41 +03:00
|
|
|
if field_dim == 1
|
|
|
|
|
return u, la
|
|
|
|
|
else
|
|
|
|
|
nnodes = round(Int, length(u)/field_dim)
|
|
|
|
|
u = reshape(u, field_dim, nnodes)
|
|
|
|
|
u = Vector{Float64}[u[:,i] for i in 1:nnodes]
|
|
|
|
|
la = reshape(la, field_dim, nnodes)
|
|
|
|
|
la = Vector{Float64}[la[:,i] for i in 1:nnodes]
|
|
|
|
|
return u, la
|
2016-02-03 20:39:03 +02:00
|
|
|
end
|
2016-02-04 17:32:51 +02:00
|
|
|
end
|
2016-07-14 12:43:41 +03:00
|
|
|
|
|
|
|
|
""" Update solution from assebly to elements. """
|
|
|
|
|
function update!{P<:FieldProblem}(problem::Problem{P}, assembly::Assembly, elements::Vector{Element}, time::Float64)
|
|
|
|
|
u, la = get_global_solution(problem, assembly)
|
2016-02-04 17:32:51 +02:00
|
|
|
field_name = get_unknown_field_name(problem)
|
2016-07-14 12:43:41 +03:00
|
|
|
# update solution u for elements
|
|
|
|
|
for element in elements
|
|
|
|
|
connectivity = get_connectivity(element)
|
|
|
|
|
update!(element, field_name, time => u[connectivity])
|
2016-02-04 17:32:51 +02:00
|
|
|
end
|
2016-07-14 12:43:41 +03:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function update!{P<:BoundaryProblem}(problem::Problem{P}, assembly::Assembly, elements::Vector{Element}, time::Float64)
|
|
|
|
|
u, la = get_global_solution(problem, assembly)
|
|
|
|
|
parent_field_name = get_parent_field_name(problem) # displacement
|
2017-03-21 08:36:18 +02:00
|
|
|
field_name = get_unknown_field_name(problem) # lambda
|
|
|
|
|
# update solution and lagrange multipliers for boundary elements
|
2016-07-14 12:43:41 +03:00
|
|
|
for element in elements
|
|
|
|
|
connectivity = get_connectivity(element)
|
|
|
|
|
update!(element, parent_field_name, time => u[connectivity])
|
2017-03-21 08:36:18 +02:00
|
|
|
update!(element, field_name, time => la[connectivity])
|
2016-02-01 09:12:41 +02:00
|
|
|
end
|
|
|
|
|
end
|
2016-01-01 20:34:10 +02:00
|
|
|
|
2016-07-03 05:01:18 +03:00
|
|
|
function get_elements(problem::Problem)
|
2015-11-27 10:10:00 +02:00
|
|
|
return problem.elements
|
2015-10-09 23:45:28 +03:00
|
|
|
end
|
|
|
|
|
|
2016-07-14 12:43:41 +03:00
|
|
|
function get_assembly(problem::Problem)
|
|
|
|
|
return problem.assembly
|
|
|
|
|
end
|
|
|
|
|
|
2016-07-03 05:01:18 +03:00
|
|
|
function length(problem::Problem)
|
|
|
|
|
return length(problem.elements)
|
|
|
|
|
end
|
|
|
|
|
|
2016-07-14 12:43:41 +03:00
|
|
|
function update!(problem::Problem, field_name::AbstractString, data)
|
2016-10-01 13:37:15 +03:00
|
|
|
#if haskey(problem.fields, field_name)
|
|
|
|
|
# update!(problem.fields[field_name], field_name::AbstractString, data)
|
|
|
|
|
#else
|
|
|
|
|
# problem.fields[field_name] = Field(data)
|
|
|
|
|
#end
|
2016-07-14 12:43:41 +03:00
|
|
|
update!(problem.elements, field_name::AbstractString, data)
|
2016-06-25 04:12:53 +03:00
|
|
|
end
|
|
|
|
|
|
2016-08-04 13:15:19 +03:00
|
|
|
function haskey(problem::Problem, field_name::AbstractString)
|
|
|
|
|
return haskey(problem.fields, field_name)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function getindex(problem::Problem, field_name::AbstractString)
|
|
|
|
|
return problem.fields[field_name]
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
""" Return field calculated to nodal points for elements in problem p. """
|
2016-11-13 13:24:08 +02:00
|
|
|
function (problem::Problem)(field_name::AbstractString, time::Float64=0.0)
|
2016-10-01 13:37:15 +03:00
|
|
|
#if haskey(problem, field_name)
|
|
|
|
|
# return problem[field_name](time)
|
|
|
|
|
#end
|
2016-08-04 13:15:19 +03:00
|
|
|
f = nothing
|
|
|
|
|
for element in get_elements(problem)
|
|
|
|
|
haskey(element, field_name) || continue
|
|
|
|
|
for (c, v) in zip(get_connectivity(element), element(field_name, time))
|
|
|
|
|
if f == nothing
|
|
|
|
|
f = Dict(c => v)
|
|
|
|
|
continue
|
|
|
|
|
end
|
|
|
|
|
if haskey(f, c)
|
|
|
|
|
if !isapprox(f[c], v)
|
|
|
|
|
info("several values for single node when returning field $field_name")
|
|
|
|
|
info("already have: $(f[c]), and trying to set $v")
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
f[c] = v
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
2016-10-01 13:37:15 +03:00
|
|
|
#f == nothing && return f
|
|
|
|
|
#update!(problem, field_name, time => f)
|
2016-08-04 13:15:19 +03:00
|
|
|
return f
|
|
|
|
|
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 20:39:03 +02:00
|
|
|
""" Return the name of the parent field of this (boundary) problem. """
|
|
|
|
|
function get_parent_field_name{P<:BoundaryProblem}(problem::Problem{P})
|
|
|
|
|
return problem.parent_field_name
|
2015-10-28 04:29:14 +02:00
|
|
|
end
|
2015-12-17 15:33:51 +02:00
|
|
|
|
2016-07-01 02:55:56 +03:00
|
|
|
function push!(problem::Problem, elements...)
|
|
|
|
|
push!(problem.elements, elements...)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function push!(problem::Problem, elements::Vector)
|
|
|
|
|
push!(problem.elements, elements...)
|
2015-12-31 07:40:38 +02:00
|
|
|
end
|
2016-02-05 11:31:23 +02:00
|
|
|
|
2016-07-03 05:01:18 +03:00
|
|
|
function push!(problem::Problem, elements_::Vector...)
|
|
|
|
|
for elements in elements_
|
|
|
|
|
push!(problem.elements, elements...)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2016-05-22 02:34:38 +03:00
|
|
|
function get_gdofs(element::Element, dim::Int)
|
|
|
|
|
conn = get_connectivity(element)
|
2016-05-28 21:39:29 +03:00
|
|
|
if length(conn) == 0
|
|
|
|
|
error("element connectivity not defined, cannot determine global dofs for element: $element")
|
|
|
|
|
end
|
|
|
|
|
gdofs = vec([dim*(i-1)+j for j=1:dim, i in conn])
|
2016-05-22 02:34:38 +03:00
|
|
|
return gdofs
|
|
|
|
|
end
|
|
|
|
|
|
2016-06-27 16:11:33 +03:00
|
|
|
function empty!(problem::Problem)
|
|
|
|
|
empty!(problem.assembly)
|
|
|
|
|
end
|
|
|
|
|
|
2016-05-28 21:39:29 +03:00
|
|
|
""" Return global degrees of freedom for element.
|
2016-05-22 02:34:38 +03:00
|
|
|
|
2016-05-28 21:39:29 +03:00
|
|
|
Notes
|
|
|
|
|
-----
|
|
|
|
|
First look dofs from problem.dofmap, it not found, update dofmap from
|
|
|
|
|
element.element connectivity using formula gdofs = [dim*(nid-1)+j for j=1:dim]
|
|
|
|
|
1. look element dofs from problem.dofmap
|
|
|
|
|
2. if not found, use element.connectivity to update dofmap and 1.
|
|
|
|
|
"""
|
2016-05-22 02:34:38 +03:00
|
|
|
function get_gdofs(problem::Problem, element::Element)
|
2016-05-30 01:03:34 +03:00
|
|
|
if !haskey(problem.dofmap, element)
|
2016-05-28 21:39:29 +03:00
|
|
|
dim = get_unknown_field_dimension(problem)
|
|
|
|
|
problem.dofmap[element] = get_gdofs(element, dim)
|
|
|
|
|
end
|
|
|
|
|
return problem.dofmap[element]
|
2016-05-22 02:34:38 +03:00
|
|
|
end
|