{ "nbformat": 4, "nbformat_minor": 0, "metadata": { "colab": { "name": "pdes.ipynb", "version": "0.3.2", "provenance": [], "private_outputs": true, "toc_visible": true }, "kernelspec": { "name": "python3", "display_name": "Python 3" } }, "cells": [ { "cell_type": "markdown", "metadata": { "id": "_omgylxzm5i9", "colab_type": "text" }, "source": [ "##### Copyright 2019 The TensorFlow Authors." ] }, { "cell_type": "code", "metadata": { "cellView": "form", "colab_type": "code", "id": "f0A2utIXbPc5", "colab": {} }, "source": [ "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n", "# you may not use this file except in compliance with the License.\n", "# You may obtain a copy of the License at\n", "#\n", "# https://www.apache.org/licenses/LICENSE-2.0\n", "#\n", "# Unless required by applicable law or agreed to in writing, software\n", "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", "# See the License for the specific language governing permissions and\n", "# limitations under the License." ], "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "eriCSHTznS4U", "colab_type": "text" }, "source": [ "# Partial Differential Equations" ] }, { "cell_type": "markdown", "metadata": { "id": "uYCNQT4snWr6", "colab_type": "text" }, "source": [ "\n", " \n", " \n", "
\n", " Run in Google Colab\n", " \n", " View source on GitHub\n", "
" ] }, { "cell_type": "markdown", "metadata": { "id": "zxQvbi5gnyMm", "colab_type": "text" }, "source": [ "TensorFlow isn't just for machine learning. Here you will use TensorFlow to simulate the behavior of a [partial differential equation](https://en.wikipedia.org/wiki/Partial_differential_equation). You'll simulate the surface of a square pond as a few raindrops land on it.\n", "\n", "## Basic setup\n", "\n", "A few imports you'll need." ] }, { "cell_type": "code", "metadata": { "id": "FG6DLet6ol3j", "colab_type": "code", "colab": {} }, "source": [ "from __future__ import absolute_import, division, print_function, unicode_literals\n", "\n", "#Import libraries for simulation\n", "import tensorflow as tf\n", "import numpy as np\n", "\n", "#Imports for visualization\n", "import PIL.Image\n", "from io import BytesIO\n", "from IPython.display import clear_output, Image, display\n" ], "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "7vd7rHS0oqEF", "colab_type": "text" }, "source": [ "A function for displaying the state of the pond's surface as an image." ] }, { "cell_type": "code", "metadata": { "id": "fJ8SpYYUoq6G", "colab_type": "code", "colab": {} }, "source": [ "def DisplayArray(a, fmt='jpeg', rng=[0,1]):\n", " \"\"\"Display an array as a picture.\"\"\"\n", " a = (a - rng[0])/float(rng[1] - rng[0])*255\n", " a = np.uint8(np.clip(a, 0, 255))\n", " f = BytesIO()\n", " PIL.Image.fromarray(a).save(f, fmt)\n", " clear_output(wait = True)\n", " display(Image(data=f.getvalue()))" ], "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "NjiZ2_6Mou13", "colab_type": "text" }, "source": [ "\n", "Here you start an interactive TensorFlow session for convenience in playing around. A regular session would work as well if you were doing this in an executable .py file." ] }, { "cell_type": "code", "metadata": { "id": "cH82JlsPozdV", "colab_type": "code", "colab": {} }, "source": [ "sess = tf.InteractiveSession()" ], "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "Hbk97yero5a9", "colab_type": "text" }, "source": [ "## Computational convenience functions" ] }, { "cell_type": "code", "metadata": { "id": "XVomNV1OpBbX", "colab_type": "code", "colab": {} }, "source": [ "def make_kernel(a):\n", " \"\"\"Transform a 2D array into a convolution kernel\"\"\"\n", " a = np.asarray(a)\n", " a = a.reshape(list(a.shape) + [1,1])\n", " return tf.constant(a, dtype=1)\n", "\n", "def simple_conv(x, k):\n", " \"\"\"A simplified 2D convolution operation\"\"\"\n", " x = tf.expand_dims(tf.expand_dims(x, 0), -1)\n", " y = tf.nn.depthwise_conv2d(x, k, [1, 1, 1, 1], padding='SAME')\n", " return y[0, :, :, 0]\n", "\n", "def laplace(x):\n", " \"\"\"Compute the 2D laplacian of an array\"\"\"\n", " laplace_k = make_kernel([[0.5, 1.0, 0.5],\n", " [1.0, -6., 1.0],\n", " [0.5, 1.0, 0.5]])\n", " return simple_conv(x, laplace_k)" ], "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "f9gBib2lpINO", "colab_type": "text" }, "source": [ "## Define the PDE\n", "\n", "Our pond is a perfect 500 x 500 square, as is the case for most ponds found in nature." ] }, { "cell_type": "code", "metadata": { "id": "7faiwBQhpK1Z", "colab_type": "code", "colab": {} }, "source": [ "N = 500" ], "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "U_DscmhfpPs0", "colab_type": "text" }, "source": [ "\n", "Here you create a pond and hit it with some rain drops." ] }, { "cell_type": "code", "metadata": { "id": "Mtk8t0IOpSrb", "colab_type": "code", "colab": {} }, "source": [ "# Initial Conditions -- some rain drops hit a pond\n", "\n", "# Set everything to zero\n", "u_init = np.zeros([N, N], dtype=np.float32)\n", "ut_init = np.zeros([N, N], dtype=np.float32)\n", "\n", "# Some rain drops hit a pond at random points\n", "for n in range(40):\n", " a,b = np.random.randint(0, N, 2)\n", " u_init[a,b] = np.random.uniform()\n", "\n", "DisplayArray(u_init, rng=[-0.1, 0.1])" ], "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "5vzdx9rHpXsl", "colab_type": "text" }, "source": [ "Now you specify the details of the differential equation." ] }, { "cell_type": "code", "metadata": { "id": "c6uj8LFDpaZO", "colab_type": "code", "colab": {} }, "source": [ "# Parameters:\n", "# eps -- time resolution\n", "# damping -- wave damping\n", "eps = tf.placeholder(tf.float32, shape=())\n", "damping = tf.placeholder(tf.float32, shape=())\n", "\n", "# Create variables for simulation state\n", "U = tf.Variable(u_init)\n", "Ut = tf.Variable(ut_init)\n", "\n", "# Discretized PDE update rules\n", "U_ = U + eps * Ut\n", "Ut_ = Ut + eps * (laplace(U) - damping * Ut)\n", "\n", "# Operation to update the state\n", "step = tf.group(\n", " U.assign(U_),\n", " Ut.assign(Ut_))" ], "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "eAjwNRjTppN-", "colab_type": "text" }, "source": [ "## Run the simulation\n", "\n", "This is where it gets fun -- running time forward with a simple for loop." ] }, { "cell_type": "code", "metadata": { "id": "jJLvEydzprsy", "colab_type": "code", "colab": {} }, "source": [ "# Initialize state to initial conditions\n", "tf.global_variables_initializer().run()\n", "\n", "# Run 1000 steps of PDE\n", "for i in range(1000):\n", " # Step simulation\n", " step.run({eps: 0.03, damping: 0.04})\n", "\n", "# Show final image\n", "DisplayArray(U.eval(), rng=[-0.1, 0.1])" ], "execution_count": 0, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "8AcEDQfbpyDT", "colab_type": "text" }, "source": [ "Look! Ripples!" ] } ] }