// Copyright (C) Stichting Deltares 2018. All rights reserved.
//
// This file is part of the Dam Engine.
//
// The Dam Engine is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero 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.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using Deltares.DamEngine.Calculators.KernelWrappers.Common;
using Deltares.DamEngine.Calculators.KernelWrappers.Interfaces;
using Deltares.DamEngine.Calculators.Properties;
using Deltares.DamEngine.Data.General;
using Deltares.DamEngine.Data.General.Results;
using Deltares.DamEngine.Data.Geotechnics;
using Deltares.DamEngine.Data.RegionalAssessmentResults;
using Deltares.DamEngine.Data.Standard.Calculation;
using Deltares.DamEngine.Data.Standard.Language;
using Deltares.DamEngine.Data.Standard.Logging;
using Deltares.DamPiping.BlighCalculator;
using Deltares.DamPiping.Sellmeijer4ForcesCalculator;
namespace Deltares.DamEngine.Calculators.DikesAssessmentRegional
{
///
/// Exception for RegionalScenariosCalculation class
///
public class RegionalScenariosCalculationException : ApplicationException
{
public RegionalScenariosCalculationException() { }
public RegionalScenariosCalculationException(string message) : base(message) { }
}
///
/// Class to perform the calculation of reginal scenarios
///
///
public class RegionalScenariosCalculation : ICalculation
{
private DamProjectData damProjectData;
public List Execute(DamProjectData aDamProjectData)
{
damProjectData = aDamProjectData;
maxCalculationCores = damProjectData.MaxCalculationCores;
var dj = damProjectData.DikeJob;
evaluationJob = damProjectData.GetEvaluationJob();
//evaluationJob.Locations.AddRange();
Run();
return new List();
}
private IKernelWrapper CreateKernelWrapperforJob(DamFailureMechanismeCalculationSpecification currentSpecification,
Location location, SoilGeometryProbability soilGeometryProbability, out IKernelDataInput kernelDataInput,
out IKernelDataOutput kernelDataOutput)
{
IKernelWrapper kernelWrapper = KernelWrapperHelper.CreateKernelWrapper(currentSpecification);
if (kernelWrapper == null)
{
throw new NotImplementedException(Resources.DesignCalculatorKernelNotImplemented);
}
//damProjectData.DesignCalculations = new List();
var calculationMessages = new List();
// Prepare input
var damKernelInput = new DamKernelInput();
var projectPath = damProjectData.ProjectPath != "" ? damProjectData.ProjectPath : Directory.GetCurrentDirectory();
damKernelInput.ProjectDir = projectPath;
damKernelInput.CalculationDir = Path.Combine(projectPath, damProjectData.CalculationMap);
damKernelInput.Location = location;
damKernelInput.SubSoilScenario = soilGeometryProbability;
//damKernelInput.DesignScenario = location.Scenarios[designScenarioIndex];
damKernelInput.DamFailureMechanismeCalculationSpecification = damProjectData.DamProjectCalculationSpecification.CurrentSpecification;
damKernelInput.RiverLevelHigh = damKernelInput.DesignScenario.RiverLevel;// #Bka hier geen Dscen
damKernelInput.RiverLevelLow = damKernelInput.DesignScenario.RiverLevelLow;// #Bka hier geen Dscen
AnalysisType analysisType = DamProjectCalculationSpecification.SelectedAnalysisType;
// SynchronizeDesignScenarioDataWithLocationData(damKernelInput.DesignScenario, damKernelInput.Location);
// IKernelDataInput kernelDataInput;
//IKernelDataOutput kernelDataOutput;
PrepareResult prepareResult = kernelWrapper.Prepare(damKernelInput, 0, out kernelDataInput, out kernelDataOutput);
// Sometimes the kernelDataInput is not created (p.e when soilprofileprobablility is meant for
// stability where Piping calc is wanted). In that case, do nothing but just skip.
if (prepareResult == PrepareResult.Successful)
{
// switch (analysisType)
// {
// case AnalysisType.AdaptGeometry:
// PerformDesignCalculation(kernelWrapper, kernelDataInput, kernelDataOutput,
// damKernelInput, calculationMessages, damProjectData.DesignCalculations);
// break;
// case AnalysisType.NoAdaption:
// PerformSingleCalculation(kernelWrapper, kernelDataInput, kernelDataOutput,
// damKernelInput, calculationMessages, damProjectData.DesignCalculations);
// break;
//
// }
}
else
{
if (prepareResult == PrepareResult.NotRelevant)
{
calculationMessages.Add(new LogMessage(LogMessageType.Info, null,
string.Format(Resources.DesignCalculatorIrrelevant,
location.Name,
soilGeometryProbability.ToString(),
damKernelInput.DesignScenario.LocationScenarioID))); // #Bka hier geen Dscen
}
if (prepareResult == PrepareResult.Failed)
{
calculationMessages.Add(new LogMessage(LogMessageType.Error, null,
string.Format(Resources.DesignCalculatorPrepareError,
location.Name,
soilGeometryProbability.ToString(),
damKernelInput.DesignScenario.LocationScenarioID)));// #Bka hier geen Dscen
}
}
return kernelWrapper;//calculationMessages;
}
private EvaluationJob evaluationJob = null;
private GetValuesDelegate getValuesDelegate;
private ProgressDelegate progressDelegate;
private SendMessageDelegate sendMessageDelegate;
private string mstabExePath = @".\DGeoStability.exe";
private int maxCalculationCores = 255;
private Dictionary runningJobs = new Dictionary();
private bool isSkipStabilityCalculation = false;
///
/// Gets or sets the type of the piping model.
///
///
/// The type of the piping model.
///
public PipingModelType PipingModelType { get; set; }
///
/// Gets or sets the m stab parameters.
///
///
/// The m stab parameters.
///
public MStabParameters MStabParameters { get; set; }
#region ICalculation Members
///
/// Gets the results.
///
/// The results.
///
public CalculationResult GetResults(ref string results)
{
// try
// {
// XmlSerializer serializer = new XmlSerializer();
// results = serializer.SerializeToString(this.evaluationJob);
// return CalculationResult.Succeeded;
// }
// catch
// {
// return CalculationResult.UnexpectedError;
// }##Bka
return CalculationResult.UnexpectedError;
}
///
/// Loads the specified input.
///
/// The input.
///
public CalculationResult Load(string input)
{
// try
// {
// XmlDeserializer deserializer = new XmlDeserializer();
// this.evaluationJob = (EvaluationJob)deserializer.XmlDeserializeFromString(input, typeof(EvaluationJob), new DefaultClassFactory());
// return CalculationResult.Succeeded;
// }
// catch
// {
// return CalculationResult.UnexpectedError;
// }##Bka
return CalculationResult.UnexpectedError;
}
///
/// Registers the get values.
///
/// The get values delegate.
///
public CalculationResult RegisterGetValues(GetValuesDelegate aGetValuesDelegate)
{
getValuesDelegate = aGetValuesDelegate;
return CalculationResult.Succeeded;
}
///
/// Registers the progress.
///
/// The progress delegate.
///
public CalculationResult RegisterProgress(ProgressDelegate aProgressDelegate)
{
progressDelegate = aProgressDelegate;
return CalculationResult.Succeeded;
}
///
/// Registers the send debug information.
///
/// The send debug information delegate.
///
public CalculationResult RegisterSendDebugInfo(SendDebugInfodelegate sendDebugInfoDelegate)
{
return CalculationResult.Succeeded;
}
///
/// Registers the send message.
///
/// The send message delegate.
///
public CalculationResult RegisterSendMessage(SendMessageDelegate aSendMessageDelegate)
{
sendMessageDelegate = aSendMessageDelegate;
return CalculationResult.Succeeded;
}
///
/// Registers the set values.
///
/// The set values delegate.
///
public CalculationResult RegisterSetValues(SetValuesDelegate setValuesDelegate)
{
return CalculationResult.Succeeded;
}
///
/// Registers the user abort.
///
/// The user abort delegate.
///
public CalculationResult RegisterUserAbort(UserAbortDelegate userAbortDelegate)
{
return CalculationResult.Succeeded;
}
///
/// Runs this instance.
///
///
public CalculationResult Run()
{
try
{
List tasks = FillQueue();
General.Parallel.Run(tasks, RunTask, progressDelegate, maxCalculationCores);
FillResults(tasks);
return CalculationResult.Succeeded;
}
catch(Exception exception)
{
sendMessageDelegate(new LogMessage(LogMessageType.Warning, null, "Unexpected error:" + exception.Message));
throw exception;
}
}
///
/// Validates this instance.
///
///
public CalculationResult Validate()
{
return CalculationResult.Succeeded;
}
#endregion
///
/// Gets the version.
///
///
/// The version.
///
public string Version
{
get { return System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(); }
}
///
/// Gets or sets the mstab executable path.
///
///
/// The mstab executable path.
///
public string MStabExePath
{
get { return mstabExePath; }
set { mstabExePath = value; }
}
///
/// Gets or sets a value indicating whether this instance is skip stability calculation.
///
///
/// true if this instance is skip stability calculation; otherwise, false.
///
public bool IsSkipStabilityCalculation
{
get { return isSkipStabilityCalculation; }
set { isSkipStabilityCalculation = value; }
}
private List FillQueue()
{
List tasks = new List();
evaluationJob.FailedEvaluatedLocations = new List();
foreach (var location in evaluationJob.Locations)
{
if (location.Segment == null)
{
// Add this location to the failed locations
if (evaluationJob.FailedEvaluatedLocations.IndexOf(location) < 0)
{
evaluationJob.FailedEvaluatedLocations.Add(location);
var locationHasNoSegment = LocalizationManager.GetTranslatedText(GetType(), "LocationHasNoSegment");
sendMessageDelegate(new LogMessage(LogMessageType.Error, location, locationHasNoSegment));
}
}
else
{
// TODO: Ask Erik Vastenburg how to handle piping and stability soilprofiles when determining RWScenarios
// For now we only use the stability profiles.
var soilGeometryProbabilities =
location.Segment.SoilProfileProbabilities.Where(s => (s.SegmentFailureMechanismType == null) ||
(s.SegmentFailureMechanismType.Value ==
FailureMechanismSystemType.StabilityInside)).ToList();
if (soilGeometryProbabilities.Count == 0)
{
evaluationJob.FailedEvaluatedLocations.Add(location);
sendMessageDelegate(
new LogMessage(LogMessageType.Warning, location, string.Format("Location has no soilprofiles: ") +
string.Format("Segment: {0}", location.Segment.Name)));
}
else
{
foreach (SoilGeometryProbability soilGeometryProbability in soilGeometryProbabilities)
{
if (soilGeometryProbability.SoilProfileType == SoilProfileType.ProfileType2D || soilGeometryProbability.SoilProfileType == SoilProfileType.ProfileTypeStiFile)
{
evaluationJob.FailedEvaluatedLocations.Add(location);
sendMessageDelegate(new LogMessage(LogMessageType.Warning, location, LocalizationManager.GetTranslatedText(this, "Geometry2DNotSupportedInRegionalAssessment") +
string.Format("Segment: {0}", location.Segment.Name)));
}
else
{
SoilProfile soilProfile = soilGeometryProbability.SoilProfile1D;
IList regionalScenarios;
try
{
regionalScenarios = GetRegionalScenarios(location, soilGeometryProbability);
}
catch (Exception e)
{
regionalScenarios = null;
// Add this location to the failed locations
if (evaluationJob.FailedEvaluatedLocations.IndexOf(location) < 0)
{
evaluationJob.FailedEvaluatedLocations.Add(location);
sendMessageDelegate(
new LogMessage(LogMessageType.Warning, location, String.Format("Cannot generate scenarios: {0}", e.Message) +
String.Format("Soilprofile: {0}", soilProfile.Name)));
}
}
if (regionalScenarios != null)
{
foreach (RegionalScenarioProfileResult job in regionalScenarios)
{
tasks.Add(job);
}
}
}
}
}
}
}
return tasks;
}
private IList GetRegionalScenarios(Location location, SoilGeometryProbability soilGeometryProbability)
{
RegionalScenarioSelector selector = new RegionalScenarioSelector
{
PipingModelType = PipingModelType,
MStabParameters = MStabParameters
};
return selector.GetScenarios(location, soilGeometryProbability);
}
private void RunTask(object task)
{
var job = (RegionalScenarioProfileResult)task;
try
{
if (!IsSkipStabilityCalculation)
{
ProcessJob(job);
}
else
{
job.CalculationResult = CalculationResult.NoRun;
}
}
catch (Exception e)
{
job.CalculationResult = CalculationResult.UnexpectedError;
sendMessageDelegate(new LogMessage(LogMessageType.Warning, job, String.Format(job.LocationName + " Error: {0}", e.Message)));
}
}
///
/// Select which job processor to use, depending on failuremechanism
///
///
private void ProcessJob(RegionalScenarioProfileResult job)
{
Debug.WriteLine(String.Format("Job {0}, location {1}, Scenario {2}", job.FailureMechanismType.ToString(), job.LocationName, job.ScenarioType.ToString()));
switch (job.FailureMechanismType)
{
case FailureMechanismSystemType.StabilityInside:
ProcessJobStability(job);
break;
case FailureMechanismSystemType.Piping:
ProcessJobPiping(job);
break;
default:
throw new RegionalScenariosCalculationException(String.Format("Failuremechanism {0} not yet implemented for scenario calculation", job.FailureMechanismType));
}
}
///
/// Process a job for failuremechanism Piping
///
///
private void ProcessJobPiping(RegionalScenarioProfileResult job)
{
if (job.Location.ModelFactors.UpliftCriterionPiping.HasValue)
{
// var modelParametersForPLLines = new ModelParametersForPlLines();
// var calculator = GetCalculatorForPipingModel(job, modelParametersForPLLines);
// double waterLevel;
// switch (job.LoadSituation)
// {
// case LoadSituation.Dry:
// waterLevel = job.Location.BoezemLevelLbp;
// break;
// default: // LoadSituation.Wet
// waterLevel = job.Location.BoezemLevelTp;
// break;
// }
// //job.SoilGeometryProbability.SoilProfile1D.EnsureUniqueLayerIds();
// var calculationName = GetCalculationNameForPipingCalculator(job);
// calculator.FilenameCalculation = Path.Combine(Path.Combine(damProjectData.ProjectPath, job.FailureMechanismType.ToString()), calculationName);
// calculator.IsHydraulicShortcut = (job.HydraulicShortcutType == HydraulicShortcutType.HydraulicShortcut);
// double? pipingFactor = calculator.CalculatePipingFactor(job.Location, job.Location.SurfaceLine, job.SoilGeometryProbability.SoilProfile1D, waterLevel);
// job.BaseFileName = calculator.FilenameCalculation;
//
// job.RegionalResultType = RegionalResultType.SafetyFactor;
// if (pipingFactor.HasValue)
// {
// job.SafetyFactor = pipingFactor.Value;
// job.CalculationResult = CalculationResult.Succeeded;
// job.ProbabilityOfFailure = double.NaN;
// job.RegionalResultType = RegionalResultType.SafetyFactor;
// }
//
// else
// {
// job.SafetyFactor = double.NaN;
// job.CalculationResult = CalculationResult.RunFailed;
// }
}
else
{
throw new RegionalScenariosCalculationException(String.Format("Uplift criterion not defined for location {0}", job.Location.Name));
}
}
private string GetCalculationNameForPipingCalculator(RegionalScenarioProfileResult job)
{
string calculationName;
switch (job.PipingModelOption)
{
case PipingModelType.SellmeijerVnk : calculationName = String.Format("Calc(SellmeijerVnk)_Loc({0})_Pro({1}))",
job.LocationName, job.SoilProfileName);
break;
case PipingModelType.Sellmeijer4Forces: calculationName = String.Format("Calc(Sellmeijer4Forces)_Loc({0})_Pro({1}))",
job.LocationName, job.SoilProfileName);
break;
// Set Sellmeijer4Forces as default.
default: calculationName = String.Format("Calc(Sellmeijer4Forces)_Loc({0})_Pro({1}))",
job.LocationName, job.SoilProfileName);
break;
}
calculationName = Regex.Replace(calculationName, @"[\\\/:\*\?""'<>|.]", "_");
return calculationName;
}
///
/// Determines the proper calculator for pipng
///
///
///
/// proper piping calculator
// private PipingCalculator GetCalculatorForPipingModel(RegionalScenarioProfileResult job, ModelParametersForPLLines modelParametersForPlLines)
// {
// PipingCalculator calculator;
// switch (job.PipingModelOption)
// {
// case PipingModelType.SellmeijerVnk: calculator = new PipingCalculatorSellmeijer(modelParametersForPLLines,
// 1.0, null, null, null, job.Location.ModelFactors.UpliftCriterionPiping.Value);
// break;
// case PipingModelType.Sellmeijer4Forces: calculator = new PipingCalculatorSellmeijer4Forces(modelParametersForPLLines,
// 1.0, null, null, job.Location.ModelFactors.UpliftCriterionPiping.Value);
// break;
// case PipingModelType.Bligh: calculator = new PipingCalculatorBligh(modelParametersForPLLines,
// 1.0, null, null, job.Location.ModelFactors.UpliftCriterionPiping.Value);
// break;
// default:
// throw new RegionalScenariosCalculationException(String.Format("Piping model {0} not yet implemented for scenario calculation", job.PipingModelOption));
// }
// return calculator;
// }
///
/// Process a job for failuremechanism Stability
///
///
private void ProcessJobStability(RegionalScenarioProfileResult job)
{
// StabilityCalculation calculator = new StabilityCalculation();
var currentSpecification = damProjectData.DamProjectCalculationSpecification.CurrentSpecification;
currentSpecification.FailureMechanismSystemType = job.FailureMechanismType;
IKernelDataInput kernelDataInput;
IKernelDataOutput kernelDataOutput;
var calculator = CreateKernelWrapperforJob(currentSpecification, job.Location, job.SoilGeometryProbability,
out kernelDataInput, out kernelDataOutput);
lock (runningJobs)
{
runningJobs[calculator] = job;
}
// calculator.MStabExePath = this.MStabExePath;
// calculator.RegisterSendMessage(this.SendStabilityMessage);
//
// string soilDatabaseName = job.Location.StabilityOptions.SoilDatabaseName;
// DamFailureMechanismeCalculationSpecification damCalculation =
// calculator.GetSpecification(this.evaluationJob.DikeName, soilDatabaseName, job.Location, new SoilGeometry(job.SoilGeometryProbability.SoilProfile1D, null),
// (MStabModelType)job.MstabModelOption, job.LoadSituation, job.DikeDrySensitivity, job.HydraulicShortcutType, MStabParameters);
//
// calculator.SaveToFile(damCalculation.FailureMechanismParametersMStab);
// string inputFile = damCalculation.FailureMechanismParametersMStab.MStabParameters.ProjectFileName;
//
// job.BaseFileName = inputFile.Replace(DamProject.ProjectWorkingPath, @"").Replace(".sti", "");
// calculator.Load(inputFile);
List messages;
calculator.Execute(kernelDataInput, kernelDataOutput, out messages);
job.CalculationResult = CalculationResult.Succeeded; //Run();
if (job.CalculationResult == CalculationResult.Succeeded)
{
string resultMessage = "";
List results;
var input = (DamKernelInput) kernelDataInput;
calculator.PostProcess(input, kernelDataOutput, resultMessage, out results);
//string results = "";
job.SafetyFactor = results[0].SafetyFactor.Value;
job.CalculationResult = results[0].CalculationResult;
job.RegionalResultType = RegionalResultType.SafetyFactor;
//XmlDeserializer deserializer = new XmlDeserializer();
// RegionalResult result = (RegionalResult)deserializer.XmlDeserializeFromString(results, typeof(RegionalResult));
// job.SafetyFactor = result.SafetyFactor;
// job.ProbabilityOfFailure = result.ProbabilityOfFailure;
// job.RegionalResultType = result.RegionalResultType;
// job.CalculationResult = result.CalculationResult;
}
else
{
job.RegionalResultType = (currentSpecification.FailureMechanismParametersMStab.MStabParameters.IsProbabilistic ? RegionalResultType.ProbabilityOfFailure : RegionalResultType.SafetyFactor);
job.SafetyFactor = double.NaN;
job.ProbabilityOfFailure = double.NaN;
}
lock (runningJobs)
{
runningJobs.Remove(calculator);
}
}
///
/// Log messages
///
///
private void SendStabilityMessage(LogMessage logMessage)
{
lock (runningJobs)
{
if (logMessage.Subject != null)
{
var job = (RegionalScenarioProfileResult)runningJobs[(ICalculation)logMessage.Subject];
logMessage.Subject = job.Location;
}
}
this.sendMessageDelegate(logMessage);
}
///
/// Fill the results for the scenarios
///
private void FillResults(List tasks)
{
// Fill scenariosResult structure with jobs just run
foreach (Location location in this.evaluationJob.Locations)
{
try
{
RegionalScenariosResult scenariosResult = new RegionalScenariosResult();
if (this.evaluationJob.FailedEvaluatedLocations.IndexOf(location) < 0)
{
// scenarios were succesfully created, so results are available
foreach (RegionalScenarioProfileResult job in tasks)
{
if (job.LocationName.Equals(location.Name))
{
RegionalScenarioResult scenarioResult = null;
foreach (var existingScenarioResult in scenariosResult.RegionalScenarioResults)
{
if (existingScenarioResult.ScenarioType == job.ScenarioType)
{
scenarioResult = existingScenarioResult;
}
}
if (scenarioResult == null)
{
scenarioResult = new RegionalScenarioResult();
scenarioResult.ScenarioType = job.ScenarioType;
scenariosResult.RegionalScenarioResults.Add(scenarioResult);
}
scenarioResult.RegionalScenarioProfileResults.Add(job);
}
}
// Combine results
foreach (var scenarioResult in scenariosResult.RegionalScenarioResults)
{
this.CombineProfiles(scenarioResult);
}
this.CombineScenarios(scenariosResult);
}
else
{
// scenarios were not succesfully created, so results are not available
// no succesful calculations found
scenariosResult.CalculationResult = CalculationResult.RunFailed;
scenariosResult.SafetyFactor = double.NaN;
}
// scenariosResult are the results of all scenarios for one location.
evaluationJob.Results.Add(scenariosResult);
}
catch (Exception e)
{
RegionalScenariosResult scenariosResult = new RegionalScenariosResult
{
CalculationResult = CalculationResult.RunFailed,
SafetyFactor = double.NaN
};
sendMessageDelegate(new LogMessage(LogMessageType.Warning, location, String.Format("Error in location {0}: {1}", location.Name, e.Message)));
}
}
}
private void CombineProfiles(RegionalScenarioResult scenarioResult)
{
// combine results of profiles
scenarioResult.SafetyFactor = Double.MaxValue;
foreach (var profileResult in scenarioResult.RegionalScenarioProfileResults)
{
if (profileResult.CalculationResult == CalculationResult.Succeeded)
{
if (profileResult.SafetyFactor < scenarioResult.SafetyFactor)
{
scenarioResult.SafetyFactor = profileResult.SafetyFactor;
}
scenarioResult.CalculationResult = CalculationResult.Succeeded;
}
}
if (scenarioResult.CalculationResult != CalculationResult.Succeeded)
{
// no succesful calculations found
scenarioResult.CalculationResult = scenarioResult.RegionalScenarioProfileResults[0].CalculationResult;
scenarioResult.SafetyFactor = scenarioResult.RegionalScenarioProfileResults[0].SafetyFactor;
}
}
private void CombineScenarios(RegionalScenariosResult scenariosResult)
{
// combine results of scenarios
scenariosResult.SafetyFactor = Double.MaxValue;
foreach (var scenarioResult in scenariosResult.RegionalScenarioResults)
{
if (scenarioResult.CalculationResult == CalculationResult.Succeeded)
{
if (scenarioResult.SafetyFactor < scenariosResult.SafetyFactor)
{
scenariosResult.SafetyFactor = scenarioResult.SafetyFactor;
}
scenariosResult.CalculationResult = CalculationResult.Succeeded;
}
}
}
}
}