{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "### Example of a model with a compressible material\n", "\n", "An instantaneous 2D extension model. A compressible material is subject to lateral extension boundary conditions along the vertical walls.\n", "\n", "The compressible stokes flow equations are based on the compressible elasticity formulation: see Hughes, sec4.3, The Finite Element Method, 1987\n", "\n", "-----\n", "The momentum equtaion\n", "\n", "$\n", " \\sigma_{i,j} = -\\mathbf{p}\\delta_{i,j} + 2 \\eta \\dot\\epsilon_{i,j} = f_{i}\n", "$\n", "\n", "The continuity equation\n", "\n", "$\n", " \\mathbf{v}_{i,i} + \\frac{\\mathbf{p}}{\\lambda} = 0\n", "$ \n", "where:\n", " * $ \\dot \\epsilon_{i,j} = \\frac{1}{2}\\left[ \\mathbf{v}_{i,j} + \\mathbf{v}_{j,i} \\right ]$\n", " * $\\mathbf{v}$ is the velocity field\n", " * $\\mathbf{p}$ is the pressure like variable\n", " * $\\eta$ is the isotropic shear viscosity\n", " * $\\lambda$ is the bulk viscosity\n", " * $f$ is the body force" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import underworld as uw\n", "import numpy as np\n", "import math\n", "import os\n", "from underworld import function as fn\n", "import glucifer" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "minX = 0.0\n", "maxX = 2.0\n", "maxY = 1.0\n", "resX = 64\n", "resY = 32\n", "elementType=\"Q1/dQ0\"\n", "\n", "mesh = uw.mesh.FeMesh_Cartesian( elementType = (elementType), \n", " elementRes = ( resX, resY), \n", " minCoord = ( minX, 0.), \n", " maxCoord = ( maxX, maxY),\n", " periodic = [False, False] ) \n", "\n", "vField = uw.mesh.MeshVariable( mesh=mesh, nodeDofCount=mesh.dim )\n", "pField = uw.mesh.MeshVariable( mesh=mesh.subMesh, nodeDofCount=1 )\n", "\n", "vField.data[:] = [0.,0.]\n", "pField.data[:] = 0." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "# model parameters\n", "viscosityFn = 1.0 # isoviscous\n", "vel_extend = 0.5 # simple extension velocity\n", "oneonlambdaFn = 1.0e3 # 1/(bulk viscosity)\n", "buoyancyFn = ( 0.0, 0.0 ) # the body force" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "# first define strain rate tensor\n", "strainRateFn = fn.tensor.symmetric( vField.fn_gradient )\n", "strainRate_2ndInvariantFn = fn.tensor.second_invariant(strainRateFn)\n", "velmag = fn.math.sqrt( fn.math.dot(vField, vField) )" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "leftWall = mesh.specialSets[\"MinI_VertexSet\"]\n", "rightWall = mesh.specialSets[\"MaxI_VertexSet\"]\n", "\n", "bottomWall = mesh.specialSets[\"MinJ_VertexSet\"]\n", "topWall = mesh.specialSets[\"MaxJ_VertexSet\"]\n", "\n", "iWalls = leftWall + rightWall\n", "jWalls = bottomWall + topWall" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "def buildVelocityField( mesh, velField, extV ):\n", " '''\n", " Build the extension velocity field. Only extending the incomp beam.\n", " '''\n", " import math\n", " # set the all nodes on the vertical wall to extend extension\n", " for index in leftWall: # velocity to the left\n", " ycoord = mesh.data[index][1]\n", " velField.data[index] = [-1.0*extV, 0.]\n", "# velField.data[index] = [-1.0*extV*math.sin(ycoord*2*math.pi), 0.]\n", " for index in rightWall: # velocity to the right\n", " ycoord = mesh.data[index][1]\n", " velField.data[index] = [extV, 0.]\n", "\n", "buildVelocityField( mesh, vField, vel_extend)\n", "bcs_1 = uw.conditions.DirichletCondition( variable = vField, \n", " indexSetsPerDof = ( iWalls, jWalls) ) " ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "# fn_bodyforce is 0. So ONLY dynamic pressure is produced in this model.\n", "# For the incompressible material d. pressure is the mesh variable\n", "# For the compressibly material d. pressure is -lambda*div(vField)\n", "stokes = uw.systems.Stokes( velocityField = vField, \n", " pressureField = pField, \n", " conditions = bcs_1,\n", " fn_viscosity = viscosityFn,\n", " fn_bodyforce = buoyancyFn,\n", " fn_one_on_lambda = oneonlambdaFn )\n", "\n", "solver = uw.systems.Solver( stokes )" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "# can't use the AugmentedLagrangian with the penaly method yet\n", "# solver.set_penalty(1.0e6) \n", "solver.solve( nonLinearIterate=False, nonLinearTolerance=1e-2 )\n", "# solver.print_stats()" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "# analytics\n", "gradV = vField.fn_gradient\n", "divV = gradV[0] + gradV[3] # du_dx + dv_dy\n", "shouldBeZero = fn.math.abs(divV + pField*oneonlambdaFn)\n", "\n", "errorInt = uw.utils.Integral( shouldBeZero, mesh)\n", "volInt = uw.utils.Integral(1.0, mesh)" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "3.52124312125e-15\n" ] } ], "source": [ "# error across domain\n", "tol = 1e-6\n", "error = errorInt.evaluate()[0]/volInt.evaluate()[0]\n", "if error > tol:\n", " raise RuntimeError(\"Error: The continuity equation isn't solving within a volume averaged\" +\n", " \" tolerance of {} - it's value is {}\".format(tol, error))\n", "print(error)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(1.1477448914757307e-14, 1.6428302536547724e-16)" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "stokes.eqResiduals" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "figVel = glucifer.Figure()\n", "figVel.append( glucifer.objects.VectorArrows(mesh, vField, scaling=.25, arrowHead=0.2) )\n", "figVel.show()" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [], "source": [ "# # The pressure using the compute field\n", "# figP = glucifer.Figure( **figVel )\n", "# figP.append( glucifer.objects.Surface(mesh, pField*oneonlambdaFn, onMesh=True) )\n", "# figP.show()" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.5.3" } }, "nbformat": 4, "nbformat_minor": 1 }