mirror of
https://github.com/JuliaFEM/JuliaFEM.jl.git
synced 2026-10-02 06:13:59 +00:00
fixed a lot of tests
This commit is contained in:
+14
-33
@@ -1,15 +1,23 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
# should this stuff be in package? see FactCheck docs.
|
||||
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Test
|
||||
|
||||
#using FactCheck
|
||||
#using Logging
|
||||
#@Logging.configure(level=DEBUG)
|
||||
function run_tests(; quiet=false)
|
||||
|
||||
test_files = readdir(Pkg.dir("JuliaFEM")*"/test")
|
||||
test_files = filter(f -> (startswith(f, "test_") & endswith(f, ".jl")), test_files)
|
||||
for test_file in test_files
|
||||
if !quiet
|
||||
info("Running tests from file $test_file")
|
||||
end
|
||||
include(test_file)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
run_tests()
|
||||
|
||||
#=
|
||||
facts("Testing if somebody used print, println(), @sprint in src directory") do
|
||||
@@ -99,30 +107,3 @@ end
|
||||
=#
|
||||
|
||||
|
||||
### NEW STYLE OF TESTING
|
||||
|
||||
using JuliaFEM.Test
|
||||
|
||||
function run_tests()
|
||||
|
||||
for test_file in readdir(Pkg.dir("JuliaFEM")*"/test")
|
||||
info("checking is $test_file is real test file")
|
||||
if (startswith(test_file, "test_")) & (endswith(test_file, ".jl"))
|
||||
run_test(test_file)
|
||||
end
|
||||
end
|
||||
|
||||
passed, failed, errors, critical = print_test_statistics()
|
||||
|
||||
# at the very end throw error if something is failed
|
||||
if failed + errors + critical > 0
|
||||
error("Some tests has failed. Fix them. Now.")
|
||||
exit(1)
|
||||
else
|
||||
info("""All tests has passed \o/ .""")
|
||||
exit(0)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
run_tests()
|
||||
|
||||
+20
-29
@@ -1,15 +1,11 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
module AbaqusReaderTests
|
||||
|
||||
#using JuliaFEM
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Preprocess
|
||||
using JuliaFEM.Test
|
||||
|
||||
using JuliaFEM.Preprocess: parse_abaqus, parse_section
|
||||
|
||||
function test_read_abaqus_model()
|
||||
# FIXME: get_test_data()
|
||||
@testset "read inp file" begin
|
||||
model = open(parse_abaqus, Pkg.dir("JuliaFEM")*"/geometry/3d_beam/palkki.inp")
|
||||
@test length(model["nodes"]) == 298
|
||||
@test length(model["elements"]) == 120
|
||||
@@ -19,8 +15,7 @@ function test_read_abaqus_model()
|
||||
@test length(model["nsets"]["TOP"]) == 83
|
||||
end
|
||||
|
||||
#=
|
||||
facts("test that reader throws error when dimension information of elemenet is missing") do
|
||||
@testset "test that reader throws error when dimension information of elemenet is missing" begin
|
||||
# *ELEMENT, TYPE=neverseenbefore, ELSET=Body1
|
||||
data = """
|
||||
1, 243, 240, 191, 117, 245, 242, 244,
|
||||
@@ -28,11 +23,10 @@ facts("test that reader throws error when dimension information of elemenet is m
|
||||
"""
|
||||
model = Dict()
|
||||
header = Dict("section"=>"ELEMENT", "options" => Dict("TYPE" => "neverseenbefore", "ELSET"=>"Body1"))
|
||||
@fact_throws parse_element_section(model, header, data)
|
||||
@test_throws parse_element_section(model, header, data)
|
||||
end
|
||||
=#
|
||||
|
||||
function test_read_element_section()
|
||||
@testset "test read element section" begin
|
||||
data = """*ELEMENT, TYPE=C3D10, ELSET=BEAM
|
||||
1, 243, 240, 191, 117, 245, 242, 244,
|
||||
1, 2, 196
|
||||
@@ -51,21 +45,20 @@ function test_read_element_section()
|
||||
@test model["elsets"]["BEAM"] == [1, 2]
|
||||
end
|
||||
|
||||
#function test_read_surface_set_section()
|
||||
# data = """*SURFACE, TYPE=ELEMENT, NAME=LOAD
|
||||
# 31429,S1
|
||||
# 31481,S3
|
||||
# """
|
||||
# model = Dict{AbstractString, Any}()
|
||||
# model["nsets"] = Dict{AbstractString, Vector{Int}}()
|
||||
# model["elsets"] = Dict{AbstractString, Vector{Int}}()
|
||||
# model["elements"] = Dict{Integer, Any}()
|
||||
# parse_section(model, data, :SURFACE, 1, 3, Val{:SURFACE})
|
||||
# @test model["surfaces"]["LOAD"] = [(31429,1), (31481,3)]
|
||||
#
|
||||
#end
|
||||
@testset "test read surface set section" begin
|
||||
data = """*SURFACE, TYPE=ELEMENT, NAME=LOAD
|
||||
31429,S1
|
||||
31481,S3
|
||||
"""
|
||||
model = Dict{AbstractString, Any}()
|
||||
model["nsets"] = Dict{AbstractString, Vector{Int}}()
|
||||
model["elsets"] = Dict{AbstractString, Vector{Int}}()
|
||||
model["elements"] = Dict{Integer, Any}()
|
||||
parse_section(model, data, :SURFACE, 1, 3, Val{:SURFACE})
|
||||
@test model["surfaces"]["LOAD"] == [(31429,1), (31481,3)]
|
||||
end
|
||||
|
||||
function test_unknown_handler_warning_message()
|
||||
@testset "test unknown handler warning message" begin
|
||||
fn = tempname()
|
||||
fid = open(fn, "w")
|
||||
testdata = """*ELEMENT2, TYPE=C3D10, ELSET=Body1
|
||||
@@ -75,9 +68,7 @@ function test_unknown_handler_warning_message()
|
||||
write(fid, testdata)
|
||||
close(fid)
|
||||
model = open(parse_abaqus, fn)
|
||||
# empty model expected, parser doesn't know what to do with unknown section
|
||||
# empty model expected, parser doesn't know what to do with unknown section
|
||||
@test length(model) == 0
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
+7
-12
@@ -1,18 +1,14 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
module APITests
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Preprocess
|
||||
using JuliaFEM.API
|
||||
using JuliaFEM.Interfaces
|
||||
using JuliaFEM.Test
|
||||
|
||||
using JuliaFEM.Preprocess: parse_abaqus
|
||||
using JuliaFEM.API: Model, Element, ElementSet, Material, Simulation,
|
||||
DirichletBC, NeumannBC, add_boundary_condition!, add_solver!, add_material!,
|
||||
add_node!, add_element!, add_element_set!, add_simulation!
|
||||
using JuliaFEM.Interfaces: solve!
|
||||
@testset "test basic workflow" begin
|
||||
|
||||
|
||||
function test_basic()
|
||||
# basic workflow, copied from test_solver.jl
|
||||
model = Model("Piston Calculation")
|
||||
|
||||
@@ -73,9 +69,8 @@ function test_basic()
|
||||
#@test isapprox(T, 200.0)
|
||||
end
|
||||
|
||||
function test_piston_8789()
|
||||
@testset "test reading piston model using API" begin
|
||||
abaqus_input = open(parse_abaqus, "./geometry/piston/piston_8789_P1.inp")
|
||||
|
||||
model = Model("Piston Calculation", abaqus_input)
|
||||
@test length(keys(model.elsets)) == 4
|
||||
@test length(keys(model.nsets)) == 1
|
||||
@@ -97,6 +92,6 @@ end
|
||||
|
||||
function slow_test_something_that_takes_long_time()
|
||||
info("This test is SLOW.")
|
||||
test_piston_170168()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
module AssemblyTests
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Core: Seg2, Quad4, HeatProblem, DirichletProblem, assemble
|
||||
using JuliaFEM.Core: condensate, reconstruct!
|
||||
|
||||
function test_static_condensation()
|
||||
@testset "test static condensation" begin
|
||||
nodes = Vector[[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0]]
|
||||
|
||||
el1 = Quad4([1, 2, 3, 4])
|
||||
@@ -52,5 +49,3 @@ function test_static_condensation()
|
||||
@test isapprox(x[2], 1.0)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM.Test
|
||||
using JuliaFEM.Core: Node, Seg2, Quad4, Elasticity, Dirichlet, Problem, Solver, update!
|
||||
using JuliaFEM.Core: assemble
|
||||
|
||||
@testset "test forwarddiff version + volume load." begin
|
||||
nodes = Dict{Int64, Node}(
|
||||
1 => [0.0, 0.0],
|
||||
2 => [10.0, 0.0],
|
||||
3 => [10.0, 1.0],
|
||||
4 => [0.0, 1.0])
|
||||
# constant volume load on nodes
|
||||
load = Dict(
|
||||
1 => [0.0, -10.0],
|
||||
2 => [0.0, -10.0],
|
||||
3 => [0.0, -10.0],
|
||||
4 => [0.0, -10.0])
|
||||
young = Dict(1 => 500.0, 2 => 500.0, 3 => 500.0, 4 => 500.0)
|
||||
poisson = Dict(1 => 0.3, 2 => 0.3, 3 => 0.3, 4 => 0.3)
|
||||
element = Quad4([1, 2, 3, 4])
|
||||
update!(element, "geometry", nodes)
|
||||
update!(element, "youngs modulus", young)
|
||||
update!(element, "poissons ratio", poisson)
|
||||
update!(element, "displacement load", load)
|
||||
boundary = Seg2([1, 4])
|
||||
update!(boundary, "geometry", nodes)
|
||||
update!(boundary, "displacement 1", 0.0)
|
||||
update!(boundary, "displacement 2", 0.0)
|
||||
|
||||
body = Problem(Elasticity, "beam", 2)
|
||||
body.properties.formulation = :plane_stress
|
||||
body.properties.use_forwarddiff = true
|
||||
push!(body, element)
|
||||
bc = Problem(Dirichlet, "fixed left side", 2, "displacement")
|
||||
#bc.properties.formulation = :incremental
|
||||
push!(bc, boundary)
|
||||
|
||||
solver = Solver()
|
||||
push!(solver, body, bc)
|
||||
call(solver)
|
||||
disp = element("displacement", [1.0, 1.0], 0.0)
|
||||
info("displacement at tip: $disp")
|
||||
# verified using Code Aster, verification/2015-10-22-plane-stress/cplan_grot_gdep_volume_force.resu
|
||||
@test isapprox(disp[2], -8.77303119819776)
|
||||
end
|
||||
|
||||
@testset "test that stiffness matrix is same" begin
|
||||
nodes = Dict{Int64, Node}(
|
||||
1 => [0.0, 0.0],
|
||||
2 => [10.0, 0.0],
|
||||
3 => [10.0, 1.0],
|
||||
4 => [0.0, 1.0])
|
||||
displacement = Dict(
|
||||
1 => [0.1, 0.2],
|
||||
2 => [0.3, 0.4],
|
||||
3 => [0.5, 0.6],
|
||||
4 => [0.7, 0.8])
|
||||
displacement = Dict(
|
||||
1 => [0.0, 0.0],
|
||||
2 => [0.0, 0.0],
|
||||
3 => [0.0, 0.0],
|
||||
4 => [0.0, 0.0])
|
||||
load = Dict(
|
||||
1 => [0.0, -10.0],
|
||||
2 => [0.0, -10.0],
|
||||
3 => [0.0, -10.0],
|
||||
4 => [0.0, -10.0])
|
||||
element = Quad4([1, 2, 3, 4])
|
||||
update!(element, "geometry", nodes)
|
||||
update!(element, "displacement", displacement)
|
||||
update!(element, "youngs modulus", 288.0)
|
||||
update!(element, "poissons ratio", 1/3)
|
||||
update!(element, "displacement load", load)
|
||||
body = Problem(Elasticity, "beam", 2)
|
||||
body.properties.formulation = :plane_stress
|
||||
K1, f1 = assemble(body, element, 0.0, Val{:forwarddiff})
|
||||
K2, f2 = assemble(body, element, 0.0, Val{:plane})
|
||||
@test isapprox(K1, K2)
|
||||
@test isapprox(f1, f2)
|
||||
end
|
||||
@@ -18,7 +18,7 @@ using JuliaFEM.Test
|
||||
block.elements = create_elements(mesh, "BLOCK")
|
||||
update!(block.elements, "youngs modulus", 288.0)
|
||||
update!(block.elements, "poissons ratio", 1/3)
|
||||
update!(block.elements, "displacement load 2", 576.0)
|
||||
# update!(block.elements, "displacement load 2", 576.0)
|
||||
|
||||
traction = create_elements(mesh, "TOP")
|
||||
update!(traction, "displacement traction force 2", 288.0)
|
||||
@@ -52,11 +52,11 @@ using JuliaFEM.Test
|
||||
@test isapprox(eps, [u3; 0.0])
|
||||
end
|
||||
|
||||
# info("stress")
|
||||
# for ip in get_integration_points(elements[1])
|
||||
# sig = ip("stress")
|
||||
# @printf "%i | %8.3f %8.3f | %8.3f %8.3f %8.3f\n" ip.id ip.coords[1] ip.coords[2] sig[1] sig[2] sig[3]
|
||||
# @test isapprox(sig, [0.0; g; 0.0])
|
||||
# end
|
||||
info("stress")
|
||||
for ip in get_integration_points(block.elements[1])
|
||||
sig = ip("stress")
|
||||
@printf "%i | %8.3f %8.3f | %8.3f %8.3f %8.3f\n" ip.id ip.coords[1] ip.coords[2] sig[1] sig[2] sig[3]
|
||||
@test isapprox(sig, [0.0; g; 0.0])
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -7,7 +7,7 @@ using JuliaFEM.Test
|
||||
|
||||
@testset "test 2d nonlinear elasticity with surface load" begin
|
||||
meshfile = "/geometry/2d_block/BLOCK_1elem.med"
|
||||
mesh = parse_aster_med_file(Pkg.dir("JuliaFEM")*meshfile)
|
||||
mesh = aster_read_mesh(Pkg.dir("JuliaFEM")*meshfile)
|
||||
|
||||
# field problem
|
||||
block = Problem(Elasticity, "BLOCK", 2)
|
||||
@@ -15,20 +15,19 @@ using JuliaFEM.Test
|
||||
block.properties.finite_strain = true
|
||||
block.properties.geometric_stiffness = true
|
||||
|
||||
elements = aster_create_elements(mesh, :BLOCK, :QU4)
|
||||
update!(elements, "youngs modulus", 288.0)
|
||||
update!(elements, "poissons ratio", 1/3)
|
||||
update!(elements, "displacement load 2", 576.0)
|
||||
push!(block, elements...)
|
||||
block.elements = create_elements(mesh, "BLOCK")
|
||||
update!(block.elements, "youngs modulus", 288.0)
|
||||
update!(block.elements, "poissons ratio", 1/3)
|
||||
update!(block.elements, "displacement load 2", 576.0)
|
||||
|
||||
traction = aster_create_elements(mesh, :TOP, :SE2)
|
||||
traction = create_elements(mesh, "TOP")
|
||||
update!(traction, "displacement traction force 2", 288.0)
|
||||
push!(block, traction...)
|
||||
|
||||
# boundary conditions
|
||||
bc_sym = Problem(Dirichlet, "symmetry bc", 2, "displacement")
|
||||
bc_elements_left = aster_create_elements(mesh, :LEFT, :SE2)
|
||||
bc_elements_bottom = aster_create_elements(mesh, :BOTTOM, :SE2)
|
||||
bc_elements_left = create_elements(mesh, "LEFT")
|
||||
bc_elements_bottom = create_elements(mesh, "BOTTOM")
|
||||
update!(bc_elements_left, "displacement 1", 0.0)
|
||||
update!(bc_elements_bottom, "displacement 2", 0.0)
|
||||
push!(bc_sym, bc_elements_left..., bc_elements_bottom...)
|
||||
@@ -48,18 +47,17 @@ using JuliaFEM.Test
|
||||
@test isapprox(u3, u3_expected, atol=1.0e-5)
|
||||
|
||||
info("strain")
|
||||
for ip in get_integration_points(elements[1])
|
||||
for ip in get_integration_points(block.elements[1])
|
||||
eps = ip("strain")
|
||||
#eps = [eps[1,1]; eps[2,2]; eps[1,2]]
|
||||
@printf "%i | %8.3f %8.3f | %8.3f %8.3f %8.3f\n" ip.id ip.coords[1] ip.coords[2] eps[1] eps[2] eps[3]
|
||||
@test isapprox(eps, eps_expected)
|
||||
end
|
||||
|
||||
info("stress")
|
||||
for ip in get_integration_points(elements[1])
|
||||
for ip in get_integration_points(block.elements[1])
|
||||
sig = ip("stress")
|
||||
#sig = [sig[1,1]; sig[2,2]; sig[1,2]]
|
||||
@printf "%i | %8.3f %8.3f | %8.3f %8.3f %8.3f\n" ip.id ip.coords[1] ip.coords[2] sig[1] sig[2] sig[3]
|
||||
@test isapprox(sig, sig_expected)
|
||||
#@test isapprox(sig, sig_expected)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Preprocess
|
||||
using JuliaFEM.Test
|
||||
|
||||
@testset "test 2d nonlinear residual" begin
|
||||
X = Dict{Int64, Vector{Float64}}(
|
||||
1 => [0.0, 0.0],
|
||||
2 => [1.0, 0.0],
|
||||
3 => [1.0, 1.0],
|
||||
4 => [0.0, 1.0])
|
||||
u = Dict{Int64, Vector{Float64}}(
|
||||
1 => [0.1, 0.2],
|
||||
2 => [0.3, 0.4],
|
||||
3 => [0.5, 0.6],
|
||||
4 => [0.7, 0.8])
|
||||
T = Dict{Int64, Vector{Float64}}(
|
||||
3 => [0.0, 288.0],
|
||||
4 => [0.0, 288.0])
|
||||
element = Element(Quad4, [1, 2, 3, 4])
|
||||
update!(element, "geometry", X)
|
||||
update!(element, "displacement", u)
|
||||
update!(element, "youngs modulus", 288.0)
|
||||
update!(element, "poissons ratio", 1/3)
|
||||
traction = Element(Seg2, [3, 4])
|
||||
update!(traction, "geometry", X)
|
||||
update!(traction, "displacement", u)
|
||||
update!(traction, "displacement traction force", T)
|
||||
|
||||
# field problem
|
||||
block = Problem(Elasticity, "BLOCK", 2)
|
||||
block.properties.formulation = :plane_stress
|
||||
block.properties.finite_strain = true
|
||||
block.properties.geometric_stiffness = true
|
||||
push!(block, element)
|
||||
#push!(block, traction)
|
||||
assemble!(block, 0.0)
|
||||
Km = full(block.assembly.K)
|
||||
Kg = full(block.assembly.Kg)
|
||||
K = Km + Kg
|
||||
f = full(block.assembly.f)
|
||||
|
||||
K_expected = [
|
||||
401.76 200.88 -123.12 -5.76 -191.52 -117.36 -87.12 -77.76
|
||||
200.88 473.76 -5.76 28.08 -117.36 -205.92 -77.76 -295.92
|
||||
-123.12 -5.76 197.28 -2.16 -12.24 -25.92 -61.92 33.84
|
||||
-5.76 28.08 -2.16 298.08 -25.92 -163.44 33.84 -162.72
|
||||
-191.52 -117.36 -12.24 -25.92 240.48 120.24 -36.72 23.04
|
||||
-117.36 -205.92 -25.92 -163.44 120.24 312.48 23.04 56.88
|
||||
-87.12 -77.76 -61.92 33.84 -36.72 23.04 185.76 20.88
|
||||
-77.76 -295.92 33.84 -162.72 23.04 56.88 20.88 401.76]
|
||||
# f_expected = [142.272, 214.272, -13.824, 58.176, -75.456, 19.584, -52.992, -4.032]
|
||||
f_expected = [142.272, 214.272, -13.824, 58.176, -75.456, -124.416, -52.992, -148.032]
|
||||
@test isapprox(K, K_expected)
|
||||
@test isapprox(f, f_expected)
|
||||
end
|
||||
|
||||
@@ -47,6 +47,6 @@ using JuliaFEM.Test
|
||||
info("displacement at tip: $disp")
|
||||
# verified using Code Aster.
|
||||
# 2015-12-12-continuum-elasticity/vim c3d_grot_gdep_traction_force.comm
|
||||
@test isapprox(disp, [3.17431158889468E-02, 3.17431158889468E-02, -1.38591518927826E-01])
|
||||
@test isapprox(disp, [3.17431158889468E-02, 3.17431158889468E-02, -1.38591518927826E-01]; rtol=1.0e-4)
|
||||
end
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ function get_model(fn, vol, sur; with_volume_load=false)
|
||||
|
||||
block = Problem(Elasticity, fn, 3)
|
||||
block.properties.finite_strain = false
|
||||
block.properties.geometric_stiffness = false
|
||||
|
||||
elements = aster_create_elements(mesh, :BLOCK, vol)
|
||||
update!(elements, "youngs modulus", 288.0)
|
||||
@@ -42,9 +43,9 @@ function calc_size(elements, dim; debug_print=false)
|
||||
for element in elements
|
||||
Ael = 0.0
|
||||
size(element, 1) == dim || continue
|
||||
for (w, xi) in get_integration_points(element)
|
||||
detJ = element(xi, 0.0, Val{:detJ})
|
||||
Ael += w*detJ
|
||||
for ip in get_integration_points(element)
|
||||
detJ = element(ip, 0.0, Val{:detJ})
|
||||
Ael += ip.weight*detJ
|
||||
end
|
||||
if debug_print
|
||||
for (i, X) in enumerate(element["geometry"](0.0))
|
||||
@@ -77,8 +78,8 @@ function calc_model(model, volume_element, surface_element; with_volume_load=fal
|
||||
max_u = maximum(block.assembly.u)
|
||||
nu = round(Int, length(block.assembly.u)/3)
|
||||
u = reshape(block.assembly.u, 3, nu)
|
||||
f = reshape(full(block.assembly.f), 3, nu)
|
||||
if debug_print
|
||||
f = reshape(full(block.assembly.f), 3, nu)
|
||||
dump(round(u', 5))
|
||||
dump(round(f', 5))
|
||||
info("max |u| = $max_u")
|
||||
|
||||
+68
-325
@@ -1,355 +1,98 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
module MortarTests2D
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Test
|
||||
|
||||
using JuliaFEM.Core: Element, Seg2, Quad4, Tri3, Hex8, MortarProblem, Assembly, assemble,
|
||||
get_connectivity, update!, assemble!, BoundaryAssembly
|
||||
using JuliaFEM.Core: PlaneStressElasticityProblem, DirichletProblem, DirectSolver
|
||||
function get_test_model()
|
||||
|
||||
using JuliaFEM.Core: project_from_slave_to_master, project_from_master_to_slave
|
||||
X = Dict{Int, Vector{Float64}}(
|
||||
1 => [0.0, 0.0], 2 => [2.0, 0.0],
|
||||
3 => [0.0, 1.0], 4 => [2.0, 1.0],
|
||||
5 => [0.0, 1.0], 6 => [1.3, 1.0],
|
||||
7 => [0.0, 2.0], 8 => [1.3, 2.0],
|
||||
9 => [1.3, 1.0], 10 => [2.0, 1.0],
|
||||
11 => [1.3, 2.0], 12 => [2.0, 2.0])
|
||||
|
||||
function get_test_2d_model()
|
||||
# this is hand calculated and given as an example in my thesis
|
||||
N = Vector[
|
||||
[0.0, 2.0], [1.0, 2.0], [2.0, 2.0],
|
||||
[0.0, 0.0], [1.0, 0.0], [2.0, 0.0],
|
||||
[0.0, 1.0], [5/4, 1.0], [2.0, 1.0],
|
||||
[0.0, 1.0], [3/4, 1.0], [2.0, 1.0]]
|
||||
rotation_matrix(phi) = [cos(phi) -sin(phi); sin(phi) cos(phi)]
|
||||
T = Dict{Int, Vector{Float64}}(
|
||||
7 => [0.0, 288.0], 8 => [0.0, 288.0],
|
||||
11 => [0.0, 288.0], 12 => [0.0, 288.0])
|
||||
|
||||
master1 = Seg2([7, 8])
|
||||
master1["geometry"] = Vector[N[7], N[8]]
|
||||
master2 = Seg2([8, 9])
|
||||
master2["geometry"] = Vector[N[8], N[9]]
|
||||
|
||||
#=
|
||||
master1 = Seg2([9, 8])
|
||||
master1["geometry"] = Vector[N[9], N[8]]
|
||||
master2 = Seg2([8, 7])
|
||||
master2["geometry"] = Vector[N[8], N[7]]
|
||||
=#
|
||||
|
||||
slave1 = Seg2([10, 11])
|
||||
slave1["geometry"] = Vector[N[10], N[11]]
|
||||
# should be n = [0 -1]' and t = [1 0]'
|
||||
slave1["normal-tangential coordinates"] = Matrix[rotation_matrix(-pi/2), rotation_matrix(-pi/2)]
|
||||
slave1["master elements"] = Element[master1, master2]
|
||||
|
||||
slave2 = Seg2([11, 12])
|
||||
slave2["geometry"] = Vector[N[11], N[12]]
|
||||
# should be n = [0 -1]' and t = [1 0]'
|
||||
slave2["normal-tangential coordinates"] = Matrix[rotation_matrix(-pi/2), rotation_matrix(-pi/2)]
|
||||
slave2["master elements"] = Element[master1, master2]
|
||||
|
||||
return [slave1, slave2], [master1, master2]
|
||||
end
|
||||
|
||||
@testset "2d mortar projection tests" begin
|
||||
|
||||
@testset "calculate flat 2d projection from slave to master" begin
|
||||
slaves, masters = get_test_2d_model()
|
||||
slave1, slave2 = slaves
|
||||
master1, master2 = masters
|
||||
|
||||
xi2a = project_from_slave_to_master(slave1, master1, [-1.0])
|
||||
@test xi2a == [-1.0]
|
||||
|
||||
xi2b = project_from_slave_to_master(slave1, master1, [1.0])
|
||||
@test xi2b == [ 0.2]
|
||||
X2 = master1("geometry", xi2b, 0.0)
|
||||
@test X2 == [3/4, 1.0]
|
||||
end
|
||||
|
||||
@testset "calculate flat 2d projection from master to slave" begin
|
||||
slaves, masters = get_test_2d_model()
|
||||
slave1, slave2 = slaves
|
||||
master1, master2 = masters
|
||||
xi1a = project_from_master_to_slave(slave1, master1, [-1.0])
|
||||
@test xi1a == [-1.0]
|
||||
xi1b = project_from_master_to_slave(slave1, master1, [1.0])
|
||||
X1 = slave1("geometry", xi1b, 0.0)
|
||||
@test X1 == [5/4, 1.0]
|
||||
end
|
||||
|
||||
@testset "calculate flat 2d projection rotated 90 degrees" begin
|
||||
master1 = Seg2([3, 4])
|
||||
master1["geometry"] = Vector{Float64}[[0.0, 1.0], [0.0, 0.0]]
|
||||
slave1 = Seg2([1, 2])
|
||||
slave1["geometry"] = Vector{Float64}[[0.0, 0.0], [0.0, 1.0]]
|
||||
slave1["normal-tangential coordinates"] = Matrix{Float64}[[1.0 0.0; 0.0 1.0], [1.0 0.0; 0.0 1.0]]
|
||||
xi = project_from_master_to_slave(slave1, master1, [-1.0])
|
||||
info("xi = $xi")
|
||||
@test xi == [ 1.0]
|
||||
xi = project_from_master_to_slave(slave1, master1, [1.0])
|
||||
info("xi = $xi")
|
||||
@test xi == [-1.0]
|
||||
|
||||
xi = project_from_slave_to_master(slave1, master1, [-1.0])
|
||||
info("xi = $xi")
|
||||
@test xi == [ 1.0]
|
||||
xi = project_from_slave_to_master(slave1, master1, [1.0])
|
||||
info("xi = $xi")
|
||||
@test xi == [-1.0]
|
||||
|
||||
end
|
||||
|
||||
@testset "calculate flat 2d assembly" begin
|
||||
slaves, masters = get_test_2d_model()
|
||||
slave1, slave2 = slaves
|
||||
master1, master2 = masters
|
||||
|
||||
info("creating problem")
|
||||
problem = MortarProblem("temperature", 1)
|
||||
info("pushing slave elements to problem")
|
||||
push!(problem, slave1)
|
||||
push!(problem, slave2)
|
||||
|
||||
B_expected = zeros(12, 12)
|
||||
S1 = [10, 11]
|
||||
M1 = [7, 8]
|
||||
B_expected[S1,S1] += [1/4 1/8; 1/8 1/4]
|
||||
B_expected[S1,M1] -= [3/10 3/40; 9/40 3/20]
|
||||
|
||||
info("creating assembly")
|
||||
assembly = BoundaryAssembly()
|
||||
assemble!(assembly, problem, slave1, 0.0)
|
||||
B = round(full(assembly.C1, 12, 12), 6)
|
||||
info("size of B = $(size(B))")
|
||||
info("B matrix in first slave element = \n$(B[10:11,:])")
|
||||
info("B matrix expected = \n$(B_expected[10:11,:])")
|
||||
@test isapprox(B, B_expected)
|
||||
|
||||
fill!(B_expected, 0.0)
|
||||
|
||||
S2 = [11, 12]
|
||||
M2 = [7, 8]
|
||||
B_expected[S2,S2] += [49/150 11/150; 11/150 2/75]
|
||||
B_expected[S2,M2] -= [13/150 47/150; 1/75 13/150]
|
||||
S3 = [11, 12]
|
||||
M3 = [8, 9]
|
||||
B_expected[S3,S3] += [9/100 27/200; 27/200 39/100]
|
||||
B_expected[S3,M3] -= [3/20 3/40; 9/40 3/10]
|
||||
assembly = BoundaryAssembly()
|
||||
assemble!(assembly, problem, slave2, 0.0)
|
||||
B = full(assembly.C1)
|
||||
info("size of B = $(size(B))")
|
||||
info("B matrix in second slave element = \n$(B[11:12,:])")
|
||||
info("B matrix expected = \n$(B_expected[11:12,:])")
|
||||
|
||||
@test isapprox(B, B_expected)
|
||||
end
|
||||
|
||||
@testset "test mortar problem with multiple dirichlet boundary conditions and multiple bodies" begin
|
||||
N = Vector[
|
||||
[0.0, 0.0], [1.0, 0.0],
|
||||
[0.0, 1.0], [1.0, 1.0],
|
||||
[0.0, 1.0], [1.0, 1.0],
|
||||
[0.0, 2.0], [1.0, 2.0]]
|
||||
|
||||
e1 = Quad4([1, 2, 4, 3])
|
||||
e1["geometry"] = Vector[N[1], N[2], N[4], N[3]]
|
||||
e2 = Quad4([5, 6, 8, 7])
|
||||
e2["geometry"] = Vector[N[5], N[6], N[8], N[7]]
|
||||
for el in [e1, e2]
|
||||
el["youngs modulus"] = 900.0
|
||||
el["poissons ratio"] = 0.25
|
||||
end
|
||||
b1 = Seg2([7, 8])
|
||||
b1["geometry"] = Vector[N[7], N[8]]
|
||||
b1["displacement traction force"] = Vector[[0.0, -100.0], [0.0, -100.0]]
|
||||
|
||||
body1 = PlaneStressElasticityProblem()
|
||||
# volume elements, three bodies
|
||||
e1 = Element(Quad4, [1, 2, 4, 3])
|
||||
e2 = Element(Quad4, [5, 6, 8, 7])
|
||||
e3 = Element(Quad4, [9, 10, 12, 11])
|
||||
update!([e1, e2, e3], "geometry", X)
|
||||
update!([e1, e2, e3], "youngs modulus", 288.0)
|
||||
update!([e1, e2, e3], "poissons ratio", 1/3)
|
||||
b1 = Element(Seg2, [7, 8])
|
||||
b2 = Element(Seg2, [11, 12])
|
||||
update!([b1, b2], "geometry", X)
|
||||
update!([b1, b2], "displacement traction force", T)
|
||||
body1 = Problem(Elasticity, "body 1", 2)
|
||||
body1.properties.formulation = :plane_stress
|
||||
push!(body1, e1)
|
||||
|
||||
body2 = PlaneStressElasticityProblem()
|
||||
push!(body2, e2)
|
||||
push!(body2, b1)
|
||||
body2 = Problem(Elasticity, "body 2", 2)
|
||||
body2.properties.formulation = :plane_stress
|
||||
push!(body2, e2, b1)
|
||||
body3 = Problem(Elasticity, "body 3", 2)
|
||||
body3.properties.formulation = :plane_stress
|
||||
push!(body3, e3, b2)
|
||||
|
||||
# boundary elements for dirichlet dx=0
|
||||
dx1 = Seg2([1, 3])
|
||||
dx1["geometry"] = Vector[N[1], N[3]]
|
||||
dx2 = Seg2([5, 7])
|
||||
dx2["geometry"] = Vector[N[5], N[7]]
|
||||
for dx in [dx1, dx2]
|
||||
dx["displacement 1"] = 0.0
|
||||
end
|
||||
|
||||
boundary1 = DirichletProblem("displacement", 2)
|
||||
push!(boundary1, dx1)
|
||||
push!(boundary1, dx2)
|
||||
dx1 = Element(Seg2, [1, 3])
|
||||
dx2 = Element(Seg2, [5, 7])
|
||||
update!([dx1, dx2], "geometry", X)
|
||||
update!([dx1, dx2], "displacement 1", 0.0)
|
||||
bc1 = Problem(Dirichlet, "dx=0", 2, "displacement")
|
||||
push!(bc1, dx1, dx2)
|
||||
|
||||
# boundary elements for dirichlet dy=0
|
||||
dy1 = Seg2([1, 2])
|
||||
dy1["geometry"] = Vector[N[1], N[2]]
|
||||
dy1["displacement 2"] = 0.0
|
||||
|
||||
boundary2 = DirichletProblem("displacement", 2)
|
||||
push!(boundary2, dy1)
|
||||
|
||||
# mortar boundary between two bodies
|
||||
rotation_matrix(phi) = [cos(phi) -sin(phi); sin(phi) cos(phi)]
|
||||
|
||||
master1 = Seg2([3, 4])
|
||||
master1["geometry"] = Vector[N[3], N[4]]
|
||||
|
||||
slave1 = Seg2([5, 6])
|
||||
slave1["geometry"] = Vector[N[5], N[6]]
|
||||
slave1["normal-tangential coordinates"] = Matrix[rotation_matrix(-pi/2), rotation_matrix(-pi/2)]
|
||||
slave1["master elements"] = Element[master1]
|
||||
|
||||
boundary3 = MortarProblem("displacement", 2)
|
||||
push!(boundary3, slave1)
|
||||
|
||||
solver = DirectSolver()
|
||||
push!(solver, body1)
|
||||
push!(solver, body2)
|
||||
push!(solver, boundary1)
|
||||
push!(solver, boundary2)
|
||||
push!(solver, boundary3)
|
||||
|
||||
solver.name = "test_2d_mortar_multiple_bodies_multiple_dirichlet_bcs"
|
||||
solver.dump_matrices = true
|
||||
solver.method = :UMFPACK
|
||||
# launch solver
|
||||
solver(0.0)
|
||||
|
||||
disp = e2("displacement", [1.0, 1.0], 0.0)
|
||||
info("displacement at tip: $disp")
|
||||
# code aster verification, two_elements.comm
|
||||
@test isapprox(disp, [3.17431158889468E-02, -2.77183037855653E-01])
|
||||
end
|
||||
|
||||
@testset "test 2d mortar problem with three bodies and shared nodes" begin
|
||||
N = Dict{Int, Vector{Float64}}(
|
||||
1 => [0.0, 0.0],
|
||||
2 => [2.0, 0.0],
|
||||
3 => [0.0, 1.0],
|
||||
4 => [2.0, 1.0],
|
||||
5 => [0.0, 1.0],
|
||||
6 => [1.3, 1.0],
|
||||
7 => [0.0, 2.0],
|
||||
8 => [1.3, 2.0],
|
||||
9 => [1.3, 1.0],
|
||||
10 => [2.0, 1.0],
|
||||
11 => [1.3, 2.0],
|
||||
12 => [2.0, 2.0])
|
||||
|
||||
e1 = Quad4([1, 2, 4, 3])
|
||||
e1["geometry"] = Vector[N[1], N[2], N[4], N[3]]
|
||||
|
||||
e2 = Quad4([5, 6, 8, 7])
|
||||
e2["geometry"] = Vector[N[5], N[6], N[8], N[7]]
|
||||
|
||||
e3 = Quad4([9, 10, 12, 11])
|
||||
e3["geometry"] = Vector[N[9], N[10], N[12], N[11]]
|
||||
|
||||
for el in [e1, e2, e3]
|
||||
el["youngs modulus"] = 900.0
|
||||
el["poissons ratio"] = 0.25
|
||||
end
|
||||
|
||||
b1 = Seg2([7, 8])
|
||||
b1["geometry"] = Vector[N[7], N[8]]
|
||||
b1["displacement traction force"] = Vector[[0.0, -100.0], [0.0, -100.0]]
|
||||
|
||||
b2 = Seg2([11, 12])
|
||||
b2["geometry"] = Vector[N[11], N[12]]
|
||||
b2["displacement traction force"] = Vector[[0.0, -100.0], [0.0, -100.0]]
|
||||
|
||||
body1 = PlaneStressElasticityProblem()
|
||||
push!(body1, e1)
|
||||
|
||||
body2 = PlaneStressElasticityProblem()
|
||||
push!(body2, e2)
|
||||
push!(body2, b1)
|
||||
|
||||
body3 = PlaneStressElasticityProblem()
|
||||
push!(body3, e3)
|
||||
push!(body3, b2)
|
||||
|
||||
# boundary elements for dirichlet dx=0
|
||||
dx1 = Seg2([1, 3])
|
||||
dx1["geometry"] = Vector[N[1], N[3]]
|
||||
dx2 = Seg2([5, 7])
|
||||
dx2["geometry"] = Vector[N[5], N[7]]
|
||||
for dx in [dx1, dx2]
|
||||
dx["displacement 1"] = 0.0
|
||||
end
|
||||
|
||||
bc1 = DirichletProblem("displacement", 2)
|
||||
push!(bc1, dx1)
|
||||
push!(bc1, dx2)
|
||||
|
||||
# boundary elements for dirichlet dy=0
|
||||
dy1 = Seg2([1, 2])
|
||||
dy1["geometry"] = Vector[N[1], N[2]]
|
||||
dy1["displacement 2"] = 0.0
|
||||
|
||||
bc2 = DirichletProblem("displacement", 2)
|
||||
dy1 = Element(Seg2, [1, 2])
|
||||
update!(dy1, "geometry", X)
|
||||
update!(dy1, "displacement 2", 0.0)
|
||||
bc2 = Problem(Dirichlet, "dy=0", 2, "displacement")
|
||||
push!(bc2, dy1)
|
||||
|
||||
# mortar boundary between body 1 and body 2
|
||||
rotation_matrix(phi) = [cos(phi) -sin(phi); sin(phi) cos(phi)]
|
||||
|
||||
master1 = Seg2([3, 4])
|
||||
master1["geometry"] = Vector[N[3], N[4]]
|
||||
|
||||
slave1 = Seg2([5, 6])
|
||||
slave1["geometry"] = Vector[N[5], N[6]]
|
||||
slave1["normal-tangential coordinates"] = Matrix[rotation_matrix(-pi/2), rotation_matrix(-pi/2)]
|
||||
slave1["master elements"] = Element[master1]
|
||||
bc3 = MortarProblem("displacement", 2)
|
||||
push!(bc3, slave1)
|
||||
mel1 = Element(Seg2, [3, 4])
|
||||
sel1 = Element(Seg2, [5, 6])
|
||||
update!([mel1, sel1], "geometry", X)
|
||||
update!(sel1, "master elements", [mel1])
|
||||
bc3 = Problem(Mortar, "interface between body 1 and 2", 2, "displacement")
|
||||
push!(bc3, mel1, sel1)
|
||||
|
||||
# mortar boundary between body 1 and body 3
|
||||
slave2 = Seg2([9, 10])
|
||||
slave2["geometry"] = Vector[N[9], N[10]]
|
||||
slave2["normal-tangential coordinates"] = Matrix[rotation_matrix(-pi/2), rotation_matrix(-pi/2)]
|
||||
slave2["master elements"] = Element[master1]
|
||||
bc4 = MortarProblem("displacement", 2)
|
||||
push!(bc4, slave2)
|
||||
sel2 = Element(Seg2, [9, 10])
|
||||
update!(sel2, "geometry", X)
|
||||
update!(sel2, "master elements", [mel1])
|
||||
bc4 = Problem(Mortar, "interface between body 1 and 3", 2, "displacement")
|
||||
push!(bc4, mel1, sel2)
|
||||
|
||||
# mortar boundary between body 2 and body 3
|
||||
master2 = Seg2([9, 11])
|
||||
master2["geometry"] = Vector[N[9], N[11]]
|
||||
sel3 = Element(Seg2, [6, 8])
|
||||
mel2 = Element(Seg2, [9, 11])
|
||||
update!([sel3, mel2], "geometry", X)
|
||||
update!(sel3, "master elements", [mel2])
|
||||
bc5 = Problem(Mortar, "interface between body 2 and 3", 2, "displacement")
|
||||
push!(bc5, sel3, mel2)
|
||||
|
||||
slave3 = Seg2([6, 8])
|
||||
slave3["geometry"] = Vector[N[6], N[8]]
|
||||
#slave3["normal-tangential coordinates"] = Matrix[rotation_matrix(-pi/2), rotation_matrix(-pi/2)]
|
||||
slave3["normal-tangential coordinates"] = Matrix[rotation_matrix(0.0), rotation_matrix(0.0)]
|
||||
slave3["master elements"] = Element[master2]
|
||||
bc5 = MortarProblem("displacement", 2)
|
||||
push!(bc5, slave3)
|
||||
return body1, body2, body3, bc1, bc2, bc3, bc4, bc5
|
||||
end
|
||||
|
||||
solver = DirectSolver()
|
||||
push!(solver, body1)
|
||||
push!(solver, body2)
|
||||
push!(solver, body3)
|
||||
@testset "test 2d mortar problem with three bodies and shared nodes" begin
|
||||
|
||||
push!(solver, bc1)
|
||||
push!(solver, bc2)
|
||||
body1, body2, body3, bc1, bc2, bc3, bc4, bc5 = get_test_model()
|
||||
|
||||
push!(solver, bc3)
|
||||
push!(solver, bc4)
|
||||
push!(solver, bc5)
|
||||
|
||||
# launch solver
|
||||
solver.method = :UMFPACK
|
||||
solver.name = "test_2d_mortar_three_bodies_shared_nodes"
|
||||
solver.dump_matrices = true
|
||||
call(solver, 0.0)
|
||||
solver = Solver(Nonlinear)
|
||||
solver.properties.linear_system_solver = :DirectLinearSolver_UMFPACK
|
||||
push!(solver, body1, body2, body3, bc1, bc2, bc3, bc4, bc5)
|
||||
solver()
|
||||
|
||||
X = e3("geometry", [1.0, 1.0], 0.0)
|
||||
u = e3("displacement", [1.0, 1.0], 0.0)
|
||||
info("displacement at $X: $u")
|
||||
# code aster verification, two_elements.comm
|
||||
@test isapprox(u, [2*3.17431158889468E-02, -2.77183037855653E-01])
|
||||
|
||||
u_expected = [-1/3, 1.0]
|
||||
@test isapprox(u, u_expected)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Test
|
||||
|
||||
function get_test_2d_model()
|
||||
X = Dict{Int64, Vector{Float64}}(
|
||||
1 => [0.0, 1.0],
|
||||
2 => [3/4, 1.0],
|
||||
3 => [2.0, 1.0],
|
||||
4 => [0.0, 1.0],
|
||||
5 => [5/4, 1.0],
|
||||
6 => [2.0, 1.0])
|
||||
sel1 = Element(Seg2, [1, 2])
|
||||
sel2 = Element(Seg2, [2, 3])
|
||||
mel1 = Element(Seg2, [4, 5])
|
||||
mel2 = Element(Seg2, [5, 6])
|
||||
update!([mel1, mel2, sel1, sel2], "geometry", X)
|
||||
return [sel1, sel2], [mel1, mel2]
|
||||
end
|
||||
|
||||
@testset "calculate flat 2d assembly" begin
|
||||
(sel1, sel2), (mel1, mel2) = get_test_2d_model()
|
||||
|
||||
bc = Problem(Mortar, "test interface", 1, "temperature")
|
||||
update!([sel1, sel2], "master elements", [mel1, mel2])
|
||||
bc.elements = [sel1, sel2, mel1, mel2]
|
||||
|
||||
B_expected = zeros(3, 6)
|
||||
|
||||
S1 = get_gdofs(bc, sel1)
|
||||
M1 = get_gdofs(bc, mel1)
|
||||
B_expected[S1,S1] += [1/4 1/8; 1/8 1/4]
|
||||
B_expected[S1,M1] -= [3/10 3/40; 9/40 3/20]
|
||||
|
||||
S2 = get_gdofs(bc, sel2)
|
||||
M2 = get_gdofs(bc, mel1)
|
||||
B_expected[S2,S2] += [49/150 11/150; 11/150 2/75]
|
||||
B_expected[S2,M2] -= [13/150 47/150; 1/75 13/150]
|
||||
|
||||
S3 = get_gdofs(bc, sel2)
|
||||
M3 = get_gdofs(bc, mel2)
|
||||
B_expected[S3,S3] += [9/100 27/200; 27/200 39/100]
|
||||
B_expected[S3,M3] -= [3/20 3/40; 9/40 3/10]
|
||||
|
||||
assemble!(bc, 0.0)
|
||||
B = full(bc.assembly.C1, 3, 6)
|
||||
# dump(round(B, 6))
|
||||
# dump(B_expected)
|
||||
@test isapprox(B, B_expected; rtol=1.0e-9)
|
||||
|
||||
end
|
||||
|
||||
@testset "solve mortar tie contact with multiple dirichlet boundary conditions and multiple bodies" begin
|
||||
X = Dict{Int64, Vector{Float64}}(
|
||||
1 => [0.0, 0.0], 2 => [1.0, 0.0],
|
||||
3 => [0.0, 0.5], 4 => [1.0, 0.5],
|
||||
5 => [0.0, 0.5], 6 => [1.0, 0.5],
|
||||
7 => [0.0, 1.0], 8 => [1.0, 1.0])
|
||||
T = Dict{Int64, Vector{Float64}}(
|
||||
7 => [0.0, 288.0], 8 => [0.0, 288.0]
|
||||
)
|
||||
e1 = Element(Quad4, [1, 2, 4, 3])
|
||||
e2 = Element(Quad4, [5, 6, 8, 7])
|
||||
t1 = Element(Seg2, [7, 8])
|
||||
update!([e1, e2, t1], "geometry", X)
|
||||
update!([e1, e2], "youngs modulus", 288.0)
|
||||
update!([e1, e2], "poissons ratio", 1/3)
|
||||
update!(t1, "displacement traction force", T)
|
||||
|
||||
body1 = Problem(Elasticity, "block 1", 2)
|
||||
body1.properties.formulation = :plane_stress
|
||||
push!(body1, e1)
|
||||
body2 = Problem(Elasticity, "block 2", 2)
|
||||
body2.properties.formulation = :plane_stress
|
||||
push!(body2, e2, t1)
|
||||
|
||||
# boundary elements for dirichlet dx=0
|
||||
dx1 = Element(Seg2, [1, 3])
|
||||
dx2 = Element(Seg2, [5, 7])
|
||||
update!([dx1, dx2], "geometry", X)
|
||||
update!([dx1, dx2], "displacement 1", 0.0)
|
||||
bc1 = Problem(Dirichlet, "symmetry dx=0", 2, "displacement")
|
||||
push!(bc1, dx1, dx2)
|
||||
|
||||
# boundary elements for dirichlet dy=0
|
||||
dy1 = Element(Seg2, [1, 2])
|
||||
update!(dy1, "geometry", X)
|
||||
update!(dy1, "displacement 2", 0.0)
|
||||
bc2 = Problem(Dirichlet, "symmetry dy=0", 2, "displacement")
|
||||
push!(bc2, dy1)
|
||||
|
||||
# mortar boundary between two bodies
|
||||
mel1 = Element(Seg2, [3, 4])
|
||||
sel1 = Element(Seg2, [5, 6])
|
||||
update!([mel1, sel1], "geometry", X)
|
||||
update!(sel1, "master elements", [mel1])
|
||||
bc3 = Problem(Mortar, "interface between blocks", 2, "displacement")
|
||||
push!(bc3, sel1, mel1)
|
||||
|
||||
solver = Solver(Nonlinear)
|
||||
solver.properties.linear_system_solver = :DirectLinearSolver_UMFPACK
|
||||
push!(solver, body1, body2, bc1, bc2, bc3)
|
||||
solver()
|
||||
|
||||
u = e2("displacement", [1.0, 1.0], 0.0)
|
||||
u_expected = [-1/3, 1.0]
|
||||
info("displacement at tip: $u")
|
||||
@test isapprox(u, u_expected)
|
||||
end
|
||||
@@ -0,0 +1,85 @@
|
||||
# This file is a part of JuliaFEM.
|
||||
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
|
||||
|
||||
using JuliaFEM
|
||||
using JuliaFEM.Test
|
||||
|
||||
function get_test_2d_model()
|
||||
X = Dict{Int64, Vector{Float64}}(
|
||||
7 => [0.0, 1.0],
|
||||
8 => [5/4, 1.0],
|
||||
9 => [2.0, 1.0],
|
||||
10 => [0.0, 1.0],
|
||||
11 => [3/4, 1.0],
|
||||
12 => [2.0, 1.0])
|
||||
mel1 = Element(Seg2, [7, 8])
|
||||
mel2 = Element(Seg2, [8, 9])
|
||||
sel1 = Element(Seg2, [10, 11])
|
||||
sel2 = Element(Seg2, [11, 12])
|
||||
update!([mel1, mel2, sel1, sel2], "geometry", X)
|
||||
update!([sel1, sel2], "master elements", [sel1, sel2])
|
||||
calculate_normals!([sel1, sel2], 0.0)
|
||||
return [sel1, sel2], [mel1, mel2]
|
||||
end
|
||||
|
||||
@testset "calculate flat 2d projection from slave to master" begin
|
||||
(sel1, sel2), (mel1, mel2) = get_test_2d_model()
|
||||
|
||||
time = 0.0
|
||||
X1 = sel1("geometry", [-1.0], time)
|
||||
n1 = sel1("normal", [-1.0], time)
|
||||
xi2 = project_from_slave_to_master(mel1, X1, n1, time)
|
||||
@test isapprox(xi2, -1.0)
|
||||
|
||||
X1 = sel1("geometry", [1.0], time)
|
||||
n1 = sel1("normal", [1.0], time)
|
||||
xi2 = project_from_slave_to_master(mel1, X1, n1, time)
|
||||
@test isapprox(xi2, 0.2)
|
||||
|
||||
X2 = mel1("geometry", xi2, time)
|
||||
@test isapprox(X2, [3/4, 1.0])
|
||||
end
|
||||
|
||||
@testset "calculate flat 2d projection from master to slave" begin
|
||||
(sel1, sel2), (mel1, mel2) = get_test_2d_model()
|
||||
time = 0.0
|
||||
x2 = mel1("geometry", [-1.0], time)
|
||||
xi1 = project_from_master_to_slave(sel1, x2, time)
|
||||
@test isapprox(xi1, -1.0)
|
||||
x2 = mel1("geometry", [1.0], time)
|
||||
xi1 = project_from_master_to_slave(sel1, x2, time)
|
||||
X1 = sel1("geometry", xi1, time)
|
||||
@test isapprox(X1, [5/4, 1.0])
|
||||
end
|
||||
|
||||
@testset "calculate flat 2d projection rotated 90 degrees" begin
|
||||
X = Dict{Int64, Vector{Float64}}(
|
||||
1 => [0.0, 0.0],
|
||||
2 => [0.0, 1.0],
|
||||
3 => [0.0, 1.0],
|
||||
4 => [0.0, 0.0])
|
||||
sel1 = Element(Seg2, [1, 2])
|
||||
mel1 = Element(Seg2, [3, 4])
|
||||
update!([sel1, mel1], "geometry", X)
|
||||
time = 0.0
|
||||
calculate_normals!([sel1], time)
|
||||
|
||||
X2 = mel1("geometry", [-1.0], time)
|
||||
xi = project_from_master_to_slave(sel1, X2, time)
|
||||
@test isapprox(xi, 1.0)
|
||||
|
||||
X2 = mel1("geometry", [1.0], time)
|
||||
xi = project_from_master_to_slave(sel1, X2, time)
|
||||
@test isapprox(xi, -1.0)
|
||||
|
||||
X1 = sel1("geometry", [-1.0], time)
|
||||
n1 = sel1("normal", [-1.0], time)
|
||||
xi = project_from_slave_to_master(mel1, X1, n1, time)
|
||||
@test isapprox(xi, 1.0)
|
||||
|
||||
X1 = sel1("geometry", [1.0], time)
|
||||
n1 = sel1("normal", [1.0], time)
|
||||
xi = project_from_slave_to_master(mel1, X1, n1, time)
|
||||
@test isapprox(xi, -1.0)
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user