// 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.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.MacroStability.CSharpWrapper;
using Deltares.MacroStability.CSharpWrapper.Output;
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 Calculator stabilityCalculator;
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 MacroStabilityKernelDataInput();
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 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);
TrafficLoad trafficLoad = null;
if (damKernelInput.Location.StabilityOptions.TrafficLoad.HasValue)
{
trafficLoad = new TrafficLoad();
trafficLoad.Pressure = damKernelInput.Location.StabilityOptions.TrafficLoad.Value;
trafficLoad.XStart = damKernelInput.Location.SurfaceLine
.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.TrafficLoadInside).X;
trafficLoad.XEnd = damKernelInput.Location.SurfaceLine
.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.TrafficLoadOutside).X;
}
FillMacroStabilityWrapperInputFromEngine fillMacroStabilityWrapperFromEngine = new FillMacroStabilityWrapperInputFromEngine()
{
TrafficLoad = trafficLoad
// ToDo MWDAM-1373/1374: fill SoilProfile2D
// ToDo MWDAM-1399: add data for calculation grid Uplift Van, connect it to actual engine input
};
macroStabilityInput.Input = fillMacroStabilityWrapperFromEngine.CreateMacroStabilityInput(damKernelInput, FailureMechanismParametersMStab, waternet);
// KernelModel expectedKernelModel = fillMacroStabilityWrapperFromEngine.CreateKernelModel();
// expectedKernelModel.
// var xmlInput = CreateXmlInput(macroStabilityInput, FailureMechanismParametersMStab.EmbankmentDesignParameters);
return PrepareKernel(macroStabilityInput.Input);
}
return PrepareResult.NotRelevant;
}
catch
{
kernelDataOutput = macroStabilityOutput;
return PrepareResult.Failed;
}
}
kernelDataInput = null;
return PrepareResult.NotRelevant;
}
private PrepareResult PrepareKernel(MacroStability.CSharpWrapper.Input.MacroStabilityInput input)
{
try
{
stabilityCalculator = new Calculator(input);
// For now a simple check to see if any data has been past at all.
var inputAsXml = stabilityCalculator.KernelInputXml;
if (inputAsXml.Length > 10)
{
return PrepareResult.Successful;
}
else
{
return PrepareResult.Failed;
}
}
catch
{
return PrepareResult.Failed;
}
}
///
/// 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)
{
// Todo implement validation as soon as it has been implemented in the C# wrapper.
messages = new List();
return 0;
}
///
/// Executes the kernel.
///
/// The kernel data input.
/// The kernel data output.
/// The return messages.
public void Execute(IKernelDataInput kernelDataInput, IKernelDataOutput kernelDataOutput, out List messages)
{
MacroStabilityKernelDataInput macroStabilityKernelDataInput = (MacroStabilityKernelDataInput)kernelDataInput;
MacroStabilityOutput macroStabilityOutput = (MacroStabilityOutput)kernelDataOutput;
ThrowWhenMacroStabilityKernelInputNull(macroStabilityKernelDataInput);
ThrowWhenMacroStabilityKernelOutputNull(macroStabilityOutput);
messages = new List();
PerformStabilityCalculation(out messages, macroStabilityOutput, macroStabilityKernelDataInput);
}
private void PerformStabilityCalculation(out List messages, MacroStabilityOutput macroStabilityOutput,
MacroStabilityKernelDataInput macroStabilityKernelDataInput)
{
macroStabilityOutput.CalculationResult = CalculationResult.NoRun;
macroStabilityOutput.StabilityOutputItems = new List();
messages = new List();
try
{
var macroStabilityOutputKernel = stabilityCalculator.Calculate();
ParseRunResult(macroStabilityOutputKernel, out var macroStabilityOutputItem, out messages);
macroStabilityOutput.StabilityOutputItems.Add(macroStabilityOutputItem);
macroStabilityOutput.CalculationResult = CalculationResult.Succeeded;
}
catch (Exception e)
{
macroStabilityOutput.CalculationResult = CalculationResult.UnexpectedError;
messages.Add(new LogMessage(LogMessageType.Error, null, e.Message));
}
}
internal void ParseRunResult(MacroStability.CSharpWrapper.Output.MacroStabilityOutput runResult, out MacroStabilityOutputItem macroStabilityOutputItem, out List messages)
{
messages = new List();
macroStabilityOutputItem = new MacroStabilityOutputItem();
macroStabilityOutputItem.SafetyFactor = runResult.StabilityOutput.SafetyFactor;
if (runResult.ResultType == CalculationResultType.Succeeded)
{
macroStabilityOutputItem.CalculationResult = CalculationResult.Succeeded;
macroStabilityOutputItem.StabilityModelType =
ConversionHelper.ConvertToMStabModelTypeFromOutput(runResult.StabilityOutput.ModelOptionType);
// macroStabilityOutputItem.CircleSurfacePointLeftXCoordinate =
// runResult.StabilityOutput.MinimumSafetyCurve.Slices.First().TopLeftPoint.X;
// macroStabilityOutputItem.CircleSurfacePointRightXCoordinate =
// runResult.StabilityOutput.MinimumSafetyCurve.Slices.Last().TopRightPoint.X;
}
else
{
macroStabilityOutputItem.CalculationResult = ConversionHelper.ConvertToDamResultType(runResult.ResultType);
}
if (runResult.StabilityOutput.Messages != null)
{
foreach (var message in runResult.StabilityOutput.Messages)
{
messages.Add(new LogMessage
{
Message = message.Content,
MessageType = ConversionHelper.ConvertKernelLogMessageTypeToLogMessageType(message.MessageType)
});
}
}
}
///
/// Creates the calculator for stability based on kernel input.
///
public void CreateStabilityCalculator()
{
//Calculator.Calculate();
}
///
/// 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(MacroStabilityKernelDataInput macroStabilityKernelDataInput)
{
if (macroStabilityKernelDataInput == 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);
}
}
///
/// 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)
{
MacroStabilityKernelDataInput macroStabilityKernelDataInput = kernelDataInput as MacroStabilityKernelDataInput;
MacroStabilityOutput macroStabilityOutput = kernelDataOutput as MacroStabilityOutput;
ThrowWhenMacroStabilityKernelInputNull(macroStabilityKernelDataInput);
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)
{
MacroStabilityKernelDataInput macroStabilityKernelDataInput = kernelDataInput as MacroStabilityKernelDataInput;
ThrowWhenMacroStabilityKernelInputNull(macroStabilityKernelDataInput);
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(macroStabilityKernelDataInput, 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;
}
}
}
}