{ "cells": [ { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "# Definition of Symbolic PDE Based on MindFlow\n", "\n", "[![DownloadNotebook](https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/website-images/r2.0.0-alpha/resource/_static/logo_notebook_en.png)](https://obs.dualstack.cn-north-4.myhuaweicloud.com/mindspore-website/notebook/r2.0.0-alpha/mindflow/en/physics_driven/mindspore_sympy_pde_definition.ipynb) [![DownloadCode](https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/website-images/r2.0.0-alpha/resource/_static/logo_download_code_en.png)](https://obs.dualstack.cn-north-4.myhuaweicloud.com/mindspore-website/notebook/r2.0.0-alpha/mindflow/en/physics_driven/mindspore_sympy_pde_definition.py) [![ViewSource](https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/website-images/r2.0.0-alpha/resource/_static/logo_source_en.png)](https://gitee.com/mindspore/docs/blob/r2.0.0-alpha/docs/mindflow/docs/source_en/physics_driven/sympy_pde_definition.ipynb)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Partial differential equations (PDEs) play an important role in engineering application since most of the physics governing natural or man-made complex systems are described by PDEs. Here, the definition of PDE based on MindFlow with sympy and the model construction based on Physics-Informed Neural Networks (PINNs) are introduced. Using *mindflow.pde.PDEWithLoss*, one can describe the partial differential equation in symbolic form, and calculates the loss of all equations easily. This makes the equation simple, easy to understand and expand. One can inherit *mindflow.pde.PDEWithLoss* to realize user-defined partial differential equations." ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "## Example of PDE: Navier-Stokes equation\n", "\n", "The Navier-Stokes equation, referred to as `N-S` equation, is a classical partial differential equation in the field of fluid mechanics. In the case of viscous incompressibility, the dimensionless `N-S` equation has the following form:\n", "\n", "$$\n", "\\frac{\\partial u}{\\partial x} + \\frac{\\partial v}{\\partial y} = 0\n", "$$\n", "\n", "$$\n", "\\frac{\\partial u} {\\partial t} + u \\frac{\\partial u}{\\partial x} + v \\frac{\\partial u}{\\partial y} + \\frac{\\partial p}{\\partial x} - \\frac{1} {Re} (\\frac{\\partial^2u}{\\partial x^2} + \\frac{\\partial^2u}{\\partial y^2}) = 0\n", "$$\n", "\n", "$$\n", "\\frac{\\partial v} {\\partial t} + u \\frac{\\partial v}{\\partial x} + v \\frac{\\partial v}{\\partial y} + \\frac{\\partial p}{\\partial y} - \\frac{1} {Re} (\\frac{\\partial^2v}{\\partial x^2} + \\frac{\\partial^2v}{\\partial y^2}) = 0\n", "$$\n", "\n", "where `Re` stands for Reynolds number." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Symbol Declaration" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[x, y, t]\n", "[u(x, y, t), v(x, y, t), p(x, y, t)]\n" ] } ], "source": [ "from sympy import symbols, Function\n", "\n", "x, y, t = symbols('x y t')\n", "u = Function('u')(x, y, t)\n", "v = Function('v')(x, y, t)\n", "p = Function('p')(x, y, t)\n", "\n", "# independent variables\n", "in_vars = [x, y, t]\n", "print(in_vars)\n", "\n", "# dependent variables\n", "out_vars = [u, v, p]\n", "print(out_vars)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### PDE in Symbolic Forms\n", "\n", "Define PDEs using the symbol declaration above." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "from sympy import diff" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Governing Equations" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "u(x, y, t)*Derivative(u(x, y, t), x) + v(x, y, t)*Derivative(u(x, y, t), y) + Derivative(p(x, y, t), x) + Derivative(u(x, y, t), t) - 0.00999999977648258*Derivative(u(x, y, t), (x, 2)) - 0.00999999977648258*Derivative(u(x, y, t), (y, 2))\n", "u(x, y, t)*Derivative(v(x, y, t), x) + v(x, y, t)*Derivative(v(x, y, t), y) + Derivative(p(x, y, t), y) + Derivative(v(x, y, t), t) - 0.00999999977648258*Derivative(v(x, y, t), (x, 2)) - 0.00999999977648258*Derivative(v(x, y, t), (y, 2))\n", "Derivative(u(x, y, t), x) + Derivative(v(x, y, t), y)\n" ] } ], "source": [ "# Consider Reynolds number is 100\n", "re = 100\n", "number = np.float32(1.0 / re)\n", "\n", "# X Momemtum\n", "momentum_x = u.diff(t) + u * u.diff(x) + v * u.diff(y) + p.diff(x) - number*(diff(u, (x, 2)) + diff(u, (y, 2)))\n", "print(momentum_x)\n", "\n", "# Y Momemtum\n", "momentum_y = v.diff(t) + u * v.diff(x) + v * v.diff(y) + p.diff(y) - number*(diff(v, (x, 2)) + diff(v, (y, 2)))\n", "print(momentum_y)\n", "\n", "# continuty\n", "continuty = u.diff(x) + v.diff(y)\n", "print(continuty)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Boundary Condition" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "u(x, y, t)\n", "v(x, y, t)\n" ] } ], "source": [ "bc_u = u\n", "print(bc_u)\n", "\n", "bc_v = v\n", "print(bc_v)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "### Initial Condition" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "u(x, y, t)\n", "v(x, y, t)\n", "p(x, y, t)\n" ] } ], "source": [ "ic_u = u\n", "print(bc_u)\n", "\n", "ic_v = v\n", "print(ic_v)\n", "\n", "ic_p = p\n", "print(ic_p)" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "## Example of Problem Modeling\n", "\n", "The following `CylinderFlow` defines the 2d unsteady flow passing over a cylinder problem. Specifically, it includes 3 parts defined above: governing equation, initial condition and boundary conditions." ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "The `NavierStokes` base class, the input and output variables, and the governing equations are defined.\n", "\n", "If you want to define other governing equations, you can overwrite the `NavierStokes` base class." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "from mindspore import nn\n", "from mindflow.pde import PDEWithLoss\n", "\n", "\n", "class NavierStokes(PDEWithLoss):\n", " def __init__(self, model, re=100, loss_fn=nn.MSELoss()):\n", " self.number = np.float32(1.0 / re)\n", " self.x, self.y, self.t = symbols('x y t')\n", " self.u = Function('u')(self.x, self.y, self.t)\n", " self.v = Function('v')(self.x, self.y, self.t)\n", " self.p = Function('p')(self.x, self.y, self.t)\n", " self.in_vars = [self.x, self.y, self.t]\n", " self.out_vars = [self.u, self.v, self.p]\n", " super(NavierStokes, self).__init__(model, self.in_vars, self.out_vars)\n", " self.loss_fn = loss_fn\n", "\n", " def pde(self):\n", " momentum_x = self.u.diff(self.t) + self.u * self.u.diff(self.x) + self.v * self.u.diff(self.y) +\\\n", " self.p.diff(self.x) - self.number * (diff(self.u, (self.x, 2)) + diff(self.u, (self.y, 2)))\n", " momentum_y = self.v.diff(self.t) + self.u * self.v.diff(self.x) + self.v * self.v.diff(self.y) +\\\n", " self.p.diff(self.y) - self.number * (diff(self.v, (self.x, 2)) + diff(self.v, (self.y, 2)))\n", " continuty = self.u.diff(self.x) + self.v.diff(self.y)\n", "\n", " equations = {\"momentum_x\": momentum_x, \"momentum_y\": momentum_y, \"continuty\": continuty}\n", " return equations" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "Next, we use the `NavierStokes` base class to define initial and boundary conditions, as well as loss functions." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "from mindspore import nn, ops, Tensor\n", "from mindspore import dtype as mstype\n", "from mindflow.pde import PDEWithLoss, NavierStokes, sympy_to_mindspore\n", "\n", "\n", "class CylinderFlow(NavierStokes):\n", " def __init__(self, model, re=100, loss_fn=nn.MSELoss()):\n", " super(CylinderFlow, self).__init__(model, re=re, loss_fn=loss_fn)\n", " self.ic_nodes = sympy_to_mindspore(self.ic(), self.in_vars, self.out_vars)\n", " self.bc_nodes = sympy_to_mindspore(self.bc(), self.in_vars, self.out_vars)\n", "\n", " def bc(self):\n", " bc_u = self.u\n", " bc_v = self.v\n", " equations = {\"bc_u\": bc_u, \"bc_v\": bc_v}\n", " return equations\n", "\n", " def ic(self):\n", " ic_u = self.u\n", " ic_v = self.v\n", " ic_p = self.p\n", " equations = {\"ic_u\": ic_u, \"ic_v\": ic_v, \"ic_p\": ic_p}\n", " return equations\n", "\n", " def get_loss(self, pde_data, bc_data, bc_label, ic_data, ic_label):\n", " pde_res = self.parse_node(self.pde_nodes, inputs=pde_data)\n", " pde_residual = ops.Concat(1)(pde_res)\n", " pde_loss = self.loss_fn(pde_residual, Tensor(np.array([0.0]).astype(np.float32), mstype.float32))\n", "\n", " ic_res = self.parse_node(self.ic_nodes, inputs=ic_data)\n", " ic_residual = ops.Concat(1)(ic_res)\n", " ic_loss = self.loss_fn(ic_residual, ic_label)\n", "\n", " bc_res = self.parse_node(self.bc_nodes, inputs=bc_data)\n", " bc_residual = ops.Concat(1)(bc_res)\n", " bc_loss = self.loss_fn(bc_residual, bc_label)\n", "\n", " return pde_loss + ic_loss + bc_loss" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "For details, see [PINNs-based solution for flow past a cylinder](https://www.mindspore.cn/mindflow/docs/en/r0.1.0-alpha/physics_driven/navier_stokes2D.html)." ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "## Example of Neumann Boundary Condition Definition" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "In mathematics, Neumann boundary conditions are also called \"the second kind of boundary conditions\" of ordinary differential equations or partial differential equations. The Neumann boundary condition specifies the differential at the boundary of the solution of the differential equation." ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "The following `Poisson2D` problem defines Dirichlet boundary conditions(`bc_outer`) and Neumann boundary conditions(`bc_inner`)." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "import sympy\n", "from mindflow.pde import Poisson\n", "\n", "class Poisson2D(Poisson):\n", " def __init__(self, model, loss_fn=nn.MSELoss()):\n", " super(Poisson2D, self).__init__(model, loss_fn=loss_fn)\n", " self.bc_outer_nodes = sympy_to_mindspore(self.bc_outer(), self.in_vars, self.out_vars)\n", " self.bc_inner_nodes = sympy_to_mindspore(self.bc_inner(), self.in_vars, self.out_vars)\n", "\n", " def bc_outer(self):\n", " bc_outer_eq = self.u\n", " equations = {\"bc_outer\": bc_outer_eq}\n", " return equations\n", "\n", " def bc_inner(self):\n", " bc_inner_eq = sympy.Derivative(self.u, self.normal) - 0.5\n", " equations = {\"bc_inner\": bc_inner_eq}\n", " return equations\n", "\n", " def get_loss(self, pde_data, bc_outer_data, bc_inner_data, bc_inner_normal):\n", " pde_res = self.parse_node(self.pde_nodes, inputs=pde_data)\n", " pde_loss = self.loss_fn(pde_res[0], Tensor(np.array([0.0]), mstype.float32))\n", "\n", " bc_inner_res = self.parse_node(self.bc_inner_nodes, inputs=bc_inner_data, norm=bc_inner_normal)\n", " bc_inner_loss = self.loss_fn(bc_inner_res[0], Tensor(np.array([0.0]), mstype.float32))\n", "\n", " bc_outer_res = self.parse_node(self.bc_outer_nodes, inputs=bc_outer_data)\n", " bc_outer_loss = self.loss_fn(bc_outer_res[0], Tensor(np.array([0.0]), mstype.float32))\n", "\n", " return pde_loss + bc_inner_loss + bc_outer_loss" ] }, { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "For details, see [Solve Poisson's Equation on a Ring based on PINNS](https://www.mindspore.cn/mindflow/docs/en/r0.1.0-alpha/physics_driven/poisson_ring.html)." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3.8.0 64-bit", "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.0" }, "orig_nbformat": 4, "vscode": { "interpreter": { "hash": "df0893f56f349688326838aaeea0de204df53a132722cbd565e54b24a8fec5f6" } } }, "nbformat": 4, "nbformat_minor": 2 }