{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "o4JZ84moBKMr"
   },
   "source": [
    "# Navier-Stokes Forward Simulation with Φ<sub>Flow</sub>\n",
    "\n",
    "... now a more complex example with fluid simulations (Navier-Stokes) ... still very simple with phiflow (complexity of the differentiable operators hidden).\n",
    "\n",
    "As before, the first command with a \"!\" prefix installs the [Φ<sub>Flow</sub> Python package from GitHub](https://github.com/tum-pbs/PhiFlow) via `pip` in your python environment. (Skip or modify this command if necessary.)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "da1uZcDXdVcF",
    "outputId": "1082dc87-796c-4b57-e72e-5790fc1444c9"
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/thuerey/anaconda3/envs/tf/lib/python3.8/_collections_abc.py:743: MatplotlibDeprecationWarning: The global colormaps dictionary is no longer considered public API.\n",
      "  for key in self._mapping:\n",
      "/home/thuerey/anaconda3/envs/tf/lib/python3.8/_collections_abc.py:744: MatplotlibDeprecationWarning: The global colormaps dictionary is no longer considered public API.\n",
      "  yield (key, self._mapping[key])\n",
      "/home/thuerey/phiflow/phi/viz/display.py:80: UserWarning: GUI is disabled because of missing dependencies: No module named 'imageio'. To install all dependencies, run $ pip install phiflow[gui]\n",
      "  warnings.warn('GUI is disabled because of missing dependencies: %s. To install all dependencies, run $ pip install phiflow[gui]' % import_error)\n"
     ]
    }
   ],
   "source": [
    "!pip install --upgrade --quiet phiflow\n",
    "from phi.flow import *  # The Dash GUI is not supported on Google Colab, ignore the warning\n",
    "import pylab"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "BVV1IKVqDfLl"
   },
   "source": [
    "## Setting up the simulation\n",
    "\n",
    "Φ<sub>Flow</sub> is object-oriented, i.e. you assemble your simulation by constructing a number of objects and adding them to the world.\n",
    "\n",
    "The following code sets up four fluid simulations that run in parallel (`batch_size=4`). Each fluid simulation has a circular Inflow at a different location."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "id": "WrA3IXDxv31P"
   },
   "outputs": [],
   "source": [
    "world = World()\n",
    "fluid = world.add(Fluid(Domain([40, 32], boundaries=CLOSED), buoyancy_factor=0.05), physics=IncompressibleFlow())\n",
    "world.add(Inflow(Sphere(center=[5,14], radius=3), rate=0.2));"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "ExA0Pi2sFVka"
   },
   "source": [
    "The inflow affects the fluid's marker density. Because a Boussinesq model with a positive `buoyancy_factor` is active, the marker field `density` creates an upward force. Note that this density is not the density of the fluid, but the amount of marker quantity present in each cell.\n",
    "\n",
    "Let's plot the marker density after one simulation frame."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 282
    },
    "id": "WmGZdOwswOva",
    "outputId": "3ae4d68d-b586-4bbe-eca9-a223d7720949"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.image.AxesImage at 0x7f9cf945eee0>"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 4112 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "world.step()\n",
    "pylab.imshow(fluid.density.data[0,...,0], origin='lower', cmap='magma')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A lot has happened internally in the `world.step()` call, e.g., for fluids we have a more complex `struct` object that stores the different fields of the simulation. For fluids we have the aforementioned marker density in addition to a velocity."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Fluid state: Fluid[density: Grid[40x32(1), size=[40. 32.], float32], velocity: StaggeredGrid[40x32, size=[40. 32.], float32]]\n",
      "\n",
      " Velocity content:\n",
      "(1, 41, 32, 1)\n",
      "(1, 40, 33, 1)\n"
     ]
    }
   ],
   "source": [
    "print(\"Fluid state: \" + format(fluid.state))\n",
    "print(\"\\nVelocity content:\")\n",
    "[print(grid.data.shape) for grid in fluid.velocity.unstack()];"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Note that we actually created two variables, one for each velocity component. If you're interested in how this  works, have a look at the [Struct documentation](https://github.com/tum-pbs/PhiFlow/blob/master/documentation/Structs.ipynb).\n",
    "\n",
    "If you look closely at the output from the last `print` command, you'll notice that the shapes of the variables differ. This is because the velocity is sampled in [staggered form](https://github.com/tum-pbs/PhiFlow/blob/master/documentation/Staggered_Grids.md).\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "PA-2tGuWGHv2"
   },
   "source": [
    "We can run more steps by repeatedly calling `world.step()`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/"
    },
    "id": "0hZk5HX3w4Or",
    "outputId": "f7811af7-4b58-4ff6-a8b6-6e7bedefaa6e"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Computing frame 0\n",
      "Computing frame 1\n",
      "Computing frame 2\n",
      "Computing frame 3\n",
      "Computing frame 4\n",
      "Computing frame 5\n",
      "Computing frame 6\n",
      "Computing frame 7\n",
      "Computing frame 8\n",
      "Computing frame 9\n"
     ]
    }
   ],
   "source": [
    "for frame in range(10):\n",
    "  print('Computing frame %d' % frame)\n",
    "  world.step(dt=1.5)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "GMKKWQBLHIwP"
   },
   "source": [
    "Now the hot plume is starting to rise:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 282
    },
    "id": "Mfl80CjZxZcL",
    "outputId": "92f3a9ba-d403-4799-a543-132ee8ed234c"
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.image.AxesImage at 0x7fa84d3553d0>"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 5040 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "pylab.imshow(fluid.density.data[0,...,0], origin='lower', cmap='magma')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "wnbQJvA-HPSL"
   },
   "source": [
    "Let's compute and show a few more steps of the simulation."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "colab": {
     "base_uri": "https://localhost:8080/",
     "height": 489
    },
    "id": "tkhCOzc0ITsj",
    "outputId": "f6366c12-1eb5-4ff6-e0d7-94b806bfd8e4"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Computing frame 0\n",
      "Computing frame 1\n",
      "Computing frame 2\n",
      "Computing frame 3\n",
      "Computing frame 4\n",
      "Computing frame 5\n",
      "Computing frame 6\n",
      "Computing frame 7\n",
      "Computing frame 8\n",
      "Computing frame 9\n",
      "Computing frame 10\n",
      "Computing frame 11\n",
      "Computing frame 12\n",
      "Computing frame 13\n",
      "Computing frame 14\n",
      "Computing frame 15\n",
      "Computing frame 16\n",
      "Computing frame 17\n",
      "Computing frame 18\n",
      "Computing frame 19\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<matplotlib.image.AxesImage at 0x7fa84d2d8790>"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 20516 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "frames = [fluid.density.data[0,...,0]]\n",
    "for frame in range(20):\n",
    "  print('Computing frame %d' % frame)\n",
    "  world.step(dt=1.5)\n",
    "  if frame%5==0:\n",
    "    frames.append(fluid.density.data[0,...,0])\n",
    "\n",
    "pylab.imshow(np.concatenate(frames,axis=1), origin='lower', cmap='magma')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "ooqVxCPM8PXl"
   },
   "source": [
    "It looks simple here, but this is a powerful tool. The simulation could easily be extended to more complex cases or 3D, and they're fully compatible with back-propagation pipelines of deep learning frameworks. \n",
    "\n",
    "In the next chapters we'll show how to use these simulations for training NNs, and how to steer and modify them via trained NNs. This will illustrate how much we can improve the training process by having a solver in the loop, and especially by having differentiable solvers."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "id": "BL-AOqwMJmkq"
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "colab": {
   "collapsed_sections": [],
   "name": "Forw Simulations with Φ-Flow.ipynb",
   "provenance": []
  },
  "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.8.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
