mirror of
https://github.com/JuliaFEM/JuliaFEM.jl.git
synced 2026-10-03 14:47:55 +00:00
frictional contact tests, not working yet
This commit is contained in:
@@ -27,6 +27,7 @@ function append!(assembly::Assembly, sub_assembly::Assembly)
|
|||||||
append!(assembly.C2, sub_assembly.C2)
|
append!(assembly.C2, sub_assembly.C2)
|
||||||
append!(assembly.D, sub_assembly.D)
|
append!(assembly.D, sub_assembly.D)
|
||||||
append!(assembly.g, sub_assembly.g)
|
append!(assembly.g, sub_assembly.g)
|
||||||
|
append!(assembly.c, sub_assembly.c)
|
||||||
end
|
end
|
||||||
|
|
||||||
function assemble!(problem::Problem, time::Float64; empty_assembly::Bool=true)
|
function assemble!(problem::Problem, time::Float64; empty_assembly::Bool=true)
|
||||||
|
|||||||
+126
-59
@@ -668,10 +668,15 @@ type Mortar <: BoundaryProblem
|
|||||||
tangential_condition :: Symbol # Stick or Slip
|
tangential_condition :: Symbol # Stick or Slip
|
||||||
minimum_distance :: Float64 # don't check for a contact if elements are far enough
|
minimum_distance :: Float64 # don't check for a contact if elements are far enough
|
||||||
store_debug_info :: Bool # for making debugging easier
|
store_debug_info :: Bool # for making debugging easier
|
||||||
|
always_in_contact :: Vector{Int64} # nodes in this list always in contact
|
||||||
|
always_in_stick :: Vector{Int64} # nodes in this list always in stick
|
||||||
|
always_in_slip :: Vector{Int64} # nodes in this list always in slip
|
||||||
|
contact :: Bool
|
||||||
|
friction :: Bool
|
||||||
end
|
end
|
||||||
|
|
||||||
function Mortar()
|
function Mortar()
|
||||||
Mortar(:Dual, false, :Tie, :Stick, Inf, false)
|
Mortar(:Dual, false, :Tie, :Stick, Inf, false, [], [], [], false, false)
|
||||||
end
|
end
|
||||||
|
|
||||||
function get_unknown_field_name(::Type{Mortar})
|
function get_unknown_field_name(::Type{Mortar})
|
||||||
@@ -699,6 +704,15 @@ function assemble!{E<:MortarElements2D}(assembly::Assembly, problem::Problem{Mor
|
|||||||
|
|
||||||
slave_dofs = get_gdofs(slave_element, field_dim)
|
slave_dofs = get_gdofs(slave_element, field_dim)
|
||||||
|
|
||||||
|
local_assembly = Assembly()
|
||||||
|
|
||||||
|
nnodes = size(slave_element, 2)
|
||||||
|
c = zeros(2*nnodes)
|
||||||
|
u = zeros(2*nnodes)
|
||||||
|
u1 = zeros(2*nnodes)
|
||||||
|
u2 = zeros(2*nnodes)
|
||||||
|
la = zeros(2*nnodes)
|
||||||
|
|
||||||
for master_element in slave_element["master elements"]
|
for master_element in slave_element["master elements"]
|
||||||
|
|
||||||
# if distance between elements is "far enough" cannot expect contact
|
# if distance between elements is "far enough" cannot expect contact
|
||||||
@@ -715,10 +729,9 @@ function assemble!{E<:MortarElements2D}(assembly::Assembly, problem::Problem{Mor
|
|||||||
xi1b = 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)
|
xi1 = clamp([xi1a xi1b], -1.0, 1.0)
|
||||||
l = 1/2*abs(xi1[2]-xi1[1])
|
l = 1/2*abs(xi1[2]-xi1[1])
|
||||||
l > 1.0e-9 || continue # no contribution
|
isapprox(l, 0.0) && continue # no contribution
|
||||||
|
|
||||||
# Calculate slave side projection matrix D
|
# Calculate slave side projection matrix D
|
||||||
nnodes = size(slave_element, 2)
|
|
||||||
Ae = zeros(nnodes, nnodes)
|
Ae = zeros(nnodes, nnodes)
|
||||||
De = zeros(nnodes, nnodes)
|
De = zeros(nnodes, nnodes)
|
||||||
Me = zeros(nnodes, nnodes)
|
Me = zeros(nnodes, nnodes)
|
||||||
@@ -767,7 +780,7 @@ function assemble!{E<:MortarElements2D}(assembly::Assembly, problem::Problem{Mor
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Calculate normal-tangential constraints and initial weighted gap
|
# Calculate normal-tangential constraints
|
||||||
X1 = vec(slave_element("geometry", time))
|
X1 = vec(slave_element("geometry", time))
|
||||||
X2 = vec(master_element("geometry", time))
|
X2 = vec(master_element("geometry", time))
|
||||||
Q = slave_element("normal-tangential coordinates", time)
|
Q = slave_element("normal-tangential coordinates", time)
|
||||||
@@ -780,79 +793,133 @@ function assemble!{E<:MortarElements2D}(assembly::Assembly, problem::Problem{Mor
|
|||||||
D2 = zeros(2*nnodes, 2*nnodes)
|
D2 = zeros(2*nnodes, 2*nnodes)
|
||||||
C2S2 = Q2'*C1S2
|
C2S2 = Q2'*C1S2
|
||||||
C2M2 = Q2'*C1M2
|
C2M2 = Q2'*C1M2
|
||||||
|
|
||||||
|
# initial weighted gap
|
||||||
G = -(C2S2*X1 - C2M2*X2)
|
G = -(C2S2*X1 - C2M2*X2)
|
||||||
|
|
||||||
# Calculate weighted gap in deformed configuration
|
|
||||||
if haskey(slave_element, "displacement")
|
if haskey(slave_element, "displacement")
|
||||||
u1 = vec(slave_element("displacement", time))
|
u1 = vec(slave_element("displacement", time))
|
||||||
else
|
|
||||||
u1 = zeros(2*nnodes)
|
|
||||||
end
|
end
|
||||||
if haskey(master_element, "displacement")
|
if haskey(master_element, "displacement")
|
||||||
u2 = vec(master_element("displacement", time))
|
u2 = vec(master_element("displacement", time))
|
||||||
else
|
|
||||||
u2 = zeros(2*nnodes)
|
|
||||||
end
|
end
|
||||||
x1 = X1 + u1
|
|
||||||
x2 = X2 + u2
|
# weighted gap change caused by deformation
|
||||||
g = -(C2S2*x1 - C2M2*x2)
|
u = -(C2S2*u1 - C2M2*u2)
|
||||||
|
|
||||||
|
# weighted gap in current configuration
|
||||||
|
#g = -(C2S2*x1 - C2M2*x2)
|
||||||
|
g = G + u
|
||||||
|
|
||||||
# Calculate "complementarity condition"
|
# Calculate "complementarity condition"
|
||||||
if haskey(slave_element, "reaction force")
|
if haskey(slave_element, "reaction force")
|
||||||
la = vec(slave_element("reaction force", time))
|
la = vec(slave_element("reaction force", time))
|
||||||
else
|
|
||||||
la = zeros(2*nnodes)
|
|
||||||
end
|
end
|
||||||
c = Q2'*la - g
|
c = Q2'*la - g
|
||||||
active_nodes = find(c[1:field_dim:end] .> 0)
|
|
||||||
inactive_nodes = find(c[1:field_dim:end] .<= 0)
|
|
||||||
|
|
||||||
# normal constraint: if contact, remove inactive nodes
|
|
||||||
if problem.properties.normal_condition == :Contact
|
|
||||||
if length(active_nodes) == 0
|
|
||||||
# all nodes inactive, nothing to contribute
|
|
||||||
return
|
|
||||||
end
|
|
||||||
for j in inactive_nodes
|
|
||||||
dofs = [2*(j-1)+1, 2*(j-1)+2]
|
|
||||||
G[dofs] = 0
|
|
||||||
C1S2[dofs,:] = 0
|
|
||||||
C1M2[dofs,:] = 0
|
|
||||||
C2S2[dofs,:] = 0
|
|
||||||
C2M2[dofs,:] = 0
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# tangential constraint: stick or slip
|
|
||||||
if problem.properties.tangential_condition == :Slip
|
|
||||||
D2 = copy(C2S2)
|
|
||||||
D2[1:field_dim:end, :] = 0
|
|
||||||
C2S2[2:field_dim:end, :] = 0
|
|
||||||
C2M2[2:field_dim:end, :] = 0
|
|
||||||
end
|
|
||||||
|
|
||||||
# Add contributions
|
# Add contributions
|
||||||
add!(assembly.C1, slave_dofs, slave_dofs, C1S2)
|
add!(local_assembly.C1, slave_dofs, slave_dofs, C1S2)
|
||||||
add!(assembly.C1, slave_dofs, master_dofs, -C1M2)
|
add!(local_assembly.C1, slave_dofs, master_dofs, -C1M2)
|
||||||
add!(assembly.C2, slave_dofs, slave_dofs, C2S2)
|
add!(local_assembly.C2, slave_dofs, slave_dofs, C2S2)
|
||||||
add!(assembly.C2, slave_dofs, master_dofs, -C2M2)
|
add!(local_assembly.C2, slave_dofs, master_dofs, -C2M2)
|
||||||
add!(assembly.D, slave_dofs, slave_dofs, D2)
|
add!(local_assembly.D, slave_dofs, slave_dofs, D2)
|
||||||
add!(assembly.c, slave_dofs, c)
|
add!(local_assembly.c, slave_dofs, c)
|
||||||
add!(assembly.g, slave_dofs, G)
|
add!(local_assembly.g, slave_dofs, G)
|
||||||
|
|
||||||
if props.store_debug_info
|
end # all master elements are done
|
||||||
slave_element["G"] = G
|
|
||||||
slave_element["g"] = g
|
# if only equality constraints, i.e., mesh tying problem, we're done for this element.
|
||||||
slave_element["c"] = c
|
if !props.contact
|
||||||
slave_element["C1S2"] = C1S2
|
append!(assembly, local_assembly)
|
||||||
slave_element["C1M2"] = C1M2
|
return
|
||||||
slave_element["C2S2"] = C2S2
|
|
||||||
slave_element["C2M2"] = C2M2
|
|
||||||
slave_element["D2"] = D2
|
|
||||||
slave_element["active nodes"] = active_nodes
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
C1 = sparse(local_assembly.C1)
|
||||||
|
C2 = sparse(local_assembly.C2)
|
||||||
|
D = sparse(local_assembly.D)
|
||||||
|
g = sparse(local_assembly.g)
|
||||||
|
c = sparse(local_assembly.c)
|
||||||
|
|
||||||
|
# normal condition
|
||||||
|
cn = c[1:field_dim:end]
|
||||||
|
inactive_nodes = find(cn .<= 0)
|
||||||
|
active_nodes = find(cn .> 0)
|
||||||
|
|
||||||
|
# inactive element
|
||||||
|
if length(active_nodes) == 0
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
# normal constraint: remove inactive nodes
|
||||||
|
for j in inactive_nodes
|
||||||
|
if length(props.always_in_contact) != 0
|
||||||
|
j in props.always_in_contact && continue
|
||||||
|
end
|
||||||
|
dofs = [2*(j-1)+1, 2*(j-1)+2]
|
||||||
|
C1[dofs,:] = 0
|
||||||
|
C2[dofs,:] = 0
|
||||||
|
g[dofs] = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
# frictionless contact
|
||||||
|
if !props.friction
|
||||||
|
for j in active_nodes
|
||||||
|
dofs = [2*(j-1)+1, 2*(j-1)+2]
|
||||||
|
D[dofs[2],dofs] = C2[dofs[2],dofs]
|
||||||
|
C2[dofs[2],:] = 0
|
||||||
|
g[dofs[2]] = 0
|
||||||
|
end
|
||||||
|
local_assembly.C1 = C1
|
||||||
|
local_assembly.C2 = C2
|
||||||
|
local_assembly.D = D
|
||||||
|
local_assembly.g = g
|
||||||
|
local_assembly.c = c
|
||||||
|
append!(assembly, local_assembly)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
# frictional contact, see Gitterle2010
|
||||||
|
mu = 0.3
|
||||||
|
lat = la[2:field_dim:end]
|
||||||
|
ut = u[2:field_dim:end]
|
||||||
|
ct = lat + ut
|
||||||
|
println("cn, ct, lat")
|
||||||
|
println(cn)
|
||||||
|
println(ct)
|
||||||
|
println(lat)
|
||||||
|
println("full(cn)")
|
||||||
|
prinln(full(cn))
|
||||||
|
C = max(mu*cn, abs(ct))*lat - mu*max(0, cn)*ct
|
||||||
|
stick_nodes = find(abs(ct) - mu*cn .< 0)
|
||||||
|
slip_nodes = find(abs(ct) - mu*cn .>= 0)
|
||||||
|
stick_nodes = setdiff(stick_nodes, inactive_nodes)
|
||||||
|
slip_nodes = setdiff(slip_nodes, inactive_nodes)
|
||||||
|
|
||||||
|
for j in active_nodes
|
||||||
|
dofs = [2*(j-1)+1, 2*(j-1)+2]
|
||||||
|
D[dofs[2],dofs] = C2[dofs[2],dofs]
|
||||||
|
C2[dofs[2],:] = 0
|
||||||
|
g[dofs[2]] = C[dofs[2]]
|
||||||
|
end
|
||||||
|
|
||||||
|
if props.store_debug_info
|
||||||
|
slave_element["G"] = G
|
||||||
|
slave_element["g"] = g
|
||||||
|
slave_element["c"] = c
|
||||||
|
slave_element["C1"] = C1
|
||||||
|
slave_element["C2"] = C2
|
||||||
|
slave_element["D"] = D2
|
||||||
|
slave_element["active nodes"] = active_nodes
|
||||||
|
end
|
||||||
|
|
||||||
|
local_assembly.C1 = C1
|
||||||
|
local_assembly.C2 = C2
|
||||||
|
local_assembly.D = D
|
||||||
|
local_assembly.g = g
|
||||||
|
local_assembly.c = c
|
||||||
|
|
||||||
|
append!(assembly, local_assembly)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
typealias MortarElements3D Union{Tri3, Quad4}
|
typealias MortarElements3D Union{Tri3, Quad4}
|
||||||
|
|||||||
@@ -48,6 +48,47 @@ end
|
|||||||
function handle_overconstraint_error!(problem, nodes, all_dofs, C1_, C1, C2_, C2, D_, D, g_, g)
|
function handle_overconstraint_error!(problem, nodes, all_dofs, C1_, C1, C2_, C2, D_, D, g_, g)
|
||||||
# old, new, old, new...
|
# old, new, old, new...
|
||||||
|
|
||||||
|
#= herzian contact with symmetry boundary
|
||||||
|
# INFO: SUMMARY for node id 555 with dofs 1109, 1110:
|
||||||
|
# INFO: ----- Current constraint -----
|
||||||
|
# INFO: lambda coefficients in C1 matrix are:
|
||||||
|
# INFO: dof 1109: ⋯ + 0.15*λ₁₁₀₉ ⋯
|
||||||
|
# INFO: rows in constraint matrix C2 & D
|
||||||
|
# INFO: dof 1109: 0.15*u₁₁₀₉ = -0.0 <-- overconstrained dof
|
||||||
|
# INFO: ----- New constraint -----
|
||||||
|
# INFO: lambda coefficients in C1 matrix are:
|
||||||
|
# INFO: dof 1109: ⋯ + 0.15*λ₁₁₀₉ ⋯
|
||||||
|
# INFO: dof 1110: ⋯ + 0.15*λ₁₁₁₀ ⋯
|
||||||
|
# INFO: rows in constraint matrix C2 & D
|
||||||
|
# INFO: dof 1109: 0.0*u₁₅₃ - 0.0*u₁₅₄ - 0.0*u₁₅₅ + 0.15*u₁₅₆ + 0.0*u₁₁₀₉ - 0.15*u₁₁₁₀ = -0.0 <-- overconstrained dof
|
||||||
|
# INFO: dof 1110: 0.15*λ₁₁₀₉ + 0.0*λ₁₁₁₀ = -0.0
|
||||||
|
# INFO: ----- Related equations -----
|
||||||
|
# INFO: dof 1110: 0.15*λ₁₁₀₉ + 0.0*λ₁₁₁₀ = -0.0
|
||||||
|
# INFO: dof 155: 0.165*u₁₅₅ = 0.0
|
||||||
|
# INFO: algorithm 1 solved issue? false
|
||||||
|
# INFO: algorithm 2 solved issue? true
|
||||||
|
# INFO: fixed: new setting is
|
||||||
|
# INFO: dof 1109: 0.0*u₁₅₃ - 0.0*u₁₅₄ - 0.0*u₁₅₅ + 0.15*u₁₅₆ + 0.0*u₁₁₀₉ - 0.15*u₁₁₁₀ = -0.0
|
||||||
|
|
||||||
|
if 555 in nodes
|
||||||
|
info("overconstraint DIRTY HACK")
|
||||||
|
# It is possible to selectively remove mortar constraints and the associated
|
||||||
|
# Lagrange multiplier components in certain axis directions and replace them
|
||||||
|
# with the Dirichlet (symmetry) conditions.
|
||||||
|
# old configuration is dirichlet symmetry condition
|
||||||
|
# new configuration is mortar constraint
|
||||||
|
# 1. remove mortar constrains and associated Lagrange multiplier components
|
||||||
|
# in dof 1109, that is, x direction of node 555.
|
||||||
|
C1[1109,:] = 0
|
||||||
|
C2[1109,:] = 0
|
||||||
|
D[1109,:] = 0
|
||||||
|
g[1109,:] = 0
|
||||||
|
# D[1110,1110] = 0
|
||||||
|
# g[1110] = 0
|
||||||
|
return
|
||||||
|
end
|
||||||
|
=#
|
||||||
|
|
||||||
""" Return all other dofs which connects to overconstrained dofs. """
|
""" Return all other dofs which connects to overconstrained dofs. """
|
||||||
function get_related_dofs(dofs)
|
function get_related_dofs(dofs)
|
||||||
dofs_ = Set(dofs)
|
dofs_ = Set(dofs)
|
||||||
|
|||||||
Reference in New Issue
Block a user