Co-Simulation API

 

A general Application Programming Interface (API) is available, enabling PSCAD/EMTDC to link to, and co-simulate with, just about any external application. Referred to as the Co-Simulation API, it is in it’s basic form, a C-language structure called EmtdcCosimulation_Channel, which houses a collection C-language functions. These functions can be used to customize an interface on the external application side. At the same time, a new master library component called the Co-Simulation Component, is utilized as the interface on the PSCAD/EMTDC-side. The Communication Fabric (ComFab) is utilized to provide the inter-application communications control architecture.

 

 

Note that the onus remains on the user to program the interface from the external application side, as all external applications differ in complexity and purpose. A complete description of the Co-Simulation API is provided in the following sections.

Co-Simulation Requirements

The values that are exchanged between PSCAD/EMTDC and the external application must be expressed as a 64-bit, floating point values.

 

PSCAD/EMTDC simulations are performed in the time domain, thus any data provided by an external application for co-simulation purposes, must also be able to provide time domain values (i.e. data that is associated with a time).

 

In order to prevent the possibility of deadlocking both PSCAD/EMTDC and the external application must provide default values, prior to any data exchanged. See the Co-Simulation Component for more.

Setup in PSCAD

On the PSCAD/EMTDC side, connection to the Co-Simulation API is accomplished via the Co-Simulation Component.

 

Example Co-Simulation Setup In PSCAD

 

The co-simulation component is configured to accept and provide data to the PSCAD/EMTDC simulation, as well as to provide data required by the external application.

Setup in the External Application

The external application co-simulating with PSCAD/EMTDC, must setup to utilize the open source, EmtdcCosimulation_Channel interface.

  1. To initialize the co-simulation, the external application must first call the EmtdcCosimulation_InitializeCoSimulation function, provided as part of the EmtdcCosimulation_Channel interface.

  2. For the external application to exchange data it must use a channel provided by the EmtdcCosimulation_Channel interface. After EmtdcCosimulation_InitializeCoSimulation is called, the channel is created and configured for use. In order to retrieve the channel, call EmtdcCosimulation_FindChannel.

  3. Once the external application has retrieved the channel, it may receive the corresponding data by using the GetValue function provided.

  4. The external application may send data using the channel by setting each of data point via calling SetValue. After each data point is set then call Send.

  5. When the simulation is complete, call the EmtdcCosimulation_FinalizeCosimulation function. This will ensure all memory and resources are cleaned up and that PSCAD is informed that the co-simulation is complete.

EmtdcCosimulation_Channel (Structure)

This c-language structure is open source, and may also be referred to as the Co-Simulation API. Below are descriptions of all methods and functions used.

Methods

The following methods may be utilized as needed.

 

 

 

double   GetValue

(

                  EmtdcCosimulation_Channel*       _this

               ,  double                           val

               ,  int                              index

               )

 

Parameters:

 

Name

Type

Description

_this

(EmtdcCosimulation_Channel*)

A pointer to the structure being operated on. This parameter should always be the content from which it is called.

val

double

The value that was sent from the other application at the other end of this channel.

index

int

The index location of the value being requested.

 

Return Value:

 

Type

Description

double

The value at the specified index for the valid time value on this channel.

 

Remarks:

 

This function will find the correct value and return it in as efficient time as possible. During its execution it may be reading other channel information from the same client or other time values. These values will be cached or discarded depending on the status of the channel that received the information.

 

The time value for the channel MUST increase over time and never decrease. For example if the previous call on this channel had a time value of 0.002 then the next call must be this value or higher. Values are discarded after they are no longer in the valid time cycle.

 

Each channel is independent in its cached values and time domain use when retrieving values.

 

The time step does not need to be synchronized with the other end of the channel in the co-simulation, and the valid value will be used for the time provided, independently of the time step of either application.

 

It is recommended that you do not read values at the 0 time, and to start with an initial condition rather than reading from the channel this is to prevent the possibility of dead-locking. Both application should start with initial conditions and run their first time step independently.

 

The maximum size of the index is one less than value returned from GetRecvSize().

 

Example:

 

// Get the channel with channel ID of 10

EmtdcCosimulation_Channel * channel = EmtdcCosimulation_FindChannel(10);

