Skip to content

Commit 2ee2031

Browse files
authored
Channel transport with particles (#700)
* Add initial setup * Configure the case properly * Add preliminary README * Add config-visualization * Update note * Add a changelog entry * Add a setup image * MercuryDPM cleaning utility * Add a run script * Extend the README
1 parent 2579210 commit 2ee2031

25 files changed

+844
-0
lines changed

changelog-entries/700.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Added a tutorial for particle tracing with MercuryDPM, Nutils, and OpenFOAM, highlighting the just-in-time mappings in preCICE.
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
---
2+
title: Channel transport with particles
3+
permalink: tutorials-channel-transport-particles.html
4+
keywords: volume coupling, particles, OpenFOAM, MercuryDPM, transport, just-in-time mapping
5+
summary: A CFD problem is coupled to a particles in a uni-directional way for particles tracing.
6+
---
7+
8+
{% note %}
9+
Get the [case files of this tutorial](https://github.com/precice/tutorials/tree/develop/channel-transport-particles), as continuously rendered here, or see the [latest released version](https://github.com/precice/tutorials/tree/master/channel-transport-particles) (if there is already one). Read how in the [tutorials introduction](https://precice.org/tutorials.html).
10+
{% endnote %}
11+
12+
## Setup
13+
14+
We model a two-dimensional incompressible fluid flowing through a channel with an obstacle. The fluid problem is coupled to a particle participant for particle tracing. Similar to the transport problem (see the [channel-transport tutorial](tutorials-channel-transport.html)), particles are arranged in a circular blob close to the inflow. The particles then move along with the flow as depicted in the following figure
15+
16+
![preCICE configuration visualization](images/tutorials-channel-transport-particles-setup.png)
17+
18+
Note that this scenario features a unidirectional coupling, where the fluid velocity affects the particles, but the particles do not affect the fluid.
19+
20+
## Configuration
21+
22+
preCICE configuration (image generated using the [precice-config-visualizer](https://precice.org/tooling-config-visualization.html)):
23+
24+
![preCICE configuration visualization](images/tutorials-channel-transport-particles-precice-config.pdf
25+
)
26+
27+
## Available solvers
28+
29+
Fluid participant:
30+
31+
* Nutils. For more information, have a look at the [Nutils adapter documentation](https://precice.org/adapter-nutils.html). This Nutils solver requires at least Nutils v7.0.
32+
33+
* OpenFOAM (pimpleFoam). For more information, have a look at the [OpenFOAM adapter documentation](https://precice.org/adapter-openfoam-overview.html).
34+
35+
Particle participant:
36+
37+
* MercuryDPM. The specific case is available as part of MercuryDPM. To use it, compile MercuryDPM with support for preCICE (`-D MercuryDPM_PreCICE_COUPLING="ON"`). You can compile the relevant executable only using `make ChannelTransport`. Afterwards, the executable `ChannelTransport` is available in the build tree. The `run.sh` script can pick-up the executable, if a `MERCURYDPM_BUILD_DIR` has been exported. Copying the executable or providing it as a command line argument is also possible. Use `run.sh --help` for detailed information. Note that the drag model is mostly an arbitrary choice to validate the technical correctness, but it has no physical background.
38+
39+
## Running the simulation
40+
41+
For the fluid solver, use Nutils for ease of installation and OpenFOAM for speed.
42+
43+
Open two separate terminals and start one fluid and one transport participant by calling the respective run scripts `run.sh` located in each of the participants' directory. For example:
44+
45+
```bash
46+
cd fluid-nutils
47+
./run.sh
48+
```
49+
50+
and the particle solver
51+
52+
```bash
53+
cd particles-mercurydpm
54+
./run.sh
55+
```
56+
57+
## Post-processing
58+
59+
All solvers generate `vtk` files which can be visualized using, e.g., ParaView.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../tools/clean-tutorial-base.sh
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/usr/bin/env sh
2+
set -e -u
3+
4+
. ../../tools/cleaning-tools.sh
5+
6+
clean_nutils .
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
#! /usr/bin/env python3
2+
3+
#
4+
# Incompressible NSE solved within a channel geometry with parabolic inflow profile and an obstacle attached to the bottom towards the middle of the domain. The fluid field is initialized with a Stokes solution. The resulting velocity field is written to preCICE on the complete volume.
5+
#
6+
7+
from nutils import function, mesh, cli, solver, export
8+
import treelog as log
9+
import numpy as np
10+
import precice
11+
from mpi4py import MPI
12+
13+
14+
def main():
15+
16+
print("Running Nutils")
17+
18+
# define the Nutils mesh
19+
nx = 48
20+
ny = 16
21+
step_start = nx // 3
22+
step_end = nx // 2
23+
step_hight = ny // 2
24+
25+
grid = np.linspace(0, 6, nx + 1), np.linspace(0, 2, ny + 1)
26+
domain, geom = mesh.rectilinear(grid)
27+
domain = domain.withboundary(inflow="left", outflow="right", wall="top,bottom") - domain[
28+
step_start:step_end, :step_hight
29+
].withboundary(wall="left,top,right")
30+
31+
# cloud of Gauss points
32+
gauss = domain.sample("gauss", degree=4)
33+
34+
# Nutils namespace
35+
ns = function.Namespace()
36+
ns.x = geom
37+
38+
ns.ubasis = domain.basis("std", degree=2).vector(2)
39+
ns.pbasis = domain.basis("std", degree=1)
40+
ns.u_i = "ubasis_ni ?u_n" # solution
41+
ns.p = "pbasis_n ?p_n" # solution
42+
ns.dudt_i = "ubasis_ni (?u_n - ?u0_n) / ?dt" # time derivative
43+
ns.μ = 0.5 # viscosity
44+
ns.σ_ij = "μ (u_i,j + u_j,i) - p δ_ij"
45+
ns.uin = "10 x_1 (2 - x_1)" # inflow profile
46+
47+
# define the weak form, Stokes problem
48+
ures = gauss.integral("ubasis_ni,j σ_ij d:x" @ ns)
49+
pres = gauss.integral("pbasis_n u_k,k d:x" @ ns)
50+
51+
# define Dirichlet boundary condition
52+
sqr = domain.boundary["inflow"].integral("(u_0 - uin)^2 d:x" @ ns, degree=2)
53+
sqr += domain.boundary["inflow,outflow"].integral("u_1^2 d:x" @ ns, degree=2)
54+
sqr += domain.boundary["wall"].integral("u_k u_k d:x" @ ns, degree=2)
55+
cons = solver.optimize(["u"], sqr, droptol=1e-15)
56+
57+
# preCICE setup
58+
participant = precice.Participant("Fluid", "../precice-config.xml", 0, 1)
59+
60+
# define coupling mesh
61+
mesh_name = "Fluid-Mesh"
62+
vertices = gauss.eval(ns.x)
63+
vertex_ids = participant.set_mesh_vertices(mesh_name, vertices)
64+
65+
# coupling data
66+
data_name = "Velocity"
67+
68+
participant.initialize()
69+
70+
timestep = 0
71+
solver_dt = 0.005
72+
precice_dt = participant.get_max_time_step_size()
73+
dt = min(precice_dt, solver_dt)
74+
75+
state = solver.solve_linear(("u", "p"), (ures, pres), constrain=cons) # initial condition
76+
77+
# add convective term and time derivative for Navier-Stokes
78+
ures += gauss.integral("ubasis_ni (dudt_i + μ (u_i u_j)_,j) d:x" @ ns)
79+
80+
while participant.is_coupling_ongoing():
81+
82+
if timestep % 1 == 0: # visualize
83+
bezier = domain.sample("bezier", 2)
84+
x, u, p = bezier.eval(["x_i", "u_i", "p"] @ ns, **state)
85+
with log.add(log.DataLog()):
86+
export.vtk("Fluid_" + str(timestep), bezier.tri, x, u=u, p=p)
87+
88+
precice_dt = participant.get_max_time_step_size()
89+
90+
# potentially adjust non-matching timestep sizes
91+
dt = min(solver_dt, precice_dt)
92+
93+
# solve Nutils timestep
94+
state["u0"] = state["u"]
95+
state["dt"] = dt
96+
state = solver.newton(("u", "p"), (ures, pres), constrain=cons, arguments=state).solve(1e-10)
97+
98+
velocity_values = gauss.eval(ns.u, **state)
99+
participant.write_data(mesh_name, data_name, vertex_ids, velocity_values)
100+
101+
# do the coupling
102+
participant.advance(dt)
103+
104+
# advance variables
105+
timestep += 1
106+
107+
participant.finalize()
108+
109+
110+
if __name__ == "__main__":
111+
cli.run(main)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
setuptools # required by nutils
2+
nutils==7
3+
numpy >1, <2
4+
pyprecice~=3.0
5+
setuptools
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#!/usr/bin/env bash
2+
set -e -u
3+
4+
. ../../tools/log.sh
5+
exec > >(tee --append "$LOGFILE") 2>&1
6+
7+
if [ ! -v PRECICE_TUTORIALS_NO_VENV ]
8+
then
9+
python3 -m venv .venv
10+
. .venv/bin/activate
11+
pip install -r requirements.txt && pip freeze > pip-installed-packages.log
12+
fi
13+
14+
python3 fluid.py
15+
16+
close_log
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
FoamFile
2+
{
3+
version 2.0;
4+
format ascii;
5+
class volVectorField;
6+
object U;
7+
}
8+
9+
dimensions [0 1 -1 0 0 0 0];
10+
internalField uniform (10 0 0);
11+
12+
boundaryField
13+
{
14+
inlet
15+
{
16+
type fixedValue;
17+
value $internalField;
18+
}
19+
outlet
20+
{
21+
type zeroGradient;
22+
}
23+
obstacle
24+
{
25+
type noSlip;
26+
}
27+
upperWall
28+
{
29+
type noSlip;
30+
}
31+
lowerWall
32+
{
33+
type noSlip;
34+
}
35+
frontAndBack
36+
{
37+
type empty;
38+
}
39+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
FoamFile
2+
{
3+
version 2.0;
4+
format ascii;
5+
class volScalarField;
6+
object p;
7+
}
8+
9+
dimensions [0 2 -2 0 0 0 0];
10+
11+
internalField uniform 0;
12+
13+
boundaryField
14+
{
15+
inlet
16+
{
17+
type zeroGradient;
18+
}
19+
20+
outlet
21+
{
22+
type fixedValue;
23+
value uniform 0;
24+
}
25+
26+
obstacle
27+
{
28+
type zeroGradient;
29+
}
30+
31+
upperWall
32+
{
33+
type zeroGradient;
34+
}
35+
36+
lowerWall
37+
{
38+
type zeroGradient;
39+
}
40+
41+
frontAndBack
42+
{
43+
type empty;
44+
}
45+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/usr/bin/env sh
2+
set -e -u
3+
4+
. ../../tools/cleaning-tools.sh
5+
6+
clean_openfoam .

0 commit comments

Comments
 (0)