mirror of
https://github.com/JuliaFEM/JuliaFEM.jl.git
synced 2026-09-27 04:10:54 +00:00
1307 lines
48 KiB
Plaintext
1307 lines
48 KiB
Plaintext
{
|
||
"cells": [
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"# Solving elasticity problems using JuliaFEM\n",
|
||
"\n",
|
||
"Author(s): Jukka Aho\n",
|
||
"\n",
|
||
"**Abstract**: A workflow to solve typical elasticity problem. This document also tries to give some quidelines how to develop JuliaFEM."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Bottom-up design\n",
|
||
"\n",
|
||
"We go piece by piece starting from something simple and going up to more complicated programming model."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"*Design principle 1*: we introduce new ideas using Notebooks."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"*Design principle 2*: we use ``Logging``. Forget ``println``."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 2,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"Logger(root,DEBUG,Pipe(open, 0 bytes waiting),root)"
|
||
]
|
||
},
|
||
"execution_count": 2,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"using JuliaFEM\n",
|
||
"using Logging\n",
|
||
"Logging.configure(level=DEBUG)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"*Design principle 3*: we write docstrings using [numpy style](https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt).\n",
|
||
"\n",
|
||
"*Design principle 4*: we don't use greek characters in code which is implemented to JuliaFEM. In notebooks they are ok.\n",
|
||
"\n",
|
||
"*Design principle 5*: we use 4 space indentation like in Python.\n",
|
||
"\n",
|
||
"Our task is: for given $\\mathbf{u}$ calculate $\\mathbf{R}(\\mathbf{u}) = \\mathbf{T}(\\mathbf{u}) - \\mathbf{F}(\\mathbf{u})$ and it's partial derivative with respect to $\\mathbf{u}$, i.e. $\\partial \\mathbf{R}(\\mathbf{u}) / \\partial \\mathbf{u}$."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 3,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"jacobian (generic function with 1 method)"
|
||
]
|
||
},
|
||
"execution_count": 3,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"function calc_residual_vector_integrand(el::JuliaFEM.Element, xi)\n",
|
||
" # Calculate dN/dX\n",
|
||
" dbasisdX = JuliaFEM.get_dbasisdX(el, xi)\n",
|
||
"\n",
|
||
" # Calculate residual force vector R(u) = T(u) - F(u)\n",
|
||
" function T(u)\n",
|
||
" # kinematics\n",
|
||
" gradu = u*dbasisdX\n",
|
||
" F = I + gradu\n",
|
||
" E = 1/2*(gradu' + gradu + gradu'*gradu)\n",
|
||
" # constitutive equation\n",
|
||
" lambda = JuliaFEM.interpolate(el, \"lambda\", xi)\n",
|
||
" mu = JuliaFEM.interpolate(el, \"mu\", xi)\n",
|
||
" S = lambda*trace(E)*I + 2*mu*E\n",
|
||
" P = F*S\n",
|
||
" T = P*dbasisdX'\n",
|
||
" return T\n",
|
||
" end\n",
|
||
"\n",
|
||
" u = el.attributes[\"displacement\"]\n",
|
||
" R(u) = T(u)\n",
|
||
" return R(u) # we skip calculating external force vector for now.\n",
|
||
"end\n",
|
||
"\n",
|
||
"calc_residual_vector = JuliaFEM.integrate(calc_residual_vector_integrand)\n",
|
||
"# calculate partial derivatives of R with respect to field \"displacement\"\n",
|
||
"calc_tangent_stiffness = JuliaFEM.linearize(calc_residual_vector, \"displacement\")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"That was our geometrically nonlinear elasticity solver. Note how we used automatic differentiation to linearize residual vector.\n",
|
||
"\n",
|
||
"*Design principle 6*: we test our code. We use FactCheck for testing."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 4,
|
||
"metadata": {
|
||
"collapsed": true
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"using FactCheck"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 6,
|
||
"metadata": {
|
||
"collapsed": false,
|
||
"scrolled": false
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"test solve one element model\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"17-Aug 18:21:25:DEBUG:root:Converged in 6 iterations.\n",
|
||
"17-Aug 18:21:25:DEBUG:root:solution vector: \n",
|
||
" [0.0 -0.3991450609547433 -0.07228582695592461 0.0\n",
|
||
" 0.0 -2.1779892317073504 -2.222244754401764 0.0]\n",
|
||
"17-Aug 18:21:25:DEBUG:root:norm of u: 3.1292483947150047\n",
|
||
"17-Aug 18:21:25:DEBUG:root:Converged in 6 iterations.\n",
|
||
"17-Aug 18:21:25:DEBUG:root:solution vector: \n",
|
||
" [0.0 0.7433248532717796 1.048521014723486 0.0\n",
|
||
" 0.0 -2.085766534304891 -1.9606633242166027 0.0]\n",
|
||
"17-Aug 18:21:26:DEBUG:root:norm of u: 3.1292483947150056\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"2 facts verified.\n"
|
||
]
|
||
},
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"delayed_handler (generic function with 4 methods)"
|
||
]
|
||
},
|
||
"execution_count": 6,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"function get_test_element()\n",
|
||
" # set up one linear quadrangle element\n",
|
||
" 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.0, 1.0, 1.0, 1.0]\n",
|
||
" attributes = Dict()\n",
|
||
" e = JuliaFEM.Element(1, [1, 2, 3, 4], basis, dbasis, attributes, ipoints, iweights)\n",
|
||
" E = 90.0\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",
|
||
" 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.0 0.0; 0.0 0.0]'\n",
|
||
" return e\n",
|
||
"end\n",
|
||
"\n",
|
||
"facts(\"test solve one element model\") do\n",
|
||
"\n",
|
||
" e = get_test_element()\n",
|
||
" F = [0.0 0.0; 0.0 0.0; 0.0 -2.0; 0.0 0.0]'\n",
|
||
"\n",
|
||
" du = zeros(2, 4)\n",
|
||
"\n",
|
||
" free_dofs = [3, 4, 5, 6]\n",
|
||
" for i=1:10\n",
|
||
" R = calc_residual_vector(e)\n",
|
||
" K = calc_tangent_stiffness(e)\n",
|
||
" du[free_dofs] = K[free_dofs, free_dofs] \\ -(R - F)[free_dofs]\n",
|
||
" e.attributes[\"displacement\"] += du\n",
|
||
" if norm(du) < 1.0e-9\n",
|
||
" Logging.debug(\"Converged in $i iterations.\")\n",
|
||
" break\n",
|
||
" end\n",
|
||
" end\n",
|
||
"\n",
|
||
" # Tested against Elmer solution\n",
|
||
" u = e.attributes[\"displacement\"]\n",
|
||
" Logging.debug(\"solution vector: \\n $u\")\n",
|
||
" @fact u[2, 3] --> roughly(-2.222244754401764)\n",
|
||
" norm1 = norm(u)\n",
|
||
" Logging.debug(\"norm of u: $(norm(u))\")\n",
|
||
"\n",
|
||
" # We rotate model a bit and make sure that norm remains same\n",
|
||
" phi = 30/180*pi\n",
|
||
" rmat = [\n",
|
||
" cos(phi) -sin(phi)\n",
|
||
" sin(phi) cos(phi)]\n",
|
||
" e.attributes[\"coordinates\"] = rmat*e.attributes[\"coordinates\"]\n",
|
||
" F = rmat*F\n",
|
||
"\n",
|
||
" e.attributes[\"displacement\"] = [0.0 0.0; 0.0 0.0; 0.0 0.0; 0.0 0.0]'\n",
|
||
" du = zeros(2, 4)\n",
|
||
" for i=1:10\n",
|
||
" R = calc_residual_vector(e)\n",
|
||
" K = calc_tangent_stiffness(e)\n",
|
||
" du[free_dofs] = K[free_dofs, free_dofs] \\ -(R - F)[free_dofs]\n",
|
||
" e.attributes[\"displacement\"] += du\n",
|
||
" if norm(du) < 1.0e-9\n",
|
||
" Logging.debug(\"Converged in $i iterations.\")\n",
|
||
" break\n",
|
||
" end\n",
|
||
" end\n",
|
||
" u = e.attributes[\"displacement\"]\n",
|
||
" Logging.debug(\"solution vector: \\n $u\")\n",
|
||
" Logging.debug(\"norm of u: $(norm(u))\")\n",
|
||
" @fact norm(u) --> roughly(norm1) \n",
|
||
"end"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"One element solutions are not particularly interesting so next step is to create function that assembles global matrix from local matrices. Some data types:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 9,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"assemble_element! (generic function with 2 methods)"
|
||
]
|
||
},
|
||
"execution_count": 9,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"function assemble_element!(ass::Assembly, el::Element)\n",
|
||
"\n",
|
||
" # Material properties\n",
|
||
" E = el.attributes[\"Young\"]\n",
|
||
" nu = el.attributes[\"Poisson\"]\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",
|
||
" dofs = prod(size(el.coordinates))\n",
|
||
" X = el.coordinates\n",
|
||
" u = el.attributes[\"displacement\"]\n",
|
||
" R = el.attributes[\"displacement nodal force\"]\n",
|
||
" K = el.attributes[\"displacement tangent stiffness\"]\n",
|
||
"\n",
|
||
" gdofs = ass.gdofs[el.id]\n",
|
||
" #Logging.debug(\"Assemble element $(el.id) to gdofs $gdofs\")\n",
|
||
" basis, dbasis = get_shape_functions(el)\n",
|
||
" ipoints, iweights = get_integration_scheme(el, io)\n",
|
||
" calc_local_matrices!(X, u, R, K, basis, dbasis, la, mu, ipoints, iweights)\n",
|
||
"\n",
|
||
" for i=1:dofs\n",
|
||
" for j=1:dofs\n",
|
||
" push!(ass.I, gdofs[i])\n",
|
||
" push!(ass.J, gdofs[j])\n",
|
||
" push!(ass.A, K[i,j])\n",
|
||
" end\n",
|
||
" push!(ass.i, gdofs[i])\n",
|
||
" push!(ass.b, R[i])\n",
|
||
" end\n",
|
||
"end"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"Time to test again. From last test we know that correct solution is\n",
|
||
"\n",
|
||
" [0.0 -0.39914506095474317 -0.07228582695592449 0.0\n",
|
||
" 0.0 -2.1779892317073504 -2.222244754401764 0.0]\n",
|
||
"\n",
|
||
"This time we assemble global stiffness matrix in different order, 2 3 4 1"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 10,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"WARNING: the `=>` syntax is deprecated, use `-->` instead\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"one element assembly\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"15-Aug 17:03:55:DEBUG:root:Adding nodes to array\n",
|
||
"15-Aug 17:03:55:DEBUG:root:Creating elements\n",
|
||
"15-Aug 17:03:55:DEBUG:root:Starting iteration 1\n",
|
||
"15-Aug 17:03:55:DEBUG:root:Assembling\n",
|
||
"15-Aug 17:03:57:DEBUG:root:Solution norm = 3.090022136728999\n",
|
||
"15-Aug 17:03:57:DEBUG:root:Starting iteration 2\n",
|
||
"15-Aug 17:03:57:DEBUG:root:Assembling\n",
|
||
"15-Aug 17:03:57:DEBUG:root:Solution norm = 0.32121316021535135\n",
|
||
"15-Aug 17:03:57:DEBUG:root:Starting iteration 3\n",
|
||
"15-Aug 17:03:57:DEBUG:root:Assembling\n",
|
||
"15-Aug 17:03:57:DEBUG:root:Solution norm = 0.040431781939994194\n",
|
||
"15-Aug 17:03:57:DEBUG:root:Starting iteration 4\n",
|
||
"15-Aug 17:03:57:DEBUG:root:Assembling\n",
|
||
"15-Aug 17:03:57:DEBUG:root:Solution norm = 0.0009291101052124042\n",
|
||
"15-Aug 17:03:57:DEBUG:root:Starting iteration 5\n",
|
||
"15-Aug 17:03:57:DEBUG:root:Assembling\n",
|
||
"15-Aug 17:03:57:DEBUG:root:Solution norm = 1.5638899022213175e-7\n",
|
||
"15-Aug 17:03:58:DEBUG:root:Starting iteration 6\n",
|
||
"15-Aug 17:03:58:DEBUG:root:Assembling\n",
|
||
"15-Aug 17:03:58:DEBUG:root:Solution norm = 1.0118539067290854e-14\n",
|
||
"15-Aug 17:03:58:DEBUG:root:Converged in 6 iterations.\n",
|
||
"15-Aug 17:03:58:DEBUG:root:Displacement of element = \n",
|
||
"[-0.39914506095474334 -0.0722858269559246 0.0 0.0\n",
|
||
" -2.1779892317073504 -2.2222447544017645 0.0 0.0]\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"1 fact verified.\n"
|
||
]
|
||
},
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"delayed_handler (generic function with 4 methods)"
|
||
]
|
||
},
|
||
"execution_count": 10,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"facts(\"one element assembly\") do\n",
|
||
" # Create model\n",
|
||
" #Logging.debug(\"Creating nodes\")\n",
|
||
" #n1 = Node(1)\n",
|
||
" #n2 = Node(2)\n",
|
||
" #n3 = Node(3)\n",
|
||
" #n4 = Node(4)\n",
|
||
" Logging.debug(\"Adding nodes to array\")\n",
|
||
" #nodes = [n1.id, n2.id, n3.id, n4.id]\n",
|
||
" node_ids = [1, 2, 3, 4]\n",
|
||
" coordinates = [10.0 0.0; 10.0 1.0; 0.0 1.0; 0.0 0.0]'\n",
|
||
" attributes = Dict(\"Young\" => 90, \"Poisson\" => 0.25)\n",
|
||
" Logging.debug(\"Creating elements\")\n",
|
||
" el = Element(1, node_ids, coordinates, attributes)\n",
|
||
"\n",
|
||
" # Initialize elements ready for solution\n",
|
||
" el.attributes[\"displacement\"] = zeros(2, 4)\n",
|
||
" el.attributes[\"displacement nodal force\"] = zeros(2, 4)\n",
|
||
" el.attributes[\"displacement tangent stiffness\"] = zeros(8, 8)\n",
|
||
"\n",
|
||
" for i=1:10\n",
|
||
" Logging.debug(\"Starting iteration $i\")\n",
|
||
" ass = Assembly(Int64[], Int64[], Float64[], Int64[], Float64[], Dict{Int64,Array{Int64,1}}())\n",
|
||
" ass.gdofs[el.id] = [1, 2, 3, 4, 5, 6, 7, 8]\n",
|
||
" Logging.debug(\"Assembling\")\n",
|
||
" assemble_element!(ass, el)\n",
|
||
"\n",
|
||
" # Boundary conditions\n",
|
||
" F = [0 0; 0 -2; 0 0; 0 0]'\n",
|
||
" F = reshape(F, prod(size(F)))\n",
|
||
" free_dofs = [1, 2, 3, 4]\n",
|
||
"\n",
|
||
" # solution\n",
|
||
" K = sparse(ass.I, ass.J, ass.A)\n",
|
||
" R = full(sparsevec(ass.i, ass.b))\n",
|
||
" R = R - F\n",
|
||
" du = zeros(8) # must be determined from ass\n",
|
||
" du[free_dofs] = K[free_dofs, free_dofs] \\ -R[free_dofs]\n",
|
||
"\n",
|
||
" Logging.debug(\"Solution norm = $(norm(du))\")\n",
|
||
"\n",
|
||
" # update solution back to elements\n",
|
||
" eldu = du[ass.gdofs[el.id]]\n",
|
||
" eldu = reshape(eldu, (2, round(Int, length(eldu)/2)))\n",
|
||
" el.attributes[\"displacement\"] += eldu\n",
|
||
" if norm(du) < 1.0e-9\n",
|
||
" Logging.debug(\"Converged in $i iterations.\")\n",
|
||
" break\n",
|
||
" end\n",
|
||
" end\n",
|
||
" disp = el.attributes[\"displacement\"]\n",
|
||
" Logging.debug(\"Displacement of element = \\n$disp\")\n",
|
||
" @fact norm(disp) => roughly(3.1292483947150043)\n",
|
||
"end"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"Seems to be working. But we still need to handle boundary conditions more \"cleverly\" and generalize assembly to several elements (which is not problem).\n",
|
||
"\n",
|
||
"First of all, essential boundary conditions are nothing more than equality constraints saying that value for some degree of freedom is fixed. Elimination is just a special case when this value equals to zero. There is couple of different strategies to handle essential boundary conditions. One option is to force them using Lagrange multipliers which can also be used to create all kind of kinematic constraints also. (For example, contact can be considered as a kinematic constraint.) Another option is to manipulate matrix such a way that constraint is satisfied.\n",
|
||
"\n",
|
||
"Because we are now going \"bottom-up\", we develop something extremely simple that however deals with the problem:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 11,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"type BC\n",
|
||
" dofs :: Array{Int64, 1}\n",
|
||
" values :: Array{Float64, 1}\n",
|
||
"end"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 12,
|
||
"metadata": {
|
||
"collapsed": false,
|
||
"scrolled": false
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"solve two element problem\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"15-Aug 17:03:59:DEBUG:root:Creating elements\n",
|
||
"15-Aug 17:03:59:INFO:root:create_ldof2gdofmap: dofs per node: 2\n",
|
||
"15-Aug 17:04:00:DEBUG:root:Dict(4=>[7,8],2=>[3,4],3=>[5,6],5=>[9,10],6=>[11,12],1=>[1,2])\n",
|
||
"15-Aug 17:04:04:INFO:root:solve!: dofs per node: 2\n",
|
||
"15-Aug 17:04:04:DEBUG:root:Problem size = 12\n",
|
||
"15-Aug 17:04:04:DEBUG:root:Starting iteration 1\n",
|
||
"15-Aug 17:04:04:DEBUG:root:Assembling\n",
|
||
"15-Aug 17:04:05:DEBUG:root:Adding Dirichlet boundary conditions using Lagrange multipliers\n",
|
||
"15-Aug 17:04:05:DEBUG:root:Added 5 Lagrange multipliers to model\n",
|
||
"15-Aug 17:04:05:DEBUG:root:Adding Neumann boundary conditions\n",
|
||
"15-Aug 17:04:05:DEBUG:root:Solving system of equations. Total size = 16\n",
|
||
"15-Aug 17:04:05:DEBUG:root:Solution norm du = 0.6015838690633517\n",
|
||
"15-Aug 17:04:05:DEBUG:root:Starting iteration 2\n",
|
||
"15-Aug 17:04:05:DEBUG:root:Assembling\n",
|
||
"15-Aug 17:04:05:DEBUG:root:Adding Dirichlet boundary conditions using Lagrange multipliers\n",
|
||
"15-Aug 17:04:05:DEBUG:root:Added 5 Lagrange multipliers to model\n",
|
||
"15-Aug 17:04:05:DEBUG:root:Adding Neumann boundary conditions\n",
|
||
"15-Aug 17:04:05:DEBUG:root:Solving system of equations. Total size = 16\n",
|
||
"15-Aug 17:04:05:DEBUG:root:Solution norm du = 0.013420417380980414\n",
|
||
"15-Aug 17:04:05:DEBUG:root:Starting iteration 3\n",
|
||
"15-Aug 17:04:05:DEBUG:root:Assembling\n",
|
||
"15-Aug 17:04:05:DEBUG:root:Adding Dirichlet boundary conditions using Lagrange multipliers\n",
|
||
"15-Aug 17:04:05:DEBUG:root:Added 5 Lagrange multipliers to model\n",
|
||
"15-Aug 17:04:05:DEBUG:root:Adding Neumann boundary conditions\n",
|
||
"15-Aug 17:04:06:DEBUG:root:Solving system of equations. Total size = 16\n",
|
||
"15-Aug 17:04:06:DEBUG:root:Solution norm du = 0.00032202957936854873\n",
|
||
"15-Aug 17:04:06:DEBUG:root:Starting iteration 4\n",
|
||
"15-Aug 17:04:06:DEBUG:root:Assembling\n",
|
||
"15-Aug 17:04:06:DEBUG:root:Adding Dirichlet boundary conditions using Lagrange multipliers\n",
|
||
"15-Aug 17:04:06:DEBUG:root:Added 5 Lagrange multipliers to model\n",
|
||
"15-Aug 17:04:06:DEBUG:root:Adding Neumann boundary conditions\n",
|
||
"15-Aug 17:04:06:DEBUG:root:Solving system of equations. Total size = 16\n",
|
||
"15-Aug 17:04:06:DEBUG:root:Solution norm du = 9.906677094801476e-8\n",
|
||
"15-Aug 17:04:06:DEBUG:root:Starting iteration 5\n",
|
||
"15-Aug 17:04:06:DEBUG:root:Assembling\n",
|
||
"15-Aug 17:04:06:DEBUG:root:Adding Dirichlet boundary conditions using Lagrange multipliers\n",
|
||
"15-Aug 17:04:06:DEBUG:root:Added 5 Lagrange multipliers to model\n",
|
||
"15-Aug 17:04:06:DEBUG:root:Adding Neumann boundary conditions\n",
|
||
"15-Aug 17:04:06:DEBUG:root:Solving system of equations. Total size = 16\n",
|
||
"15-Aug 17:04:06:DEBUG:root:Solution norm du = 5.027624635820698e-15\n",
|
||
"15-Aug 17:04:06:DEBUG:root:Converged in 5 iterations.\n",
|
||
"15-Aug 17:04:06:DEBUG:root:Displacement of element = \n",
|
||
"[-0.02442313597467864 -0.039356000063335075 0.021097993207232584 0.020877031423993653\n",
|
||
" -0.12673626841485705 -0.40433021969759375 -0.40656320177872923 -0.1275776940913048]\n"
|
||
]
|
||
},
|
||
{
|
||
"name": "stdout",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"0 facts verified.\n"
|
||
]
|
||
},
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"delayed_handler (generic function with 4 methods)"
|
||
]
|
||
},
|
||
"execution_count": 12,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"\"\"\"\n",
|
||
"Create local dof to global dof mapping for given elements\n",
|
||
"\"\"\"\n",
|
||
"function create_ldof2gdofmap(elements; ndofs=2)\n",
|
||
" Logging.info(\"create_ldof2gdofmap: dofs per node: $ndofs\")\n",
|
||
"\n",
|
||
" all_node_ids = Int64[]\n",
|
||
" for el in elements\n",
|
||
" eldim, elnodes = size(el.coordinates)\n",
|
||
" for nid in el.node_ids\n",
|
||
" push!(all_node_ids, nid)\n",
|
||
" end\n",
|
||
" end\n",
|
||
" all_node_ids = unique(all_node_ids)\n",
|
||
" sort!(all_node_ids)\n",
|
||
"\n",
|
||
" # Assign global dof for each node\n",
|
||
" pdim = 1\n",
|
||
" ngdofs = Dict{Int64, Array{Int64,1}}()\n",
|
||
" for nid in all_node_ids\n",
|
||
" ngdofs[nid] = collect(pdim:pdim+ndofs-1)\n",
|
||
" pdim += ndofs\n",
|
||
" end\n",
|
||
"\n",
|
||
" return ngdofs\n",
|
||
"end\n",
|
||
"\n",
|
||
"function solve!(elements, dofmap, neumann_bcs, dirichlet_bcs; ndofs=2, max_iterations=10)\n",
|
||
"\n",
|
||
" dbc = \"lagrange\"\n",
|
||
" \n",
|
||
" Logging.info(\"solve!: dofs per node: $ndofs\")\n",
|
||
" pdim = length(dofmap)*ndofs\n",
|
||
" Logging.debug(\"Problem size = $pdim\")\n",
|
||
"\n",
|
||
" # Initialize elements ready for solution\n",
|
||
" for el in elements\n",
|
||
" eldim, elnodes = size(el.coordinates)\n",
|
||
" el.attributes[\"displacement\"] = zeros(ndofs, elnodes)\n",
|
||
" el.attributes[\"displacement nodal force\"] = zeros(ndofs, elnodes)\n",
|
||
" el.attributes[\"displacement tangent stiffness\"] = zeros(ndofs*elnodes, ndofs*elnodes)\n",
|
||
" end\n",
|
||
"\n",
|
||
" # Assign global dofs for elements\n",
|
||
" gdofs = Dict{Int64, Array{Int64,1}}()\n",
|
||
" for el in elements\n",
|
||
" gdofs[el.id] = Int64[]\n",
|
||
" for nid in el.node_ids\n",
|
||
" for ndof in dofmap[nid]\n",
|
||
" push!(gdofs[el.id], ndof)\n",
|
||
" end\n",
|
||
" end\n",
|
||
" end\n",
|
||
"\n",
|
||
" ass = Assembly(Int64[], Int64[], Float64[], Int64[], Float64[], gdofs)\n",
|
||
"\n",
|
||
" for iter=1:max_iterations\n",
|
||
" Logging.debug(\"Starting iteration $iter\")\n",
|
||
" ass.I = []\n",
|
||
" ass.J = []\n",
|
||
" ass.A = []\n",
|
||
" ass.i = []\n",
|
||
" ass.b = []\n",
|
||
" \n",
|
||
" Logging.debug(\"Assembling\")\n",
|
||
" for el in elements\n",
|
||
" assemble_element!(ass, el)\n",
|
||
" #println(\"Element stiffness matrix\")\n",
|
||
" #dump(round(el.attributes[\"displacement tangent stiffness\"], 2))\n",
|
||
" end\n",
|
||
"\n",
|
||
" i = 1\n",
|
||
" if dbc == \"lagrange\"\n",
|
||
" Logging.debug(\"Adding Dirichlet boundary conditions using Lagrange multipliers\")\n",
|
||
" # Dirichlet boundary conditions\n",
|
||
" for bc in dirichlet_bcs\n",
|
||
" for (dof, val) in zip(bc.dofs, bc.values)\n",
|
||
" #Logging.debug(\"dof $dof => $val\")\n",
|
||
" push!(ass.I, dof)\n",
|
||
" push!(ass.J, pdim+i)\n",
|
||
" push!(ass.A, 1)\n",
|
||
" push!(ass.I, pdim+i)\n",
|
||
" push!(ass.J, dof)\n",
|
||
" push!(ass.A, 1)\n",
|
||
" push!(ass.i, pdim+i)\n",
|
||
" push!(ass.b, 0)\n",
|
||
" i += 1\n",
|
||
" end\n",
|
||
" end\n",
|
||
" Logging.debug(\"Added $i Lagrange multipliers to model\")\n",
|
||
" end\n",
|
||
" i -= 1\n",
|
||
"\n",
|
||
" Logging.debug(\"Adding Neumann boundary conditions\")\n",
|
||
" F = zeros(pdim+i)\n",
|
||
" # Neumann boundary conditions\n",
|
||
" for bc in neumann_bcs\n",
|
||
" for (dof, val) in zip(bc.dofs, bc.values)\n",
|
||
" F[dof] += val\n",
|
||
" end\n",
|
||
" end\n",
|
||
"\n",
|
||
" Logging.debug(\"Solving system of equations. Total size = $(pdim+i)\")\n",
|
||
" # solution\n",
|
||
" K = sparse(ass.I, ass.J, ass.A)\n",
|
||
" R = full(sparsevec(ass.i, ass.b))\n",
|
||
" R = R - F\n",
|
||
" #Logging.debug(dump(round(full(K), 2)))\n",
|
||
" #print_matrix(full(K))\n",
|
||
" #Logging.debug(dump(round(R', 1)))\n",
|
||
"\n",
|
||
" if dbc == \"eliminate\"\n",
|
||
" Logging.debug(\"Eliminating Dirichlet boundary conditions\")\n",
|
||
" throw(\"Implement this properly\")\n",
|
||
" free_dofs = [1, 2, 3, 4, 5, 6, 7, 8]\n",
|
||
" du = zeros(12)\n",
|
||
" Logging.debug(\"K norm = $(norm(full(K[free_dofs, free_dofs])))\")\n",
|
||
" du[free_dofs] = K[free_dofs, free_dofs] \\ -R[free_dofs]\n",
|
||
" else\n",
|
||
" du = K \\ -R\n",
|
||
" end\n",
|
||
"\n",
|
||
" #du = reshape(du, 2, 6)\n",
|
||
" solnorm = norm(du[1:pdim])\n",
|
||
" #Logging.debug(\"du = $du\")\n",
|
||
" Logging.debug(\"Solution norm du = $solnorm\")\n",
|
||
"\n",
|
||
" # update solution back to elements\n",
|
||
" for el in elements\n",
|
||
" #Logging.debug(\"update element $(el.id)\")\n",
|
||
" eldisp = el.attributes[\"displacement\"]\n",
|
||
" #Logging.debug(\"displacement before update $(el.id) : \\n$eldisp\")\n",
|
||
" eldu = du[ass.gdofs[el.id]]\n",
|
||
" eldu = reshape(eldu, (ndofs, round(Int, length(eldu)/ndofs)))\n",
|
||
" #Logging.debug(\"eldu for element $(el.id) \\n$eldu\")\n",
|
||
" el.attributes[\"displacement\"] += eldu\n",
|
||
" eldisp = el.attributes[\"displacement\"]\n",
|
||
" #Logging.debug(\"displacement after update $(el.id) : \\n$eldisp\")\n",
|
||
"\n",
|
||
" end\n",
|
||
" if solnorm < 1.0e-9\n",
|
||
" Logging.debug(\"Converged in $iter iterations.\")\n",
|
||
" break\n",
|
||
" end\n",
|
||
" end\n",
|
||
"\n",
|
||
"end\n",
|
||
"\n",
|
||
"ENV[\"COLUMNS\"] = 160\n",
|
||
"\n",
|
||
"function test1():\n",
|
||
" facts(\"solve one element problem\") do\n",
|
||
" # Create model\n",
|
||
" Logging.debug(\"Creating nodes\")\n",
|
||
" node_ids = [1, 2, 3, 4]\n",
|
||
" coordinates = [10.0 0.0; 10.0 1.0; 0.0 1.0; 0.0 0.0]'\n",
|
||
" attributes = Dict(\"Young\" => 90, \"Poisson\" => 0.25)\n",
|
||
" Logging.debug(\"Creating elements\")\n",
|
||
" el = Element(1, node_ids, coordinates, attributes)\n",
|
||
" elements = [el]\n",
|
||
" dofmap = create_ldof2gdofmap(elements)\n",
|
||
" Logging.debug(dofmap)\n",
|
||
" # Boundary conditions\n",
|
||
" # here we want to create nodal force for third dof, that is, node id 2, second dof\n",
|
||
" bc1 = BC([dofmap[2][2]], [-2.0])\n",
|
||
" # dirichlet bc, set dx=dy=0 on support\n",
|
||
" bc2 = BC([dofmap[3][1], dofmap[3][2], dofmap[4][1], dofmap[4][2]], [0.0, 0.0, 0.0, 0.0])\n",
|
||
" solve!(elements, dofmap, [bc1], [bc2]; max_iterations=7)\n",
|
||
" disp = elements[1].attributes[\"displacement\"]\n",
|
||
" Logging.debug(\"Displacement of element = \\n$disp\")\n",
|
||
" @fact norm(disp) => roughly(3.1292483947150043)\n",
|
||
" end\n",
|
||
"end\n",
|
||
"\n",
|
||
"facts(\"solve two element problem\") do\n",
|
||
" # Create model\n",
|
||
" attributes = Dict(\"Young\" => 90, \"Poisson\" => 0.25)\n",
|
||
"\n",
|
||
" Logging.debug(\"Creating elements\")\n",
|
||
" nids1 = [5, 1, 3, 6]\n",
|
||
" coords1 = [0.0 0.0; 5.0 0.0; 5.0 1.0; 0.0 1.0]'\n",
|
||
" el1 = Element(1, nids1, coords1, copy(attributes))\n",
|
||
" nids2 = [1, 2, 4, 3]\n",
|
||
" coords2 = [5.0 0.0; 10.0 0.0; 10.0 1.0; 5.0 1.0]'\n",
|
||
" el2 = Element(2, nids2, coords2, copy(attributes))\n",
|
||
" elements = [el1, el2]\n",
|
||
"\n",
|
||
" dofmap = create_ldof2gdofmap(elements)\n",
|
||
" Logging.debug(dofmap)\n",
|
||
" # Boundary conditions\n",
|
||
" # here we want to create nodal force for third dof, that is, node id 2, second dof\n",
|
||
" bc1 = BC([dofmap[4][2]], [-0.1])\n",
|
||
" # dirichlet bc, set dx=dy=0 on support\n",
|
||
" bc2 = BC([dofmap[5][1], dofmap[5][2], dofmap[6][1], dofmap[6][2]], [0.0, 0.0, 0.0, 0.0])\n",
|
||
" solve!(elements, dofmap, [bc1], [bc2]; max_iterations=7)\n",
|
||
" disp = elements[2].attributes[\"displacement\"]\n",
|
||
" Logging.debug(\"Displacement of element = \\n$disp\")\n",
|
||
" #@fact norm(disp) => roughly(3.1292483947150043)\n",
|
||
"end"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Top-down design\n",
|
||
"\n",
|
||
"Next we see this problem from \"other direction\", by parsing ABAQUS .inp file and making 3d simulation."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 13,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"\n",
|
||
"WARNING: deprecated syntax \"{a=>b, ...}\" at /Users/jukka/.julia/v0.4/JuliaFEM/src/abaqus_reader.jl:11.\n",
|
||
"Use \"Dict{Any,Any}(a=>b, ...)\" instead.\n",
|
||
"\n",
|
||
"WARNING: deprecated syntax \"{a=>b, ...}\" at /Users/jukka/.julia/v0.4/JuliaFEM/src/abaqus_reader.jl:32.\n",
|
||
"Use \"Dict{Any,Any}(a=>b, ...)\" instead.\n",
|
||
"15-Aug 17:04:20:INFO:root:Registered handlers: Any[\"ELEMENT\",\"NODE\",\"NSET\"]\n",
|
||
"WARNING: beginswith is deprecated, use startswith instead.\n",
|
||
" in depwarn at /Applications/Julia-0.4.0-dev-539c818c4e.app/Contents/Resources/julia/lib/julia/sys.dylib\n",
|
||
" in beginswith at deprecated.jl:30\n",
|
||
" in parse_abaqus at /Users/jukka/.julia/v0.4/JuliaFEM/src/abaqus_reader.jl:113\n",
|
||
" in include_string at loading.jl:99\n",
|
||
" in execute_request_0x535c5df2 at /Users/jukka/.julia/v0.4/IJulia/src/execute_request.jl:157\n",
|
||
" in eventloop at /Users/jukka/.julia/v0.4/IJulia/src/IJulia.jl:123\n",
|
||
" in anonymous at task.jl:365\n",
|
||
"while loading In[13], in expression starting on line 3\n",
|
||
"WARNING: beginswith is deprecated, use startswith instead.\n",
|
||
" in depwarn at /Applications/Julia-0.4.0-dev-539c818c4e.app/Contents/Resources/julia/lib/julia/sys.dylib\n",
|
||
" in beginswith at deprecated.jl:30\n",
|
||
" in parse_abaqus at /Users/jukka/.julia/v0.4/JuliaFEM/src/abaqus_reader.jl:113\n",
|
||
" in include_string at loading.jl:99\n",
|
||
" in execute_request_0x535c5df2 at /Users/jukka/.julia/v0.4/IJulia/src/execute_request.jl:157\n",
|
||
" in eventloop at /Users/jukka/.julia/v0.4/IJulia/src/IJulia.jl:123\n",
|
||
" in anonymous at task.jl:365\n",
|
||
"while loading In[13], in expression starting on line 3\n",
|
||
"15-Aug 17:04:21:DEBUG:root:Found NODE section\n",
|
||
"15-Aug 17:04:22:DEBUG:root:Found ELEMENT section\n",
|
||
"WARNING: integer(s::AbstractString) is deprecated, use parse(Int,s) instead.\n",
|
||
" in depwarn at /Applications/Julia-0.4.0-dev-539c818c4e.app/Contents/Resources/julia/lib/julia/sys.dylib\n",
|
||
" in integer at deprecated.jl:49\n",
|
||
" in map at abstractarray.jl:1251\n",
|
||
" in parse_element_section at /Users/jukka/.julia/v0.4/JuliaFEM/src/abaqus_reader.jl:59\n",
|
||
" in process_section at /Users/jukka/.julia/v0.4/JuliaFEM/src/abaqus_reader.jl:108\n",
|
||
" in parse_abaqus at /Users/jukka/.julia/v0.4/JuliaFEM/src/abaqus_reader.jl:117\n",
|
||
" in include_string at loading.jl:99\n",
|
||
" in execute_request_0x535c5df2 at /Users/jukka/.julia/v0.4/IJulia/src/execute_request.jl:157\n",
|
||
" in eventloop at /Users/jukka/.julia/v0.4/IJulia/src/IJulia.jl:123\n",
|
||
" in anonymous at task.jl:365\n",
|
||
"while loading In[13], in expression starting on line 3\n",
|
||
"15-Aug 17:04:27:DEBUG:root:120 elements found\n",
|
||
"15-Aug 17:04:27:INFO:root:Creating ELSET Body1\n",
|
||
"15-Aug 17:04:27:DEBUG:root:Found NSET section\n",
|
||
"15-Aug 17:04:28:DEBUG:root:Creating node set SUPPORT\n",
|
||
"15-Aug 17:04:28:DEBUG:root:Found NSET section\n",
|
||
"15-Aug 17:04:28:DEBUG:root:Creating node set LOAD\n",
|
||
"15-Aug 17:04:28:DEBUG:root:Found NSET section\n",
|
||
"15-Aug 17:04:28:DEBUG:root:Creating node set TOP\n"
|
||
]
|
||
},
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"Dict{Any,Any} with 4 entries:\n",
|
||
" \"nodes\" => Dict{Any,Any}(288=>[97.5,7.5,10.0],11=>[92.5,2.5,5.0],134=>[45.0,10.0,0.0],158=>[2.5,2.5,0.0],160=>[7.5,7.5,0.0],215=>[60.0,0.0,5.0],29=>[2.5,7…\n",
|
||
" \"elements\" => Dict{Any,Any}(68=>[71,144,149,198,51,150,57,43,50,214],2=>[204,199,175,130,207,208,209,3,4,176],89=>[95,78,104,52,127,126,106,60,68,67],11=>[15…\n",
|
||
" \"elsets\" => Dict{Any,Any}(\"Body1\"=>[1,2,3,4,5,6,7,8,9,10 … 111,112,113,114,115,116,117,118,119,120])\n",
|
||
" \"nsets\" => Dict{Any,Any}(\"LOAD\"=>[82,84,87,179,197,246,249,256,257],\"SUPPORT\"=>[108,109,111,155,162,216,225,281,298],\"TOP\"=>[70,75,76,84,88,90,95,96,98,10…"
|
||
]
|
||
},
|
||
"execution_count": 13,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"using JuliaFEM.abaqus_reader\n",
|
||
"fid = open(\"../geometry/3d_beam/palkki.inp\")\n",
|
||
"model = JuliaFEM.abaqus_reader.parse_abaqus(fid)\n",
|
||
"close(fid)\n",
|
||
"model"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 14,
|
||
"metadata": {
|
||
"collapsed": false,
|
||
"scrolled": false
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"15-Aug 17:04:30:DEBUG:root:Creating elements\n",
|
||
"15-Aug 17:04:31:INFO:root:create_ldof2gdofmap: dofs per node: 3\n",
|
||
"15-Aug 17:04:31:INFO:root:solve!: dofs per node: 3\n",
|
||
"15-Aug 17:04:31:DEBUG:root:Problem size = 894\n",
|
||
"15-Aug 17:04:31:DEBUG:root:Starting iteration 1\n",
|
||
"15-Aug 17:04:31:DEBUG:root:Assembling\n",
|
||
"15-Aug 17:04:36:DEBUG:root:Adding Dirichlet boundary conditions using Lagrange multipliers\n",
|
||
"15-Aug 17:04:36:DEBUG:root:Added 28 Lagrange multipliers to model\n",
|
||
"15-Aug 17:04:36:DEBUG:root:Adding Neumann boundary conditions\n",
|
||
"15-Aug 17:04:36:DEBUG:root:Solving system of equations. Total size = 921\n",
|
||
"15-Aug 17:04:36:DEBUG:root:Solution norm du = 72.87727091053921\n",
|
||
"15-Aug 17:04:36:DEBUG:root:Starting iteration 2\n",
|
||
"15-Aug 17:04:36:DEBUG:root:Assembling\n",
|
||
"15-Aug 17:04:40:DEBUG:root:Adding Dirichlet boundary conditions using Lagrange multipliers\n",
|
||
"15-Aug 17:04:40:DEBUG:root:Added 28 Lagrange multipliers to model\n",
|
||
"15-Aug 17:04:40:DEBUG:root:Adding Neumann boundary conditions\n",
|
||
"15-Aug 17:04:40:DEBUG:root:Solving system of equations. Total size = 921\n",
|
||
"15-Aug 17:04:40:DEBUG:root:Solution norm du = 2.737285770100854\n",
|
||
"15-Aug 17:04:40:DEBUG:root:Starting iteration 3\n",
|
||
"15-Aug 17:04:40:DEBUG:root:Assembling\n",
|
||
"15-Aug 17:04:44:DEBUG:root:Adding Dirichlet boundary conditions using Lagrange multipliers\n",
|
||
"15-Aug 17:04:44:DEBUG:root:Added 28 Lagrange multipliers to model\n",
|
||
"15-Aug 17:04:44:DEBUG:root:Adding Neumann boundary conditions\n",
|
||
"15-Aug 17:04:44:DEBUG:root:Solving system of equations. Total size = 921\n",
|
||
"15-Aug 17:04:44:DEBUG:root:Solution norm du = 0.07997112801214978\n",
|
||
"15-Aug 17:04:44:DEBUG:root:Starting iteration 4\n",
|
||
"15-Aug 17:04:44:DEBUG:root:Assembling\n",
|
||
"15-Aug 17:04:48:DEBUG:root:Adding Dirichlet boundary conditions using Lagrange multipliers\n",
|
||
"15-Aug 17:04:48:DEBUG:root:Added 28 Lagrange multipliers to model\n",
|
||
"15-Aug 17:04:48:DEBUG:root:Adding Neumann boundary conditions\n",
|
||
"15-Aug 17:04:48:DEBUG:root:Solving system of equations. Total size = 921\n",
|
||
"15-Aug 17:04:48:DEBUG:root:Solution norm du = 6.406557430235748e-5\n",
|
||
"15-Aug 17:04:48:DEBUG:root:Starting iteration 5\n",
|
||
"15-Aug 17:04:48:DEBUG:root:Assembling\n",
|
||
"15-Aug 17:04:52:DEBUG:root:Adding Dirichlet boundary conditions using Lagrange multipliers\n",
|
||
"15-Aug 17:04:52:DEBUG:root:Added 28 Lagrange multipliers to model\n",
|
||
"15-Aug 17:04:52:DEBUG:root:Adding Neumann boundary conditions\n",
|
||
"15-Aug 17:04:52:DEBUG:root:Solving system of equations. Total size = 921\n",
|
||
"15-Aug 17:04:52:DEBUG:root:Solution norm du = 6.870072007793185e-11\n",
|
||
"15-Aug 17:04:52:DEBUG:root:Converged in 5 iterations.\n",
|
||
"15-Aug 17:04:52:INFO:root:Maximum absolute displacement in y direction: 6.9925206227884695\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"function solve_3d_model()\n",
|
||
" Logging.debug(\"Creating elements\")\n",
|
||
" elements = Element[]\n",
|
||
" coordinates = zeros(3, 10)\n",
|
||
" for (elid, node_ids) in model[\"elements\"]\n",
|
||
" for (i, nid) in enumerate(node_ids)\n",
|
||
" coordinates[:,i] = model[\"nodes\"][nid]\n",
|
||
" end\n",
|
||
" attributes = Dict(\"Young\" => 90, \"Poisson\" => 0.25)\n",
|
||
" el = Element(elid, node_ids, coordinates, attributes)\n",
|
||
" push!(elements, el)\n",
|
||
" end\n",
|
||
"\n",
|
||
" # create \"dofmap\" so that we know how to assemble global stiffness matrix\n",
|
||
" dofmap = create_ldof2gdofmap(elements; ndofs=3)\n",
|
||
"\n",
|
||
" # Boundary conditions\n",
|
||
"\n",
|
||
" # dirichlet bc, set dx=dy=dz for all nodes in set SUPPORT\n",
|
||
" bc_support = BC(Int64[], Float64[])\n",
|
||
" for nid in model[\"nsets\"][\"SUPPORT\"]\n",
|
||
" for i=1:3\n",
|
||
" push!(bc_support.dofs, dofmap[nid][i])\n",
|
||
" push!(bc_support.values, 0.0)\n",
|
||
" end\n",
|
||
" end\n",
|
||
"\n",
|
||
" # force boundary condition, put -1 to 2nd dof for each node in set LOAD\n",
|
||
" bc_load = BC(Int64[], Float64[])\n",
|
||
" for nid in model[\"nsets\"][\"LOAD\"]\n",
|
||
" push!(bc_load.dofs, dofmap[nid][2])\n",
|
||
" push!(bc_load.values, -30.0)\n",
|
||
" end\n",
|
||
"\n",
|
||
" #solve!(elements, [bc1], [bc2]; max_iterations=7)\n",
|
||
" neumann_bcs = [bc_load]\n",
|
||
" dirichlet_bcs = [bc_support]\n",
|
||
" # ndofs = dimension of unknown field in nodes\n",
|
||
" solve!(elements, dofmap, neumann_bcs, dirichlet_bcs; ndofs=3, max_iterations=10)\n",
|
||
"\n",
|
||
" # Let's pick maximum absolute displacement in y direction\n",
|
||
" maxdisp = 0.0\n",
|
||
" for el in elements\n",
|
||
" eldisp = el.attributes[\"displacement\"]\n",
|
||
" eldispy = eldisp[2,:]\n",
|
||
" maxeldisp = maximum(abs(eldispy))\n",
|
||
" if maxeldisp > maxdisp\n",
|
||
" maxdisp = maxeldisp\n",
|
||
" end\n",
|
||
" end\n",
|
||
" Logging.info(\"Maximum absolute displacement in y direction: $maxdisp\")\n",
|
||
" return model, elements, dofmap\n",
|
||
"end\n",
|
||
"\n",
|
||
"model, elements, dofmap = solve_3d_model();"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Saving results to file"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 15,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"<Grid Name=\"Grid\">\n",
|
||
" <Time Value=\"0\"/>\n",
|
||
"</Grid>\n"
|
||
]
|
||
},
|
||
"execution_count": 15,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"xdoc, xmodel = JuliaFEM.xdmf.xdmf_new_model()\n",
|
||
"temporal_collection = JuliaFEM.xdmf.xdmf_new_temporal_collection(xmodel)\n",
|
||
"grid = JuliaFEM.xdmf.xdmf_new_grid(temporal_collection; time=0)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"Save geometry to xdmf file"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 16,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [
|
||
{
|
||
"name": "stderr",
|
||
"output_type": "stream",
|
||
"text": [
|
||
"15-Aug 17:04:54:INFO:root:Number of nodes in model: 298\n",
|
||
"15-Aug 17:04:54:INFO:root:Number of elements in model: 120\n"
|
||
]
|
||
}
|
||
],
|
||
"source": [
|
||
"nnodes = length(model[\"nodes\"])\n",
|
||
"Logging.info(\"Number of nodes in model: $nnodes\")\n",
|
||
"node_ids = Int64[]\n",
|
||
"for nid in keys(model[\"nodes\"])\n",
|
||
" push!(node_ids, nid)\n",
|
||
"end\n",
|
||
"sort!(node_ids)\n",
|
||
"X = zeros(3, nnodes)\n",
|
||
"for (i, nid) in enumerate(node_ids)\n",
|
||
" X[:,i] = model[\"nodes\"][nid]\n",
|
||
"end\n",
|
||
"\n",
|
||
"nelements = length(model[\"elements\"])\n",
|
||
"Logging.info(\"Number of elements in model: $nelements\")\n",
|
||
"elmap = zeros(Int64, 11, nelements)\n",
|
||
"elmap[1,:] = 0x0026\n",
|
||
"for elid in 1:nelements\n",
|
||
" elmap[2:end,elid] = model[\"elements\"][elid]\n",
|
||
"end"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 17,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"true"
|
||
]
|
||
},
|
||
"execution_count": 17,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"using LightXML\n",
|
||
"\n",
|
||
"function xdmf_new_mesh(grid, X, elmap)\n",
|
||
" dim, nnodes = size(X)\n",
|
||
" geometry = new_child(grid, \"Geometry\")\n",
|
||
" set_attribute(geometry, \"Type\", \"XYZ\")\n",
|
||
" dataitem = new_child(geometry, \"DataItem\")\n",
|
||
" set_attribute(dataitem, \"DataType\", \"Float\")\n",
|
||
" set_attribute(dataitem, \"Dimensions\", \"$nnodes $dim\")\n",
|
||
" set_attribute(dataitem, \"Format\", \"XML\")\n",
|
||
" set_attribute(dataitem, \"Precision\", 8)\n",
|
||
" #add_text(dataitem, join(X, \" \"))\n",
|
||
" s = \"\\n\"\n",
|
||
" \n",
|
||
" for i=1:nnodes\n",
|
||
" s *= \"\\t\\t\" * join(X[:,i], \" \") * \"\\n\"\n",
|
||
" end\n",
|
||
" s *= \" \"\n",
|
||
" add_text(dataitem, s)\n",
|
||
"\n",
|
||
" elmap2 = copy(elmap)\n",
|
||
" elmap2[2:end,:] -= 1\n",
|
||
" dim, nelements = size(elmap2)\n",
|
||
"\n",
|
||
" topology = new_child(grid, \"Topology\")\n",
|
||
" #set_attribute(topology, \"Dimensions\", \"1\")\n",
|
||
" set_attribute(topology, \"TopologyType\", \"Mixed\")\n",
|
||
" set_attribute(topology, \"NumberOfElements\", nelements)\n",
|
||
" dataitem = new_child(topology, \"DataItem\")\n",
|
||
" set_attribute(dataitem, \"DataType\", \"Int\")\n",
|
||
" set_attribute(dataitem, \"Dimensions\", \"$nelements $dim\")\n",
|
||
" set_attribute(dataitem, \"Format\", \"XML\")\n",
|
||
" set_attribute(dataitem, \"Precision\", 8)\n",
|
||
" s = \"\\n\"\n",
|
||
" for i=1:nelements\n",
|
||
" s *= \"\\t\\t\" * join(elmap2[:,i], \" \") * \"\\n\"\n",
|
||
" end\n",
|
||
" add_text(dataitem, s)\n",
|
||
" #add_text(dataitem, join(elmap2, \" \"))\n",
|
||
" \n",
|
||
"end\n",
|
||
"\n",
|
||
"xdmf_new_mesh(grid, X, elmap)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 18,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"10435"
|
||
]
|
||
},
|
||
"execution_count": 18,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"JuliaFEM.xdmf.xdmf_save_model(xdoc, \"/tmp/3d_solid_model.xmf\")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"Save nodal data to model"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 19,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"Dict{Any,Any} with 298 entries:\n",
|
||
" 288 => [-0.21784897897079505,-6.64256844921929,0.18339325827190953]\n",
|
||
" 11 => [-0.17342410820059667,-6.343125806991628,0.17544367431766225]\n",
|
||
" 158 => [-0.0007723334905839533,-0.2321904799732306,-0.03883691791045858]\n",
|
||
" 215 => [-0.03299227384130259,-4.2236276356937505,-0.0017757488281830807]\n",
|
||
" 134 => [-0.06336705102703495,-3.3332586850719337,0.06555932581531249]\n",
|
||
" 160 => [0.03205303832663507,-0.536361456950779,-0.07291283371223893]\n",
|
||
" 29 => [-0.01620524134284992,-0.19455583841608232,-0.03838421619811468]\n",
|
||
" 131 => [0.04015396763870081,-3.5101776818531523,0.10045744211179368]\n",
|
||
" 249 => [-0.2491004521409732,-6.570813533283954,0.06837890174506163]\n",
|
||
" 207 => [0.03974407267311282,-3.48588780058722,0.007971846403163977]\n",
|
||
" 173 => [-0.04472757590353555,-4.582185697159958,-0.04434348606400347]\n",
|
||
" 289 => [-0.16494613158592017,-6.360857515886982,0.33435404817411213]\n",
|
||
" 74 => [-0.03449870789750817,-3.947284664599636,0.0692691027146262]\n",
|
||
" 201 => [-0.00128347996939122,-3.8527236749372054,0.054216444201382656]\n",
|
||
" 176 => [-0.004729440266412542,-3.132546258410676,0.0036604388995965386]\n",
|
||
" 57 => [-0.021453552968802154,-4.134921994863808,0.04888988010136468]\n",
|
||
" 31 => [-0.005045439296021616,-0.3424143474221696,-0.0365148544462663]\n",
|
||
" 285 => [-0.19371941654927557,-6.446502168659889,0.18022053743770028]\n",
|
||
" 70 => [0.006277500845425116,-3.802694347992476,0.06251589929767469]\n",
|
||
" 33 => [-0.02778798411401373,-0.5091869603980016,0.03538255963543149]\n",
|
||
" 252 => [-0.11915625386204923,-1.2182594899567352,-0.025975085489623087]\n",
|
||
" 114 => [-0.14643901527350212,-0.4628626545501056,-0.0057156433415159625]\n",
|
||
" 165 => [-0.07462160313837857,-4.426674712264929,-0.04391022455570823]\n",
|
||
" 96 => [0.0541064545893336,-5.057801826440659,-0.01669155772495867]\n",
|
||
" 133 => [0.01615115174975327,-3.140610327091724,0.028951801068022566]\n",
|
||
" ⋮ => ⋮"
|
||
]
|
||
},
|
||
"execution_count": 19,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"nodaldisp = Dict()\n",
|
||
"for el in elements\n",
|
||
" for (i, nid) in enumerate(el.node_ids)\n",
|
||
" nodaldisp[nid] = el.attributes[\"displacement\"][:, i]\n",
|
||
" end\n",
|
||
"end\n",
|
||
"nodaldisp"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 20,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"3x298 Array{Float64,2}:\n",
|
||
" -0.202475 -0.17437 0.0131267 -0.0340868 -0.0252162 0.0521758 … -0.054781 -0.169903 0.186936 0.102666 -0.0970747 -0.164397 0.0\n",
|
||
" -1.34204 -1.66404 -3.20587 -3.27673 -3.68732 -3.36789 -4.33822 -1.03943 -2.27466 -1.67467 -2.91213 -2.52353 0.0\n",
|
||
" 0.0211856 0.0324162 0.00213878 0.0377156 0.0683502 0.030081 -0.00684333 -0.035509 0.304867 0.26033 0.113802 0.152433 0.0"
|
||
]
|
||
},
|
||
"execution_count": 20,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"u = zeros(3, nnodes)\n",
|
||
"for (i, nid) in enumerate(node_ids)\n",
|
||
" u[:,i] = nodaldisp[nid]\n",
|
||
"end\n",
|
||
"u"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 21,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"true"
|
||
]
|
||
},
|
||
"execution_count": 21,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"JuliaFEM.xdmf.xdmf_new_field(grid, \"Displacement\", \"nodes\", u)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 22,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"text/plain": [
|
||
"28330"
|
||
]
|
||
},
|
||
"execution_count": 22,
|
||
"metadata": {},
|
||
"output_type": "execute_result"
|
||
}
|
||
],
|
||
"source": [
|
||
"JuliaFEM.xdmf.xdmf_save_model(xdoc, \"/tmp/3d_solid_model.xmf\")"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": null,
|
||
"metadata": {
|
||
"collapsed": true
|
||
},
|
||
"outputs": [],
|
||
"source": []
|
||
}
|
||
],
|
||
"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
|
||
}
|