OpenMI components can be linked via a configuration utility such as e.g. the OpenMI editor.
However, once can also develop a linked system by calling the OpenMI interfaces. This page describes how to set up a hard-coded linked system, where the establishment of links and the deployment and execution of a combination of components is completely encapsulated in the source code.

When developing a hard-coded system, you usually know the underlying OpenMI components and their capabilities in terms of input and output. Hard-coding the system then comes down to the following steps:

  1. Instantiate the LinkableComponents and initialize them with the proper input data sets.
  2. Create the Quantity and ElementSet objects by querying ExchangeItems.
  3. Create the Link objects and populate them with the Quantity and ElementSet objects.
  4. Add the Link objects to the components and validate them.
  5. Prepare the event listener to catch events.
  6. Run the simulation (including preparation and finish).
  7. Dispose of the components.
    You must also continuously catch exceptions on all steps.

Example to setup a hard-coded system

The sample below provides a (pseudo) C#-code example that includes all phases in the utilization of OpenMI components. Note that this example does not include data operations and associated validations, while the calendar conversion between the DateTime data type of C# and the OpenMI Time object is omitted.

// --- Basic information ----
// Note for namespaces: the abbreviation MC refers to Model Components

// --- MyRain-module hard-coded  information ----
string myRainArguments          = new Argument[1];
myRainArguments[0]              = new Argument("FilePath", "C:\OpenMI\\Examples\MC\SimpleRain\Data",true,"");

// --- MyRainfallRunoff-model hard-coded  information ----
string myRRArguments         = new Argument[1];
myRRArguments[0]             = new Argument "FilePath", "C:\OpenMI\Examples\MC\SimpleRainfallRunoff\Data",true,"");

// --- MyRiverModel hard-coded  information ----
string myRiverArguments         = new Argument[1];
myRiverArguments[0]             = new Argument("FilePath", "C:\OpenMI\Examples\MC\SimpleRiver\Data",true,"");

// -- Create LinkableComponents ---
ILinkableComponent MyRainModule = new SimpleRainModuleWrapper();
ILinkableComponent MyRRModel    = new SimpleRREngineWrapper();
ILinkableComponent MyRiverModel = new SimpleRiverEngineWrapper();
ILinkableComponent trigger      = new Trigger();
MyRainModule.Initialize(myRainArguments);
MyRRModel.Initialize(myRRArguments);
MyRiverModel.Initialize(myRiverArguments);

// --- Query Quantities and ElementSets

// Outputs
IQuantity Rain_Precipitation = (MyRainModule).GetOutputExchangeItem(0).Quantity;
IQuantity RR_Outflows        = (MyRRModel).GetOutputExchangeItem(0).Quantity;
IQuantity Riv_WaterLevels    = (MyRiverModel).GetOutputExchangeItem(0).Quantity;
IElementSet Rain_MyRainGrid  = (MyRainModule).GetOutputExchangeItem(0).ElementSet;
IElementSet RR_Outlets       = (MyRRModel).GetOutputExchangeItem(0).ElementSet;
IElementSet Riv_RiverNetwork = (MyRiverModel).GetOutputExchangeItem(0).ElementSet;
IDataOperation Rain_TmAvg    = (MyRainModule).GetOutputExchangeItem(0).DataOperation(0);
IDataOperation Rain_TmAccu   = (MyRainModule).GetOutputExchangeItem(0).DataOperation(1);
IDataOperation Rain_SptAvg   = (MyRainModule).GetOutputExchangeItem(0).DataOperation(2);
IDataOperation RR_TmAvg      = (MyRRModel).GetOutputExchangeItem(0).DataOperation(0);
IDataOperation RR_TmMaxVal   = (MyRRModel).GetOutputExchangeItem(0).DataOperation(1);
IDataOperation Riv_SpatIntp  = (MyRiverModel).GetOutputExchangeItem(0).DataOperation(0);

//Inputs
IQuantity RR_Rainfall         = (MyRRModel).GetInputExchangeItem(0).Quantity;
IQuantity Riv_LateralInflows  = (MyRiverModel).GetInputExchangeItem(0).Quantity;
IElementSet RR_SubCatchments  = (MyRRModel).GetInputExchangeItem(0).ElementSet;
IElementSet Riv_LateralInlets = (MyRiverModel).GetInputExchangeItem(0).ElementSet;


