This guide helps you to upgrade from preCICE 2.x to preCICE 3.x.

preCICE API

  • The main preCICE header file was renamed. This means that you need to:
    • Replace #include "precice/SolverInterface.hpp" with #include "precice/precice.hpp".
    • Where declaring a preCICE object, replace the precice::SolverInterface type with precice::Participant
    • Where constructing a preCICE object, replace the precice::SolverInterface( ... ) constructor with precice::Participant( ... ).
    • Consider renaming your objects from, e.g., interface to participant, to better reflect the purpose and to be consistent with the rest of the changes.
  • Migrate connectivity information to the vertex-only API. All setMeshX methods take vertex IDs as input and return nothing.
    • Directly define face elements or cells of your coupling mesh available in your solver by passing their vectices to preCICE, which automatically handles edges of triangles etc. See Mesh Connectivity for more information.
    • Rename setMeshTriangleWithEdges to setMeshTriangle and setMeshQuadWithEdges to setMeshQuad. The edge-based implementation was removed.
    • Use the new bulk functions to reduce sanitization overhead: setMeshEdges, setMeshTriangles, setMeshQuads, setMeshTetrahedra
  • Remove mapWriteDataFrom() and mapReadDataTo().
  • Remove initializeData() and initialize the data after defining the mesh and before calling initialize() if requiresInitialData() is true.
  • Remove isReadDataAvailable() and isWriteDataRequired(), or replace them with your own logic if you are subcycling in your adapter.
  • Remove getMeshVertices() and getMeshVertexIDsFromPositions(). This information is already known by the adapter.
  • Replace precice::constants::* with isActionRequired() and markActionFulfilled() with their respective requirement clause: requiresInitialData(), requiresReadingCheckpoint() or requiresWritingCheckpoint(). If these requirements are checked, then they are promised to be acted on.
  • Replace isMeshConnectivityRequired with requiresMeshConnectivityFor.
  • Replace isGradientDataRequired with requiresGradientDataFor. Instead of the input argument dataID, pass the meshName and dataName.
  • Remove the now obsolete calls to getMeshID() and getDataID().
  • Remove hasMesh() and hasData().
  • Replace the commands to read data: readBlockVectorData, readVectorData, readBlockScalarData, readScalarData with a single command readData.
  • Replace the commands to write data: writeBlockVectorData, writeVectorData, writeBlockScalarData, writeScalarData with a single command writeData.
  • Replace the commands to write gradient data: writeBlockVectorGradientData, writeVectorGradientData, writeBlockScalarGradientData, writeScalarGradientData with a single command writeGradientData.
  • Replace getMeshVerticesAndIDs with getMeshVertexIDsAndCoordinates. Change the input argument meshID to meshName.
  • Change integer input argument mesh ID to a string with the mesh name in the API commands hasMesh, requiresMeshConnectivityFor, setMeshVertex, getMeshVertexSize, setMeshVertices, setMeshEdge, setMeshEdges, setMeshTriangle, setMeshTriangles, setMeshQuad, setMeshQuads, setMeshTetrahedron, setMeshTetrahedrons, setMeshAccessRegion.
  • Replace double preciceDt = initialize() and double preciceDt = advance(dt) with initialize() and advance(dt), as they don’t have a return value. If you need to know preciceDt, you can use double preciceDt = getMaxTimeStepSize().
  • Replace getDimensions() with either getMeshDimensions(meshName) or getDataDimensions(meshName, dataName), depending on whether the mesh dimension or data dimension is required.

  • Renamed CMake variables as follows:
    • PRECICE_PETScMapping -> PRECICE_FEATURE_PETSC_MAPPING
    • PRECICE_MPICommunication -> PRECICE_FEATURE_MPI_COMMUNICATION
    • PRECICE_Packages -> PRECICE_CONFIGURE_PACKAGE_GENERATION
    • PRECICE_PythonActions -> PRECICE_FEATURE_PYTHON_ACTIONS
    • PRECICE_ENABLE_C -> PRECICE_BINDINGS_C
    • PRECICE_ENABLE_FORTRAN ->PRECICE_BINDINGS_FORTRAN
    • PRECICE_ENABLE_LIBBACKTRACE -> PRECICE_FEATURE_LIBBACKTRACE_STACKTRACES

Add relativeReadTime for all read data calls

The previously optional argument relativeReadTime is now mandatory for read data calls. This requires you to update all read data calls. See time interpolation for more details on this argument. If you don’t want to use subcycling or time interpolation, you can simply get the required relativeReadTime by calling double preciceDt = getMaxTimeStepSize() call. Change:

- couplingInterface.readBlockVectorData(meshName, dataReadName, numberOfVertices, vertexIDs.data(), readData.data());
+ preciceDt = couplingInterface.getMaxTimeStepSize();
+ couplingInterface.readBlockVectorData(meshName, dataReadName, numberOfVertices, vertexIDs.data(), preciceDt, readData.data())

If you use subcycling, please do the following:

