// Copyright (C) Stichting Deltares 2019. 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.Data;
using System.Linq;
using Deltares.DamEngine.Calculators.DikesDesign;
using Deltares.DamEngine.Calculators.KernelWrappers.Common;
using Deltares.DamEngine.Calculators.KernelWrappers.DamMacroStabilityCommon;
using Deltares.DamEngine.Calculators.KernelWrappers.Interfaces;
using Deltares.DamEngine.Calculators.KernelWrappers.MacroStabilityCommon;
using Deltares.DamEngine.Calculators.KernelWrappers.MacroStabilityCommon.MacroStabilityIo;
using Deltares.DamEngine.Calculators.Properties;
using Deltares.DamEngine.Data.Design;
using Deltares.DamEngine.Data.General;
using Deltares.DamEngine.Data.General.Results;
using Deltares.DamEngine.Data.Geotechnics;
using Deltares.DamEngine.Data.Standard;
using Deltares.DamEngine.Data.Standard.Calculation;
using Deltares.WTIStability.Calculation.Wrapper;
using ConversionHelper = Deltares.DamEngine.Calculators.KernelWrappers.MacroStabilityCommon.MacroStabilityIo.ConversionHelper;
using GeometryPoint = Deltares.DamEngine.Data.Geometry.GeometryPoint;
using LogMessage = Deltares.DamEngine.Data.Standard.Logging.LogMessage;
using LogMessageType = Deltares.DamEngine.Data.Standard.Logging.LogMessageType;
namespace Deltares.DamEngine.Calculators.KernelWrappers.MacroStabilityInwards
{
public class MacroStabilityInwardsKernelWrapper : IKernelWrapper
{
private WTIStabilityCalculation stabilityCalculator = null;
private int lastIterationIndex = 0;
///
/// Gets or sets the failure mechanisme paramaters for mstab.
///
///
/// The failure mechanisme paramaters mstab.
///
public FailureMechanismParametersMStab FailureMechanismParametersMStab { get; set; } //ToDo MWDAM-? Use same as for DGeoStability or create new one?
public bool tmpPresumePrepareSucceeds; //ToDo MWDAM-1356
public bool tmpPresumeInputValid; //ToDo MWDAM-1356
public bool tmpPresumeRunSucceeds; //ToDo MWDAM-1356
///
/// Prepares the specified dam kernel input.
///
/// The dam kernel input.
/// The number of the current iteration.
/// The kernel data input.
/// The kernel data output
///
/// Result of the prepare
///
public PrepareResult Prepare(DamKernelInput damKernelInput, int iterationIndex, out IKernelDataInput kernelDataInput, out IKernelDataOutput kernelDataOutput)
{
var macroStabilityInput = new MacroStabilityInput();
kernelDataInput = macroStabilityInput;
var macroStabilityOutput = new MacroStabilityOutput
{
CalculationResult = CalculationResult.NoRun
};
kernelDataOutput = macroStabilityOutput;
if (damKernelInput.SubSoilScenario.SegmentFailureMechanismType.Value.In(SegmentFailureMechanismType.Stability, SegmentFailureMechanismType.Stability))
{
try
{
// Determine whether there is uplift
UpliftSituation upliftSituation;
const bool useRivelLevelLow = false;
var upliftHelper = new UpliftHelper();
var plLines = upliftHelper.DeterminePlLinesForStability(damKernelInput, useRivelLevelLow, out upliftSituation);
upliftSituation.IsUplift = UpliftHelper.DetermineIsUplift(plLines, damKernelInput.Location, damKernelInput.SubSoilScenario);
macroStabilityOutput.UpliftSituation = upliftSituation;
if (upliftSituation.IsUplift)
{
// ToDo MWDAM-1356: Not clear yet what parts are required for input.
var left = 0.0;// ToDo MWDAM-1356: first point of surfaceline
var right = 100.0;// ToDo MWDAM-1356: last point of surfaceline
var penetrationLength = damKernelInput.Location.ModelParametersForPlLines.PenetrationLength;
var waternet = PlLinesToWaternetConverter.ConvertPlLineToWaternet(plLines, damKernelInput.SubSoilScenario.SoilProfile1D,
penetrationLength, left, right);
FillWtiKernelData fillWtiKernelData = new FillWtiKernelData()
{
SoilList = damKernelInput.Location.SoilList,
FailureMechanismParametersMStab = this.FailureMechanismParametersMStab,
Location = damKernelInput.Location,
// ToDo MWDAM-1373/1374: fill SoilProfile2D
// SoilProfile2D = expectedSoilProfile2D,
SurfaceLine2 = damKernelInput.Location.SurfaceLine,
Waternet = waternet,
// ToDo MWDAM-1399: add data for calculation grid Uplift Van
// UpliftVanCalculationGrid = expectedUpliftVanCalculationGrid
};
// ToDo MWDAM-1356: following line is not working yet, first all necessary input must be declared
//KernelModel expectedKernelModel = fillWtiKernelData.CreateKernelModel();
var xmlInput = CreateXmlInput(macroStabilityInput, FailureMechanismParametersMStab.EmbankmentDesignParameters);
return PrepareKernel(xmlInput);
}
return PrepareResult.NotRelevant;
}
catch
{
kernelDataOutput = macroStabilityOutput;
return PrepareResult.Failed;
}
}
kernelDataInput = null;
return PrepareResult.NotRelevant;
}
private PrepareResult PrepareKernel(string xmlInput)
{
ThrowWhenMacroStabilityCalculatorNull(stabilityCalculator);
try
{
// ToDo MWDAM-1356: Not clear yet what parts are required for input. Temporary test code added.
//macroStabilityCalculator.InitializeForDeterministic(xmlInput); //ToDo: uncomment when input is set
//return PrepareResult.Successful; //ToDo: uncomment when input is set
if (tmpPresumePrepareSucceeds) //ToDo: remove the temporary test code when input is set
{
return PrepareResult.Successful;
}
else
{
return PrepareResult.Failed;
}
}
catch
{
return PrepareResult.Failed;
}
}
private string CreateXmlInput(MacroStabilityInput macroStabilityInput, EmbankmentDesignParameters embankmentDesignParameters)
{
string xmlInput = "";
//ToDo in MWDAM-1356
return xmlInput;
}
///
/// Validates the specified kernel data input.
///
/// The kernel data input.
/// The kernel data output.
/// The return messages.
///
/// Zero when there are no errors, one when there are errors that prevent a calculation
///
public int Validate(IKernelDataInput kernelDataInput, IKernelDataOutput kernelDataOutput, out List messages)
{
ThrowWhenMacroStabilityCalculatorNull(stabilityCalculator);
if (tmpPresumeInputValid)
{
messages = new List();
return 0;
}
else
{
messages = new List();
messages.Add(new LogMessage(LogMessageType.Error, null, "Not implemented yet"));
// Todo MWDAM-1356 : make valid XML, only then following lines can be enabled
// string kernelMessage = macroStabilityCalculator.Validate();
// ParseValidationResult(kernelMessage, out messages);
MacroStabilityOutput macroStabilityOutput = (MacroStabilityOutput)kernelDataOutput;
var numberOfErrors = messages.Count(mt => mt.MessageType == LogMessageType.Error);
if (numberOfErrors > 0)
{
macroStabilityOutput.CalculationResult = CalculationResult.InvalidInputData;
}
return numberOfErrors;
}
}
internal void ParseValidationResult(string xmlValidationResult, out List messages)
{
messages = new List();
var validationResults = WtiDeserializer.DeserializeValidation(xmlValidationResult);
foreach (var result in validationResults)
{
messages.Add(new LogMessage
{
Message = result.Text,
MessageType = ConversionHelper.ConvertKernelValidationResultTypeToLogMessageType(result.MessageType)
});
}
}
///
/// Executes the kernel.
///
/// The kernel data input.
/// The kernel data output.
/// The return messages.
public void Execute(IKernelDataInput kernelDataInput, IKernelDataOutput kernelDataOutput, out List messages)
{
MacroStabilityInput macroStabilityInput = (MacroStabilityInput)kernelDataInput;
MacroStabilityOutput macroStabilityOutput = (MacroStabilityOutput)kernelDataOutput;
ThrowWhenMacroStabilityKernelInputNull(macroStabilityInput);
ThrowWhenMacroStabilityKernelOutputNull(macroStabilityOutput);
messages = new List();
PerformStabilityCalculation(out messages, macroStabilityOutput, macroStabilityInput);
}
private void PerformStabilityCalculation(out List messages, MacroStabilityOutput macroStabilityOutput,
MacroStabilityInput macroStabilityInput)
{
ThrowWhenMacroStabilityCalculatorNull(stabilityCalculator);
macroStabilityOutput.CalculationResult = CalculationResult.NoRun;
macroStabilityOutput.StabilityOutputItems = new List();
messages = new List();
//this must be code when prepare is done
// try
// {
// string kernelMessage = macroStabilityCalculator.Run();
// ParseRunResult(kernelMessage, macroStabilityOutput, messages);
// macroStabilityOutput.CalculationResult = CalculationResult.Succeeded;
// }
// catch (Exception e)
// {
// macroStabilityOutput.CalculationResult = CalculationResult.UnexpectedError;
// messages.Add(new LogMessage(LogMessageType.Error, null, e.Message));
// }
// ToDo MWDAM-1356: setting input is not done yet. Temporary test code added.
// start of temporary test code
if (tmpPresumeRunSucceeds)
{
//presume run succeeded
MacroStabilityOutputItem macroStabilityOutputItem = new MacroStabilityOutputItem();
macroStabilityOutputItem.CalculationResult = CalculationResult.Succeeded;
macroStabilityOutputItem.SafetyFactor = 1.357;
macroStabilityOutput.CalculationResult = macroStabilityOutputItem.CalculationResult;
macroStabilityOutput.StabilityOutputItems.Add(macroStabilityOutputItem);
}
else
{
//presume run failed
macroStabilityOutput.CalculationResult = CalculationResult.RunFailed;
messages.Add(new LogMessage(LogMessageType.Error, null, "run failed"));
}
// end of temporary test code
}
internal void ParseRunResult(string xmlRunResult, out MacroStabilityOutputItem macroStabilityOutputItem, out List messages)
{
messages = new List();
macroStabilityOutputItem = new MacroStabilityOutputItem();
var calculationResults = WtiDeserializer.DeserializeResult(xmlRunResult);
var slicesCount = calculationResults.Curve.Slices.Count;
if (slicesCount > 0)
{
calculationResults.XMinEntry = calculationResults.Curve.Slices[0].TopLeftX;
calculationResults.XMaxEntry = calculationResults.Curve.Slices[slicesCount - 1].TopRightX;
}
else
{
macroStabilityOutputItem.CalculationResult = CalculationResult.UnexpectedError;
}
macroStabilityOutputItem.CalculationResult = calculationResults.Calculated ?
CalculationResult.Succeeded : CalculationResult.RunFailed;
macroStabilityOutputItem.SafetyFactor = calculationResults.FactorOfSafety;
macroStabilityOutputItem.CircleSurfacePointLeftXCoordinate = calculationResults.XMinEntry;
macroStabilityOutputItem.CircleSurfacePointRightXCoordinate = calculationResults.XMaxEntry;
macroStabilityOutputItem.StabilityModelType = ConversionHelper.ConvertToMStabModelType(calculationResults.ModelOption);
foreach (var message in calculationResults.Messages)
{
messages.Add(new LogMessage
{
Message = message.Message,
MessageType = ConversionHelper.ConvertKernelLogMessageTypeToLogMessageType(message.MessageType)
});
}
}
///
/// Creates the calculator for stability based on kernel input.
///
public void CreateStabilityCalculator()
{
stabilityCalculator = new WTIStabilityCalculation();
}
///
/// Fills the design results with the kernel output.
///
/// The dam kernel input.
/// The kernel data output.
/// The design scenario.
/// The result message.
/// The design results.
///
public void PostProcess(DamKernelInput damKernelInput, IKernelDataOutput kernelDataOutput, DesignScenario designScenario,
string resultMessage, out List designResults)
{
ThrowWhenMacroStabilityDamKernelInputNull(damKernelInput);
MacroStabilityOutput macroStabilityOutput = kernelDataOutput as MacroStabilityOutput;
ThrowWhenMacroStabilityKernelOutputNull(macroStabilityOutput);
designResults = new List();
if (macroStabilityOutput.StabilityOutputItems.Count > 0)
{
var macroStabilityOutputItem = macroStabilityOutput.StabilityOutputItems[0];
if (macroStabilityOutputItem != null)
{
var designResult = NewDesignResult(damKernelInput, designScenario, macroStabilityOutputItem);
FillDesignResult(macroStabilityOutputItem, designResult);
designResult.StabilityDesignResults.NumberOfIterations = lastIterationIndex;
designResult.StabilityDesignResults.UpliftSituation = macroStabilityOutput.UpliftSituation;
designResults.Add(designResult);
}
}
}
private DesignResult NewDesignResult(DamKernelInput damKernelInput, DesignScenario designScenario,
MacroStabilityOutputItem macroStabilityOutputItem)
{
string soilProfile2DName = damKernelInput.SubSoilScenario.ToString();
var designResult = new DesignResult(damKernelInput.DamFailureMechanismeCalculationSpecification,
designScenario, damKernelInput.SubSoilScenario.SoilProfile1D, soilProfile2DName)
{
// initialize as failed
CalculationResult = CalculationResult.RunFailed
};
designResult.StabilityDesignResults = new StabilityDesignResults();
var stabilityDesignResults = new StabilityDesignResults();
stabilityDesignResults.RedesignedSurfaceLine = damKernelInput.Location.SurfaceLine;
designResult.ProfileName = soilProfile2DName;
designResult.StabilityDesignResults = stabilityDesignResults;
return designResult;
}
private static void FillDesignResult(MacroStabilityOutputItem macroStabilityOutputItem, DesignResult designResult)
{
designResult.CalculationResult = macroStabilityOutputItem.CalculationResult;
designResult.StabilityDesignResults.StabilityModelType = macroStabilityOutputItem.StabilityModelType;
if (designResult.CalculationResult == CalculationResult.Succeeded)
{
designResult.StabilityDesignResults.SafetyFactor = macroStabilityOutputItem.SafetyFactor;
}
}
///
/// Throws the when macro stability kernel input is not assigned.
///
/// The dam macro stability input.
///
public static void ThrowWhenMacroStabilityKernelInputNull(MacroStabilityInput macroStabilityInput)
{
if (macroStabilityInput == null)
{
throw new NoNullAllowedException(Resources.MacroStabilityKernelWrapper_NoMacroStabilityInputObjectDefined);
}
}
///
/// Throws the when macro stability kernel output is not assigned.
///
/// The dam macro stability output.
///
public static void ThrowWhenMacroStabilityKernelOutputNull(MacroStabilityOutput macroStabilityOutput)
{
if (macroStabilityOutput == null)
{
throw new NoNullAllowedException(Resources.MacroStabilityKernelWrapper_NoMacroStabilityOutputObjectDefined);
}
}
///
/// Throws the when macro stability dam kernel input is not assigned.
///
/// The dam kernel input.
///
public static void ThrowWhenMacroStabilityDamKernelInputNull(DamKernelInput damKernelInput)
{
if (damKernelInput == null)
{
throw new NoNullAllowedException(Resources.MacroStabilityKernelWrapper_NoDamInputObjectDefinedForMacroStability);
}
}
///
/// Throws the when macro stability calculator is not assigned.
///
/// The macro stability calculator.
///
public static void ThrowWhenMacroStabilityCalculatorNull(WTIStabilityCalculation macroStabilityCalculator)
{
if (macroStabilityCalculator == null)
{
throw new NoNullAllowedException(Resources.MacroStabilityKernelWrapper_NoDamKernelObjectDefinedForMacroStability);
}
}
///
/// Calculates the design at point.
///
/// The dam kernel input.
/// The kernel data input.
/// The kernel data output.
/// The point.
/// The messages.
///
///
public ShoulderDesign CalculateDesignAtPoint(DamKernelInput damKernelInput, IKernelDataInput kernelDataInput,
IKernelDataOutput kernelDataOutput, GeometryPoint point, out List messages)
{
// ToDo: Not clear yet if this must be done or how
throw new NotImplementedException();
}
///
/// Evaluates the design (current factor greater than desired factor)
///
/// The dam kernel input.
/// The kernel data input.
/// The kernel data output.
/// The design advise.
/// The evaluation message.
///
/// if the design was succesful
///
///
public bool EvaluateDesign(DamKernelInput damKernelInput, IKernelDataInput kernelDataInput, IKernelDataOutput kernelDataOutput,
out DesignAdvise designAdvise, out string evaluationMessage)
{
MacroStabilityInput macroStabilityInput = kernelDataInput as MacroStabilityInput;
MacroStabilityOutput macroStabilityOutput = kernelDataOutput as MacroStabilityOutput;
ThrowWhenMacroStabilityKernelInputNull(macroStabilityInput);
ThrowWhenMacroStabilityKernelOutputNull(macroStabilityOutput);
ThrowWhenMacroStabilityDamKernelInputNull(damKernelInput);
double fosRequired = damKernelInput.Location.ModelFactors.RequiredSafetyFactorStabilityInnerSlope;
double fosAchieved = macroStabilityOutput.StabilityOutputItems[0].SafetyFactor;
double exitPointXCoordinate = macroStabilityOutput.StabilityOutputItems[0].CircleSurfacePointRightXCoordinate;
GeometryPoint limitPointForShoulderDesign = damKernelInput.Location.SurfaceLine.GetLimitPointForShoulderDesign();
evaluationMessage = String.Format(Resources.FactorAchievedVsFactorRequired, fosAchieved, fosRequired);
if (exitPointXCoordinate > limitPointForShoulderDesign.X)
{
designAdvise = DesignAdvise.ShoulderInwards;
}
else
{
designAdvise = DesignAdvise.SlopeInwards;
}
bool isDesignReady = fosAchieved >= fosRequired;
if (isDesignReady)
{
designAdvise = DesignAdvise.None;
}
return isDesignReady;
}
///
/// Prepares the design.
///
/// The kernel data input.
/// The kernel data output.
/// The dam kernel input.
/// Index of the iteration.
/// The embankment design parameters.
public void PrepareDesign(IKernelDataInput kernelDataInput, IKernelDataOutput kernelDataOutput, DamKernelInput damKernelInput,
int iterationIndex, out EmbankmentDesignParameters embankmentDesignParameters)
{
MacroStabilityInput macroStabilityInput = kernelDataInput as MacroStabilityInput;
ThrowWhenMacroStabilityKernelInputNull(macroStabilityInput);
lastIterationIndex = iterationIndex;
var location = damKernelInput.Location;
//ToDo MWDAM-1356: Not clear yet what parts are required for input. subSoilScenario, riverLevel and others might be necessary for CreateXmlInput
//MStabModelType model = MStabModelType.UpliftVan;
//var subSoilScenario = damKernelInput.SubSoilScenario;
//double riverLevel = damKernelInput.RiverLevelHigh;
EmbankmentDesignParameters embankmentDesignParametersForKernelInput;
if (iterationIndex < 1)
{
// This is the first (initial) call to prepareDesign.
// The embankment material is set to DikeEmbankmentMaterial, because the next iteration (Index = 1) will be height adaption
embankmentDesignParameters = new EmbankmentDesignParameters()
{
EmbankmentMaterialname = location.DikeEmbankmentMaterial,
};
//ToDo MWDAM-? Use FailureMechanismParametersMStab or create new one?
FailureMechanismParametersMStab.EmbankmentDesignParameters = embankmentDesignParameters;
embankmentDesignParametersForKernelInput = null;
}
else
{
// Calculation iterations start with IterationIndex = 1.
// When IterationIndex = 1: height adaption.
// When Iteration > 1: Slope/Shoulder adaption.
// Starting from IterationIndex 2 the following parameters should be used:
// - The embankment material is set to ShoulderEmbankmentMaterial.
// - The previous geometry is set to the height adapted geometry (name is constructed with iteration index 1).
if (iterationIndex == 2)
{
FailureMechanismParametersMStab.EmbankmentDesignParameters.EmbankmentMaterialname = location.ShoulderEmbankmentMaterial;
}
// In the following prepareDesign calls just return the stored embankmentDesignParameters
embankmentDesignParameters = FailureMechanismParametersMStab.EmbankmentDesignParameters;
embankmentDesignParametersForKernelInput = embankmentDesignParameters;
}
var xmlInput = CreateXmlInput(macroStabilityInput, embankmentDesignParametersForKernelInput);
var prepareResult = PrepareKernel(xmlInput);
if (prepareResult != PrepareResult.Successful)
{
throw new MacroStabilityException(Resources.MacroStabilityKernelWrapper_PrepareForMacroStabilityDidNotSucceed);
}
}
///
/// Gets the design strategy
///
///
///
public DesignStrategy GetDesignStrategy(DamKernelInput damKernelInput)
{
switch (damKernelInput.Location.StabilityDesignMethod)
{
case StabilityDesignMethod.OptimizedSlopeAndShoulderAdaption:
return DesignStrategy.OptimizedSlopeAndShoulderAdaption;
case StabilityDesignMethod.SlopeAdaptionBeforeShoulderAdaption:
return DesignStrategy.SlopeAdaptionBeforeShoulderAdaption;
default:
return DesignStrategy.NoDesignPossible;
}
}
}
}