Skip to content

Add navtabs + Python to step-by-step description #211

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions css/customstyles-precice.css
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
53 changes: 52 additions & 1 deletion css/printstyles.css
Original file line number Diff line number Diff line change
Expand Up @@ -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: "";
}

Expand Down Expand Up @@ -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;
}
129 changes: 129 additions & 0 deletions pages/docs/couple-your-code/couple-your-code-mesh-and-data-access.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:

<ul id="apiTabs" class="nav nav-tabs">
<li class="active"><a href="#cpp-1" data-toggle="tab">C++</a></li>
<li><a href="#python-1" data-toggle="tab">Python</a></li>
</ul>
<div class="tab-content">
<div role="tabpanel" class="tab-pane active" id="cpp-1" markdown="1">

```cpp
VertexID setMeshVertex(
::precice::string_view meshName,
Expand Down Expand Up @@ -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:.
</div>
<div role="tabpanel" class="tab-pane active" id="python-1" markdown="1">

```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:.

</div>
</div>

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`.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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:

<ul id="apiTabs" class="nav nav-tabs">
<li class="active"><a href="#cpp" data-toggle="tab">C++</a></li>
<li><a href="#python" data-toggle="tab">Python</a></li>
</ul>
<div class="tab-content">
<div role="tabpanel" class="tab-pane active" id="cpp" markdown="1">

```cpp
turnOnSolver(); //e.g. setup and partition mesh

Expand All @@ -18,8 +25,25 @@ while (not simulationDone()){ // time loop
endTimeStep(); // e.g. update variables, increment time
}
turnOffSolver();

```

</div>
<div role="tabpanel" class="tab-pane" id="python" markdown="1">

```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()
```

</div>
</div>
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)).
Expand Down
75 changes: 74 additions & 1 deletion pages/docs/couple-your-code/couple-your-code-steering-methods.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,65 @@ 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:

<ul id="apiTabs" class="nav nav-tabs">
<li class="active"><a href="#cpp-1" data-toggle="tab">C++</a></li>
<li><a href="#python-1" data-toggle="tab">Python</a></li>
</ul>
<div class="tab-content">
<div role="tabpanel" class="tab-pane active" id="cpp-1" markdown="1">

```cpp
Participant( String participantName, String configurationFileName, int rank, int size );
void initialize();
void advance ( double computedTimeStepSize );
void finalize();
```

</div>
<div role="tabpanel" class="tab-pane" id="python-1" markdown="1">

```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()

```

</div>
</div>
What do they do?

* `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.

The following function allows us to query the maximum allowed time step size from preCICE:

<ul id="apiTabs" class="nav nav-tabs">
<li class="active"><a href="#cpp-2" data-toggle="tab">C++</a></li>
<li><a href="#python-2" data-toggle="tab">Python</a></li>
</ul>
<div class="tab-content">
<div role="tabpanel" class="tab-pane active" id="cpp-2" markdown="1">
```cpp
double getMaxTimeStepSize();
```
Expand Down Expand Up @@ -53,3 +97,32 @@ while (not simulationDone()){ // time loop
precice.finalize(); // frees data structures and closes communication channels
turnOffSolver();
```

</div>
<div role="tabpanel" class="tab-pane" id="python-2" markdown="1">

```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

```

</div>
</div>