View on GitHub

CoSimIO

Small standalone tool for interprocess communication in CoSimulation contexts for coupling and exchanging data between different solvers or other software-tools.

Tutorial for integrating the CoSimIO using C interface

Main Page of Documentation

Table of Contents


This tutorial helps you to integrate the CoSimIO into a solver/software-tool using the C++ interface.

What you need

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:

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.