Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the flow-over-heated-plate for nearest-projection #159

Merged
merged 6 commits into from
Mar 23, 2021
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 122 additions & 0 deletions flow-over-heated-plate-nearest-projection/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
---
title: Flow over heated plate nearest projection
permalink: tutorials-flow-over-heated-plate-nearest-projection.html
keywords: OpenFOAM, nearest-projection, CHT
summary: This tutorial introduces an example simulation setup for nearest-projection mapping with the OpenFOAM adapter. The demonstrated "flow over a heated plate" scenario is exactly the same as in the `buoyantPimpleFoam-laplacianFoam` tutorial (with a thinner plate). The following text explains the _general functionality_ of the adapter, the _current capability_ of the adapter and the necessary _changes in the tutorials_ for your own simulation.
---

## Setup

The setup is exactly the same as described in our [flow-over-heated-plate tutorial](tutorials-flow-over-heated-plate.html). Since the physical setup is not the main concern of this tutorial, we focus in the following on the nearest-projection mapping within preCICE. Let's start with general information about mapping methods. The [preCICE docs](configuration-mapping.html) contains an overview with available mapping methods in preCICE. The nearest-projection mapping is a second-order method. But, contrary to the RBF mapping, mesh connectivity information is needed for the interpolation.
There are two participants in each mapping, but the connectivity of one mesh is sufficient for an interpolation. Which of the participants must provide mesh connectivity is not arbitrary and depends on the constraint type:

- for `consistent` mappings, the `from` participant needs to provide connectivity
- for `conservative` mappings, the `to` participant needs to provide connectivity

For example, in our case, we exchange `Temperature` data in a `consistent` way from the `Fluid` to the `Solid` participant. Hence, `Fluid` needs to provide mesh connectivity.

Notes:

- In a standard **CHT** calculation, both data sets (heat flux and temperature) are mapped consistently. Therefore, both participants need to provide connectivity.
- In a standard **FSI** calculation, forces are mapped conservatively from `Fluid` to `Solid`, while displacements are mapped consistently from `Solid` to `Fluid`. Hence, it is `Solid` that needs to provide connectivity and not `Fluid`.

If mesh connectivity is not provided in the described way, you are nevertheless able to define a nearest-projection mapping in your `precice-config.xml`file, but it will _fall back to a first-order nearest-neighbor mapping_.

## Available solvers

Fluid participant:

* OpenFOAM (buoyantPimpleFoam). For more information, have a look at the [OpenFOAM adapter documentation](adapter-openfoam-overview.html).

Solid participant:

* OpenFOAM (laplacianFoam). For more information, have a look at the [OpenFOAM adapter documentation](adapter-openfoam-overview.html).

Since OpenFOAM is a finite-volume based solver, data is located in the middle of the cell, or on the cell face centers for a coupling interface. Mesh connectivity can be given to preCICE using the methods `setMeshTriangle` and `setMeshEdge`. Using the face centers as arguments for these methods is cumbersome. The main reason is that, although OpenFOAM decomposes the mesh for parallel simulations and distributes the subdomains to different processes, mesh connectivity needs to be defined over the partitioned mesh boundaries. This problem vanishes if we define mesh connectivity based on the face nodes, since boundary nodes can be shared among processors. Therefore, mesh connectivity can only be provided on the face nodes (not on the face centers).

As described already, the data is not stored on the face nodes, but on the face centers. Therefore, we use OpenFOAM functions to interpolate from face centers to face nodes. The following image illustrates the workflow:

