mirror of
https://github.com/JuliaFEM/JuliaFEM.jl.git
synced 2026-09-20 10:08:31 +00:00
2d mortar
This commit is contained in:
@@ -34,6 +34,7 @@ export @debug, set_debug_on!, set_debug_off!
|
||||
|
||||
using ForwardDiff
|
||||
autodiffcache = ForwardDiffCache()
|
||||
export derivative, jacobian, hessian
|
||||
|
||||
""" Simple linspace extension to arrays.
|
||||
|
||||
@@ -60,6 +61,7 @@ include("types.jl") # type definitions
|
||||
include("elements.jl")
|
||||
include("lagrange.jl") # Lagrange elements
|
||||
#include("hierarchical.jl") # P-elements
|
||||
include("mortar_elements.jl") # Mortar elements
|
||||
|
||||
### EQUATIONS ###
|
||||
include("integrate.jl") # default integration points for elements
|
||||
@@ -69,6 +71,7 @@ include("problems.jl")
|
||||
|
||||
### FORMULATIION ###
|
||||
include("dirichlet.jl")
|
||||
include("mortar.jl") # mortar projection
|
||||
include("heat.jl")
|
||||
include("elasticity.jl")
|
||||
|
||||
|
||||
+28
-20
@@ -15,7 +15,7 @@ type DirichletProblem <: BoundaryProblem
|
||||
unknown_field_name :: ASCIIString
|
||||
unknown_field_dimension :: Int
|
||||
equations :: Vector{DirichletEquation}
|
||||
element_mapping :: Dict{Element, Equation}
|
||||
# element_mapping :: Dict{DataType, DataType}
|
||||
field_value :: Function
|
||||
end
|
||||
|
||||
@@ -36,14 +36,15 @@ Create u(X) = 0.0 boundary condition for three-dimensional elasticity problem:
|
||||
>>> u(X) = [0.0, 0.0, 0.0]
|
||||
>>> bc = DirichletProblem(3, u)
|
||||
"""
|
||||
function DirichletProblem(dimension::Int=1, field_value::Function=(X)->[0.0,0.0,0.0])
|
||||
element_mapping = nothing
|
||||
if dimension == 1
|
||||
element_mapping = Dict(
|
||||
Seg2 => DBC2D2
|
||||
)
|
||||
end
|
||||
DirichletProblem("reaction force", dimension, [], element_mapping, field_value)
|
||||
function DirichletProblem(dimension::Int=1, field_value::Function=(X)->[0.0,0.0,0.0], equations=[])
|
||||
# element_mapping = nothing
|
||||
# if dimension == 1
|
||||
# element_mapping = Dict(
|
||||
# Seg2 => DBC2D2
|
||||
# )
|
||||
# end
|
||||
DirichletProblem("reaction force", dimension, equations, field_value)
|
||||
# DirichletProblem("reaction force", dimension, [], element_mapping, field_value)
|
||||
end
|
||||
|
||||
""" Dirichlet boundary condition element for 2 node line segment """
|
||||
@@ -51,17 +52,22 @@ type DBC2D2 <: DirichletEquation
|
||||
element :: Seg2
|
||||
integration_points :: Vector{IntegrationPoint}
|
||||
end
|
||||
function DBC2D2(element::Seg2)
|
||||
integration_points = default_integration_points(element)
|
||||
if !haskey(element, "reaction force")
|
||||
element["reaction force"] = zeros(1, 2)
|
||||
end
|
||||
|
||||
function Base.size(equation::DBC2D2)
|
||||
return (1, 2)
|
||||
end
|
||||
|
||||
#function DBC2D2(element::Seg2)
|
||||
function Base.convert(::Type{DirichletEquation}, element::Seg2)
|
||||
integration_points = line3()
|
||||
haskey(element, "reaction force") || (element["reaction force"] = zeros(1, 2))
|
||||
DBC2D2(element, integration_points)
|
||||
end
|
||||
Base.size(equation::DBC2D2) = (1, 2)
|
||||
|
||||
|
||||
function assemble!(assembly::Assembly, equation::DirichletEquation, time::Number=0.0, problem=nothing)
|
||||
gdofs = get_gdofs(equation)
|
||||
# info("gdofs = $gdofs")
|
||||
element = get_element(equation)
|
||||
basis = get_basis(element)
|
||||
detJ = det(basis)
|
||||
@@ -69,11 +75,13 @@ function assemble!(assembly::Assembly, equation::DirichletEquation, time::Number
|
||||
w = ip.weight * detJ(ip)
|
||||
N = basis(ip, time)
|
||||
add!(assembly.stiffness_matrix, gdofs, gdofs, w*N'*N)
|
||||
if !isa(problem, Void)
|
||||
X = basis("geometry", ip, time)
|
||||
u = problem.field_value(X)
|
||||
add!(assembly.force_vector, gdofs, w*N'*u)
|
||||
end
|
||||
# info("added $(w*N'*N)")
|
||||
# if !isa(problem, Void)
|
||||
# X = basis("geometry", ip, time)
|
||||
# u = problem.field_value(X)[1:length(gdofs)]
|
||||
# add!(assembly.force_vector, gdofs, w*N'*u)
|
||||
# end
|
||||
end
|
||||
# info("assembly done")
|
||||
end
|
||||
|
||||
|
||||
+50
-20
@@ -19,8 +19,7 @@ Saint Venant-Kirchhoff material model, which is simply
|
||||
|
||||
S(E) = λtr(E) + 2μE
|
||||
"""
|
||||
function get_internal_energy(equation::Equation, ip::IntegrationPoint,
|
||||
time::Number, F::Matrix)
|
||||
function get_internal_energy(equation::ElasticityEquation, ip::IntegrationPoint, time::Number, F::Matrix)
|
||||
element = get_element(equation)
|
||||
basis = get_basis(element)
|
||||
dbasis = grad(basis)
|
||||
@@ -72,8 +71,7 @@ https://en.wikipedia.org/wiki/Plane_stress
|
||||
https://en.wikipedia.org/wiki/Hooke's_law
|
||||
|
||||
"""
|
||||
function get_residual_vector(equation::ElasticityEquation, ip::IntegrationPoint,
|
||||
time::Number; variation=nothing)
|
||||
function get_residual_vector(equation::ElasticityEquation, ip::IntegrationPoint, time::Number; variation=nothing)
|
||||
|
||||
element = get_element(equation)
|
||||
basis = get_basis(element)
|
||||
@@ -82,9 +80,10 @@ function get_residual_vector(equation::ElasticityEquation, ip::IntegrationPoint,
|
||||
u = basis("displacement", ip, time, variation)
|
||||
gradu = dbasis("displacement", ip, time, variation)
|
||||
F = I + gradu # deformation gradient
|
||||
|
||||
#info("Deformation gradient: $F")
|
||||
# residual vector - internal energy
|
||||
r = get_internal_energy(equation, ip, time, F)
|
||||
#info("boundary element")
|
||||
|
||||
# external forces - volume load
|
||||
if haskey(element, "displacement load")
|
||||
@@ -94,40 +93,71 @@ function get_residual_vector(equation::ElasticityEquation, ip::IntegrationPoint,
|
||||
|
||||
return vec(r)
|
||||
end
|
||||
has_residual_vector(equation::ElasticityEquation) = true
|
||||
|
||||
### Problem 1 - plane elasticity ###
|
||||
### Plane stress elasticity ###
|
||||
|
||||
abstract PlaneElasticityProblem <: ElasticityProblem
|
||||
abstract PlaneStressElasticityEquation <: ElasticityEquation
|
||||
|
||||
type PlaneStressElasticityProblem <: PlaneElasticityProblem
|
||||
unknown_field_name :: ASCIIString
|
||||
unknown_field_dimension :: Int
|
||||
equations :: Array{ElasticityEquation, 1}
|
||||
element_mapping :: Dict{DataType, DataType}
|
||||
equations :: Vector{PlaneStressElasticityEquation}
|
||||
end
|
||||
|
||||
function PlaneStressElasticityProblem(equations=[])
|
||||
element_mapping = Dict(
|
||||
Quad4 => CPS4)
|
||||
return PlaneStressElasticityProblem("displacement", 2, equations, element_mapping)
|
||||
return PlaneStressElasticityProblem("displacement", 2, equations)
|
||||
end
|
||||
|
||||
### Equations ###
|
||||
|
||||
abstract PlaneElasticityEquation <: ElasticityEquation
|
||||
abstract PlaneStressElasticityEquation <: PlaneElasticityEquation
|
||||
|
||||
""" 4-node plane stress element. """
|
||||
type CPS4 <: PlaneStressElasticityEquation
|
||||
element :: Quad4
|
||||
integration_points :: Array{IntegrationPoint, 1}
|
||||
end
|
||||
function CPS4(element::Quad4)
|
||||
|
||||
function Base.size(equation::CPS4)
|
||||
return (2, 4)
|
||||
end
|
||||
|
||||
function Base.convert(::Type{PlaneStressElasticityEquation}, element::Quad4)
|
||||
integration_points = get_default_integration_points(element)
|
||||
if !haskey(element, "displacement")
|
||||
element["displacement"] = zeros(2, 4)
|
||||
end
|
||||
haskey(element, "displacement") || (element["displacement"] = zeros(2, 4))
|
||||
CPS4(element, integration_points)
|
||||
end
|
||||
Base.size(equation::CPS4) = (2, 4)
|
||||
|
||||
""" Boundary element for plane stress problem for surface loads. """
|
||||
type CPS2 <: PlaneStressElasticityEquation
|
||||
element :: Seg2
|
||||
integration_points :: Vector{IntegrationPoint}
|
||||
end
|
||||
|
||||
function Base.size(equation::CPS2)
|
||||
return (2, 2)
|
||||
end
|
||||
|
||||
function Base.convert(::Type{PlaneStressElasticityEquation}, element::Seg2)
|
||||
integration_points = get_default_integration_points(element)
|
||||
haskey(element, "displacement") || (element["displacement"] = zeros(2, 2))
|
||||
CPS2(element, integration_points)
|
||||
end
|
||||
|
||||
function get_residual_vector(equation::CPS2, ip::IntegrationPoint, time::Number; variation=nothing)
|
||||
|
||||
element = get_element(equation)
|
||||
basis = get_basis(element)
|
||||
|
||||
u = basis("displacement", ip, time, variation)
|
||||
r = zeros(size(equation))
|
||||
|
||||
if haskey(element, "displacement traction force")
|
||||
T = basis("displacement traction force", ip, time)
|
||||
# info("traction force = $T")
|
||||
# info("basis = $(basis(ip, time))")
|
||||
r -= T*basis(ip, time)
|
||||
end
|
||||
|
||||
return vec(r)
|
||||
end
|
||||
|
||||
|
||||
@@ -97,6 +97,12 @@ function get_gdofs(equation::Equation)
|
||||
return gdofs
|
||||
end
|
||||
|
||||
function get_gdofs(element::Element, dim::Int)
|
||||
conn = get_connectivity(element)
|
||||
gdofs = vec(vcat([dim*conn'-i for i=dim-1:-1:0]...))
|
||||
return gdofs
|
||||
end
|
||||
|
||||
""" Assemble element. """
|
||||
function assemble!(assembly::Assembly, equation::Equation, time::Number=0.0, problem=nothing)
|
||||
|
||||
|
||||
+22
-22
@@ -72,46 +72,46 @@ end
|
||||
""" Diffusive heat transfer for 4-node bilinear element. """
|
||||
type DC2D4 <: HeatEquation
|
||||
element :: Quad4
|
||||
integration_points :: Array{IntegrationPoint, 1}
|
||||
integration_points :: Vector{IntegrationPoint}
|
||||
end
|
||||
function DC2D4(element::Quad4)
|
||||
integration_points = get_default_integration_points(element)
|
||||
if !haskey(element, "temperature")
|
||||
element["temperature"] = zeros(4)
|
||||
end
|
||||
DC2D4(element, integration_points)
|
||||
|
||||
function Base.size(equation::DC2D4)
|
||||
return (1, 4)
|
||||
end
|
||||
Base.size(equation::DC2D4) = (1, 4)
|
||||
|
||||
""" Diffusive heat transfer for 2-node linear segment. """
|
||||
type DC2D2 <: HeatEquation
|
||||
element :: Seg2
|
||||
integration_points :: Vector{IntegrationPoint}
|
||||
end
|
||||
function DC2D2(element::Seg2)
|
||||
|
||||
function Base.size(equation::DC2D2)
|
||||
return (1, 2)
|
||||
end
|
||||
|
||||
# Conversions element -> equation
|
||||
|
||||
function Base.convert(::Type{HeatEquation}, element::Quad4)
|
||||
integration_points = get_default_integration_points(element)
|
||||
if !haskey(element, "temperature")
|
||||
element["temperature"] = zeros(2)
|
||||
end
|
||||
haskey(element, "temperature") || (element["temperature"] = zeros(4))
|
||||
DC2D4(element, integration_points)
|
||||
end
|
||||
|
||||
function Base.convert(::Type{HeatEquation}, element::Seg2)
|
||||
integration_points = get_default_integration_points(element)
|
||||
haskey(element, "temperature") || (element["temperature"] = zeros(2))
|
||||
DC2D2(element, integration_points)
|
||||
end
|
||||
Base.size(equation::DC2D2) = (1, 2)
|
||||
|
||||
### Problems ###
|
||||
|
||||
type PlaneHeatProblem <: HeatProblem
|
||||
unknown_field_name :: ASCIIString
|
||||
unknown_field_dimension :: Int
|
||||
equations :: Vector{Equation}
|
||||
#element_mapping :: Dict{Element, Equation}
|
||||
# FIXME: Why is not working ^
|
||||
element_mapping :: Dict{Any, Any}
|
||||
equations :: Vector{HeatEquation}
|
||||
end
|
||||
|
||||
""" Default constructor for problem takes no arguments. """
|
||||
function PlaneHeatProblem()
|
||||
element_mapping = Dict(
|
||||
Quad4 => DC2D4,
|
||||
Seg2 => DC2D2)
|
||||
return PlaneHeatProblem("temperature", 1, [], element_mapping)
|
||||
function PlaneHeatProblem(equations=[])
|
||||
return PlaneHeatProblem("temperature", 1, equations)
|
||||
end
|
||||
|
||||
+24
-26
@@ -11,12 +11,20 @@ function get_default_integration_points(element::Quad4)
|
||||
]
|
||||
end
|
||||
|
||||
function get_default_integration_points(element::Seg2)
|
||||
|
||||
function line1()
|
||||
[
|
||||
IntegrationPoint([0.0], 2.0)
|
||||
]
|
||||
end
|
||||
|
||||
function line2()
|
||||
[
|
||||
IntegrationPoint([-sqrt(1/3)], 1)
|
||||
IntegrationPoint([+sqrt(1/3)], 1)
|
||||
]
|
||||
end
|
||||
|
||||
function line3()
|
||||
[
|
||||
IntegrationPoint([0.0], 8/9),
|
||||
@@ -25,6 +33,15 @@ function line3()
|
||||
]
|
||||
end
|
||||
|
||||
function line4()
|
||||
[
|
||||
IntegrationPoint([+sqrt(3/7 - 2/7*sqrt(6/5))], (18+sqrt(30))/36)
|
||||
IntegrationPoint([-sqrt(3/7 - 2/7*sqrt(6/5))], (18+sqrt(30))/36)
|
||||
IntegrationPoint([+sqrt(3/7 + 2/7*sqrt(6/5))], (18-sqrt(30))/36)
|
||||
IntegrationPoint([-sqrt(3/7 + 2/7*sqrt(6/5))], (18-sqrt(30))/36)
|
||||
]
|
||||
end
|
||||
|
||||
function line5()
|
||||
[
|
||||
IntegrationPoint([-1/3*sqrt(5 + 2*sqrt(10/7))], (322-13*sqrt(70))/900),
|
||||
@@ -35,29 +52,10 @@ function line5()
|
||||
]
|
||||
end
|
||||
|
||||
#integration_points = [
|
||||
# IntegrationPoint([ 0.0000000000000000], 0.5688888888888889),
|
||||
# IntegrationPoint([-0.5384693101056831], 0.4786286704993665),
|
||||
# IntegrationPoint([ 0.5384693101056831], 0.4786286704993665),
|
||||
# IntegrationPoint([-0.9061798459386640], 0.2369268850561891),
|
||||
# IntegrationPoint([ 0.9061798459386640], 0.2369268850561891)
|
||||
#]
|
||||
#integration_points = [
|
||||
# IntegrationPoint([+sqrt(3/7 - 2/7*sqrt(6/5))], (18+sqrt(30))/36)
|
||||
# IntegrationPoint([-sqrt(3/7 - 2/7*sqrt(6/5))], (18+sqrt(30))/36)
|
||||
# IntegrationPoint([+sqrt(3/7 + 2/7*sqrt(6/5))], (18-sqrt(30))/36)
|
||||
# IntegrationPoint([-sqrt(3/7 + 2/7*sqrt(6/5))], (18-sqrt(30))/36)
|
||||
#]
|
||||
#integration_points = [
|
||||
# IntegrationPoint([0.0], 8/9),
|
||||
# IntegrationPoint([-sqrt(3/5)], 5/9),
|
||||
# IntegrationPoint([+sqrt(3/5)], 5/9)
|
||||
#]
|
||||
#integration_points = [
|
||||
# IntegrationPoint([-sqrt(1/3)], 1)
|
||||
# IntegrationPoint([+sqrt(1/3)], 1)
|
||||
#]
|
||||
#integration_points = [
|
||||
# IntegrationPoint([0.0], 2)
|
||||
#]
|
||||
function get_default_integration_points(element::Seg2)
|
||||
return line1()
|
||||
end
|
||||
|
||||
function get_default_integration_points(element::MSeg2)
|
||||
return line3()
|
||||
end
|
||||
|
||||
+58
-50
@@ -1,78 +1,86 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
# Mortar projection integration
|
||||
# Mortar equations
|
||||
|
||||
abstract MortarEquation <: Equation
|
||||
|
||||
function get_unknown_field_name(equation::MortarEquation)
|
||||
return "reaction force"
|
||||
end
|
||||
|
||||
""" Mortar boundary condition element for 2-dimensional problem, 2 node line segment. """
|
||||
type MBC2D2 <: MortarEquation
|
||||
element :: MSeg2
|
||||
integration_points :: Vector{IntegrationPoint}
|
||||
end
|
||||
|
||||
function Base.size(equation::MBC2D2)
|
||||
return (1, 2)
|
||||
end
|
||||
|
||||
function Base.convert(::Type{MortarEquation}, element::MSeg2)
|
||||
return MBC2D2(element, get_default_integration_points(element))
|
||||
end
|
||||
|
||||
# Mortar problem
|
||||
|
||||
"""
|
||||
Parameters
|
||||
----------
|
||||
node_csys
|
||||
coordinate system in node, normal + tangent + "binormal"
|
||||
element_pairs
|
||||
m x s matrix of boolean values, indicating elements sharing
|
||||
common surface. s is number of slave elements and m is number
|
||||
of master elements.
|
||||
in 3d 3x3 matrix, in 2d 2x2 matrix, respectively
|
||||
"""
|
||||
type MortarProblem <: BoundaryProblem
|
||||
unknown_field_name :: ASCIIString
|
||||
unknown_field_dimension :: Int
|
||||
equations :: Vector{MortarEquation}
|
||||
element_mapping :: Dict{Element, MortarEquation}
|
||||
master_elements :: Vector{Element} # mortar surface
|
||||
node_csys :: Dict{Int, Matrix{Float64}}
|
||||
element_pairs :: Matrix{Bool}
|
||||
end
|
||||
|
||||
function MortarProblem(dimension::Int=1, equations=[], master_elements=[])
|
||||
element_mapping = Dict(
|
||||
Seg2 => MBC2D2,
|
||||
)
|
||||
MortarProblem("reaction force", dimension, equations, element_mapping, master_elements, Dict(), zeros(0,0))
|
||||
function MortarProblem(dimension::Int=1, equations=[])
|
||||
MortarProblem("reaction force", dimension, equations)
|
||||
end
|
||||
|
||||
""" Mortar boundary condition element for 2-dimensional problem, 2 node line segment. """
|
||||
type MBC2D2 <: MortarEquation
|
||||
element :: Seg2 # == non-mortar surface element
|
||||
integration_points :: Vector{IntegrationPoint}
|
||||
end
|
||||
function MBC2D2(element::Seg2)
|
||||
integration_points = default_integration_points(element)
|
||||
if !haskey(element, "reaction force")
|
||||
element["reaction force"] = zeros(1, 2)
|
||||
end
|
||||
MBC2D2(element, integration_points)
|
||||
end
|
||||
Base.size(equation::MBC2D2) = (1, 2)
|
||||
# Mortar projection calculation
|
||||
|
||||
function find_master_elements(slave_element, problem)
|
||||
# find slave element "position" in element pairs matrix
|
||||
all_elements = map((equation) -> get_element(equation), problem.equations)
|
||||
seid = findfirst(slave_element, all_elements)
|
||||
info("slave element id = $seid")
|
||||
# find master element "positions" in element pairs matrix
|
||||
meids = find(problem.element_pairs[:, seid])
|
||||
info("master element ids = $meids")
|
||||
# master elements
|
||||
master_elements = problem.master_elements[meids]
|
||||
return master_elements
|
||||
""" Find master or "mortar" elements for this slave element. """
|
||||
function get_master_elements(element::MortarElement)
|
||||
return element.master_elements
|
||||
end
|
||||
|
||||
function calculate_local_assembly!(assembly::LocalAssembly, equation::MortarEquation, unknown_field_name::ASCIIString, time::Number=0.0, problem=nothing)
|
||||
# slave element = non-mortar element where integration happens
|
||||
# master element = mortar element projected to non-mortar side
|
||||
isa(problem, Void) && error("Cannot create projection without problem")
|
||||
initialize_local_assembly!(assembly, equation)
|
||||
function assemble!(assembly::Assembly, equation::MortarEquation, time::Number=0.0, problem=nothing)
|
||||
slave_element = get_element(equation)
|
||||
basis = get_basis(slave_element)
|
||||
detJ = det(basis)
|
||||
master_elements = find_master_elements(equation, problem)
|
||||
master_elements = get_master_elements(slave_element)
|
||||
slave_basis = get_basis(slave_element)
|
||||
detJ = det(slave_basis)
|
||||
dim = size(equation, 1) # number of nodes
|
||||
slave_dofs = get_gdofs(slave_element, dim)
|
||||
for master_element in master_elements
|
||||
for ip in get_integration_points(slave_element)
|
||||
mortar_basis = 0 # ...
|
||||
assembly.stiffness_matrix += w*basis'*basis
|
||||
assembly.force_vector += w*N'*gn
|
||||
master_dofs = get_gdofs(master_element, dim)
|
||||
xi1a = project_from_master_to_slave(slave_element, master_element, [-1.0])
|
||||
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")
|
||||
continue # no contribution
|
||||
end
|
||||
master_basis = get_basis(master_element)
|
||||
for ip in get_integration_points(equation)
|
||||
w = ip.weight*detJ(ip)*l
|
||||
|
||||
# integration point on slave side segment
|
||||
xi_gauss = 1/2*(1-ip.xi)*xi1[1] + 1/2*(1+ip.xi)*xi1[2]
|
||||
# projected integration point
|
||||
xi_projected = project_from_slave_to_master(slave_element, master_element, xi_gauss)
|
||||
|
||||
# add contribution to left hand side
|
||||
N1 = slave_basis(xi_gauss, time)
|
||||
N2 = master_basis(xi_projected, time)
|
||||
add!(assembly.lhs, slave_dofs, slave_dofs, w*N1'*N1)
|
||||
add!(assembly.lhs, slave_dofs, master_dofs, -w*N1'*N2)
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
# Mortar elements
|
||||
|
||||
# slave element = non-mortar element where integration happens
|
||||
# master element = mortar element projected to non-mortar side
|
||||
|
||||
abstract MortarElement <: Element
|
||||
|
||||
type MSeg2 <: MortarElement
|
||||
connectivity :: Vector{Int}
|
||||
basis :: Basis
|
||||
fields :: FieldSet
|
||||
master_elements :: Vector{MortarElement}
|
||||
end
|
||||
|
||||
function MSeg2(connectivity, master_elements=[], biorthogonal=false)
|
||||
basis(xi) = [(1-xi[1])/2 (1+xi[1])/2]
|
||||
dbasisdxi(xi) = [-1/2 1/2]
|
||||
return MSeg2(connectivity, Basis(basis, dbasisdxi), FieldSet(), master_elements)
|
||||
end
|
||||
|
||||
""" Find projection from slave nodes to master element, i.e. find xi2 from
|
||||
master element corresponding to the xi1.
|
||||
"""
|
||||
function project_from_slave_to_master(slave::MortarElement, master::MortarElement, xi1::Vector, time::Float64=0.0; max_iterations=5, tol=1.0e-9)
|
||||
slave_basis = get_basis(slave)
|
||||
master_basis = get_basis(master)
|
||||
|
||||
# slave side geometry and normal direction at xi1
|
||||
X1 = slave_basis("geometry", xi1, time)
|
||||
N1 = slave_basis("nodal ntsys", xi1, time)[:,1]
|
||||
|
||||
# master side geometry at xi2
|
||||
X2(xi2) = master_basis("geometry", [xi2], time)
|
||||
# dX2(xi2) = dmaster_basis("geometry", xi2, time)
|
||||
|
||||
# equation to solve
|
||||
R(xi2) = det([X2(xi2)-X1 N1]')
|
||||
# dR(xi2) = det([dX2(xi2) N1]')
|
||||
dR = ForwardDiff.derivative(R)
|
||||
|
||||
# go!
|
||||
xi2 = 0.0
|
||||
for i=1:max_iterations
|
||||
dxi2 = -R(xi2) / dR(xi2)
|
||||
xi2 += dxi2
|
||||
if norm(dxi2) < tol
|
||||
return Float64[xi2]
|
||||
end
|
||||
end
|
||||
error("find projection from slave to master: did not converge")
|
||||
end
|
||||
|
||||
""" Find projection from master surface to slave point, i.e. find xi1 from slave element corresponding to the xi2. """
|
||||
function project_from_master_to_slave(slave::MortarElement, master::MortarElement, xi2::Vector, time::Float64=0.0; max_iterations=5, tol=1.0e-9)
|
||||
slave_basis = get_basis(slave)
|
||||
master_basis = get_basis(master)
|
||||
|
||||
# slave side geometry and normal direction at xi1
|
||||
X1(xi1) = slave_basis("geometry", [xi1], time)
|
||||
N1(xi1) = slave_basis("nodal ntsys", [xi1], time)[:,1]
|
||||
|
||||
# master side geometry at xi2
|
||||
X2 = master_basis("geometry", xi2, time)
|
||||
|
||||
# equation to solve
|
||||
R(xi1) = det([X1(xi1)-X2 N1(xi1)]')
|
||||
# dR(xi1) = det([dX1(xi1) N1(xi1)]') + det([X1(xi1)-X2 dN1(xi1)]')
|
||||
dR = ForwardDiff.derivative(R)
|
||||
|
||||
# go!
|
||||
xi1 = 0.0
|
||||
for i=1:max_iterations
|
||||
dxi1 = -R(xi1) / dR(xi1)
|
||||
xi1 += dxi1
|
||||
if norm(dxi1) < tol
|
||||
return Float64[xi1]
|
||||
end
|
||||
end
|
||||
error("find projection from master to slave: did not converge")
|
||||
end
|
||||
|
||||
+5
-4
@@ -33,10 +33,11 @@ Notes
|
||||
Equation is automatically created during process based on problem
|
||||
element -> equation mapping and element type.
|
||||
"""
|
||||
function Base.push!(problem::Problem, element::Element)
|
||||
element_type = typeof(element)
|
||||
equation_type = problem.element_mapping[element_type]
|
||||
push!(problem.equations, equation_type(element))
|
||||
function Base.push!(problem::Problem, element::Element, args...)
|
||||
# element_type = typeof(element)
|
||||
# equation_type = problem.element_mapping[element_type]
|
||||
# push!(problem.equations, equation_type(element, args...))
|
||||
push!(problem.equations, element)
|
||||
end
|
||||
|
||||
"""
|
||||
|
||||
+22
-21
@@ -111,25 +111,26 @@ common situation, i.e., some main field problem and it's Dirichlet boundary.
|
||||
Cu = g
|
||||
|
||||
"""
|
||||
function call(solver::SimpleSolver, time::Number=Inf)
|
||||
p1, p2 = get_problems(solver)
|
||||
function call(solver::SimpleSolver, time::Number=0.0)
|
||||
problem1, problem2 = get_problems(solver)
|
||||
|
||||
ga1 = initialize_global_assembly(p1)
|
||||
calculate_global_assembly!(ga1, p1)
|
||||
ga2 = initialize_global_assembly(p2)
|
||||
calculate_global_assembly!(ga2, p2)
|
||||
assembly1 = Assembly()
|
||||
assemble!(assembly1, problem1, time)
|
||||
assembly2 = Assembly()
|
||||
assemble!(assembly2, problem2, time)
|
||||
|
||||
A1 = ga1.stiffness_matrix
|
||||
b1 = ga1.force_vector
|
||||
A2 = ga2.stiffness_matrix
|
||||
b2 = ga2.force_vector
|
||||
# info("Creating sparse matrices")
|
||||
A1 = sparse(assembly1.stiffness_matrix)
|
||||
b1 = sparse(assembly1.force_vector, size(A1, 1), 1)
|
||||
A2 = sparse(assembly2.stiffness_matrix)
|
||||
b2 = sparse(assembly2.force_vector, size(A2, 1), 1)
|
||||
|
||||
# create a saddle point problem
|
||||
A = [A1 A2; A2' zeros(A2)]
|
||||
b = [b1; b2]
|
||||
|
||||
# solve problem
|
||||
nz = unique(rowvals(A)) # here we remove any zero rows
|
||||
nz = unique(rowvals(A)) # take only non-zero rows
|
||||
x = zeros(b)
|
||||
x[nz] = lufact(A[nz,nz]) \ full(b[nz])
|
||||
|
||||
@@ -138,23 +139,23 @@ function call(solver::SimpleSolver, time::Number=Inf)
|
||||
x2 = x[length(b1)+1:end]
|
||||
|
||||
# update field for elements in problem 1
|
||||
for equation in get_equations(p1)
|
||||
for equation in get_equations(problem1)
|
||||
element = get_element(equation)
|
||||
field_name = get_unknown_field_name(p1)
|
||||
gdofs = get_gdofs(p1, equation)
|
||||
field_name = get_unknown_field_name(problem1)
|
||||
gdofs = get_gdofs(problem1, equation)
|
||||
element_solution = full(x1[gdofs])
|
||||
field = Field(time, element_solution)
|
||||
push!(element[field_name], field)
|
||||
field = Increment(element_solution)
|
||||
push!(element[field_name], TimeStep(time, field))
|
||||
end
|
||||
|
||||
# update field for elements in problem 2 (Dirichlet boundary)
|
||||
for equation in get_equations(p2)
|
||||
for equation in get_equations(problem2)
|
||||
element = get_element(equation)
|
||||
field_name = get_unknown_field_name(p2)
|
||||
gdofs = get_gdofs(p2, equation)
|
||||
field_name = get_unknown_field_name(problem2)
|
||||
gdofs = get_gdofs(problem2, equation)
|
||||
element_solution = full(x2[gdofs])
|
||||
field = Field(time, element_solution)
|
||||
push!(element[field_name], field)
|
||||
field = Increment(element_solution)
|
||||
push!(element[field_name], TimeStep(time, field))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
+3
-3
@@ -14,8 +14,8 @@ function SparseMatrixIJV()
|
||||
SparseMatrixIJV([], [], [])
|
||||
end
|
||||
|
||||
function Base.sparse(A::SparseMatrixIJV)
|
||||
return sparse(A.I, A.J, A.V)
|
||||
function Base.sparse(A::SparseMatrixIJV, args...)
|
||||
return sparse(A.I, A.J, A.V, args...)
|
||||
end
|
||||
|
||||
function Base.push!(A::SparseMatrixIJV, I::Int, J::Int, V::Float64)
|
||||
@@ -37,7 +37,7 @@ function Base.append!(A::SparseMatrixIJV, I::Vector{Int}, J::Vector{Int}, V::Vec
|
||||
end
|
||||
|
||||
function Base.full(A::SparseMatrixIJV, args...)
|
||||
return full(sparse(A.I, A.J, A.V), args...)
|
||||
return full(sparse(A.I, A.J, A.V, args...))
|
||||
end
|
||||
|
||||
""" Add local element matrix to sparse matrix. This basically does:
|
||||
|
||||
Reference in New Issue
Block a user