phiflow 2 updates of overview sims

This commit is contained in:
NT committed 2021-06-17 16:31:41 +02:00
1 parent 1f1c8703b7
commit 3cbaa5ef5d
2 files changed
+99 -75

No files matched your search

+29 -24
View File
@@ -6,9 +6,9 @@
"source": [ "source": [
"# Simple Forward Simulation of Burgers Equation with phiflow\n", "# Simple Forward Simulation of Burgers Equation with phiflow\n",
"\n", "\n",
"This chapter will give an introduction for how to run _forward_, i.e., regular simulations starting with a given initial state and approximating a later state numerically, with Φ<sub>Flow</sub>. The phiflow framework provides a set of differentiable building blocks that directly interface with deep learning frameworks, and before going for deeper and more complicated integrations, this notebook (and the next one), will show how regular simulations can be done with phiflow. Later on, we can use very similar code to couple them with neural networks.\n", "This chapter will give an introduction for how to run _forward_, i.e., regular simulations starting with a given initial state and approximating a later state numerically, with Φ<sub>Flow</sub>. The Φ<sub>Flow</sub> framework provides a set of differentiable building blocks that directly interface with deep learning frameworks, and before going for deeper and more complicated integrations, this notebook (and the next one), will show how regular simulations can be done with Φ<sub>Flow</sub>. Later on, we can use very similar code to couple them with neural networks.\n",
"\n", "\n",
"The main repository for phiflow is https://github.com/tum-pbs/PhiFlow, and additional API documenation and examples can be found at https://tum-pbs.github.io/PhiFlow/.\n", "The main repository for Φ<sub>Flow</sub> (in the following \"phiflow\") is https://github.com/tum-pbs/PhiFlow, and additional API documenation and examples can be found at https://tum-pbs.github.io/PhiFlow/.\n",
"\n", "\n",
"For this jupyter notebook (and all following ones), you can find a _\"[run in colab]\"_ link at the end of the first paragraph. This link will load the latest version from the PBDL github repo in a colab notebook that you can execute on the spot: \n", "For this jupyter notebook (and all following ones), you can find a _\"[run in colab]\"_ link at the end of the first paragraph. This link will load the latest version from the PBDL github repo in a colab notebook that you can execute on the spot: \n",
"[[run in colab]](https://colab.research.google.com/github/tum-pbs/pbdl-book/blob/main/overview-burgers-forw.ipynb)\n", "[[run in colab]](https://colab.research.google.com/github/tum-pbs/pbdl-book/blob/main/overview-burgers-forw.ipynb)\n",
@@ -31,14 +31,14 @@
"source": [ "source": [
"## Importing and loading phiflow\n", "## Importing and loading phiflow\n",
"\n", "\n",
"Let's get some preliminaries out of the way: first we'll import the Φ<sub>Flow</sub> library, more specifically the `numpy` operators for fluid flow simulations: `phi.flow` (differentiable versions for a DL framework _X_ are loaded via `phi.X.flow` instead).\n", "Let's get some preliminaries out of the way: first we'll import the phiflow library, more specifically the `numpy` operators for fluid flow simulations: `phi.flow` (differentiable versions for a DL framework _X_ are loaded via `phi.X.flow` instead).\n",
"\n", "\n",
"**Note:** Below, the first command with a \"!\" prefix will install the [Φ<sub>Flow</sub> Python package from GitHub](https://github.com/tum-pbs/PhiFlow) via `pip` in your python environment once you uncomment it. We've assumed that phiflow isn't installed, but if you have already done so, just comment out the first line (the same will hold for all following notebooks)." "**Note:** Below, the first command with a \"!\" prefix will install the [phiflow python package from GitHub](https://github.com/tum-pbs/PhiFlow) via `pip` in your python environment once you uncomment it. We've assumed that phiflow isn't installed, but if you have already done so, just comment out the first line (the same will hold for all following notebooks)."
] ]
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 2, "execution_count": 1,
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{ {
@@ -65,12 +65,16 @@
"Next we can define and initialize the necessary constants (denoted by upper-case names):\n", "Next we can define and initialize the necessary constants (denoted by upper-case names):\n",
"our simulation domain will have `N=128` cells as discretization points for the 1D velocity $u$ in a periodic domain $\\Omega$ for the interval $[-1,1]$. We'll use 32 time `STEPS` for a time interval of 1, giving us `DT=1/32`. Additionally, we'll use a viscosity `NU` of $\\nu=0.01/\\pi$.\n", "our simulation domain will have `N=128` cells as discretization points for the 1D velocity $u$ in a periodic domain $\\Omega$ for the interval $[-1,1]$. We'll use 32 time `STEPS` for a time interval of 1, giving us `DT=1/32`. Additionally, we'll use a viscosity `NU` of $\\nu=0.01/\\pi$.\n",
"\n", "\n",
"We'll also define an initial state given by $-\\text{sin}(\\pi x)$ in the numpy array `INITIAL`, which we'll use to initialize the velocity $u$ in the simulation in the next cell. This initialization will produce a nice shock in the center of our domain.\n" "We'll also define an initial state given by $-\\text{sin}(\\pi x)$ in the numpy array `INITIAL_NUMPY`, which we'll use to initialize the velocity $u$ in the simulation in the next cell. This initialization will produce a nice shock in the center of our domain. \n",
"\n",
"Phiflow is object-oriented and centered around field data in the form of grids (internally represented by a tensor object). I.e. you assemble your simulation by constructing a number of grids, and updating them over the course of time steps. \n",
"\n",
"Phiflow internally works with tensors that have named dimensions. This will be especially handy later on for 2D simulations with additional batch and channel dimensions, but for now we'll simply convert the 1D array into a phiflow tensor that has a single spatial dimension `'x'`.\n"
] ]
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 3, "execution_count": 2,
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
@@ -80,40 +84,40 @@
"NU = 0.01/np.pi\n", "NU = 0.01/np.pi\n",
"\n", "\n",
"# initialization of velocities\n", "# initialization of velocities\n",
"INITIAL = np.asarray( [-np.sin(np.pi * x) * 1. for x in np.linspace(-1,1,N)] ) # 1D array" "INITIAL_NUMPY = np.asarray( [-np.sin(np.pi * x) * 1. for x in np.linspace(-1,1,N)] ) # 1D numpy array\n",
"\n",
"INITIAL = math.tensor(INITIAL_NUMPY, spatial('x') ) # convert to phiflow tensor\n"
] ]
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": {}, "metadata": {},
"source": [ "source": [
"Φ<sub>Flow</sub> is object-oriented and centered around field data in the form of grids (internally represented by a tensor object). I.e. you assemble your simulation by constructing a number of grids, and updating them over the course of time steps.\n",
"\n", "\n",
"Next, we declare the `domain` object to contain $\\Omega$, as outlined above periodically for $[-1,1]$. We also \n", "Next, we initialize a 1D `velocity` grid from the `INITIAL` numpy array that was converted into a tensor.\n",
"initialize a 1D `velocity` grid from the `INITIAL` numpy array.\n", "The extent of our domain $\\Omega$ is specifiied via the `bounds` parameter $[-1,1]$, and the grid uses periodic boundary conditions (`extrapolation.PERIODIC`). These two properties are the main difference between a tensor and a grid: the latter has boundary conditions and a physical extent.\n",
"\n", "\n",
"Just to illustrate, we'll also print some info about the velocity object: it's a `phiflow.math` tensor with a size of 128. Note that the actual grid content is contained in the `values` of the grid. Below we're printing five entries by using the `numpy()` function to convert the content of the phiflow tensor into a numpy array." "Just to illustrate, we'll also print some info about the velocity object: it's a `phi.math` tensor with a size of 128. Note that the actual grid content is contained in the `values` of the grid. Below we're printing five entries by using the `numpy()` function to convert the content of the phiflow tensor into a numpy array. For tensors with more dimensions, we'd need to specify the order here, e.g., `'y,x,vector'` for a 2D velocity field. (If we'd call `numpy('x,vector')` below, this would convert the 1D array into one with an additional dimension for each 1D velocity component.)"
] ]
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 7, "execution_count": 3,
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{ {
"name": "stdout", "name": "stdout",
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"Velocity tensor shape: (x=128)\n", "Velocity tensor shape: (xˢ=128)\n",
"Velocity tensor type: <class 'phi.math._tensors.CollapsedTensor'>\n", "Velocity tensor type: <class 'phi.math._tensors.CollapsedTensor'>\n",
"Velocity tensor entries 10 to 14: [0.47480196 0.51774486 0.55942075 0.59972764 0.6385669 ]\n" "Velocity tensor entries 10 to 14: [0.47480196 0.51774486 0.55942075 0.59972764 0.6385669 ]\n"
] ]
} }
], ],
"source": [ "source": [
"DOMAIN = Domain(x=N, boundaries=PERIODIC, bounds=Box[-1:1])\n", "velocity = CenteredGrid(INITIAL, extrapolation.PERIODIC, x=N, bounds=Box[-1:1])\n",
"velocity = DOMAIN.scalar_grid(INITIAL)\n", "#velocity = CenteredGrid(Noise(), extrapolation.PERIODIC, x=N, bounds=Box[-1:1]) # random init\n",
"#velocity = DOMAIN.grid(Noise(vector=1)) # random init instead of sine curve\n",
"\n", "\n",
"print(\"Velocity tensor shape: \" + format( velocity.shape )) # == velocity.values.shape\n", "print(\"Velocity tensor shape: \" + format( velocity.shape )) # == velocity.values.shape\n",
"print(\"Velocity tensor type: \" + format( type(velocity.values) ))\n", "print(\"Velocity tensor type: \" + format( type(velocity.values) ))\n",
@@ -131,7 +135,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 8, "execution_count": 4,
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{ {
@@ -158,7 +162,7 @@
"cell_type": "markdown", "cell_type": "markdown",
"metadata": {}, "metadata": {},
"source": [ "source": [
"Here we're actually collecting all time steps in the list `vels`. This is not necessary in general (and could consume lots of memory for long-running sims), but useful here to plot the evolution of the velocity states later on.\n", "Here we're actually collecting all time steps in the list `velocities`. This is not necessary in general (and could consume lots of memory for long-running sims), but useful here to plot the evolution of the velocity states later on.\n",
"\n", "\n",
"The print statements print a few of the velocity entries, and already shows that something is happening in our simulation, but it's difficult to get an intuition for the behavior of the PDE just from these numbers. Hence, let's visualize the states over time to show what is happening.\n", "The print statements print a few of the velocity entries, and already shows that something is happening in our simulation, but it's difficult to get an intuition for the behavior of the PDE just from these numbers. Hence, let's visualize the states over time to show what is happening.\n",
"\n", "\n",
@@ -169,16 +173,16 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 14, "execution_count": 5,
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"<matplotlib.legend.Legend at 0x7fe4d809d190>" "<matplotlib.legend.Legend at 0x7f9ca2d4ef70>"
] ]
}, },
"execution_count": 14, "execution_count": 5,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
}, },
@@ -222,7 +226,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 17, "execution_count": 6,
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{ {
@@ -277,7 +281,8 @@
"\n", "\n",
"Some things to try based on this simulation setup:\n", "Some things to try based on this simulation setup:\n",
"\n", "\n",
"- Feel free to experiment - the setup above is very simple, you can change the simulation parameters, or the initialization. E.g., you can use a noise field via `Noise(vector=1)` to get more chaotic results.\n", "- Feel free to experiment - the setup above is very simple, you can change the simulation parameters, or the initialization. E.g., you can use a noise field via `Noise()` to get more chaotic results (cf. the comment in the `velocity` cell above).\n",
"\n",
"- A bit more complicated: extend the simulation to 2D (or higher). This will require changes throughout, but all operators above support higher dimensions. Before trying this, you probably will want to check out the next example, which covers a 2D Navier-Stokes case." "- A bit more complicated: extend the simulation to 2D (or higher). This will require changes throughout, but all operators above support higher dimensions. Before trying this, you probably will want to check out the next example, which covers a 2D Navier-Stokes case."
] ]
} }
+70 -51
View File
@@ -8,7 +8,7 @@
"source": [ "source": [
"# Navier-Stokes Forward Simulation\n", "# Navier-Stokes Forward Simulation\n",
"\n", "\n",
"Now let's target a somewhat more complex example: a fluid simulations based on the Navier-Stokes equations. This is still very simple with Φ<sub>Flow</sub>, as differentiable operators for all steps exist. The Navier-Stokes equations (in their incompressible form) introduce an additional pressure field $p$, and a constraint for conservation of mass, as introduced in equation {eq}`model-boussinesq2d`. We're also moving a marker field, denoted by $d$ here, with the flow. It indicates regions of higher temperature, and excerts a force via with a bouyancy factor $\\xi$:\n", "Now let's target a somewhat more complex example: a fluid simulations based on the Navier-Stokes equations. This is still very simple with Φ<sub>Flow</sub> (phiflow), as differentiable operators for all steps exist. The Navier-Stokes equations (in their incompressible form) introduce an additional pressure field $p$, and a constraint for conservation of mass, as introduced in equation {eq}`model-boussinesq2d`. We're also moving a marker field, denoted by $d$ here, with the flow. It indicates regions of higher temperature, and excerts a force via with a bouyancy factor $\\xi$:\n",
"\n", "\n",
"$$\\begin{aligned}\n", "$$\\begin{aligned}\n",
" \\frac{\\partial \\mathbf{u}}{\\partial{t}} + \\mathbf{u} \\cdot \\nabla \\mathbf{u} &= - \\frac{\\Delta t}{\\rho} \\nabla p + \\nu \\nabla\\cdot \\nabla \\mathbf{u} + (0,1)^T \\xi d\n", " \\frac{\\partial \\mathbf{u}}{\\partial{t}} + \\mathbf{u} \\cdot \\nabla \\mathbf{u} &= - \\frac{\\Delta t}{\\rho} \\nabla p + \\nu \\nabla\\cdot \\nabla \\mathbf{u} + (0,1)^T \\xi d\n",
@@ -29,7 +29,7 @@
"source": [ "source": [
"## Implementation\n", "## Implementation\n",
"\n", "\n",
"As in the previous section, 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.)" "As in the previous section, the first command with a \"!\" prefix installs the [phiflow python package from GitHub](https://github.com/tum-pbs/PhiFlow) via `pip` in your python environment. (Skip or modify this command if necessary.)"
] ]
}, },
{ {
@@ -46,6 +46,7 @@
"source": [ "source": [
"#!pip install --upgrade --quiet git+https://github.com/tum-pbs/PhiFlow@develop\n", "#!pip install --upgrade --quiet git+https://github.com/tum-pbs/PhiFlow@develop\n",
"#!pip install --upgrade --quiet phiflow \n", "#!pip install --upgrade --quiet phiflow \n",
"\n",
"from phi.flow import * # The Dash GUI is not supported on Google Colab, ignore the warning\n", "from phi.flow import * # The Dash GUI is not supported on Google Colab, ignore the warning\n",
"import pylab" "import pylab"
] ]
@@ -58,8 +59,9 @@
"source": [ "source": [
"## Setting up the simulation\n", "## Setting up the simulation\n",
"\n", "\n",
"The following code sets up a simulation domain with the physical size, an inflow object to emit a smoke density, and three field: a staggerend `velocity` grid, and two centered grids for the smoke density and a pressure field. We'll use $40\\times32$ cells to discretize our domain, introduce a slight viscosity via $\\nu$, and define the time step to be $\\Delta t=1.5$. \n", "The following code sets up a few constants, which are denoted by upper case names. We'll use $40\\times32$ cells to discretize our domain, introduce a slight viscosity via $\\nu$, and define the time step to be $\\Delta t=1.5$. \n",
"(As the following variables are constants, they have upper case names.)" "\n",
"We're creating a first `CenteredGrid` here, which is initialized by a `Sphere` geometry object. This will represent the inflow region `INFLOW` where hot smoke is generated."
] ]
}, },
{ {
@@ -70,11 +72,10 @@
}, },
"outputs": [], "outputs": [],
"source": [ "source": [
"DOMAIN = Domain(x=40, y=32, boundaries=CLOSED, bounds=Box[0:100, 0:80])\n",
"INFLOW = DOMAIN.grid(Sphere(center=(30, 15), radius=10)) * 0.2\n",
"\n",
"DT = 1.5\n", "DT = 1.5\n",
"NU = 0.01" "NU = 0.01\n",
"\n",
"INFLOW = CenteredGrid(Sphere(center=(30,15), radius=10), extrapolation.BOUNDARY, x=32, y=40, bounds=Box[0:80, 0:100]) * 0.2\n"
] ]
}, },
{ {
@@ -83,12 +84,11 @@
"id": "ExA0Pi2sFVka" "id": "ExA0Pi2sFVka"
}, },
"source": [ "source": [
"The inflow will be used to inject smoke into the `smoke` grid to represent the marker field $d$ from above. Note that we've defined a `Box` of size $100x80$ above. This is the physical scale in terms of spatial units in our simulation, i.e., a velocity of magnitude $1$ will move the smoke density by 1 unit per 1 time unit, which may be larger or smaller than a cell in the discretized grid, depending on the settings for `x,y`. You could parametrize your simulation grid to directly resemble real-world units, or keep conversion factors in mind for conversion. \n", "The inflow will be used to inject smoke into a second centered grid `smoke` grid that represents the marker field $d$ from above. Note that we've defined a `Box` of size $100x80$ above. This is the physical scale in terms of spatial units in our simulation, i.e., a velocity of magnitude $1$ will move the smoke density by 1 unit per 1 time unit, which may be larger or smaller than a cell in the discretized grid, depending on the settings for `x,y`. You could parametrize your simulation grid to directly resemble real-world units, or keep conversion factors in mind for conversion. \n",
"\n", "\n",
"The inflow sphere above is already using the \"world\" coordinates: it is located at $x=30$ along the first axis, and $y=15$ (within the $100x80$ domain box).\n", "The inflow sphere above is already using the \"world\" coordinates: it is located at $x=30$ along the first axis, and $y=15$ (within the $100x80$ domain box).\n",
"\n", "\n",
"Next, we create grids for the quantities we want to simulate. For this example, we require a velocity field and a smoke density field.\n", "Next, we create grids for the quantities we want to simulate. For this example, we require a velocity field and a smoke density field."
"We sample the smoke field at the cell centers and the velocity in [staggered form](https://tum-pbs.github.io/PhiFlow/Staggered_Grids.html)."
] ]
}, },
{ {
@@ -97,15 +97,17 @@
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"smoke = DOMAIN.scalar_grid(0) # sampled at cell centers\n", "smoke = CenteredGrid(0, extrapolation.BOUNDARY, x=32, y=40, bounds=Box[0:80, 0:100]) # sampled at cell centers\n",
"velocity = DOMAIN.staggered_grid(0) # sampled in staggered form at face centers " "velocity = StaggeredGrid(0, extrapolation.ZERO, x=32, y=40, bounds=Box[0:80, 0:100]) # sampled in staggered form at face centers "
] ]
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": {}, "metadata": {},
"source": [ "source": [
"Let's define the update step, and plot the marker density after one simulation frame." "We sample the smoke field at the cell centers and the velocity in [staggered form](https://tum-pbs.github.io/PhiFlow/Staggered_Grids.html). The staggered grid internally contains 2 centered grids with different dimensions, and can be converted into centered grids (or simply numpy arrays) via the `unstack` function, as explained in the link above.\n",
"\n",
"Next we define the update step of the simulation, which calls the necessary functions to advance the state of our fluid system by `dt`. The next cell computes one such step, and plots the marker density after one simulation frame."
] ]
}, },
{ {
@@ -124,13 +126,13 @@
"name": "stdout", "name": "stdout",
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"Max. velocity and mean density: [0.135354, 0.007865495]\n" "Max. velocity and mean marker density: [0.15530995, 0.008125]\n"
] ]
}, },
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"<matplotlib.image.AxesImage at 0x7fa14cffd5b0>" "<matplotlib.image.AxesImage at 0x7fb319d14f10>"
] ]
}, },
"execution_count": 4, "execution_count": 4,
@@ -139,7 +141,7 @@
}, },
{ {
"data": { "data": {
"image/png": "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\n", "image/png": "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\n",
"text/plain": [ "text/plain": [
"<Figure size 432x288 with 1 Axes>" "<Figure size 432x288 with 1 Axes>"
] ]
@@ -154,14 +156,14 @@
"def step(velocity, smoke, pressure, dt=1.0, buoyancy_factor=1.0):\n", "def step(velocity, smoke, pressure, dt=1.0, buoyancy_factor=1.0):\n",
" smoke = advect.semi_lagrangian(smoke, velocity, dt) + INFLOW\n", " smoke = advect.semi_lagrangian(smoke, velocity, dt) + INFLOW\n",
" buoyancy_force = smoke * (0, buoyancy_factor) >> velocity # resamples smoke to velocity sample points\n", " buoyancy_force = smoke * (0, buoyancy_factor) >> velocity # resamples smoke to velocity sample points\n",
" velocity = advect.semi_lagrangian(velocity, velocity, 1) + dt * buoyancy_force\n", " velocity = advect.semi_lagrangian(velocity, velocity, dt) + dt * buoyancy_force\n",
" velocity = diffuse.explicit(velocity, NU, dt)\n", " velocity = diffuse.explicit(velocity, NU, dt)\n",
" velocity, pressure, iterations, divergence = fluid.make_incompressible(velocity, DOMAIN, pressure_guess=pressure)\n", " velocity, pressure = fluid.make_incompressible(velocity)\n",
" return velocity, smoke, pressure\n", " return velocity, smoke, pressure\n",
"\n", "\n",
"velocity, smoke, pressure = step(velocity, smoke, None, dt=DT)\n", "velocity, smoke, pressure = step(velocity, smoke, None, dt=DT)\n",
"\n", "\n",
"print(\"Max. velocity and mean density: \" + format( [ math.max(velocity.values) , math.mean(smoke.values) ] ))\n", "print(\"Max. velocity and mean marker density: \" + format( [ math.max(velocity.values) , math.mean(smoke.values) ] ))\n",
"\n", "\n",
"pylab.imshow(np.asarray(smoke.values.numpy('y,x')), origin='lower', cmap='magma')" "pylab.imshow(np.asarray(smoke.values.numpy('y,x')), origin='lower', cmap='magma')"
] ]
@@ -172,7 +174,7 @@
"source": [ "source": [
"A lot has happened in this `step()` call: we've advected the smoke field, added an upwards force via a Boussinesq model, advected the velocity field, and finally made it divergence free via a pressure solve.\n", "A lot has happened in this `step()` call: we've advected the smoke field, added an upwards force via a Boussinesq model, advected the velocity field, and finally made it divergence free via a pressure solve.\n",
"\n", "\n",
"The Boussinesq model uses a multiplication by a tuple `(0, buoyancy_factor)` to turn the smoke field into a 2 component force field, sampled at the staggered velocity components via the `>>` operator. \n", "The Boussinesq model uses a multiplication by a tuple `(0, buoyancy_factor)` to turn the smoke field into a 2 component force field, sampled at the staggered velocity components via the `>>` operator. **TODO, write out**\n",
"\n", "\n",
"The pressure projection step in `make_incompressible` is typically the computationally most expensive step in the sequence above. It solves a Poisson equation for the boundary conditions of the domain, and updates the velocity field with the gradient of the computed pressure.\n", "The pressure projection step in `make_incompressible` is typically the computationally most expensive step in the sequence above. It solves a Poisson equation for the boundary conditions of the domain, and updates the velocity field with the gradient of the computed pressure.\n",
"\n", "\n",
@@ -180,9 +182,9 @@
"\n", "\n",
"## Datatypes and dimensions\n", "## Datatypes and dimensions\n",
"\n", "\n",
"The created grids are instances of the class `Grid`.\n", "The variables we created for the fields of the simulation here are instances of the class `Grid`.\n",
"Like tensors, grids also have the `shape` attribute which lists all batch, spatial and channel dimensions.\n", "Like tensors, grids also have the `shape` attribute which lists all batch, spatial and channel dimensions.\n",
"[Shapes in Φ<sub>Flow</sub>](https://tum-pbs.github.io/PhiFlow/Math.html#shapes) store not only the sizes of the dimensions but also their names and types." "[Shapes in phiflow](https://tum-pbs.github.io/PhiFlow/Math.html#shapes) store not only the sizes of the dimensions but also their names and types."
] ]
}, },
{ {
@@ -194,10 +196,10 @@
"name": "stdout", "name": "stdout",
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"Smoke: (x=40, y=32)\n", "Smoke: (xˢ=32, yˢ=40)\n",
"Velocity: (x=40, y=32, vector=2)\n", "Velocity: (xˢ=32, yˢ=40, vectorᵛ=2)\n",
"Inflow: (x=40, y=32)\n", "Inflow: (xˢ=32, yˢ=40)\n",
"Inflow, spatial only: (x=40, y=32)\n" "Inflow, spatial only: (xˢ=32, yˢ=40)\n"
] ]
} }
], ],
@@ -205,15 +207,16 @@
"print(f\"Smoke: {smoke.shape}\")\n", "print(f\"Smoke: {smoke.shape}\")\n",
"print(f\"Velocity: {velocity.shape}\")\n", "print(f\"Velocity: {velocity.shape}\")\n",
"print(f\"Inflow: {INFLOW.shape}\")\n", "print(f\"Inflow: {INFLOW.shape}\")\n",
"print(f\"Inflow, spatial only: {INFLOW.shape.spatial}\")\n", "print(f\"Inflow, spatial only: {INFLOW.shape.spatial}\")\n"
"\n"
] ]
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": {}, "metadata": {},
"source": [ "source": [
"The grid values can be accessed using the `values` property." "Note that the phiflow output here indicates the type of a dimension, e.g., $^V$ for a vector dimension. Later on for learning, we'll also introduce batch dimensions.\n",
"\n",
"The grid values can be accessed using the `values` property. This is an important difference to a phiflow tensor object, which does not have `values`, as illustrated in the code example below."
] ]
}, },
{ {
@@ -225,16 +228,24 @@
"name": "stdout", "name": "stdout",
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"(x=40, y=32) float32 0.0 < ... < 0.2\n", "Statistics of the different simulation grids:\n",
"(x=(41, 40) along vector, y=(32, 33) along vector, vector=2) float32 -0.10927753 < ... < 0.135354\n", "(xˢ=32, yˢ=40) float32 0.0 < ... < 0.20000000298023224\n",
"(x=40, y=32) float32 0.0 < ... < 0.2\n" "(xˢ=(31, 32), yˢ=(40, 39), vectorᵛ=2) float32 -0.12352858483791351 < ... < 0.15530994534492493\n",
"(xˢ=32, yˢ=40) float32 0.0 < ... < 0.20000000298023224\n",
"Reordered test tensor shape: (3, 5, 2)\n"
] ]
} }
], ],
"source": [ "source": [
"print(\"Statistics of the different simulation grids:\")\n",
"print(smoke.values)\n", "print(smoke.values)\n",
"print(velocity.values)\n", "print(velocity.values)\n",
"print(INFLOW.values)" "print(INFLOW.values)\n",
"\n",
"# in contrast to a simple tensor:\n",
"test_tensor = math.tensor(numpy.zeros([2, 5, 3]), spatial('x,y'), channel('vector'))\n",
"print(\"Reordered test tensor shape: \" + format(test_tensor.numpy('vector,y,x').shape) )\n",
"#print(test_tensor.values.numpy('y,x')) # error! tensors don't return their content via \".values\"\n"
] ]
}, },
{ {
@@ -242,8 +253,7 @@
"metadata": {}, "metadata": {},
"source": [ "source": [
"Grids have many more properties which are documented [here](https://tum-pbs.github.io/PhiFlow/phi/field/#phi.field.Grid).\n", "Grids have many more properties which are documented [here](https://tum-pbs.github.io/PhiFlow/phi/field/#phi.field.Grid).\n",
"Also note that the staggered grid has a [non-uniform shape](https://tum-pbs.github.io/PhiFlow/Math.html#non-uniform-tensors) because the number of faces is not equal to the number of cells. The `INFLOW` grid naturally has the same dimensions as the `smoke` grid.\n", "Also note that the staggered grid has a [non-uniform shape](https://tum-pbs.github.io/PhiFlow/Math.html#non-uniform-tensors) because the number of faces is not equal to the number of cells (in this example the x component has $31 \\times 40$ cells, while y has $32 \\times 39$). The `INFLOW` grid naturally has the same dimensions as the `smoke` grid.\n"
"\n"
] ]
}, },
{ {
@@ -270,16 +280,16 @@
"name": "stdout", "name": "stdout",
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"Computed frame 0, max velocity 0.40485728\n", "Computed frame 0, max velocity 0.4609803557395935\n",
"Computed frame 1, max velocity 0.80262446\n", "Computed frame 1, max velocity 0.8926814794540405\n",
"Computed frame 2, max velocity 1.3215623\n", "Computed frame 2, max velocity 1.4052708148956299\n",
"Computed frame 3, max velocity 1.99783\n", "Computed frame 3, max velocity 2.036500930786133\n",
"Computed frame 4, max velocity 2.8307805\n", "Computed frame 4, max velocity 2.921010971069336\n",
"Computed frame 5, max velocity 3.756278\n", "Computed frame 5, max velocity 3.828195810317993\n",
"Computed frame 6, max velocity 4.5489845\n", "Computed frame 6, max velocity 4.516851425170898\n",
"Computed frame 7, max velocity 5.147038\n", "Computed frame 7, max velocity 4.861286640167236\n",
"Computed frame 8, max velocity 5.5985193\n", "Computed frame 8, max velocity 5.125314235687256\n",
"Computed frame 9, max velocity 6.0121617\n" "Computed frame 9, max velocity 5.476282119750977\n"
] ]
} }
], ],
@@ -313,7 +323,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"<matplotlib.image.AxesImage at 0x7fa148246700>" "<matplotlib.image.AxesImage at 0x7fb31a2bc2b0>"
] ]
}, },
"execution_count": 8, "execution_count": 8,
@@ -322,7 +332,7 @@
}, },
{ {
"data": { "data": {
"image/png": "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 truncated "image/png": "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 truncated
"text/plain": [ "text/plain": [
"<Figure size 432x288 with 1 Axes>" "<Figure size 432x288 with 1 Axes>"
] ]
@@ -370,7 +380,7 @@
}, },
{ {
"data": { "data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAA54AAACqCAYAAADFjJDBAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/Il7ecAAAACXBIWXMAAAsTAAALEwEAmpwYAAAwlElEQVR4nO3deZxkZXkv8N9T1Xv39HTPyiwwDNvAMMoiQZCgCAioUYkaRRTxunBvYhKz3YhJiDE30cRPolnMNSGByxIUYlQgsiggBoWRZWSG2ZiVWXumZ7qn96ru2t77RxdV9Xtneu/Tder07/v59GfO0+dUnXe6nzpVp8/7nMeccxAREREREREJSqzcAxAREREREZFo04mniIiIiIiIBEonniIiIiIiIhIonXiKiIiIiIhIoHTiKSIiIiIiIoHSiaeIiIiIiIgESiee08zM7jKzvyj3OESCohyXKFE+S9QpxyXqlOOVQyeeIWJme8zs6lHWX2FmB6bw/L9rZofNrNfM7jSz2sk+l8hkBJnjZvYJM8uaWX/J1xWTHavIWALO5zVm9kMz6zCz4xpum9k8M/u+mQ2Y2V4zu3Ey+xEZTZlz/CdmNlhyPN82mf2IjCbgHL/ZzNblP3cfMLOvmllVyfpZdxzXiecsYWbXArgVwFUAVgA4DcCXyjookem31jnXVPL1k3IPSGSS0gD+A8CnRlj/TwBSABYD+CiAb5rZuTM0NpHpMFaOA8BvlhzPV83QuESmSwOA3wGwAMCbMfwZ/A9K1s+647hOPKfIzC4ws1+YWZ+ZPQCgbpRtTzezH5tZZ/4vfPeZWUt+3b0ATgHwX/m/7P2h99hGAI8BWFry17+lExjqzQDucM5tds51Afg/AD4xof+szEoVlOMiY6qUfHbObXPO3QFg8wnG1QjgAwBuc871O+d+BuBhADeN9/kluqKQ4yKjqaAc/6Zz7qfOuZRz7iCA+wBcVvLcs+44rhPPKTCzGgAPArgXwDwA38FwEo34EABfAbAUwDkATgbwZwDgnLsJwD4A78n/Ze+rpQ90zg0AeCeAtpK//rWZ2Y1m1j3K1yn5pzgXwIaSp9wAYLGZzZ/SD0EircJyHAAuyL+xbDez20qntIhUYD6P5CwAGefc9pLvbcDwcV5msQjl+Ou+kj+mP2sqnRBUfI6/FcU/tMzK47g+lE3NJQCqAfydc84B+E8z+72RNnbO7QSwMx8eNbOvAfjiVAbgnPsWgG+NY9MmAD0l8evLcwB0TmUMEmmVlOPPAFgDYC+GD9wPAMhg+A1HBKisfB5NE4Be73s9GD6ey+wWlRwHgM8D2ILhqYg3YPiq1PnOuV3T8NxSuSoyx83skwAuAvDp/Ldm5XFcJ55TsxTAwXziv27vSBub2WIAfw/gcgwnVgxAV6AjLOoH0FwSv77cN0P7l8pUMTnunNtdEm40sz8H8L+hE08pqph8HoN/PEc+1vFcopLjcM49XxLebWYfAfAuAP9YpiFJOFRcjpvZ9Rj+LHK1c64j/+1ZeRzXVNupOQRgmZlZyfdGm0LyZQAOwBucc80APobhKQCvO+6ubp4T3fXto8Z38fS/Xh/PZgDnlTz0PADtzjld7ZTRVFKOn+i5bIR1MjtVcj6X2g6gyszOLPneeVCtnEQnx0fal47pUlE5bmbXAfhXDE/n3VjyNLPyOK4Tz6lZi+GpfL9tZtVm9n4AF4+y/RwM/4Wjx8yWYfhqTKl2DN9tdiTtAOab2dzXv+Gcu8+7i6f/tS+/6T0APmVmq224qPpPANw1gf+rzE4Vk+Nm9s78XzZhZmcDuA3AQxP8/0q0VVI+m5nVAajJx3WWb4GVrzv6HoA/N7NGM7sMwPswXPMks1skctzMWszs2vz3qszsoxiuj3t8Ij8MiaRKyvErMXxDoQ84514ofdLZehzXiecUOOdSAN6P4bvDHgPwYQwn0Ui+BOBCDM/hfuQE234FwJ/YcGHyH/gPds69CuDbAHbnt5nInbUeB/BVAE9juJB6L6Y4x12ir5JyHMO3KX/FzAYAPJrf95cn8HiJuArL5xUAkij+9TsJoLSP4W8AqAdwJL+PX3fORfov5TK2COV4NYC/AHAUQAeA3wJwvXcjFpmFKizHbwMwF8CjJVdDHytZP+uO48ZTpEVERERERESml654ioiIiIiISKB04ikiIiIiIiKB0omniIiIiIiIBEonniIiIiIiIhIonXiKiIiIiIhIoKpmcmdmplvoykzocM4tLMeOleMyE5xzZWmirvyWGaJjuERdheY4v/XEYrUU11gDxXXg9dXe5a64FZ8v5r2r+W9y/qCPi71v5Lz12Vxxg5y3bdZ7tqz36Cyy3nOneb3jOOcyJePix479P4mME+b4jJ54DovP/C5llsnuLe/+leMSJP9NbKYpvyVoOoZL1FVmjpvVUNxUt5LipbXnUbzaTqd4SQOfdsytKZ5eeqsQ9848s975Wdo7sxz03hqTXtyXKj6g33twX5ZPHHtcguLeWDdv747y+kwbjyV1rLCcyvBjc7khHljZ39ODcuIcH3OqrZnVmdkLZrbBzDab2Zfy319pZs+b2U4ze8D8bBSpEMpxiTLlt0SdclyiTjkuUWHOvzbtb2BmABqdc/1mVg3gZwA+B+D3AHzPOXe/mf0zgA3OuW+O8VxOf0mU4GXXOecuGu/WynGpLNkJTbVVfkvl0TFcoq5ycjweby4snzfnQ7Tu86fxTMpfectrFNeeVsf7bq3nuL5kKm6NNyYb49qY8y55+vNnUxkK3VDJVc2ENzV2wIv7OM508b6SHXx59kjHHIpfPDqvsPyTdn67/tnQFor39T9H8VCar6ZW7hXRE+f4mFc83bD+fFid/3IArgTwn/nv3w3g+ukZqMjMUo5LlCm/JeqU4xJ1ynGJinHd1dbM4ma2HsARAE8A2AWg27lC9ewBAMtGeOwtZvaSmb00DeMVCYRyXKJM+S1RpxyXqFOOSxSM68TTOZd1zp0PYDmAiwGcPd4dOOdud85dNJEpBSIzTTkuUab8lqhTjkvUKcclCiZ0V1vnXLeZPQ3gUgAtZlaV/0vLcgAHgxigyExSjkuUKb8l6mZPjvtl3lNty+43nygV2XYPFWmmc7yxdklh+ealS2jdr753N8XxM7jm02q804wqv59KSV1nzFvn91c5Lh5je69G1ErXe/Wgca9eNJ7huspqr160Ps1xayJF8ZkH9hWWr3iO7/d07/Y1FP+7dyq2s+9JijOZY4iS8dzVdqGZteSX6wG8A8BWAE8D+GB+s5sBPBTQGEUCpRyXKFN+S9QpxyXqlOMSFeO54rkEwN1mFsfwiep/OOd+YGZbANxvZn8B4GUAdwQ4TpEgKcclypTfEnXKcYk65bhEwpgnns65VwBccILv78bwHHORiqYclyhTfkvUKccl6pTjEhUTqvEUERERkcngGrSWpnMp/sCc6yn+7XO6CstrPjDEzzS/adQ9ub4kxdlDAxT3b+Mat/W7TyosP9LWSOse7t1E8c7uR3lfbnDUsUil4Tw9p/rKwvKNa/bQuvjJ3L8SXu2jy3LtpNVW8/a1JRV/jbW8zq8PrfXWjyXH+3Y11SNsCFiK+3Ye1yPUq/n0e4RaPdd4xhuKdZ3L5/bSuk9W76X46Dq+R9SRzHaKj/X1eKOt1L6ew6ZajS4iIiIiIiIyKp14ioiIiIiISKB04ikiIiIiIiKBUo2niIiIyLTjWrllLVdQfMeqiyh++zVeT8RF9YVll+WaTHe0b0IjibVyfVzzm/n53npJd2H58oGjtO6PN9ZT/G/r/pDivz30BMXtPWsnNDYJF0Oc4jUN8wvLLef30zqX4NpIl+TaR2S8Wkmv12ZsTkmPyzrOaavn/pdorOP4uBpQb/s5XKtspTWfSa8u2e8JGo97671etnXevkZhC7kOduGl3Jfz8n1cH/pE3zkUd9mrFDunGk8RERERERGREenEU0RERERERAKlqbYiIiIi02x5y5UUP3XxGRSfdmU7xVblTd9zxel9Vu+1gvCnGRpPYfSnNCLnTRXMetP1SqZEmvfY5kv4sb/35gMUX3L/pRR/eusyind0PUixgzcdU0LFYjyldU1rMR+sifMw18VtftJH+Hc71MPXt6pqOJfqVxbj+Bvm8UBaeYqqa5nL6+t4+rj1cNsSHO7kuGSqrlvA+7L2o962PL38uKm3/lRdv/1KqWp+rcYWcyukN8zvoviknSdRvN37fWSyld2+SFc8RUREREREJFA68RQREREREZFA6cRTREREREREAqUaTxEREZEpqqleRPHXT7+Y4tOvOUSxy3l1mDV8LcAaa0qW/VYSXs2ZX4Pmm0CNp0txnZ4lud2DS/FjL/0Vro/7s+RZFP/PoZUU9yV2jD5WKauaqmaK3zg3WVh2/dw+xa/pbN/N9YuHerlOc159kuJT6rsLy3Wt3GbEzzvrS/gD5diry8zt4bzse7G478aV/NrLJbhGs/psrie1BfwzOW7fPv/1Vvpc1fxanT+vh+KWuFd/atE6VdMVTxEREREREQmUTjxFREREREQkUDrxFBERERERkUBFa+KwiIjMerFYgxdzfVw2w/3e1FdQpsPFDTdQ/L737KPYpbwaTr9O0+/FWVWyfqyazph3HSHj1XD6NZ2j1ISa99HQOa5XM79+zevt+KGb2ij+0Vc/TPG9Q/9QMiyv96KUXU0V12U2VhXrOnNJzqPEEf7dbz46n+K1ndxr86R6rgH96IL+wnJdE2+LFdzPkl4PALJPbaT45UdbKf6XHUt4LIO7Css575h/ddMqij++kvPyzFO5d23z272eol6vTmso6ck7Sr0nAKRT/P8ayvHPOOe41rXS6YqniIiIiIiIBEonniIiIiIiIhIonXiKiIiIiIhIoFTjKSIioVMVb6H4qqZPU/x3Fxdrg1b9BtckYTHX+hwn7r31Zbnep+efN1H8uz86rbD8QNddtC45xLU/MruYFeuH/2iV12szxjWbLsWLine truncated "image/png": "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 truncated
"text/plain": [ "text/plain": [
"<Figure size 1152x360 with 5 Axes>" "<Figure size 1152x360 with 5 Axes>"
] ]
@@ -410,7 +420,7 @@
"outputs": [ "outputs": [
{ {
"data": { "data": {
"image/png": "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 truncated "image/png": "iVBORw0KGgoAAAANSUhEUgAAA6IAAAD2CAYAAADMDzr7AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/Il7ecAAAACXBIWXMAAAsTAAALEwEAmpwYAABcCUlEQVR4nO29e7Bs6Vne97zr0t37dvY+9zlz0YykEZJGgEbJIKQC2UgESoiiwIQkQEyUsohwYlJQUDEKTmIgYEOwUcoFJhZGHpHiGiMHGdvEihARsrGkkTS6DtKM5qKZ0Zz72fe+95c/dg/sXu9z5nynu/fq7nWeX9Wpc/Z71uVb33rWt9bavb/fthAChBBCCCGEEEKIskhm3QAhhBBCCCGEELcWehEVQgghhBBCCFEqehEVQgghhBBCCFEqehEVQgghhBBCCFEqehEVQgghhBBCCFEqehEVQgghhBBCCFEqehEVQgghhBBCCFEqehEVQgghhBBCCFEqehFdAMzsT8zsB1/g/+8xs2Bm2Zjb/34ze8rM9szs/zazE+O3Voib5ygzbmbfZGYDM9s99Oetk7VYiBfmiDN9zszeZ2ZfGW7jnsL/183s3Wa2bWbnzezHxjgEIV6QGWf8QTPrFMb1dIzDEIJyxPn+djP7sJltDsfof2pma4f+/5YZw/UieotjZq8C8E8A/ACAswD2AfzjmTZKiOnzlRDC6qE/75l1g4SYgAGAPwLwn17n/38KwMsA3A3gjQD+tpm9uZymCTEVbpRxAPjfCuN6v6S2CTEp6wB+FsDtAF4J4A4Av3jo/38Kt8gYrhfRCIbf8bj30NcPmtnP3mCdnzCzjzz/nRIz+2/N7HNm1iDLHjezPzSzS2Z2bfjvO4f/93MA3gDgl4ff8ftlsrsPDf/eHC7z+ps4vP8SwL8MIXwohLAL4H8G8N2HvzMjqk/FMy5uQaqc6RDChRDCPwbwsess8lYA/2sI4VoI4REAvwbgv47dvlgMbvGMi4pT8Xz/Vgjhj0II+yGEazgYo7/h0CK3zBiuF9Gj4xcBtAH8T2b2MgB/D8BfDyG0yLIJgH+Gg+98vAhAE8AvA0AI4e8A+FMAPzz8jt8Pk/X/yvDvjeEyf2Zm3zj8yP96f75xuM6rAHzq+Q2FEL4EoAPgqybtAFF5FiXjAHDGzC6Y2RNm9k4zW5lKD4iqsUiZppjZcQDncGhcH/77VTEdICrPwmf8EP+dmV01s4+b2Qt9cipuHRY1338FwOeAW28MH2tOobgxIYSBmf1XAD4B4L/AwY+QfPI6y14B8PvPfz38TswHJ9z/hwFsRCy6CmCrUNsCoE9ExQuyQBn/cwD3D/++G8B7APwSgB+aZP+ieixQpl+I1eHfh8d1jekCQGUyDgD/CMCP4yDb3wrgd83sfAjh301h22JBWcR8m9m34OAT0K8flm6pMVyfiB4hIYQncRDqewD8yvWWM7NlM/sndiAM2sbBx/0bVs7E+10Axwq1YwB2Sti3WHAWIeMhhPMhhM+HEAYhhCcA/G288LwjcQuzCJm+AbvDvw+P6xrTxV9QgYwjhPCJEMKVEEIvhPCvAfwmgO+edbvE7FmkfJvZ6wD8FoDvCSF8cVi+pcZwvYjGsQ9g+dDXt8WsZGbfDuD1AD6A0UnIRX4cwMsBfH0I4Rj+8uN+G/4dbrAr9/9m9gYbtckV/7xhuOjnALz60HovAVAH8MXiNkWlqXLG2bY09lWfWynTf7nRg/lGz+HQuD789+dutK5YOG7JjL/AvuyGS4lFotL5NrPXAHgfgL8RQvjAX2z0FhvD9TAWx8MAvt/MUjuwVv3VG61gZqcA/FMAP4iDj9y/w8zecp3F13Dws+mbdvCrU/5u4f8vAHjJC+zuEg4Mc3+xTAjhTws2ueKfPx0u+pvDtr3BDubN/QyA94YQKvmdF3FdHkZFM25mbzSzu+2AuwD8PIA/uNHxiYXnYVQ008O2NnDwTUMAqNuojOM3cDBH6riZvQLAfwPgwRc+erGAPIxbNONm9j1mtmpmiZl9K4C/joOHelEdHkZF821mX40DK/R/H0L4l2Tbt84YHkLQnxv8AfAADr4TsQPg/wTw2wB+9gbrvBfA/3Ho628D8BUAJ8mytwP4Exx8HP9FHMxdCwCy4f+/fli/BuAfXWd/P4ODi2ITwOtu8vi+H8CXAezh4AH9xKz7XH/K/VPljAP4MQDP4uC7q0/jYG7R2qz7XH+O9k+VMz1cNxT/HPq/OoB3A9jGwcPUj836fOjP9P/c4hn/UxzMm9vGgcjle2d9PvRnun+qnG8cSJIGw30//+dzh/7/lhnDbXjAQgghhBBCCCFEKehHc4UQQgghhBBClIpeRCfAzH7yOpOR/82s2ybENFDGRdVQpkXVUcZFlVG+q4V+NFcIIYQQQgghRKnoE1EhhBBCCCGEEKWSlbmz9Ww5nKmvl7nLm8Lm+DdQldG0WX02Pu0P5R/bP385hHB6uluN49gcZbyMzMzzNTNtpp3TSTb3pRllnOV72hGIzRRfzPcqWy5+H3FnadzrIHb7sYQJzgbLd+z2+Lpx22PrznIMX8uWw+naRun7ZRli+WBnJDG/XEIW5MuRWkL2S5azwnL0Opj2AMGyNiC1wLLma4PIdQdse+Tg2HKDOcv4SroSNvKNkVqftLFHGs6W68N34uA6I0ARI32YkM/IMhKuGgl5LfX7aJA819Keq+V1fxxJvdCWWuqWQUZqCfmcj10LLBx9Espen9T8cqFLzoU/VPR7vn39Aav5RvdJxlntieZzURkv9UX0TH0d73zV3xhrXTZYxhI7DsbuY5JxddzjYDeVacOuh/h1Ix9YSlj3Oz72956K2uARcKa+jl+8721jrRv74wnsgWCS7U2S+zKumVlQRk7JrYY/AJHlvvuhn5tJxs/U1/FLhTF8kpzFZootl5GHi9R8b6Vke6zG9kvXZftNyAMMbvyQPsl9jUEfltlzToh94PDL9SIfTLrkoYbV2Lpv+ejfn9kYfrq2gZ97xQ+O1Ni9cZKXfvaCmZNc1dkDNMlaI/UPqau5f/pcyrq+ViPLNTp+vzW/j6wxWktzcl2RmkUOGuwFc9D1/d7rkEy2/ctBp+Nr7Y5/DG53fa3ZzV2t1fPba/b9uvtkuVk+p2zkG/ibL/qhkdqWP+W42vYnYKvjc7DT9yvvo+1qPfh1c/h+XbW6q52u11zt9mXfry9Z9W2+d7Xlai8+vulqZ+/ZdbX6vY2Rr5M7j7tlcIp8+LCy7GvsQb5NOn7LtyNc2fG1i3657nO+31uX/H53rjVcbWvP1zbb/lxsdvy52CTXzA88/DNRGdeP5gohhBBCCCGEKBW9iAohhBBCCCGEKBW9iAohhBBCCCGEKJVS54jeakwy/6eMOaEx+5xk3mj8fv1OYufjiWpTxhy6WJTTajOR3IVJOArbo3Nfp5xv9p3lAZnLSCU4ZBKrkQmmrJ/YPM/YvmPrzhtcSjP+9lJ6r2Xzw/1Opn1LphIidu6IBKZYo/NByVMmq9G2kTmiRUHS9fHzEf3MNiCQOc8DMpe51/fb6xEhjRGbz7TvY9Og2KIukxWR67898P3Qhp9n3La4OaJ9sm5G5qbv93xoWn0/R7RLzieb105hA2hWKNb9nFYs+bmVgc0RZVKjJd8nRubD0lrN90le23a1pNb0tdTXGMwT0Bn449gl86Bj0SeiQgghhBBCCCFKRS+iQgghhBBCCCFKRS+iQgghhBBCCCFKRS+iQgghhBBCCCFKRbIiMRUkcimPQPp12tKTWTBPQgeW3Plp3XxBfCLR3+FkfcrGjTQyG2xd2pYSslbMMxXATFvGxYq0T4gEh7SFDeFcTMSWY42pDqyvidvlOuvGjTCsr1nGJ5EpcVkRWS7zR5xkxWX8eglxu0TbGCOvDyoI6pM+IaIjJj+K7hNyzubpPnY9Anw+BiS8fRLyXvDFJlqutm+7rtaCrzHa2HC1pHfK1Y51vCBnp8fkOr7GhFRGbhaWF/axXHfLUDERqYXMXyDW87ImliBrd3yRiJOsTvZR9weW1r0kKc99LUv8+U6JRWwiOevYawohhBBCCCGEEGOgF1EhhBBCCCGEEKWiF1EhhBBCCCGEEKWiF1EhhBBCCCGEEKWyMLIiKqFYgEnhMcTO258FrG2xEgSGJDDXZxLpy7S3N0kkY9edxfU7K6kWPVayX68KWEyipTmRGeBSI19Lp3wqqaAkVmRSWI4d67QlY+z6ZhIiJsth4hV2Nd8KYqJitnrk+JhIKLYfIocDSkrC1h2wtsSN9iyXaUpkJN4LgyQvZLxO8lKjO41qW/AeF6BDBEFEiBTISUtSUouUFVXlefN6sOx2ySDbhj8p+4mXEG2Hi365/hVXG5CT3M5Ou9pJnHS1YzWf8dsa/i56dsnLlI6tNV0tWSK5zAr7YEajBhEYra/75VJ/EYVu19VsQO6ge/u+ViOvcMX2AjBWS3w/MXFXbO4neY/RJ6JCCCGEEEIIIUpFL6JCCCGEEEIIIUpFL6JCCCGEEEIIIUrlhi+iZtYws4+a2afM7HNm9tPD+oNm9oSZPTz8c/+Rt1aII0AZF1VG+RZVRxkXVUcZF1UlRlbUBvCmEMKumeUAPmxm/2b4f/9DCOGfH13zpkOcgmG+hUhcJDFdQqRmZtoCozlgahkP8H0xzzKqeWfafcdyGiswYk2JXTf28qDymsllSnMxhk8iMIo/H3QnpDK+Ni0hy7E2F2vs3KZEDhFLIH0yIG1LE9LzA/896ECaQiVMZEF2f0omUp7dNFPNeDEfTEzUJd3KlqO5JzAJETufxDGCnGSrTwRGVFJFThOT+qR1IjAqyF2SZbL9nIlSYmVFfp+B5Zld40RWZF1SI9cguy7nQGA05YwXvmayouD7ug0v19nDNVfb6X7Fr9vdcrUTy/e62gP29a72NSe99eqeFd++Fy23Xe3Mmpcprd7hjyN/0aqr2e0nRgvrfplYwgpZt0+MXJ2OrzX88cdLine truncated
"text/plain": [ "text/plain": [
"<Figure size 1152x360 with 5 Axes>" "<Figure size 1152x360 with 5 Axes>"
] ]
@@ -422,7 +432,7 @@
}, },
{ {
"data": { "data": {
"image/png": "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 truncated "image/png": "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 truncated
"text/plain": [ "text/plain": [
"<Figure size 1152x360 with 5 Axes>" "<Figure size 1152x360 with 5 Axes>"
] ]
@@ -456,6 +466,15 @@
"\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, especially when the solver is _differentiable_. Before moving to these more complex training processes, we will cover a simpler supervised approach in the next chapter. This is very fundamental: even when aiming for advanced physics-based learning setups, a working supervised training is always the first step." "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, especially when the solver is _differentiable_. Before moving to these more complex training processes, we will cover a simpler supervised approach in the next chapter. This is very fundamental: even when aiming for advanced physics-based learning setups, a working supervised training is always the first step."
] ]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Next steps\n",
"\n",
"You could create a variety of nice fluid simulations based on this setup. E.g., try chaning the spatial resolution, the buoyancy factors, and the overall length of the simulation run."
]
} }
], ],
"metadata": { "metadata": {