/* MOD_V1.0
* Copyright (c) 2011 OpenDA Association
* All rights reserved.
*
* This file is part of OpenDA.
*
* OpenDA is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* OpenDA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with OpenDA. If not, see .
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using OpenDA.DotNet.Bridge;
using OpenDA.DotNet.Interfaces;
using OpenMI.Standard2;
using OpenMI.Standard2.TimeSpace;
using ITime=OpenDA.DotNet.Interfaces.ITime;
//using Oatc.OpenMI.Sdk.Backbone;
//using Oatc.OpenMI.Sdk.Backbone.Generic;
//using Oatc.OpenMI.Sdk.Buffer;
namespace OpenDA.DotNet.OpenMI.Bridge
{
public class ModelInstance : IModelInstance
{
private readonly ModelFactory _openDaModelFactory;
private readonly ITimeSpaceComponent _openMIComponent;
private readonly IDictionary _inputs = new Dictionary();
private readonly IDictionary _outputs = new Dictionary();
private readonly IDictionary _inout = new Dictionary();
private int _mSheTstep;
private double _finalTimeOfSimulation;
private IList _listModelIndicesAtObservations;
private ITimeSpaceComponentExtensions _extendedComponent;
public ModelInstance(ModelFactory myModelFactory, ITimeSpaceComponent openMIComponent)
{
_mSheTstep = 0;
_openDaModelFactory = myModelFactory;
_openMIComponent = openMIComponent;
GetExchangeItemsFromOpenMIComponent();
_openMIComponent.Update();
}
public IInstance GetParent()
{
return _openDaModelFactory;
}
public ITimeSpaceComponent OpenMIComponent
{
get { return _openMIComponent; }
}
/* Note: With New Verson - must remove this method
*
public bool DoWrite()
{
return GetParent().DoWrite();
}
*/
public ITime TimeHorizon
{
get
{
global::OpenMI.Standard2.TimeSpace.ITime timeHorizon = _openMIComponent.TimeExtent.TimeHorizon;
double beginTime = timeHorizon.StampAsModifiedJulianDay;
double endTime = beginTime + timeHorizon.DurationInDays;
//We do not have info on the timestepping. Hence we fill in NaN. Noise models will then use their own specified stepping scheme.
double stepMJD = Double.NaN;
DotNet.Bridge.Time openDATimeHorizon = new DotNet.Bridge.Time(beginTime, endTime, stepMJD, true);
return openDATimeHorizon;
}
}
public ITime CurrentTime
{
get
{
return DetermineCurrentTime(TimeHorizon.BeginTime);
}
}
public void Compute(ITime targetTime)
{
ITime lastTime = DetermineCurrentTime(null);
//double FinalSimTime = TimeHorizon.MJD ;
double FinalSimTime = TimeHorizon.EndTime.MJD;
// Get the precision for comparing times as specified by the user.
double timePrecisionMJD = org.openda.utils.performance.OdaGlobSettings.getTimePrecision();
ITime current = lastTime;
if (lastTime == null)
{
throw new Exception("Could not find time/space output item to check model's current time");
}
// Note: we are absolutely not sure why we have the second part in the while check!!!!
while (lastTime.EndTime.MJD+timePrecisionMJD < targetTime.MJD && FinalSimTime - timePrecisionMJD > lastTime.EndTime.MJD)
{
current = lastTime;
try
{
_openMIComponent.Update();
}
catch (Exception e)
{
FileStream fileStream = File.Open("MShe_Exceptions.txt", FileMode.Append);
StreamWriter streamWriter = new StreamWriter(fileStream);
streamWriter.WriteLine("Exception in Update()" + e);
streamWriter.Close();
}
// Get the timeStamp of the Model. This is used in case time information is missing in the exhangeItems of the Model
ITime timeStampModel = DetermineCurrentTime(null);
foreach (KeyValuePair output in _outputs)
{
output.Value.AddNewOpenMIOutputValuesToBuffer(timeStampModel.MJD);
output.Value.UpdatetstepCount();
}
foreach (KeyValuePair inout in _inout)
{
inout.Value.AddNewOpenMIOutputValuesToBuffer(timeStampModel.MJD);
inout.Value.UpdatetstepCount();
}
foreach (KeyValuePair input in _inputs)
{
input.Value.UpdatetstepCount();
}
lastTime = DetermineCurrentTime(null);
_mSheTstep++;
}
}
public string[] ExchangeItemIDs
{
get
{
string[] exchangeItemIDs = new string[_inputs.Count + _outputs.Count];
_inputs.Keys.CopyTo(exchangeItemIDs, 0);
_outputs.Keys.CopyTo(exchangeItemIDs, _inputs.Count);
return exchangeItemIDs;
}
}
public string[] GetExchangeItemIDs(int roleAsInt)
{
Role role = DotNet.Bridge.Utils.RoleMapJ2N(roleAsInt);
string[] exchangeItemIDs;
switch (role)
{
case Role.Input:
exchangeItemIDs = new string[_inputs.Count];
_inputs.Keys.CopyTo(exchangeItemIDs, 0);
break;
case Role.Output:
exchangeItemIDs = new string[_inputs.Count];
_outputs.Keys.CopyTo(exchangeItemIDs, 0);
break;
case Role.InOut:
exchangeItemIDs = ExchangeItemIDs;
break;
default:
throw new Exception("Invalid Role value: " + role);
}
return exchangeItemIDs;
}
public IExchangeItem GetExchangeItem(string exchangeItemID)
{
// ZZZ Removes the . at the end of the exchangeItemID if there is one
// Try and Map what's after the . to a location index
char[] delimiterChars = { '.'};
string[] idx = exchangeItemID.Split(delimiterChars);
int idxTemp;
if (idx.Length == 2)
{
if (_inout.ContainsKey(idx[1]))
{
ExchangeItem I = _inout[idx[1]];
try
{
idxTemp = Convert.ToInt32(idx[0]);
I.AddSingleIdx(idxTemp);
}
catch (Exception e)
{
System.Console.WriteLine("ExchangeItem index invalid (not an integer): " + e.Message);
}
return I;
//return _outputs[exchangeItemID];
}
if (_outputs.ContainsKey(idx[1]))
{
ExchangeItem I = _outputs[idx[1]];
try
{
idxTemp = Convert.ToInt32(idx[0]);
I.AddSingleIdx(idxTemp);
}
catch (Exception e)
{
System.Console.WriteLine("ExchangeItem index invalid (not an integer): " + e.Message);
}
return I;
//return _outputs[exchangeItemID];
}
if (!_inputs.ContainsKey(idx[1]))
{
throw new Exception("Could not find exchange item \"" + exchangeItemID + "\"");
}
return _inputs[idx[1]];
}
if (idx.Length == 1)
{
if (_inout.ContainsKey(idx[0]))
{
ExchangeItem I = _inout[idx[0]];
return I;
//return _outputs[exchangeItemID];
}
if (_outputs.ContainsKey(idx[0]))
{
ExchangeItem I = _outputs[idx[0]];
return I;
//return _outputs[exchangeItemID];
}
if (!_inputs.ContainsKey(idx[1]))
{
throw new Exception("Could not find exchange item \"" + exchangeItemID + "\"");
}
return _inputs[idx[1]];
}
return null;
}
public IModelState SaveInternalState()
{
throw new NotImplementedException();
}
public void RestoreInternalState(IModelState savedInternalState)
{
throw new NotImplementedException();
}
public void ReleaseInternalState(IModelState savedInternalState)
{
throw new NotImplementedException();
}
public IModelState LoadPersistentState(string algorithmStateFilePath)
{
throw new NotImplementedException();
}
///
/// Get the values from the model corresponding to the observations.
/// The first this is called, _listModelIndicesAtObservations will be null so a list must be created.
///
/// The observations.
/// Model values corresponding to observation points.
public IVector GetObservedValues(OpenDA.DotNet.Interfaces.IObservationDescriptions observationDescriptions)
{
if (_extendedComponent == null && _openMIComponent is ITimeSpaceComponentExtensions)
{
_extendedComponent = (ITimeSpaceComponentExtensions) _openMIComponent;
_listModelIndicesAtObservations = _extendedComponent.CreateModelIndicesHashTable(observationDescriptions);
return new Vector(_extendedComponent.getObservedValues(observationDescriptions));
}
else if (_listModelIndicesAtObservations != null)
{
double[] modelValuesAtIndices = _extendedComponent.ModelValuesAtProvidedIndices(observationDescriptions,
_listModelIndicesAtObservations);
return new Vector(modelValuesAtIndices);
}
return null;
}
public IVector[] GetObservedLocalization(String exchangeItemID, IObservationDescriptions observationDescriptions, double distance)
{
if (_openMIComponent is ITimeSpaceComponentExtensions)
{
int nObs = observationDescriptions.ObservationCount;
IVector[] retVectors = new IVector[nObs];
ITimeSpaceComponentExtensions extendedComponent = (ITimeSpaceComponentExtensions)_openMIComponent;
double[][] mask = extendedComponent.getLocalization(exchangeItemID, observationDescriptions, distance);
if (mask != null)
{
for (int iObs = 0; iObs < nObs; iObs++)
{
retVectors[iObs] = new OpenDA.DotNet.Bridge.Vector(mask[iObs]);
}
}
return retVectors;
}
else
{
throw new NotImplementedException();
return null;
}
}
public IVector[] GetObservedLocalization(IObservationDescriptions observationDescriptions, double distance)
{
throw new NotImplementedException();
//NOTE OLD STUFF
if (_openMIComponent is ITimeSpaceComponentExtensions)
{
ITimeSpaceComponentExtensions extendedComponent = (ITimeSpaceComponentExtensions)_openMIComponent;
//Determine the number of observations (=number of columns)
int nObs = observationDescriptions.ObservationCount;
org.openda.utils.TreeVector[] retVectorsTree = new org.openda.utils.TreeVector[nObs];
for (int iObs = 0; iObs < nObs; iObs++)
{
retVectorsTree[iObs] = new org.openda.utils.TreeVector("localizationMask");
}
// Loop over all active echangeItems
// Note interface of this method must be improved to fix and answer the question which echangeItems are inwhat order in the state vector
foreach (KeyValuePair inout in _inout)
{
string exchangeItemID = inout.Key;
double[][] mask = extendedComponent.getLocalization(exchangeItemID, observationDescriptions, distance);
if (mask != null)
{
for (int iObs = 0; iObs < nObs; iObs++)
{
org.openda.utils.Vector vec = new org.openda.utils.Vector(mask[iObs]);
org.openda.utils.TreeVector subVec = new org.openda.utils.TreeVector(exchangeItemID, vec);
retVectorsTree[iObs].addChild(subVec);
}
}
}
// Cast fancy treevectors to vectors
IVector[] retVectors = new IVector[nObs];
for (int iObs = 0; iObs < nObs; iObs++)
{
double[] values = retVectorsTree[iObs].getValues();
retVectors[iObs] = new OpenDA.DotNet.Bridge.Vector(values);
}
return retVectors;
}
else
{
throw new NotImplementedException();
return null;
}
}
public string ModelRunDirPath
{
get { return null; } // model instance's run dir is not known
}
public void Finish()
{
_openMIComponent.Finish();
}
private ITime DetermineCurrentTime(ITime currentTime)
{
/* In case the component implements some extensions, use them */
if (_openMIComponent is ITimeSpaceComponentExtensions){
ITimeSpaceComponentExtensions extendedComponent = (ITimeSpaceComponentExtensions) _openMIComponent;
double now = extendedComponent.currentTime().StampAsModifiedJulianDay;
return new DotNet.Bridge.Time(now);
}
/* We have to fall back on a proper time administration in the exhange items */
foreach (KeyValuePair output in _outputs)
{
if (output.Value.Times != null && output.Value.Times.Length > 0)
{
double timeAsMJD = output.Value.Times[output.Value.Times.Length - 1];
currentTime = new DotNet.Bridge.Time(timeAsMJD);
if (currentTime != null)
{
return currentTime;
}
}
}
foreach (KeyValuePair inout in _inout)
{
if (inout.Value.Times != null && inout.Value.Times.Length > 0)
{
double timeAsMJD = inout.Value.Times[inout.Value.Times.Length - 1];
currentTime = new DotNet.Bridge.Time(timeAsMJD);
break;
}
break;
}
if (currentTime == null)
{
currentTime = TimeHorizon.BeginTime;
}
return currentTime;
// }
}
private ITime DetermineFinalTime(ITime currentTime)
{
foreach (KeyValuePair output in _outputs)
{
if (output.Value.Times != null && output.Value.Times.Length > 0)
{
double timeAsMJD = output.Value.Times[output.Value.Times.Length - 1];
currentTime = new DotNet.Bridge.Time(timeAsMJD);
break;
}
}
foreach (KeyValuePair inout in _inout)
{
if (inout.Value.Times != null && inout.Value.Times.Length > 0)
{
double timeAsMJD = inout.Value.Times[inout.Value.Times.Length - 1];
currentTime = new DotNet.Bridge.Time(timeAsMJD);
break;
}
}
if (currentTime == null)
{
currentTime = TimeHorizon.BeginTime;
}
return currentTime;
}
private void GetExchangeItemsFromOpenMIComponent()
{
// ZZZ
// Match the Input and Output Exchange Items
foreach (IBaseInput baseInput in _openMIComponent.Inputs)
{
foreach (IBaseOutput baseOutput in _openMIComponent.Outputs)
{
if (baseInput.Id.CompareTo(baseOutput.Id) == 0)
{
ITimeSpaceInput timeSpaceInput = baseInput as ITimeSpaceInput;
ITimeSpaceOutput timeSpaceOutput = baseOutput as ITimeSpaceOutput;
var IO = new ExchangeItem(timeSpaceOutput);
IO.AddIn(timeSpaceInput);
if (IO != null && !_inout.ContainsKey(timeSpaceOutput.Id))
{
_inout.Add(timeSpaceOutput.Id, IO);
}
}
}
}
foreach (IBaseInput baseIn in _openMIComponent.Inputs)
{
ITimeSpaceInput timeSpaceIn = baseIn as ITimeSpaceInput;
if (timeSpaceIn != null && !_inout.ContainsKey(baseIn.Id))
{
_inputs.Add(timeSpaceIn.Id, new ExchangeItem(timeSpaceIn));
}
}
foreach (IBaseOutput baseOut in _openMIComponent.Outputs)
{
ITimeSpaceOutput timeSpaceOut = baseOut as ITimeSpaceOutput;
if (timeSpaceOut != null && !_inout.ContainsKey(baseOut.Id))
{
//ZZZ
var I = new ExchangeItem(timeSpaceOut);
if (I != null)
_outputs.Add(timeSpaceOut.Id, I);
}
}
}
}
}