double time = 0.000;

double time_step = 0.001;

 

while (time < 1 )

   {

   double val1 = 0;

   double val2 = 0;         

   if ( time > 0 )

      {

      channel->GetValue(channel, time, 0);

      channel->GetValue(channel, time, 1);

      }

   // Perform Computations

      .

      .

      .

   // Increment the time step

   time += time_step;

   }

 

 

 

 

 

void  SetValue

               (

                  EmtdcCosimulation_Channel*       _this

               ,  double                           value

               ,  int                              index

               )

 

Parameters:

 

Name

Type

Description

_this

(EmtdcCosimulation_Channel*)

A pointer to the structure being operated on. This parameter should always be the content from which it is called.

value

double

The value that is to be sent to the other application at the other end of this channel.

index

int

The index location of the value to be sent.

 

Return Value:

 

None.

 

Remarks:

 

This function sets values in a cache to be sent when a call to Send() is made. This function does not send the value explicitly.

    

The maximum index value is one less than the return value from GetSendSize().

 

Example:

 

// Get the channel with channel ID of 10

EmtdcCosimulation_Channel * channel = EmtdcCosimulation_FindChannel(10);

double time = 0.000;

double time_step = 0.001;

 

while (time < 1 )

   {

   // Perform Computations

      .

      .

      .

   // Set the value to be sent

   channel->SetValue(channel, val1, 0);

   channel->SetValue(channel, val2, 1);

 

   // Send the cached values, they are valid until the next time step is complete

   channel->Send(time + time_step);

 

   // Increment the time step

   time += time_step;

   }

 

 

 

 

 

void  Send

         (

         EmtdcCosimulation_Channel*       _this

         double                           time

         )

 

Parameters:

 

Name

Type

Description

_this

(EmtdcCosimulation_Channel*)

A pointer to the structure being operated on. This parameter should always be the content from which it is called.

time

double

The time value for the values sent will be valid until.

 

Return Value:

 

None.

 

Remarks:

 

Values are sent with this call, use SetValue() to set the values that will be sent (any unset value are defaulted to 0).

 

It is assumed that value validity does not overlap between messages. If the previous send was 0.001 then this send will not be valid until the 0.001 has passed, then it will be valid until whatever time was passed.

 

Each channel is independent in terms of valid time sent.

 

Good practice is to always send first then receive that value required for the next time-step.

 

Example:

 

// Get the channel with channel ID of 10

EmtdcCosimulation_Channel * channel = EmtdcCosimulation_FindChannel(10);

double time = 0.000;

double time_step = 0.001;

 

while (time < 1 )

   {

   // Perform Computations

      .

      .

      .

   // Set the value to be sent

   channel->SetValue(channel, val1, 0);

   channel->SetValue(channel, val2, 1);

  

   // Send the cached values, they are valid until the next time step is complete

   channel->Send(time + time_step);

 

   // Increment the time step

   time += time_step;

   }

 

 

 

 

 

unsigned int   GetChannelId

               (

                 EmtdcCosimulation_Channel*       _this

               )

 

Parameters:

 

Name

Type

Description

_this

(EmtdcCosimulation_Channel*)

A pointer to the structure being operated on. This parameter should always be the content from which it is called.

 

Return Value:

 

Type

Description

unsigned int

The channel ID.

 

Remarks:

 

This value will not change for the duration of the channel life.

 

Example:

 

// Get the channel with channel ID of 10

EmtdcCosimulation_Channel * channel = EmtdcCosimulation_FindChannel(10);

 

// Ensure channel id is as expected

ASSERT(channel->GetChannelId(channel) == 10);

 

 

 

 

 

int   GetSendSize

               (

                 EmtdcCosimulation_Channel*       _this

               )

 

Parameters:

 

Name

Type

Description

_this

(EmtdcCosimulation_Channel*)

A pointer to the structure being operated on. This parameter should always be the content from which it is called.

 

Return Value:

 

Type

Description

int

The amount of double that will be sent with each send call.

 

Remarks:

 

This value will not change for the duration of the channel life.

 

Example:

 

// Get the channel with channel ID of 10

EmtdcCosimulation_Channel * channel = EmtdcCosimulation_FindChannel(10);

 

