// Copyright (C) Stichting Deltares 2024. 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.IO; 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.PlLines; using Deltares.DamEngine.Data.General.Results; using Deltares.DamEngine.Data.Geometry; using Deltares.DamEngine.Data.Geotechnics; using Deltares.DamEngine.Data.Standard; using Deltares.DamEngine.Data.Standard.Calculation; using Deltares.DamEngine.Data.Standard.Logging; using Deltares.MacroStability.CSharpWrapper; using Deltares.MacroStability.CSharpWrapper.Output; using Point2D = Deltares.DamEngine.Data.Geometry.Point2D; using UpliftVanCalculationGrid = Deltares.DamEngine.Calculators.KernelWrappers.MacroStabilityCommon.UpliftVanCalculationGrid; namespace Deltares.DamEngine.Calculators.KernelWrappers.MacroStabilityInwards; public class MacroStabilityInwardsKernelWrapper : IKernelWrapper { private readonly MacroStabilityCommonHelper macroStabilityCommonHelper; private Calculator stabilityCalculator; private Calculator stabilityCalculatorForSecondCalculation; private string fileNameForCalculation; private string fileNameForSecondCalculation; private int lastIterationIndex; /// /// Initializes a new instance of the class. /// public MacroStabilityInwardsKernelWrapper() { macroStabilityCommonHelper = new MacroStabilityCommonHelper(); } /// /// Gets or sets the failure mechanism parameters for MStab. /// /// /// The failure mechanism parameters MStab. /// public FailureMechanismParametersMStab FailureMechanismParametersMStab { get; set; } /// /// 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 preparation /// public PrepareResult Prepare(DamKernelInput damKernelInput, int iterationIndex, out IKernelDataInput kernelDataInput, out IKernelDataOutput kernelDataOutput) { fileNameForCalculation = ""; fileNameForSecondCalculation = ""; var macroStabilityInput = new MacroStabilityKernelDataInput(); kernelDataInput = macroStabilityInput; var macroStabilityOutput = new MacroStabilityOutput { CalculationResult = CalculationResult.NoRun }; kernelDataOutput = macroStabilityOutput; if (damKernelInput.SubSoilScenario.SegmentFailureMechanismType != null && damKernelInput.SubSoilScenario.SegmentFailureMechanismType.Value.In(SegmentFailureMechanismType.Stability, SegmentFailureMechanismType.All)) { try { bool isBishopUpliftVan = FailureMechanismParametersMStab.MStabParameters.Model == StabilityModelType.BishopUpliftVan; StabilityModelType model = FailureMechanismParametersMStab.MStabParameters.Model; if (isBishopUpliftVan) { // if current model is BishopUpliftVan then set to Bishop for proper name/path for input file model = StabilityModelType.Bishop; } if (damKernelInput.OriginalSoilProfile2D != null) { // Clone the original soil profile for design iterations damKernelInput.SubSoilScenario.SoilProfile2D = damKernelInput.OriginalSoilProfile2D.Clone(); } MacroStabilityCommonHelper.CombineSoilProfileWithSurfaceLine(damKernelInput.SubSoilScenario, damKernelInput.Location.SurfaceLine, damKernelInput.CurrentEmbankmentSoil); if ((damKernelInput.OriginalSoilProfile2D == null) && (damKernelInput.SubSoilScenario.SoilProfileType == SoilProfileType.ProfileType2D)) { // Clone the newly created 2D profile the original soil profile for design iterations damKernelInput.OriginalSoilProfile2D = damKernelInput.SubSoilScenario.SoilProfile2D.Clone(); } const bool useRiverLevelLow = false; // Determine whether there is uplift var upliftHelper = new UpliftHelper(); PlLines plLines = upliftHelper.DeterminePlLinesForStability(damKernelInput, useRiverLevelLow, out UpliftSituation upliftSituation); macroStabilityOutput.UpliftSituation = upliftSituation; Waternet waterNet = MacroStabilityCommonHelper.CreateWaternet(damKernelInput, plLines); var fillMacroStabilityWrapperFromEngine = new FillMacroStabilityWrapperInputFromEngine { TrafficLoad = MacroStabilityCommonHelper.FillTrafficLoad(damKernelInput) }; if (FailureMechanismParametersMStab.MStabParameters.Model == StabilityModelType.Bishop || FailureMechanismParametersMStab.MStabParameters.Model == StabilityModelType.BishopUpliftVan) { fillMacroStabilityWrapperFromEngine.BishopCalculationGrid = MacroStabilityCommonHelper.FillBishopCalculationGrid(damKernelInput); } if (FailureMechanismParametersMStab.MStabParameters.Model == StabilityModelType.UpliftVan || FailureMechanismParametersMStab.MStabParameters.Model == StabilityModelType.BishopUpliftVan) { if (!upliftSituation.IsUplift && !isBishopUpliftVan) { return PrepareResult.NotRelevant; } fillMacroStabilityWrapperFromEngine.UpliftVanCalculationGrid = FillUpliftVanCalculationGrid(damKernelInput, upliftSituation.XCoordinateLowestUpliftFactorPoint); } FailureMechanismParametersMStab.MStabParameters.Model = model; macroStabilityInput.Input = fillMacroStabilityWrapperFromEngine.CreateMacroStabilityInput(damKernelInput, FailureMechanismParametersMStab.MStabParameters, waterNet); fileNameForCalculation = MacroStabilityCommonHelper.GetStabilityInputFileName(damKernelInput, iterationIndex, FailureMechanismParametersMStab.MStabParameters.Model); stabilityCalculator = new Calculator(macroStabilityInput.Input); PrepareResult firstPrepareResult = MacroStabilityCommonHelper.PrepareKernel(stabilityCalculator, fileNameForCalculation); if (isBishopUpliftVan && upliftSituation.IsUplift && firstPrepareResult == PrepareResult.Successful) { model = StabilityModelType.UpliftVan; FailureMechanismParametersMStab.MStabParameters.Model = model; //C#wrapper hier vervangen door MAC direct macroStabilityInput.Input = fillMacroStabilityWrapperFromEngine.CreateMacroStabilityInput(damKernelInput, FailureMechanismParametersMStab.MStabParameters, waterNet); fileNameForSecondCalculation = MacroStabilityCommonHelper.GetStabilityInputFileName(damKernelInput, iterationIndex, FailureMechanismParametersMStab.MStabParameters.Model); // reset model FailureMechanismParametersMStab.MStabParameters.Model = StabilityModelType.BishopUpliftVan; stabilityCalculatorForSecondCalculation = new Calculator(macroStabilityInput.Input); return MacroStabilityCommonHelper.PrepareKernel(stabilityCalculatorForSecondCalculation, fileNameForSecondCalculation); } if (isBishopUpliftVan) { // reset model FailureMechanismParametersMStab.MStabParameters.Model = StabilityModelType.BishopUpliftVan; } return firstPrepareResult; } catch (Exception e) { macroStabilityOutput.Message = new LogMessage { MessageType = LogMessageType.FatalError, Message = e.Message }; kernelDataOutput = macroStabilityOutput; return PrepareResult.Failed; } } kernelDataInput = null; return PrepareResult.NotRelevant; } /// /// 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) { return macroStabilityCommonHelper.Validate(kernelDataInput, kernelDataOutput, out messages); } /// /// Executes the kernel. /// /// The kernel data input. /// The kernel data output. /// The return messages. public void Execute(IKernelDataInput kernelDataInput, IKernelDataOutput kernelDataOutput, out List messages) { var macroStabilityKernelDataInput = (MacroStabilityKernelDataInput) kernelDataInput; var macroStabilityOutput = (MacroStabilityOutput) kernelDataOutput; MacroStabilityCommonHelper.ThrowWhenMacroStabilityKernelInputNull(macroStabilityKernelDataInput); MacroStabilityCommonHelper.ThrowWhenMacroStabilityKernelOutputNull(macroStabilityOutput); bool isBishopUpliftVan = FailureMechanismParametersMStab.MStabParameters.Model == StabilityModelType.BishopUpliftVan; if (isBishopUpliftVan) { macroStabilityKernelDataInput.Input.StabilityModel.ModelOption = StabilityModelOptionType.Bishop; } macroStabilityCommonHelper.PerformStabilityCalculation(macroStabilityKernelDataInput.Input, macroStabilityOutput, fileNameForCalculation, stabilityCalculator, out messages); string fileName = Path.GetFileNameWithoutExtension(fileNameForCalculation); foreach (LogMessage logMessage in messages) { logMessage.Message = fileName + ": " + logMessage.Message; } if (isBishopUpliftVan && macroStabilityOutput.UpliftSituation.IsUplift) { macroStabilityKernelDataInput.Input.StabilityModel.ModelOption = StabilityModelOptionType.UpliftVan; macroStabilityCommonHelper.PerformStabilityCalculation(macroStabilityKernelDataInput.Input, macroStabilityOutput, fileNameForSecondCalculation, stabilityCalculatorForSecondCalculation, out messages); fileName = Path.GetFileNameWithoutExtension(fileNameForSecondCalculation); foreach (LogMessage logMessage in messages) { logMessage.Message = fileName + ": " + logMessage.Message; } } } /// /// 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) { MacroStabilityCommonHelper.ThrowWhenMacroStabilityDamKernelInputNull(damKernelInput); var macroStabilityOutput = kernelDataOutput as MacroStabilityOutput; MacroStabilityCommonHelper.ThrowWhenMacroStabilityKernelOutputNull(macroStabilityOutput); if (designScenario.CalculationResult == CalculationResult.Succeeded) { designScenario.CalculationResult = macroStabilityOutput!.CalculationResult; } designResults = new List(); MacroStabilityOutputItem macroStabilityOutputItem = ProperMacroStabilityResultsItem(macroStabilityOutput, 0); AddDesignResult(damKernelInput, designScenario, designResults, macroStabilityOutputItem, macroStabilityOutput); bool isBishopUpliftVan = FailureMechanismParametersMStab.MStabParameters.Model == StabilityModelType.BishopUpliftVan; if (isBishopUpliftVan) { macroStabilityOutputItem = ProperMacroStabilityResultsItem(macroStabilityOutput, 1); AddDesignResult(damKernelInput, designScenario, designResults, macroStabilityOutputItem, macroStabilityOutput); // If no uplift therefore no UpliftVan calculation was made. So add a fictive (empty) design result. if (macroStabilityOutputItem == null && !macroStabilityOutput!.UpliftSituation.IsUplift) { AddDesignResultNoRun(damKernelInput, designScenario, designResults, macroStabilityOutput); } // Now add the overall result for Bishop/UpliftVan only if both results are available. if (designResults.Count == 2) { int index; // add worst result from Bishop/UpliftVan, but only if both succeeded. if (designResults[0].CalculationResult == CalculationResult.Succeeded && designResults[1].CalculationResult == CalculationResult.Succeeded) { index = designResults[0].StabilityDesignResults.SafetyFactor <= designResults[1].StabilityDesignResults.SafetyFactor ? 0 : 1; } else if (designResults[0].CalculationResult != CalculationResult.Succeeded) { // There is no reason why Bishop should not have succeeded therefore no end results can be given index = 0; } else if (designResults[1].CalculationResult == CalculationResult.NoRun) { // No uplift therefore no UpliftVan calculation was made. Present Bishop result. index = 0; } else { // UpliftVan calculation failed. No end results can be given index = 1; } macroStabilityOutputItem = ProperMacroStabilityResultsItem(macroStabilityOutput, index); DesignResult overallResult = MacroStabilityCommonHelper.NewDesignResult(damKernelInput, designScenario); MacroStabilityCommonHelper.FillDesignResult(macroStabilityOutputItem, overallResult, lastIterationIndex); overallResult.StabilityDesignResults.UpliftSituation = macroStabilityOutput!.UpliftSituation; overallResult.StabilityDesignResults.StabilityModelType = StabilityModelType.BishopUpliftVan; if (macroStabilityOutputItem.CalculationResult != CalculationResult.Succeeded) { SoilGeometryProbability subSoilScenario = damKernelInput.SubSoilScenario; overallResult.StabilityDesignResults.ResultMessage = designScenario.GetResultMessage(subSoilScenario.SoilProfile1D, subSoilScenario.SoilProfile2D); } designResults.Add(overallResult); } // If not both Bishop and Uplift-Van results are available, this is unexpected. else { DesignResult overallResult = MacroStabilityCommonHelper.NewDesignResult(damKernelInput, designScenario); overallResult.StabilityDesignResults.StabilityModelType = StabilityModelType.BishopUpliftVan; overallResult.CalculationResult = CalculationResult.UnexpectedError; SoilGeometryProbability subSoilScenario = damKernelInput.SubSoilScenario; overallResult.StabilityDesignResults.ResultMessage = designScenario.GetResultMessage(subSoilScenario.SoilProfile1D, subSoilScenario.SoilProfile2D); designResults.Add(overallResult); } } } /// /// 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, Point2D 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 successful /// /// public bool EvaluateDesign(DamKernelInput damKernelInput, IKernelDataInput kernelDataInput, IKernelDataOutput kernelDataOutput, out DesignAdvise designAdvise, out string evaluationMessage) { var macroStabilityKernelDataInput = kernelDataInput as MacroStabilityKernelDataInput; var macroStabilityOutput = kernelDataOutput as MacroStabilityOutput; MacroStabilityCommonHelper.ThrowWhenMacroStabilityKernelInputNull(macroStabilityKernelDataInput); MacroStabilityCommonHelper.ThrowWhenMacroStabilityKernelOutputNull(macroStabilityOutput); MacroStabilityCommonHelper.ThrowWhenMacroStabilityDamKernelInputNull(damKernelInput); double fosRequired = damKernelInput.Location.CurrentScenario.RequiredSafetyFactorStabilityInnerSlope; if (macroStabilityOutput != null) { MacroStabilityOutputItem leadingStabilityOutputItem = DetemineLeadingOutputItem(macroStabilityOutput.StabilityOutputItems); // Abort if calculation failed if ((leadingStabilityOutputItem == null) || (leadingStabilityOutputItem.CalculationResult != CalculationResult.Succeeded)) { designAdvise = DesignAdvise.Abort; evaluationMessage = "Stability calculation failed."; return true; } // Check if the factor of safety is achieved double fosAchieved = leadingStabilityOutputItem.SafetyFactor; double exitPointXCoordinate = leadingStabilityOutputItem.CircleSurfacePointRightXCoordinate; Point2D 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; } designAdvise = DesignAdvise.None; evaluationMessage = "No Output"; return false; } /// /// 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) { var macroStabilityKernelDataInput = kernelDataInput as MacroStabilityKernelDataInput; MacroStabilityCommonHelper.ThrowWhenMacroStabilityKernelInputNull(macroStabilityKernelDataInput); lastIterationIndex = iterationIndex; Location location = damKernelInput.Location; 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 }; FailureMechanismParametersMStab.EmbankmentDesignParameters = embankmentDesignParameters; } 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; } } /// /// 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; } } private static void AddDesignResultNoRun(DamKernelInput damKernelInput, DesignScenario designScenario, List designResults, MacroStabilityOutput macroStabilityOutput) { DesignResult designResultUpliftNoRun = MacroStabilityCommonHelper.NewDesignResult(damKernelInput, designScenario); designResultUpliftNoRun.StabilityDesignResults.StabilityModelType = StabilityModelType.UpliftVan; designResultUpliftNoRun.CalculationResult = CalculationResult.NoRun; designResultUpliftNoRun.SafetyFactor = null; designResultUpliftNoRun.StabilityDesignResults.UpliftSituation = macroStabilityOutput.UpliftSituation; designResultUpliftNoRun.CalculationSubDir = designResults.Count == 1 ? designResults[0].CalculationSubDir.Replace(StabilityModelType.Bishop.ToString(), StabilityModelType.UpliftVan.ToString()) : ""; designResults.Add(designResultUpliftNoRun); } private void AddDesignResult(DamKernelInput damKernelInput, DesignScenario designScenario, List designResults, MacroStabilityOutputItem macroStabilityOutputItem, MacroStabilityOutput macroStabilityOutput) { if (macroStabilityOutputItem != null) { DesignResult designResult = MacroStabilityCommonHelper.NewDesignResult(damKernelInput, designScenario); MacroStabilityCommonHelper.FillDesignResult(macroStabilityOutputItem, designResult, lastIterationIndex); designResult.StabilityDesignResults.NumberOfIterations = lastIterationIndex; designResult.StabilityDesignResults.UpliftSituation = macroStabilityOutput.UpliftSituation; if ((macroStabilityOutputItem.CalculationResult != CalculationResult.Succeeded) || (designResult.CalculationResult != CalculationResult.Succeeded)) { SoilGeometryProbability subSoilScenario = damKernelInput.SubSoilScenario; designResult.StabilityDesignResults.ResultMessage = designScenario.GetResultMessage(subSoilScenario.SoilProfile1D, subSoilScenario.SoilProfile2D); } designResults.Add(designResult); } } private static MacroStabilityOutputItem DetemineLeadingOutputItem(List stabilityOutputItems) { if (stabilityOutputItems.Count == 1) { return stabilityOutputItems[0]; } if (stabilityOutputItems[0].CalculationResult == CalculationResult.Succeeded && stabilityOutputItems[1].CalculationResult == CalculationResult.Succeeded) { return stabilityOutputItems[0].SafetyFactor < stabilityOutputItems[1].SafetyFactor ? stabilityOutputItems[0] : stabilityOutputItems[1]; } return null; } private static UpliftVanCalculationGrid FillUpliftVanCalculationGrid(DamKernelInput damKernelInput, double xCoordinateLastUpliftPoint) { SlipCircleDefinition slipCircleDefinition = damKernelInput.DamFailureMechanismeCalculationSpecification .FailureMechanismParametersMStab.MStabParameters.SlipCircleDefinition; slipCircleDefinition.XCoordinateLowestUpliftFactorPoint = xCoordinateLastUpliftPoint; UpliftVanCalculationGrid upliftVanCalculationGrid = UpliftVanGridCreator.DetermineGridsFromSettings( slipCircleDefinition, damKernelInput.Location.SurfaceLine); double centerOfLeftGridXCoordinate = (upliftVanCalculationGrid.LeftGridXLeft + upliftVanCalculationGrid.LeftGridXRight) * 0.5; SoilProfile1D soilProfile1DAtCenterOfLeftGridXCoordinate = damKernelInput.SubSoilScenario.DetermineSoilProfile1DAtX(centerOfLeftGridXCoordinate, damKernelInput.Location.SurfaceLine, damKernelInput.Location.GetDikeEmbankmentSoil()); UpliftVanGridCreator.DetermineTangentLines(upliftVanCalculationGrid, slipCircleDefinition, soilProfile1DAtCenterOfLeftGridXCoordinate); return upliftVanCalculationGrid; } private MacroStabilityOutputItem ProperMacroStabilityResultsItem(MacroStabilityOutput macroStabilityOutput, int requestedIndex) { MacroStabilityOutputItem macroStabilityOutputItem = null; if (macroStabilityOutput?.StabilityOutputItems != null && macroStabilityOutput.StabilityOutputItems.Count > requestedIndex && macroStabilityOutput.StabilityOutputItems[requestedIndex] != null) { macroStabilityOutputItem = macroStabilityOutput.StabilityOutputItems[requestedIndex]; } return macroStabilityOutputItem; } }