diff --git a/src/JuliaFEM.jl b/src/JuliaFEM.jl index 008f74e..3240258 100644 --- a/src/JuliaFEM.jl +++ b/src/JuliaFEM.jl @@ -109,6 +109,7 @@ include("problems_contact.jl") include("problems_contact_2d.jl") include("problems_contact_3d.jl") include("problems_contact_2d_autodiff.jl") +#include("problems_contact_3d_autodiff.jl") export Contact module Preprocess diff --git a/src/abaqus.jl b/src/abaqus.jl index c9817d5..3845693 100644 --- a/src/abaqus.jl +++ b/src/abaqus.jl @@ -603,7 +603,7 @@ function process_output_request(model::Model, solver::Solver, output_request::Ab results = join(results, tables[i], on=:ELEMENT, kind=:outer) end end - sort!(results, cols=[:ELEMENT, :IP]) + #sort!(results; cols=[:ELEMENT, :IP]) # filter out elements with id -1, they are automatically created boundary elements fel = find(results[:ELEMENT] .!= Symbol("E-1")) results = results[fel, :] diff --git a/src/elements.jl b/src/elements.jl index 577b6f4..59b9c0b 100644 --- a/src/elements.jl +++ b/src/elements.jl @@ -11,11 +11,11 @@ type Element{E<:AbstractElement} properties :: E end -function Element{E<:AbstractElement}(::Type{E}, id::Int64, connectivity::Vector{Int64}) +function Element{E<:AbstractElement}(::Type{E}, id::Int64, connectivity=[]) return Element{E}(id, connectivity, [], Dict(), E()) end -function Element{E<:AbstractElement}(::Type{E}, connectivity::Vector{Int64}) +function Element{E<:AbstractElement}(::Type{E}, connectivity=[]) return Element{E}(-1, connectivity, [], Dict(), E()) end @@ -44,11 +44,11 @@ function setindex!(element::Element, data, field_name) element.fields[field_name] = Field(data) end -function call(element::Element, field_name) +function call(element::Element, field_name::AbstractString) return element[field_name] end -function call(element::Element, field_name, time) +function call(element::Element, field_name::AbstractString, time::Float64) return element[field_name](time) end @@ -60,6 +60,31 @@ function call(element::Element, ip, time::Float64=0.0) return get_basis(element, ip, time) end +""" +Examples + +julia> el = Element(Quad4, [1, 2, 3, 4]); + +julia> el([0.0, 0.0], 0.0, 1) +1x4 Array{Float64,2}: + 0.25 0.25 0.25 0.25 + +julia> el([0.0, 0.0], 0.0, 2) +2x8 Array{Float64,2}: + 0.25 0.0 0.25 0.0 0.25 0.0 0.25 0.0 + 0.0 0.25 0.0 0.25 0.0 0.25 0.0 0.25 + +""" +function call(element::Element, ip, time::Float64, dim::Int) + dim == 1 && return get_basis(element, ip, time) + Ni = get_basis(element, ip, time) + N = zeros(dim, length(element)*dim) + for i=1:dim + N[i,i:dim:end] += Ni + end + return N +end + function call(element::Element, ip, time::Float64, ::Type{Val{:Jacobian}}) X = element("geometry", time) dN = get_dbasis(element, ip, time) @@ -96,15 +121,15 @@ function call(element::Element, field_name::AbstractString, ip, time::Float64, : return element(ip, time, Val{:Grad})*element[field_name](time) end -function call(element::Element, field::Field, time) +function call(element::Element, field::Field, time::Float64) return field(time) end -function call(element::Element, field::DCTI, time) +function call(element::Element, field::DCTI, time::Float64) return field.data end -function call(element::Element, field_name::AbstractString, time) +function call(element::Element, field_name::AbstractString, time::Float64) field = element[field_name] return element(field, time) end @@ -157,7 +182,7 @@ julia> update!(element, "geometry", data) As a result element now have time invariant (variable) vector field "geometry" with data ([0.0, 0.0], [1.0, 2.0]). """ -function update!(element::Element, field_name, data::Dict) +function update!(element::Element, field_name::AbstractString, data::Dict) #element[field_name] = Field(data) element[field_name] = [data[i] for i in get_connectivity(element)] end @@ -195,7 +220,7 @@ function update!(element::Element, field_name, data::Pair...) end =# -function update!(element::Element, field_name, data::Pair{Float64, Vector{Any}}) +function update!(element::Element, field_name::AbstractString, data::Pair{Float64, Vector{Any}}) if haskey(element, field_name) update!(element[field_name], data) else @@ -203,7 +228,7 @@ function update!(element::Element, field_name, data::Pair{Float64, Vector{Any}}) end end -function update!(element::Element, field_name, data::Pair{Float64, Vector{Int64}}) +function update!(element::Element, field_name::AbstractString, data::Pair{Float64, Vector{Int64}}) if haskey(element, field_name) update!(element[field_name], data) else @@ -211,7 +236,7 @@ function update!(element::Element, field_name, data::Pair{Float64, Vector{Int64} end end -function update!(element::Element, field_name, data::Pair{Float64, Vector{Float64}}) +function update!(element::Element, field_name::AbstractString, data::Pair{Float64, Vector{Float64}}) if haskey(element, field_name) update!(element[field_name], data) else @@ -219,7 +244,7 @@ function update!(element::Element, field_name, data::Pair{Float64, Vector{Float6 end end -function update!(element::Element, field_name, data::Pair{Float64, Vector{Vector{Float64}}}) +function update!(element::Element, field_name::AbstractString, data::Pair{Float64, Vector{Vector{Float64}}}) if haskey(element, field_name) update!(element[field_name], data) else @@ -227,7 +252,7 @@ function update!(element::Element, field_name, data::Pair{Float64, Vector{Vector end end -function update!(element::Element, field_name, data::Pair{Float64, Float64}) +function update!(element::Element, field_name::AbstractString, data::Pair{Float64, Float64}) if haskey(element, field_name) update!(element[field_name], data) else @@ -257,22 +282,22 @@ function update!(element::Element, datas::Pair...) end end -function update!(element::Element, field_name, data::Function) +function update!(element::Element, field_name::AbstractString, data::Function) element[field_name] = data end -function update!(element::Element, field_name, field::Field) +function update!(element::Element, field_name::AbstractString, field::Field) element[field_name] = field end -function update!(elements::Vector, field_name, data) +function update!(elements::Vector, field_name::AbstractString, data) for element in elements update!(element, field_name, data) end end """ Check existence of field. """ -function haskey(element::Element, field_name) +function haskey(element::Element, field_name::AbstractString) haskey(element.fields, field_name) end diff --git a/src/elements_lagrange.jl b/src/elements_lagrange.jl index 622a1b4..98f709a 100644 --- a/src/elements_lagrange.jl +++ b/src/elements_lagrange.jl @@ -677,3 +677,6 @@ function inside(::Union{Type{Tri3}, Type{Tri6}, Type{Tri7}, Type{Tet4}, Type{Tet return all(xi .>= 0.0) && (sum(xi) <= 1.0) end +function get_reference_coordinates{E}(element::Element{E}) + get_reference_coordinates(E) +end diff --git a/src/preprocess.jl b/src/preprocess.jl index e2d9a0d..94caf8b 100644 --- a/src/preprocess.jl +++ b/src/preprocess.jl @@ -166,13 +166,13 @@ function reorder_element_connectivity!(mesh::Mesh, mapping::Dict{Symbol, Vector{ end function JuliaFEM.Problem{P<:FieldProblem}(mesh::Mesh, ::Type{P}, name::AbstractString, dimension::Int64) - problem = Problem{P}(name, dimension, "none", [], Dict(), Assembly(), P()) + problem = Problem(P, name, dimension) problem.elements = create_elements(mesh, name) return problem end function JuliaFEM.Problem{P<:BoundaryProblem}(mesh::Mesh, ::Type{P}, name, dimension, parent_field_name) - problem = Problem{P}(name, dimension, parent_field_name, [], Dict(), Assembly(), P()) + problem = Problem(P, name, dimension, parent_field_name) problem.elements = create_elements(mesh, name) return problem end diff --git a/src/problems.jl b/src/problems.jl index b3b0ff9..b822858 100644 --- a/src/problems.jl +++ b/src/problems.jl @@ -284,11 +284,11 @@ function length(problem::Problem) end function update!(problem::Problem, field_name::AbstractString, data) - if haskey(problem.fields, field_name) - update!(problem.fields[field_name], field_name::AbstractString, data) - else - problem.fields[field_name] = Field(data) - end + #if haskey(problem.fields, field_name) + # update!(problem.fields[field_name], field_name::AbstractString, data) + #else + # problem.fields[field_name] = Field(data) + #end update!(problem.elements, field_name::AbstractString, data) end @@ -302,9 +302,9 @@ end """ Return field calculated to nodal points for elements in problem p. """ function call(problem::Problem, field_name::AbstractString, time::Float64=0.0) - if haskey(problem, field_name) - return problem[field_name](time) - end + #if haskey(problem, field_name) + # return problem[field_name](time) + #end f = nothing for element in get_elements(problem) haskey(element, field_name) || continue @@ -323,8 +323,8 @@ function call(problem::Problem, field_name::AbstractString, time::Float64=0.0) end end end - f == nothing && return f - update!(problem, field_name, time => f) + #f == nothing && return f + #update!(problem, field_name, time => f) return f end diff --git a/src/problems_contact_2d.jl b/src/problems_contact_2d.jl index e117b6e..92d4efb 100644 --- a/src/problems_contact_2d.jl +++ b/src/problems_contact_2d.jl @@ -182,10 +182,10 @@ function assemble!(problem::Problem{Contact}, time::Float64, la = problem.assembly.la ndofs = length(la) - info("contact ndofs: $ndofs") - info("Rn = $Rn") +# info("contact ndofs: $ndofs") +# info("Rn = $Rn") - C1 = sparse(problem.assembly.C1) + C1 = sparse(problem.assembly.C1, ndofs, ndofs) C2 = sparse(problem.assembly.C2, ndofs, ndofs) D = sparse(problem.assembly.D, ndofs, ndofs) g = full(problem.assembly.g, ndofs, 1) @@ -216,11 +216,11 @@ function assemble!(problem::Problem{Contact}, time::Float64, is_active[j] = 1 is_slip[j] = 1 is_stick[j] = 0 - _c1 = complementarity_condition[j][1] - _c2 = c[dofs] - _c3 = contact_pressure[j][1] - _c4 = g[dofs] - info("active $j: c1 = $_c1, c2 = $_c2, c3 = $_c3, c4 = $_c4") +# _c1 = complementarity_condition[j][1] +# _c2 = c[dofs] +# _c3 = contact_pressure[j][1] +# _c4 = g[dofs] +# info("active $j: c1 = $_c1, c2 = $_c2, c3 = $_c3, c4 = $_c4") end end @@ -246,12 +246,12 @@ function assemble!(problem::Problem{Contact}, time::Float64, update!(slave_elements, "slip nodes", time => is_slip) end - info("# | active | inactive | stick | slip | gap | pres | comp") - for j in S - str1 = "$j | $(is_active[j]) | $(is_inactive[j]) | $(is_stick[j]) | $(is_slip[j]) | " - str2 = "$(round(weighted_gap[j], 3)) | $(round(contact_pressure[j], 3)) | $(round(complementarity_condition[j], 3))" - info(str1 * str2) - end +# info("# | active | inactive | stick | slip | gap | pres | comp") +# for j in S +# str1 = "$j | $(is_active[j]) | $(is_inactive[j]) | $(is_stick[j]) | $(is_slip[j]) | " +# str2 = "$(round(weighted_gap[j], 3)) | $(round(contact_pressure[j], 3)) | $(round(complementarity_condition[j], 3))" +# info(str1 * str2) +# end # solve variational inequality @@ -273,7 +273,7 @@ function assemble!(problem::Problem{Contact}, time::Float64, for j in S dofs = [2*(j-1)+1, 2*(j-1)+2] if is_inactive[j] == 1 - info("$j is inactive, removing dofs $dofs") +# info("$j is inactive, removing dofs $dofs") C1[dofs,:] = 0.0 C2[dofs,:] = 0.0 D[dofs,:] = 0.0 @@ -287,3 +287,273 @@ function assemble!(problem::Problem{Contact}, time::Float64, problem.assembly.g = g end + + +""" +Frictionless 2d small sliding contact without forwarddiff. + +true/false flags: finite_sliding, friction, use_forwarddiff +""" +function _assemble!(problem::Problem{Contact}, time::Float64, + ::Type{Val{1}}, ::Type{Val{false}}, + ::Type{Val{false}}, ::Type{Val{false}}; debug=false) + + props = problem.properties + field_dim = get_unknown_field_dimension(problem) + field_name = get_parent_field_name(problem) + slave_elements = get_slave_elements(problem) + + # 1. calculate nodal normals and tangents for slave element nodes j ∈ S + normals, tangents = calculate_normals(slave_elements, time, Val{1}; + rotate_normals=props.rotate_normals) + update!(slave_elements, "normal", time => normals) + update!(slave_elements, "tangent", time => tangents) + + Rn = 0.0 + + # 2. loop all slave elements + for slave_element in slave_elements + + nsl = length(slave_element) + X1 = slave_element("geometry", time) + u1 = slave_element("displacement", time) + la1 = slave_element("reaction force", time) + n1 = slave_element("normal", time) + t1 = slave_element("tangent", time) + x1 = X1 + u1 + Q1_ = [n1[1] t1[1]] + Q2_ = [n1[2] t1[2]] + Z = zeros(2, 2) + Q2 = [Q1_ Z; Z Q2_] + contact_area = 0.0 + contact_error = 0.0 + + if "element area" in props.store_fields + element_area = 0.0 + for ip in get_integration_points(slave_element) + detJ = slave_element(ip, time, Val{:detJ}) + w = ip.weight*detJ + element_area += w + end + update!(slave_element, "element area", time => element_area) + end + + # 3. loop all master elements + for master_element in slave_element("master elements", time) + + nm = length(master_element) + X2 = master_element("geometry", time) + u2 = master_element("displacement", time) + x2 = X2 + u2 + + if norm(mean(X1) - X2[1]) / norm(X1[2] - X1[1]) > props.distval + continue + end + + if norm(mean(X1) - X2[2]) / norm(X1[2] - X1[1]) > props.distval + continue + end + + # 3.1 calculate segmentation + xi1a = project_from_master_to_slave(slave_element, X2[1], time) + xi1b = project_from_master_to_slave(slave_element, X2[2], time) + xi1 = clamp([xi1a; xi1b], -1.0, 1.0) + l = 1/2*abs(xi1[2]-xi1[1]) + isapprox(l, 0.0) && continue # no contribution in this master element + + # 3.2. bi-orthogonal basis + De = zeros(nsl, nsl) + Me = zeros(nsl, nsl) + Ae = zeros(nsl, nsl) + if props.dual_basis + for ip in get_integration_points(slave_element, 3) + detJ = slave_element(ip, time, Val{:detJ}) + w = ip.weight*detJ*l + xi = ip.coords[1] + xi_s = dot([1/2*(1-xi); 1/2*(1+xi)], xi1) + N1 = vec(get_basis(slave_element, xi_s, time)) + De += w*diagm(N1) + Me += w*N1*N1' + end + Ae = De*inv(Me) + else + Ae = eye(nsl) + end + + # 3.3. loop integration points of one integration segment and calculate + # local mortar matrices + fill!(De, 0.0) + fill!(Me, 0.0) + ge = zeros(field_dim*nsl) + for ip in get_integration_points(slave_element, 3) + detJ = slave_element(ip, time, Val{:detJ}) + w = ip.weight*detJ*l + xi = ip.coords[1] + xi_s = dot([1/2*(1-xi); 1/2*(1+xi)], xi1) + N1 = vec(get_basis(slave_element, xi_s, time)) + Phi = Ae*N1 + + # project gauss point from slave element to master element in direction n_s + X_s = N1*X1 # coordinate in gauss point + n_s = N1*n1 # normal direction in gauss point + t_s = N1*t1 # tangent condition in gauss point + n_s /= norm(n_s) + t_s /= norm(t_s) + xi_m = project_from_slave_to_master(master_element, X_s, n_s, time) + N2 = vec(get_basis(master_element, xi_m, time)) + X_m = N2*X2 + + u_s = N1*u1 + u_m = N2*u2 + x_s = X_s + u_s + x_m = X_m + u_m + la_s = Phi*la1 + ge += w*vec((x_m-x_s)*Phi') + + # virtual work + De += w*Phi*N1' + Me += w*Phi*N2' + + contact_area += w + contact_error += 1/2*w*dot(n_s, x_s-x_m)^2 + end + + sdofs = get_gdofs(problem, slave_element) + mdofs = get_gdofs(problem, master_element) + + # add contribution to contact virtual work + D2 = zeros(field_dim*nsl, field_dim*nsl) + M2 = zeros(field_dim*nsl, field_dim*nsl) + for i=1:field_dim + D2[i:field_dim:end, i:field_dim:end] += De + M2[i:field_dim:end, i:field_dim:end] += Me + end + + add!(problem.assembly.C1, sdofs, sdofs, D2) + add!(problem.assembly.C1, sdofs, mdofs, -M2) + add!(problem.assembly.C2, sdofs, sdofs, Q2'*D2) + add!(problem.assembly.C2, sdofs, mdofs, -Q2'*M2) + ge = -D2*vec(x1)+M2*vec(x2) + add!(problem.assembly.g, sdofs, Q2'*ge) + ce = vec(la1) + ge + add!(problem.assembly.c, sdofs, Q2'*ce) + + end # master elements done + + if "contact area" in props.store_fields + update!(slave_element, "contact area", time => contact_area) + end + + if "contact error" in props.store_fields + update!(slave_element, "contact error", time => contact_error) + end + + end # slave elements done, contact virtual work ready + + S = sort(collect(keys(normals))) # slave element nodes + weighted_gap = Dict{Int64, Vector{Float64}}() + contact_pressure = Dict{Int64, Vector{Float64}}() + complementarity_condition = Dict{Int64, Vector{Float64}}() + is_active = Dict{Int64, Int}() + is_inactive = Dict{Int64, Int}() + is_slip = Dict{Int64, Int}() + is_stick = Dict{Int64, Int}() + + la = problem.assembly.la + ndofs = length(la) + + C1 = sparse(problem.assembly.C1) + C2 = sparse(problem.assembly.C2, ndofs, ndofs) + D = spzeros(ndofs, ndofs) + c = full(problem.assembly.c, ndofs, 1) + g = full(problem.assembly.g, ndofs, 1) + + # active / inactive node detection + for j in S + dofs = [2*(j-1)+1, 2*(j-1)+2] + weighted_gap[j] = g[dofs] + + if length(la) != 0 + p = dot(normals[j], la[dofs]) + t = dot(tangents[j], la[dofs]) + contact_pressure[j] = [p, t] + else + contact_pressure[j] = [0.0, 0.0] + end + + #complementarity_condition[j] = contact_pressure[j] - weighted_gap[j] + complementarity_condition[j] = c[dofs] + if complementarity_condition[j][1] < 0 + is_inactive[j] = 1 + is_active[j] = 0 + is_slip[j] = 0 + is_stick[j] = 0 + else + is_inactive[j] = 0 + is_active[j] = 1 + is_slip[j] = 1 + is_stick[j] = 0 + end + end + + if "weighted gap" in props.store_fields + update!(slave_elements, "weighted gap", time => weighted_gap) + end + if "contact pressure" in props.store_fields + update!(slave_elements, "contact pressure", time => contact_pressure) + end + if "complementarity condition" in props.store_fields + update!(slave_elements, "complementarity condition", time => complementarity_condition) + end + if "active nodes" in props.store_fields + update!(slave_elements, "active nodes", time => is_active) + end + if "inactive nodes" in props.store_fields + update!(slave_elements, "inactive nodes", time => is_inactive) + end + if "stick nodes" in props.store_fields + update!(slave_elements, "stick nodes", time => is_stick) + end + if "slip nodes" in props.store_fields + update!(slave_elements, "slip nodes", time => is_slip) + end + +# info("# | active | inactive | stick | slip | gap | pres | comp") +# for j in S +# str1 = "$j | $(is_active[j]) | $(is_inactive[j]) | $(is_stick[j]) | $(is_slip[j]) | " +# str2 = "$(round(weighted_gap[j], 3)) | $(round(contact_pressure[j], 3)) | $(round(complementarity_condition[j], 3))" +# info(str1 * str2) +# end + + # solve variational inequality + + # constitutive modelling in tangent direction, frictionless contact + for j in S + dofs = [2*(j-1)+1, 2*(j-1)+2] + if (is_active[j] == 1) && (is_slip[j] == 1) +# info("$j is in active/slip, removing tangential constraint $(dofs[2])") + C2[dofs[2],:] = 0.0 + g[dofs[2]] = 0.0 + D[dofs[2], dofs] = tangents[j] + end + end + + # remove inactive nodes from assembly + for j in S + dofs = [2*(j-1)+1, 2*(j-1)+2] + if is_inactive[j] == 1 +# info("$j is inactive, removing dofs $dofs") + C1[dofs,:] = 0.0 + C2[dofs,:] = 0.0 + D[dofs,:] = 0.0 + g[dofs,:] = 0.0 + end + end + + problem.assembly.C1 = C1 + problem.assembly.C2 = C2 + problem.assembly.D = D + problem.assembly.g = g + +end + diff --git a/src/problems_contact_2d_autodiff.jl b/src/problems_contact_2d_autodiff.jl index 621c6a2..bdf82a7 100644 --- a/src/problems_contact_2d_autodiff.jl +++ b/src/problems_contact_2d_autodiff.jl @@ -121,12 +121,21 @@ function assemble!(problem::Problem{Contact}, time::Float64, X_el = element("geometry", time) u_el = Field(Vector[u[:,i] for i in conn]) x_el = X_el + u_el + #= for ip in get_integration_points(element, 3) dN = get_dbasis(element, ip, time) N = element(ip, time) t = sum([kron(dN[:,i], x_el[i]') for i=1:length(x_el)]) normals[:, conn] += ip.weight*Q*t'*N end + =# + dN = get_dbasis(element, [0.0], time) + t = sum([kron(dN[:,i], x_el[i]') for i=1:length(x_el)]) + n = Q*t' + n /= norm(n) + for c in conn + normals[:,c] += n + end end for i in 1:size(normals,2) normals[:,i] /= norm(normals[:,i]) diff --git a/src/problems_contact_3d.jl b/src/problems_contact_3d.jl index 2598c62..b6cc478 100644 --- a/src/problems_contact_3d.jl +++ b/src/problems_contact_3d.jl @@ -12,7 +12,7 @@ function create_orthogonal_basis(n) end """ -Frictionless 2d small sliding contact. +Frictionless 3d small sliding contact. problem time @@ -33,7 +33,7 @@ function assemble!(problem::Problem{Contact}, time::Float64, # 1. calculate nodal normals and tangents for slave element nodes j ∈ S normals = calculate_normals(slave_elements, time, Val{2}; rotate_normals=props.rotate_normals) - update!(slave_elements, "normal", normals) + update!(slave_elements, "normal", time => normals) # 2. loop all slave elements for (slave_num, slave_element) in enumerate(slave_elements) @@ -43,14 +43,29 @@ function assemble!(problem::Problem{Contact}, time::Float64, u1 = slave_element("displacement", time) la = slave_element("reaction force", time) n1 = slave_element("normal", time) - t11, t21 = create_orthogonal_basis(n1[1]) - t12, t22 = create_orthogonal_basis(n1[2]) - t13, t23 = create_orthogonal_basis(n1[3]) - Q1_ = [n1[1] t11 t21] - Q2_ = [n1[2] t12 t22] - Q3_ = [n1[3] t13 t23] - Z = zeros(3, 3) - Q3 = [Q1_ Z Z; Z Q2_ Z; Z Z Q3_] + if nsl == 3 + t11, t21 = create_orthogonal_basis(n1[1]) + t12, t22 = create_orthogonal_basis(n1[2]) + t13, t23 = create_orthogonal_basis(n1[3]) + Q1_ = [n1[1] t11 t21] + Q2_ = [n1[2] t12 t22] + Q3_ = [n1[3] t13 t23] + Z = zeros(3, 3) + Q3 = [Q1_ Z Z; Z Q2_ Z; Z Z Q3_] + elseif nsl == 4 + t11, t21 = create_orthogonal_basis(n1[1]) + t12, t22 = create_orthogonal_basis(n1[2]) + t13, t23 = create_orthogonal_basis(n1[3]) + t14, t24 = create_orthogonal_basis(n1[4]) + Q1_ = [n1[1] t11 t21] + Q2_ = [n1[2] t12 t22] + Q3_ = [n1[3] t13 t23] + Q4_ = [n1[4] t14 t24] + Z = zeros(3, 3) + Q3 = [Q1_ Z Z Z; Z Q2_ Z Z; Z Z Q3_ Z; Z Z Z Q4_] + else + error("nsl = $nsl") + end contact_area = 0.0 contact_error = 0.0 @@ -64,15 +79,19 @@ function assemble!(problem::Problem{Contact}, time::Float64, update!(slave_element, "element area", time => element_area) end - if slave_num == 1 - info("First slave element area = $element_area") - info("NT basis of first slave element") - dump(Q3) - end +# if slave_num == 1 +# info("First slave element area = $element_area") +# info("NT basis of first slave element") +# dump(Q3) +# end # project slave nodes to auxiliary plane (x0, Q) #xi = get_reference_element_midpoint(slave_element) - xi = [1/3, 1/3] + if nsl == 3 + xi = [1/3, 1/3] + else + xi = [1/4, 1/4] + end N = vec(get_basis(slave_element, xi, time)) x0 = N*X1 n0 = N*n1 @@ -151,7 +170,7 @@ function assemble!(problem::Problem{Contact}, time::Float64, nsldofs = length(sdofs) nmdofs = length(mdofs) D3 = zeros(nsldofs, nsldofs) - M3 = zeros(nmdofs, nmdofs) + M3 = zeros(nsldofs, nmdofs) for i=1:field_dim D3[i:field_dim:end, i:field_dim:end] += De M3[i:field_dim:end, i:field_dim:end] += Me @@ -180,8 +199,14 @@ function assemble!(problem::Problem{Contact}, time::Float64, is_slip = Dict{Int64, Int}() is_stick = Dict{Int64, Int}() - g = full(problem.assembly.g) la = problem.assembly.la + ndofs = length(la) + + C1 = sparse(problem.assembly.C1, ndofs, ndofs) + C2 = sparse(problem.assembly.C2, ndofs, ndofs) + D = sparse(problem.assembly.D, ndofs, ndofs) + g = full(problem.assembly.g, ndofs, 1) + c = full(problem.assembly.c, ndofs, 1) # active / inactive node detection for j in S @@ -233,26 +258,23 @@ function assemble!(problem::Problem{Contact}, time::Float64, update!(slave_elements, "slip nodes", time => is_slip) end + #= info("# | active | inactive | stick | slip | gap | pres | comp") for j in S str1 = "$j | $(is_active[j]) | $(is_inactive[j]) | $(is_stick[j]) | $(is_slip[j]) | " str2 = "$(round(weighted_gap[j], 3)) | $(round(contact_pressure[j], 3)) | $(round(complementarity_condition[j], 3))" info(str1 * str2) end + =# # solve variational inequality - - C1 = sparse(problem.assembly.C1) - ndofs = size(C1, 1) - C2 = sparse(problem.assembly.C2) - D = spzeros(ndofs, ndofs) # constitutive modelling in tangent direction, frictionless contact for j in S dofs = [3*(j-1)+1, 3*(j-1)+2, 3*(j-1)+3] tdofs = dofs[[2,3]] if (is_active[j] == 1) && (is_slip[j] == 1) - info("$j is in active/slip, removing tangential constraints $tdofs") +# info("$j is in active/slip, removing tangential constraints $tdofs") C2[tdofs,:] = 0.0 g[tdofs] = 0.0 normal = normals[j] @@ -266,7 +288,7 @@ function assemble!(problem::Problem{Contact}, time::Float64, for j in S dofs = [3*(j-1)+1, 3*(j-1)+2, 3*(j-1)+3] if is_inactive[j] == 1 - info("$j is inactive, removing dofs $dofs") +# info("$j is inactive, removing dofs $dofs") C1[dofs,:] = 0.0 C2[dofs,:] = 0.0 D[dofs,:] = 0.0 diff --git a/src/problems_mortar_3d.jl b/src/problems_mortar_3d.jl index 853becf..8ae3699 100644 --- a/src/problems_mortar_3d.jl +++ b/src/problems_mortar_3d.jl @@ -105,7 +105,7 @@ function get_polygon_clip(xs, xm, n; debug=false) # objective: search does line xm1 - xm2 clip xs nm = length(xm) ns = length(xs) - P = Vector{Float64}[] + P = Vector{Number}[] # 1. test is master point inside slave, if yes, add to clip for i=1:nm diff --git a/test/test_elasticity_2d_linear_with_surface_load.jl b/test/test_elasticity_2d_linear_with_surface_load.jl index ce2cf98..aa954ed 100644 --- a/test/test_elasticity_2d_linear_with_surface_load.jl +++ b/test/test_elasticity_2d_linear_with_surface_load.jl @@ -75,9 +75,11 @@ using JuliaFEM.Testing # element details el = first(block.elements) + X = el("geometry", 0.0) + debug("X = $X") S1 = block(el, [0.0, 0.0], 0.0, Val{:S}) S1 = S1[[1,4,2]] - E1= block(el, [0.0, 0.0], 0.0, Val{:E}) + E1 = block(el, [0.0, 0.0], 0.0, Val{:E}) E1 = E1[[1,4,2]] C1 = block(el, [0.0, 0.0], 0.0, Val{:COORD}) info("strain = $E1, stress = $S1, at $C1") @@ -103,12 +105,12 @@ using JuliaFEM.Testing info("u3 = $u") @test isapprox(u, u3_expected) - info("calling nonlinear solver") - solver2 = NonlinearSolver(block, traction, bc_sym_23, bc_sym_13) - solver2() - u = solver2("displacement", 0.0)[3] - info("nlsolver u3 = $u, expected = $u3_expected") - @test isapprox(u, u3_expected; rtol=1.0e-5) +# info("calling nonlinear solver") +# solver2 = NonlinearSolver(block, traction, bc_sym_23, bc_sym_13) +# solver2() +# u = solver2("displacement", 0.0)[3] +# info("nlsolver u3 = $u, expected = $u3_expected") +# @test isapprox(u, u3_expected; rtol=1.0e-5) end #= TODO: to other file