diff --git a/volume-coupled-flow/README.md b/volume-coupled-flow/README.md new file mode 100644 index 000000000..dd83f5fe9 --- /dev/null +++ b/volume-coupled-flow/README.md @@ -0,0 +1,65 @@ +--- +title: Volume-coupled flow +permalink: tutorials-volume-coupled-flow.html +keywords: volume coupling, OpenFOAM, source terms +summary: A dummy source participant is coupled to a fluid in a uni-directional way over a region of the domain. The coupling enforces source terms on that region. +--- + +{% note %} +Get the [case files of this tutorial](https://github.com/precice/tutorials/tree/master/volume-coupled-flow). Read how in the [tutorials introduction](https://www.precice.org/tutorials.html). +{% endnote %} + +## Setup + +We introduce flow into a fluid through a square-shaped source located between $$ (3.0, 1.0) $$ and $$ (3.5, 1.5) $$. The velocity at the source is constant in the x component $$ (U.x() = 10.0) $$. + +The state of the $$ U.x() $$ of the fluid at $$ t = 0.5s $$ (the source region is highlighted): + +![Ux](images/tutorials-volume-coupled-flow-Ux.png) + +This case is a convenient starting point for volume coupling where OpenFOAM is a reading participant. The writing Nutils participant (dummy source) can be replaced by a more complex solver according to the user's needs. + +## Available solvers + +Fluid participant: + +* OpenFOAM (buoyantPimpleFoam). For more information, have a look at the [OpenFOAM adapter documentation](https://precice.org/adapter-openfoam-overview.html). + +Source participant: + +* Nutils. For more information, have a look at the [Nutils adapter documentation](https://www.precice.org/adapter-nutils.html). This Nutils solver requires at least Nutils v7.0. + +## Running the simulation + +Open two separate terminals and start the participants by calling the respective run scripts `run.sh` located in each of the participants' directory. For example: + +```bash +cd fluid-openfoam +./run.sh +``` + +and + +```bash +cd source-nutils +./run.sh +``` + +## Post-processing + +The fluid participants generates a `.foam` file which can be visualized using, e.g., ParaView. + +## Notes on the configuration + +This case uses OpenFOAM's `fvOptions` to enforce source terms. Additionally, the coupled variable `U` needs to be given an alternative name in order for this to work: + +```C++ +FF +{ + nameU U_vol; +}; +``` + +Since OpenFOAM already uses `U`, we need to create an additional velocity variable to use specifically for the coupling. That allows us to carry the desired value over to OpenFOAM and apply it at the correct moment in the iteration. A simplified view of the workflow: + +![reading-config](images/tutorials-volume-coupled-flow-config.png) diff --git a/volume-coupled-flow/clean-tutorial.sh b/volume-coupled-flow/clean-tutorial.sh new file mode 120000 index 000000000..4713f5092 --- /dev/null +++ b/volume-coupled-flow/clean-tutorial.sh @@ -0,0 +1 @@ +../tools/clean-tutorial-base.sh \ No newline at end of file diff --git a/volume-coupled-flow/fluid-openfoam/0/T b/volume-coupled-flow/fluid-openfoam/0/T new file mode 100644 index 000000000..03a8bbf6a --- /dev/null +++ b/volume-coupled-flow/fluid-openfoam/0/T @@ -0,0 +1,40 @@ +FoamFile +{ + version 2.0; + format ascii; + class volScalarField; + object T; +} + +dimensions [ 0 0 0 1 0 0 0 ]; + +internalField uniform 300; + +boundaryField +{ + inlet + { + type fixedValue; + value $internalField; + } + outlet + { + type zeroGradient; + } + upperWall + { + type zeroGradient; + } + lowerWall + { + type zeroGradient; + } + frontAndBack + { + type empty; + } + defaultFaces + { + type empty; + } +} diff --git a/volume-coupled-flow/fluid-openfoam/0/U b/volume-coupled-flow/fluid-openfoam/0/U new file mode 100644 index 000000000..74f1b5960 --- /dev/null +++ b/volume-coupled-flow/fluid-openfoam/0/U @@ -0,0 +1,40 @@ +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 +{ + inlet + { + type fixedValue; + value $internalField; + } + outlet + { + type zeroGradient; + } + upperWall + { + type noSlip; + } + lowerWall + { + type noSlip; + } + frontAndBack + { + type empty; + } + defaultFaces + { + type empty; + } +} diff --git a/volume-coupled-flow/fluid-openfoam/0/U_vol b/volume-coupled-flow/fluid-openfoam/0/U_vol new file mode 100644 index 000000000..d66054ec8 --- /dev/null +++ b/volume-coupled-flow/fluid-openfoam/0/U_vol @@ -0,0 +1,40 @@ +FoamFile +{ + version 2.0; + format ascii; + class volVectorField; + object U_vol; +} + +dimensions [ 0 1 -1 0 0 0 0 ]; + +internalField uniform ( 0.1 0 0 ); + +boundaryField +{ + inlet + { + type fixedValue; + value $internalField; + } + outlet + { + type zeroGradient; + } + upperWall + { + type noSlip; + } + lowerWall + { + type noSlip; + } + frontAndBack + { + type empty; + } + defaultFaces + { + type empty; + } +} diff --git a/volume-coupled-flow/fluid-openfoam/0/alphat b/volume-coupled-flow/fluid-openfoam/0/alphat new file mode 100644 index 000000000..0fdc5b1a3 --- /dev/null +++ b/volume-coupled-flow/fluid-openfoam/0/alphat @@ -0,0 +1,43 @@ +FoamFile +{ + version 2.0; + format ascii; + class volScalarField; + object alphat; +} + +dimensions [ 1 -1 -1 0 0 0 0 ]; + +internalField uniform 0; + +boundaryField +{ + inlet + { + type compressible::alphatWallFunction; + value uniform 0; + } + outlet + { + type compressible::alphatWallFunction; + value uniform 0; + } + upperWall + { + type compressible::alphatWallFunction; + value uniform 0; + } + lowerWall + { + type compressible::alphatWallFunction; + value uniform 0; + } + frontAndBack + { + type empty; + } + defaultFaces + { + type empty; + } +} diff --git a/volume-coupled-flow/fluid-openfoam/0/epsilon b/volume-coupled-flow/fluid-openfoam/0/epsilon new file mode 100644 index 000000000..434843c59 --- /dev/null +++ b/volume-coupled-flow/fluid-openfoam/0/epsilon @@ -0,0 +1,43 @@ +FoamFile +{ + version 2.0; + format ascii; + class volScalarField; + object epsilon; +} + +dimensions [ 0 2 -3 0 0 0 0 ]; + +internalField uniform 0.01; + +boundaryField +{ + inlet + { + type epsilonWallFunction; + value uniform 0.01; + } + outlet + { + type epsilonWallFunction; + value uniform 0.01; + } + upperWall + { + type epsilonWallFunction; + value uniform 0.01; + } + lowerWall + { + type epsilonWallFunction; + value uniform 0.01; + } + frontAndBack + { + type empty; + } + defaultFaces + { + type empty; + } +} diff --git a/volume-coupled-flow/fluid-openfoam/0/k b/volume-coupled-flow/fluid-openfoam/0/k new file mode 100644 index 000000000..37d6a819b --- /dev/null +++ b/volume-coupled-flow/fluid-openfoam/0/k @@ -0,0 +1,43 @@ +FoamFile +{ + version 2.0; + format ascii; + class volScalarField; + object k; +} + +dimensions [ 0 2 -2 0 0 0 0 ]; + +internalField uniform 0.1; + +boundaryField +{ + inlet + { + type kqRWallFunction; + value uniform 0.1; + } + outlet + { + type kqRWallFunction; + value uniform 0.1; + } + upperWall + { + type kqRWallFunction; + value uniform 0.1; + } + lowerWall + { + type kqRWallFunction; + value uniform 0.1; + } + frontAndBack + { + type empty; + } + defaultFaces + { + type empty; + } +} diff --git a/volume-coupled-flow/fluid-openfoam/0/nut b/volume-coupled-flow/fluid-openfoam/0/nut new file mode 100644 index 000000000..f5c45835b --- /dev/null +++ b/volume-coupled-flow/fluid-openfoam/0/nut @@ -0,0 +1,43 @@ +FoamFile +{ + version 2.0; + format ascii; + class volScalarField; + object nut; +} + +dimensions [ 0 2 -1 0 0 0 0 ]; + +internalField uniform 0; + +boundaryField +{ + inlet + { + type nutkWallFunction; + value uniform 0; + } + outlet + { + type nutkWallFunction; + value uniform 0; + } + upperWall + { + type nutkWallFunction; + value uniform 0; + } + lowerWall + { + type nutkWallFunction; + value uniform 0; + } + frontAndBack + { + type empty; + } + defaultFaces + { + type empty; + } +} diff --git a/volume-coupled-flow/fluid-openfoam/0/p b/volume-coupled-flow/fluid-openfoam/0/p new file mode 100644 index 000000000..bbd499549 --- /dev/null +++ b/volume-coupled-flow/fluid-openfoam/0/p @@ -0,0 +1,43 @@ +FoamFile +{ + version 2.0; + format ascii; + class volScalarField; + object p; +} + +dimensions [ 1 -1 -2 0 0 0 0 ]; + +internalField uniform 103500; + +boundaryField +{ + inlet + { + type calculated; + value $internalField; + } + outlet + { + type calculated; + value $internalField; + } + upperWall + { + type calculated; + value $internalField; + } + lowerWall + { + type calculated; + value $internalField; + } + frontAndBack + { + type empty; + } + defaultFaces + { + type empty; + } +} diff --git a/volume-coupled-flow/fluid-openfoam/0/p_rgh b/volume-coupled-flow/fluid-openfoam/0/p_rgh new file mode 100644 index 000000000..57b7d70c3 --- /dev/null +++ b/volume-coupled-flow/fluid-openfoam/0/p_rgh @@ -0,0 +1,40 @@ +FoamFile +{ + version 2.0; + format ascii; + class volScalarField; + object p_rgh; +} + +dimensions [ 1 -1 -2 0 0 0 0 ]; + +internalField uniform 103500; + +boundaryField +{ + inlet + { + type zeroGradient; + } + outlet + { + type fixedValue; + value $internalField; + } + upperWall + { + type zeroGradient; + } + lowerWall + { + type zeroGradient; + } + frontAndBottom + { + type empty; + } + defaultFaces + { + type empty; + } +} diff --git a/volume-coupled-flow/fluid-openfoam/clean.sh b/volume-coupled-flow/fluid-openfoam/clean.sh new file mode 100755 index 000000000..c31d9fc76 --- /dev/null +++ b/volume-coupled-flow/fluid-openfoam/clean.sh @@ -0,0 +1,6 @@ +#!/bin/sh +set -e -u + +. ../../tools/cleaning-tools.sh + +clean_openfoam . diff --git a/volume-coupled-flow/fluid-openfoam/constant/fvOptions b/volume-coupled-flow/fluid-openfoam/constant/fvOptions new file mode 100644 index 000000000..d43c960da --- /dev/null +++ b/volume-coupled-flow/fluid-openfoam/constant/fvOptions @@ -0,0 +1,42 @@ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object fvOptions; +} + +codedSource +{ + type vectorCodedSource; + selectionMode cellSet; + cellSet box1; + + fields (U); + name sourceTime; + + codeConstrain //constrain + #{ + return; + #}; + + codeCorrect //correct + #{ + const labelList& cells = this->cells(); + const volVectorField& U_vol = mesh_.lookupObject("U_vol"); + for(auto cell : cells) + { + fld[cell].x() = U_vol[cell].x(); + } + #}; + + codeAddSup // source term + #{ + return; + #}; + + codeAddSupRho + #{ + return; + #}; +} \ No newline at end of file diff --git a/volume-coupled-flow/fluid-openfoam/constant/g b/volume-coupled-flow/fluid-openfoam/constant/g new file mode 100644 index 000000000..ca544e1f1 --- /dev/null +++ b/volume-coupled-flow/fluid-openfoam/constant/g @@ -0,0 +1,10 @@ +FoamFile +{ + version 2.0; + format ascii; + class uniformDimensionedVectorField; + object g; +} + +dimensions [0 1 -2 0 0 0 0]; +value (0 -9.81 0); diff --git a/volume-coupled-flow/fluid-openfoam/constant/thermophysicalProperties b/volume-coupled-flow/fluid-openfoam/constant/thermophysicalProperties new file mode 100644 index 000000000..7b93ee2ea --- /dev/null +++ b/volume-coupled-flow/fluid-openfoam/constant/thermophysicalProperties @@ -0,0 +1,37 @@ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + location "constant"; + object thermophysicalProperties; +} + +thermoType +{ + type heRhoThermo; + mixture pureMixture; + transport const; + thermo hConst; + equationOfState perfectGas; + specie specie; + energy sensibleEnthalpy; +} + +mixture +{ + specie + { + molWeight 24.0999; + } + thermodynamics + { + Cp 5000.0; + Hf 0; + } + transport + { + mu 0.0002; + Pr 0.01; + } +} diff --git a/volume-coupled-flow/fluid-openfoam/constant/turbulenceProperties b/volume-coupled-flow/fluid-openfoam/constant/turbulenceProperties new file mode 100644 index 000000000..b75c49530 --- /dev/null +++ b/volume-coupled-flow/fluid-openfoam/constant/turbulenceProperties @@ -0,0 +1,9 @@ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object turbulenceProperties; +} + +simulationType laminar; diff --git a/volume-coupled-flow/fluid-openfoam/run.sh b/volume-coupled-flow/fluid-openfoam/run.sh new file mode 100755 index 000000000..3418d12d1 --- /dev/null +++ b/volume-coupled-flow/fluid-openfoam/run.sh @@ -0,0 +1,9 @@ +#!/bin/sh +set -e -u + +blockMesh +topoSet +touch fluid-openfoam.foam + +../../tools/run-openfoam.sh "$@" +. ../../tools/openfoam-remove-empty-dirs.sh && openfoam_remove_empty_dirs diff --git a/volume-coupled-flow/fluid-openfoam/system/blockMeshDict b/volume-coupled-flow/fluid-openfoam/system/blockMeshDict new file mode 100644 index 000000000..baeacdef4 --- /dev/null +++ b/volume-coupled-flow/fluid-openfoam/system/blockMeshDict @@ -0,0 +1,87 @@ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object blockMeshDict; +} + +x0 0.; +x1 6.; + +y0 0.; +y1 2.; + +z0 0; +z1 1; + +vertices +( + ($x0 $y0 $z0 ) // 0 + ($x1 $y0 $z0 ) // 1 + ($x0 $y1 $z0 ) // 2 + ($x1 $y1 $z0 ) // 3 + + ($x0 $y0 $z1 ) // 4 + ($x1 $y0 $z1 ) // 5 + ($x0 $y1 $z1 ) // 6 + ($x1 $y1 $z1 ) // 7 +); + + +// Grading +h1 60; +v1 20; + +blocks +( + hex ( 0 1 3 2 4 5 7 6 ) + ($h1 $v1 1 ) + simpleGrading (1 1 1) + +); + +boundary +( + inlet + { + type patch; + faces + ( + ( 0 2 6 4 ) + ); + } + outlet + { + type patch; + faces + ( + ( 1 3 7 5 ) + ); + } + upperWall + { + type wall; + faces + ( + ( 2 3 7 6 ) + ); + } + lowerWall + { + type wall; + faces + ( + ( 0 1 5 4 ) + ); + } + frontAndBack + { + type empty; + faces + ( + ( 0 1 3 2 ) + ( 4 5 7 6 ) + ); + } +); diff --git a/volume-coupled-flow/fluid-openfoam/system/controlDict b/volume-coupled-flow/fluid-openfoam/system/controlDict new file mode 100644 index 000000000..4565b2d4a --- /dev/null +++ b/volume-coupled-flow/fluid-openfoam/system/controlDict @@ -0,0 +1,46 @@ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object controlDict; +} + +application buoyantPimpleFoam; + +startFrom startTime; + +startTime 0; + +stopAt endTime; + +endTime 4; + +deltaT 0.005; + +writeControl runTime; + +writeInterval 0.01; + +purgeWrite 0; + +writeFormat ascii; + +writePrecision 6; + +writeCompression off; + +timeFormat general; + +timePrecision 6; + +runTimeModifiable false; + +functions +{ + preCICE_Adapter + { + type preciceAdapterFunctionObject; + libs ("libpreciceAdapterFunctionObject.so"); + } +} diff --git a/volume-coupled-flow/fluid-openfoam/system/decomposeParDict b/volume-coupled-flow/fluid-openfoam/system/decomposeParDict new file mode 100644 index 000000000..0d1859e14 --- /dev/null +++ b/volume-coupled-flow/fluid-openfoam/system/decomposeParDict @@ -0,0 +1,16 @@ +FoamFile { + version 2.0; + class dictionary; + object decomposeParDict; + format ascii; +} + +numberOfSubdomains 2; + +method simple; + +simpleCoeffs +{ + n (2 1 1); + delta 0.001; +} diff --git a/volume-coupled-flow/fluid-openfoam/system/fvSchemes b/volume-coupled-flow/fluid-openfoam/system/fvSchemes new file mode 100644 index 000000000..fd48cb5b7 --- /dev/null +++ b/volume-coupled-flow/fluid-openfoam/system/fvSchemes @@ -0,0 +1,48 @@ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + location "system"; + object fvSchemes; +} + +ddtSchemes +{ + default Euler; +} + +gradSchemes +{ + default Gauss linear; +} + +divSchemes +{ + default none; + div(phi,U) Gauss upwind; + div(phi,h) Gauss upwind; + div(phi,e) Gauss upwind; + div(phi,k) Gauss upwind; + div(phi,epsilon) Gauss upwind; + div(phi,R) Gauss upwind; + div(phi,K) Gauss linear; + div(phi,Ekp) Gauss linear; + div(R) Gauss linear; + div(((rho*nuEff)*dev2(T(grad(U))))) Gauss linear; +} + +laplacianSchemes +{ + default Gauss linear corrected; +} + +interpolationSchemes +{ + default linear; +} + +snGradSchemes +{ + default corrected; +} diff --git a/volume-coupled-flow/fluid-openfoam/system/fvSolution b/volume-coupled-flow/fluid-openfoam/system/fvSolution new file mode 100644 index 000000000..e7047fa96 --- /dev/null +++ b/volume-coupled-flow/fluid-openfoam/system/fvSolution @@ -0,0 +1,55 @@ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + location "system"; + object fvSolution; +} + +solvers +{ + "rho.*" + { + solver PCG; + preconditioner DIC; + tolerance 0; + relTol 0; + } + + p_rgh + { + solver PCG; + preconditioner DIC; + tolerance 1e-8; + relTol 0.01; + } + + p_rghFinal + { + $p_rgh; + relTol 0; + } + + "(U|h|e|k|epsilon|R)" + { + solver PBiCGStab; + preconditioner DILU; + tolerance 1e-6; + relTol 0.1; + } + + "(U|h|e|k|epsilon|R)Final" + { + $U; + relTol 0; + } +} + +PIMPLE +{ + momentumPredictor yes; + nOuterCorrectors 1; + nCorrectors 2; + nNonOrthogonalCorrectors 0; +} diff --git a/volume-coupled-flow/fluid-openfoam/system/preciceDict b/volume-coupled-flow/fluid-openfoam/system/preciceDict new file mode 100644 index 000000000..93d1204d6 --- /dev/null +++ b/volume-coupled-flow/fluid-openfoam/system/preciceDict @@ -0,0 +1,39 @@ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + location "system"; + object preciceDict; +} + +preciceConfig "../precice-config.xml"; + +participant Fluid; + +modules (FF); + +interfaces +{ + Interface1 + { + mesh Fluid-Mesh; + patches (); + cellSets (box1); + locations volumeCenters; + + readData + ( + Velocity + ); + + writeData + ( + ); + }; +}; + +FF +{ + nameU U_vol; +}; diff --git a/volume-coupled-flow/fluid-openfoam/system/topoSetDict b/volume-coupled-flow/fluid-openfoam/system/topoSetDict new file mode 100644 index 000000000..602cd60e7 --- /dev/null +++ b/volume-coupled-flow/fluid-openfoam/system/topoSetDict @@ -0,0 +1,20 @@ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object topoSetDict; +} + +actions +( + { + name box1; + type cellSet; + action new; + source boxToCell; + box (3.0 1.0 0.0) (3.5 1.5 1.0); + } +); + + diff --git a/volume-coupled-flow/images/tutorials-volume-coupled-flow-Ux.png b/volume-coupled-flow/images/tutorials-volume-coupled-flow-Ux.png new file mode 100644 index 000000000..26a5edeaa Binary files /dev/null and b/volume-coupled-flow/images/tutorials-volume-coupled-flow-Ux.png differ diff --git a/volume-coupled-flow/images/tutorials-volume-coupled-flow-config.png b/volume-coupled-flow/images/tutorials-volume-coupled-flow-config.png new file mode 100644 index 000000000..bd9f8d341 Binary files /dev/null and b/volume-coupled-flow/images/tutorials-volume-coupled-flow-config.png differ diff --git a/volume-coupled-flow/precice-config.xml b/volume-coupled-flow/precice-config.xml new file mode 100644 index 000000000..d175f6d28 --- /dev/null +++ b/volume-coupled-flow/precice-config.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/volume-coupled-flow/source-nutils/clean.sh b/volume-coupled-flow/source-nutils/clean.sh new file mode 100755 index 000000000..6893c1ea5 --- /dev/null +++ b/volume-coupled-flow/source-nutils/clean.sh @@ -0,0 +1,6 @@ +#!/bin/sh +set -e -u + +. ../../tools/cleaning-tools.sh + +clean_nutils . diff --git a/volume-coupled-flow/source-nutils/run.sh b/volume-coupled-flow/source-nutils/run.sh new file mode 100755 index 000000000..3ef84763d --- /dev/null +++ b/volume-coupled-flow/source-nutils/run.sh @@ -0,0 +1,4 @@ +#!/bin/sh +set -e -u + +python3 source.py diff --git a/volume-coupled-flow/source-nutils/source.py b/volume-coupled-flow/source-nutils/source.py new file mode 100644 index 000000000..71bcfeb95 --- /dev/null +++ b/volume-coupled-flow/source-nutils/source.py @@ -0,0 +1,70 @@ +#! /usr/bin/env python3 + + +from nutils import function, mesh, cli, solver, export +import treelog as log +import numpy as np +import precice +from mpi4py import MPI + + +def main(): + + print("Running Nutils") + + timestamp = 0.0 + + # define the Nutils mesh + nx = 60 + ny = 20 + + grid = np.linspace(0, 6, nx + 1), np.linspace(0, 2, ny + 1) + domain, geom = mesh.rectilinear(grid) + domain = domain.withboundary(inflow="left", outflow="right", wall="top,bottom") + + # cloud of Gauss points + uniform_grid = domain.sample("uniform", degree=1) + + # Nutils namespace + ns = function.Namespace(fallback_length=2) + ns.x = geom + + # preCICE setup + participant = precice.Participant("Source-Velocity", "../precice-config.xml", 0, 1) + + # define coupling mesh + mesh_name = "Source-Mesh" + vertices = uniform_grid.eval(ns.x) + vertex_ids = participant.set_mesh_vertices(mesh_name, vertices) + + source_values = np.full((vertices.shape[0], 2), [10.0, 0.0]) + + # coupling data + data_name = "Velocity" + + participant.initialize() + precice_dt = participant.get_max_time_step_size() + + timestep = 0 + dt = 0.005 + + while participant.is_coupling_ongoing(): + + precice_dt = participant.get_max_time_step_size() + + # potentially adjust non-matching timestep sizes + dt = min(dt, precice_dt) + + participant.write_data(mesh_name, data_name, vertex_ids, source_values) + # do the coupling + participant.advance(dt) + + # advance variables + timestep += 1 + timestamp += dt + + participant.finalize() + + +if __name__ == "__main__": + cli.run(main)