// Copyright (C) Stichting Deltares 2019. All rights reserved.
//
// This file is part of the application DAM - Live.
//
// DAM - UI is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
//
// All names, logos, and references to "Deltares" are registered trademarks of
// Stichting Deltares and remain full property of Stichting Deltares at all times.
// All rights reserved.
using System;
using System.IO;
using System.Xml.Linq;
using Deltares.Dam.Application.Live.Properties;
using Deltares.Dam.Data;
using Deltares.Dam.Data.Assemblers;
using Deltares.Standard.Application;
namespace Deltares.Dam.Application.Live
{
public class ModelRunner : IModelRunner
{
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();
protected internal FileInfo DamXFile { get; set; }
protected internal FileInfo FewsInputFile { get; set; }
protected internal FileInfo FewsOutputFile { get; set; }
protected internal FileInfo ParametersFile { get; set; }
///
/// Gets or sets the DAM project data used for stability calculations
///
public DamProjectData ProjectData { 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 string Filter { get; set; }
public IModelRunner RunnerDelegate { get; set; }
public bool HasErrors
{
get { return Logger.HasLoggedExceptions; }
}
public ModelRunner()
{
// 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. Validates input files, deletes former project files,
/// creates working folders and prepares the in and output time series collections
///
public virtual void Initialize()
{
if (ProjectData == null)
{
if (DamXFile == null)
throw new InvalidOperationException(NoDamxFile);
ProjectData = 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);
}
}
///
/// Creates and set's up the working directories. By default the directory the output file
/// will be used if the working path is not set
///
public virtual void CreateAndSetWorkingDirectories()
{
string targetPath;
string defaultFolder = FewsOutputFile != null ? FewsOutputFile.DirectoryName : null;
if (!string.IsNullOrWhiteSpace(WorkingPath))
{
targetPath = WorkingPath;
}
else
{
if (defaultFolder == null)
{
throw new InvalidOperationException(ErrorExtractingWorkingFolder);
}
targetPath = string.IsNullOrWhiteSpace(defaultFolder) ? "." : defaultFolder;
}
CreateWorkingDirectory(targetPath);
// The following path's are sub folders of the main working path
StabilityWorkingPath = Path.Combine(targetPath, StabilityWorkingPath);
CreateWorkingDirectory(StabilityWorkingPath);
PipingWorkingPath = Path.Combine(targetPath, PipingWorkingPath);
CreateWorkingDirectory(PipingWorkingPath);
}
///
/// Creates the working directory if they not exist.
///
/// Name of the directory.
protected static void CreateWorkingDirectory(string directoryName)
{
if (string.IsNullOrWhiteSpace(directoryName))
throw new ArgumentNullException("directoryName");
if (!Directory.Exists(directoryName))
{
Directory.CreateDirectory(directoryName);
}
}
///
/// Performs all the steps to transform the input time series collection to
/// the output time series collection with the calculated values
///
public virtual void Run()
{
Initialize();
CreateAndSetWorkingDirectories();
DeleteFormerProjectFiles();
Process();
WriteResultsToFile(FewsOutputFile.FullName);
}
///
/// Processes an output time series using the input time series collection
/// and the required project data.
///
public virtual void Process()
{
if (ProjectData == null)
throw new InvalidOperationException("No DAM project data available.");
if (InputTimeSeriesCollection == null)
throw new InvalidOperationException("No input time series collection available.");
if (OutputTimeSeriesCollection == null)
throw new InvalidOperationException("No output time series collection available.");
if (RunnerDelegate != null)
{
RunnerDelegate.WorkingPath = WorkingPath;
RunnerDelegate.WaterLevelOffset = WaterLevelOffset;
RunnerDelegate.StabilityExePath = StabilityExePath;
RunnerDelegate.PipingWorkingPath = PipingWorkingPath;
RunnerDelegate.UseMStabForCalculation = UseMStabForCalculation;
RunnerDelegate.StabilityWorkingPath = StabilityWorkingPath;
RunnerDelegate.CalculationParameters = CalculationParameters;
RunnerDelegate.InputTimeSeriesCollection = InputTimeSeriesCollection;
RunnerDelegate.OutputTimeSeriesCollection = OutputTimeSeriesCollection;
RunnerDelegate.ProjectData = ProjectData;
RunnerDelegate.Filter = Filter;
RunnerDelegate.Run();
// sync back the processed data
OutputTimeSeriesCollection = RunnerDelegate.OutputTimeSeriesCollection;
}
else
{
Logger.LogWarning("No model runner set to delegate the processing of the time series to");
}
}
///
/// Cleanup the working directory
///
protected void DeleteFormerProjectFiles()
{
// remove known files for stability calculation
var di = new DirectoryInfo(StabilityWorkingPath);
FileInfo[] rgFiles = di.GetFiles("*.st?");
foreach (FileInfo fi in rgFiles)
File.Delete(fi.FullName);
rgFiles = di.GetFiles("*.sti.xml");
foreach (FileInfo fi in rgFiles)
File.Delete(fi.FullName);
rgFiles = di.GetFiles("*.wmf");
foreach (FileInfo fi in rgFiles)
File.Delete(fi.FullName);
rgFiles = di.GetFiles("*.err");
foreach (FileInfo fi in rgFiles)
File.Delete(fi.FullName);
foreach (FileInfo fi in rgFiles)
File.Delete(fi.FullName);
// remove known files for piping calculator
di = new DirectoryInfo(PipingWorkingPath);
rgFiles = di.GetFiles("*.txt");
foreach (FileInfo fi in rgFiles)
File.Delete(fi.FullName);
}
///
/// Writes all the results in the output collection to the given file
///
///
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);
}
}
}
}