{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    "This notebook sets up and runs a set of benchmarks to compare\n",
    "different numerical discretizations of the SWEs\n",
    "\n",
    "Copyright (C) 2016, 2017, 2018  SINTEF ICT\n",
    "\n",
    "This program is free software: you can redistribute it and/or modify\n",
    "it under the terms of the GNU General Public License as published by\n",
    "the Free Software Foundation, either version 3 of the License, or\n",
    "(at your option) any later version.\n",
    "\n",
    "This program is distributed in the hope that it will be useful,\n",
    "but WITHOUT ANY WARRANTY; without even the implied warranty of\n",
    "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n",
    "GNU General Public License for more details.\n",
    "\n",
    "You should have received a copy of the GNU General Public License\n",
    "along with this program.  If not, see <http://www.gnu.org/licenses/>.\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Lets have matplotlib \"inline\"\n",
    "%matplotlib inline\n",
    "\n",
    "#Python 2.7 compatibility\n",
    "from __future__ import print_function\n",
    "\n",
    "#Import packages we need\n",
    "import numpy as np\n",
    "from matplotlib import animation, rc\n",
    "from matplotlib import pyplot as plt\n",
    "from mpl_toolkits.axes_grid1 import make_axes_locatable\n",
    "#import mpld3\n",
    "\n",
    "import subprocess\n",
    "import socket\n",
    "import time\n",
    "import os\n",
    "import gc\n",
    "import datetime\n",
    "\n",
    "import pycuda.driver as cuda\n",
    "\n",
    "try:\n",
    "    from StringIO import StringIO\n",
    "except ImportError:\n",
    "    from io import StringIO\n",
    "\n",
    "#Finally, import our simulator\n",
    "from GPUSimulators import Common, LxF, FORCE, HLL, HLL2, KP07, KP07_dimsplit, WAF, IPythonMagic"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Console logger using level INFO\n",
      "File logger using level DEBUG to output.log\n",
      "Python version 3.6.5 |Anaconda custom (64-bit)| (default, Mar 29 2018, 13:32:41) [MSC v.1900 64 bit (AMD64)]\n",
      "Registering cuda_context in user workspace\n",
      "PyCUDA version 2017.1.1\n",
      "CUDA version (9, 1, 0)\n",
      "Driver version 9010\n",
      "Using 'GeForce 840M' GPU\n",
      "Created context handle <311559736768>\n",
      "Using CUDA cache dir c:\\Users\\anbro\\Documents\\projects\\GPUSimulators\\GPUSimulators\\cuda_cache\n",
      "Autotuning enabled. It may take several minutes to run the code the first time: have patience\n"
     ]
    }
   ],
   "source": [
    "%setup_logging\n",
    "%cuda_context_handler cuda_context"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Misc plotting setup\n",
    "def setBwStyles(ax):\n",
    "    from cycler import cycler\n",
    "\n",
    "    ax.set_prop_cycle( cycler('marker', ['.', 'x', 4, '+', '*', '1', 5]) +\n",
    "                       cycler('linestyle', ['-.', '--', ':', '-.', '--', ':', '-.']) +\n",
    "                       #cycler('markersize', [5, 5, 5, 5, 5, 5]) +\n",
    "                       cycler('color', ['k', 'k', 'k', 'k', 'k', 'k', 'k']) )    \n",
    "\n",
    "#Set large figure sizes\n",
    "plt.rcParams['figure.figsize'] = [12, 8]\n",
    "plt.rcParams['figure.dpi'] = 100\n",
    "plt.rcParams['animation.html'] = 'html5'\n",
    "#plt.rcParams['legend.markerscale'] = 1.0\n",
    "#plt.rcParams['lines.markersize'] = 6\n",
    "plt.rcParams['lines.markeredgewidth'] = 1.5\n",
    "#plt.rcParams['savefig.dpi'] = 400"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "def save_figure(fig, stem):\n",
    "    if (not os.path.isdir(\"figures\")):\n",
    "        os.mkdir(\"figures\")\n",
    "    \n",
    "    fig_filename = os.path.join(\"figures\", \"convergence_shock1d_\" + stem + \".pdf\")\n",
    "    \n",
    "    metadata = {\n",
    "        'created': time.strftime(\"%Y_%m_%d-%H_%M_%S\"),\n",
    "        'hostname': socket.gethostname()\n",
    "    }\n",
    "        \n",
    "    legend = fig.gca().legend_\n",
    "    if (legend != None):\n",
    "        fig.savefig(fig_filename, dpi=300,format='pdf',\n",
    "                transparent=True, pad_inches=0.0, frameon=None, \n",
    "                metadata=metadata, \n",
    "                bbox_extra_artists=(legend, ), bbox_inches='tight')\n",
    "    else:\n",
    "        fig.savefig(fig_filename, dpi=300,format='pdf',\n",
    "                transparent=True, pad_inches=0.0, frameon=None, \n",
    "                metadata=metadata)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "def gen_reference(nx):\n",
    "    csv_filename = os.path.abspath(os.path.join(\"reference\", \"swashes_1_nx=\" + str(nx) + \".csv\"))\n",
    "\n",
    "    #If we do not have the data, generate it    \n",
    "    if (not os.path.isfile(csv_filename)):\n",
    "        print(\"Generating new reference!\")\n",
    "        swashes_path = r'C:\\Users\\anbro\\Documents\\programs\\SWASHES-1.03.00_win\\bin\\swashes_win.exe'\n",
    "\n",
    "        swashes_args = [\\\n",
    "                        '1', # 1D problems \\\n",
    "                        '3', # Dam breaks \\\n",
    "                        '1', # Domain 1 \\\n",
    "                        '1', # Wet domain no friction\n",
    "                        str(nx) #Number of cells X\n",
    "                       ]\n",
    "\n",
    "        with open(csv_filename, 'w') as csv_file:\n",
    "            p = subprocess.check_call([swashes_path] + swashes_args, stdout=csv_file)\n",
    "\n",
    "    reference = np.genfromtxt(csv_filename, comments='#', delimiter='\\t', skip_header=0, usecols=(0, 1, 2))\n",
    "    x, h, u = reference[:, 0], reference[:, 1], reference[:, 2]\n",
    "    return x, h, h*u"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "def downsample(highres_solution, factor):\n",
    "    if (len(highres_solution.shape) == 1):\n",
    "        highres_solution = highres_solution.reshape((1, highres_solution.size))\n",
    "\n",
    "    assert(highres_solution.shape[1] % factor == 0)\n",
    "    ny = highres_solution.shape[0] \n",
    "    nx = highres_solution.shape[1] / factor\n",
    "\n",
    "    if (factor == 1):\n",
    "        return highres_solution\n",
    "    else:\n",
    "        \n",
    "        return highres_solution.reshape([int(ny), int(1), int(nx), int(factor)]).mean(3).mean(1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "def wall_boundary_conditions(data, num_ghost_cells):\n",
    "    data[0:num_ghost_cells,:] = data[2*num_ghost_cells-1:num_ghost_cells-1:-1,:]\n",
    "    data[-num_ghost_cells:,:] = data[-num_ghost_cells-1:-2*num_ghost_cells-1:-1,:]\n",
    "    data[:,0:num_ghost_cells] = data[:,2*num_ghost_cells-1:num_ghost_cells-1:-1]\n",
    "    data[:,-num_ghost_cells:] = data[:,-num_ghost_cells-1:-2*num_ghost_cells-1:-1]\n",
    "    return data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 25852 characters]\n",
      "text/plain": [
       "<Figure size 1200x800 with 6 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0.1, 1.0, 0.1917647230683736]\n"
     ]
    }
   ],
   "source": [
    "def gen_test_data(nx, ref_nx, g, num_ghost_cells):\n",
    "    assert(num_ghost_cells >= 1)\n",
    "    ref_ny = num_ghost_cells\n",
    "    ny = ref_ny\n",
    "    \n",
    "    dx = 10.0 / float(nx)\n",
    "    dy = 1.0\n",
    "\n",
    "    h_highres = np.zeros((ref_ny, ref_nx))\n",
    "    h = np.zeros((ny+2*num_ghost_cells, nx+2*num_ghost_cells), dtype=np.float32); \n",
    "    hu = np.zeros((ny+2*num_ghost_cells, nx+2*num_ghost_cells), dtype=np.float32);\n",
    "    hv = np.zeros((ny+2*num_ghost_cells, nx+2*num_ghost_cells), dtype=np.float32);\n",
    "\n",
    "    #Create dam break\n",
    "    x = np.linspace(0, 10, ref_nx)\n",
    "    \n",
    "    h_highres = np.where(x < 5, 0.005, 0.001);    \n",
    "    h[num_ghost_cells:-num_ghost_cells, num_ghost_cells:-num_ghost_cells] = downsample(h_highres, ref_nx/nx)\n",
    "    h = wall_boundary_conditions(h, num_ghost_cells);\n",
    "    \n",
    "    max_h_estimate = 0.005\n",
    "    max_u_estimate = 0.3\n",
    "    dt = min(dx, dy) / (max_u_estimate + np.sqrt(g*max_h_estimate))\n",
    "    \n",
    "    return h, hu, hv, dx, dy, dt\n",
    "\n",
    "\n",
    "h, hu, hv, dx, dy, dt = gen_test_data(nx=100, ref_nx=1000, g=9.81, num_ghost_cells=2)\n",
    "\n",
    "plt.figure()\n",
    "ax=plt.subplot(1,3,1)\n",
    "im=plt.imshow(h, extent=[0, 100, 0, 100])\n",
    "divider = make_axes_locatable(ax)\n",
    "cax = divider.append_axes(\"right\", size=\"5%\", pad=0.05)\n",
    "plt.colorbar(im, cax=cax)\n",
    "\n",
    "ax=plt.subplot(1,3,2)\n",
    "im=plt.imshow(hu, extent=[0, 100, 0, 100])\n",
    "divider = make_axes_locatable(ax)\n",
    "cax = divider.append_axes(\"right\", size=\"5%\", pad=0.05)\n",
    "plt.colorbar(im, cax=cax)\n",
    "\n",
    "ax=plt.subplot(1,3,3)\n",
    "im=plt.imshow(hv, extent=[0, 100, 0, 100])\n",
    "divider = make_axes_locatable(ax)\n",
    "cax = divider.append_axes(\"right\", size=\"5%\", pad=0.05)\n",
    "plt.colorbar(im, cax=cax)\n",
    "\n",
    "plt.show()\n",
    "\n",
    "print([dx, dy, dt])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "def gen_filename(simulator, nx):\n",
    "    return os.path.abspath(os.path.join(\"data\", \"shock1d\", str(simulator.__name__) + \"_\" + str(nx) + \".npz\"))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "def sanity_check(variable, variable_name):\n",
    "    maxval = np.amax(variable)\n",
    "    minval = np.amin(variable)\n",
    "    assert np.isnan(maxval) == False and np.isnan(minval) == False, variable_name + \" contains NaN values\"\n",
    "\n",
    "def run_benchmark(datafilename, simulator, courant_number, nx, ref_nx, ghost_cells, g=9.81, force_rerun=False, transpose=False):\n",
    "    datafilename = gen_filename(simulator, nx)\n",
    "\n",
    "    if (datafilename and os.path.isfile(datafilename) and force_rerun == False):\n",
    "        print(\"WARNING: Existing simulation exists, skipping simulation\")\n",
    "        return [0, 0, 0]\n",
    "    else:\n",
    "        h0, hu0, hv0, dx, dy, dt = gen_test_data(nx, ref_nx, g, ghost_cells)\n",
    "        ny = ghost_cells\n",
    "        dt = dt * courant_number\n",
    "\n",
    "        #Initialize simulator\n",
    "        with Common.Timer(simulator.__name__ + \"_\" + str(nx)) as timer:\n",
    "            if (transpose):\n",
    "                h0 = np.ascontiguousarray(np.transpose(h0))\n",
    "                hu0, hv0 = np.ascontiguousarray(np.transpose(hv0)), np.ascontiguousarray(np.transpose(hu0))\n",
    "                dx, dy = dy, dx\n",
    "                nx, ny = ny, nx\n",
    "                \n",
    "            sim = simulator(cuda_context, \\\n",
    "                            h0, hu0, hv0, \\\n",
    "                            nx, ny, \\\n",
    "                            dx, dy, dt, \\\n",
    "                            g)\n",
    "\n",
    "            t, nt = sim.simulate(6.0)\n",
    "            h, hu, hv = sim.download()\n",
    "\n",
    "            if (transpose):\n",
    "                h = np.transpose(h)\n",
    "                hu, hv = np.ascontiguousarray(np.transpose(hv)), np.ascontiguousarray(np.transpose(hu))\n",
    "\n",
    "            sanity_check(h, \"h\")\n",
    "            sanity_check(hu, \"hu\")\n",
    "            sanity_check(hv, \"hv\")\n",
    "\n",
    "            if (datafilename):\n",
    "                dirname = os.path.dirname(datafilename)\n",
    "                if (dirname and not os.path.isdir(dirname)):\n",
    "                    os.makedirs(dirname)\n",
    "                np.savez_compressed(datafilename, h=h, hu=hu, hv=hv)\n",
    "        \n",
    "    gc.collect() # Force run garbage collection to free up memory\n",
    "    \n",
    "    return [timer.secs, nt, dt]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "LxF [1x16] simulated 6.000000 seconds to 6.000000 with 6 steps (Euler)\n",
      "FORCE [1x16] simulated 6.000000 seconds to 6.000000 with 6 steps (Euler)\n",
      "HLL [1x16] simulated 6.000000 seconds to 6.000000 with 6 steps (Euler)\n",
      "HLL2 [2x16] simulated 6.000000 seconds to 6.000000 with 6 steps (dimsplit)\n",
      "KP07 [2x16] simulated 6.000000 seconds to 6.000000 with 6 steps (RK2)\n",
      "KP07_dimsplit [2x16] simulated 6.000000 seconds to 6.000000 with 6 steps (dimsplit)\n",
      "WAF [2x16] simulated 6.000000 seconds to 6.000000 with 6 steps (dimsplit)\n",
      "LxF [1x32] simulated 6.000000 seconds to 6.000000 with 11 steps (Euler)\n",
      "LxF [1x64] simulated 6.000000 seconds to 6.000000 with 22 steps (Euler)\n",
      "LxF [1x128] simulated 6.000000 seconds to 6.000000 with 43 steps (Euler)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Completed warmup in 0.41629648208618164 s\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "LxF [1x256] simulated 6.000000 seconds to 6.000000 with 85 steps (Euler)\n",
      "LxF [1x512] simulated 6.000000 seconds to 6.000000 with 169 steps (Euler)\n",
      "LxF [1x1024] simulated 6.000000 seconds to 6.000000 with 338 steps (Euler)\n",
      "LxF [1x2048] simulated 6.000000 seconds to 6.000000 with 675 steps (Euler)\n",
      "LxF [1x4096] simulated 6.000000 seconds to 6.000000 with 1350 steps (Euler)\n",
      "LxF [1x16384] simulated 6.000000 seconds to 6.000000 with 10793 steps (Euler)\n",
      "FORCE [1x32] simulated 6.000000 seconds to 6.000000 with 11 steps (Euler)\n",
      "FORCE [1x64] simulated 6.000000 seconds to 6.000000 with 22 steps (Euler)\n",
      "FORCE [1x128] simulated 6.000000 seconds to 6.000000 with 43 steps (Euler)\n",
      "FORCE [1x256] simulated 6.000000 seconds to 6.000000 with 85 steps (Euler)\n",
      "FORCE [1x512] simulated 6.000000 seconds to 6.000000 with 169 steps (Euler)\n",
      "FORCE [1x1024] simulated 6.000000 seconds to 6.000000 with 338 steps (Euler)\n",
      "FORCE [1x2048] simulated 6.000000 seconds to 6.000000 with 675 steps (Euler)\n",
      "FORCE [1x4096] simulated 6.000000 seconds to 6.000000 with 1350 steps (Euler)\n",
      "FORCE [1x16384] simulated 6.000000 seconds to 6.000000 with 10793 steps (Euler)\n",
      "HLL [1x32] simulated 6.000000 seconds to 6.000000 with 11 steps (Euler)\n",
      "HLL [1x64] simulated 6.000000 seconds to 6.000000 with 22 steps (Euler)\n",
      "HLL [1x128] simulated 6.000000 seconds to 6.000000 with 43 steps (Euler)\n",
      "HLL [1x256] simulated 6.000000 seconds to 6.000000 with 85 steps (Euler)\n",
      "HLL [1x512] simulated 6.000000 seconds to 6.000000 with 169 steps (Euler)\n",
      "HLL [1x1024] simulated 6.000000 seconds to 6.000000 with 338 steps (Euler)\n",
      "HLL [1x2048] simulated 6.000000 seconds to 6.000000 with 675 steps (Euler)\n",
      "HLL [1x4096] simulated 6.000000 seconds to 6.000000 with 1350 steps (Euler)\n",
      "HLL [1x16384] simulated 6.000000 seconds to 6.000000 with 10793 steps (Euler)\n",
      "HLL2 [2x32] simulated 6.000000 seconds to 6.000000 with 12 steps (dimsplit)\n",
      "HLL2 [2x64] simulated 6.000000 seconds to 6.000000 with 22 steps (dimsplit)\n",
      "HLL2 [2x128] simulated 6.000000 seconds to 6.000000 with 44 steps (dimsplit)\n",
      "HLL2 [2x256] simulated 6.000000 seconds to 6.000000 with 86 steps (dimsplit)\n",
      "HLL2 [2x512] simulated 6.000000 seconds to 6.000000 with 170 steps (dimsplit)\n",
      "HLL2 [2x1024] simulated 6.000000 seconds to 6.000000 with 338 steps (dimsplit)\n",
      "HLL2 [2x2048] simulated 6.000000 seconds to 6.000000 with 676 steps (dimsplit)\n",
      "HLL2 [2x4096] simulated 6.000000 seconds to 6.000000 with 1350 steps (dimsplit)\n",
      "HLL2 [2x16384] simulated 6.000000 seconds to 6.000000 with 10794 steps (dimsplit)\n",
      "KP07 [2x32] simulated 6.000000 seconds to 6.000000 with 11 steps (RK2)\n",
      "KP07 [2x64] simulated 6.000000 seconds to 6.000000 with 22 steps (RK2)\n",
      "KP07 [2x128] simulated 6.000000 seconds to 6.000000 with 43 steps (RK2)\n",
      "KP07 [2x256] simulated 6.000000 seconds to 6.000000 with 85 steps (RK2)\n",
      "KP07 [2x512] simulated 6.000000 seconds to 6.000000 with 169 steps (RK2)\n",
      "KP07 [2x1024] simulated 6.000000 seconds to 6.000000 with 338 steps (RK2)\n",
      "KP07 [2x2048] simulated 6.000000 seconds to 6.000000 with 675 steps (RK2)\n",
      "KP07 [2x4096] simulated 6.000000 seconds to 6.000000 with 1350 steps (RK2)\n",
      "KP07 [2x16384] simulated 6.000000 seconds to 6.000000 with 10793 steps (RK2)\n",
      "KP07_dimsplit [2x32] simulated 6.000000 seconds to 6.000000 with 12 steps (dimsplit)\n",
      "KP07_dimsplit [2x64] simulated 6.000000 seconds to 6.000000 with 22 steps (dimsplit)\n",
      "KP07_dimsplit [2x128] simulated 6.000000 seconds to 6.000000 with 44 steps (dimsplit)\n",
      "KP07_dimsplit [2x256] simulated 6.000000 seconds to 6.000000 with 86 steps (dimsplit)\n",
      "KP07_dimsplit [2x512] simulated 6.000000 seconds to 6.000000 with 170 steps (dimsplit)\n",
      "KP07_dimsplit [2x1024] simulated 6.000000 seconds to 6.000000 with 338 steps (dimsplit)\n",
      "KP07_dimsplit [2x2048] simulated 6.000000 seconds to 6.000000 with 676 steps (dimsplit)\n",
      "KP07_dimsplit [2x4096] simulated 6.000000 seconds to 6.000000 with 1350 steps (dimsplit)\n",
      "KP07_dimsplit [2x16384] simulated 6.000000 seconds to 6.000000 with 10794 steps (dimsplit)\n",
      "WAF [2x32] simulated 6.000000 seconds to 6.000000 with 12 steps (dimsplit)\n",
      "WAF [2x64] simulated 6.000000 seconds to 6.000000 with 22 steps (dimsplit)\n",
      "WAF [2x128] simulated 6.000000 seconds to 6.000000 with 44 steps (dimsplit)\n",
      "WAF [2x256] simulated 6.000000 seconds to 6.000000 with 86 steps (dimsplit)\n",
      "WAF [2x512] simulated 6.000000 seconds to 6.000000 with 170 steps (dimsplit)\n",
      "WAF [2x1024] simulated 6.000000 seconds to 6.000000 with 338 steps (dimsplit)\n",
      "WAF [2x2048] simulated 6.000000 seconds to 6.000000 with 676 steps (dimsplit)\n",
      "WAF [2x4096] simulated 6.000000 seconds to 6.000000 with 1350 steps (dimsplit)\n",
      "WAF [2x16384] simulated 6.000000 seconds to 6.000000 with 10794 steps (dimsplit)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Completed simulation in 86.85749387741089 s\n"
     ]
    }
   ],
   "source": [
    "reference_nx = 16384\n",
    "domain_sizes = [32, 64, 128, 256, 512, 1024, 2048, 4096]\n",
    "simulators = [LxF.LxF, FORCE.FORCE, HLL.HLL, HLL2.HLL2, KP07.KP07, KP07_dimsplit.KP07_dimsplit, WAF.WAF]\n",
    "simulator_ghost_cells = [1, 1, 1, 2, 2, 2, 2]\n",
    "simulator_reference = [LxF.LxF, FORCE.FORCE, HLL.HLL, HLL2.HLL2, KP07.KP07, KP07_dimsplit.KP07_dimsplit, WAF.WAF]\n",
    "simulator_courant_numbers = [0.95, 0.95, 0.95, 0.95, 0.95, 0.95, 0.95]\n",
    "force_rerun=True\n",
    "transpose=True\n",
    "\n",
    "#simulators = [HLL2.HLL2, WAF.WAF]\n",
    "#simulator_ghost_cells = [2, 2]\n",
    "#simulator_reference = [HLL2.HLL2, WAF.WAF]\n",
    "#simulator_courant_numbers = [0.95, 0.95]\n",
    "#force_rerun=True\n",
    "\n",
    "#Warmup to compile kernels\n",
    "with Common.Timer(\"warmup\") as timer:\n",
    "    for i in range(len(simulators)):\n",
    "        run_benchmark(\"warmup\", \n",
    "                      simulators[i], \n",
    "                      simulator_courant_numbers[i], \n",
    "                      16, 16, \n",
    "                      simulator_ghost_cells[i], \n",
    "                      force_rerun=force_rerun,\n",
    "                      transpose=transpose)\n",
    "print(\"Completed warmup in {:} s\".format(timer.secs))\n",
    "        \n",
    "with Common.Timer(\"simulation\") as timer:\n",
    "    for i in range(len(simulators)):        \n",
    "        for j, nx in enumerate(domain_sizes):\n",
    "            datafilename = gen_filename(simulators[i], nx)\n",
    "            run_benchmark(datafilename, \\\n",
    "                          simulators[i], \\\n",
    "                          simulator_courant_numbers[i], \\\n",
    "                          nx, reference_nx, \\\n",
    "                          simulator_ghost_cells[i], \\\n",
    "                          force_rerun=force_rerun,\n",
    "                          transpose=transpose)\n",
    "            gc.collect()\n",
    "            \n",
    "        # Run reference with a low CFL-number\n",
    "        datafilename = gen_filename(simulators[i], reference_nx)\n",
    "        run_benchmark(datafilename, \n",
    "                      simulators[i], \n",
    "                      simulator_courant_numbers[i] * 0.5, \n",
    "                      reference_nx, reference_nx, \n",
    "                      simulator_ghost_cells[i], \n",
    "                      force_rerun=force_rerun,\n",
    "                      transpose=transpose)\n",
    "print(\"Completed simulation in {:} s\".format(timer.secs))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "c:\\Users\\anbro\\AppData\\Local\\Continuum\\anaconda3\\lib\\site-packages\\matplotlib\\backends\\backend_pdf.py:1579: UserWarning: Unknown infodict keyword: created\n",
      "  warnings.warn('Unknown infodict keyword: %s' % k)\n",
      "c:\\Users\\anbro\\AppData\\Local\\Continuum\\anaconda3\\lib\\site-packages\\matplotlib\\backends\\backend_pdf.py:1579: UserWarning: Unknown infodict keyword: hostname\n",
      "  warnings.warn('Unknown infodict keyword: %s' % k)\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 110692 characters]\n",
      "text/plain": [
       "<Figure size 1200x800 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "use_analytic = False\n",
    "conservation = np.zeros((len(simulators), len(domain_sizes)))\n",
    "error = np.zeros((len(simulators), len(domain_sizes)))\n",
    "\n",
    "for i, simulator in enumerate(simulators):\n",
    "    if (use_analytic):\n",
    "        #Read the reference solution\n",
    "        _, h_ref, _ = gen_reference(reference_nx)\n",
    "    else:\n",
    "        #Read the reference solution\n",
    "        datafilename = gen_filename(simulator, reference_nx)\n",
    "        with np.load(datafilename) as data:\n",
    "            h_ref = data['h']\n",
    "        \n",
    "    \n",
    "    #Compute conservation and error for subsequent resolutions\n",
    "    for j, nx in enumerate(domain_sizes):\n",
    "        #Read current resolution\n",
    "        datafilename = gen_filename(simulator, nx)\n",
    "        with np.load(datafilename) as data:\n",
    "            h = data['h']\n",
    "        \n",
    "        #Downsample reference to current resolution\n",
    "        h_ref_downsampled = downsample(h_ref, h_ref.size/h.size)\n",
    "        \n",
    "        #Compute error per cell\n",
    "        error[i, j] = np.linalg.norm((h_ref_downsampled - h).flatten(), ord=1) / nx\n",
    "        conservation[i, j] = (np.sum(h_ref_downsampled) - np.sum(h))\n",
    "    \n",
    "fig = plt.figure()\n",
    "setBwStyles(fig.gca())\n",
    "\n",
    "x = np.linspace(domain_sizes[0], domain_sizes[-1], 100);\n",
    "\n",
    "scaling = np.max(error[:,0]) * domain_sizes[0] * 1.5\n",
    "plt.loglog(x, scaling/x, '-', color='gray', label='Order 1')\n",
    "\n",
    "scaling = np.min(error[:,0]) * domain_sizes[0]**2 * 0.5\n",
    "plt.loglog(x, scaling/(x*x), '-', color='gray', label='Order 2')\n",
    "\n",
    "for i, simulator in enumerate(simulators):\n",
    "    plt.loglog(domain_sizes, error[i,:], label=simulators[i].__name__)\n",
    "    \n",
    "plt.axis([10**1, 10**4, 10**-8, 10**-2])\n",
    "plt.xlabel('Number of cells')\n",
    "plt.ylabel('L2 error')\n",
    "plt.legend()\n",
    "save_figure(fig, 'convergence')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "c:\\Users\\anbro\\AppData\\Local\\Continuum\\anaconda3\\lib\\site-packages\\matplotlib\\backends\\backend_pdf.py:1579: UserWarning: Unknown infodict keyword: created\n",
      "  warnings.warn('Unknown infodict keyword: %s' % k)\n",
      "c:\\Users\\anbro\\AppData\\Local\\Continuum\\anaconda3\\lib\\site-packages\\matplotlib\\backends\\backend_pdf.py:1579: UserWarning: Unknown infodict keyword: hostname\n",
      "  warnings.warn('Unknown infodict keyword: %s' % k)\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 87752 characters]\n",
      "text/plain": [
       "<Figure size 1200x800 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "fig = plt.figure()\n",
    "setBwStyles(fig.gca())\n",
    "\n",
    "for i, simulator in enumerate(simulators):\n",
    "    a = np.arange(1, len(domain_sizes))\n",
    "    order = np.log2(error[i, :-1] / error[i, 1:])\n",
    "    #order = np.log2(error[i, 0] / (error[i, 1:]) )/a\n",
    "    plt.plot(order, label=simulator.__name__)\n",
    "    \n",
    "plt.ylim([0, 3])\n",
    "plt.xlabel('Number of cells')\n",
    "plt.ylabel('Order')\n",
    "plt.legend()\n",
    "save_figure(fig, 'convergence2')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "c:\\Users\\anbro\\AppData\\Local\\Continuum\\anaconda3\\lib\\site-packages\\matplotlib\\backends\\backend_pdf.py:1579: UserWarning: Unknown infodict keyword: created\n",
      "  warnings.warn('Unknown infodict keyword: %s' % k)\n",
      "c:\\Users\\anbro\\AppData\\Local\\Continuum\\anaconda3\\lib\\site-packages\\matplotlib\\backends\\backend_pdf.py:1579: UserWarning: Unknown infodict keyword: hostname\n",
      "  warnings.warn('Unknown infodict keyword: %s' % k)\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 80460 characters]\n",
      "text/plain": [
       "<Figure size 1200x800 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 82872 characters]\n",
      "text/plain": [
       "<Figure size 1200x800 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 73616 characters]\n",
      "text/plain": [
       "<Figure size 1200x800 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 59052 characters]\n",
      "text/plain": [
       "<Figure size 1200x800 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 63592 characters]\n",
      "text/plain": [
       "<Figure size 1200x800 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 62488 characters]\n",
      "text/plain": [
       "<Figure size 1200x800 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 60992 characters]\n",
      "text/plain": [
       "<Figure size 1200x800 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def plot_solution(simulator, nx, label, **kwargs):\n",
    "    datafilename = gen_filename(simulator, nx)\n",
    "    \n",
    "    #Read the solution\n",
    "    with np.load(datafilename) as data:\n",
    "        h = data['h']\n",
    "        \n",
    "    x = np.linspace(0.5, nx-0.5, nx)*10.0/float(nx)\n",
    "    y = h[0,:]\n",
    "    \n",
    "    plt.plot(x, y, label=label, **kwargs)\n",
    "    \n",
    "    h = None\n",
    "    x = None\n",
    "    gc.collect() # Force run garbage collection to free up memory\n",
    "\n",
    "for simulator in simulators:\n",
    "    fig = plt.figure()\n",
    "    setBwStyles(fig.gca())\n",
    "    \n",
    "    #Plot reference solution\n",
    "    ref_x, ref_h, _ = gen_reference(4096)\n",
    "    plt.plot(ref_x, ref_h, '-', label='Reference')\n",
    "    ref_x = None\n",
    "    ref_h = None\n",
    "    gc.collect()\n",
    "    \n",
    "    #Plot simulation results\n",
    "    for j, nx in enumerate(domain_sizes):\n",
    "        plot_solution(simulator, nx, 'nx=' + str(nx), marker=' ')\n",
    "    plt.title(str(simulator.__name__))\n",
    "    plt.axis([0, 10, 0, 0.0055])\n",
    "    plt.legend()\n",
    "    \n",
    "    save_figure(fig, simulator.__name__)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 24884 characters]\n",
      "text/plain": [
       "<Figure size 1200x800 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "figLegend = plt.figure()#figsize = (1.5,1.3))\n",
    "plt.plot(0, 0)\n",
    "plt.figlegend(*fig.gca().get_legend_handles_labels(), loc = 'center')\n",
    "plt.axis('off')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "c:\\Users\\anbro\\AppData\\Local\\Continuum\\anaconda3\\lib\\site-packages\\matplotlib\\backends\\backend_pdf.py:1579: UserWarning: Unknown infodict keyword: created\n",
      "  warnings.warn('Unknown infodict keyword: %s' % k)\n",
      "c:\\Users\\anbro\\AppData\\Local\\Continuum\\anaconda3\\lib\\site-packages\\matplotlib\\backends\\backend_pdf.py:1579: UserWarning: Unknown infodict keyword: hostname\n",
      "  warnings.warn('Unknown infodict keyword: %s' % k)\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 45808 characters]\n",
      "text/plain": [
       "<Figure size 1200x800 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 117988 characters]\n",
      "text/plain": [
       "<Figure size 1200x800 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 125492 characters]\n",
      "text/plain": [
       "<Figure size 1200x800 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 113504 characters]\n",
      "text/plain": [
       "<Figure size 1200x800 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "def plot_comparison(**kwargs):\n",
    "    ref_x, ref_h, _ = gen_reference(4096)\n",
    "    plt.plot(ref_x, ref_h, '-', color='black', label='Analytic')\n",
    "    ref_x = None\n",
    "    ref_h = None\n",
    "    gc.collect()\n",
    "\n",
    "    for i, simulator in enumerate(simulators):\n",
    "        nx = 512\n",
    "        plot_solution(simulator, nx, simulator.__name__, **kwargs)\n",
    "        \n",
    "\n",
    "fig = plt.figure()\n",
    "setBwStyles(fig.gca())\n",
    "\n",
    "boxes = np.array([\\\n",
    "         [[3.5, 4.1], [0.0044, 0.00505]], \\\n",
    "         [[4.7, 5.05], [0.0025, 0.0027]],  \\\n",
    "         [[6.1, 6.40], [0.0009, 0.0026]] \\\n",
    "         ])\n",
    "\n",
    "plot_comparison(marker=' ')\n",
    "for box_x, box_y in boxes:\n",
    "    x = np.kron(box_x, np.ones((2)))\n",
    "    y = np.hstack((box_y, box_y[::-1]))\n",
    "    fig.gca().fill(x, y, fill=True, linestyle='-', color='gray', alpha=0.5)\n",
    "plt.xlim([0, 10])\n",
    "plt.ylim([0, 0.0055])\n",
    "plt.legend(loc='lower left')\n",
    "save_figure(fig, 'solution')\n",
    "\n",
    "for i, bbox in enumerate(boxes):\n",
    "    fig = plt.figure()\n",
    "    setBwStyles(fig.gca())\n",
    "    plot_comparison()\n",
    "    plt.xlim(bbox[0])\n",
    "    plt.ylim(bbox[1])\n",
    "    plt.legend()\n",
    "    \n",
    "    save_figure(fig, \"solution_zoom_\" + str(i))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python [default]",
   "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.6.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
