{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Tie contact 3d\n",
    "\n",
    "Author(s): Jukka Aho"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Solid block\n",
    "\n",
    "Geometry and mesh:\n",
    "\n",
    "<div class=\"main_block\" style=\"max-width: 800px;\">\n",
    "  <div class=\"inner_block\" style=\"display: inline-block; float:left; width:50%;\">\n",
    "    <img src=\"http://results.juliafem.org/2015-12-13-box_geom.png\"\n",
    "         style=\"width:100%; height:auto; vertical-align:middle;\">\n",
    "  </div>\n",
    "  <div class=\"inner_block\" style=\"display: inline-block; float:left; width:50%;\">\n",
    "    <img src=\"http://results.juliafem.org/2015-12-13-box_bcs.png\"\n",
    "         style=\"width:100%; height:auto; vertical-align:middle;\">\n",
    "  </div>\n",
    "</div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "using JuliaFEM\n",
    "using JuliaFEM.Preprocess: parse_aster_med_file\n",
    "using JuliaFEM.Core: LinearElasticityProblem, DirichletProblem, get_connectivity, Quad4, Hex8, DirectSolver"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO: Found 4 element sets: SYM23, SYM12, SYM13, LOAD\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "Dict{ASCIIString,Any} with 2 entries:\n",
       "  \"nodes\"        => Dict(2=>[0.0,0.0,0.0],11=>[0.0,0.3333333333333333,1.0],39=>…\n",
       "  \"connectivity\" => Dict(68=>(:QU4,:OTHER,[45,47,48,46]),2=>(:SE2,:OTHER,[9,10]…"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mesh = parse_aster_med_file(Pkg.dir(\"JuliaFEM\")*\"/geometry/unit_box/mesh.med\")\n",
    "#mesh = parse_aster_med_file(Pkg.dir(\"JuliaFEM\")*\"/geometry/unit_box/twoelem_box.med\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO: created 36 elements.\n"
     ]
    }
   ],
   "source": [
    "# interior elements are of type HE8\n",
    "field_problem = LinearElasticityProblem()\n",
    "for (elid, (eltype, elset, elcon)) in mesh[\"connectivity\"]\n",
    "    eltype == :HE8 || continue\n",
    "    element = Hex8(elcon)\n",
    "    element[\"geometry\"] = Vector{Float64}[mesh[\"nodes\"][i] for i in get_connectivity(element)]\n",
    "    element[\"youngs modulus\"] = 900.0\n",
    "    element[\"poissons ratio\"] = 0.25\n",
    "    push!(field_problem, element)\n",
    "end\n",
    "# Neumann boundary condition, traction force -100 on Z direction for element set LOAD\n",
    "for (elid, (eltype, elset, elcon)) in mesh[\"connectivity\"]\n",
    "    (eltype == :QU4) && (elset == :LOAD) || continue\n",
    "    element = Quad4(elcon)\n",
    "    element[\"geometry\"] = Vector{Float64}[mesh[\"nodes\"][i] for i in get_connectivity(element)]\n",
    "    element[\"displacement traction force\"] = Vector{Float64}[[0.0, 0.0, -100.0] for i=1:4]\n",
    "    push!(field_problem, element)\n",
    "end\n",
    "info(\"created $(length(field_problem.elements)) elements.\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO: created 27 boundary elements.\n"
     ]
    }
   ],
   "source": [
    "# boundary conditions\n",
    "boundary_problem = DirichletProblem(\"displacement\", 3)\n",
    "for (elid, (eltype, elset, elcon)) in mesh[\"connectivity\"]\n",
    "    (eltype == :QU4) && (elset in [:SYM23, :SYM12, :SYM13]) || continue\n",
    "    element = Quad4(elcon)\n",
    "    element[\"geometry\"] = Vector{Float64}[mesh[\"nodes\"][i] for i in get_connectivity(element)]\n",
    "    if elset == :SYM23\n",
    "        element[\"displacement 1\"] = 0.0\n",
    "    elseif elset == :SYM12\n",
    "        element[\"displacement 3\"] = 0.0\n",
    "    elseif elset == :SYM13\n",
    "        element[\"displacement 2\"] = 0.0\n",
    "    end\n",
    "    push!(boundary_problem, element)\n",
    "end\n",
    "info(\"created $(length(boundary_problem.elements)) boundary elements.\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": false,
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO: # of field problems: 1\n",
      "INFO: # of boundary problems: 1\n",
      "INFO: Starting iteration 1\n",
      "INFO: Assembling field problems...\n",
      "INFO: Assembling body 1...\n",
      "INFO: dim = 192\n",
      "INFO: Assembling boundary problems...\n",
      "INFO: Assembling boundary 1...\n",
      "INFO: dumping matrices to disk, file = matrices_block_host_1_iteration_1.jld\n",
      "INFO: Solving system\n",
      "INFO: CHOLMOD: all dofs = 192\n",
      "INFO: CHOLMOD: interior dofs = 144\n",
      "INFO: CHOLMOD: boundary dofs = 48\n",
      "INFO: CHOLMOD: displacement on boundary solved.\n",
      "INFO: CHOLMOD: homogeneous dirichlet boundary\n",
      "INFO: CHOLMOD: LDLt factorization done in 0.0012049674987792969 seconds\n",
      "INFO: CHOLMOD: solved in 0.05479288101196289 seconds. norm = 0.5879447357921324\n",
      "INFO: timing info for iteration:\n",
      "INFO: boundary assembly       : 0.09608697891235352\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "(1,true)"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO: field assembly          : 1.0157549381256104\n",
      "INFO: dump matrices to disk   : 0.9569120407104492\n",
      "INFO: solve problem           : 0.48387885093688965\n",
      "INFO: update element data     : 0.01578807830810547\n",
      "INFO: non-linear iteration    : 2.568441867828369\n",
      "INFO: solver finished in 2.7200798988342285 seconds.\n"
     ]
    }
   ],
   "source": [
    "solver = DirectSolver()\n",
    "solver.name = \"block\"\n",
    "solver.nonlinear_problem = false\n",
    "#solver.method = :UMFPACK\n",
    "solver.dump_matrices = true\n",
    "push!(solver, field_problem)\n",
    "push!(solver, boundary_problem)\n",
    "call(solver, 0.0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO: nid near corner = 7\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "7"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "nid = 0\n",
    "for (nid, coords) in mesh[\"nodes\"]\n",
    "    if isapprox(coords, [1.0, 1.0, 1.0])\n",
    "        info(\"nid near corner = $nid\")\n",
    "        break\n",
    "    end\n",
    "end\n",
    "nid"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO: displacement X = [1.0,1.0,1.0], u = [0.027777777777777794,0.02777777777777784,-0.11111111111111129]\n",
      "INFO: displacement X = [1.0,1.0,1.0], u = [0.027777777777777794,0.02777777777777784,-0.11111111111111129]\n"
     ]
    }
   ],
   "source": [
    "using JuliaFEM.Test\n",
    "known_value = [1/36, 1/36, -1/9]\n",
    "for element in field_problem.elements\n",
    "    i = indexin([nid], get_connectivity(element))[1]\n",
    "    i != 0 || continue\n",
    "    X = element(\"geometry\", 0.0)\n",
    "    u = element(\"displacement\", 0.0)\n",
    "    info(\"displacement X = $(X[i]), u = $(u[i])\")\n",
    "    @test isapprox(u[i], known_value)\n",
    "end"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO: XDFM: ndim = 192\n"
     ]
    }
   ],
   "source": [
    "xdoc, xmodel = JuliaFEM.Postprocess.xdmf_new_model()\n",
    "coll = JuliaFEM.Postprocess.xdmf_new_temporal_collection(xmodel)\n",
    "grid = JuliaFEM.Postprocess.xdmf_new_grid(coll; time=0.0)\n",
    "\n",
    "Xg = Dict{Int64, Vector{Float64}}()\n",
    "ug = Dict{Int64, Vector{Float64}}()\n",
    "for element in field_problem.elements\n",
    "    conn = get_connectivity(element)\n",
    "    X = element(\"geometry\", 0.0)\n",
    "    u = element(\"displacement\", 0.0)\n",
    "    for (i, c) in enumerate(conn)\n",
    "        Xg[c] = X[i]\n",
    "        ug[c] = u[i]\n",
    "    end\n",
    "end\n",
    "perm = sort(collect(keys(Xg)))\n",
    "nodes = Vector{Float64}[Xg[i] for i in perm]\n",
    "disp = Vector{Float64}[ug[i] for i in perm]\n",
    "elements = []\n",
    "for el in field_problem.elements\n",
    "    isa(el, JuliaFEM.Core.Element{JuliaFEM.Core.Hex8}) || continue\n",
    "    push!(elements, (:Hex8, get_connectivity(el)))\n",
    "end\n",
    "#elements\n",
    "JuliaFEM.Postprocess.xdmf_new_mesh!(grid, nodes, elements)\n",
    "JuliaFEM.Postprocess.xdmf_new_nodal_field!(grid, \"displacement\", disp)\n",
    "JuliaFEM.Postprocess.xdmf_save_model(xdoc, \"/tmp/foobar2.xmf\");"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<img src=\"http://results.juliafem.org/2015-12-13-box_results.png\" width=300px style=\"float:left\">"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Block divived to two parts\n",
    "\n",
    "Block is now divided to two parts and meshes are tied using mortar method.\n",
    "\n",
    "<div class=\"main_block\" style=\"max-width: 800px;\">\n",
    "  <div class=\"inner_block\" style=\"display: inline-block; float:left; width:50%;\">\n",
    "    <img src=\"http://results.juliafem.org/2015-12-13-divided-block-geometry.png\"\n",
    "         style=\"width:100%; height:auto; vertical-align:middle;\">\n",
    "  </div>\n",
    "  <div class=\"inner_block\" style=\"display: inline-block; float:left; width:50%;\">\n",
    "    <img src=\"http://results.juliafem.org/2015-12-17-divided-block-both-parts.png\"\n",
    "         style=\"width:100%; height:auto; vertical-align:middle;\">\n",
    "  </div>\n",
    "</div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO: Found 6 element sets: SYM23, SYM12, UPPER_TO_LOWER, LOAD, SYM13, LOWER_TO_UPPER\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "Dict{ASCIIString,Any} with 2 entries:\n",
       "  \"nodes\"        => Dict(11=>[1.0,0.0,0.5],134=>[0.5,0.25,1.0],158=>[1.0,0.5,0.…\n",
       "  \"connectivity\" => Dict(288=>(:HE8,:OTHER,[176,177,180,179,167,168,171,170]),3…"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "using JuliaFEM\n",
    "using JuliaFEM.Preprocess: parse_aster_med_file\n",
    "using JuliaFEM.Core: LinearElasticityProblem, DirichletProblem, get_connectivity,\n",
    "                     Quad4, Hex8, LinearSolver, update\n",
    "mesh = parse_aster_med_file(Pkg.dir(\"JuliaFEM\")*\"/geometry/unit_box/BLOCKS.med\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO: created 107 elements.\n",
      "INFO: created 59 boundary elements.\n"
     ]
    }
   ],
   "source": [
    "# interior elements are of type HE8\n",
    "field_problem = LinearElasticityProblem()\n",
    "\n",
    "for (elid, (eltype, elset, elcon)) in mesh[\"connectivity\"]\n",
    "    eltype == :HE8 || continue\n",
    "    element = Hex8(elcon)\n",
    "    update(element, \"geometry\", mesh[\"nodes\"])\n",
    "    element[\"youngs modulus\"] = 900.0\n",
    "    element[\"poissons ratio\"] = 0.25\n",
    "    #info(\"lower: add element with connectivity $elcon\")\n",
    "    push!(field_problem, element)\n",
    "end\n",
    "\n",
    "# Neumann boundary condition, traction force -100 on Z direction for element set LOAD\n",
    "for (elid, (eltype, elset, elcon)) in mesh[\"connectivity\"]\n",
    "    (eltype == :QU4) && (elset == :LOAD) || continue\n",
    "    element = Quad4(elcon)\n",
    "    update(element, \"geometry\", mesh[\"nodes\"])\n",
    "    element[\"displacement traction force 3\"] = -100.0\n",
    "    push!(field_problem, element)\n",
    "end\n",
    "info(\"created $(length(field_problem.elements)) elements.\")\n",
    "\n",
    "# boundary conditions\n",
    "boundary_problem = DirichletProblem(\"displacement\", 3)\n",
    "\n",
    "for (elid, (eltype, elset, elcon)) in mesh[\"connectivity\"]\n",
    "    (eltype == :QU4) && (elset in [:SYM23, :SYM12, :SYM13]) || continue\n",
    "    element = Quad4(elcon)\n",
    "    update(element, \"geometry\", mesh[\"nodes\"])\n",
    "    if elset == :SYM23\n",
    "        element[\"displacement 1\"] = 0.0\n",
    "    elseif elset == :SYM12\n",
    "        element[\"displacement 3\"] = 0.0\n",
    "    elseif elset == :SYM13\n",
    "        element[\"displacement 2\"] = 0.0\n",
    "    end\n",
    "    push!(boundary_problem, element)\n",
    "end\n",
    "info(\"created $(length(boundary_problem.elements)) boundary elements.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Creating tie contact\n",
    "- define slave element surface (the one where integration happend)\n",
    "- define potential master elements for slave elements"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "WARNING: using PyPlot.mesh in module Main conflicts with an existing identifier.\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 22392 characters]",
      "text/plain": [
       "PyPlot.Figure(PyObject <matplotlib.figure.Figure object at 0x7f5cf2a922d0>)"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "(-0.1,1.1)"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "using JuliaFEM.Core: Element, MortarProblem, calculate_normal_tangential_coordinates!\n",
    "\n",
    "using PyPlot\n",
    "\n",
    "#mortar_surface = :LOWER_TO_UPPER\n",
    "#slave_surface = :UPPER_TO_LOWER\n",
    "mortar_surface = :UPPER_TO_LOWER\n",
    "slave_surface = :LOWER_TO_UPPER\n",
    "\n",
    "fig1 = figure(figsize=(5, 5))\n",
    "master_elements = JuliaFEM.Core.Element[]\n",
    "for (elid, (eltype, elset, elcon)) in mesh[\"connectivity\"]\n",
    "    (eltype == :QU4) && (elset == mortar_surface) || continue\n",
    "    element = Quad4(elcon)\n",
    "    update(element, \"geometry\", mesh[\"nodes\"])\n",
    "    X = element(\"geometry\", 0.0)\n",
    "    x = [X[mod(i, 4)+1][1] for i=1:5]\n",
    "    y = [X[mod(i, 4)+1][2] for i=1:5]\n",
    "    plot(x, y, \"-bo\", alpha=0.5)\n",
    "    push!(master_elements, element)\n",
    "end\n",
    "\n",
    "contact_problem = MortarProblem(\"displacement\", 3)\n",
    "for (elid, (eltype, elset, elcon)) in mesh[\"connectivity\"]\n",
    "    (eltype == :QU4) && (elset == slave_surface) || continue\n",
    "    element = Quad4(reverse(elcon))\n",
    "    update(element, \"geometry\", mesh[\"nodes\"])\n",
    "    element[\"master elements\"] = master_elements\n",
    "    X = element(\"geometry\", 0.0)\n",
    "    x = [X[mod(i, 4)+1][1] for i=1:5]\n",
    "    y = [X[mod(i, 4)+1][2] for i=1:5]\n",
    "    plot(x, y, \"-ro\", alpha=0.5)\n",
    "    calculate_normal_tangential_coordinates!(element, 0.0)\n",
    "    push!(contact_problem, element)\n",
    "end\n",
    "xlim(-0.1, 1.1)\n",
    "ylim(-0.1, 1.1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO: # of field problems: 1\n",
      "INFO: # of boundary problems: 2\n",
      "INFO: Starting iteration 1\n",
      "INFO: Assembling field problems...\n",
      "INFO: Assembling body 1...\n",
      "INFO: Assembly: 10.0 % done. \n",
      "INFO: Assembly: 20.0 % done. \n",
      "INFO: Assembly: 30.0 % done. \n",
      "INFO: Assembly: 40.0 % done. \n",
      "INFO: Assembly: 50.0 % done. \n",
      "INFO: Assembly: 60.0 % done. \n",
      "INFO: Assembly: 70.0 % done. \n",
      "INFO: Assembly: 80.0 % done. \n",
      "INFO: Assembly: 90.0 % done. \n",
      "INFO: Assembly: 100.0 % done. \n",
      "INFO: dim = 567\n",
      "INFO: Assembling boundary problems...\n",
      "INFO: Assembling boundary 1...\n",
      "INFO: Assembling boundary 2...\n",
      "INFO: dumping matrices to disk, file = matrices_tie_contact_3d_host_1_iteration_1.jld\n",
      "INFO: Solving system\n",
      "INFO: UMFPACK: solved in 0.21409296989440918 seconds. norm = 1.0506403593090503\n",
      "INFO: timing info for iteration:\n",
      "INFO: boundary assembly       : 1.9287428855895996\n",
      "INFO: field assembly          : 1.2453219890594482\n",
      "INFO: dump matrices to disk   : 1.1484379768371582\n",
      "INFO: solve problem           : 0.34978604316711426\n",
      "INFO: update element data     : 0.023519039154052734\n",
      "INFO: non-linear iteration    : 4.695832014083862\n",
      "INFO: solver finished in 4.851454019546509 seconds.\n",
      "INFO: nid near corner = 95\n",
      "INFO: displacement X = [1.0,1.0,1.0], u = [0.027777777777777818,0.02777777777777777,-0.11111111111111108]\n"
     ]
    }
   ],
   "source": [
    "using JuliaFEM.Core: DirectSolver\n",
    "solver = DirectSolver()\n",
    "solver.name = \"tie_contact_3d\"\n",
    "solver.method = :UMFPACK\n",
    "solver.nonlinear_problem = false\n",
    "solver.max_iterations = 1\n",
    "solver.dump_matrices = true\n",
    "push!(solver, field_problem)\n",
    "push!(solver, boundary_problem)\n",
    "push!(solver, contact_problem)\n",
    "call(solver, 0.0)\n",
    "\n",
    "using JuliaFEM.Test\n",
    "\n",
    "nid = 0\n",
    "for (nid, coords) in mesh[\"nodes\"]\n",
    "    if isapprox(coords, [1.0, 1.0, 1.0])\n",
    "        info(\"nid near corner = $nid\")\n",
    "        break\n",
    "    end\n",
    "end\n",
    "nid\n",
    "\n",
    "known_value = [1/36, 1/36, -1/9]\n",
    "\n",
    "for element in field_problem.elements\n",
    "    i = indexin([nid], get_connectivity(element))[1]\n",
    "    i != 0 || continue\n",
    "    X = element(\"geometry\", 0.0)\n",
    "    u = element(\"displacement\", 0.0)\n",
    "    info(\"displacement X = $(X[i]), u = $(u[i])\")\n",
    "    @test isapprox(u[i], known_value)\n",
    "end"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO: displacement X = [1.0,1.0,1.0], u = [0.027777777777777818,0.02777777777777777,-0.11111111111111108]\n",
      "INFO: XDFM: ndim = 567\n"
     ]
    }
   ],
   "source": [
    "xdoc, xmodel = JuliaFEM.Postprocess.xdmf_new_model()\n",
    "coll = JuliaFEM.Postprocess.xdmf_new_temporal_collection(xmodel)\n",
    "grid = JuliaFEM.Postprocess.xdmf_new_grid(coll; time=0.0)\n",
    "\n",
    "Xg = Dict{Int64, Vector{Float64}}()\n",
    "ug = Dict{Int64, Vector{Float64}}()\n",
    "for element in field_problem.elements\n",
    "    conn = get_connectivity(element)\n",
    "    X = element(\"geometry\", 0.0)\n",
    "    u = element(\"displacement\", 0.0)\n",
    "    for (i, c) in enumerate(conn)\n",
    "        Xg[c] = X[i]\n",
    "        ug[c] = u[i]\n",
    "    end\n",
    "end\n",
    "perm = sort(collect(keys(Xg)))\n",
    "nodes = Vector{Float64}[Xg[i] for i in perm]\n",
    "disp = Vector{Float64}[ug[i] for i in perm]\n",
    "elements = []\n",
    "for el in field_problem.elements\n",
    "    isa(el, JuliaFEM.Core.Element{JuliaFEM.Core.Hex8}) || continue\n",
    "    push!(elements, (:Hex8, get_connectivity(el)))\n",
    "end\n",
    "#elements\n",
    "JuliaFEM.Postprocess.xdmf_new_mesh!(grid, nodes, elements)\n",
    "JuliaFEM.Postprocess.xdmf_new_nodal_field!(grid, \"displacement\", disp)\n",
    "JuliaFEM.Postprocess.xdmf_save_model(xdoc, \"/tmp/blocks.xmf\");"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "<img src=\"http://results.juliafem.org/2015-12-17-divided-block-results.png\"\n",
    "         style=\"width:80%; height:auto; vertical-align:middle;\">"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "using JuliaFEM\n",
    "using JuliaFEM.Preprocess: parse_aster_med_file\n",
    "using JuliaFEM.Core: LinearElasticityProblem, DirichletProblem, get_connectivity, Tri3, Tet4, LinearSolver, update"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO: Found 6 element sets: SYM23, SYM12, UPPER_TO_LOWER, LOAD, SYM13, LOWER_TO_UPPER\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "Dict{ASCIIString,Any} with 2 entries:\n",
       "  \"nodes\"        => Dict(11=>[0.0,0.3333333333333333,0.0],134=>[0.0,0.869378844…\n",
       "  \"connectivity\" => Dict(306=>(:TE4,:OTHER,[53,24,51,83]),1316=>(:TE4,:OTHER,[2…"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mesh = parse_aster_med_file(Pkg.dir(\"JuliaFEM\")*\"/geometry/unit_box/BLOCKS_TET4.med\")\n",
    "#med = JuliaFEM.Preprocess.MEDFile(Pkg.dir(\"JuliaFEM\")*\"/geometry/unit_box/BLOCKS_TET4.med\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO: created 955 elements.\n",
      "INFO: created 116 boundary elements.\n"
     ]
    }
   ],
   "source": [
    "# interior elements are of type HE8\n",
    "field_problem = LinearElasticityProblem()\n",
    "\n",
    "for (elid, (eltype, elset, elcon)) in mesh[\"connectivity\"]\n",
    "    eltype == :TE4 || continue\n",
    "    element = Tet4(elcon)\n",
    "    update(element, \"geometry\", mesh[\"nodes\"])\n",
    "    element[\"youngs modulus\"] = 900.0\n",
    "    element[\"poissons ratio\"] = 0.25\n",
    "    #info(\"lower: add element with connectivity $elcon\")\n",
    "    push!(field_problem, element)\n",
    "end\n",
    "\n",
    "# Neumann boundary condition, traction force -100 on Z direction for element set LOAD\n",
    "for (elid, (eltype, elset, elcon)) in mesh[\"connectivity\"]\n",
    "    (eltype == :TR3) && (elset == :LOAD) || continue\n",
    "    element = Tri3(elcon)\n",
    "    update(element, \"geometry\", mesh[\"nodes\"])\n",
    "    element[\"displacement traction force 3\"] = -100.0\n",
    "    push!(field_problem, element)\n",
    "end\n",
    "info(\"created $(length(field_problem.elements)) elements.\")\n",
    "\n",
    "# boundary conditions\n",
    "boundary_problem = DirichletProblem(\"displacement\", 3)\n",
    "\n",
    "for (elid, (eltype, elset, elcon)) in mesh[\"connectivity\"]\n",
    "    (eltype == :TR3) && (elset in [:SYM23, :SYM12, :SYM13]) || continue\n",
    "    element = Tri3(elcon)\n",
    "    update(element, \"geometry\", mesh[\"nodes\"])\n",
    "    if elset == :SYM23\n",
    "        element[\"displacement 1\"] = 0.0\n",
    "    elseif elset == :SYM12\n",
    "        element[\"displacement 3\"] = 0.0\n",
    "    elseif elset == :SYM13\n",
    "        element[\"displacement 2\"] = 0.0\n",
    "    end\n",
    "    push!(boundary_problem, element)\n",
    "end\n",
    "info(\"created $(length(boundary_problem.elements)) boundary elements.\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "WARNING: using PyPlot.mesh in module Main conflicts with an existing identifier.\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 106788 characters]",
      "text/plain": [
       "PyPlot.Figure(PyObject <matplotlib.figure.Figure object at 0x7f7024d3c2d0>)"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "(-0.1,1.1)"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "using JuliaFEM.Core: Element, MortarProblem, calculate_normal_tangential_coordinates!\n",
    "\n",
    "using PyPlot\n",
    "\n",
    "#mortar_surface = :LOWER_TO_UPPER\n",
    "#slave_surface = :UPPER_TO_LOWER\n",
    "mortar_surface = :UPPER_TO_LOWER\n",
    "slave_surface = :LOWER_TO_UPPER\n",
    "\n",
    "fig1 = figure(figsize=(5, 5))\n",
    "master_elements = JuliaFEM.Core.Element[]\n",
    "for (elid, (eltype, elset, elcon)) in mesh[\"connectivity\"]\n",
    "    (eltype == :TR3) && (elset == mortar_surface) || continue\n",
    "    element = Tri3(elcon)\n",
    "    update(element, \"geometry\", mesh[\"nodes\"])\n",
    "    X = element(\"geometry\", 0.0)\n",
    "    x = [X[mod(i, 3)+1][1] for i=1:4]\n",
    "    y = [X[mod(i, 3)+1][2] for i=1:4]\n",
    "    plot(x, y, \"-bo\", alpha=0.5)\n",
    "    push!(master_elements, element)\n",
    "end\n",
    "\n",
    "contact_problem = MortarProblem(\"displacement\", 3)\n",
    "for (elid, (eltype, elset, elcon)) in mesh[\"connectivity\"]\n",
    "    (eltype == :TR3) && (elset == slave_surface) || continue\n",
    "    element = Tri3(reverse(elcon))\n",
    "    update(element, \"geometry\", mesh[\"nodes\"])\n",
    "    element[\"master elements\"] = master_elements\n",
    "    X = element(\"geometry\", 0.0)\n",
    "    x = [X[mod(i, 3)+1][1] for i=1:4]\n",
    "    y = [X[mod(i, 3)+1][2] for i=1:4]\n",
    "    plot(x, y, \"-ro\", alpha=0.5)\n",
    "    calculate_normal_tangential_coordinates!(element, 0.0)\n",
    "    push!(contact_problem, element)\n",
    "end\n",
    "xlim(-0.1, 1.1)\n",
    "ylim(-0.1, 1.1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO: # of field problems: 1\n",
      "INFO: # of boundary problems: 2\n",
      "INFO: Starting iteration 1\n",
      "INFO: Assembling field problems...\n",
      "INFO: Assembling body 1...\n",
      "INFO: Assembly: 10.0 % done. \n",
      "INFO: Assembly: 20.0 % done. \n",
      "INFO: Assembly: 30.0 % done. \n",
      "INFO: Assembly: 40.0 % done. \n",
      "INFO: Assembly: 50.0 % done. \n",
      "INFO: Assembly: 60.0 % done. \n",
      "INFO: Assembly: 70.0 % done. \n",
      "INFO: Assembly: 80.0 % done. \n",
      "INFO: Assembly: 90.0 % done. \n",
      "INFO: Assembly: 100.0 % done. \n",
      "INFO: dim = 807\n",
      "INFO: Assembling boundary problems...\n",
      "INFO: Assembling boundary 1...\n",
      "INFO: Assembly: 10.0 % done. \n",
      "INFO: Assembly: 20.0 % done. \n",
      "INFO: Assembly: 30.0 % done. \n",
      "INFO: Assembly: 40.0 % done. \n",
      "INFO: Assembly: 50.0 % done. \n",
      "INFO: Assembly: 60.0 % done. \n",
      "INFO: Assembly: 70.0 % done. \n",
      "INFO: Assembly: 80.0 % done. \n",
      "INFO: Assembly: 90.0 % done. \n",
      "INFO: Assembly: 100.0 % done. \n",
      "INFO: Assembling boundary 2...\n",
      "INFO: dumping matrices to disk, file = matrices_tie_contact_3d_host_1_iteration_1.jld\n",
      "INFO: Solving system\n",
      "INFO: UMFPACK: solved in 0.23568201065063477 seconds. norm = 1.2500614850006646\n",
      "INFO: timing info for iteration:\n",
      "INFO: boundary assembly       : 3.2558910846710205\n",
      "INFO: field assembly          : 1.247041940689087\n",
      "INFO: dump matrices to disk   : 1.1785790920257568\n",
      "INFO: solve problem           : 0.3804500102996826\n",
      "INFO: update element data     : 0.03557395935058594\n",
      "INFO: non-linear iteration    : 6.097559213638306\n",
      "INFO: solver finished in 6.260515928268433 seconds.\n",
      "INFO: nid near corner = 120\n",
      "INFO: displacement X = [1.0,1.0,1.0], u = [0.027777777777777707,0.027777777777777592,-0.11111111111111081]\n",
      "INFO: displacement X = [1.0,1.0,1.0], u = [0.027777777777777707,0.027777777777777592,-0.11111111111111081]\n",
      "INFO: displacement X = [1.0,1.0,1.0], u = [0.027777777777777707,0.027777777777777592,-0.11111111111111081]\n",
      "INFO: displacement X = [1.0,1.0,1.0], u = [0.027777777777777707,0.027777777777777592,-0.11111111111111081]\n",
      "INFO: displacement X = [1.0,1.0,1.0], u = [0.027777777777777707,0.027777777777777592,-0.11111111111111081]\n",
      "INFO: displacement X = [1.0,1.0,1.0], u = [0.027777777777777707,0.027777777777777592,-0.11111111111111081]\n",
      "INFO: displacement X = [1.0,1.0,1.0], u = [0.027777777777777707,0.027777777777777592,-0.11111111111111081]\n",
      "INFO: displacement X = [1.0,1.0,1.0], u = [0.027777777777777707,0.027777777777777592,-0.11111111111111081]\n",
      "INFO: displacement X = [1.0,1.0,1.0], u = [0.027777777777777707,0.027777777777777592,-0.11111111111111081]\n",
      "INFO: displacement X = [1.0,1.0,1.0], u = [0.027777777777777707,0.027777777777777592,-0.11111111111111081]\n",
      "INFO: displacement X = [1.0,1.0,1.0], u = [0.027777777777777707,0.027777777777777592,-0.11111111111111081]\n",
      "INFO: displacement X = [1.0,1.0,1.0], u = [0.027777777777777707,0.027777777777777592,-0.11111111111111081]\n"
     ]
    }
   ],
   "source": [
    "using JuliaFEM.Core: DirectSolver\n",
    "solver = DirectSolver()\n",
    "solver.name = \"tie_contact_3d\"\n",
    "solver.method = :UMFPACK\n",
    "solver.nonlinear_problem = false\n",
    "solver.max_iterations = 1\n",
    "solver.dump_matrices = true\n",
    "push!(solver, field_problem)\n",
    "push!(solver, boundary_problem)\n",
    "push!(solver, contact_problem)\n",
    "call(solver, 0.0)\n",
    "\n",
    "using JuliaFEM.Test\n",
    "\n",
    "nid = 0\n",
    "for (nid, coords) in mesh[\"nodes\"]\n",
    "    if isapprox(coords, [1.0, 1.0, 1.0])\n",
    "        info(\"nid near corner = $nid\")\n",
    "        break\n",
    "    end\n",
    "end\n",
    "nid\n",
    "\n",
    "known_value = [1/36, 1/36, -1/9]\n",
    "\n",
    "for element in field_problem.elements\n",
    "    i = indexin([nid], get_connectivity(element))[1]\n",
    "    i != 0 || continue\n",
    "    X = element(\"geometry\", 0.0)\n",
    "    u = element(\"displacement\", 0.0)\n",
    "    info(\"displacement X = $(X[i]), u = $(u[i])\")\n",
    "    @test isapprox(u[i], known_value, atol=1.0e-5)\n",
    "end"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO: XDFM: ndim = 807\n"
     ]
    }
   ],
   "source": [
    "xdoc, xmodel = JuliaFEM.Postprocess.xdmf_new_model()\n",
    "coll = JuliaFEM.Postprocess.xdmf_new_temporal_collection(xmodel)\n",
    "grid = JuliaFEM.Postprocess.xdmf_new_grid(coll; time=0.0)\n",
    "\n",
    "Xg = Dict{Int64, Vector{Float64}}()\n",
    "ug = Dict{Int64, Vector{Float64}}()\n",
    "for element in field_problem.elements\n",
    "    conn = get_connectivity(element)\n",
    "    X = element(\"geometry\", 0.0)\n",
    "    u = element(\"displacement\", 0.0)\n",
    "    for (i, c) in enumerate(conn)\n",
    "        Xg[c] = X[i]\n",
    "        ug[c] = u[i]\n",
    "    end\n",
    "end\n",
    "perm = sort(collect(keys(Xg)))\n",
    "nodes = Vector{Float64}[Xg[i] for i in perm]\n",
    "disp = Vector{Float64}[ug[i] for i in perm]\n",
    "elements = []\n",
    "for el in field_problem.elements\n",
    "    isa(el, JuliaFEM.Core.Element{JuliaFEM.Core.Tet4}) || continue\n",
    "    push!(elements, (:Tet4, get_connectivity(el)))\n",
    "end\n",
    "#elements\n",
    "JuliaFEM.Postprocess.xdmf_new_mesh!(grid, nodes, elements)\n",
    "JuliaFEM.Postprocess.xdmf_new_nodal_field!(grid, \"displacement\", disp)\n",
    "JuliaFEM.Postprocess.xdmf_save_model(xdoc, \"/tmp/blocks_tet4.xmf\");"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<img src=\"http://results.juliafem.org/divided-block-tet4/2015-12-17-tet4-results.png\"\n",
    "         style=\"width:80%; height:auto; vertical-align:middle;\">"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Several contacts with shared nodes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO: Found 12 element sets: BLOCK4_TO_BLOCK3, SYM12, SYM23, BLOCK4_TO_BLOCK2, BLOCK3_TO_BLOCK4, BLOCK1_TO_BLOCK3, SYM13, LOAD, BLOCK1_TO_BLOCK2, BLOCK2_TO_BLOCK4, BLOCK2_TO_BLOCK1, BLOCK3_TO_BLOCK1\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "Dict{ASCIIString,Any} with 2 entries:\n",
       "  \"nodes\"        => Dict(306=>[0.0,0.8469606634303125,0.4191161978569679],29=>[…\n",
       "  \"connectivity\" => Dict(2843=>(:TE4,:OTHER,[631,574,595,513]),1316=>(:TR3,:SYM…"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "using JuliaFEM\n",
    "using JuliaFEM.Preprocess: parse_aster_med_file\n",
    "using JuliaFEM.Core: LinearElasticityProblem, DirichletProblem, get_connectivity, Tri3, Tet4, LinearSolver, update\n",
    "mesh = parse_aster_med_file(Pkg.dir(\"JuliaFEM\")*\"/geometry/unit_box/SUPERBLOCK.med\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO: created 2878 elements.\n",
      "INFO: created 403 boundary elements.\n"
     ]
    }
   ],
   "source": [
    "# interior elements are of type HE8\n",
    "field_problem = LinearElasticityProblem()\n",
    "\n",
    "for (elid, (eltype, elset, elcon)) in mesh[\"connectivity\"]\n",
    "    eltype == :TE4 || continue\n",
    "    element = Tet4(elcon)\n",
    "    update(element, \"geometry\", mesh[\"nodes\"])\n",
    "    element[\"youngs modulus\"] = 900.0\n",
    "    element[\"poissons ratio\"] = 0.25\n",
    "    #info(\"lower: add element with connectivity $elcon\")\n",
    "    push!(field_problem, element)\n",
    "end\n",
    "\n",
    "# Neumann boundary condition, traction force -100 on Z direction for element set LOAD\n",
    "for (elid, (eltype, elset, elcon)) in mesh[\"connectivity\"]\n",
    "    (eltype == :TR3) && (elset == :LOAD) || continue\n",
    "    element = Tri3(elcon)\n",
    "    update(element, \"geometry\", mesh[\"nodes\"])\n",
    "    element[\"displacement traction force 3\"] = -100.0\n",
    "    push!(field_problem, element)\n",
    "end\n",
    "info(\"created $(length(field_problem.elements)) elements.\")\n",
    "\n",
    "# boundary conditions\n",
    "boundary_problem = DirichletProblem(\"displacement\", 3)\n",
    "\n",
    "for (elid, (eltype, elset, elcon)) in mesh[\"connectivity\"]\n",
    "    (eltype == :TR3) && (elset in [:SYM23, :SYM12, :SYM13]) || continue\n",
    "    element = Tri3(elcon)\n",
    "    update(element, \"geometry\", mesh[\"nodes\"])\n",
    "    if elset == :SYM23\n",
    "        element[\"displacement 1\"] = 0.0\n",
    "    elseif elset == :SYM12\n",
    "        element[\"displacement 3\"] = 0.0\n",
    "    elseif elset == :SYM13\n",
    "        element[\"displacement 2\"] = 0.0\n",
    "    end\n",
    "    push!(boundary_problem, element)\n",
    "end\n",
    "info(\"created $(length(boundary_problem.elements)) boundary elements.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Contact pairs: BLOCK1 <-> BLOCK3, BLOCK1 <-> BLOCK2, BLOCK2 <-> BLOCK4, BLOCK3 <-> BLOCK4"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "using JuliaFEM.Core: Element, MortarProblem, calculate_normal_tangential_coordinates!\n",
    "\n",
    "function create_contact(master_surface, slave_surface)\n",
    "\n",
    "    master_elements = JuliaFEM.Core.Element[]\n",
    "    for (elid, (eltype, elset, elcon)) in mesh[\"connectivity\"]\n",
    "        (eltype == :TR3) && (elset == master_surface) || continue\n",
    "        element = Tri3(elcon)\n",
    "        update(element, \"geometry\", mesh[\"nodes\"])\n",
    "        push!(master_elements, element)\n",
    "    end\n",
    "\n",
    "    contact_problem = MortarProblem(\"displacement\", 3)\n",
    "    for (elid, (eltype, elset, elcon)) in mesh[\"connectivity\"]\n",
    "        (eltype == :TR3) && (elset == slave_surface) || continue\n",
    "        element = Tri3(reverse(elcon))\n",
    "        update(element, \"geometry\", mesh[\"nodes\"])\n",
    "        element[\"master elements\"] = master_elements\n",
    "        calculate_normal_tangential_coordinates!(element, 0.0)\n",
    "        push!(contact_problem, element)\n",
    "    end\n",
    "\n",
    "    return contact_problem\n",
    "end\n",
    "\n",
    "tie1 = create_contact(:BLOCK1_TO_BLOCK3, :BLOCK3_TO_BLOCK1)\n",
    "tie2 = create_contact(:BLOCK1_TO_BLOCK2, :BLOCK2_TO_BLOCK1)\n",
    "tie3 = create_contact(:BLOCK2_TO_BLOCK4, :BLOCK4_TO_BLOCK2)\n",
    "tie4 = create_contact(:BLOCK3_TO_BLOCK4, :BLOCK4_TO_BLOCK3);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO: # of field problems: 1\n",
      "INFO: # of boundary problems: 5\n",
      "INFO: Starting iteration 1\n",
      "INFO: Assembling field problems...\n",
      "INFO: Assembling body 1...\n",
      "INFO: Assembly: 10.0 % done. \n",
      "INFO: Assembly: 20.0 % done. \n",
      "INFO: Assembly: 30.0 % done. \n",
      "INFO: Assembly: 40.0 % done. \n",
      "INFO: Assembly: 50.0 % done. \n",
      "INFO: Assembly: 60.0 % done. \n",
      "INFO: Assembly: 70.0 % done. \n",
      "INFO: Assembly: 80.0 % done. \n",
      "INFO: Assembly: 90.0 % done. \n",
      "INFO: Assembly: 100.0 % done. \n",
      "INFO: dim = 2562\n",
      "INFO: Assembling boundary problems...\n",
      "INFO: Assembling boundary 1...\n",
      "INFO: Assembly: 10.0 % done. \n",
      "INFO: Assembly: 20.0 % done. \n",
      "INFO: Assembly: 30.0 % done. \n",
      "INFO: Assembly: 40.0 % done. \n",
      "INFO: Assembly: 50.0 % done. \n",
      "INFO: Assembly: 60.0 % done. \n",
      "INFO: Assembly: 70.0 % done. \n",
      "INFO: Assembly: 80.0 % done. \n",
      "INFO: Assembly: 90.0 % done. \n",
      "INFO: Assembly: 100.0 % done. \n",
      "INFO: Assembling boundary 2...\n",
      "INFO: Assembling boundary 3...\n",
      "INFO: Assembling boundary 4...\n",
      "INFO: Assembling boundary 5...\n",
      "INFO: dumping matrices to disk, file = matrices_tie_contact_3d_host_1_iteration_1.jld\n",
      "INFO: Solving system\n",
      "INFO: UMFPACK: solved in 0.2858870029449463 seconds. norm = 1.9710688787586395\n",
      "INFO: timing info for iteration:\n",
      "INFO: boundary assembly       : 10.795902967453003\n",
      "INFO: field assembly          : 1.356456995010376\n",
      "INFO: dump matrices to disk   : 1.1161930561065674\n",
      "INFO: solve problem           : 0.4241180419921875\n",
      "INFO: update element data     : 0.05763602256774902\n",
      "INFO: non-linear iteration    : 13.75032901763916\n",
      "INFO: solver finished in 13.92406702041626 seconds.\n",
      "INFO: nid near corner = 502\n",
      "INFO: displacement X = [1.0,1.0,1.0], u = [0.027777977912483327,0.02776944079303928,-0.11111675469425412]\n",
      "INFO: displacement X = [1.0,1.0,1.0], u = [0.027777977912483327,0.02776944079303928,-0.11111675469425412]\n",
      "INFO: displacement X = [1.0,1.0,1.0], u = [0.027777977912483327,0.02776944079303928,-0.11111675469425412]\n",
      "INFO: displacement X = [1.0,1.0,1.0], u = [0.027777977912483327,0.02776944079303928,-0.11111675469425412]\n",
      "INFO: displacement X = [1.0,1.0,1.0], u = [0.027777977912483327,0.02776944079303928,-0.11111675469425412]\n",
      "INFO: displacement X = [1.0,1.0,1.0], u = [0.027777977912483327,0.02776944079303928,-0.11111675469425412]\n",
      "INFO: displacement X = [1.0,1.0,1.0], u = [0.027777977912483327,0.02776944079303928,-0.11111675469425412]\n",
      "INFO: displacement X = [1.0,1.0,1.0], u = [0.027777977912483327,0.02776944079303928,-0.11111675469425412]\n"
     ]
    }
   ],
   "source": [
    "using JuliaFEM.Core: DirectSolver\n",
    "solver = DirectSolver()\n",
    "solver.name = \"tie_contact_3d\"\n",
    "solver.method = :UMFPACK\n",
    "solver.nonlinear_problem = false\n",
    "solver.max_iterations = 1\n",
    "solver.dump_matrices = true\n",
    "push!(solver, field_problem)\n",
    "push!(solver, boundary_problem)\n",
    "push!(solver, tie1, tie2, tie3, tie4)\n",
    "call(solver, 0.0)\n",
    "\n",
    "using JuliaFEM.Test\n",
    "\n",
    "nid = 0\n",
    "for (nid, coords) in mesh[\"nodes\"]\n",
    "    if isapprox(coords, [1.0, 1.0, 1.0])\n",
    "        info(\"nid near corner = $nid\")\n",
    "        break\n",
    "    end\n",
    "end\n",
    "nid\n",
    "\n",
    "known_value = [1/36, 1/36, -1/9]\n",
    "\n",
    "for element in field_problem.elements\n",
    "    i = indexin([nid], get_connectivity(element))[1]\n",
    "    i != 0 || continue\n",
    "    X = element(\"geometry\", 0.0)\n",
    "    u = element(\"displacement\", 0.0)\n",
    "    info(\"displacement X = $(X[i]), u = $(u[i])\")\n",
    "    @test isapprox(u[i], known_value, atol=1.0e-3)\n",
    "end"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "INFO: XDFM: ndim = 2562\n"
     ]
    }
   ],
   "source": [
    "xdoc, xmodel = JuliaFEM.Postprocess.xdmf_new_model()\n",
    "coll = JuliaFEM.Postprocess.xdmf_new_temporal_collection(xmodel)\n",
    "grid = JuliaFEM.Postprocess.xdmf_new_grid(coll; time=0.0)\n",
    "\n",
    "Xg = Dict{Int64, Vector{Float64}}()\n",
    "ug = Dict{Int64, Vector{Float64}}()\n",
    "for element in field_problem.elements\n",
    "    conn = get_connectivity(element)\n",
    "    X = element(\"geometry\", 0.0)\n",
    "    u = element(\"displacement\", 0.0)\n",
    "    for (i, c) in enumerate(conn)\n",
    "        Xg[c] = X[i]\n",
    "        ug[c] = u[i]\n",
    "    end\n",
    "end\n",
    "perm = sort(collect(keys(Xg)))\n",
    "nodes = Vector{Float64}[Xg[i] for i in perm]\n",
    "disp = Vector{Float64}[ug[i] for i in perm]\n",
    "elements = []\n",
    "for el in field_problem.elements\n",
    "    isa(el, JuliaFEM.Core.Element{JuliaFEM.Core.Tet4}) || continue\n",
    "    push!(elements, (:Tet4, get_connectivity(el)))\n",
    "end\n",
    "#elements\n",
    "JuliaFEM.Postprocess.xdmf_new_mesh!(grid, nodes, elements)\n",
    "JuliaFEM.Postprocess.xdmf_new_nodal_field!(grid, \"displacement\", disp)\n",
    "JuliaFEM.Postprocess.xdmf_save_model(xdoc, \"/tmp/superblock.xmf\");"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<img src=\"http://results.juliafem.org/2015-12-17-superblock.png\"\n",
    "         style=\"width:80%; height:auto; vertical-align:middle;\">"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Julia 0.4.2",
   "language": "julia",
   "name": "julia-0.4"
  },
  "language_info": {
   "file_extension": ".jl",
   "mimetype": "application/julia",
   "name": "julia",
   "version": "0.4.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
