mirror of
https://github.com/JuliaFEM/JuliaFEM.jl.git
synced 2026-09-21 18:33:36 +00:00
some mortar code
This commit is contained in:
+23
-10
@@ -10,12 +10,29 @@ abstract DirichletEquation <: Equation
|
||||
type DirichletProblem <: BoundaryProblem
|
||||
unknown_field_name :: ASCIIString
|
||||
unknown_field_dimension :: Int
|
||||
equations :: Array{DirichletEquation, 1}
|
||||
element_mapping :: Dict{DataType, DataType}
|
||||
equations :: Vector{DirichletEquation}
|
||||
element_mapping :: Dict{Element, Equation}
|
||||
field_value :: Function
|
||||
end
|
||||
|
||||
function DirichletProblem(dimension::Int, field_value::Function=(X)->[0.0,0.0,0.0])
|
||||
""" Initialize new Dirichlet boundary condition.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
dimension
|
||||
dimension of unknown field
|
||||
field_value
|
||||
boundary function
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
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(
|
||||
@@ -28,12 +45,10 @@ end
|
||||
""" Dirichlet boundary condition element for 2 node line segment """
|
||||
type DBC2D2 <: DirichletEquation
|
||||
element :: Seg2
|
||||
integration_points :: Array{IntegrationPoint, 1}
|
||||
integration_points :: Vector{IntegrationPoint}
|
||||
end
|
||||
function DBC2D2(element::Seg2)
|
||||
integration_points = [
|
||||
IntegrationPoint([-sqrt(1/3)], 1.0),
|
||||
IntegrationPoint([+sqrt(1/3)], 1.0)]
|
||||
integration_points = default_integration_points(element)
|
||||
if !haskey(element, "reaction force")
|
||||
element["reaction force"] = zeros(1, 2)
|
||||
end
|
||||
@@ -41,9 +56,7 @@ function DBC2D2(element::Seg2)
|
||||
end
|
||||
Base.size(equation::DBC2D2) = (1, 2)
|
||||
|
||||
function calculate_local_assembly!(assembly::LocalAssembly, equation::DirichletEquation,
|
||||
unknown_field_name::ASCIIString, time::Number=Inf,
|
||||
problem=nothing)
|
||||
function calculate_local_assembly!(assembly::LocalAssembly, equation::DirichletEquation, unknown_field_name::ASCIIString, time::Number=0.0, problem=nothing)
|
||||
initialize_local_assembly!(assembly, equation)
|
||||
element = get_element(equation)
|
||||
basis = get_basis(element)
|
||||
|
||||
@@ -1,140 +0,0 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
# There are here for now until I figure a better place for them.
|
||||
|
||||
|
||||
"""
|
||||
Fit field s.t. || ∫ (Nᵢ(ξ)αᵢ - f(el, ξ)) dS || -> min!
|
||||
|
||||
Parameters
|
||||
----------
|
||||
f::Function
|
||||
Needs to take (el::Element, xi::Vector) as argument
|
||||
fixed_coeffs::Int[]
|
||||
These coefficients are not changed during fitting -> constrained optimizatio
|
||||
"""
|
||||
function fit_field!(el::Element, field, f, fixed_coeffs=Int[])
|
||||
w = [
|
||||
128/225,
|
||||
(332+13*sqrt(70))/900,
|
||||
(332+13*sqrt(70))/900,
|
||||
(332-13*sqrt(70))/900,
|
||||
(332-13*sqrt(70))/900]
|
||||
xi = Vector[
|
||||
[0.0],
|
||||
[ 1/3*sqrt(5 - 2*sqrt(10/7))],
|
||||
[-1/3*sqrt(5 - 2*sqrt(10/7))],
|
||||
[ 1/3*sqrt(5 + 2*sqrt(10/7))],
|
||||
[-1/3*sqrt(5 + 2*sqrt(10/7))]]
|
||||
n = get_number_of_basis_functions(el)
|
||||
fld = get_field(el, field)
|
||||
nfld = length(fld[1])
|
||||
#Logging.debug("dim of field $field: $nfld")
|
||||
|
||||
M = zeros(n, n)
|
||||
b = zeros(n, nfld)
|
||||
for i=1:length(w)
|
||||
detJ = get_detJ(el, xi[i])
|
||||
N = get_basis(el, xi[i])
|
||||
M += w[i]*N*N'*detJ
|
||||
fi = f(el, xi[i])
|
||||
for j=1:nfld
|
||||
b[:, j] += w[i]*N*fi[j]*detJ
|
||||
end
|
||||
end
|
||||
|
||||
coeffs = zeros(n)
|
||||
for j=1:nfld
|
||||
for k=1:n
|
||||
coeffs[k] = fld[k][j]
|
||||
end
|
||||
if length(fixed_coeffs) != 0
|
||||
# constrained problem, some coefficients are fixed
|
||||
N = Int[] # rest of coeffs
|
||||
S = Int[] # fixed coeffs
|
||||
for i = 1:n
|
||||
if i in fixed_coeffs
|
||||
push!(S, i)
|
||||
else
|
||||
push!(N, i)
|
||||
end
|
||||
end
|
||||
lhs = M[N,N]
|
||||
rhs = b[N,j] - M[N,S]*coeffs[S]
|
||||
coeffs[N] = lhs \ rhs
|
||||
else
|
||||
coeffs[:] = M \ b[:,j]
|
||||
end
|
||||
for k=1:n
|
||||
fld[k][j] = coeffs[k]
|
||||
end
|
||||
end
|
||||
set_field(el, field, fld)
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
"""
|
||||
Fit field s.t. || ∫ ∂/∂ξ(∑Nᵢ(ξ)αᵢ)f(el, ξ) dS || -> min!
|
||||
"""
|
||||
function fit_derivative_field!(el::Element, field, f, fixed_coeffs=Int[])
|
||||
w = [
|
||||
128/225,
|
||||
(332+13*sqrt(70))/900,
|
||||
(332+13*sqrt(70))/900,
|
||||
(332-13*sqrt(70))/900,
|
||||
(332-13*sqrt(70))/900]
|
||||
xi = Vector[
|
||||
[0.0],
|
||||
[ 1/3*sqrt(5 - 2*sqrt(10/7))],
|
||||
[-1/3*sqrt(5 - 2*sqrt(10/7))],
|
||||
[ 1/3*sqrt(5 + 2*sqrt(10/7))],
|
||||
[-1/3*sqrt(5 + 2*sqrt(10/7))]]
|
||||
n = get_number_of_basis_functions(el)
|
||||
fld = get_field(el, field)
|
||||
nfld = length(fld[1])
|
||||
#Logging.debug("dim of field $field: $nfld")
|
||||
|
||||
M = zeros(n, n)
|
||||
b = zeros(n, nfld)
|
||||
for i=1:length(w)
|
||||
detJ = get_detJ(el, xi[i])
|
||||
dNdxi = get_dbasisdxi(el, xi[i])
|
||||
dNdX = dNdxi / detJ
|
||||
M += w[i]*dNdX*dNdX'*detJ
|
||||
fi = f(el, xi[i])
|
||||
for j=1:nfld
|
||||
b[:, j] += w[i]*dNdX*fi[j]*detJ
|
||||
end
|
||||
end
|
||||
|
||||
coeffs = zeros(n)
|
||||
for j=1:nfld
|
||||
for k=1:n
|
||||
coeffs[k] = fld[k][j]
|
||||
end
|
||||
if length(fixed_coeffs) != 0
|
||||
#Logging.info("constrained problem, some coefficients are fixed")
|
||||
N = Int[] # rest of coeffs
|
||||
S = Int[] # fixed coeffs
|
||||
for i = 1:n
|
||||
if i in fixed_coeffs
|
||||
push!(S, i)
|
||||
else
|
||||
push!(N, i)
|
||||
end
|
||||
end
|
||||
lhs = M[N,N]
|
||||
rhs = b[N,j] - M[N,S]*coeffs[S]
|
||||
coeffs[N] = lhs \ rhs
|
||||
else
|
||||
coeffs[:] = M \ b[:,j]
|
||||
end
|
||||
for k=1:n
|
||||
fld[k][j] = coeffs[k]
|
||||
end
|
||||
end
|
||||
set_field(el, field, fld)
|
||||
return
|
||||
end
|
||||
+72
-93
@@ -1,101 +1,80 @@
|
||||
"""
|
||||
calculate "local" normals in elements, in a way that
|
||||
n = Nᵢnᵢ gives some reasonable results for ξ ∈ [-1, 1]
|
||||
"""
|
||||
function calculate_normals!(el::Element, t, field_name=symbol("normals"))
|
||||
new_field!(el, field_name, Vector)
|
||||
for xi in Vector[[-1.0], [1.0]]
|
||||
t = dinterpolate(el, :Geometry, xi)
|
||||
n = [0 -1; 1 0]*t
|
||||
n /= norm(n)
|
||||
push_field!(el, field_name, n)
|
||||
end
|
||||
end
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
# Mortar projection integration
|
||||
|
||||
abstract MortarEquation <: Equation
|
||||
|
||||
"""
|
||||
Alter normal field such that normals of adjacent elements are averaged.
|
||||
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.
|
||||
"""
|
||||
function average_normals!(elements, normal_field=symbol("normals"))
|
||||
d = Dict()
|
||||
for el in elements
|
||||
c = get_connectivity(el)
|
||||
n = get_field(el, normal_field)
|
||||
for (ci, ni) in zip(c, n)
|
||||
d[ci] = haskey(d, ci) ? d[ci] + ni : ni
|
||||
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))
|
||||
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)
|
||||
|
||||
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
|
||||
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)
|
||||
slave_element = get_element(equation)
|
||||
basis = get_basis(slave_element)
|
||||
detJ = det(basis)
|
||||
master_elements = find_master_elements(equation, problem)
|
||||
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
|
||||
end
|
||||
end
|
||||
for (ci, ni) in d
|
||||
d[ci] /= norm(d[ci])
|
||||
end
|
||||
for el in elements
|
||||
c = get_connectivity(el)
|
||||
new_normals = [d[ci] for ci in c]
|
||||
set_field(el, normal_field, new_normals)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
""" Find projection from slave nodes to master element. """
|
||||
function calc_projection_slave_nodes_to_master_element(sel, mel)
|
||||
X1 = get_field(sel, :Geometry)
|
||||
N1 = get_field(sel, :Normals)
|
||||
X2(xi) = interpolate(mel, :Geometry, xi)
|
||||
dX2(xi) = dinterpolate(mel, :Geometry, xi)
|
||||
R(xi, k) = det([X2(xi) - X1[k] N1[k]]')
|
||||
dR(xi, k) = det([dX2(xi) N1[k]]')
|
||||
xi2 = Vector[[0.0], [0.0]]
|
||||
for k=1:2
|
||||
xi = xi2[k]
|
||||
for i=1:3
|
||||
dxi = -R(xi, k)/dR(xi, k)
|
||||
xi += dxi
|
||||
if abs(dxi) < 1.0e-9
|
||||
break
|
||||
end
|
||||
end
|
||||
xi2[k] = xi
|
||||
end
|
||||
clamp!(xi2, -1, 1)
|
||||
return xi2
|
||||
end
|
||||
|
||||
""" Find projection from master nodes to slave element. """
|
||||
function calc_projection_master_nodes_to_slave_element(sel, mel)
|
||||
X1(xi) = interpolate(sel, :Geometry, xi)
|
||||
dX1(xi) = dinterpolate(sel, :Geometry, xi)
|
||||
N1(xi) = interpolate(sel, :Normals, xi)
|
||||
dN1(xi) = dinterpolate(sel, :Normals, xi)
|
||||
X2 = get_field(mel, :Geometry)
|
||||
R(xi, k) = det([X1(xi) - X2[k] N1(xi)]')
|
||||
dR(xi, k) = det([dX1(xi) N1(xi)]') + det([X1(xi) - X2[k] dN1(xi)]')
|
||||
xi1 = Vector[[0.0], [0.0]]
|
||||
for k=1:2
|
||||
xi = xi1[k]
|
||||
for i=1:3
|
||||
dxi = -R(xi, k)/dR(xi, k)
|
||||
xi += dxi
|
||||
if abs(dxi) < 1.0e-9
|
||||
break
|
||||
end
|
||||
end
|
||||
xi1[k] = xi
|
||||
end
|
||||
clamp!(xi1, -1, 1)
|
||||
return xi1
|
||||
end
|
||||
|
||||
function has_projection(sel, mel)
|
||||
xi1 = calc_projection_master_nodes_to_slave_element(sel, mel)
|
||||
l = abs(xi1[2]-xi1[1])[1]
|
||||
return l > 1.0e-9
|
||||
end
|
||||
|
||||
"""
|
||||
Calculate projection between 1d boundary elements
|
||||
"""
|
||||
function calc_projection(sel, mel)
|
||||
xi1 = calc_projection_master_nodes_to_slave_element(sel, mel)
|
||||
xi2 = calc_projection_slave_nodes_to_master_element(sel, mel)
|
||||
return xi1, xi2
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user