#region Copyright
/*
* Copyright (c) 2005,2006,2007, OpenMI Association
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenMI Association nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY "OpenMI Association" ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL "OpenMI Association" BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#endregion
using System;
using System.Collections;
using System.Runtime.Remoting;
using RTCTools.OpenMI.Sdk.Spatial;
using OpenMI.Standard;
using RTCTools.OpenMI.Sdk.Backbone;
using RTCTools.OpenMI.Sdk.Buffer;
namespace RTCTools.OpenMI.Sdk.Wrapper
{
///
/// Smart output link
///
[Serializable]
public class SmartOutputLink : SmartLink
{
private SmartBuffer smartBuffer;
private ElementMapper elementMapper;
private bool _useSpatialMapping;
LinearConversionDataOperation _linearDataOperation;
private Hashtable _bufferStates;
///
/// Constructor
///
/// reference to the engine
/// The ILink object
public SmartOutputLink(IRunEngine engine, ILink link)
{
this._link = link;
this._engine = engine;
}
///
/// Initialize will create buffers, prepare data operations and create the mapping matrice when georeferenced links are used.
/// The initialize method should be invoked in the ILinkableComponent prepare method (is done from the LinkableRunEngine).
///
public void Initialize()
{
_bufferStates = new Hashtable();
smartBuffer = new SmartBuffer();
_useSpatialMapping = false;
_linearDataOperation = null;
//Setup Spatial mapper - mapping method is set to default for now!
int index = -1;
string description = " ";
for (int i = 0; i < link.DataOperationsCount; i++)
{
for (int n = 0; n < link.GetDataOperation(i).ArgumentCount; n++)
{
if (link.GetDataOperation(i).GetArgument(n).Key == "Type" && link.GetDataOperation(i).GetArgument(n).Value == "SpatialMapping")
{
for (int m = 0; m < link.GetDataOperation(i).ArgumentCount; m++)
{
if (link.GetDataOperation(i).GetArgument(m).Key == "Description")
{
description = link.GetDataOperation(i).GetArgument(m).Value;
break;
}
}
index = i;
break;
}
}
if (index == i)
{
break;
}
}
if (index >= 0)
{
if (description == " ")
{
throw new Exception("Missing key: \"Description\" in spatial dataoperation arguments");
}
_useSpatialMapping = true;
elementMapper =new ElementMapper();
elementMapper.Initialise(description,link.SourceElementSet, link.TargetElementSet);
}
//Prepare linear data operation
for(int i = 0; i < link.DataOperationsCount; i++)
{
if (link.GetDataOperation(i).ID == (new LinearConversionDataOperation()).ID)
{
_linearDataOperation = (LinearConversionDataOperation) link.GetDataOperation(i);
_linearDataOperation.Prepare();
break;
}
}
//prepare SmartBufferDataOperation
for(int i = 0; i < link.DataOperationsCount; i++)
{
if (link.GetDataOperation(i).ID == (new SmartBufferDataOperation()).ID)
{
((SmartBufferDataOperation)link.GetDataOperation(i)).Prepare();
smartBuffer.DoExtendedDataVerification = ((SmartBufferDataOperation)link.GetDataOperation(i)).DoExtendedValidation;
smartBuffer.RelaxationFactor = ((SmartBufferDataOperation)link.GetDataOperation(i)).RelaxationFactor;
break;
}
}
}
///
/// The last time in the buffer
///
/// the latest time in the buffer
public ITimeStamp GetLastBufferedTime()
{
ITime time = SmartBuffer.GetTimeAt(SmartBuffer.TimesCount - 1);
if (time is ITimeSpan)
{
return new TimeStamp( ((ITimeSpan)time).End);
}
else
{
return (ITimeStamp) time;
}
}
///
/// The SmartBuffer associated to the SmartOutputLink
///
public SmartBuffer SmartBuffer
{
get
{
return smartBuffer;
}
}
///
/// Update the associated buffer with the last values calculated by the engine
///
public virtual void UpdateBuffer()
{
if ((link.SourceQuantity != null) && (link.SourceElementSet != null))
{
if (this.Engine is RTCTools.OpenMI.Sdk.Wrapper.IAdvancedEngine)
{
TimeValueSet timeValueSet = ((IAdvancedEngine) this.Engine).GetValues(link.SourceQuantity.ID, link.SourceElementSet.ID);
if (timeValueSet.Time != null)
{
if (_useSpatialMapping)
{
this.smartBuffer.AddValues(timeValueSet.Time, elementMapper.MapValues(timeValueSet.ValueSet));
}
else
{
this.smartBuffer.AddValues(timeValueSet.Time, timeValueSet.ValueSet);
}
}
}
else // the engine is IEngine or IRunEngine
{
ITime time = this.Engine.GetCurrentTime();
IValueSet valueSet = this.Engine.GetValues(link.SourceQuantity.ID,link.SourceElementSet.ID);
if (_useSpatialMapping)
{
this.smartBuffer.AddValues(time,elementMapper.MapValues(valueSet));
}
else
{
this.smartBuffer.AddValues(time,valueSet);
}
}
}
SmartBuffer.ClearBefore(link.TargetComponent.EarliestInputTime);
}
///
/// Retrieves a value from the buffer that applies to the time passes as argument.
/// During this process the buffer will do temporal operations,
/// such as extrapolations, interpolations, or aggregation
///
/// The time for which the values should apply
/// The values
public virtual IValueSet GetValue(ITime time)
{
IValueSet values = this.SmartBuffer.GetValues(time);
if (_linearDataOperation != null)
{
values = _linearDataOperation.PerformDataOperation(values);
}
return ConvertUnit(values);
}
///
/// Convert the units according the what is specified in the link
///
/// The values
/// The unit converted values
private IValueSet ConvertUnit(IValueSet values)
{
double aSource = link.SourceQuantity.Unit.ConversionFactorToSI;
double bSource = link.SourceQuantity.Unit.OffSetToSI;
double aTarget = link.TargetQuantity.Unit.ConversionFactorToSI;
double bTarget = link.TargetQuantity.Unit.OffSetToSI;
if (aSource != aTarget || bSource != bTarget)
{
if (values is IScalarSet)
{
double[] x = new double[values.Count];
for (int i = 0; i < values.Count; i++)
{
x[i] = (((IScalarSet) values).GetScalar(i) * aSource + bSource - bTarget) / aTarget;
}
return new ScalarSet(x);
}
else if (values is IVectorSet)
{
ArrayList vectors = new ArrayList();
for (int i = 0; i < values.Count; i++)
{
double x = (((IVectorSet) values).GetVector(i).XComponent * aSource + bSource - bTarget) / aTarget;
double y = (((IVectorSet) values).GetVector(i).YComponent * aSource + bSource - bTarget) / aTarget;
double z = (((IVectorSet) values).GetVector(i).ZComponent * aSource + bSource - bTarget) / aTarget;
Vector newVector = new Vector(x, y, z);
vectors.Add (newVector);
}
return new VectorSet((Vector[]) vectors.ToArray(typeof(Vector)));
}
else
{
throw new Exception ("Type " + values.GetType().FullName + " not suppported for unit conversion");
}
}
return values;
}
///
/// Saves a copy of the buffer
///
/// ID for the saved buffer state
public void KeepCurrentBufferState(string bufferStateID)
{
_bufferStates.Add(bufferStateID, new SmartBuffer(this.SmartBuffer));
}
///
/// Clears a buffer state
///
/// ID for the state to clear
public void ClearBufferState(string bufferStateID)
{
_bufferStates.Remove(bufferStateID);
}
///
/// Restores the buffer with a previously saved buffer state
///
/// ID for the state to restore
public void RestoreBufferState(string bufferStateID)
{
this.smartBuffer = new SmartBuffer((SmartBuffer) _bufferStates[bufferStateID]);
}
}
}