Skip to content

Commit 4085a8e

Browse files
davidscnMakisH
andauthored
Add partitioned-heat OpenFOAM participant with solver (#223)
* Rename Heat to Heat-Flux according to naming scheme * Add initial field function for non-default initial conditions * Add the OpenFOAM Neumann configuration * Fix shell description for initial field * Add modified solver version including non-zero RHS * Format precice config according to our standard * Rename 'Flux' to 'Heat-Flux' in precice-config.xml * Remove license header and write some custom text * Add non-saved modifications missing in the previous commit * Add an additional Dirichlet participant * Fix some typos and missing brackets * Add value slot in groovyBC for paraFoam reader * Add run and clean scripts and README description * Move openfoam solver in dedicated directory on the top level * Update documentation for updated structure * Store generated executable in FOAM_USER_APPBIN and adjust documentation as well as run scripts accordingly * Add a comment on the heat transfer coefficient * Fix duplicated 'in the' in controlDict * Plug everything in one script to enable easy mesh modifications * Adjust the documentation for updated workflows * Apply suggestions from Makis review Co-authored-by: Gerasimos Chourdakis <[email protected]> * Remove OpenFOAM header from Temperature file * Add a changelog entry * Clean up cleaning files and add a solver cleaning script Co-authored-by: Gerasimos Chourdakis <[email protected]>
1 parent 0af0cf2 commit 4085a8e

34 files changed

+912
-60
lines changed

changelog-entries/223.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Added OpenFOAM solver as well as the participants (Dirichlet and Neumann) to our partiitoned-heat tutorial [#223](https://github.com/precice/tutorials/pull/223)

partitioned-heat-conduction/README.md

+21-19
Original file line numberDiff line numberDiff line change
@@ -15,50 +15,52 @@ We solve a partitioned heat equation. For information on the non-partitioned cas
1515

1616
Case setup from [3]. `D` denotes the Dirichlet participant and `N` denotes the Neumann participant.
1717

18-
The heat equation is solved on a rectangular domain `Omega = [0,2] x [0,1]` with given Dirichlet boundary conditions. We split the domain at `x_c = 1` using a straight vertical line, the coupling interface. The left part of the domain will be referred to as the Dirichlet partition and the right part as the Neumann partition. To couple the two participants we use Dirichlet-Neumann coupling. Here, the Dirichlet participant receives Dirichlet boundary conditions (`Temperature`) at the coupling interface and solves the heat equation using these boundary conditions on the left part of the domain. Then the Dirichlet participant computes the resulting heat flux (`Flux`) from the solution and sends it to the Neumann participant. The Neumann participant uses the flux as a Neumann boundary condition to solve the heat equation on the right part of the domain. We then extract the temperature from the solution and send it back to the Dirichlet participant. This establishes the coupling between the two participants.
18+
The heat equation is solved on a rectangular domain `Omega = [0,2] x [0,1]` with given Dirichlet boundary conditions. We split the domain at `x_c = 1` using a straight vertical line, the coupling interface. The left part of the domain will be referred to as the Dirichlet partition and the right part as the Neumann partition. To couple the two participants we use Dirichlet-Neumann coupling. Here, the Dirichlet participant receives Dirichlet boundary conditions (`Temperature`) at the coupling interface and solves the heat equation using these boundary conditions on the left part of the domain. Then the Dirichlet participant computes the resulting heat flux (`Heat-Flux`) from the solution and sends it to the Neumann participant. The Neumann participant uses the flux as a Neumann boundary condition to solve the heat equation on the right part of the domain. We then extract the temperature from the solution and send it back to the Dirichlet participant. This establishes the coupling between the two participants.
1919

2020
This simple case allows us to compare the solution for the partitioned case to a known analytical solution (method of manufactures solutions, see [1, p.37ff]). For more usage examples and details, please refer to [3, sect. 4.1].
2121

2222
## Available solvers and dependencies
2323

24-
You can either couple a solver with itself or different solvers with each other. In any case you will need to have preCICE and the python bindings installed on your system.
24+
You can either couple a solver with itself or different solvers with each other. In any case you will need to have preCICE
2525

2626
* FEniCS. Install [FEniCS](https://fenicsproject.org/download/) and the [FEniCS-adapter](https://github.com/precice/fenics-adapter). The code is largely based on this [fenics-tutorial](https://github.com/hplgit/fenics-tutorial/blob/master/pub/python/vol1/ft03_heat.py) from [1].
2727

2828
* Nutils. Install [Nutils](http://www.nutils.org/en/latest/).
2929

30-
## Running the simulation
30+
* OpenFOAM. Install OpenFOAM and the [OpenFOAM adapter](https://www.precice.org/adapter-openfoam-overview.html). This tutorial uses a custom solver, which you can find in `tutorials/partitioned-heat-conduction/openfoam-solver` and build using `cd tutorials/partitioned-heat-conduction/openfoam-solver && wmake`. Have a look at the section below (Notes on the OpenFOAM case) for further information.
3131

32-
This tutorial is for FEniCS and Nutils. You can find the corresponding `run.sh` script in the folders `fenics` and `nutils`.
32+
### Notes on the OpenFOAM case
3333

34-
For choosing whether you want to run the Dirichlet-kind and a Neumann-kind participant, please provide the following commandline input:
34+
Running this tutorial with OpenFOAM is a bit of a challenge and requires some special considerations:
3535

36-
* `-d` flag will enforce Dirichlet boundary conditions on the coupling interface.
37-
* `-n` flag will enforce Neumann boundary conditions on the coupling interface.
36+
* First of all, OpenFOAM does not provide a Laplace solver with a non-zero right-hand side. Therefore, we provide a modified Laplace solver together with the tutorial, which needs to be compiled before running the tutorial. The solver can be compiled by executing `wmake` in the solver directory `./openfoam-solver/`. The generated executable will be stored in the `FOAM_USER_APPBIN` by default. Afterwards, the custom solver `heatTransfer` can be started from the respective OpenFOAM case directory, as usual.
3837

39-
For running the case, open two terminals run:
38+
* The second challenge is given by the time- and space-dependent Dirichlet boundary conditions required for domain boundaries not belonging to the interface. For this purpose, a valid installation of `groovyBC` (part of `swak4Foam`) is required.
4039

41-
```bash
42-
cd fenics
43-
./run.sh -d
44-
```
40+
* The third challenge is given by the space-dependent initial conditions. We use `funkySetFields` (installed with OpenFOAM) to evaluate the initial condition. You can directly execute the `./run.sh` script, which calls the `setInitialField.sh` in order to evaluate the required initial condition and store it in the `0` directory. Note that `run.sh` deletes the `0` time directory and copies it again from `0.orig`. If you start modifying the initial or boundary conditions, make sure you modify the files located in the `0.orig` directory in combination with the default `run.sh` scripts.
4541

46-
and
42+
## Running the simulation
4743

48-
```bash
49-
cd fenics
50-
./run.sh -n
51-
```
44+
You can find the corresponding `run.sh` script in each participant solver.
45+
46+
In case of `fenics` and `nutils` the Dirichlet-kind and a Neumann-kind participant are currently merged into a single participant directory. Therefore, please provide the following command line input argument:
5247

53-
If you want to use Nutils for one or both sides of the setup, just `cd nutils`. The FEniCS case also supports parallel runs. Here, you cannot use the `run.sh` script, but must simply execute
48+
* `-d` flag will enforce Dirichlet boundary conditions on the coupling interface.
49+
* `-n` flag will enforce Neumann boundary conditions on the coupling interface.
50+
51+
For running the case, a Dirichlet and a Neumann participant need to be executed, e.g., `./run.sh -d` and `./run.sh. -n`
52+
53+
The FEniCS case also supports parallel runs. Here, you cannot use the `run.sh` script, but must simply execute
5454

5555
```bash
5656
mpirun -n <N_PROC> python3 heat.py -d
5757
```
5858

59+
OpenFOAM supports parallel runs as usual. However, you need to execute the command manually by running: `mpirun -np <N_PROC> ./heatTransfer`.
60+
5961
### Note on the combination of Nutils & FEniCS
6062

61-
You can mix the Nutils and FEniCS solver, if you like. Note that the error for a pure FEniCS simulation is lower than for a mixed one. We did not yet study the origin of this error, but assume that this is due to the fact that Nutils uses Gauss points as coupling mesh and therefore entails extrapolation in the data mapping at the top and bottom corners.
63+
You can mix the Nutils and FEniCS solver, if you like. Note that the error for a pure FEniCS simulation is lower than for a mixed one, because the FEniCS participants use the same coupling mesh, i.e., the mapping error becomes significantly smaller.
6264

6365
## Visualization
6466

partitioned-heat-conduction/fenics/heat.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ def determine_gradient(V_g, u, flux):
170170

171171
if problem is ProblemType.DIRICHLET:
172172
flux = Function(V_g)
173-
flux.rename("Flux", "")
173+
flux.rename("Heat-Flux", "")
174174

175175
while precice.is_coupling_ongoing():
176176

partitioned-heat-conduction/fenics/precice-adapter-config-D.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"config_file_name": "../precice-config.xml",
44
"interface": {
55
"coupling_mesh_name": "Dirichlet-Mesh",
6-
"write_data_name": "Flux",
6+
"write_data_name": "Heat-Flux",
77
"read_data_name": "Temperature"
88
}
99
}

partitioned-heat-conduction/fenics/precice-adapter-config-N.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@
44
"interface": {
55
"coupling_mesh_name": "Neumann-Mesh",
66
"write_data_name": "Temperature",
7-
"read_data_name": "Flux"
7+
"read_data_name": "Heat-Flux"
88
}
99
}

partitioned-heat-conduction/nutils/heat.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,8 @@ def main(side='Dirichlet'):
6868
vertex_ids = interface.set_mesh_vertices(mesh_id, vertices)
6969

7070
# coupling data
71-
write_data = "Temperature" if side == "Neumann" else "Flux"
72-
read_data = "Flux" if side == "Neumann" else "Temperature"
71+
write_data = "Temperature" if side == "Neumann" else "Heat-Flux"
72+
read_data = "Heat-Flux" if side == "Neumann" else "Temperature"
7373
write_data_id = interface.get_data_id(write_data, mesh_id)
7474
read_data_id = interface.get_data_id(read_data, mesh_id)
7575

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
FoamFile
2+
{
3+
version 2.0;
4+
format ascii;
5+
class volScalarField;
6+
location "0";
7+
object T;
8+
}
9+
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
10+
11+
dimensions [0 0 0 1 0 0 0];
12+
13+
14+
internalField uniform 0;
15+
16+
boundaryField
17+
{
18+
interface
19+
{
20+
type fixedValue;
21+
value uniform 2;
22+
}
23+
24+
DirichletBoundary
25+
{
26+
type groovyBC;
27+
variables "val=1+pow(pos().x,2)+(3*pow(pos().y,2))+1.3*time();";
28+
valueExpression "val";
29+
value uniform 0;
30+
evaluateDuringConstruction 1;
31+
}
32+
33+
defaultFaces
34+
{
35+
type empty;
36+
}
37+
}
38+
39+
// ************************************************************************* //
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/bin/sh
2+
set -e -u
3+
4+
. ../../tools/cleaning-tools.sh
5+
6+
clean_openfoam .
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
FoamFile
2+
{
3+
version 2.0;
4+
format ascii;
5+
class dictionary;
6+
location "constant";
7+
object transportProperties;
8+
}
9+
10+
DT DT [ 0 2 -1 0 0 0 0 ] 1;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#!/bin/sh
2+
set -e -u
3+
4+
blockMesh
5+
touch openfoam-dirichlet.foam
6+
./setInitialField.sh
7+
8+
../../tools/run-openfoam.sh "$@"
9+
. ../../tools/openfoam-remove-empty-dirs.sh && openfoam_remove_empty_dirs
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#!/bin/sh
2+
set -e -u
3+
4+
# Remove the old directory and copy the uninitialized field
5+
rm -rf ./0
6+
cp -r ./0.orig 0
7+
# Initialize the new field
8+
funkySetFields -keepPatches -field T -expression '1+pow(pos().x,2)+(3*pow(pos().y,2))+1.3*time()' -time '0'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
FoamFile
2+
{
3+
version 2.0;
4+
format ascii;
5+
class dictionary;
6+
object blockMeshDict;
7+
}
8+
9+
vertices
10+
(
11+
12+
(0 0 0)
13+
(1 0 0)
14+
(1 1 0)
15+
(0 1 0)
16+
17+
(0 0 .1)
18+
(1 0 .1)
19+
(1 1 .1)
20+
(0 1 .1)
21+
);
22+
23+
blocks
24+
(
25+
hex (0 1 2 3 4 5 6 7) (100 100 1) simpleGrading (1 1 1)
26+
);
27+
28+
edges
29+
(
30+
);
31+
32+
boundary
33+
(
34+
35+
interface
36+
{
37+
type patch;
38+
faces
39+
(
40+
(1 2 6 5)
41+
);
42+
}
43+
44+
DirichletBoundary
45+
{
46+
type patch;
47+
faces
48+
(
49+
(4 7 3 0)
50+
(7 6 2 3)
51+
(4 0 1 5)
52+
);
53+
}
54+
);
55+
56+
mergePatchPairs
57+
(
58+
);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
FoamFile
2+
{
3+
version 2.0;
4+
format ascii;
5+
class dictionary;
6+
location "system";
7+
object controlDict;
8+
}
9+
10+
// Make sure you build the solver located
11+
// in ./openfoam-solver before running
12+
// the case
13+
application heatTransfer;
14+
15+
libs ( "libgroovyBC.so" ) ;
16+
17+
startFrom startTime;
18+
19+
startTime 0;
20+
21+
stopAt endTime;
22+
23+
endTime 1;
24+
25+
deltaT 0.1;
26+
27+
writeControl runTime;
28+
29+
writeInterval 0.1;
30+
31+
purgeWrite 0;
32+
33+
writeFormat ascii;
34+
35+
writePrecision 6;
36+
37+
writeCompression off;
38+
39+
timeFormat general;
40+
41+
timePrecision 6;
42+
43+
runTimeModifiable false;
44+
45+
functions
46+
{
47+
preCICE_Adapter
48+
{
49+
type preciceAdapterFunctionObject;
50+
libs ("libpreciceAdapterFunctionObject.so");
51+
}
52+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
FoamFile {
2+
version 2.0;
3+
class dictionary;
4+
object decomposeParDict;
5+
format ascii;
6+
}
7+
8+
numberOfSubdomains 2;
9+
10+
method simple;
11+
12+
simpleCoeffs
13+
{
14+
n (2 1 1);
15+
delta 0.001;
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
FoamFile
2+
{
3+
version 2.0;
4+
format ascii;
5+
class dictionary;
6+
location "system";
7+
object fvSchemes;
8+
}
9+
10+
ddtSchemes
11+
{
12+
default Euler;
13+
}
14+
15+
gradSchemes
16+
{
17+
default Gauss linear;
18+
grad(T) Gauss linear;
19+
}
20+
21+
divSchemes
22+
{
23+
default none;
24+
}
25+
26+
laplacianSchemes
27+
{
28+
default none;
29+
laplacian(DT,T) Gauss linear corrected;
30+
}
31+
32+
interpolationSchemes
33+
{
34+
default linear;
35+
}
36+
37+
snGradSchemes
38+
{
39+
default corrected;
40+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
FoamFile
2+
{
3+
version 2.0;
4+
format ascii;
5+
class dictionary;
6+
location "system";
7+
object fvSolution;
8+
}
9+
10+
solvers
11+
{
12+
T
13+
{
14+
solver PCG;
15+
preconditioner DIC;
16+
tolerance 1e-06;
17+
relTol 0;
18+
}
19+
}
20+
21+
SIMPLE
22+
{
23+
nNonOrthogonalCorrectors 2;
24+
}

0 commit comments

Comments
 (0)