diff --git a/css/customstyles-precice.css b/css/customstyles-precice.css
index 360bc4fef2b..06e40be4a4c 100644
--- a/css/customstyles-precice.css
+++ b/css/customstyles-precice.css
@@ -340,4 +340,14 @@ div#tg-sb-sidebar {
div#tg-sb-sidebar {
position: static;
}
+/* style navtabs */
+.post-content ol li, .post-content ul li {
+ margin: 0px;
+}
+div.tab-content {
+ padding: 0px;
+ background-color: white;
+ }
+div.tab-content div.tab-pane pre {
+ margin-top: 0px;
}
\ No newline at end of file
diff --git a/css/printstyles.css b/css/printstyles.css
index 6735dccb72a..a8fc64e7af0 100644
--- a/css/printstyles.css
+++ b/css/printstyles.css
@@ -40,7 +40,7 @@ a[href^="http:"]::after, a[href^="https:"]::after, a[href^="ftp:"]::after {
a[href] {
color: #0A76BB !important;
}
-a[href*="mailto"]::after, a[data-toggle="tooltip"]::after, a[href].noCrossRef::after {
+a[href*="mailto"]::after, a[data-toggle="tooltip"]::after, a[href].noCrossRef::after, a[data-toggle="tab"]::after {
content: "";
}
@@ -219,4 +219,55 @@ pre > code {
h1[id], h2[id], h3[id], h4[id], h5[id], h6[id], dt[id] {
padding-top: 1.5em;
margin-top: -1em;
+}
+
+/* prepare nav tabs for printing */
+.nav > li.active > a, /* tab headers */
+.nav > li > a {
+ color: black;
+ background-color: white;
+ border: 1px solid #ccc;
+ border-radius: 4px 4px 0 0;
+}
+.tab-content > .tab-pane {
+ display: block !important; /* display non-active panes */
+ position: relative;
+}
+div.tab-content div.tab-pane pre {
+ margin-top: 1em;
+}
+/* create counters to link tab headers to tab contents */
+.post-content ul.nav.nav-tabs {
+ counter-reset: tab_number; /* creates a new instance of counter with name tab_number */
+}
+.post-content .nav.nav-tabs li::after {
+ counter-increment: tab_number; /* increment counter */
+ content: counter(tab_number); /* display value in small bubble */
+ position: absolute;
+ top: -1em;
+ left: -1em;
+ padding: 2px 5px;
+ background-color: white;
+ color: black;
+ font-size: 0.65em;
+ border-radius: 50%;
+ border: 1px solid #ccc;
+ box-shadow: 1px 1px 1px grey;
+}
+div.tab-content {
+ counter-reset: pane_number;
+}
+div.tab-pane::after {
+ counter-increment: pane_number;
+ content: counter(pane_number);
+ position: absolute;
+ top: -1em;
+ left: -1em;
+ padding: 2px 5px;
+ background-color: white;
+ color: black;
+ font-size: 0.65em;
+ border-radius: 50%;
+ border: 1px solid #ccc;
+ box-shadow: 1px 1px 1px gray;
}
\ No newline at end of file
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 6cc97dc8e25..bde19180fac 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
@@ -9,6 +9,13 @@ For coupling, we need coupling meshes. Let's see how we can tell preCICE about o
Coupling meshes and associated data fields are defined in the preCICE configuration file, which you probably already know from the tutorials. The concrete values, however, you can access with the API:
+
+
+
+
```cpp
VertexID setMeshVertex(
::precice::string_view meshName,
@@ -88,6 +95,128 @@ turnOffSolver();
```
Did you see that your fluid solver now also needs to provide the functions `computeForces` and `setDisplacements`? As you are an expert in your fluid code, these functions should be easy to implement. Most probably, you already have such functionality anyway. If you are not an expert in your code try to find an expert :smirk:.
+
+
+
+ ```python
+"""
+ Parameters
+ ----------
+ mesh_name : str
+ Name of the mesh to add the vertex to.
+ position : array_like
+ The coordinates of the vertex.
+
+ Returns
+ -------
+ vertex_id : int
+ ID of the vertex which is set.
+"""
+set_mesh_vertex(mesh_name, position)
+
+"""
+ Parameters
+ ----------
+ mesh_name : str
+ Name of the mesh to add the vertices to.
+ positions : array_like
+ The coordinates of the vertices in a numpy array [N x D] where
+ N = number of vertices and D = dimensions of geometry.
+
+ Returns
+ -------
+ vertex_ids : numpy.ndarray
+ IDs of the created vertices.
+"""
+set_mesh_vertices(mesh_name, positions)
+```
+
+* `set_mesh_vertex` defines the coordinates of a single mesh vertex and returns a vertex ID, which you can use to refer to this vertex.
+* `set_mesh_vertices` defines multiple vertices at once. So, you can use this function instead of calling `set_mesh_vertex` multiple times. This is also good practice for performance reasons.
+
+To write data to the coupling data structure the following API function is needed:
+
+```python
+"""
+ Parameters
+ ----------
+ mesh_name : str
+ name of the mesh to write to.
+ data_name : str
+ Data name to write to.
+ vertex_ids : array_like
+ Indices of the vertices.
+ values : array_like
+ Values of data
+"""
+write_data(self, mesh_name, data_name, vertex_ids, values)
+```
+
+Similarly, there is a `read_data` API function for reading coupling data:
+
+```python
+"""
+ Parameters
+ ----------
+ mesh_name : str
+ Name of the mesh to write to.
+ data_name : str
+ ID to read from.
+ vertex_ids : array_like
+ Indices of the vertices.
+ relative_read_time : double
+ Point in time where data is read relative to the beginning of the current time step
+
+ Returns
+ -------
+ values : numpy.ndarray
+ Contains the read data.
+"""
+read_data(mesh_name, data_name, vertex_ids, relative_read_time)
+```
+
+The relative read time can be anything from the current point in time (`0`) to the end of the time window (`get_max_time_step_size()`). We will talk about the additional argument `relative_read_time` in detail in [the section on time interpolation](couple-your-code-waveform.html).
+
+Let's define coupling meshes and access coupling data in our example code:
+
+```python
+turn_on_solver() # e.g. setup and partition mesh
+num_vertices = 3
+precice = precice.Participant("FluidSolver", "precice-config.xml", rank, size) # Initialize participant
+
+mesh_dim = precice.get_mesh_dimensions("FluidMesh")
+
+vertices = np.zeros((num_vertices, participant.get_mesh_dimensions(mesh_name))) # coords of vertices at wet surface
+vertex_ids = precice.set_mesh_vertices("FluidMesh", vertices)
+
+forces_dim = precice.get_data_dimensions("FluidMesh", "Forces")
+forces = np.zeros((num_vertices, forces_dim))
+
+displacements_dim = precice.get_data_dimensions("FluidMesh", "Displacements")
+displacements = np.zeros((num_vertices, displacements_dim))
+
+
+precice.initialize()
+while participant.is_coupling_ongoing(): # time loop
+ precice_dt = precice.get_max_time_step_size()
+ solver_dt = begin_time_step() # e.g. compute adaptive dt
+ dt = min(precice_dt, solver_dt)
+ precice.read_data("FluidMesh", "Displacements", vertex_ids, dt, displacements)
+ set_displacements(displacements)
+ solve_time_step(dt)
+ compute_forces(forces)
+ precice.write_data("FluidMesh", "Forces", vertex_ids, forces)
+ precice.advance(dt)
+ end_time_step() # e.g. update variables, increment time
+
+precice.finalize() # frees data structures and closes communication channels
+turn_off_solver()
+```
+
+Did you see that your fluid solver now also needs to provide the functions `compute_forces` and `set_displacements`? As you are an expert in your fluid code, these functions should be easy to implement. Most probably, you already have such functionality anyway. If you are not an expert in your code try to find an expert :smirk:.
+
+
+
Once your adapter reaches this point, it is a good idea to test your adapter against one of the [solverdummies](couple-your-code-api#minimal-reference-implementation), which then plays the role of the `SolidSolver`.
diff --git a/pages/docs/couple-your-code/couple-your-code-preparing-your-solver.md b/pages/docs/couple-your-code/couple-your-code-preparing-your-solver.md
index dc1bff4dd42..f8958f2dfdd 100644
--- a/pages/docs/couple-your-code/couple-your-code-preparing-your-solver.md
+++ b/pages/docs/couple-your-code/couple-your-code-preparing-your-solver.md
@@ -7,6 +7,13 @@ summary: "If you want to couple your own code you need to properly understand it
Let's say you want to prepare a fluid solver for fluid-structure interaction and that your code looks like this:
+
+
+
+
```cpp
turnOnSolver(); //e.g. setup and partition mesh
@@ -18,8 +25,25 @@ while (not simulationDone()){ // time loop
endTimeStep(); // e.g. update variables, increment time
}
turnOffSolver();
+
+```
+
+
+
+
+```python
+turn_on_solver() #e.g. setup and partition mesh
+
+while not simulation_done(): # time loop
+ dt = begin_time_step() #e.g compute adaptive dt
+ solve_time_step(dt)
+ end_time_step() #e.g. update variables, increment time
+
+turn_off_solver()
```
+
+
Probably most solvers have such a structures: something in the beginning (reading input, domain decomposition), a big time loop, and something in the end. Each time step also falls into three parts: some pre-computations (e.g. computing an adaptive time step size), the actual computation (solving a linear or non-linear equation system), and something in the end (updating variables, incrementing time). Try to identify these parts in the code you want to couple.
In the following steps, we will slowly add more and more calls to the preCICE API in this code snippet. Some part of the preCICE API is briefly described in each step. More precisely (no pun intended :grin:), we use the native `C++` API of preCICE. The API is, however, also available in other scientific programming languages: plain `C`, `Fortran`, `Python`, `Matlab`, `Julia`, and `Rust` (see [Application Programming Interface](couple-your-code-api)).
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 325c3865062..fed1c2645de 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
@@ -9,6 +9,13 @@ summary: "In this step, you get to know the most important API functions of preC
As a first preparation step, you need to include the preCICE library headers. In C++, you need to include the file [precice.hpp](https://github.com/precice/precice/blob/develop/src/precice/precice.hpp).
The handle to the preCICE API is the class `precice::Participant`. 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:
+
+
+
+
```cpp
Participant( String participantName, String configurationFileName, int rank, int size );
void initialize();
@@ -16,6 +23,38 @@ void advance ( double computedTimeStepSize );
void finalize();
```
+
+
+
+```python
+"""
+ Parameters:
+ participant_name: string
+ Name of the solver
+ configuration_file_name: string
+ Name of preCICE config file
+ rank: int
+ Rank of the process
+ size: int
+ Size of the process
+"""
+participant = Participant(participant_name, configuration_file_name, rank, size)
+
+participant.initialize()
+
+"""
+ Parameters:
+ computed_timestep_size: double
+ Length of timestep used by solver
+"""
+participant.advance(computed_timestep_size)
+
+participant.finalize()
+
+```
+
+
+
What do they do?
* `initialize` establishes communication channels and sets up data structures of preCICE.
@@ -23,7 +62,12 @@ What do they do?
* `finalize` frees the preCICE data structures and closes communication channels.
The following function allows us to query the maximum allowed time step size from preCICE:
-
+
+
+
```cpp
double getMaxTimeStepSize();
```
@@ -53,3 +97,32 @@ while (not simulationDone()){ // time loop
precice.finalize(); // frees data structures and closes communication channels
turnOffSolver();
```
+
+
+
+
+```python
+import precice
+
+turn_on_solver() # e.g. setup and partition mesh
+
+precice = precice.Interface(
+ "FluidSolver", "precice-config.xml", rank, size
+)
+precice_dt = precice.initialize()
+
+u = initialize_solution()
+
+while t < t_end: # time loop
+ dt = compute_adaptive_dt()
+ dt = min(precice_dt, dt) # more about this in Step 5
+ u = solve_time_step(dt, u) # returns new solution
+ precice_dt = precice.advance(dt)
+ t = t + dt
+
+precice.finalize() # frees data structures and closes communication channels
+
+```
+
+
+