using System; using System.Collections.Generic; using System.Linq; using DHI.Generic.MikeZero.DFS; using DHI.Generic.MikeZero.DFS.dfs123; namespace org.openda.dotnet.DHIStochObserver { /// /// Reads a DFS2 file. /// - Assumptions: /// 1) Equidistant time series. /// 2) All items in the dfs2 are the same variable type. /// 3) the variableID (key) is contained in the title. /// 4) Each item has a name containing the x,y,z coordinate (where z is an integer layer). /// 5) Instantaneous time series only. /// public class DFS2Reader : IDfsRead { private readonly Dfs2File _dfs2File; private readonly int _numTimeSteps; private readonly int _numItems; private readonly List _itemIDs; private readonly List _times; private readonly double _deleteValueDouble; private readonly float _deleteValueFloat; private readonly List _xyLayerPoints; /// /// dfs2 reader. Gets information from the dfs file, and reads data. /// /// full path string to dfs2 file. public DFS2Reader(string dfsfile) { throw new NotImplementedException("ToDo dfs2"); // Open the file as a generic dfs file _dfs2File = DfsFileFactory.Dfs2FileOpen(dfsfile); // Header information is contained in the IDfsFileInfo IDfsFileInfo fileInfo = _dfs2File.FileInfo; // Check for dfs compliance CheckDFSCompliance(); // Number of time steps (same for all items) _numTimeSteps = fileInfo.TimeAxis.NumberOfTimeSteps; // Number of variable items in dfs2 _numItems = _dfs2File.ItemInfo.Count; // Add the IDs to list (Keys) _itemIDs = new List(); foreach (var itemInfo in _dfs2File.ItemInfo) { _itemIDs.Add(itemInfo.Name); } _times = _dfs2File.FileInfo.TimeAxis.GetDateTimes().ToList(); // Delelte Values _deleteValueDouble = _dfs2File.FileInfo.DeleteValueDouble; _deleteValueFloat = _dfs2File.FileInfo.DeleteValueFloat; _xyLayerPoints = new List(); foreach (var itemInfo in _dfs2File.ItemInfo) { throw new NotImplementedException("ToDo dfs2"); } } /// /// Get a dictionary of datetime,double values with real data. /// The order or returned data is by time then time series. /// ie. down the column then accross. /// /// start time (not included) /// end time (inclusive) /// Dictionary of real values with corresponding DateTime public List GetDataFromTimeRange(DateTime startTime, DateTime endTime) { List timeIndicesWithinRange = new List(); List valueSet = new List(); // Find the start and end indexes for (int i = 0; i < _times.Count; i++) { // if t_start 0 && DateTime.Compare( _times[i], endTime ) <= 0 ) { timeIndicesWithinRange.Add(i); } } for (int i = 0; i < _numItems; i++) { for (int j = 0; j < timeIndicesWithinRange.Count; j++) { double? value = GetDataValue(i, timeIndicesWithinRange[j]); if(value != null) { valueSet.Add(new DataPoint(_times[timeIndicesWithinRange[j]], (double)value, _xyLayerPoints[i], _itemIDs[i])); } } } return valueSet; } private double? GetDataValue(int itemNum, int timeIdx) { if (_dfs2File.ItemInfo[itemNum].DataType == DfsSimpleType.Float) { var datastruct = (IDfsItemData)_dfs2File.ReadItemTimeStep(itemNum + 1, timeIdx); // ReSharper disable CompareOfFloatsByEqualityOperator if (datastruct.Data[0] != _deleteValueFloat) // ReSharper restore CompareOfFloatsByEqualityOperator { return Convert.ToDouble(datastruct.Data[0]); } } else if (_dfs2File.ItemInfo[itemNum].DataType == DfsSimpleType.Double) { var datastruct = (IDfsItemData)_dfs2File.ReadItemTimeStep(itemNum + 1, timeIdx); // ReSharper disable CompareOfFloatsByEqualityOperator if (datastruct.Data[0] != _deleteValueDouble) // ReSharper restore CompareOfFloatsByEqualityOperator { return datastruct.Data[0]; } } // if values are not real, return null. return null; } /// /// Return the start date of the DFS file. /// public DateTime StartTime { get { return _times[0]; } } /// /// Return the end date of the DFS file. /// public DateTime EndTime { get { return _times[_times.Count-1]; } } /// /// Return number of time steps in dfs file. Does not check for NaN /// public int NumberTimeSteps { get { return _numTimeSteps; }} /// /// Return number of items in the dfs file. /// public int NumberOfItems { get { return _numItems; } } /// /// Return the ID Keys of each item. /// public string[] ItemIDs { get { return _itemIDs.ToArray(); } } /// /// Checks if the dfs is compliant (calendar, equidistant, instantaneous items...). /// private void CheckDFSCompliance() { // CHECK if Calendar Equidistant (only one supported). if (_dfs2File.FileInfo.TimeAxis.TimeAxisType != TimeAxisType.CalendarEquidistant) { throw new Exception("Error in dfs0 file. Only CalendarEquidistant supported"); } // CHECK if not all items are "Instantaneous", then error foreach (var iteminfo in _dfs2File.ItemInfo) { if (iteminfo.ValueType != DataValueType.Instantaneous) { throw new Exception("Error in dfs0 file. Only Instantaneous items supported"); } } } } }