using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Xml.Linq; using Deltares.Dam.Application.Live.Properties; using Deltares.Dam.Data; using Deltares.Dam.Data.Assemblers; using Deltares.Dam.Data.DamEngineIo; using Deltares.DamEngine.Interface; using Deltares.DamEngine.Io; using Deltares.DamEngine.Io.XmlInput; using Deltares.Standard.Application; using Deltares.Standard.Language; using Deltares.Standard.Logging; namespace Deltares.Dam.Application.Live { public class DamEngineRunner { internal const string NoDamxFile = "No .damx file set to load project data from."; internal const string NoFewsInputFileAvailable = "No FEWS input file available to read the input time series from."; internal const string NoFewsOutputFileAvailable = "No FEWS output file available to write the result to."; internal const string ErrorExtractingWorkingFolder = "An error occured while trying to extract the path from the FEWS input file. This error can be solved by setting a working folder"; internal LogHelper Logger = LogHelper.Create(); public DamProjectData DamProjectData { get; set; } public CalculationParameters CalculationParameters { get; set; } public TimeSerieCollection OutputTimeSeriesCollection { get; set; } public TimeSerieCollection InputTimeSeriesCollection { get; set; } public string StabilityWorkingPath { get; set; } public string PipingWorkingPath { get; set; } public string StabilityExePath { get; set; } public bool UseMStabForCalculation { get; set; } public double WaterLevelOffset { get; set; } public string WorkingPath { get; set; } public int MaxCalculationCores { get; set; } = 1; protected internal FileInfo DamXFile { get; set; } protected internal FileInfo FewsInputFile { get; set; } protected internal FileInfo FewsOutputFile { get; set; } protected internal FileInfo ParametersFile { get; set; } public string Filter { get; set; } public bool HasErrors { get { return Logger.HasLoggedExceptions; } } public DamEngineRunner() { // WorkingPath will be extracted from file name if available StabilityWorkingPath = Settings.Default.StabilityWorkingPath; PipingWorkingPath = Settings.Default.PipingWorkingPath; StabilityExePath = Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), Settings.Default.MStabExePath); UseMStabForCalculation = Settings.Default.UseMStabForCalculation; WaterLevelOffset = Settings.Default.WaterLevelOffset; } /// /// Initializes this instance. /// /// /// public void Initialize() { LoadDataFromFiles(); AdaptDamProjectData(); } private void AdaptDamProjectData() { // Prepare DamProjetData for serializing to Dam Engine DamProjectData.SelectedLocationJobs.Clear(); foreach (Data.Location location in DamProjectData.Locations) { var locationJob = new LocationJob() { Location = location, Run = true }; DamProjectData.LocationJobs.Add(locationJob); } DamProjectData.FillOverallSensorData(); // Add time series to DamProjectData DamProjectData.InputTimeSerieCollection = InputTimeSeriesCollection; // Set correct calculation settings DamProjectData.DamProjectType = DamProjectType.Calamity; } private void LoadDataFromFiles() { if (DamProjectData == null) { if (DamXFile == null) throw new InvalidOperationException(NoDamxFile); DamProjectData = DamProject.LoadData(DamXFile.FullName); WorkingPath = Path.ChangeExtension(DamXFile.FullName, ".Calc"); } if (InputTimeSeriesCollection == null) { if (FewsInputFile == null) throw new InvalidOperationException(NoFewsInputFileAvailable); InputTimeSeriesCollection = TimeSerieCollection.LoadFromFile(FewsInputFile); } if (OutputTimeSeriesCollection == null) { if (FewsOutputFile == null) throw new InvalidOperationException(NoFewsOutputFileAvailable); OutputTimeSeriesCollection = InputTimeSeriesCollection.GetShallowCopy(); } if (CalculationParameters == null && ParametersFile != null) { // Read calculation parameters, if available CalculationParameters = CalculationParameters.LoadFromFile(ParametersFile); } } public void Run() { Initialize(); OutputTimeSeriesCollection.Series.Clear(); RunStabilityInside(); CheckForNotImplementedModels(); WriteResultsToFile(FewsOutputFile.FullName); } private void CheckForNotImplementedModels() { if (CalculationParameters.CalculationModules.Overtopping) { Logger.LogError("Calculation module Overtopping not implemented yet"); } if (CalculationParameters.CalculationModules.PipingBligh) { Logger.LogError("Calculation module PipingBligh not implemented yet"); } if (CalculationParameters.CalculationModules.PipingIJkdijk) { Logger.LogError("Calculation module PipingIJkdijk not implemented yet"); } if (CalculationParameters.CalculationModules.PipingSellmeijer) { Logger.LogError("Calculation module PipingSellmeijer not implemented yet"); } if (CalculationParameters.CalculationModules.PipingSellmeijerProbabilistic) { Logger.LogError("Calculation module PipingSellmeijerProbabilistic not implemented yet"); } if (CalculationParameters.CalculationModules.PipingWti) { Logger.LogError("Calculation module PipingWti not implemented yet"); } if (CalculationParameters.CalculationModules.StabilityOutside) { Logger.LogError("Calculation module StabilityOutside not implemented yet"); } } private void RunStabilityInside() { if (CalculationParameters.CalculationModules.Stability) { DamProjectData.DamProjectCalculationSpecification.CurrentSpecification.FailureMechanismSystemType = FailureMechanismSystemType.StabilityInside; DamProjectData.DamProjectCalculationSpecification.CurrentSpecification.FailureMechanismeParamatersMStab.MStabParameters = CalculationParameters.MStabParameters; CallDamEngine(); OutputTimeSeriesCollection.Series.AddRange(DamProjectData.OutputTimeSerieCollection.Series); } } private void CallDamEngine() { DamProjectData.MaxCalculationCores = MaxCalculationCores; try { Input input = FillXmlInputFromDamUi.CreateInput(DamProjectData); #if DEBUG const string inputFilename = "InputFile.xml"; DamXmlSerialization.SaveInputAsXmlFile(inputFilename, input); #endif string inputXml = DamXmlSerialization.SaveInputAsXmlString(input); var damEngineInterface = new EngineInterface(inputXml); string validationMessages = damEngineInterface.Validate(); // now the validation messages should be deserialized. If any, they should be passed on to the Validator // and checked for errors. IF errors are found, then no calculation. When no messages or only warnings then // do calculate. For now, just check length if (string.IsNullOrEmpty(validationMessages)) { string outputXml = damEngineInterface.Run(); var output = DamXmlSerialization.LoadOutputFromXmlString(outputXml); FillDamUiFromXmlOutput.AddOutputToDamProjectData(DamProjectData, output); #if DEBUG const string outputFilename = "OutputFile.xml"; DamXmlSerialization.SaveOutputAsXmlFile(outputFilename, output); #endif } } catch (Exception e) { LogManager.Add(new LogMessage(LogMessageType.FatalError, typeof(EngineInterface), string.Format("{0}", e.Message))); } } protected void WriteResultsToFile(string fileName) { if (string.IsNullOrWhiteSpace(fileName)) throw new ArgumentNullException("fileName"); var timeSerieAssembler = new TimeSeriesAssembler(); XDocument doc = timeSerieAssembler.CreateDataTransferDocument(OutputTimeSeriesCollection); try { doc.Save(fileName); FileWriterUtil.RemoveThreeBytesFromXml(fileName); } catch (Exception e) { Logger.LogError("Could not export Fews xml file", e); } } } }