// (re)set boundaries = (re)initialize flag field for every block with respect to the new block structure (the size of neighbor blocks might have changed)
"Our numeric solver's symbolic representation is now complete! Next, we use pystencils to generate and compile a C implementation of our kernel. The code is generated as shown below, compiled into a shared libary and then bound to `kernel_func`. All unbound sympy symbols (`dx`, `dt` and `kappa`) as well as the fields `u` and `u_tmp` are arguments to the generated kernel function. "
"Our numeric solver's symbolic representation is now complete! Next, we use pystencils to generate and compile a C implementation of our kernel. The code is generated as shown below, compiled into a shared library and then bound to `kernel_func`. All unbound sympy symbols (`dx`, `dt` and `kappa`) as well as the fields `u` and `u_tmp` are arguments to the generated kernel function. "
]
},
{
...
...
@@ -355,7 +355,7 @@
"source": [
"### Prototype Simulation\n",
"\n",
"We can set up and run a simple simulation wich the generated kernel right here. The first step is to set up the fields and simulation parameters."
"We can set up and run a simple simulation with the generated kernel right here. The first step is to set up the fields and simulation parameters."
]
},
{
...
...
%% Cell type:code id: tags:
``` python
frompystencils.sessionimport*
importsympyassp
importnumpyasnp
importmatplotlib.pyplotasplt
sp.init_printing()
```
%% Cell type:markdown id: tags:
### Code Generation for the Heat Equation
The <atarget="_blank"href="https://en.wikipedia.org/wiki/Heat_equation">heat equation</a> which is a simple partial differential equation describing the flow of heat through a homogenous medium. We can write it as
$$
\frac{\partial u}{\partial t} =
\kappa \left(
\frac{\partial^2 u}{\partial x^2} +
\frac{\partial^2 u}{\partial y^2}
\right)
$$
where $\kappa$ is the medium's diffusion coefficient and $u(x, y, t)$ is the unknown temperature distribution at the coordinate $(x,y)$ at time $t$.
To discretize this equation using pystencils, we first need to define all the fields and other symbols involved.
%% Cell type:code id: tags:
``` python
u,u_tmp=ps.fields("u, u_tmp: [2D]",layout='fzyx')
kappa=sp.Symbol("kappa")
dx=sp.Symbol("dx")
dt=sp.Symbol("dt")
```
%% Cell type:markdown id: tags:
We define the PDE using the pystencils building blocks for transient and spatial derivatives. The definition is implicitly equalled to zero. We use `ps.fd.transient` for a first derivative by time and `ps.fd.diff` to express the second derivatives. `ps.fd.diff` takes a field and a list of spatial dimensions in which the field should be differentiated.
Next, the PDE will be discretized. We use the `Discretization2ndOrder` class to apply finite differences discretization to the spatial components, and explicit euler discretization to the transient components.
While combining the two fractions on the right as desired, it also put everything above a common denominator. If we generated the kernel from this, we'd be redundantly multiplying $u_{(0,0)}$ by $dx^2$. Let's try something else. Instead of applying `simplify` to the entire equation, we could apply it only to the second summand.
The outermost operation of `heat_pde_discretized` is a $+$, so `heat_pde_discretized` is an instance of `sp.Sum`. We take it apart by accessing its arguments, simplify the right hand summand, and put it back together again.
That looks a lot better! There is nothing left to simplify. The right-hand summand still contains a division by $dx^2$, though. Due to their inefficiency, floating-point divisions should be replaced by multiplication with their reciprocals. Before we can eliminate the division, we need to wrap the equation inside an `AssignmentCollection`. On this collection we can apply `add_subexpressions_for_divisions` to replace the division by a factor $\xi_1 = \frac{1}{dx^2}$ which in the kernel will be computed ahead of the loop.
Our numeric solver's symbolic representation is now complete! Next, we use pystencils to generate and compile a C implementation of our kernel. The code is generated as shown below, compiled into a shared libary and then bound to `kernel_func`. All unbound sympy symbols (`dx`, `dt` and `kappa`) as well as the fields `u` and `u_tmp` are arguments to the generated kernel function.
Our numeric solver's symbolic representation is now complete! Next, we use pystencils to generate and compile a C implementation of our kernel. The code is generated as shown below, compiled into a shared library and then bound to `kernel_func`. All unbound sympy symbols (`dx`, `dt` and `kappa`) as well as the fields `u` and `u_tmp` are arguments to the generated kernel function.
%% Cell type:code id: tags:
``` python
kernel_ast=ps.create_kernel(update,cpu_openmp=4)
kernel_func=kernel_ast.compile()
ps.show_code(kernel_ast)
```
%% Output
%% Cell type:markdown id: tags:
### Prototype Simulation
We can set up and run a simple simulation wich the generated kernel right here. The first step is to set up the fields and simulation parameters.
We can set up and run a simple simulation with the generated kernel right here. The first step is to set up the fields and simulation parameters.
%% Cell type:code id: tags:
``` python
domain_size=1.0
cells=25
delta_x=domain_size/cells
delta_t=0.0001
kappa_v=1.0
u=np.zeros((cells,cells))
u_tmp=np.zeros_like(u)
```
%% Cell type:markdown id: tags:
We also need the Dirichlet and Neumann Boundaries.
Not only can we run the kernel, we can even view the results as a video! This is a useful tool for debugging and testing the solver before introducing it into a larger application. We can view the simulation animated both as a colorful 2D plot or as a 3D surface plot.
The total time interval being simulated is two seconds (100 frames à 200 steps à 0.1 milliseconds).
The aim of this tutorial is to show how to build and solve the backward-facing step model using lattice Boltzman method in waLBerla.
The aim of this tutorial is to show how to build and solve the backward-facing step model using lattice Boltzmann method in waLBerla.
The "01_BasicLBM" case is used as the foundation of the current work. Therefore, most of the functionalities have already been introduced and discussed in LBM 1 tutorial.
Here the main focus is on the following areas:
...
...
@@ -54,13 +54,13 @@ Finally, viscosity consequently **omega** are calculated with the Reynolds numbe
\section tutorial05_geometry Geometry
Since the step geometry is a plain rectangular area, the simplest approach is to create it by geometry module in walberla.
This module offers capability to read boundaries of a random geometry from images, voxel files, coordinates of verticies, etc.
This module offers capability to read boundaries of a random geometry from images, voxel files, coordinates of vertices, etc.
Using this module, obstacles of basic shapes could be conveniently positioned inside the domain.
It is also easier to have the program to read the geometry specifications from the Boundaries section of the configuration file.
This is implemented by reading and storing the Boundaries block of the configuration file in 'boundariesConfig' object and passing it to a convenience function provided in the geometry class to initialize the boundaries.
\snippet 05_BackwardFacingStep.cpp geomboundary
Here a subblock 'Body' is created inside 'Boundaries' section in the configuration file in order to create a box (rectangle in 2D) using two diagonal verticies.
Here a subblock 'Body' is created inside 'Boundaries' section in the configuration file in order to create a box (rectangle in 2D) using two diagonal vertices.
\snippet 05_BackwardFacingStep.prm geometry
...
...
@@ -77,7 +77,7 @@ This mechanism is implemented by a functor named `ReattachmentLengthFinder` and
After running the program, the locations of reattachment against timestep are written to 'ReattachmentLengthLogging_Re_[Re].txt' in the working directory.
Note that there might be more than one reattachment location before the flow fully develops along the channel, and all are given in the file.
This simply means that it is expected to have multiple occurances of seperation and reattachment at the same time along the bottom boundary of the channel following the step in the early stages.
This simply means that it is expected to have multiple occurences of seperation and reattachment at the same time along the bottom boundary of the channel following the step in the early stages.
However, most of them are smeared later as the flow starts to develop.
The logging frequency can also be adjusted by 'checkFrequency' which is passed to the `ReattachmentLengthFinder` functor.
# The checksum is used as an index in a different array. If an item with that index already exists the suppression must be a duplicate and is discarded.
BEGIN {suppression=0;md5sum="md5sum"}
# If the line begins with '{', it's the start of a supression; so set the var and initialise things
# If the line begins with '{', it's the start of a suppression; so set the var and initialise things