{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Ideal plastic Von Mises material\n",
    "\n",
    "Author(s): Olli Väinölä <olli.vainola@student.oulu.fi>\n",
    "\n",
    "In this notebook is an small tutorial, how to create a Von Mises material without any hardening. Equations are formulated into rate depended form."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# imports\n",
    "using ForwardDiff\n",
    "using NLsolve\n",
    "using PyPlot"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's create a isotropic Hooke material."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "6x6 Array{Float64,2}:\n",
       " 2.69231e5  1.15385e5  1.15385e5  0.0        0.0        0.0      \n",
       " 1.15385e5  2.69231e5  1.15385e5  0.0        0.0        0.0      \n",
       " 1.15385e5  1.15385e5  2.69231e5  0.0        0.0        0.0      \n",
       " 0.0        0.0        0.0        1.53846e5  0.0        0.0      \n",
       " 0.0        0.0        0.0        0.0        1.53846e5  0.0      \n",
       " 0.0        0.0        0.0        0.0        0.0        1.53846e5"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "\n",
    "\n",
    "\"\"\"\n",
    "Create a isotropic Hooke material matrix C \n",
    "\n",
    "More information: # http://www.efunda.com/formulae/solid_mechanics/mat_mechanics/hooke_isotropic.cfm\n",
    "\n",
    "Parameters\n",
    "----------\n",
    "    E: Float\n",
    "        Elastic modulus\n",
    "    ν: Float\n",
    "        Poisson constant\n",
    "\n",
    "Returns\n",
    "-------\n",
    "    Array{Float64, (6,6)}\n",
    "\"\"\"\n",
    "function hookeStiffnessTensor(E, ν)\n",
    "    a = 1 - ν\n",
    "    b = 1 - 2*ν\n",
    "    c = 1 + ν\n",
    "    multiplier = E / (b * c)\n",
    "    return Float64[a ν ν 0 0 0;\n",
    "                   ν a ν 0 0 0;\n",
    "                   ν ν a 0 0 0;\n",
    "                   0 0 0 b 0 0;\n",
    "                   0 0 0 0 b 0;\n",
    "                   0 0 0 0 0 b].*multiplier\n",
    "end\n",
    "\n",
    "# Pick material values\n",
    "E = 200.0e3\n",
    "ν =  0.3\n",
    "C = hookeStiffnessTensor(E, ν)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "# Defining equations for the calculation\n",
    "\n",
    "Functions are defined for strain controller simulation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "calculate_stress (generic function with 1 method)"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# using vectors with double contradiction\n",
    "# http://www-2.unipv.it/compmech/teaching/available/const_mod/const_mod_mat-review_notation.pdf\n",
    "M = [1 0 0 0 0 0;\n",
    "     0 1 0 0 0 0;\n",
    "     0 0 1 0 0 0;\n",
    "     0 0 0 2 0 0;\n",
    "     0 0 0 0 2 0;\n",
    "     0 0 0 0 0 2;]\n",
    "\n",
    "\"\"\"\n",
    "Equivalent tensile stress. \n",
    "\n",
    "More info can be found from: https://en.wikipedia.org/wiki/Von_Mises_yield_criterion\n",
    "    Section: Reduced von Mises equation for different stress conditions\n",
    "\n",
    "Parameters\n",
    "----------\n",
    "    σ: Array{Float64, 6}\n",
    "        Stress in Voigt notation\n",
    "\n",
    "Returns\n",
    "-------\n",
    "    Float\n",
    "\"\"\"\n",
    "function σₑ(σ)\n",
    "    s = σ[1:6] - 1/3 * sum([σ[1], σ[2], σ[3]]) * [1 1 1 0 0 0]'\n",
    "    return sqrt(3/2 * s' * M * s)[1]\n",
    "end\n",
    "\n",
    "\n",
    "\"\"\"\n",
    "Von Mises Yield criterion\n",
    "\n",
    "More info can be found from: http://csm.mech.utah.edu/content/wp-content/uploads/2011/10/9tutorialOnJ2Plasticity.pdf\n",
    "\n",
    "Parameters\n",
    "----------\n",
    "    σ: Array{Float64, 6}\n",
    "        Stress in Voigt notation\n",
    "    k: Float64\n",
    "        Material constant, Yield limit\n",
    "\n",
    "Returns\n",
    "-------\n",
    "    Float\n",
    "\"\"\"\n",
    "function vonMisesYield(σ, k)\n",
    "    σₑ(σ) - k\n",
    "end\n",
    "\n",
    "\"\"\"\n",
    "Function for NLsolve. Inside this function are the equations which we want to find root.\n",
    "Ψ is the yield function below. Functions defined here:\n",
    "\n",
    "    dσ - C (dϵ - dλ*dΨ/dσ) = 0\n",
    "                 σₑ(σ) - k = 0\n",
    "\n",
    "Parameters\n",
    "----------\n",
    "    params: Array{Float64, 7}\n",
    "        Array containing values from solver\n",
    "    dϵ: Array{Float64, 6}\n",
    "        Strain rate vector in Voigt notation\n",
    "    C: Array{Float64, (6, 6)}\n",
    "        Material tensor\n",
    "    k: Float\n",
    "        Material constant, yield limit\n",
    "    Δt: Float\n",
    "        time increment\n",
    "    σ_begin:Array{Float64, 6}\n",
    "        Stress vector in Voigt notation\n",
    "\n",
    "Returns\n",
    "-------\n",
    "    Array{Float64, 7}, return values for solver\n",
    "\"\"\"\n",
    "function G(params, dϵ, C, k, σ_begin)\n",
    "\n",
    "    # Creating wrapper for gradient\n",
    "    yield(pars) = vonMisesYield(pars, k)\n",
    "    dfdσ = ForwardDiff.gradient(yield)\n",
    "    \n",
    "    # Stress rate\n",
    "    dσ = params[1:6]\n",
    "    \n",
    "    σ_tot = [vec(σ_begin); 0.0] + params\n",
    "    \n",
    "    # Calculating plastic strain rate\n",
    "    dϵp = params[end] * dfdσ(σ_tot)\n",
    "    \n",
    "    # Calculating equations\n",
    "    function_1 = dσ - C * (dϵ - dϵp[1:6])\n",
    "    function_2 = yield(σ_tot)\n",
    "    [vec(function_1); function_2]\n",
    "end\n",
    "\n",
    "\"\"\"\n",
    "Function which calculates the stress. Also handles if any yielding happens\n",
    "\n",
    "Parameters\n",
    "----------\n",
    "    dϵ: Array{Float64, 6}\n",
    "        Strain rate vector in Voigt notation\n",
    "    Δt: Float\n",
    "        time increment\n",
    "    σ: Array{Float64, 6}\n",
    "        Last stress vector in Voigt notation\n",
    "    C: Array{Float64, (6, 6)}\n",
    "        Material tensor\n",
    "    k: Float\n",
    "        Material constant, yield limit\n",
    "\n",
    "Returns\n",
    "-------\n",
    "    Tuple\n",
    "    Plastic strain rate dϵᵖ and new stress vector σ\n",
    "\"\"\"\n",
    "function calculate_stress(dϵ, σ, C, k)\n",
    "    # Test stress\n",
    "    σ_tria = σ + C * dϵ\n",
    "    \n",
    "    # Calculating yield\n",
    "    yield = vonMisesYield(σ_tria, k)\n",
    "\n",
    "    if yield > 0\n",
    "        # Yielding happened\n",
    "        # Creating functions for newton: xₙ₊₁ = xₙ - df⁻¹ * f and initial values\n",
    "        initial_guess = [vec(σ_tria - σ); 0.1]\n",
    "        f(σ_)  = G(σ_, dϵ, C, k, σ)\n",
    "        df     = ForwardDiff.jacobian(f)\n",
    "        \n",
    "        # Calculating root \n",
    "        result = nlsolve(not_in_place(f, df), initial_guess).zero\n",
    "\n",
    "        σ[:]  += result[1:6]\n",
    "    else\n",
    "        σ = σ_tria\n",
    "    end\n",
    "    return σ\n",
    "end"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Defining strain history"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "300-element Array{Float64,1}:\n",
       " -0.0        \n",
       " -5.67002e-5 \n",
       " -0.000113175\n",
       " -0.0001692  \n",
       " -0.000224554\n",
       " -0.000279014\n",
       " -0.000332367\n",
       " -0.000384399\n",
       " -0.000434904\n",
       " -0.00048368 \n",
       " -0.000530536\n",
       " -0.000575283\n",
       " -0.000617745\n",
       "  ⋮          \n",
       "  0.000575283\n",
       "  0.000530536\n",
       "  0.00048368 \n",
       "  0.000434904\n",
       "  0.000384399\n",
       "  0.000332367\n",
       "  0.000279014\n",
       "  0.000224554\n",
       "  0.0001692  \n",
       "  0.000113175\n",
       "  5.67002e-5 \n",
       "  6.61309e-19"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "steps = 300\n",
    "strain_max = 0.003\n",
    "num_cycles = 3\n",
    "\n",
    "ϵ_tot = zeros(Float64, (steps, 6))\n",
    "ϵ_tot2 = zeros(Float64, (steps, 6))\n",
    "ϵ_tot3 = zeros(Float64, (steps, 6))\n",
    "\n",
    "# Adding only strain in x-axis and counting for the poisson effect\n",
    "ϵ_tot[:, 1] = strain_max * sin(2 * pi * linspace(0, num_cycles, steps))\n",
    "ϵ_tot[:, 2] = strain_max * sin(2 * pi * linspace(0, num_cycles, steps)).*-ν\n",
    "ϵ_tot[:, 3] = strain_max * sin(2 * pi * linspace(0, num_cycles, steps)).*-ν"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Simulation\n",
    "\n",
    "Ok, we're good to go! Now we just need to define yield limit and the main loop.\n",
    "\n",
    "This simulation is not time dependent, but since it's already defined in the equations we'll give it value 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false,
    "scrolled": false
   },
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 47936 characters]",
      "text/plain": [
       "PyPlot.Figure(PyObject <matplotlib.figure.Figure object at 0x7f0821bd9610>)"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "PyObject <matplotlib.text.Text object at 0x7f0821a8f790>"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ϵ_last = zeros(Float64, (6))\n",
    "ϵᵖ = zeros(Float64, (6))\n",
    "σ = zeros(Float64, (6, 1))\n",
    "σy =  200.0\n",
    "ss = Float64[]\n",
    "ee = Float64[]\n",
    "\n",
    "for i=1:steps\n",
    "    dϵ = reshape(ϵ_tot[i, :, :], (6, 1)) - ϵ_last\n",
    "    σ = calculate_stress(dϵ, σ, C, σy)\n",
    "    ϵ_last += dϵ \n",
    "    push!(ss, σ[1])\n",
    "    push!(ee, ϵ_last[1])    \n",
    "end\n",
    "\n",
    "PyPlot.plot(ee, ss)\n",
    "PyPlot.title(\"Stress-Strain curve\")\n",
    "PyPlot.xlabel(\"Strain\")\n",
    "PyPlot.ylabel(\"Stress\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Julia 0.4.1-pre",
   "language": "julia",
   "name": "julia-0.4"
  },
  "language_info": {
   "file_extension": ".jl",
   "mimetype": "application/julia",
   "name": "julia",
   "version": "0.4.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
