using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms.VisualStyles;
using Deltares.Dam.Data;
using Deltares.Standard;
namespace Deltares.Dam.DamLiveShowcase
{
///
/// Calculate with DamLive
///
public class DamLiveProcessor : IDamLiveProcessor
{
private const int waterLevelSensorIndex = 0;
private const int polderLevelSensorIndex = 1;
private const int sensorValueSensorIndex = 2;
private double sensorChangeTolerance = 0.001;
private const double MissingValue = -9999;
private const string sensorBaseFilename = "Sensor";
private string damLiveExecutableFilename = "DamLive.exe";
private string workingDirectory = "";
private string damProjectFilename = "";
private string inputTimeSerieFilename = "";
private string outputTimeSerieFilename = "";
private string calculationParametersFilename = "";
private string sensorMeasurementsDirectory = "";
private int sensorCount = 3;
private double[] sensorValues;
private double[] oldSensorValues;
private string[] sensorFilenames;
DateTime currentStepDateTime;
private double currentStabilityFactor;
///
/// Initializes a new instance of the class.
///
public DamLiveProcessor()
{
sensorValues = new double[sensorCount];
oldSensorValues = new double[sensorCount];
sensorFilenames = new string[sensorCount];
}
///
/// Gets or sets the dam live executable filename.
///
///
/// The dam live executable filename.
///
public string DamLiveExecutableFilename
{
get
{
return damLiveExecutableFilename;
}
set
{
damLiveExecutableFilename = value;
}
}
///
/// Gets or sets the working directory.
///
///
/// The working directory.
///
public string WorkingDirectory
{
get
{
return workingDirectory;
}
set
{
workingDirectory = value;
}
}
///
/// Gets or sets the dam project filename.
///
///
/// The dam project filename.
///
public string DamProjectFilename
{
get
{
return damProjectFilename;
}
set
{
damProjectFilename = value;
}
}
///
/// Gets or sets the input time serie filename.
///
///
/// The input time serie filename.
///
public string InputTimeSerieFilename
{
get
{
return inputTimeSerieFilename;
}
set
{
inputTimeSerieFilename = value;
}
}
///
/// Gets or sets the output time serie filename.
///
///
/// The output time serie filename.
///
public string OutputTimeSerieFilename
{
get
{
return outputTimeSerieFilename;
}
set
{
outputTimeSerieFilename = value;
}
}
///
/// Gets or sets the calculation parameters filename.
///
///
/// The calculation parameters filename.
///
public string CalculationParametersFilename
{
get
{
return calculationParametersFilename;
}
set
{
calculationParametersFilename = value;
}
}
///
/// Gets or sets the sensor measurements directory.
///
///
/// The sensor measurements directory.
///
public string SensorMeasurementsDirectory
{
get
{
return sensorMeasurementsDirectory;
}
set
{
sensorMeasurementsDirectory = value;
}
}
public double SensorChangeTolerance
{
get
{
return sensorChangeTolerance;
}
set
{
sensorChangeTolerance = value;
}
}
///
/// Updates the old sensor values with the current values.
///
private void UpdateOldSensorValues()
{
for (int sensorIndex = 0; sensorIndex < sensorCount; sensorIndex++)
{
oldSensorValues[sensorIndex] = sensorValues[sensorIndex];
}
}
///
/// Ares the sensor values changed.
///
///
private bool AreSensorValuesChanged()
{
var isChanged = false;
for (int sensorIndex = 0; sensorIndex < sensorCount; sensorIndex++)
{
isChanged = isChanged || (Math.Abs((oldSensorValues[sensorIndex] - sensorValues[sensorIndex])) > sensorChangeTolerance);
}
return isChanged;
}
///
/// Calculates the timestep.
///
///
///
public TimeStepData CalculateTimestep()
{
ReadSensorValues();
if (AreSensorValuesChanged())
{
CreateInputForDamLive();
StartDamLiveCalculation();
ReadOutputFromDamLive();
// Dummy data
var timeStep = new TimeStepData()
{
Time = currentStepDateTime,
WaterLevel = sensorValues[waterLevelSensorIndex],
PolderLevel = sensorValues[polderLevelSensorIndex],
SensorValue = sensorValues[sensorValueSensorIndex],
SafetyFactor = currentStabilityFactor,
SlidingCurveFilename = Path.Combine(WorkingDirectory, DetermineSlipCircleFilename())
};
UpdateOldSensorValues();
return timeStep;
}
return null;
}
///
/// Initializes this instance.
///
public void Initialize()
{
for (int sensorIndex = 0; sensorIndex < sensorCount; sensorIndex++)
{
sensorFilenames[sensorIndex] = Path.GetFullPath(Path.Combine(sensorMeasurementsDirectory, String.Format("{0}{1:00}", sensorBaseFilename, sensorIndex)));
}
}
private string DetermineSlipCircleFilename()
{
string[] files = Directory.GetFiles(Path.Combine(WorkingDirectory, @"input.Calc\mstabfiles\Series001\"), "*.wmf", SearchOption.TopDirectoryOnly);
if (files.Length > 0)
{
return files[0];
}
else
{
return @"";
}
string filename = files[0];
}
///
/// Asserts the files exist.
///
private void AssertFileExists(String filename)
{
if (!File.Exists(filename))
{
throw new FileNotFoundException(String.Format("File '{0} not found", filename));
}
}
private void AssertAllFilesExist()
{
AssertFileExists(DamProjectFilename);
AssertFileExists(InputTimeSerieFilename);
AssertFileExists(OutputTimeSerieFilename);
AssertFileExists(CalculationParametersFilename);
}
///
/// Starts the dam live calculation.
///
private void StartDamLiveCalculation()
{
Directory.SetCurrentDirectory(WorkingDirectory);
String calcPath = Path.Combine(WorkingDirectory, "input.Calc");
if (Directory.Exists(calcPath))
{
Directory.Delete(calcPath, true);
}
AssertAllFilesExist();
String argument = String.Format(@"-d {0} -i {1} -o {2} -p {3}",
DamProjectFilename,
InputTimeSerieFilename,
OutputTimeSerieFilename,
CalculationParametersFilename);
var process = new Process
{
StartInfo =
{
FileName = DamLiveExecutableFilename,
Arguments = argument,
UseShellExecute = false
}
};
Parallel.KillOnAbort(process);
process.Start();
try
{
process.WaitForExit();
}
catch (ThreadInterruptedException)
{
// thread was killed by user action to stop calculation
}
}
private bool IsFileLocked(string filename)
{
FileInfo file = new FileInfo(filename);
FileStream stream = null;
try
{
stream = file.Open(FileMode.Open, FileAccess.Read, FileShare.None);
}
catch (IOException)
{
//the file is unavailable because it is:
//still being written to
//or being processed by another thread
//or does not exist (has already been processed)
return true;
}
finally
{
if (stream != null)
stream.Close();
}
//file is not locked
return false;
}
private void ReadSensorValues()
{
for (int sensorIndex = 0; sensorIndex < sensorCount; sensorIndex++)
{
// Make sure file is not in use
int steps = 0;
while (IsFileLocked(sensorFilenames[sensorIndex]) && steps <= 10)
{
System.Threading.Thread.Sleep(100);
steps++;
}
if (steps > 10)
{
continue;
}
// Read sensor values
using (TextReader textReader = new StreamReader(sensorFilenames[sensorIndex]))
{
sensorValues[sensorIndex] = double.Parse(textReader.ReadLine());
textReader.Close();
};
}
}
private void CreateInputForDamLive()
{
currentStepDateTime = DateTime.Now;
var inputTimeSerieCollection = new TimeSerieCollection();
var timeSerieWaterLevel = new TimeSerie()
{
Type = "instantaneous",
CreationDateTime = currentStepDateTime,
EndDateTime = currentStepDateTime,
MissVal = MissingValue,
LocationId = "OMZD",
StationName = "OMZD",
ParameterId = TimeSerie.WaterLevelParameterId
};
timeSerieWaterLevel.Entries.Add(new TimeSerieEntry()
{
DateTime = currentStepDateTime,
Value = sensorValues[waterLevelSensorIndex]
});
var timeSeriePolderLevel = new TimeSerie()
{
Type = "instantaneous",
CreationDateTime = currentStepDateTime,
EndDateTime = currentStepDateTime,
MissVal = MissingValue,
LocationId = "AS2",
StationName = "AS2",
ParameterId = TimeSerie.PiezoMetricHeadId
};
timeSeriePolderLevel.Entries.Add(new TimeSerieEntry()
{
DateTime = currentStepDateTime,
Value = sensorValues[polderLevelSensorIndex]
});
var timeSerieShoulderLevel = new TimeSerie()
{
Type = "instantaneous",
CreationDateTime = currentStepDateTime,
EndDateTime = currentStepDateTime,
MissVal = MissingValue,
LocationId = "AS1",
StationName = "AS1",
ParameterId = TimeSerie.PiezoMetricHeadId
};
timeSerieShoulderLevel.Entries.Add(new TimeSerieEntry()
{
DateTime = currentStepDateTime,
Value = sensorValues[sensorValueSensorIndex]
});
inputTimeSerieCollection.Series.Add(timeSerieWaterLevel);
inputTimeSerieCollection.Series.Add(timeSerieShoulderLevel);
inputTimeSerieCollection.Series.Add(timeSeriePolderLevel);
string fullFilename = Path.GetFullPath(Path.Combine(WorkingDirectory, InputTimeSerieFilename));
inputTimeSerieCollection.Save(fullFilename);
}
private void ReadOutputFromDamLive()
{
string fullFilename = Path.GetFullPath(Path.Combine(WorkingDirectory, OutputTimeSerieFilename));
TimeSerieCollection outputTimeSerieCollection = TimeSerieCollection.LoadFromFile(fullFilename);
currentStabilityFactor = outputTimeSerieCollection.Series[0].Entries[0].Value;
}
}
}