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; } } }