Files
PINA/tutorials/tutorial12/tutorial.ipynb
2025-04-17 10:48:31 +02:00

277 lines
9.8 KiB
Plaintext
Vendored

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Tutorial: The `Equation` Class\n",
"\n",
"[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/mathLab/PINA/blob/master/tutorials/tutorial12/tutorial.ipynb)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In this tutorial, we will show how to use the `Equation` Class in PINA. Specifically, we will see how use the Class and its inherited classes to enforce residuals minimization in PINNs."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Example: The Burgers 1D equation"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We will start implementing the viscous Burgers 1D problem Class, described as follows:\n",
"\n",
"\n",
"$$\n",
"\\begin{equation}\n",
"\\begin{cases}\n",
"\\frac{\\partial u}{\\partial t} + u \\frac{\\partial u}{\\partial x} &= \\nu \\frac{\\partial^2 u}{ \\partial x^2}, \\quad x\\in(0,1), \\quad t>0\\\\\n",
"u(x,0) &= -\\sin (\\pi x)\\\\\n",
"u(x,t) &= 0 \\quad x = \\pm 1\\\\\n",
"\\end{cases}\n",
"\\end{equation}\n",
"$$\n",
"\n",
"where we set $ \\nu = \\frac{0.01}{\\pi}$.\n",
"\n",
"In the class that models this problem we will see in action the `Equation` class and one of its inherited classes, the `FixedValue` class. "
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"## routine needed to run the notebook on Google Colab\n",
"try:\n",
" import google.colab\n",
" IN_COLAB = True\n",
"except:\n",
" IN_COLAB = False\n",
"if IN_COLAB:\n",
" !pip install \"pina-mathlab\"\n",
"\n",
"import torch\n",
"\n",
"#useful imports\n",
"from pina import Condition\n",
"from pina.problem import SpatialProblem, TimeDependentProblem\n",
"from pina.equation import Equation, FixedValue\n",
"from pina.domain import CartesianDomain\n",
"from pina.operator import grad, laplacian"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"# define the burger equation\n",
"def burger_equation(input_, output_):\n",
" du = grad(output_, input_)\n",
" ddu = grad(du, input_, components=[\"dudx\"])\n",
" return (\n",
" du.extract([\"dudt\"])\n",
" + output_.extract([\"u\"]) * du.extract([\"dudx\"])\n",
" - (0.01 / torch.pi) * ddu.extract([\"ddudxdx\"])\n",
" )\n",
"\n",
"\n",
"# define initial condition\n",
"def initial_condition(input_, output_):\n",
" u_expected = -torch.sin(torch.pi * input_.extract([\"x\"]))\n",
" return output_.extract([\"u\"]) - u_expected\n",
"\n",
"\n",
"class Burgers1D(TimeDependentProblem, SpatialProblem):\n",
"\n",
" # assign output/ spatial and temporal variables\n",
" output_variables = [\"u\"]\n",
" spatial_domain = CartesianDomain({\"x\": [-1, 1]})\n",
" temporal_domain = CartesianDomain({\"t\": [0, 1]})\n",
"\n",
" domains = {\n",
" \"bound_cond1\": CartesianDomain({\"x\": -1, \"t\": [0, 1]}),\n",
" \"bound_cond2\": CartesianDomain({\"x\": 1, \"t\": [0, 1]}),\n",
" \"time_cond\": CartesianDomain({\"x\": [-1, 1], \"t\": 0}),\n",
" \"phys_cond\": CartesianDomain({\"x\": [-1, 1], \"t\": [0, 1]}),\n",
" }\n",
" # problem condition statement\n",
" conditions = {\n",
" \"bound_cond1\": Condition(\n",
" domain=\"bound_cond1\", equation=FixedValue(0.0)\n",
" ),\n",
" \"bound_cond2\": Condition(\n",
" domain=\"bound_cond2\", equation=FixedValue(0.0)\n",
" ),\n",
" \"time_cond\": Condition(\n",
" domain=\"time_cond\", equation=Equation(initial_condition)\n",
" ),\n",
" \"phys_cond\": Condition(\n",
" domain=\"phys_cond\", equation=Equation(burger_equation)\n",
" ),\n",
" }"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"The `Equation` class takes as input a function (in this case it happens twice, with `initial_condition` and `burger_equation`) which computes a residual of an equation, such as a PDE. In a problem class such as the one above, the `Equation` class with such a given input is passed as a parameter in the specified `Condition`. \n",
"\n",
"The `FixedValue` class takes as input a value of same dimensions of the output functions; this class can be used to enforce a fixed value for a specific condition, e.g. Dirichlet boundary conditions, as it happens for instance in our example.\n",
"\n",
"Once the equations are set as above in the problem conditions, the PINN solver will aim to minimize the residuals described in each equation in the training phase. "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Available classes of equations include also:\n",
"- `FixedGradient` and `FixedFlux`: they work analogously to `FixedValue` class, where we can require a constant value to be enforced, respectively, on the gradient of the solution or the divergence of the solution;\n",
"- `Laplace`: it can be used to enforce the laplacian of the solution to be zero;\n",
"- `SystemEquation`: we can enforce multiple conditions on the same subdomain through this class, passing a list of residual equations defined in the problem.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Defining a new Equation class"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`Equation` classes can be also inherited to define a new class. As example, we can see how to rewrite the above problem introducing a new class `Burgers1D`; during the class call, we can pass the viscosity parameter $\\nu$:"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"class Burgers1DEquation(Equation):\n",
" \n",
" def __init__(self, nu = 0.):\n",
" \"\"\"\n",
" Burgers1D class. This class can be\n",
" used to enforce the solution u to solve the viscous Burgers 1D Equation.\n",
" \n",
" :param torch.float32 nu: the viscosity coefficient. Default value is set to 0.\n",
" \"\"\"\n",
" self.nu = nu \n",
" \n",
" def equation(input_, output_):\n",
" return grad(output_, input_, d='t') +\\\n",
" output_*grad(output_, input_, d='x') -\\\n",
" self.nu*laplacian(output_, input_, d='x')\n",
"\n",
" \n",
" super().__init__(equation)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now we can just pass the above class as input for the last condition, setting $\\nu= \\frac{0.01}{\\pi}$:"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"class Burgers1D(TimeDependentProblem, SpatialProblem):\n",
"\n",
" # define initial condition\n",
" def initial_condition(input_, output_):\n",
" u_expected = -torch.sin(torch.pi * input_.extract([\"x\"]))\n",
" return output_.extract([\"u\"]) - u_expected\n",
"\n",
" # assign output/ spatial and temporal variables\n",
" output_variables = [\"u\"]\n",
" spatial_domain = CartesianDomain({\"x\": [-1, 1]})\n",
" temporal_domain = CartesianDomain({\"t\": [0, 1]})\n",
"\n",
" domains = {\n",
" \"bound_cond1\": CartesianDomain({\"x\": -1, \"t\": [0, 1]}),\n",
" \"bound_cond2\": CartesianDomain({\"x\": 1, \"t\": [0, 1]}),\n",
" \"time_cond\": CartesianDomain({\"x\": [-1, 1], \"t\": 0}),\n",
" \"phys_cond\": CartesianDomain({\"x\": [-1, 1], \"t\": [0, 1]}),\n",
" }\n",
" # problem condition statement\n",
" conditions = {\n",
" \"bound_cond1\": Condition(\n",
" domain=\"bound_cond1\", equation=FixedValue(0.0)\n",
" ),\n",
" \"bound_cond2\": Condition(\n",
" domain=\"bound_cond2\", equation=FixedValue(0.0)\n",
" ),\n",
" \"time_cond\": Condition(\n",
" domain=\"time_cond\", equation=Equation(initial_condition)\n",
" ),\n",
" \"phys_cond\": Condition(\n",
" domain=\"phys_cond\", equation=Burgers1DEquation(nu=0.01 / torch.pi)\n",
" ),\n",
" }"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# What's next?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Congratulations on completing the `Equation` class tutorial of **PINA**! As we have seen, you can build new classes that inherit `Equation` to store more complex equations, as the Burgers 1D equation, only requiring to pass the characteristic coefficients of the problem. \n",
"From now on, you can:\n",
"- define additional complex equation classes (e.g. `SchrodingerEquation`, `NavierStokeEquation`..)\n",
"- define more `FixedOperator` (e.g. `FixedCurl`)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "pina",
"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.9.21"
},
"orig_nbformat": 4
},
"nbformat": 4,
"nbformat_minor": 2
}