- couplingInterface.readBlockVectorData(meshName, dataReadName, numberOfVertices, vertexIDs.data(), readData.data());
+ preciceDt = couplingInterface.getMaxTimeStepSize();
  double dt = min(preciceDt, solverDt);
+ couplingInterface.readBlockVectorData(meshName, dataReadName, numberOfVertices, vertexIDs.data(), dt, readData.data())

Remove initializeData() calls

The API function initializeData() has been removed in #1350. initialize() now takes care of all the initialization – including data initialization. This means, you have to call initialize(), where you previously called initializeData(). Be aware that this means that you have to write initial data before calling initialize(). Change:

- double dt = 0;
- dt        = couplingInterface.initialize();
  std::vector<double> writeData(dimensions, writeValue);

  // Write initial data before calling initialize()
  const std::string & cowid = actionWriteInitialData();
  if (couplingInterface.isActionRequired(cowid)) {
    couplingInterface.writeVectorData(writeDataID, vertexID, writeData.data());
    couplingInterface.markActionFulfilled(cowid);
  }

  // Move initialize to the place where you called initializeData() previously.
- couplingInterface.initializeData();
+ couplingInterface.initialize();
+ double dt = couplingInterface.getMaxTimeWindowSize();

Typical error message that should lead you here:

error: ‘class precice::SolverInterface’ has no member named ‘initializeData’; did you mean ‘initialize’?
   63 |   couplingInterface.initializeData();
      |                     ^~~~~~~~~~~~~~
      |                     initialize

preCICE configuration file

  • The XML tag <solver-interface> was removed and all underlying functionality was moved to the <precice-configuration> tag. Remove the lines including <solver-interface> and </solver-interface>, and move any attributes (such as experimental) from the solver-interface to the precice-configuration tag. Move the sync-mode attribute to the new <profiling> tag (see below).
  • The dimensions configuration is now defined per mesh. Move the dimensions="2" or dimensions="3" from the <solver-interface> tag to each <mesh> tag: <mesh name="MeshOne" dimensions="3">.
  • Replace mapping constraint scaled-consistent with scaled-consistent-surface.
  • Replace <use-mesh provide="true" ... /> with <provide-mesh ... />, and <use-mesh provide="false" ... /> with <receive-mesh ... />.
  • Remove <extraplation-order value="..." /> in <coupling-scheme>.
  • Replace all RBF related <mapping:rbf-... /> tags. RBF mappings are now defined in terms of the applied solver (current options <mapping:rbf-global-direct ..., <mapping:rbf-global-iterative or <mapping:rbf-pum-direct ...) and the applied basis function as a subtag of the solver. Users should use the additionally added auto selection of an appropriate solver, which omits the solver specification, as follows:
<mapping:rbf  ...>
  <basis-function:... />
</mapping:rbf>

Example:

preCICE version 2 rbf configuration:

<mapping:compact-polynomial-c0 direction="read" from= ... support-radius="0.3" />

corresponding preCICE version 3 rbf configuration (using the recommended auto selection):

<mapping:rbf  direction="read" from= ...>
  <basis-function:compact-polynomial-c0 support-radius="0.3" />
</mapping:rbf>

A specific solver should only be configured if you want to force preCICE to use and stick to a certain solver, independent of your problem size and execution.

  • Renamed <mapping:rbf... use-qr-decomposition="true" /> to <mapping:rbf-global-direct ... > <basis-function:... /> </mapping:rbf-global-direct>.
  • Remove all timings in the mapping configuration <mapping: ... timing="initial/onadvance/ondemand" />.
  • Remove the preallocations in the mapping configuration <mapping: ... preallocation="tree/compute/estimate/save/off" />.
  • Renamed the <m2n: ... /> attributes from -> acceptor and to -> connector

  • Moved and renamed the optional attribute <read-data: ... waveform-order="1" /> to <data:scalar/vector ... waveform-degree="1"

  • We dropped quite some functionality concerning data actions as these were not used to the best of our knowledge and hard to maintain:
    • Removed deprecated action timings regular-prior, regular-post, on-exchange-prior, and on-exchange-post.
    • Removed action timings read-mapping-prior, write-mapping-prior, and on-time-window-complete-post.
    • Removed ComputeCurvatureAction and ScaleByDtAction actions.
    • Removed callback functions vertexCallback and postAction from PythonAction interface.
    • Removed timewindowsize from the performAction signature of PythonAction. The new signature is performAction(time, data)
  • We removed the plain Broyden acceleration. You could use IQN-IMVJ instead, which is a multi-vector Broyden variant.

Language bindings

The renaming of the preCICE API from SolverInterface to preCICE also applies to all language bindings. The C++ header change precice/SolverInterface.hpp to precice/precice.hpp becomes:

  • In C: Replace #include "precice/SolverInterfaceC.h" with #include "precice/preciceC.h" and precicec_createSolverInterface( ... ) with precicec_createParticipant( ... ).
  • In Julia: Replace precicec_createSolverInterface( ... ) with precicec_createParticipant( ... ).
  • In Matlab: Replace SolverInterface with Participant everywhere.
  • In Fortran, Python: You don’t need to change anything.

Profiling