added assembly example

This commit is contained in:
Jukka Aho
2015-05-31 16:35:47 +03:00
parent 116775be22
commit 02196af0a3
2 changed files with 566 additions and 0 deletions
+1
View File
@@ -1,2 +1,3 @@
*~
.DS_Store
.ipynb_checkpoints
@@ -0,0 +1,565 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#Assembly\n",
"\n",
"Let's make two element model and assemble it. We split the previous one element model to 2 quadrilaterals, make assembly and solve it. Small modifications to functions, I think it's better that they don't allocate memory but do in place operations. \n",
"\n",
"**TODO**\n",
"- Tangent stiffness is calculated using forward finite difference. I think we should try ReverseDiffSparse for it's sparse matrix support, but I don't know how to use it. Or alternatively use FAD like before and assemble after linearization. It would be nice experiment to try linearization *after* assembly, would it work?\n",
"- Verify calculations using some well known FEM software.\n",
"\n",
"\n",
"Author: Jukka Aho\n",
"\n",
"Email: <jukka.aho@kapsi.fi>"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"0x00000c95556709c2"
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"tic()"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"Dict{Any,Any} with 0 entries"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"type Node\n",
" coords\n",
"end\n",
"type Element\n",
" node_ids\n",
"end\n",
"elements = Dict()\n",
"nodes = Dict()"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"Element([5,6,3,2])"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"ndim = 2\n",
"nnodes = 6\n",
"\n",
"nodes[1] = Node([0, 1, 0])\n",
"nodes[2] = Node([5, 1, 0])\n",
"nodes[3] = Node([10, 1, 0])\n",
"nodes[4] = Node([0, 0, 0])\n",
"nodes[5] = Node([5, 0, 0])\n",
"nodes[6] = Node([10, 0, 0])\n",
"elements[1] = Element([4, 5, 2, 1])\n",
"elements[2] = Element([5, 6, 3, 2])"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"(36.0,24.0)"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Partial derivatives of bilinear Lagrange polynomials\n",
"dNdξ(ξ) = [[-(1-ξ[2])/4.0 -(1-ξ[1])/4.0],\n",
" [ (1-ξ[2])/4.0 -(1+ξ[1])/4.0],\n",
" [ (1+ξ[2])/4.0 (1+ξ[1])/4.0],\n",
" [-(1+ξ[2])/4.0 (1-ξ[1])/4.0]] \n",
"\n",
"E = 90\n",
"ν = 0.25\n",
"μ = E/(2*(1+ν))\n",
"λ = E*ν/((1+ν)*(1-2*ν))\n",
"λ = 2*λ*μ/(λ + 2*μ)\n",
"μ, λ"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"calculate_internal_energy! (generic function with 2 methods)"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"function calculate_internal_energy!(X, u, Wint, dNdξ, λ, μ, dim=2)\n",
" \"\"\"Calculate internal energy for a single element.\n",
"\n",
" Parameters\n",
" ----------\n",
" X : array [dim x nodes]\n",
" u : array [dim x nodes]\n",
" dNdξ : shape function derivatives\n",
" λ : float\n",
" μ : float\n",
" dim : integer, optinal\n",
"\n",
" Returns\n",
" -------\n",
" Nothing, this is inplace function\n",
" \n",
" \"\"\"\n",
" I = eye(dim)\n",
" \n",
" function J(ξ)\n",
" Jᵀ = X*dNdξ(ξ)\n",
" ∇N = inv(Jᵀ)*dNdξ(ξ)'\n",
" ∇u = u*∇N'\n",
" F = I + ∇u # Deformation gradient\n",
" E = 1/2*(∇u' + ∇u + ∇u'*∇u) # Green-Lagrange strain tensor\n",
" P = λ*trace(E)*I + 2*μ*E # PK1 stress tensor\n",
" S = F*P # PK2 stress tensor\n",
" return S*∇N*det(Jᵀ)\n",
" end\n",
"\n",
" a = 1/sqrt(3)\n",
" ipoints = [[-a -a], [a -a], [a a], [-a a]]\n",
" iweights = [1 1 1 1]\n",
"\n",
" for m = 1:length(iweights)\n",
" w = iweights[m]\n",
" ξ = ipoints[m, :]\n",
" Wint[:,:] += w*J(ξ)\n",
" end\n",
"\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"2x4 Array{Float64,2}:\n",
" -60.6667 -1.33333 133.333 -71.3333\n",
" -24.0 -8.0 35.0 -3.0 "
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Wint = zeros(2, 4)\n",
"X = [0 0; 1 0; 1 1; 0 1]'\n",
"u = [0 0; 0 0; 1 0; 0 0]'\n",
"calculate_internal_energy!(X, u, Wint, dNdξ, λ, μ)\n",
"Wint"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"assemble! (generic function with 1 method)"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"function assemble!(u, R)\n",
" \"\"\" Assemble global residual vector R = T - F\n",
" \"\"\"\n",
" R[:] = 0.0\n",
" u = reshape(u, ndim, nnodes)\n",
" R = reshape(R, ndim, nnodes)\n",
" \n",
" Xe = zeros(ndim, 4)\n",
" Winte = zeros(ndim, 4)\n",
" \n",
" # Internal forces, T\n",
" for i=1:length(elements) # loop through elements\n",
" Xe[:,:] = 0.0 # FIXME: how to efficiently empty array?\n",
" el = elements[i]\n",
" nids = el.node_ids\n",
" for i=1:length(nids) # loop through nodes\n",
" Xe[:,i] = nodes[nids[i]].coords[1:2]\n",
" end\n",
" Winte[:,:] = 0.0\n",
" calculate_internal_energy!(Xe, u[:,nids], Winte, dNdξ, λ, μ)\n",
" R[:,nids] += Winte\n",
" end\n",
"\n",
" # External forces, F\n",
" # T - F = T + (-F)\n",
" R[2, 3] += 2 # Force to the tip of härveli\n",
"\n",
" u = reshape(u, ndim*nnodes)\n",
" R = reshape(R, ndim*nnodes)\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"1x12 Array{Float64,2}:\n",
" 0.0 0.0 34.8853 16.2 140.715 78.6 … -64.1013 -36.0 -111.499 -56.8"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"R = zeros(ndim*nnodes)\n",
"u = [0 0; 0 0; 1 0; 0 0; 0 0; 0 0]'\n",
"#u = [0 0; 0 0; 1 0; 0 0]'\n",
"assemble!(reshape(u, ndim*nnodes), R)\n",
"R'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We should use ReverseDiffSparse because of it's sparse matrix support"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"# FIXME: I don't know how to get these working!\n",
"#using ReverseDiffSparse\n",
"#using ForwardDiff\n",
"#Kt! = forwarddiff_jacobian!(assemble!, Float64, fadtype=:dual, n=12, m=12)\n",
"#Kt!(reshape(u, 12), Kt)\n",
"#Kt"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"Lin (generic function with 2 methods)"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# So we go to plan B. FIXME: change this to analytical version\n",
"\n",
"function Lin(f!, h=1.0e-6)\n",
"\n",
" function D!(x, J)\n",
" J[:,:] = 0\n",
" N = length(x)\n",
" Δx = zeros(N)\n",
" y = zeros(N)\n",
" Δy = zeros(N)\n",
" f!(x, y) # Evaluate function f in x and store results to y\n",
" for i=1:N\n",
" Δx[:] = 0.0\n",
" Δx[i] += h\n",
" f!(x+Δx, Δy) # Evaluate function f in x+Δx and store results to Δy\n",
" J[i, :] = (Δy-y) / h\n",
" end\n",
" end\n",
"\n",
" return D!\n",
"\n",
"end"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Handling homogeneous Dirichlet conditions, using elimination.\n",
"\n",
"**INFO**: We could try something like this: http://www.code-aster.org/V2/doc/default/en/man_r/r3/r3.03.01.pdf\n",
"\n",
"Here's an idea how to make a very simply elimination"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"2x6 Array{Int64,2}:\n",
" 1 0 0 1 0 0\n",
" 1 0 0 1 0 0"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"fixed_dofs = integer(zeros(ndim, nnodes))\n",
"fixed_dofs[:,1] = fixed_dofs[:,4] = 1\n",
"fixed_dofs"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"2x6 Array{Int64,2}:\n",
" 0 1 1 0 1 1\n",
" 0 1 1 0 1 1"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"free_dofs = integer(ones(ndim, nnodes)) - fixed_dofs\n",
"free_dofs"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"text/plain": [
"1x8 Array{Int64,2}:\n",
" 3 4 5 6 9 10 11 12"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"free_dofs = find(free_dofs)\n",
"free_dofs'"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Starting Newton iterations\n",
"Iteration 1, norm = 12.031651257897487\n",
"Iteration 2, norm = 3.141275068747564\n",
"Iteration 3, norm = 1.1530769747882408\n",
"Iteration 4, norm = 0.2665784114781298\n",
"Iteration 5, norm = 0.035146969229970175\n",
"Iteration 6, norm = 0.003125584242156337\n",
"Iteration 7, norm = 2.227371173806294e-6\n",
"Iteration 8, norm = 2.1397676611257455e-10\n",
"Converged.\n"
]
},
{
"data": {
"text/plain": [
"2x6 Array{Float64,2}:\n",
" 0.0 -0.106192 -1.69115 0.0 -0.761252 -2.48604\n",
" 0.0 -2.10509 -6.00728 0.0 -1.89221 -5.5914 "
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"function solve!(u, free_dofs; max_iterations=10, eps=1.0e-7)\n",
" ∇R = Lin(assemble!)\n",
" Kt = zeros(ndim*nnodes, ndim*nnodes)\n",
" R = zeros(size(u))\n",
" println(\"Starting Newton iterations\")\n",
" for i=1:max_iterations\n",
" print(\"Iteration \",i, \", \")\n",
" R[:] = 0.0\n",
" assemble!(u, R) # Calculate internal energy in nodes and store results to R\n",
" ∇R(u, Kt) # Linearize residual in u and save result to Kt\n",
" # Solve !\n",
" du = Kt[free_dofs, free_dofs] \\ -R[free_dofs]\n",
" u[free_dofs] += du\n",
" println(\"norm = \",norm(du))\n",
" if norm(du) < eps\n",
" println(\"Converged.\")\n",
" break\n",
" end\n",
" end\n",
" return u\n",
"end\n",
"\n",
"u = zeros(ndim*nnodes)\n",
"solve!(u, free_dofs)\n",
"u = reshape(u, ndim, nnodes)\n",
"u"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {
"collapsed": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"elapsed time: 4.541729719 seconds\n"
]
},
{
"data": {
"text/plain": [
"4.541729719"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"toc()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Julia 0.3.8",
"language": "julia",
"name": "julia-0.3"
},
"language_info": {
"name": "julia",
"version": "0.3.8"
}
},
"nbformat": 4,
"nbformat_minor": 0
}