// TimeHorizon
DateTime start = MyRainModule.TimeHorizon.Start;
if (start < MyRRModel.TimeHorizon.Start)
{
	start = (DateTime)MyRRModel.TimeHorizon.Start;
}
if (start < MyRiverModel.TimeHorizon.Start)
{
	start= (DateTime)MyRiverModel.TimeHorizon.Start;
}
DateTime end = MyRainModule.TimeHorizon.End;
if (end < MyRRModel.TimeHorizon.End)
{
	end = (DateTime)MyRRModel.TimeHorizon.End;
}
if (end < MyRiverModel.TimeHorizon.End)
{
	end= (DateTime)MyRiverModel.TimeHorizon.End;
}
DateTime stop = end + 0.000001;

// --- Create Links ---
// create data operations here
IDataOperation Rain_DataOperations[] = new Rain_DataOperation[1];
Rain_DataOperation(0)                = new Rain_TmAccu;
Rain_DataOperation(1)                = new Rain_SpatAvg;

// check validity: to be done raise exception
// Rain_DataOperation(1).IsValid((MyRainModule).GetOutputExchangeItem(0), (MyRRModel).GetInputExchangeItem(0), Rain_DataOperation[0])
ILink triggerLink = new Link(MyRiverModel, Riv_RiverNetwork, Riv_WaterLevels, trigger, "", "", "RiverModel to Trigger Link", "RiverModelToTrigger", new ArrayList());
ILink LinkRunoffToInflow = new Link(MyRRModel, RR_Outlets, RR_Outflow, MyRiverModel, Riv_LateralInlets, Riv_LateralInflows, "Link Runoff to River Inflow", "LinkRunoffToInflow", new ArrayList());
ILink LinkRainToCatchm = new Link(MyRainModule, MyRainGrid, Rain_Precipitation, MyRRModel, RR_SubCatchments, RR_Rainfall, "Link rainfall to catchment", "LinkRainToCatchm", Rain_DataOperations[]);

// --- Add Links ---
MyRiverModel.AddLink(triggerLink);
trigger.AddLink(triggerLink);
MyRainModule.AddLink(LinkRainToCatchm);
MyRRModel.AddLink(LinkRainToCatchm);
MyRRModel.AddLink(LinkRunoffToInflow);
MyRiverModel.AddLink(LinkRunoffToInflow);

// --- Validate Components ---
trigger.Validate;
MyRainModule.Validate;
MyRRModel.Validate;
MyRiverModel.Validate;

//--- Prepare Event listener ---
org.OpenMI.Standard.IListener myListener = new EventListener();
for (int i = 0; i < myListener.GetAcceptedEventTypeCount(); i++)
{
	for (int n = 0; n < MyRainModule.GetPublishedEventTypeCount(); n++)
	{
		if (myListener.GetAcceptedEventType(i) == MyRainModule.GetPublishedEventType(n))
		{
			MyRainModule.Subscribe(myListener, myListener.GetAcceptedEventType(i));
		}
	}
	for (int n = 0; n < MyRRModel.GetPublishedEventTypeCount(); n++)
	{
		if (myListener.GetAcceptedEventType(i) == MyRRModel.GetPublishedEventType(n))
		{
			MyRRModel.Subscribe(myListener, myListener.GetAcceptedEventType(i));
		}
	}
	for (int n = 0; n < MyRiverModel.GetPublishedEventTypeCount(); n++)
	{
		if (myListener.GetAcceptedEventType(i) == MyRiverModel.GetPublishedEventType(n))
		{
			MyRiverModel.Subscribe(myListener, myListener.GetAcceptedEventType(i));
		}
	}
}

//--- Run ---
try
{
	MyRainModule.Prepare();
	MyRRModel.Prepare();
	MyRiverModel.Prepare();
	int nrsteps=100;
	DateTimestep = (end - start)/nrsteps;
	DateTime stop = end + 0.000001;
	DateTime _time = start;
	while (_time <= stop)
	{
		Application.DoEvents();
		IValueSet Values = _trigger.GetValues(new TimeStamp(_time), _triggerLink.ID);
		_time = _time.AddSeconds(step);
	}
	GermanRhineModel.Finish();
	NethRhineModel.Finish();
} // end try
//--- Clean up ---
MyRainModule.Dispose();
MyRRModel.Dispose();
MyRiverModel.Dispose();
}
//--- Exception Handling ---
catch (Exception e)
{
	// write exception to screen;
	Console.WriteLine(e);
}

Figure Sample Hard-coded system using OpenMI linkable components