Tutorial for integrating the CoSimIO using C interface
Table of Contents
- What you need
- Building the CoSimIO
- Hello CosimIO
- Connecting and Disconnecting
- Data Exchange
- Mesh Exchange
- Next steps
This tutorial helps you to integrate the CoSimIO into a solver/software-tool using the C++ interface.
What you need
- Downloading the CosimIO from the repository:
git clone https://github.com/KratosMultiphysics/CoSimIO.git
-
A C++11 compatible compiler. This includes most of the major CPP compilers in Windows, Linux, and Mac. You may find a detailed list of C++11 compatible compilers here
- CMake
Building the CoSimIO
The C version of the CoSimIO is implemented in co_sim_io_c.h. It can be used after compiling CoSimIO into a shared library and linking against it. Check here for the available build options.
Several options for using/integrating the CoSimIO exist:
- Using CMake:
- Integrating CoSimIO as a subproject into the host with CMake:
Here the CoSimIO is directly integrated into the host code and added with
add_subdirectory(CoSimIO)
. CMake then takes care of compiling and installing the CoSimIO. Kratos uses this way to integrate the CoSimIO, check theCMakeLists.txt
of the CoSimulationApplication for details -
Compiling CoSimIO outside the host project: One can use build_c.sh or build_c.bat for compiling it.
- For GNU/Linux or MacOS:
$ bash scripts/build_c.sh
-
For Windows OS:
$ scripts/build_c.bat
- For GNU/Linux or MacOS:
After compiling, the headers need to be included (e.g. with
include_directories
) and theco_sim_io_c
shared library needs to be linked (e.g withtarget_link_libraries
).include_directories(path/to/CoSimIO/co_sim_io) target_link_libraries(my_executable co_sim_io_c)
- Integrating CoSimIO as a subproject into the host with CMake:
Here the CoSimIO is directly integrated into the host code and added with
-
Compiling CoSimIO outside the host and manually integrating it: One can use build_c.sh or build_c.bat for compiling it.
- For GNU/Linux or MacOS:
$ bash scripts/build_c.sh
-
For Windows OS:
$ scripts/build_c.bat
Is important that the compiler can find the header files of the CoSimIO. For this, one can add the folder
co_sim_io
to the include path. Example:export C_INCLUDE_PATH=$C_INCLUDE_PATH:/path/to/CoSimIO/co_sim_io
Furthermore it is required to link against the
co_sim_io_c
shared library. - For GNU/Linux or MacOS:
The shared library co_sim_io_c
will be installed in the bin/
folder. After building CoSimIO, is necessary to add the path where the shared library co_sim_io_c
was installed to (bin/
) to the library path of the system such that the it can be linked against. Depending on the operating system this can be e.g. PATH
or LD_LIBRARY_PATH
. This also needs to be available at runtime, otherwise errors when strating the execution will occur. In linux this can be achieved with the following:
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH$:$HOME/path/to/CoSimIO/bin"
Note that internally the shared library co_sim_io_c
links against the shared library co_sim_io
which is the native C++ version of CoSimIO.
After building and linking it to your project, you may use the interface defined in c/co_sim_io_c.h
:
/* CoSimulation includes */
#include "c/co_sim_io_c.h"
int main(){
return 0;
}
Hello CosimIO
After integrating the CoSimIO in your code now it’s time to say hello
CoSimIO_Info hello_info = CoSimIO_Hello();
Please note that this function like other functions in CoSimIO returns an Info
object. This object is a versatile container holding important information about the operation that has been done. See here for the documentation. In this case, it contains the version of the CoSimIO library which can be printed using CoSimIO_PrintInfo()
function:
CoSimIO_PrintInfo(stdout, hello_info);
The Info
class also provides Get...
methods for retrieving certain values knowing their type:
int major_version = CoSimIO_Info_GetInt(hello_info, "major_version");
int minor_version = CoSimIO_Info_GetInt(hello_info, "minor_version");
const char* patch_version = CoSimIO_Info_GetString(hello_info, "patch_version");
Finally it is very important to free the info using the CoSimIO_FreeInfo()
function:
CoSimIO_FreeInfo(hello_info);
This example can be found in integration_tutorials/c/hello.c.
Connecting and Disconnecting
The first step to establish a connection to Kratos CoSimulation is to use the CoSimIO_Connect
method:
// The connect must be called before any CosimIO method
CoSimIO_Info connect_info = CoSimIO_Connect(settings);
First of all, you may notice that Connect()
function takes an Info
as its arguments. So first you should create it using CoSimIO_CreateInfo()
function:
CoSimIO_Info settings = CoSimIO_CreateInfo();
It is important to mention that the CoSimIO_Info
is a pointer to the cpp info class which is allocated by the CoSimIO_CreateInfo()
. So it is don’t forget to free it when is not needed anymore using CoSimIO_FreeInfo()
function. This container can be used to pass additional information about the solver/software-tool or connection settings to the CoSimIO:
CoSimIO_Info_SetString(settings, "my_name", "the_name_of_this_solver"); // my name
CoSimIO_Info_SetString(settings, "connect_to", "the_other_solver_name"); // to whom I want to connect toto
CoSimIO_Info_SetInt(settings, "echo_level", 1);
CoSimIO_Info_SetString(settings, "version", "1.25");
It is very important that the settings for my_name
and connect_to
are set correctly, otherwise the connection cannot be established!
E.g in the above example one code sets my_name
as cpp_connect_disconnect_a
and connect_to
as cpp_connect_disconnect_b
. This means that the other code has to use the same settings but reversed: my_name
must be cpp_connect_disconnect_b
and connect_to
must be cpp_connect_disconnect_a
.
This method returns a Info
object containing information about the connection which can be queried using CoSimIO_Info_Get...
method. For further calls to CoSimIO
it is necessary to get the connection_name
:
CoSimIO_Info_GetString(info, "connection_name");
CoSimIO_Info_GetInt(info, "connection_status");
Similar things work for the Disconnect
method.
Now putting together everything:
// CoSimulation includes
#include "c/co_sim_io_c.h"
int main()
{
CoSimIO_Info settings=CoSimIO_CreateInfo();
CoSimIO_Info_SetString(settings, "my_name", "c_connect_disconnect_a");
CoSimIO_Info_SetString(settings, "connect_to", "c_connect_disconnect_b");
CoSimIO_Info_SetInt(settings, "echo_level", 1);
CoSimIO_Info_SetString(settings, "version", "1.25");
// The connect must be called before any CosimIO function called
CoSimIO_Info connect_info = CoSimIO_Connect(settings);
CoSimIO_FreeInfo(settings);
// The connect_info contains now:
// - The name of the connection ("connection_name") to be used for further calls to CoSimIO
// - The status of the connection ("connection_status")
const char* connection_name = CoSimIO_Info_GetString(connect_info, "connection_name"); // getting name of connection for future calls
if (CoSimIO_Info_GetInt(connect_info, "connection_status") != CoSimIO_Connected)
return 1;
// Now you may call any CoSimIO functions
// ...
// Here you may use the info but cannot call any CoSimIO function anymore
CoSimIO_Info disconnect_settings=CoSimIO_CreateInfo();
CoSimIO_Info_SetString(disconnect_settings, "connection_name", connection_name); // connection_name is obtained from calling "Connect"
CoSimIO_Info disconnect_info = CoSimIO_Disconnect(disconnect_settings); // disconnect afterwards
if(CoSimIO_Info_GetInt(disconnect_info, "connection_status") != CoSimIO_Disconnected)
return 1;
// Don't forget to release the settings and info
CoSimIO_FreeInfo(connect_info);
CoSimIO_FreeInfo(disconnect_settings);
CoSimIO_FreeInfo(disconnect_info);
return 0;
}
This example can be found in integration_tutorials/c/connect_disconnect_a.c and integration_tutorials/c/connect_disconnect_b.c.
Data Exchange
Make sure to connect (refer Connecting and Disconnecting) before Data Exchange.
One of the important missions of the CoSimIO is to send and recieve data between different solvers/software tools. The CoSimIO_ExportData
method can be used to send data to the Kratos or directly to another solver/software-tool. For exporting the following array 4 doubles:
double data_to_send[] = {3.14, 3.14, 3.14, 3.14};
// Creating the export_settings
CoSimIO_Info export_settings = CoSimIO_CreateInfo();
CoSimIO_Info_SetString(export_settings, "identifier", "vector_of_pi");
CoSimIO_Info_SetString(export_settings, "connection_name", connection_name); // connection_name is obtained from calling "Connect"
And then use it to export the data:
// Exporting the data
CoSimIO_Info export_info = CoSimIO_ExportData(export_settings, data_size, data_to_send);
Please note that the data_size
parameter is number of entitities in array. (Is not the size in bytes)
The ImportData()
should be used on the other side to recieve data:
// Importing the data
CoSimIO_Info import_info = CoSimIO_ImportData(import_settings, &data_allocated_size, &data);
For the above example the settings and arguments are:
double* data;
int data_allocated_size = 0;
// Creating the import_settings
CoSimIO_Info import_settings = CoSimIO_CreateInfo();
CoSimIO_Info_SetString(import_settings, "identifier", "vector_of_pi");
CoSimIO_Info_SetString(import_settings, "connection_name", connection_name); // connection_name is obtained from calling "Connect"
In this case we just pass an empty pointer and specifying to the ImportData()
that should allocate the data by itself. So, in order to ensure the memory coherance, the CoSimIO_Free()
function should be used instead of standard free()
function:
// Freeing the data using CoSimIO_Free. (Not the standard free())
CoSimIO_Free(data);
You may also allocate the memory for data by CoSimIO_Malloc()
function. If the allocated size is larger that imported data then there is no reallocation is done but if imported data is larger, then only if the data is allocated by CoSimIO_Malloc()
function a reallocation will be done. If not, it will gives an error.
This example can be found in integration_tutorials/c/export_data.c and integration_tutorials/c/import_data.c.
Mesh Exchange
Make sure to connect (refer Connecting and Disconnecting) before Mesh Exchange.
After seeing how we transfer raw data between solvers/software-tools, it is time to see how we can export and import meshes. For exporting the mesh one may use the ExportMesh()
method:
CoSimIO_Info export_settings = CoSimIO_CreateInfo();
CoSimIO_Info_SetString(export_settings, "identifier", "fluid_mesh");
CoSimIO_Info_SetString(export_settings, "connection_name", connection_name); // connection_name is obtained from calling "Connect"
CoSimIO_ModelPart model_part = CoSimIO_CreateModelPart("name_of_model_part_to_export");
CoSimIO_Info export_info = CoSimIO_ExportMesh(export_settings, model_part);
The argument model_part
is of type CoSimIO_ModelPart
. Its usage is explained here.
On the other side one can use the ImportMesh()
method to get the mesh sent by the export:
CoSimIO_Info import_settings=CoSimIO_CreateInfo();
CoSimIO_Info_SetString(import_settings, "identifier", "fluid_mesh");
CoSimIO_Info_SetString(import_settings, "connection_name", connection_name); // connection_name is obtained from calling "Connect"
CoSimIO_ModelPart model_part = CoSimIO_CreateModelPart("name_of_imported_model_part");
CoSimIO_Info import_info = CoSimIO_ImportMesh(import_settings, model_part);
This example can be found in integration_tutorials/c/export_mesh.c and integration_tutorials/c/import_mesh.c.
Next steps
In the next tutorial, a connection to Kratos is established and basic data exchange with Kratos is done.