more general way to define saddle point problem.

This commit is contained in:
Jukka Aho
2015-12-23 01:52:28 +02:00
parent a4548d5b5a
commit bba9d380fb
14 changed files with 1115 additions and 659 deletions
File diff suppressed because one or more lines are too long
@@ -2457,7 +2457,7 @@
},
{
"cell_type": "code",
"execution_count": 76,
"execution_count": 84,
"metadata": {
"collapsed": false
},
@@ -2468,7 +2468,7 @@
"false"
]
},
"execution_count": 76,
"execution_count": 84,
"metadata": {},
"output_type": "execute_result"
}
@@ -2479,9 +2479,8 @@
"using JuliaFEM.Core: calculate_normal_tangential_coordinates!\n",
"\n",
"# 2d rotation matrix\n",
"#ϕ = -pi/4\n",
"phi = pi/10\n",
"#phi = 0.0\n",
"#phi = pi/10\n",
"phi = 0.0\n",
"rmat(phi) = [cos(phi) -sin(phi); sin(phi) cos(phi)]\n",
"\n",
"geometry = Dict{Int64, Node}(\n",
@@ -2498,11 +2497,14 @@
"\n",
"el1[\"youngs modulus\"] = 900.0\n",
"el1[\"poissons ratio\"] = 0.25\n",
"# traction force in normal direction, (i.e. pressure load)\n",
"el2[\"displacement traction force N\"] = 100.0\n",
"# support sides in normal direction\n",
"el3[\"displacement 2\"] = 0.0\n",
"el4[\"displacement 1\"] = 0.0\n",
"# traction force in local coordinates\n",
"el2[\"local displacement traction force 1\"] = 100.0\n",
"# support sides in local coordinates\n",
"el3[\"local displacement 1\"] = 0.0\n",
"el4[\"local displacement 2\"] = 0.0\n",
"for el in [el3, el4]\n",
" el[\"displacement near coord (0.0,0.0)\"] = 0.0\n",
"end\n",
"problem = PlaneStressLinearElasticityProblem(\"block\")\n",
"boundary = DirichletProblem(\"dirichlet boundary conditions\", \"displacement\", 2)\n",
"push!(problem, el1, el2)\n",
@@ -2517,7 +2519,7 @@
},
{
"cell_type": "code",
"execution_count": 77,
"execution_count": 85,
"metadata": {
"collapsed": false
},
@@ -2525,14 +2527,12 @@
{
"data": {
"text/plain": [
"8x1 sparse matrix with 4 Float64 entries:\n",
"\t[5, 1] = 15.4508\n",
"\t[6, 1] = -47.5528\n",
"\t[7, 1] = 15.4508\n",
"\t[8, 1] = -47.5528"
"8x1 sparse matrix with 2 Float64 entries:\n",
"\t[6, 1] = -50.0\n",
"\t[8, 1] = -50.0"
]
},
"execution_count": 77,
"execution_count": 85,
"metadata": {},
"output_type": "execute_result"
}
@@ -2542,109 +2542,6 @@
"f = sparse(JuliaFEM.Core.assemble(problem, 0.0).force_vector)"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"B\n",
"Array(Float64,(8,8)) 8x8 Array{Float64,2}:\n",
" 2.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n",
" 0.0 2.0 0.0 0.0 0.0 0.0 0.0 0.0\n",
" 0.0 0.0 2.0 0.0 0.0 0.0 0.0 0.0\n",
" 0.0 0.0 0.0 2.0 0.0 0.0 0.0 0.0\n",
" 0.0 0.0 0.0 0.0 2.0 0.0 0.0 0.0\n",
" 0.0 0.0 0.0 0.0 0.0 2.0 0.0 0.0\n",
" 0.0 0.0 0.0 0.0 0.0 0.0 2.0 0.0\n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 2.0\n",
"C\n",
"Array(Float64,(8,8)) 8x8 Array{Float64,2}:\n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n",
"D\n",
"Array(Float64,(8,8)) 8x8 Array{Float64,2}:\n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n"
]
}
],
"source": [
"# biorthogonal version\n",
"m = [1 0; 0 1]\n",
"#m = 1/6*[2 1; 1 2]\n",
"\n",
"\n",
"B = spzeros(8, 8)\n",
"C = spzeros(8, 8)\n",
"D = spzeros(8, 8)\n",
"\n",
"B[[1,3],[1,3]] += m\n",
"B[[2,4],[2,4]] += m\n",
"\n",
"B[[1,7],[1,7]] += m\n",
"B[[2,8],[2,8]] += m\n",
"\n",
"B[[3,5],[3,5]] += m\n",
"B[[4,6],[4,6]] += m\n",
"\n",
"B[[7,5],[7,5]] += m\n",
"B[[8,6],[8,6]] += m\n",
"\n",
"# version 1\n",
"\n",
"tangents = Vector{Float64}[\n",
" rmat(phi)*[1.0, 0.0],\n",
" rmat(phi)*[1.0, 0.0],\n",
" rmat(phi)*[0.0, 1.0],\n",
" rmat(phi)*[0.0, 1.0]]\n",
"\n",
"normals = Vector{Float64}[rot(pi/2)*t for t in tangents]\n",
"\n",
"#=\n",
"# fixed in every direction\n",
"C[1, [1,2]] = normals[1]\n",
"C[2, [1,2]] = tangents[1]\n",
"#C[1,1] = 1.0\n",
"#C[2,2] = 1.0\n",
"# normal fixed, tangential free\n",
"C[3, [3,4]] = normals[2]\n",
"D[4, [3,4]] = tangents[2]\n",
"# allowed to move in n and t directions (inactive)\n",
"D[5, [5,6]] = normals[3]\n",
"D[6, [5,6]] = tangents[3]\n",
"#D[5,5] = 1.0\n",
"#D[6,6] = 1.0\n",
"# normal fixed, tangential free\n",
"C[7, [7,8]] = normals[4]\n",
"D[8, [7,8]] = tangents[4]\n",
"=#\n",
"\n",
"println(\"B\")\n",
"dump(round(full(B), 3))\n",
"println(\"C\")\n",
"dump(round(full(C), 3))\n",
"println(\"D\")\n",
"dump(round(full(D), 3))"
]
},
{
"cell_type": "code",
"execution_count": 21,
@@ -2693,7 +2590,7 @@
},
{
"cell_type": "code",
"execution_count": 78,
"execution_count": 86,
"metadata": {
"collapsed": false
},
@@ -2702,10 +2599,10 @@
"name": "stderr",
"output_type": "stream",
"text": [
"INFO: De = [0.49999999999999994 0.0\n",
" 0.0 0.49999999999999994]\n",
"INFO: De = [0.49999999999999994 0.0\n",
" 0.0 0.49999999999999994]\n"
"INFO: De = [0.5 0.0\n",
" 0.0 0.5]\n",
"INFO: De = [0.5 0.0\n",
" 0.0 0.5]\n"
]
},
{
@@ -2719,10 +2616,10 @@
"name": "stderr",
"output_type": "stream",
"text": [
"INFO: De = [0.49999999999999994 0.0\n",
" 0.0 0.49999999999999994]\n",
"INFO: De = [0.49999999999999994 0.0\n",
" 0.0 0.49999999999999994]\n"
"INFO: De = [0.5 0.0\n",
" 0.0 0.5]\n",
"INFO: De = [0.5 0.0\n",
" 0.0 0.5]\n"
]
},
{
@@ -2739,22 +2636,22 @@
" 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0\n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0\n",
"Array(Float64,(7,8)) 7x8 Array{Float64,2}:\n",
" 1.28 2.52 0.0 0.0 0.0 0.0 0.0 0.0 \n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
" 0.0 0.0 -0.62 1.9 0.0 0.0 0.0 0.0 \n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
" 0.0 0.0 0.0 0.0 0.0 0.0 1.9 0.62\n",
" 2.0 2.0 0.0 0.0 0.0 0.0 0.0 0.0\n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n",
" 0.0 0.0 0.0 2.0 0.0 0.0 0.0 0.0\n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n",
" 0.0 0.0 0.0 0.0 0.0 0.0 2.0 0.0\n",
"Array(Float64,(8,8)) 8x8 Array{Float64,2}:\n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n",
" 2.52 -1.28 0.0 0.0 0.0 0.0 0.0 0.0\n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n",
" 0.0 0.0 1.9 0.62 0.0 0.0 0.0 0.0\n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.62 -1.9\n"
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n",
" 2.0 -2.0 0.0 0.0 0.0 0.0 0.0 0.0\n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n",
" 0.0 0.0 2.0 0.0 0.0 0.0 0.0 0.0\n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -2.0\n"
]
}
],
@@ -2953,7 +2850,7 @@
},
{
"cell_type": "code",
"execution_count": 79,
"execution_count": 119,
"metadata": {
"collapsed": false
},
@@ -2962,25 +2859,25 @@
"data": {
"text/plain": [
"16x16 Array{Float64,2}:\n",
" 351.832 121.353 -231.353 -118.168 -131.832 -121.353 11.3525 118.168 2.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
" 121.353 528.168 -58.1678 11.3525 -121.353 -308.168 58.1678 -231.353 0.0 2.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
" -231.353 -58.1678 528.168 -121.353 11.3525 58.1678 -308.168 121.353 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 \n",
" -118.168 11.3525 -121.353 351.832 118.168 -231.353 121.353 -131.832 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 \n",
" -131.832 -121.353 11.3525 118.168 351.832 121.353 -231.353 -118.168 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
" -121.353 -308.168 58.1678 -231.353 121.353 528.168 -58.1678 11.3525 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
" 11.3525 58.1678 -308.168 121.353 -231.353 -58.1678 528.168 -121.353 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 \n",
" 118.168 -231.353 121.353 -131.832 -118.168 11.3525 -121.353 351.832 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 \n",
" 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
" 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
" 0.0 0.0 -0.618034 1.90211 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.90211 0.618034 0.0 0.0 0.0 0.0 \n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
" 0.0 0.0 0.0 0.0 0.0 0.0 1.90211 0.618034 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 \n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.618034 -1.90211"
" 440.0 150.0 -260.0 -30.0 -220.0 -150.0 40.0 30.0 2.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n",
" 150.0 440.0 30.0 40.0 -150.0 -220.0 -30.0 -260.0 0.0 2.0 0.0 0.0 0.0 0.0 0.0 0.0\n",
" -260.0 30.0 440.0 -150.0 40.0 -30.0 -220.0 150.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0\n",
" -30.0 40.0 -150.0 440.0 30.0 -260.0 150.0 -220.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0\n",
" -220.0 -150.0 40.0 30.0 440.0 150.0 -260.0 -30.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n",
" -150.0 -220.0 -30.0 -260.0 150.0 440.0 30.0 40.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n",
" 40.0 -30.0 -220.0 150.0 -260.0 30.0 440.0 -150.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0\n",
" 30.0 -260.0 150.0 -220.0 -30.0 40.0 -150.0 440.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0\n",
" 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n",
" 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n",
" 0.0 0.0 0.0 2.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 2.0 0.0 0.0 0.0 0.0 0.0\n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n",
" 0.0 0.0 0.0 0.0 0.0 0.0 2.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0\n",
" 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 -2.0"
]
},
"execution_count": 79,
"execution_count": 119,
"metadata": {},
"output_type": "execute_result"
}
@@ -2989,17 +2886,24 @@
"C1 = sparse(ntass.C1, 8, 8)\n",
"C2 = sparse(ntass.C2, 8, 8)\n",
"D = sparse(ntass.D, 8, 8)\n",
"C2[1,:] = 0\n",
"D[2,:] = 0\n",
"C2[1,1] = 1\n",
"C2[2,2] = 1\n",
"#C2[2,:] = D[2,:]\n",
"#D[2,:] = 0\n",
"A = [K C1'; C2 D]\n",
"A[9,:] = 0\n",
"A[10,:] = 0\n",
"A[9, 1] = 1\n",
"A[10, 2] = 1\n",
"#A[9,:] = 0\n",
"#A[9, 1] = 1\n",
"#A[10,:] = 0\n",
"#A[10, 1] = 2\n",
"#A[10, 2] = -2\n",
"full(A)"
]
},
{
"cell_type": "code",
"execution_count": 81,
"execution_count": 120,
"metadata": {
"collapsed": false
},
@@ -3008,11 +2912,11 @@
"data": {
"text/plain": [
"2x8 Array{Float64,2}:\n",
" 0.0 0.0264182 0.0607535 0.0343352 7.72542 15.4508 0.0 0.0\n",
" 0.0 0.00858381 -0.0970891 -0.105673 -23.7764 -47.5528 0.0 0.0"
" 0.0 0.0277778 0.0277778 0.0 0.0 0.0 0.0 0.0\n",
" 0.0 0.0 -0.111111 -0.111111 -25.0 -50.0 0.0 0.0"
]
},
"execution_count": 81,
"execution_count": 120,
"metadata": {},
"output_type": "execute_result"
}
@@ -3029,7 +2933,7 @@
},
{
"cell_type": "code",
"execution_count": 82,
"execution_count": 83,
"metadata": {
"collapsed": false
},
@@ -3037,16 +2941,17 @@
{
"data": {
"text/plain": [
"0.11453071182271284"
"Test Passed\n",
" Expression: isapprox(norm(sol[:,3]),0.11453071182271282)"
]
},
"execution_count": 82,
"execution_count": 83,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"norm(sol[:,3])"
"@test isapprox(norm(sol[:,3]), 0.11453071182271282)"
]
},
{
+20 -12
View File
@@ -25,6 +25,13 @@ function append!(assembly::Assembly, sub_assembly::Assembly)
append!(assembly.force_vector, sub_assembly.force_vector)
end
function append!(assembly::BoundaryAssembly, sub_assembly::BoundaryAssembly)
append!(assembly.C1, sub_assembly.C1)
append!(assembly.C2, sub_assembly.C2)
append!(assembly.D, sub_assembly.D)
append!(assembly.g, sub_assembly.g)
end
function assemble!(assembly::Assembly, problem::AllProblems, time::Float64, empty_assembly::Bool=true)
if empty_assembly
empty!(assembly)
@@ -34,17 +41,24 @@ function assemble!(assembly::Assembly, problem::AllProblems, time::Float64, empt
end
end
""" Decide assembly type from given problem type. """
function new_assembly{P}(problem_type::Type{FieldProblem{P}})
return FieldAssembly()
end
""" Decide assembly type from given problem type. """
function new_assembly{P}(problem_type::Type{BoundaryProblem{P}})
return BoundaryAssembly()
end
function assemble(problem::AllProblems, elrange::UnitRange{Int64}, time::Real, optimize=false)
elements = get_elements(problem)[elrange]
assembly = Assembly()
assembly = new_assembly(typeof(problem))
for (i, element) in enumerate(elements)
assemble!(assembly, problem, element, time)
end
if optimize
dim1 = length(assembly.stiffness_matrix.I)
optimize!(assembly)
dim2 = length(assembly.stiffness_matrix.I)
info("combine: dim1 = $dim1, dim2 = $dim2")
end
return assembly
end
@@ -53,11 +67,7 @@ function assemble(problem::AllProblems, time::Real, nchunks=10)
ne = length(get_elements(problem))
kk = round(Int, collect(linspace(0, ne, nchunks+1)))
slices = [kk[j]+1:kk[j+1] for j=1:nchunks]
# sub_assemblies = map( (elrange) -> assemble(problem, elrange, time), slices)
# assembly = sum(sub_assemblies)
assembly = Assembly()
assembly = new_assembly(typeof(problem))
for (j, elrange) in enumerate(slices)
sub_assembly = assemble(problem, elrange, time)
append!(assembly, sub_assembly)
@@ -65,9 +75,6 @@ function assemble(problem::AllProblems, time::Real, nchunks=10)
info("Assembly: ", round(j/nchunks*100,1), " % done. ")
end
end
# optimize!(assembly)
# dim = length(assembly.stiffness_matrix.I)
# info("dim of COO: $dim")
return assembly
end
@@ -173,3 +180,4 @@ function Base.(:+)(ass1::Assembly, ass2::Assembly)
force_vector = ass1.force_vector + ass2.force_vector
return Assembly(mass_matrix, stiffness_matrix, force_vector)
end
+31 -16
View File
@@ -38,11 +38,11 @@ function DirectSolver(name="DirectSolver")
1.0e-6, # convergence tolerance
false, # dump matrices
true, # reduce stiffness matrix
:CHOLMOD # method: CHOLMOD, UMFPACK, PETSc_GMRES
:UMFPACK # method: CHOLMOD, UMFPACK, PETSc_GMRES
)
end
function push!(solver::DirectSolver, problem::Problem)
function push!(solver::DirectSolver, problem::FieldProblem)
push!(solver.field_problems, problem)
end
@@ -138,9 +138,21 @@ function solve(K, f, C, g, ::Type{Val{:UMFPACK}})
return u[1:dim], u[dim+1:end]
end
function solve(K, f, C1, C2, D, g, ::Type{Val{:UMFPACK}})
t0 = time()
dim = size(K, 1)
A = [K C1'; C2 D]
b = [f; g]
nz1 = sort(unique(rowvals(A)))
nz2 = sort(unique(rowvals(A')))
u = zeros(length(b))
u[nz1] = lufact(A[nz1,nz2]) \ full(b[nz1])
info("UMFPACK: solved in ", time()-t0, " seconds. norm = ", norm(u[1:dim]))
return u[1:dim], u[dim+1:end]
end
""" Call solver to solve a set of problems. """
function call(solver::DirectSolver, time::Number=0.0)
function call(solver::DirectSolver, time::Real=0.0)
info("Starting solver $(solver.name)")
info("# of field problems: $(length(solver.field_problems))")
info("# of boundary problems: $(length(solver.boundary_problems))")
@@ -201,7 +213,7 @@ function call(solver::DirectSolver, time::Number=0.0)
tic(timing, "field assembly")
info("Assembling field problems...")
field_assembly = Assembly()
field_assembly = FieldAssembly()
for (i, problem) in enumerate(solver.field_problems)
info("Assembling body $i: $(problem.name)")
append!(field_assembly, assemble(problem, time))
@@ -216,36 +228,38 @@ function call(solver::DirectSolver, time::Number=0.0)
tic(timing, "boundary assembly")
info("Assembling boundary problems...")
boundary_assembly = Assembly()
boundary_assembly = BoundaryAssembly()
for (i, problem) in enumerate(solver.boundary_problems)
info("Assembling boundary $i: $(problem.name)")
append!(boundary_assembly, assemble(problem, time))
end
C = sparse(boundary_assembly.stiffness_matrix, dim, dim)
g = sparse(boundary_assembly.force_vector, dim, 1)
C1 = sparse(boundary_assembly.C1, dim, dim)
C2 = sparse(boundary_assembly.C2, dim, dim)
D = sparse(boundary_assembly.D, dim, dim)
g = sparse(boundary_assembly.g, dim, 1)
boundary_assembly = nothing
gc()
toc(timing, "boundary assembly")
# resize!(C, dim, dim)
# resize!(g, dim, 1)
# resize!(f, dim, 1)
tic(timing, "dump matrices to disk")
if solver.dump_matrices
filename = "matrices_$(solver.name)_host_$(myid())_iteration_$(iter).jld"
info("dumping matrices to disk, file = $filename")
save(filename, "stiffness matrix", K, "force vector", f,
"constraint matrix lhs", C, "constraint matrix rhs", g)
save(filename, "stiffness matrix K", K, "force vector f", f,
"constraint matrix C1", C1,
"constraint matrix C2", C2,
"constraint matrix D", D,
"constraint vector g", g)
end
toc(timing, "dump matrices to disk")
tic(timing, "solution of system")
info("Solving system")
gc()
# whos()
sol, la = solve(K, f, C, g, Val{solver.method})
# sol, la = solve(K, f, C, g, Val{solver.method})
sol, la = solve(K, f, C1, C2, D, g, Val{solver.method})
gc()
toc(timing, "solution of system")
@@ -297,3 +311,4 @@ function call(solver::DirectSolver, time::Number=0.0)
return (solver.max_iterations, false)
end
+7 -6
View File
@@ -10,7 +10,7 @@ function DirichletProblem(problem_name::ASCIIString, parent_field_name::ASCIIStr
return BoundaryProblem{DirichletProblem}(problem_name, parent_field_name, parent_field_dim, dim, elements)
end
function assemble!(assembly::Assembly, problem::BoundaryProblem{DirichletProblem}, element::Element, time::Number)
function assemble!(assembly::BoundaryAssembly, problem::BoundaryProblem{DirichletProblem}, element::Element, time::Real)
# get dimension and name of PARENT field
field_dim = problem.parent_field_dim
@@ -34,18 +34,19 @@ function assemble!(assembly::Assembly, problem::BoundaryProblem{DirichletProblem
for i=1:field_dim
g = element(field_name, ip, time)
ldofs = gdofs[i:field_dim:end]
add!(assembly.stiffness_matrix, ldofs, ldofs, A)
add!(assembly.force_vector, ldofs, w*g*N')
add!(assembly.C1, ldofs, ldofs, A)
add!(assembly.C2, ldofs, ldofs, A)
add!(assembly.g, ldofs, w*g*N')
end
end
for i=1:field_dim
# add per dof if defined element["blaa 1"] = 1.0, element["blaa 2"] = 0.0 etc.
if haskey(element, field_name*" $i")
g = element(field_name*" $i", ip, time)
ldofs = gdofs[i:field_dim:end]
add!(assembly.stiffness_matrix, ldofs, ldofs, A)
add!(assembly.force_vector, ldofs, w*g*N')
add!(assembly.C1, ldofs, ldofs, A)
add!(assembly.C2, ldofs, ldofs, A)
add!(assembly.g, ldofs, w*g*N')
end
end
end
+3
View File
@@ -24,6 +24,9 @@ end
function PlaneStressElasticityProblem(dim::Int=2, elements=[])
return Problem{PlaneStressElasticityProblem}("plane stress elasticity problem", dim, elements)
end
function PlaneStressElasticityProblem(problem_name::ASCIIString, dim::Int=2, elements=[])
return Problem{PlaneStressElasticityProblem}(problem_name, dim, elements)
end
""" Elasticity equations.
+31 -9
View File
@@ -3,17 +3,39 @@
# Functions to handle element level things -- integration, assembly, ...
type Assembly
mass_matrix :: SparseMatrixIJV
stiffness_matrix :: SparseMatrixIJV
force_vector :: SparseMatrixIJV
type FieldAssembly
mass_matrix :: SparseMatrixCOO
stiffness_matrix :: SparseMatrixCOO
force_vector :: SparseMatrixCOO
end
function Assembly()
return Assembly(
SparseMatrixIJV(),
SparseMatrixIJV(),
SparseMatrixIJV())
function FieldAssembly()
return FieldAssembly(
SparseMatrixCOO(),
SparseMatrixCOO(),
SparseMatrixCOO())
end
typealias Assembly FieldAssembly
"""
"Boundary" matrices C₁, C₂, D, g for general problem type
Au + C₁'λ = f
C₂u + Dλ = g
"""
type BoundaryAssembly
C1 :: SparseMatrixCOO
C2 :: SparseMatrixCOO
D :: SparseMatrixCOO
g :: SparseMatrixCOO
end
function BoundaryAssembly()
return BoundaryAssembly(
SparseMatrixCOO(),
SparseMatrixCOO(),
SparseMatrixCOO(),
SparseMatrixCOO())
end
function Base.empty!(assembly::Assembly)
+16 -15
View File
@@ -662,7 +662,7 @@ end
typealias MortarElements2D Union{Seg2, Seg3}
function assemble!{E<:MortarElements2D}(assembly::Assembly, problem::BoundaryProblem{MortarProblem}, slave_element::Element{E}, time::Real)
function assemble!{E<:MortarElements2D}(assembly::BoundaryAssembly, problem::BoundaryProblem{MortarProblem}, slave_element::Element{E}, time::Real)
# get dimension and name of PARENT field
field_dim = problem.parent_field_dim
@@ -675,13 +675,14 @@ function assemble!{E<:MortarElements2D}(assembly::Assembly, problem::BoundaryPro
xi1b = project_from_master_to_slave(slave_element, master_element, [ 1.0])
xi1 = clamp([xi1a xi1b], -1.0, 1.0)
l = 1/2*(xi1[2]-xi1[1])
if abs(l) < 1.0e-6
warn("No contribution")
if abs(l) < 1.0e-9
#warn("No contribution")
continue # no contribution
end
master_dofs = get_gdofs(master_element, field_dim)
for ip in get_integration_points(slave_element, Val{5})
w = ip.weight*det(slave_element, ip, time)*l
J = get_jacobian(slave_element, ip, time)
w = ip.weight*norm(J)*l
# integration point on slave side segment
xi_gauss = 1/2*(1-ip.xi)*xi1[1] + 1/2*(1+ip.xi)*xi1[2]
@@ -692,15 +693,14 @@ function assemble!{E<:MortarElements2D}(assembly::Assembly, problem::BoundaryPro
N1 = slave_element(xi_gauss, time)
N2 = master_element(xi_projected, time)
S = w*N1'*N1
M = w*(N1'*N2)'
# M = w*N1'*N2
# FIXME: why this needs now to be transpose?
# assembly / repeat
M = w*N1'*N2
for i=1:field_dim
sd = slave_dofs[i:field_dim:end]
md = master_dofs[i:field_dim:end]
add!(assembly.stiffness_matrix, sd, sd, S)
add!(assembly.stiffness_matrix, sd, md, -M)
add!(assembly.C1, sd, sd, S)
add!(assembly.C1, sd, md, -M)
add!(assembly.C2, sd, sd, S)
add!(assembly.C2, sd, md, -M)
end
end
@@ -735,7 +735,7 @@ function find_master_elements(slave_element::Element, time::Real)
return master_elements
end
function assemble!{E<:MortarElements3D}(assembly::Assembly, problem::BoundaryProblem{MortarProblem}, slave_element::Element{E}, time::Real)
function assemble!{E<:MortarElements3D}(assembly::BoundaryAssembly, problem::BoundaryProblem{MortarProblem}, slave_element::Element{E}, time::Real)
field_dim = problem.parent_field_dim
field_name = problem.parent_field_name
slave_dofs = get_gdofs(slave_element, field_dim)
@@ -893,13 +893,14 @@ function assemble!{E<:MortarElements3D}(assembly::Assembly, problem::BoundaryPro
@debug info("weight S = $wS, weight M = $wM, weight C = $wC")
Sm = ip.weight*N1'*N1*wC
# FIXME: master side transpose -- why?
Mm = ip.weight*(N1'*N2)'*wC
Mm = ip.weight*N1'*N2*wC
for k=1:field_dim
sd = slave_dofs[k:field_dim:end]
md = master_dofs[k:field_dim:end]
add!(assembly.stiffness_matrix, sd, sd, Sm)
add!(assembly.stiffness_matrix, sd, md, -Mm)
add!(assembly.C1, sd, sd, Sm)
add!(assembly.C1, sd, md, -Mm)
add!(assembly.C2, sd, sd, Sm)
add!(assembly.C2, sd, md, -Mm)
end
end
# info("breaking on first")
+3 -3
View File
@@ -3,7 +3,7 @@
abstract AbstractProblem
type Problem{T<:AbstractProblem}
type FieldProblem{T<:AbstractProblem}
name :: ASCIIString
dim :: Int
elements :: Vector{Element}
@@ -17,9 +17,9 @@ type BoundaryProblem{T<:AbstractProblem}
elements :: Vector{Element}
end
typealias FieldProblem Problem
typealias Problem FieldProblem
typealias AllProblems Union{Problem, BoundaryProblem}
typealias AllProblems Union{FieldProblem, BoundaryProblem}
function get_elements(problem::AllProblems)
return problem.elements
+12 -5
View File
@@ -4,16 +4,23 @@
# Sparse utils to make assembly of local and global matrices easier.
# Unoptimized but should do all necessary stuff for at start.
type SparseMatrixIJV
type SparseMatrixCOO
I :: Vector{Int}
J :: Vector{Int}
V :: Vector{Float64}
end
typealias SparseMatrixCOO SparseMatrixIJV
typealias SparseMatrixIJV SparseMatrixCOO
#=
function SparseMatrixIJV()
SparseMatrixIJV([], [], [])
warn("use SparseMatrixCOO to construct sparse matrix.""")
SparseMatrixCOO([], [], [])
end
=#
function SparseMatrixCOO()
SparseMatrixCOO([], [], [])
end
function Base.sparse(A::SparseMatrixIJV, args...)
@@ -85,8 +92,8 @@ Example
"""
function add!(A::SparseMatrixIJV, dofs1::Vector{Int}, dofs2::Vector{Int}, data::Matrix{Float64})
n, m = size(data)
for i=1:n
for j=1:m
for j=1:m
for i=1:n
push!(A.I, dofs1[i])
push!(A.J, dofs2[j])
end
+6 -1
View File
@@ -1,7 +1,12 @@
# This file is a part of JuliaFEM.
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
using BaseTestNext
if VERSION >= v"0.5-"
using Base.Test
else
using BaseTestNext
end
abstract TestResult
+1
View File
@@ -37,6 +37,7 @@ using LightXML
# > #define XDMF_3DCORECTMESH 0x1102
global eltypes = Dict{Symbol, Int}(
:Tri3 => 0x4,
:Quad4 => 0x5,
:Tet4 => 0x6,
:Hex8 => 0x9,
+1 -350
View File
@@ -1,7 +1,7 @@
# This file is a part of JuliaFEM.
# License is MIT: see https://github.com/JuliaFEM/JuliaFEM.jl/blob/master/LICENSE.md
module MortarTests
module MortarTests3D
using JuliaFEM.Test
@@ -9,9 +9,6 @@ using JuliaFEM.Core: Element, Seg2, Quad4, Tri3, Hex8, MortarProblem, Assembly,
get_connectivity, update!
using JuliaFEM.Core: PlaneStressElasticityProblem, DirichletProblem, DirectSolver
# 2d stuff
using JuliaFEM.Core: project_from_slave_to_master, project_from_master_to_slave
# 3d stuff
using JuliaFEM.Core: create_auxiliary_plane, project_point_to_auxiliary_plane,
get_edge_intersections, get_points_inside_triangle,
@@ -22,352 +19,6 @@ using JuliaFEM.Core: create_auxiliary_plane, project_point_to_auxiliary_plane,
using JuliaFEM.Core: LinearElasticityProblem
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)]
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
function test_calc_flat_2d_projection_slave_to_master()
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
function test_calc_flat_2d_projection_master_to_slave()
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
#test_calc_flat_2d_projection_master_to_slave()
function test_calc_flat_2d_projection_rotated()
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
function test_create_flat_2d_assembly()
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 = Assembly()
assemble!(assembly, problem, slave1, 0.0)
B = round(full(assembly.stiffness_matrix, 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)
empty!(assembly)
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]
assemble!(assembly, problem, slave2, 0.0)
B = full(assembly.stiffness_matrix)
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
#test_create_flat_2d_assembly()
function test_2d_mortar_multiple_bodies_multiple_dirichlet_bc()
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()
push!(body1, e1)
body2 = PlaneStressElasticityProblem()
push!(body2, e2)
push!(body2, b1)
# 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)
# 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
#test_2d_mortar_multiple_bodies_multiple_dirichlet_bc()
function test_2d_mortar_three_bodies_shared_nodes()
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)
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)
# 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)
# mortar boundary between body 2 and body 3
master2 = Seg2([9, 11])
master2["geometry"] = Vector[N[9], N[11]]
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)
solver = DirectSolver()
push!(solver, body1)
push!(solver, body2)
push!(solver, body3)
push!(solver, bc1)
push!(solver, bc2)
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)
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])
end
#test_2d_mortar_three_bodies_shared_nodes()
function test_auxiliary_plane_transforms()
+355
View File
@@ -0,0 +1,355 @@
# 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.Test
using JuliaFEM.Core: Element, Seg2, Quad4, Tri3, Hex8, MortarProblem, Assembly, assemble,
get_connectivity, update!, assemble!, BoundaryAssembly
using JuliaFEM.Core: PlaneStressElasticityProblem, DirichletProblem, DirectSolver
using JuliaFEM.Core: project_from_slave_to_master, project_from_master_to_slave
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)]
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()
push!(body1, e1)
body2 = PlaneStressElasticityProblem()
push!(body2, e2)
push!(body2, b1)
# 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)
# 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)
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)
# 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)
# mortar boundary between body 2 and body 3
master2 = Seg2([9, 11])
master2["geometry"] = Vector[N[9], N[11]]
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)
solver = DirectSolver()
push!(solver, body1)
push!(solver, body2)
push!(solver, body3)
push!(solver, bc1)
push!(solver, bc2)
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)
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])
end
end
end