mirror of
https://github.com/JuliaFEM/JuliaFEM.jl.git
synced 2026-08-06 04:21:33 +00:00
549 lines
16 KiB
Plaintext
549 lines
16 KiB
Plaintext
{
|
||
"cells": [
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"# Interpolation and integration algorithms\n",
|
||
"\n",
|
||
"Author(s): Jukka Aho\n",
|
||
"\n",
|
||
"**Abstract**: Some strategies to implement automatic differentiation. The number of different choises is caused by a fact that the linearization of function can be done before integration or vice versa, and functions can return values or do in-place modifications. There is probably performance differences between different strategies, but all of them should work."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 1,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"using JuliaFEM\n",
|
||
"using ForwardDiff"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"\"Old good\" elasticity force equilibrium equation $R = T - F$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 2,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"calc_residual_vector_integrand (generic function with 1 method)"
|
||
]
|
||
},
|
||
"execution_count": 2,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"function calc_residual_vector_integrand(el::JuliaFEM.Element, xi)\n",
|
||
" # Calculate dN/dX and interpolate material parameters\n",
|
||
" dbasisdX = JuliaFEM.get_dbasisdX(el, xi)\n",
|
||
" u = el.attributes[\"displacement\"]\n",
|
||
" lambda = JuliaFEM.interpolate(el, \"lambda\", xi)\n",
|
||
" mu = JuliaFEM.interpolate(el, \"mu\", xi)\n",
|
||
"\n",
|
||
" # Calculate residual force vector R = T - F\n",
|
||
" gradu = u*dbasisdX\n",
|
||
" F = I + gradu\n",
|
||
" E = 1/2*(gradu' + gradu + gradu'*gradu)\n",
|
||
" S = lambda*trace(E)*I + 2*mu*E\n",
|
||
" P = F*S\n",
|
||
" T = P*dbasisdX'\n",
|
||
" return T\n",
|
||
"end"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"Test case, already well known 2d elasticity in [0,10] x [0,1] grid."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 3,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"basis(xi) = [\n",
|
||
" (1-xi[1])*(1-xi[2])/4\n",
|
||
" (1+xi[1])*(1-xi[2])/4\n",
|
||
" (1+xi[1])*(1+xi[2])/4\n",
|
||
" (1-xi[1])*(1+xi[2])/4]\n",
|
||
"dbasis(xi) = [-(1-xi[2])/4.0 -(1-xi[1])/4.0\n",
|
||
" (1-xi[2])/4.0 -(1+xi[1])/4.0\n",
|
||
" (1+xi[2])/4.0 (1+xi[1])/4.0\n",
|
||
" -(1+xi[2])/4.0 (1-xi[1])/4.0]\n",
|
||
"ipoints = 1/sqrt(3)*[-1 -1; 1 -1; 1 1; -1 1]'\n",
|
||
"iweights = [1, 1, 1, 1]\n",
|
||
"attributes = Dict()\n",
|
||
"e = JuliaFEM.Element(1, [1, 2, 3, 4], basis, dbasis, attributes, ipoints, iweights)\n",
|
||
"\n",
|
||
"E = 90\n",
|
||
"nu = 0.25\n",
|
||
"mu = E/(2*(1+nu))\n",
|
||
"la = E*nu/((1+nu)*(1-2*nu))\n",
|
||
"la = 2*la*mu/(la + 2*mu)\n",
|
||
"\n",
|
||
"e.attributes[\"coordinates\"] = [0.0 0.0; 10.0 0.0; 10.0 1.0; 0.0 1.0]'\n",
|
||
"e.attributes[\"lambda\"] = la\n",
|
||
"e.attributes[\"mu\"] = mu\n",
|
||
"e.attributes[\"displacement\"] = [0.0 0.0; 0.0 0.0; 0.5 0.0; 0.0 0.0]'\n",
|
||
"e.attributes[\"displacement nodal force\"] = zeros(2, 4)\n",
|
||
"e.attributes[\"displacement tangent stiffness\"] = zeros(8, 8);"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Integration\n",
|
||
"\n",
|
||
"1. take element and function and return value\n",
|
||
"2. take function and return function which can be integrated by passing element as a function\n",
|
||
"3. do in-place integration, save values to target"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 4,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"integrate! (generic function with 1 method)"
|
||
]
|
||
},
|
||
"execution_count": 4,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"function integrate(f::Function, el::JuliaFEM.Element)\n",
|
||
" target = []\n",
|
||
" for m = 1:length(el.iweights)\n",
|
||
" w = el.iweights[m]\n",
|
||
" xi = el.ipoints[:, m]\n",
|
||
" J = JuliaFEM.interpolate(el, \"coordinates\", xi; derivative=true)\n",
|
||
" push!(target, w*f(el, xi)*det(J))\n",
|
||
" end\n",
|
||
" return sum(target)\n",
|
||
"end\n",
|
||
"\n",
|
||
"function integrate(f::Function)\n",
|
||
" function integrate(el::JuliaFEM.Element)\n",
|
||
" target = []\n",
|
||
" for m = 1:length(el.iweights)\n",
|
||
" w = el.iweights[m]\n",
|
||
" xi = el.ipoints[:, m]\n",
|
||
" J = JuliaFEM.interpolate(el, \"coordinates\", xi; derivative=true)\n",
|
||
" push!(target, w*f(el, xi)*det(J))\n",
|
||
" end\n",
|
||
" return sum(target)\n",
|
||
" end\n",
|
||
" return integrate\n",
|
||
"end\n",
|
||
"\n",
|
||
"function integrate!(f::Function, el::JuliaFEM.Element, target)\n",
|
||
" # set target to zero\n",
|
||
" el.attributes[target][:] = 0.0\n",
|
||
" for m = 1:length(el.iweights)\n",
|
||
" w = el.iweights[m]\n",
|
||
" xi = el.ipoints[:, m]\n",
|
||
" J = JuliaFEM.interpolate(el, \"coordinates\", xi; derivative=true)\n",
|
||
" el.attributes[target][:,:] += w*f(el, xi)*det(J)\n",
|
||
" end\n",
|
||
"end\n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 5,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"2x4 Array{Float64,2}:\n",
|
||
" -38.2303 -72.8697 79.4912 31.6088\n",
|
||
" -17.625 -28.475 37.7 8.4 "
|
||
]
|
||
},
|
||
"execution_count": 5,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"integrate(calc_residual_vector_integrand, e)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 6,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"2x4 Array{Float64,2}:\n",
|
||
" -38.2303 -72.8697 79.4912 31.6088\n",
|
||
" -17.625 -28.475 37.7 8.4 "
|
||
]
|
||
},
|
||
"execution_count": 6,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"calc_residual_vector = integrate(calc_residual_vector_integrand)\n",
|
||
"calc_residual_vector(e)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 7,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"2x4 Array{Float64,2}:\n",
|
||
" -38.2303 -72.8697 79.4912 31.6088\n",
|
||
" -17.625 -28.475 37.7 8.4 "
|
||
]
|
||
},
|
||
"execution_count": 7,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"integrate!(calc_residual_vector_integrand, e, \"displacement nodal force\")\n",
|
||
"e.attributes[\"displacement nodal force\"]"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Linearization\n",
|
||
"\n",
|
||
"1. take function, element and field, and return partial derivative\n",
|
||
"2. take function and field, return function which takes element as argument\n",
|
||
"3. do in-place linearization to target, requires function which takes element as argument\n",
|
||
"\n",
|
||
"In general linearization can be done before integration and vice versa, i.e.\n",
|
||
"\n",
|
||
" integrate(linearize(f, \"u\"))(e) <-> linearize(integrate(f), \"u\")(e)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 8,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"linearize! (generic function with 1 method)"
|
||
]
|
||
},
|
||
"execution_count": 8,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"function linearize(f::Function, el::JuliaFEM.Element, field::ASCIIString)\n",
|
||
" dim, nnodes = size(el.attributes[field])\n",
|
||
" function helper!(x, y)\n",
|
||
" orig = copy(el.attributes[field])\n",
|
||
" el.attributes[field] = reshape(x, dim, nnodes)\n",
|
||
" y[:] = f(el)\n",
|
||
" el.attributes[field] = copy(orig)\n",
|
||
" end\n",
|
||
" jac = ForwardDiff.forwarddiff_jacobian(helper!, Float64, fadtype=:dual, n=dim*nnodes, m=dim*nnodes)\n",
|
||
" return jac(el.attributes[field][:])\n",
|
||
"end\n",
|
||
"\n",
|
||
"function linearize(f::Function, field::ASCIIString)\n",
|
||
" function jacobian(el::JuliaFEM.Element, args...)\n",
|
||
" dim, nnodes = size(el.attributes[field])\n",
|
||
" function helper!(x, y)\n",
|
||
" orig = copy(el.attributes[field])\n",
|
||
" el.attributes[field] = reshape(x, dim, nnodes)\n",
|
||
" y[:] = f(el, args...)\n",
|
||
" el.attributes[field] = copy(orig)\n",
|
||
" end\n",
|
||
" jac = ForwardDiff.forwarddiff_jacobian(helper!, Float64, fadtype=:dual, n=dim*nnodes, m=dim*nnodes)\n",
|
||
" return jac(el.attributes[field][:])\n",
|
||
" end\n",
|
||
" return jacobian\n",
|
||
"end\n",
|
||
"\n",
|
||
"function linearize!(f::Function, el::JuliaFEM.Element, field::ASCIIString, target::ASCIIString)\n",
|
||
" el.attributes[target][:] = 0.0\n",
|
||
" dim, nnodes = size(el.attributes[field])\n",
|
||
" function helper!(x, y)\n",
|
||
" orig = copy(el.attributes[field])\n",
|
||
" el.attributes[field] = reshape(x, dim, nnodes)\n",
|
||
" y[:] = f(el)\n",
|
||
" el.attributes[field] = copy(orig)\n",
|
||
" end\n",
|
||
" jac! = ForwardDiff.forwarddiff_jacobian!(helper!, Float64, fadtype=:dual, n=dim*nnodes, m=dim*nnodes)\n",
|
||
" jac!(el.attributes[field][:], el.attributes[target])\n",
|
||
"end"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 9,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"8x8 Array{Float64,2}:\n",
|
||
" 149.721 55.55 84.679 36.65 … -55.55 -136.278 -36.65 \n",
|
||
" 55.55 329.69 42.75 167.935 -172.941 -42.8 -324.684\n",
|
||
" 84.679 42.75 185.321 105.05 -123.05 -73.522 -24.75 \n",
|
||
" 36.65 167.935 105.05 340.54 -344.759 -24.8 -163.716\n",
|
||
" -98.122 -55.5 -196.478 -116.9 135.8 76.233 36.6 \n",
|
||
" -55.55 -172.941 -123.05 -344.759 … 352.922 42.8 164.778\n",
|
||
" -136.278 -42.8 -73.522 -24.8 42.8 133.567 24.8 \n",
|
||
" -36.65 -324.684 -24.75 -163.716 164.778 24.8 323.622"
|
||
]
|
||
},
|
||
"execution_count": 9,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"integrate(linearize(calc_residual_vector_integrand, \"displacement\"))(e)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 10,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"8x8 Array{Float64,2}:\n",
|
||
" 149.721 55.55 84.679 36.65 … -55.55 -136.278 -36.65 \n",
|
||
" 55.55 329.69 42.75 167.935 -172.941 -42.8 -324.684\n",
|
||
" 84.679 42.75 185.321 105.05 -123.05 -73.522 -24.75 \n",
|
||
" 36.65 167.935 105.05 340.54 -344.759 -24.8 -163.716\n",
|
||
" -98.122 -55.5 -196.478 -116.9 135.8 76.233 36.6 \n",
|
||
" -55.55 -172.941 -123.05 -344.759 … 352.922 42.8 164.778\n",
|
||
" -136.278 -42.8 -73.522 -24.8 42.8 133.567 24.8 \n",
|
||
" -36.65 -324.684 -24.75 -163.716 164.778 24.8 323.622"
|
||
]
|
||
},
|
||
"execution_count": 10,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"linearize(integrate(calc_residual_vector_integrand), \"displacement\")(e)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 11,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"8x8 Array{Float64,2}:\n",
|
||
" 149.721 55.55 84.679 36.65 … -55.55 -136.278 -36.65 \n",
|
||
" 55.55 329.69 42.75 167.935 -172.941 -42.8 -324.684\n",
|
||
" 84.679 42.75 185.321 105.05 -123.05 -73.522 -24.75 \n",
|
||
" 36.65 167.935 105.05 340.54 -344.759 -24.8 -163.716\n",
|
||
" -98.122 -55.5 -196.478 -116.9 135.8 76.233 36.6 \n",
|
||
" -55.55 -172.941 -123.05 -344.759 … 352.922 42.8 164.778\n",
|
||
" -136.278 -42.8 -73.522 -24.8 42.8 133.567 24.8 \n",
|
||
" -36.65 -324.684 -24.75 -163.716 164.778 24.8 323.622"
|
||
]
|
||
},
|
||
"execution_count": 11,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"linearize(integrate(calc_residual_vector_integrand), e, \"displacement\")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 12,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"8x8 Array{Float64,2}:\n",
|
||
" 149.721 55.55 84.679 36.65 … -55.55 -136.278 -36.65 \n",
|
||
" 55.55 329.69 42.75 167.935 -172.941 -42.8 -324.684\n",
|
||
" 84.679 42.75 185.321 105.05 -123.05 -73.522 -24.75 \n",
|
||
" 36.65 167.935 105.05 340.54 -344.759 -24.8 -163.716\n",
|
||
" -98.122 -55.5 -196.478 -116.9 135.8 76.233 36.6 \n",
|
||
" -55.55 -172.941 -123.05 -344.759 … 352.922 42.8 164.778\n",
|
||
" -136.278 -42.8 -73.522 -24.8 42.8 133.567 24.8 \n",
|
||
" -36.65 -324.684 -24.75 -163.716 164.778 24.8 323.622"
|
||
]
|
||
},
|
||
"execution_count": 12,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"linearize!(integrate(calc_residual_vector_integrand), e, \"displacement\", \"displacement tangent stiffness\")\n",
|
||
"e.attributes[\"displacement tangent stiffness\"]"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 13,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"8x8 Array{Float64,2}:\n",
|
||
" 149.721 55.55 84.679 36.65 … -55.55 -136.278 -36.65 \n",
|
||
" 55.55 329.69 42.75 167.935 -172.941 -42.8 -324.684\n",
|
||
" 84.679 42.75 185.321 105.05 -123.05 -73.522 -24.75 \n",
|
||
" 36.65 167.935 105.05 340.54 -344.759 -24.8 -163.716\n",
|
||
" -98.122 -55.5 -196.478 -116.9 135.8 76.233 36.6 \n",
|
||
" -55.55 -172.941 -123.05 -344.759 … 352.922 42.8 164.778\n",
|
||
" -136.278 -42.8 -73.522 -24.8 42.8 133.567 24.8 \n",
|
||
" -36.65 -324.684 -24.75 -163.716 164.778 24.8 323.622"
|
||
]
|
||
},
|
||
"execution_count": 13,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"integrate!(linearize(calc_residual_vector_integrand, \"displacement\"), e, \"displacement tangent stiffness\")\n",
|
||
"e.attributes[\"displacement tangent stiffness\"]"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Validations"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 14,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"Converged in 6 iterations.\n"
|
||
]
|
||
},
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"2x4 Array{Float64,2}:\n",
|
||
" 0.0 -0.399145 -0.0722858 0.0\n",
|
||
" 0.0 -2.17799 -2.22224 0.0"
|
||
]
|
||
},
|
||
"execution_count": 14,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"free_dofs = [3, 4, 5, 6]\n",
|
||
"u = zeros(2, 4)\n",
|
||
"du = zeros(2, 4)\n",
|
||
"F = [0 0; 0 0; 0 -2; 0 0]'\n",
|
||
"for i=1:10\n",
|
||
" e.attributes[\"displacement\"] = u\n",
|
||
" K = linearize(integrate(calc_residual_vector_integrand), \"displacement\")(e)\n",
|
||
" R = integrate(calc_residual_vector_integrand)(e)\n",
|
||
" du[free_dofs] = K[free_dofs, free_dofs] \\ -(R - F)[free_dofs]\n",
|
||
" u += du\n",
|
||
" if norm(du) < 1.0e-9\n",
|
||
" println(\"Converged in $i iterations.\")\n",
|
||
" break\n",
|
||
" end\n",
|
||
"end\n",
|
||
"u # -2.222244754401764"
|
||
]
|
||
}
|
||
],
|
||
"metadata": {
|
||
"kernelspec": {
|
||
"display_name": "Julia 0.4.0-dev",
|
||
"language": "julia",
|
||
"name": "julia-0.4"
|
||
},
|
||
"language_info": {
|
||
"name": "julia",
|
||
"version": "0.4.0"
|
||
}
|
||
},
|
||
"nbformat": 4,
|
||
"nbformat_minor": 0
|
||
}
|