-
-
Notifications
You must be signed in to change notification settings - Fork 64
[WIP] Add Python code for couple your code
section
#523
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
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -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, | ||||||||||||||||||||||||||||||
|
@@ -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) | ||||||||||||||||||||||||||||||
Comment on lines
+117
to
+131
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See above. |
||||||||||||||||||||||||||||||
``` | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
* `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. | ||||||||||||||||||||||||||||||
Comment on lines
+134
to
+135
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's better not change these inline function names. At least for now. This will get too complicated. Only changing the code blocks is enough. Meaning tabs for each code block here. |
||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
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) | ||||||||||||||||||||||||||||||
Comment on lines
+140
to
+152
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||
``` | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
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 | ||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's keep the example really consistent with the CPP code. There this "3" is not used, for example. |
||||||||||||||||||||||||||||||
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 | ||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Did you double-check that the order of dimensions is correct in such calls? I am not saying that it is wrong, but I did not test it 😄 |
||||||||||||||||||||||||||||||
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)) | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Let's avoid unnecessary empty lines. |
||||||||||||||||||||||||||||||
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) | ||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
no? |
||||||||||||||||||||||||||||||
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`. | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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() | ||
|
||
Comment on lines
+29
to
+53
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think we need the docstring here. This should not replace or copy the API documentation. The meaning of the functions is explained in the text. And we don't need a full code example. This one we have below anyway. |
||
``` | ||
|
||
</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(); | ||
``` | ||
|
@@ -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 | ||
|
||
``` | ||
Comment on lines
+104
to
+125
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is still preCICE v2 (from when the original PR #211 was opened) |
||
|
||
</div> | ||
</div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need for the docstring here, but please add the return value to the call.