// Ensure this channel can send the required amount of data

ASSERT(channel->GetSendSize(channel) == 2);

 

 

 

 

 

int   GetRecvSize

               (

                 EmtdcCosimulation_Channel*       _this

               )

 

Parameters:

 

Name

Type

Description

_this

(EmtdcCosimulation_Channel*)

A pointer to the structure being operated on. This parameter should always be the content from which it is called.

 

Return Value:

 

Type

Description

int

The amount of double that will be received in a given message.

 

Remarks:

 

This value will not change for the duration of the channel life.

 

Example:

 

// Get the channel with channel ID of 10

EmtdcCosimulation_Channel * channel = EmtdcCosimulation_FindChannel(10);

 

// Ensure this channel can send the required amount of data

ASSERT(channel->>GetRecvSize(channel) == 2);

 

 

 

 

 

void  EmtdcCosimulation_InitializeCosimulation

               (

                  const char *      fabric_location

               ,  const char *      hostname

               ,  int               port

               ,  int               client_id

               )

 

Parameters:

 

Name

Type

Description

fabric_location

const char *

The absolute path the Communication Fabric DLL file (ComFab.dll).

hostname          

const char *

The Host Name or IP Address of the master process (PSCAD) that will coordinate the communication.

port

int

The port the master process (PSCAD) that will coordinate the communication is listening on.

client_id

int

A system wide unique ID for this process (it must be between 30000 and 65535) each process in the co-simulation must have a system wide unique ID.

 

Return Value:

 

None.

 

Remarks:

 

This call may take a finite amount of time to return. During this call all necessary connections are established and the required channels are constructed. The master process coordinates this entire process. This function will block until the entire system is properly configured.

 

This function should be call only once per process during per co-simulation.

 

Example:

 

// Constants

const char * path = "C:\\Program Files (x86)\\CommunicationFabric\\x86\\ComFab.dll";

const char * host = "localhost";

 

// Initialize the Co-Simulation

EmtdcCosimulation_InitializeCosimulation(path, host, 34343, 32000 );

 

 

 

 

 

void  EmtdcCosimulation_InitializeCosimulation

               (

                  const char *      file_name

               )

 

Parameters:

 

Name

Type

Description

file_name

const char *

This a full file path to a configuration file (generated by PSCAD) that contains required connect back information.

 

Return Value:

 

None.

 

Remarks:

 

This call may take a finite amount of time to return. During this call all necessary connections are established and the required channels are constructed. The master process coordinates this entire process. This function will block until the entire system is properly configured.

 

This function should be call only once per process during per co-simulation.

 

Example:

 

// Constants

const char * path = "C:\\Users\\Public\\Documents\\cosim_30001.cfg";

 

// Initialize the Co-Simulation

EmtdcCosimulation_InitializeCosimulation(path);

 

 

 

 

 

EmtdcCosimulation_Channel *  EmtdcCosimulation_FindChannel

                (

                   unsigned int channel_id

                )

 

Parameters:

 

Name

Type

Description

channel_id

unsigned int

The ID of the channel being searched for.

 

Return Value:

 

Type

Description

EmtdcCosimulation_Channel*

The channel containing the ID specified. (If channel exists with the ID it will return NULL)

 

Remarks:

 

Before this can be executed EmtdcCosimulation_InitializeCosimulation must be called.

 

If the co-simulation is not initialized then it will return NULL.

 

If no channel exists in this process with that channel ID then it will return NULL.

 

Example:

 

// Get the channel with channel ID of 10

EmtdcCosimulation_Channel * channel = EmtdcCosimulation_FindChannel(10);

 

 

 

 

 

void  EmtdcCosimulation_FinalizeCosimulation

              (

                 void

              )

 

Parameters:

 

None.

 

Return Value:

 

None.

 

Remarks:

 

This function will perform any cleanup required from the co-simulation. All EmtdcCosimulation_Channels will be de-allocated after this call.

          

Note: This call will inform the master process (PSCAD) that the client has finished running, then waits for PSCAD to give the go-ahead to disconnect.

 

Example:

 

// Finalize Co-Simulation

EmtdcCosimulation_FinalizeCosimulation();