In this step, you get to know the most important API functions of preCICE: initialize, advance, and finalize.
As a first preparation step, you need to include the preCICE library headers. In C++, you need to include the file SolverInterface.hpp.
The handle to the preCICE API is the class precice::SolverInterface
. Its constructor requires the participant’s name, the preCICE configuration file’s name and the rank
and size
of the current thread. Once the basic preCICE interface is set up, we can steer the behaviour of preCICE. For that we need the following functions:
SolverInterface( String participantName, String configurationFileName, int rank, int size );
double initialize();
double advance ( double computedTimeStepLength );
void finalize();
What do they do?
initialize
establishes communication channels, sets up data structures of preCICE, and returns the maximum time step size the solver should use next. But let’s ignore time step sizes for the moment. This will be the topic of Step 5.advance
needs to be called after the computation of every time step to advance the coupling. As an argument, you have to pass the solver’s last time step size (dt
). Again, the function returns the next maximum time step size you can use (preciceDt
). More importantly, it maps coupling data between the coupling meshes, it communicates coupling data between the coupled participants, and it accelerates coupling data. One could say the complete coupling happens within this single function.finalize
frees the preCICE data structures and closes communication channels.
So, let’s extend the code of our fluid solver:
#include "precice/SolverInterface.hpp"
turnOnSolver(); //e.g. setup and partition mesh
precice::SolverInterface precice("FluidSolver","precice-config.xml",rank,size); // constructor
double solverDt; // solver time step size
double preciceDt; // maximum precice time step size
double dt; // actual time step size
preciceDt = precice.initialize();
while (not simulationDone()){ // time loop
solverDt = beginTimeStep(); // e.g. compute adaptive dt
dt = min(preciceDt, solverDt); // more about this in Step 5
solveTimeStep(dt);
preciceDt = precice.advance(dt);
endTimeStep(); // e.g. update variables, increment time
}
precice.finalize(); // frees data structures and closes communication channels
turnOffSolver();