mirror of
https://github.com/JuliaFEM/JuliaFEM.jl.git
synced 2026-09-23 11:02:36 +00:00
more general way to define saddle point problem.
This commit is contained in:
+20
-12
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ using LightXML
|
||||
# > #define XDMF_3DCORECTMESH 0x1102
|
||||
|
||||
global eltypes = Dict{Symbol, Int}(
|
||||
:Tri3 => 0x4,
|
||||
:Quad4 => 0x5,
|
||||
:Tet4 => 0x6,
|
||||
:Hex8 => 0x9,
|
||||
|
||||
Reference in New Issue
Block a user