![nearest-projection](https://user-images.githubusercontent.com/33414590/55965109-3402b600-5c76-11e9-87eb-0cdb10b55f7b.png)

Data is obtained at the face centers, then interpolated to face nodes. Here, we have provided mesh connectivity and finally, preCICE performs the nearest-projection mapping.
It is important to notice that the target data location is again the face center mesh of the coupling partner. In the standard CHT case, where both data sets are exchanged by a nearest-projection mapping, this leads to two interface meshes (centers and nodes) per participant. Having both the centers and nodes defined, we can skip one interpolation step and read data directly to the centers (cf. picture solver B).

### Supported fields
As already mentioned, the `Fluid` participant does not need to provide the mesh connectivity in case of a standard FSI. Therefore, the `Solid` participant needs to provide it and nothing special needs to be considered compared to other mapping methods.
This implementation supports all CHT-related fields, which are mapped with a `consistent` constraint. The required settings and differences compared to the basic tutorial are given below.

### Changes in the Simulation Setup

As we are defining two meshes for each participant, we need to define them in the `precice-config.xml` and `preciceDict` configuration files. Additionally, we need to enable the `connectivity` switch for the adapter.

### Changes in `precice-config.xml`
In order to map from face nodes to face centers, both meshes need to be specified. The nodes-based mesh uses the write data and the centers-based mesh uses the read data. Have a look in the given `precice-config.xml` in this tutorial. Example: `Temperature` is calculated by the `Fluid` participant and passed to the `Solid` participant. Therefore, it is the write data of the participant `Fluid` and the read data of the participant `Solid`. This results in the following two meshes for this data:
```
<mesh name="Fluid-Mesh-Nodes">
<use-data name="Temperature"/>
</mesh>
<mesh name="Solid-Mesh-Centers">
<use-data name="Temperature"/>
</mesh>
```
All further changes follow from this interface splitting. Have a look in the given config files for all details.

### Changes in `preciceDict`

By default, the OpenFOAM adapter doesn't provide any connectivity information. Therefore, a new boolean variable called `connectivity` is introduced. This variable is associated to each interface and can be set accordingly. Note: Mesh connectivity can only be provided in case `locations faceNodes` is set (see section Adapter Implementation). Similar to the interface splitting in the `precice-config.xml` file, the interfaces also need to be defined in the `preciceDict` file. For example:

```
interfaces
{
Interface1
{
mesh Fluid-Mesh-Centers;
locations faceCenters;
connectivity false;
patches (interface);

readData
(
Heat-Flux
);

writeData
(
);
};

Interface2
{
mesh Fluid-Mesh-Nodes;
locations faceNodes;
connectivity true;
patches (interface);

readData
(
);

writeData
(
Temperature
);
};
};
```
The participant `Fluid` has its read data `Heat-Flux`, which is read on the `faceCenters`, and its write data `Temperature`, which is written to the `faceNodes`. The mesh connectivity needs only to be provided in case of the `faceNodes`, using the option `connectivity true`.

### General Notes

Since you now define mesh connectivity on your interface, you can export your coupling interface with the tag `<export:vtk directory="preCICE-output" />` in your `precice-config.xml`.

Visualizing these files (e.g. using ParaView) will show a triangular mesh, even though you use hexahedral meshes. This has nothing to do with your mesh and is just caused by the way the connectivity is defined in preCICE. As described above, the function `setMeshTriangles` is used to define the connectivity. Hence, every interface cell/face is represented by two triangles. The following image should give you an impression of a possible triangulated coupling mesh, which consists purely of hexahedral cells:

![triangulated](https://user-images.githubusercontent.com/33414590/55974257-96b07d80-5c87-11e9-9965-972b922c483d.png)

Note: Connectivity is defined on meshes associated with mesh nodes, which are named respectively e.g. `Fluid-Mesh-Nodes`. In this case, you could directly see the interface without applying filters by loading the `.vtk` files. In order to visualize additionally center based meshes, where no connectivity is provided, select a Glyph filter in ParaView. Furthermore, it makes a difference, on which participant the `<export...` tag is defined in your `precice-config.xml` file. Each participant exports interface meshes, which he provides or receives. The receiving participant filters out mesh parts that it does not need (for the mapping). Hence, a received mesh might look incomplete.

### Notes on 2D Cases

The geometry of the tutorial differs compared to the existing example: The out-of-plane thickness of the domain is reduced clearly and it is recommended. Otherwise your face centers have a quite large distance to the face nodes, which might trigger a preCICE warning. In that case, preCICE may filter out one of the meshes, especially in parallel simulations.

{% include disclaimer.html content="This offering is not approved or endorsed by OpenCFD Limited, producer and distributor of the OpenFOAM software via www.openfoam.com, and owner of the OPENFOAM® and OpenCFD® trade marks." %}
49 changes: 49 additions & 0 deletions flow-over-heated-plate-nearest-projection/clean.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#!/bin/sh
cd ${0%/*} || exit 1 # Run from this directory

echo "Cleaning..."

clean_case(){
cd ${1}
# Clean the result and auxiliary files
rm -fv *.vtk
rm -fv ${1}.log
rm -fv precice-*.log \
rm -fv precice-postProcessingInfo.log \
rm -fv precice-*-events.json
}

finished_clean(){
cd ..
}

# Openfoam
Name="fluid-openfoam"
clean_case ${Name}
# Clean specialized files
if [ -n "${WM_PROJECT}" ];
then
. $WM_PROJECT_DIR/bin/tools/CleanFunctions
cleanCase
rm -rfv ./0
touch ${Name}.foam
fi
finished_clean

Name="solid-openfoam"
clean_case ${Name}
# Clean specialized files
if [ -n "${WM_PROJECT}" ];
then
. $WM_PROJECT_DIR/bin/tools/CleanFunctions
cleanCase
rm -rfv ./0
touch ${Name}.foam
fi
finished_clean

# Remove the preCICE address files
rm -rfv precice-run

echo "Cleaning complete!"
#------------------------------------------------------------------------------
53 changes: 53 additions & 0 deletions flow-over-heated-plate-nearest-projection/fluid-openfoam/0.orig/T
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
FoamFile
{
version 2.0;
format ascii;
class volScalarField;
object T;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

dimensions [ 0 0 0 1 0 0 0 ];

internalField uniform 300;

boundaryField
{
interface
{
type fixedGradient;
gradient uniform 0;
}
inlet
{
type fixedValue;
value $internalField;
}
outlet
{
type zeroGradient;
}
top
{
type zeroGradient;
}
bottom
{
type zeroGradient;
}
slip-bottom
{
type zeroGradient;
}
outerWall
{
type zeroGradient;
}
defaultFaces
{
type empty;
}
}


// ************************************************************************* //
48 changes: 48 additions & 0 deletions flow-over-heated-plate-nearest-projection/fluid-openfoam/0.orig/U
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
FoamFile
{
version 2.0;
format ascii;
class volVectorField;
object U;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

dimensions [ 0 1 -1 0 0 0 0 ];

internalField uniform ( 0.1 0 0 );

boundaryField
{
interface
{
type noSlip;
}
inlet
{
type fixedValue;
value $internalField;
}
outlet
{
type zeroGradient;
}
top
{
type slip;
}
bottom
{
type noSlip;
}
slip-bottom
{
type slip;
}
defaultFaces
{
type empty;
}
}


// ************************************************************************* //
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
FoamFile
{
version 2.0;
format ascii;
class volScalarField;
location "0";
object alphat;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

dimensions [ 1 -1 -1 0 0 0 0 ];

internalField uniform 0;

boundaryField
{
interface
{
type compressible::alphatWallFunction;
value uniform 0;
}
inlet
{
type compressible::alphatWallFunction;
value uniform 0;
}
outlet
{
type compressible::alphatWallFunction;
value uniform 0;
}
top
{
type compressible::alphatWallFunction;
value uniform 0;
}
bottom
{
type compressible::alphatWallFunction;
value uniform 0;
}
slip-bottom
{
type compressible::alphatWallFunction;
value uniform 0;
}
defaultFaces
{
type empty;
}
}


// ************************************************************************* //
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
FoamFile
{
version 2.0;
format ascii;
class volScalarField;
location "0";
object epsilon;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

dimensions [ 0 2 -3 0 0 0 0 ];

internalField uniform 0.01;

boundaryField
{
interface
{
type epsilonWallFunction;
value uniform 0.01;
}
inlet
{
type epsilonWallFunction;
value uniform 0.01;
}
outlet
{
type epsilonWallFunction;
value uniform 0.01;
}
top
{
type epsilonWallFunction;
value uniform 0.01;
}
bottom
{
type epsilonWallFunction;
value uniform 0.01;
}
slip-bottom
{
type epsilonWallFunction;
value uniform 0.01;
}
defaultFaces
{
type empty;
}
}


// ************************************************************************* //
Loading