2015-10-09 23:45:28 +03:00
|
|
|
# This file is a part of JuliaFEM.
|
|
|
|
|
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
|
|
|
|
|
|
|
|
|
# Solver stuff
|
|
|
|
|
|
|
|
|
|
abstract Solver
|
|
|
|
|
|
2015-10-28 04:29:14 +02:00
|
|
|
"""
|
|
|
|
|
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=Inf;
|
|
|
|
|
max_iterations::Int=10, tolerance::Float64=1.0e-12, dump_matrices::Bool=false)
|
|
|
|
|
element = get_element(equation)
|
|
|
|
|
x0 = element[unknown_field_name](-Inf)
|
|
|
|
|
x = zeros(prod(size(equation)))
|
|
|
|
|
dx = fill!(similar(x), 0.0)
|
|
|
|
|
la = initialize_local_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]
|
|
|
|
|
if dump_matrices
|
|
|
|
|
dump(full(A))
|
|
|
|
|
dump(full(b)')
|
|
|
|
|
end
|
|
|
|
|
dx[free_dofs] = A \ b
|
|
|
|
|
x += dx
|
|
|
|
|
new_field = similar(x0, x)
|
|
|
|
|
new_field.time = time
|
|
|
|
|
new_field.increment = i
|
|
|
|
|
push!(element[unknown_field_name], new_field)
|
|
|
|
|
if norm(dx) < tolerance
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
Logging.err("Did not converge in $max_iterations iterations")
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
Solve field equations for a single problem with some dofs fixed. This can be used
|
|
|
|
|
to test nonlinear element formulations. Dirichlet boundary is assumed to be homogeneous
|
|
|
|
|
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=Inf;
|
|
|
|
|
max_iterations::Int=10, tolerance::Float64=1.0e-12, dump_matrices::Bool=false)
|
|
|
|
|
ga = initialize_global_assembly(problem)
|
|
|
|
|
x = zeros(ga.ndofs)
|
|
|
|
|
dx = fill!(similar(x), 0.0)
|
|
|
|
|
field_name = get_unknown_field_name(problem)
|
|
|
|
|
dim = get_unknown_field_dimension(problem)
|
|
|
|
|
for i=1:max_iterations
|
|
|
|
|
calculate_global_assembly!(ga, problem)
|
|
|
|
|
A = ga.stiffness_matrix[free_dofs, free_dofs]
|
|
|
|
|
b = ga.force_vector[free_dofs]
|
|
|
|
|
if dump_matrices
|
|
|
|
|
dump(full(A))
|
|
|
|
|
dump(full(b)')
|
|
|
|
|
end
|
|
|
|
|
dx[free_dofs] = lufact(A) \ full(b)
|
|
|
|
|
x += dx
|
|
|
|
|
for equation in get_equations(problem)
|
|
|
|
|
element = get_element(equation)
|
|
|
|
|
conn = get_connectivity(element)
|
|
|
|
|
gdofs = vec(vcat([dim*conn'-i for i=dim-1:-1:0]...))
|
|
|
|
|
old_field = element[field_name](Inf)
|
|
|
|
|
new_field = similar(old_field, full(x[gdofs]))
|
2015-10-30 12:40:56 +02:00
|
|
|
push!(element[field_name][end], new_field)
|
2015-10-28 04:29:14 +02:00
|
|
|
end
|
|
|
|
|
if norm(dx) < tolerance
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
Logging.err("Did not converge in $max_iterations iterations")
|
|
|
|
|
end
|
|
|
|
|
|
2015-10-20 15:54:47 +03:00
|
|
|
""" Add new problem to solver. """
|
2015-10-09 23:45:28 +03:00
|
|
|
function add_problem!(solver::Solver, problem::Problem)
|
|
|
|
|
push!(solver.problems, problem)
|
|
|
|
|
end
|
2015-10-28 04:29:14 +02:00
|
|
|
|
2015-10-20 15:54:47 +03:00
|
|
|
function Base.push!(solver::Solver, problem::Problem)
|
|
|
|
|
push!(solver.problems, problem)
|
|
|
|
|
end
|
2015-10-09 23:45:28 +03:00
|
|
|
|
2015-10-28 04:29:14 +02:00
|
|
|
""" Get all problems assigned to solver. """
|
2015-10-09 23:45:28 +03:00
|
|
|
function get_problems(s::Solver)
|
|
|
|
|
return s.problems
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
## SimpleSolver -- tiny direct demo solver
|
|
|
|
|
""" Simple solver for educational purposes. """
|
|
|
|
|
type SimpleSolver <: Solver
|
|
|
|
|
problems
|
|
|
|
|
end
|
2015-10-28 04:29:14 +02:00
|
|
|
|
2015-10-09 23:45:28 +03:00
|
|
|
""" Default initializer. """
|
|
|
|
|
function SimpleSolver()
|
|
|
|
|
SimpleSolver(Problem[])
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
Call solver to solve a set of problems.
|
|
|
|
|
|
2015-10-28 04:29:14 +02:00
|
|
|
This is a simple direct solver for demonstration purposes. It handles the
|
2015-10-09 23:45:28 +03:00
|
|
|
common situation, i.e., some main field problem and it's Dirichlet boundary.
|
2015-10-28 04:29:14 +02:00
|
|
|
|
|
|
|
|
Au + C'λ = f
|
|
|
|
|
Cu = g
|
|
|
|
|
|
2015-10-09 23:45:28 +03:00
|
|
|
"""
|
2015-10-28 04:29:14 +02:00
|
|
|
function call(solver::SimpleSolver, time::Number=Inf)
|
|
|
|
|
p1, p2 = get_problems(solver)
|
|
|
|
|
|
|
|
|
|
ga1 = initialize_global_assembly(p1)
|
|
|
|
|
calculate_global_assembly!(ga1, p1)
|
|
|
|
|
ga2 = initialize_global_assembly(p2)
|
|
|
|
|
calculate_global_assembly!(ga2, p2)
|
|
|
|
|
|
|
|
|
|
A1 = ga1.stiffness_matrix
|
|
|
|
|
b1 = ga1.force_vector
|
|
|
|
|
A2 = ga2.stiffness_matrix
|
|
|
|
|
b2 = ga2.force_vector
|
|
|
|
|
|
|
|
|
|
# create a saddle point problem
|
2015-10-09 23:45:28 +03:00
|
|
|
A = [A1 A2; A2' zeros(A2)]
|
|
|
|
|
b = [b1; b2]
|
|
|
|
|
|
|
|
|
|
# solve problem
|
2015-10-28 04:29:14 +02:00
|
|
|
nz = unique(rowvals(A)) # here we remove any zero rows
|
2015-10-09 23:45:28 +03:00
|
|
|
x = zeros(b)
|
|
|
|
|
x[nz] = lufact(A[nz,nz]) \ full(b[nz])
|
|
|
|
|
|
|
|
|
|
# get "problem-wise" solution vectors
|
|
|
|
|
x1 = x[1:length(b1)]
|
|
|
|
|
x2 = x[length(b1)+1:end]
|
|
|
|
|
|
|
|
|
|
# update field for elements in problem 1
|
2015-10-28 04:29:14 +02:00
|
|
|
for equation in get_equations(p1)
|
2015-10-09 23:45:28 +03:00
|
|
|
element = get_element(equation)
|
2015-10-28 04:29:14 +02:00
|
|
|
field_name = get_unknown_field_name(p1)
|
|
|
|
|
gdofs = get_gdofs(p1, equation)
|
|
|
|
|
element_solution = full(x1[gdofs])
|
|
|
|
|
field = Field(time, element_solution)
|
2015-10-20 15:54:47 +03:00
|
|
|
push!(element[field_name], field)
|
2015-10-09 23:45:28 +03:00
|
|
|
end
|
|
|
|
|
|
2015-10-28 04:29:14 +02:00
|
|
|
# update field for elements in problem 2 (Dirichlet boundary)
|
|
|
|
|
for equation in get_equations(p2)
|
2015-10-09 23:45:28 +03:00
|
|
|
element = get_element(equation)
|
2015-10-28 04:29:14 +02:00
|
|
|
field_name = get_unknown_field_name(p2)
|
|
|
|
|
gdofs = get_gdofs(p2, equation)
|
|
|
|
|
element_solution = full(x2[gdofs])
|
|
|
|
|
field = Field(time, element_solution)
|
2015-10-20 15:54:47 +03:00
|
|
|
push!(element[field_name], field)
|
2015-10-09 23:45:28 +03:00
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|