more general way to define saddle point problem.

This commit is contained in:
Jukka Aho
2015-12-23 01:52:28 +02:00
parent a4548d5b5a
commit bba9d380fb
14 changed files with 1115 additions and 659 deletions
+20 -12
View File
@@ -25,6 +25,13 @@ function append!(assembly::Assembly, sub_assembly::Assembly)
append!(assembly.force_vector, sub_assembly.force_vector)
end
function append!(assembly::BoundaryAssembly, sub_assembly::BoundaryAssembly)
append!(assembly.C1, sub_assembly.C1)
append!(assembly.C2, sub_assembly.C2)
append!(assembly.D, sub_assembly.D)
append!(assembly.g, sub_assembly.g)
end
function assemble!(assembly::Assembly, problem::AllProblems, time::Float64, empty_assembly::Bool=true)
if empty_assembly
empty!(assembly)
@@ -34,17 +41,24 @@ function assemble!(assembly::Assembly, problem::AllProblems, time::Float64, empt
end
end
""" Decide assembly type from given problem type. """
function new_assembly{P}(problem_type::Type{FieldProblem{P}})
return FieldAssembly()
end
""" Decide assembly type from given problem type. """
function new_assembly{P}(problem_type::Type{BoundaryProblem{P}})
return BoundaryAssembly()
end
function assemble(problem::AllProblems, elrange::UnitRange{Int64}, time::Real, optimize=false)
elements = get_elements(problem)[elrange]
assembly = Assembly()
assembly = new_assembly(typeof(problem))
for (i, element) in enumerate(elements)
assemble!(assembly, problem, element, time)
end
if optimize
dim1 = length(assembly.stiffness_matrix.I)
optimize!(assembly)
dim2 = length(assembly.stiffness_matrix.I)
info("combine: dim1 = $dim1, dim2 = $dim2")
end
return assembly
end
@@ -53,11 +67,7 @@ function assemble(problem::AllProblems, time::Real, nchunks=10)
ne = length(get_elements(problem))
kk = round(Int, collect(linspace(0, ne, nchunks+1)))
slices = [kk[j]+1:kk[j+1] for j=1:nchunks]
# sub_assemblies = map( (elrange) -> assemble(problem, elrange, time), slices)
# assembly = sum(sub_assemblies)
assembly = Assembly()
assembly = new_assembly(typeof(problem))
for (j, elrange) in enumerate(slices)
sub_assembly = assemble(problem, elrange, time)
append!(assembly, sub_assembly)
@@ -65,9 +75,6 @@ function assemble(problem::AllProblems, time::Real, nchunks=10)
info("Assembly: ", round(j/nchunks*100,1), " % done. ")
end
end
# optimize!(assembly)
# dim = length(assembly.stiffness_matrix.I)
# info("dim of COO: $dim")
return assembly
end
@@ -173,3 +180,4 @@ function Base.(:+)(ass1::Assembly, ass2::Assembly)
force_vector = ass1.force_vector + ass2.force_vector
return Assembly(mass_matrix, stiffness_matrix, force_vector)
end
+31 -16
View File
@@ -38,11 +38,11 @@ function DirectSolver(name="DirectSolver")
1.0e-6, # convergence tolerance
false, # dump matrices
true, # reduce stiffness matrix
:CHOLMOD # method: CHOLMOD, UMFPACK, PETSc_GMRES
:UMFPACK # method: CHOLMOD, UMFPACK, PETSc_GMRES
)
end
function push!(solver::DirectSolver, problem::Problem)
function push!(solver::DirectSolver, problem::FieldProblem)
push!(solver.field_problems, problem)
end
@@ -138,9 +138,21 @@ function solve(K, f, C, g, ::Type{Val{:UMFPACK}})
return u[1:dim], u[dim+1:end]
end
function solve(K, f, C1, C2, D, g, ::Type{Val{:UMFPACK}})
t0 = time()
dim = size(K, 1)
A = [K C1'; C2 D]
b = [f; g]
nz1 = sort(unique(rowvals(A)))
nz2 = sort(unique(rowvals(A')))
u = zeros(length(b))
u[nz1] = lufact(A[nz1,nz2]) \ full(b[nz1])
info("UMFPACK: solved in ", time()-t0, " seconds. norm = ", norm(u[1:dim]))
return u[1:dim], u[dim+1:end]
end
""" Call solver to solve a set of problems. """
function call(solver::DirectSolver, time::Number=0.0)
function call(solver::DirectSolver, time::Real=0.0)
info("Starting solver $(solver.name)")
info("# of field problems: $(length(solver.field_problems))")
info("# of boundary problems: $(length(solver.boundary_problems))")
@@ -201,7 +213,7 @@ function call(solver::DirectSolver, time::Number=0.0)
tic(timing, "field assembly")
info("Assembling field problems...")
field_assembly = Assembly()
field_assembly = FieldAssembly()
for (i, problem) in enumerate(solver.field_problems)
info("Assembling body $i: $(problem.name)")
append!(field_assembly, assemble(problem, time))
@@ -216,36 +228,38 @@ function call(solver::DirectSolver, time::Number=0.0)
tic(timing, "boundary assembly")
info("Assembling boundary problems...")
boundary_assembly = Assembly()
boundary_assembly = BoundaryAssembly()
for (i, problem) in enumerate(solver.boundary_problems)
info("Assembling boundary $i: $(problem.name)")
append!(boundary_assembly, assemble(problem, time))
end
C = sparse(boundary_assembly.stiffness_matrix, dim, dim)
g = sparse(boundary_assembly.force_vector, dim, 1)
C1 = sparse(boundary_assembly.C1, dim, dim)
C2 = sparse(boundary_assembly.C2, dim, dim)
D = sparse(boundary_assembly.D, dim, dim)
g = sparse(boundary_assembly.g, dim, 1)
boundary_assembly = nothing
gc()
toc(timing, "boundary assembly")
# resize!(C, dim, dim)
# resize!(g, dim, 1)
# resize!(f, dim, 1)
tic(timing, "dump matrices to disk")
if solver.dump_matrices
filename = "matrices_$(solver.name)_host_$(myid())_iteration_$(iter).jld"
info("dumping matrices to disk, file = $filename")
save(filename, "stiffness matrix", K, "force vector", f,
"constraint matrix lhs", C, "constraint matrix rhs", g)
save(filename, "stiffness matrix K", K, "force vector f", f,
"constraint matrix C1", C1,
"constraint matrix C2", C2,
"constraint matrix D", D,
"constraint vector g", g)
end
toc(timing, "dump matrices to disk")
tic(timing, "solution of system")
info("Solving system")
gc()
# whos()
sol, la = solve(K, f, C, g, Val{solver.method})
# sol, la = solve(K, f, C, g, Val{solver.method})
sol, la = solve(K, f, C1, C2, D, g, Val{solver.method})
gc()
toc(timing, "solution of system")
@@ -297,3 +311,4 @@ function call(solver::DirectSolver, time::Number=0.0)
return (solver.max_iterations, false)
end
+7 -6
View File
@@ -10,7 +10,7 @@ function DirichletProblem(problem_name::ASCIIString, parent_field_name::ASCIIStr
return BoundaryProblem{DirichletProblem}(problem_name, parent_field_name, parent_field_dim, dim, elements)
end
function assemble!(assembly::Assembly, problem::BoundaryProblem{DirichletProblem}, element::Element, time::Number)
function assemble!(assembly::BoundaryAssembly, problem::BoundaryProblem{DirichletProblem}, element::Element, time::Real)
# get dimension and name of PARENT field
field_dim = problem.parent_field_dim
@@ -34,18 +34,19 @@ function assemble!(assembly::Assembly, problem::BoundaryProblem{DirichletProblem
for i=1:field_dim
g = element(field_name, ip, time)
ldofs = gdofs[i:field_dim:end]
add!(assembly.stiffness_matrix, ldofs, ldofs, A)
add!(assembly.force_vector, ldofs, w*g*N')
add!(assembly.C1, ldofs, ldofs, A)
add!(assembly.C2, ldofs, ldofs, A)
add!(assembly.g, ldofs, w*g*N')
end
end
for i=1:field_dim
# add per dof if defined element["blaa 1"] = 1.0, element["blaa 2"] = 0.0 etc.
if haskey(element, field_name*" $i")
g = element(field_name*" $i", ip, time)
ldofs = gdofs[i:field_dim:end]
add!(assembly.stiffness_matrix, ldofs, ldofs, A)
add!(assembly.force_vector, ldofs, w*g*N')
add!(assembly.C1, ldofs, ldofs, A)
add!(assembly.C2, ldofs, ldofs, A)
add!(assembly.g, ldofs, w*g*N')
end
end
end
+3
View File
@@ -24,6 +24,9 @@ end
function PlaneStressElasticityProblem(dim::Int=2, elements=[])
return Problem{PlaneStressElasticityProblem}("plane stress elasticity problem", dim, elements)
end
function PlaneStressElasticityProblem(problem_name::ASCIIString, dim::Int=2, elements=[])
return Problem{PlaneStressElasticityProblem}(problem_name, dim, elements)
end
""" Elasticity equations.
+31 -9
View File
@@ -3,17 +3,39 @@
# Functions to handle element level things -- integration, assembly, ...
type Assembly
mass_matrix :: SparseMatrixIJV
stiffness_matrix :: SparseMatrixIJV
force_vector :: SparseMatrixIJV
type FieldAssembly
mass_matrix :: SparseMatrixCOO
stiffness_matrix :: SparseMatrixCOO
force_vector :: SparseMatrixCOO
end
function Assembly()
return Assembly(
SparseMatrixIJV(),
SparseMatrixIJV(),
SparseMatrixIJV())
function FieldAssembly()
return FieldAssembly(
SparseMatrixCOO(),
SparseMatrixCOO(),
SparseMatrixCOO())
end
typealias Assembly FieldAssembly
"""
"Boundary" matrices C₁, C₂, D, g for general problem type
Au + C₁'λ = f
C₂u + Dλ = g
"""
type BoundaryAssembly
C1 :: SparseMatrixCOO
C2 :: SparseMatrixCOO
D :: SparseMatrixCOO
g :: SparseMatrixCOO
end
function BoundaryAssembly()
return BoundaryAssembly(
SparseMatrixCOO(),
SparseMatrixCOO(),
SparseMatrixCOO(),
SparseMatrixCOO())
end
function Base.empty!(assembly::Assembly)
+16 -15
View File
@@ -662,7 +662,7 @@ end
typealias MortarElements2D Union{Seg2, Seg3}
function assemble!{E<:MortarElements2D}(assembly::Assembly, problem::BoundaryProblem{MortarProblem}, slave_element::Element{E}, time::Real)
function assemble!{E<:MortarElements2D}(assembly::BoundaryAssembly, problem::BoundaryProblem{MortarProblem}, slave_element::Element{E}, time::Real)
# get dimension and name of PARENT field
field_dim = problem.parent_field_dim
@@ -675,13 +675,14 @@ function assemble!{E<:MortarElements2D}(assembly::Assembly, problem::BoundaryPro
xi1b = project_from_master_to_slave(slave_element, master_element, [ 1.0])
xi1 = clamp([xi1a xi1b], -1.0, 1.0)
l = 1/2*(xi1[2]-xi1[1])
if abs(l) < 1.0e-6
warn("No contribution")
if abs(l) < 1.0e-9
#warn("No contribution")
continue # no contribution
end
master_dofs = get_gdofs(master_element, field_dim)
for ip in get_integration_points(slave_element, Val{5})
w = ip.weight*det(slave_element, ip, time)*l
J = get_jacobian(slave_element, ip, time)
w = ip.weight*norm(J)*l
# integration point on slave side segment
xi_gauss = 1/2*(1-ip.xi)*xi1[1] + 1/2*(1+ip.xi)*xi1[2]
@@ -692,15 +693,14 @@ function assemble!{E<:MortarElements2D}(assembly::Assembly, problem::BoundaryPro
N1 = slave_element(xi_gauss, time)
N2 = master_element(xi_projected, time)
S = w*N1'*N1
M = w*(N1'*N2)'
# M = w*N1'*N2
# FIXME: why this needs now to be transpose?
# assembly / repeat
M = w*N1'*N2
for i=1:field_dim
sd = slave_dofs[i:field_dim:end]
md = master_dofs[i:field_dim:end]
add!(assembly.stiffness_matrix, sd, sd, S)
add!(assembly.stiffness_matrix, sd, md, -M)
add!(assembly.C1, sd, sd, S)
add!(assembly.C1, sd, md, -M)
add!(assembly.C2, sd, sd, S)
add!(assembly.C2, sd, md, -M)
end
end
@@ -735,7 +735,7 @@ function find_master_elements(slave_element::Element, time::Real)
return master_elements
end
function assemble!{E<:MortarElements3D}(assembly::Assembly, problem::BoundaryProblem{MortarProblem}, slave_element::Element{E}, time::Real)
function assemble!{E<:MortarElements3D}(assembly::BoundaryAssembly, problem::BoundaryProblem{MortarProblem}, slave_element::Element{E}, time::Real)
field_dim = problem.parent_field_dim
field_name = problem.parent_field_name
slave_dofs = get_gdofs(slave_element, field_dim)
@@ -893,13 +893,14 @@ function assemble!{E<:MortarElements3D}(assembly::Assembly, problem::BoundaryPro
@debug info("weight S = $wS, weight M = $wM, weight C = $wC")
Sm = ip.weight*N1'*N1*wC
# FIXME: master side transpose -- why?
Mm = ip.weight*(N1'*N2)'*wC
Mm = ip.weight*N1'*N2*wC
for k=1:field_dim
sd = slave_dofs[k:field_dim:end]
md = master_dofs[k:field_dim:end]
add!(assembly.stiffness_matrix, sd, sd, Sm)
add!(assembly.stiffness_matrix, sd, md, -Mm)
add!(assembly.C1, sd, sd, Sm)
add!(assembly.C1, sd, md, -Mm)
add!(assembly.C2, sd, sd, Sm)
add!(assembly.C2, sd, md, -Mm)
end
end
# info("breaking on first")
+3 -3
View File
@@ -3,7 +3,7 @@
abstract AbstractProblem
type Problem{T<:AbstractProblem}
type FieldProblem{T<:AbstractProblem}
name :: ASCIIString
dim :: Int
elements :: Vector{Element}
@@ -17,9 +17,9 @@ type BoundaryProblem{T<:AbstractProblem}
elements :: Vector{Element}
end
typealias FieldProblem Problem
typealias Problem FieldProblem
typealias AllProblems Union{Problem, BoundaryProblem}
typealias AllProblems Union{FieldProblem, BoundaryProblem}
function get_elements(problem::AllProblems)
return problem.elements
+12 -5
View File
@@ -4,16 +4,23 @@
# Sparse utils to make assembly of local and global matrices easier.
# Unoptimized but should do all necessary stuff for at start.
type SparseMatrixIJV
type SparseMatrixCOO
I :: Vector{Int}
J :: Vector{Int}
V :: Vector{Float64}
end
typealias SparseMatrixCOO SparseMatrixIJV
typealias SparseMatrixIJV SparseMatrixCOO
#=
function SparseMatrixIJV()
SparseMatrixIJV([], [], [])
warn("use SparseMatrixCOO to construct sparse matrix.""")
SparseMatrixCOO([], [], [])
end
=#
function SparseMatrixCOO()
SparseMatrixCOO([], [], [])
end
function Base.sparse(A::SparseMatrixIJV, args...)
@@ -85,8 +92,8 @@ Example
"""
function add!(A::SparseMatrixIJV, dofs1::Vector{Int}, dofs2::Vector{Int}, data::Matrix{Float64})
n, m = size(data)
for i=1:n
for j=1:m
for j=1:m
for i=1:n
push!(A.I, dofs1[i])
push!(A.J, dofs2[j])
end
+6 -1
View File
@@ -1,7 +1,12 @@
# This file is a part of JuliaFEM.
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
using BaseTestNext
if VERSION >= v"0.5-"
using Base.Test
else
using BaseTestNext
end
abstract TestResult
+1
View File
@@ -37,6 +37,7 @@ using LightXML
# > #define XDMF_3DCORECTMESH 0x1102
global eltypes = Dict{Symbol, Int}(
:Tri3 => 0x4,
:Quad4 => 0x5,
:Tet4 => 0x6,
:Hex8 => 0x9,