/* 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.Collections; using OpenDA.DotNet.Interfaces; using OpenMI.Standard2; using OpenMI.Standard2.TimeSpace; //using DHI.OpenMI2.Sdk.Backbone.Generic; using Oatc.OpenMI.Sdk.Backbone; using Oatc.OpenMI.Sdk.Backbone.Generic; //using Oatc.OpenMI.Sdk.Buffer; namespace OpenDA.DotNet.OpenMI.Bridge { public class ExchangeItem : IExchangeItem { private ITimeSpaceInput _openMIInputItem; private ITimeSpaceOutput _openMIOutputItem; //ZZZ private List _openMIInputOutput = new List(); //private List _noise = new List(); //private List _exchangeINDX = new List(); private IDictionary _exchangeINDX = new Dictionary(); private List _exchangeINDX2 = new List(); private int _tstepCount; double[] _Values; private ITimeSpaceExchangeItem _openMIItem; private bool _useBufferedValues; private List> _bufferedValues; private List _bufferedTimes; private static double _lastOutputTime; // HACK, REMOVE private double _timeStampBackup; //In case of missing time just a best try public ExchangeItem(IBaseExchangeItem openMIItem) : this(openMIItem, false) { } public ExchangeItem(IBaseExchangeItem openMIItem, bool useBufferedValues) { _tstepCount = 0; if (openMIItem is ITimeSpaceOutput) { _openMIItem = _openMIOutputItem = (ITimeSpaceOutput)openMIItem; } else if (openMIItem is ITimeSpaceInput) { _openMIItem = _openMIInputItem = (ITimeSpaceInput)openMIItem; } else { throw new Exception("Unknown exchange item type: " + openMIItem.GetType()); } if (_openMIItem.TimeSet != null && _openMIItem.TimeSet.HasDurations) { //ZZZ throw new Exception("\"" + Id + ": OpenDA Time Spans not covered by OpenDA Exchange items"); } _useBufferedValues = useBufferedValues; if (_useBufferedValues) { _bufferedValues = new List> { new List() }; _bufferedTimes = new List(); } } public void AddOut(IBaseExchangeItem openMIo) { if (openMIo is ITimeSpaceOutput) { _openMIItem = _openMIOutputItem = (ITimeSpaceOutput)openMIo; } } public void AddSingleIdx(int idx) { if (!_exchangeINDX.ContainsKey(idx.ToString())) _exchangeINDX.Add(idx.ToString(), idx); if (!_exchangeINDX2.Contains(idx)) _exchangeINDX2.Add(idx); } public void UpdatetstepCount() { _tstepCount++; _Values = null; } public void AddIn(IBaseExchangeItem openMIo) { if (openMIo is ITimeSpaceInput) { _openMIItem = _openMIInputItem = (ITimeSpaceInput)openMIo; } } public string Id { get { return _openMIItem.Id; } } public string Description { get { return _openMIItem.Description; } } public Type ValueType { get { return typeof(IList); } } public Role Role { get { if (_openMIInputItem != null) { //ZZZ //return Role.InOut; // Input Exchange Items can be asked for their current values return Role.Input; // Input Exchange Items can be asked for their current values } return Role.Output; } } public object Values { get { if (_useBufferedValues) { if (_bufferedValues[_bufferedValues.Count - 1].Count == 0) { return _bufferedValues; } else { //Gets the final list of state values // List temp = new List(_bufferedValues[_bufferedValues.Count-1]); List> ttemp = new List>(); ttemp.Add(_bufferedValues[_bufferedValues.Count - 1]); return ttemp; } } //ZZZ Note to self // condition ? first_expression : second_expression; // If condition is true, first expression is evaluated and becomes the result; if false, // the second expression is evaluated and becomes the result. Only one of two expressions is ever evaluated. ITimeSpaceValueSet openMIValueSet = _openMIOutputItem != null ? _openMIOutputItem.Values : _openMIInputItem.Values; // TODO: remove handling only one time step // TODO: replace loop by openMIValueSet.GetValue(new[] { 0 }) List> values = new List> { new List() }; int index0CountValues0 = openMIValueSet.GetIndexCount(new[] { 0 }); for (int i = 0; i < index0CountValues0; i++) { values[0].Add((double)openMIValueSet.GetValue(new[] { 0, i })); } return values; } set { if (_openMIInputItem == null) { throw new Exception("\"" + Id + "SetValues: Values can not be set for output item"); } if (!(value is double[])) { throw new Exception("\"" + Id + "SetValues: Unexpected object type for setting Values: " + value.GetType()); } double[] doubles = (double[])value; if (doubles.Length != 1) { throw new Exception("\"" + Id + "SetValues: Unexpected size for setting Values: " + value.GetType()); } // _openMIInputItem.Values = new ValueSet(_openMIItem, doubles[0]); _openMIInputItem.Values = new ValueSetArray((IList)value); } } public double[] ValuesAsDoubles { get { FillLocalValues(); double[] retVals = new double[_Values.Length]; for (int i = 0; i < _Values.Length; i++) { retVals[i] = _Values[i]; } return retVals; //return ((List>)Values)[0].ToArray(); } set { FillLocalValues(); if (_openMIInputItem == null) { throw new Exception("\"" + Id + "SetValues: Values can not be set for output item"); } if (_Values.Length != value.Length) { throw new Exception("\"" + Id + "SetValues: dimensions of array ("+value.Length+") does not correspond to dimension of echange item ("+_Values.Length+")"); } for (int i = 0; i < _Values.Length; i++) { _Values[i]=value[i]; } _openMIInputItem.Values = new ValueSet(_openMIItem, value); } } // ZZZ TODO // AXPY - Adds a scalar multiple of a vector to this vector. (this += alpha * xx) // this.content[i] = this.content[i] + alpha * x.getValue(i); // This method is called for two different cases // 1. To update the exchange item state variable ( for all the time steps ) // 2. To add noise to the model using only time axpyValues to the last time step // // Therefore needs to differentiate between the two by the number of axpyValues // being passed. This could be a cause of error if only one time step in the model // is run before an observation is available public void AxpyOnValuesStef(double alpha, double[] axpyValues) { if (_openMIInputItem == null) { throw new Exception("\"" + Id + "SetValues: Values can not be set for output item"); } IList timeSeriesValuesForElement = _openMIInputItem.Values.GetElementValuesForTime(0); for (int index = 0; index < axpyValues.Length; index++) { timeSeriesValuesForElement[index] = (double)timeSeriesValuesForElement[index] + alpha * axpyValues[index]; } _openMIInputItem.Values.SetElementValuesForTime(0, timeSeriesValuesForElement); /* tijdelijk */ for (int i = 0; i < _Values.Length; i++) { _Values[i] += axpyValues[i] * alpha; } } public void AxpyOnValues(double alpha, double[] axpyValues) { FillLocalValues(); if (axpyValues.Length > 0) { for (int i = 0; i < _Values.Length; i++) { _Values[i] += axpyValues[i] * alpha; } /*_openMIInputItem.Values = new ValueSetArray((IList)dvalues); */ _openMIInputItem.Values = new ValueSetArray(_Values); } /* ITimeSpaceValueSet temp = _openMIOutputItem.Values; double[] axpyValuesArray = new double[temp.Values2D[0].Count]; List dvalues = new List(); if (axpyValues.Length > 0) { for (int i = 0; i < temp.Values2D[0].Count; i++) { dvalues.Add((double)temp.GetValue(0, i) + axpyValues[i] * alpha); } _openMIInputItem.Values = new ValueSetArray((IList)dvalues); } //throw new NotImplementedException(); */ } public List ApxyLinearly(ITimeSpaceValueSet data, double[] apxValue) { int size = data.Values2D[0].Count; double incrementV = apxValue[0] / size; List dvalues = new List(); for (int i = 0; i < size; i++) { dvalues.Add((double)data.GetValue(0, i) + incrementV * i); } return dvalues; } public void MultiplyValues(double[] multiplicationFactors) { throw new NotImplementedException(); } public double[] Times { get { if (_useBufferedValues) { double[] t = new double[1]; if (_bufferedTimes.Count == 0) { //t[0] = _openMIItem.TimeSet.Times[0].StampAsModifiedJulianDay; return _bufferedTimes.ToArray(); } else { t[0] = _bufferedTimes[_bufferedTimes.Count - 1]; return t; }//return _bufferedTimes.ToArray(); } IList openMITimes = _openMIItem.TimeSet.Times; double[] openDATimes = new double[openMITimes.Count]; if (openMITimes.Count > 0) { for (int i = 0; i < openMITimes.Count; i++) { openDATimes[i] = openMITimes[i].StampAsModifiedJulianDay; } return openDATimes; } else { double[] t = new double[1]; t[0] = _timeStampBackup; return t; } } set { throw new Exception("\"" + Id + "Set times not allowed for OpenMI exchange items"); } } public void AddNewOpenMIOutputValuesToBuffer_marc() { //ZZZ _bufferedValues = new List>(); //_bufferedTimes = new List(); string notimplemented = "seepage"; string notimplemented2 = "groundwater"; if (!_openMIOutputItem.Caption.Contains(notimplemented) && !_openMIOutputItem.Caption.Contains(notimplemented2)) { ITimeSpaceValueSet timeSpaceValueSet = _openMIOutputItem.Values; int index0CountValues0 = timeSpaceValueSet.GetIndexCount(new[] { 0 }); //_bufferedValues[0].Add((double)timeSpaceValueSet.Values2D[0][2]); List templist = new List(); // Place the indexed values to buffer for (int i = 0; i < index0CountValues0; i++) { templist.Add((double)timeSpaceValueSet.Values2D[0][i]); } //templist.Add((double)timeSpaceValueSet.Values2D[0][2]); _bufferedValues.Add(templist); if (_openMIItem.TimeSet != null && _openMIItem.TimeSet.Times.Count > 0) { _bufferedTimes.Add(_openMIItem.TimeSet.Times[0].StampAsModifiedJulianDay); _lastOutputTime = _openMIItem.TimeSet.Times[0].StampAsModifiedJulianDay; // HACK, REMOVE } else { _bufferedTimes.Add(_lastOutputTime); // HACK, REMOVE } } } /// /// Buffer values to the axchangeItems in case of buffering and check/complete time administration when it is missing /// /// Time Stamp of the model. This timestamp is used in case the exchangeItmem itself does not have a timestemp for some reason public void AddNewOpenMIOutputValuesToBuffer(double timeStampModel) { string notimplemented = "seepage"; string notimplemented2 = "groundwater"; string debug1 = "head elevation"; //Some check for handling time when this is not available for an exchangeItem ITimeSpaceValueSet timeSpaceValueSet = _openMIOutputItem.Values; if (!(_openMIItem.TimeSet != null && _openMIItem.TimeSet.Times.Count > 0)) { // Set the time of this echangeItem _timeStampBackup = timeStampModel; } // NOTE: for now we have disabled buffering return; /* if (_openMIOutputItem.Caption.Contains(debug1)) { debug1 = debug1; } if (!_openMIOutputItem.Caption.Contains(notimplemented) && !_openMIOutputItem.Caption.Contains(notimplemented2)) { ITimeSpaceValueSet timeSpaceValueSet = _openMIOutputItem.Values; if (_openMIItem.TimeSet != null && _openMIItem.TimeSet.Times.Count > 0) { double currentOutputTimeAsMJD = _openMIItem.TimeSet.Times[0].StampAsModifiedJulianDay; if (!_bufferedTimes.Contains(currentOutputTimeAsMJD)) { _bufferedValues[0].Add((double)timeSpaceValueSet.Values2D[0][0]); _bufferedTimes.Add(currentOutputTimeAsMJD); _lastOutputTime = currentOutputTimeAsMJD; // HACK, REMOVE } } else { _bufferedValues[0].Add((double)timeSpaceValueSet.Values2D[0][0]); _bufferedTimes.Add(_lastOutputTime); // HACK, REMOVE } } */ } private void FillLocalValues() { if (_Values == null) { ITimeSpaceValueSet temp = _openMIOutputItem.Values; int nVals = temp.Values2D[0].Count; _Values = new double[nVals]; for (int i = 0; i < temp.Values2D[0].Count; i++) { _Values[i] = (double)temp.GetValue(0, i); } } } } }