// 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; } } } }