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 timestep size the solver should use next. But let’s ignore timestep sizes for the moment. This will be the topic of Step 5.
  • advance needs to be called after the computation of every timestep to advance the coupling. As an argument, you have to pass the solver’s last timestep size (dt). Again, the function returns the next maximum timestep size you can use (precice_dt). 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 solver_dt; // solver timestep size
double precice_dt; // maximum precice timestep size
double dt; // actual time step size

precice_dt = precice.initialize();
while (not simulationDone()){ // time loop
  solver_dt = beginTimeStep(); // e.g. compute adaptive dt
  dt = min(precice_dt, solver_dt); // more about this in Step 5
  precice_dt = precice.advance(dt);
  endTimeStep(); // e.g. update variables, increment time
precice.finalize(); // frees data structures and closes communication channels