From 03b0cbb283be99d1e4b478dd2f519a3b318b1548 Mon Sep 17 00:00:00 2001 From: Benjamin Rodenberg Date: Sun, 28 May 2023 13:40:10 +0200 Subject: [PATCH] v3: Update documentation w.r.t getMaxTimeStep(). (#258) * Update documentation w.r.t getMaxTimeStep(). * Implements changes from https://github.com/precice/precice/pull/1623 --------- Co-authored-by: Benjamin Uekermann --- .../configuration/configuration-coupling.md | 6 +++--- ...uple-your-code-existing-mpi-environment.md | 2 +- .../couple-your-code-gradient-data.md | 4 ++-- .../couple-your-code-implicit-coupling.md | 5 +++-- ...le-your-code-initializing-coupling-data.md | 3 +-- .../couple-your-code-mesh-and-data-access.md | 5 +++-- .../couple-your-code-steering-methods.md | 21 ++++++++++++------- .../couple-your-code-time-step-sizes.md | 17 ++++++++++----- .../couple-your-code-waveform.md | 7 ++++--- 9 files changed, 43 insertions(+), 27 deletions(-) diff --git a/pages/docs/configuration/configuration-coupling.md b/pages/docs/configuration/configuration-coupling.md index ea9a4fa109..75ff1cc2bc 100644 --- a/pages/docs/configuration/configuration-coupling.md +++ b/pages/docs/configuration/configuration-coupling.md @@ -39,7 +39,7 @@ Now, the `first` and the `second` participant are executed at the same time. Act With `max-time-windows`, you say how many coupling time windows you want to simulate. Alternatively, you can use: ```xml - + ``` Afterwards, @@ -68,7 +68,7 @@ For implicit coupling, you need to specify several additional options: ... - + @@ -82,7 +82,7 @@ To control the number of sub-iterations within an implicit coupling loop, you ca * `relative-convergence-measure` for a relative criterion * `absolute-convergence-measure` for an absolute criterion -* `min-iteration-convergence-measure` to require a minimum of iterations +* `min-iteration-convergence-measure` to require a minimum of iterations If multiple convergence measure are combined they all need to be fulfilled to go to the next time window. Alternatively, you can specify `suffices="yes"` within any convergence measure. The data used for a convergence measure needs to be exchanged within the coupling-scheme (tag `exchange`). diff --git a/pages/docs/couple-your-code/couple-your-code-existing-mpi-environment.md b/pages/docs/couple-your-code/couple-your-code-existing-mpi-environment.md index 6a07cf2a0f..dcfcf41e73 100644 --- a/pages/docs/couple-your-code/couple-your-code-existing-mpi-environment.md +++ b/pages/docs/couple-your-code/couple-your-code-existing-mpi-environment.md @@ -31,7 +31,7 @@ precice.configure("precice-config.xml"); [...] // declare meshes vertices etc. -double preciceDt = precice.initialize(); +precice.initialize(); [...] // solving and coupling diff --git a/pages/docs/couple-your-code/couple-your-code-gradient-data.md b/pages/docs/couple-your-code/couple-your-code-gradient-data.md index 50bd802c44..c06e35ea12 100644 --- a/pages/docs/couple-your-code/couple-your-code-gradient-data.md +++ b/pages/docs/couple-your-code/couple-your-code-gradient-data.md @@ -72,7 +72,7 @@ double* stress = new double[vertexSize * dim]; // create gradient data double* stressGradient = new double[vertexSize * dim * dim] [...] -preciceDt = precice.initialize(); +precice.initialize(); while (not simulationDone()){ // time loop precice.readBlockVectorData(displID, vertexSize, vertexIDs, displacements); @@ -89,7 +89,7 @@ while (not simulationDone()){ // time loop precice.writeBlockVectorGradientData(stressID, vertexSize, vertexIDs, stressGradient); } - preciceDt = precice.advance(dt); + precice.advance(dt); } [...] ``` diff --git a/pages/docs/couple-your-code/couple-your-code-implicit-coupling.md b/pages/docs/couple-your-code/couple-your-code-implicit-coupling.md index 8a086257d3..a4a34537bd 100644 --- a/pages/docs/couple-your-code/couple-your-code-implicit-coupling.md +++ b/pages/docs/couple-your-code/couple-your-code-implicit-coupling.md @@ -49,12 +49,13 @@ double dt; // actual time step size ``` ```cpp -preciceDt = precice.initialize(); +precice.initialize(); while (precice.isCouplingOngoing()){ if(precice.isActionRequired(cowic)){ saveOldState(); // save checkpoint precice.markActionFulfilled(cowic); } + preciceDt = precice.getMaxTimeStepSize(); solverDt = beginTimeStep(); // e.g. compute adaptive dt dt = min(preciceDt, solverDt); precice.readBlockVectorData(displID, vertexSize, vertexIDs, displacements); @@ -62,7 +63,7 @@ while (precice.isCouplingOngoing()){ solveTimeStep(dt); computeForces(forces); precice.writeBlockVectorData(forceID, vertexSize, vertexIDs, forces); - preciceDt = precice.advance(dt); + precice.advance(dt); if(precice.isActionRequired(coric)){ // time step not converged reloadOldState(); // set variables back to checkpoint precice.markActionFulfilled(coric); diff --git a/pages/docs/couple-your-code/couple-your-code-initializing-coupling-data.md b/pages/docs/couple-your-code/couple-your-code-initializing-coupling-data.md index a2823f6fc2..d1bdd8325b 100644 --- a/pages/docs/couple-your-code/couple-your-code-initializing-coupling-data.md +++ b/pages/docs/couple-your-code/couple-your-code-initializing-coupling-data.md @@ -33,14 +33,13 @@ double* displacements = new double[vertexSize*dim]; [...] -preciceDt = precice.initialize(); if(precice.isActionRequired(cowid)){ precice.writeBlockVectorData(forceID, vertexSize, vertexIDs, forces); precice.markActionFulfilled(cowid); } -precice.initializeData(); +precice.initialize(); while (precice.isCouplingOngoing()){ [...] diff --git a/pages/docs/couple-your-code/couple-your-code-mesh-and-data-access.md b/pages/docs/couple-your-code/couple-your-code-mesh-and-data-access.md index f56b075d1a..8e26cb5ab3 100644 --- a/pages/docs/couple-your-code/couple-your-code-mesh-and-data-access.md +++ b/pages/docs/couple-your-code/couple-your-code-mesh-and-data-access.md @@ -64,8 +64,9 @@ double solverDt; // solver time step size double preciceDt; // maximum precice time step size double dt; // actual time step size -preciceDt = precice.initialize(); +precice.initialize(); while (not simulationDone()){ // time loop + preciceDt = precice.getMaxTimeStepSize(); solverDt = beginTimeStep(); // e.g. compute adaptive dt dt = min(preciceDt, solverDt); precice.readBlockVectorData(displID, vertexSize, vertexIDs, displacements); @@ -73,7 +74,7 @@ while (not simulationDone()){ // time loop solveTimeStep(dt); computeForces(forces); precice.writeBlockVectorData(forceID, vertexSize, vertexIDs, forces); - preciceDt = precice.advance(dt); + precice.advance(dt); endTimeStep(); // e.g. update variables, increment time } precice.finalize(); // frees data structures and closes communication channels diff --git a/pages/docs/couple-your-code/couple-your-code-steering-methods.md b/pages/docs/couple-your-code/couple-your-code-steering-methods.md index 2328ace0c4..76a1669744 100644 --- a/pages/docs/couple-your-code/couple-your-code-steering-methods.md +++ b/pages/docs/couple-your-code/couple-your-code-steering-methods.md @@ -11,18 +11,24 @@ The handle to the preCICE API is the class `precice::SolverInterface`. Its const ```cpp SolverInterface( String participantName, String configurationFileName, int rank, int size ); -double initialize(); -double advance ( double computedTimeStepLength ); +void initialize(); +void advance ( double computedTimeStepSize ); 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](couple-your-code-time-step-sizes.html). -* `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. +* `initialize` establishes communication channels and sets up data structures of preCICE. +* `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`). Additionally, 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: +The following function allows us to query the maximum allowed time step size from preCICE: + +```cpp +double getMaxTimeStepSize(); +``` + +But let's ignore the details of time step sizes for the moment. This will be the topic of [Step 5](couple-your-code-time-step-sizes.html). We can now extend the code of our fluid solver: ```cpp #include "precice/SolverInterface.hpp" @@ -35,12 +41,13 @@ double solverDt; // solver time step size double preciceDt; // maximum precice time step size double dt; // actual time step size -preciceDt = precice.initialize(); +precice.initialize(); while (not simulationDone()){ // time loop + preciceDt = getMaxTimeStepSize(); solverDt = beginTimeStep(); // e.g. compute adaptive dt dt = min(preciceDt, solverDt); // more about this in Step 5 solveTimeStep(dt); - preciceDt = precice.advance(dt); + precice.advance(dt); endTimeStep(); // e.g. update variables, increment time } precice.finalize(); // frees data structures and closes communication channels diff --git a/pages/docs/couple-your-code/couple-your-code-time-step-sizes.md b/pages/docs/couple-your-code/couple-your-code-time-step-sizes.md index 4ee1531fca..e406d7f3aa 100644 --- a/pages/docs/couple-your-code/couple-your-code-time-step-sizes.md +++ b/pages/docs/couple-your-code/couple-your-code-time-step-sizes.md @@ -15,8 +15,9 @@ double solverDt; // solver time step size double preciceDt; // maximum precice time step size double dt; // actual time step size -preciceDt = precice.initialize(); +precice.initialize(); while (not simulationDone()){ // time loop + preciceDt = precice.getMaxTimeStepSize(); solverDt = beginTimeStep(); // e.g. compute adaptive dt dt = min(preciceDt, solverDt); solveTimeStep(dt); @@ -47,10 +48,10 @@ The figure below illustrates this procedure (k is the subcycling index, the dash ![Timestepping with a fixed time window](images/docs/couple-your-code-timestepping-fixed.png) -* After each time step, both participants tell preCICE which time step size `dt` they just used. This way, preCICE can keep track of the total time. preCICE returns the remainder time to the next window. +* After each time step, both participants tell preCICE which time step size `dt` they just used by calling `precice.advance(dt)`. This way, preCICE can keep track of the total time. `preciceDt` is the remainder time to the next window: ```c++ -preciceDt = precice.advance(dt); +preciceDt = precice.getMaxTimeStepSize(); ``` * Both participants compute their next (adaptive) time step size. It can be larger or smaller than the remainder `preciceDt`. @@ -85,6 +86,7 @@ You can use them as follows: ```c++ while (not simulationDone()){ // time loop + preciceDt = precice.getMaxTimeStepSize(); solverDt = beginTimeStep(); // e.g. compute adaptive dt dt = min(preciceDt, solverDt); if (precice.isReadDataAvailable()){ @@ -96,7 +98,7 @@ while (not simulationDone()){ // time loop computeForces(forces); precice.writeBlockVectorData(forceID, vertexSize, vertexIDs, forces); } - preciceDt = precice.advance(dt); + precice.advance(dt); endTimeStep(); // e.g. update variables, increment time } ``` @@ -111,10 +113,15 @@ The `first` participant sets the time step size. This requires that the `second` * In `advance`, this time step size is given to preCICE (Step 2). ```c++ -preciceDt = precice.advance(dt); +precice.advance(dt); ``` * preCICE has tracked the time level of the orange participant A and returns the remainder to reach B's time step size. + +```c++ +preciceDt = precice.getMaxTimeStepSize(); +``` + * A computes its next (adaptive) time step size. It can now be larger or smaller than the remainder. ```c++ diff --git a/pages/docs/couple-your-code/couple-your-code-waveform.md b/pages/docs/couple-your-code/couple-your-code-waveform.md index e874787b3f..528cf3d904 100644 --- a/pages/docs/couple-your-code/couple-your-code-waveform.md +++ b/pages/docs/couple-your-code/couple-your-code-waveform.md @@ -50,7 +50,7 @@ void readBlockVectorData(int dataID, int size, const int* valueIndices, double* void readBlockVectorData(int dataID, int size, const int* valueIndices, double relativeReadTime, double* values) const; ``` -`relativeReadTime` describes the time relatively to the beginning of the current time step. This means that `relativeReadTime = 0` gives us access to data at the beginning of the time step. By choosing `relativeReadTime > 0` we can sample data at later points. The maximum allowed `relativeReadTime` corresponds to the remaining time until the end of the current time window. Remember that the remaining time until the end of the time window is always returned when calling `preciceDt = precice.advance(dt)` as `preciceDt`. So `relativeReadTime = preciceDt` corresponds to sampling data at the end of the current time window. +`relativeReadTime` describes the time relatively to the beginning of the current time step. This means that `relativeReadTime = 0` gives us access to data at the beginning of the time step. By choosing `relativeReadTime > 0` we can sample data at later points. The maximum allowed `relativeReadTime` corresponds to the remaining time until the end of the current time window. Remember that the remaining time until the end of the time window is always returned when calling `preciceDt = precice.getMaxTimeStepSize()` as `preciceDt`. So `relativeReadTime = preciceDt` corresponds to sampling data at the end of the current time window. If we choose to use a smaller time step size `dt < preciceDt`, we apply subcycling and therefore `relativeReadTime = dt` corresponds to sampling data at the end of the time step. But we can also use smaller values for `relativeReadTime`, as shown in the usage example below. When using subcycling, it is important to note that `relativeReadTime = preciceDt` is the default behavior, if no `relativeReadTime` is provided, because preCICE cannot know the `dt` our solver wants to use. This also means that if subcycling is applied one must use the experimental API and provide `relativeReadTime` to benefit from the higher accuracy waveforms. @@ -74,10 +74,11 @@ We are now ready to extend the example from ["Step 6 - Implicit coupling"](coupl ```cpp ... -preciceDt = precice.initialize(); +precice.initialize(); while (not simulationDone()){ // time loop // write checkpoint ... + preciceDt = precice.getMaxTimeStepSize(); solverDt = beginTimeStep(); // e.g. compute adaptive dt dt = min(preciceDt, solverDt); if (precice.isReadDataAvailable()){ // if waveform order >= 1 always true, because we can sample at arbitrary points @@ -90,7 +91,7 @@ while (not simulationDone()){ // time loop computeForces(forces); precice.writeBlockVectorData(forceID, vertexSize, vertexIDs, forces); } - preciceDt = precice.advance(dt); + precice.advance(dt); // read checkpoint & end time step ... }