// 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.Linq; using Deltares.DamEngine.Calculators.KernelWrappers.Common; using Deltares.DamEngine.Calculators.KernelWrappers.Interfaces; using Deltares.DamEngine.Calculators.KernelWrappers.MacroStabilityCommon; 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.Geometry; using Deltares.DamEngine.Data.Geotechnics; using Deltares.DamEngine.Data.Standard.Calculation; using Deltares.DamEngine.Data.Standard.Logging; using Deltares.DamEngine.Data.Standard.Validation; namespace Deltares.DamEngine.Calculators.DikesDesign; /// /// Design strategy: combined slope adaption and shoulder adaption /// public class DesignCalculatorCombinedSlopeAndShoulderAdaption { private const double defaultMaxFractionOfDikeHeightForShoulderHeight = 0.67; /// /// Performs the design calculation combined slope adaption and shoulder adaption. /// /// The kernel wrapper. /// The kernel data input. /// The kernel data output. /// The dam kernel input. /// The calculation messages. /// The design calculations. /// /// /// public static void PerformDesignCalculationCombinedSlopeAdaptionAndShoulderAdaption( IKernelWrapper kernelWrapper, IKernelDataInput kernelDataInput, IKernelDataOutput kernelDataOutput, DamKernelInput damKernelInput, List calculationMessages, List designCalculations) { List designResults; Location location = damKernelInput.Location; DesignScenario designScenario = location.CurrentScenario; SoilGeometryProbability subSoilScenario = damKernelInput.SubSoilScenario; const int maxRedesignIterations = 200; var resultMessage = ""; int iterationIndex = -1; designScenario.CalculationResult = CalculationResult.NoRun; EmbankmentDesignParameters embankmentDesignParameters; // Prepare the kernel for design kernelWrapper.PrepareDesign(kernelDataInput, kernelDataOutput, damKernelInput, iterationIndex, out embankmentDesignParameters); SurfaceLine2 surfaceLine = designScenario.GetMostRecentSurfaceLine(subSoilScenario.SoilProfile1D, subSoilScenario.SoilProfile2D); if (surfaceLine == null) { surfaceLine = location.SurfaceLine; } surfaceLine = surfaceLine.FullDeepClone(); try { iterationIndex = 1; bool isRedesignRequired; location.SurfaceLine = surfaceLine; location.AlignBoundaryPointsOfPl1LineWithAdaptedSurfaceLine(surfaceLine); List locationCalculationMessages; DesignCalculatorUtils.KernelCalculate(out kernelDataInput, kernelWrapper, out kernelDataOutput, damKernelInput, iterationIndex, out locationCalculationMessages); calculationMessages.AddRange(locationCalculationMessages); DesignAdvise designAdvise; string evaluationMessage; isRedesignRequired = !kernelWrapper.EvaluateDesign(damKernelInput, kernelDataInput, kernelDataOutput, out designAdvise, out evaluationMessage); if (!isRedesignRequired && surfaceLine != null) { // Set redesigned surfaceline to original, so in case no redesign is needed, the original surfaceline will be returned designScenario.SetRedesignedSurfaceLine(subSoilScenario.SoilProfile1D, subSoilScenario.SoilProfile2D, surfaceLine); } else { double maxFractionOfDikeHeightForShoulderHeight = location.UseNewMaxHeightShoulderAsFraction ? location.NewMaxHeightShoulderAsFraction : defaultMaxFractionOfDikeHeightForShoulderHeight; double maxShoulderLevel = DesignCalculatorUtils.CalculateMaximumShoulderLevel(surfaceLine, maxFractionOfDikeHeightForShoulderHeight); damKernelInput.CurrentEmbankmentSoil = location.GetShoulderEmbankmentSoil(); while (isRedesignRequired && surfaceLine != null) { // Always start with the original soil profile damKernelInput.SubSoilScenario.SoilProfile2D = damKernelInput.OriginalSoilProfile2D; iterationIndex++; DesignCalculatorUtils.ThrowWhenMaxIterationsExceeded(iterationIndex, maxRedesignIterations); GeometryPoint limitPointForShoulderDesign = surfaceLine.GetLimitPointForShoulderDesign(); if (designAdvise == DesignAdvise.ShoulderInwards) { // If exit point of circle is after the limitPointForShoulderDesign then enlarge the shoulder // Determine new width and height for shoulder double shoulderHeight; double shoulderLength; DesignCalculatorUtils.DetermineNewShoulderLengthAndHeight(location.StabilityShoulderGrowDeltaX, location.StabilityShoulderGrowSlope, surfaceLine, limitPointForShoulderDesign, out shoulderHeight, out shoulderLength); // Create new shoulder var surfaceLineShoulderAdapter = new SurfaceLineShoulderAdapter(surfaceLine, location, designScenario.PolderLevel); surfaceLineShoulderAdapter.MaxShoulderLevel = maxShoulderLevel; surfaceLine = surfaceLineShoulderAdapter.ConstructNewSurfaceLine(shoulderLength, shoulderHeight, false); ValidationResult validationError = surfaceLine.Validate().FirstOrDefault(vr => vr.MessageType == ValidationResultType.Error); if (validationError != null) { throw new SurfaceLineException(validationError.Text); } designScenario.SetRedesignedSurfaceLine(subSoilScenario.SoilProfile1D, subSoilScenario.SoilProfile2D, surfaceLine); } else if (designAdvise == DesignAdvise.SlopeInwards) { // If exit point of circle is in the slope (inward) of the dike or the top of the shoulder then adapt slope var surfaceLineSlopeAdapter = new SurfaceLineSlopeAdapter(surfaceLine, location, designScenario.PolderLevel); surfaceLine = surfaceLineSlopeAdapter.ConstructNewSurfaceLine(location.StabilitySlopeAdaptionDeltaX); ValidationResult validationError = surfaceLine.Validate().FirstOrDefault(vr => vr.MessageType == ValidationResultType.Error); if (validationError != null) { throw new SurfaceLineException(validationError.Text); } designScenario.SetRedesignedSurfaceLine(subSoilScenario.SoilProfile1D, subSoilScenario.SoilProfile2D, surfaceLine); } else { throw new NotImplementedException(); } // Calculate again location.AlignBoundaryPointsOfPl1LineWithAdaptedSurfaceLine(surfaceLine); location.SurfaceLine = surfaceLine; kernelWrapper.PrepareDesign(kernelDataInput, kernelDataOutput, damKernelInput, iterationIndex, out embankmentDesignParameters); if (subSoilScenario.SoilProfileType == SoilProfileType.ProfileType2D) { Soil embankmentSoil = location.SoilList.GetSoilByName(embankmentDesignParameters.EmbankmentMaterialname); subSoilScenario.SoilProfile2D = MacroStabilityCommonHelper.CombineSoilProfileWithSurfaceLine(subSoilScenario, surfaceLine, embankmentSoil); } DesignCalculatorUtils.KernelCalculate(out kernelDataInput, kernelWrapper, out kernelDataOutput, damKernelInput, iterationIndex, out locationCalculationMessages); calculationMessages.AddRange(locationCalculationMessages); isRedesignRequired = !kernelWrapper.EvaluateDesign(damKernelInput, kernelDataInput, kernelDataOutput, out designAdvise, out evaluationMessage); } } calculationMessages.AddRange(locationCalculationMessages); designScenario.CalculationResult = CalculationResult.Succeeded; designScenario.SetResultMessage(subSoilScenario.SoilProfile1D, subSoilScenario.SoilProfile2D, "Succes"); kernelWrapper.PostProcess(damKernelInput, kernelDataOutput, designScenario, resultMessage, out designResults); designCalculations.AddRange(designResults); } catch (Exception exception) { string errorMessage = exception.Message; Exception innerException = exception.InnerException; while (innerException != null) { errorMessage = errorMessage + ";" + innerException.Message; innerException = innerException.InnerException; } designScenario.SetResultMessage(subSoilScenario.SoilProfile1D, subSoilScenario.SoilProfile2D, errorMessage); designScenario.CalculationResult = CalculationResult.RunFailed; // Redesign not succesful, so no redesigned surfaceline will be returned designScenario.SetRedesignedSurfaceLine(subSoilScenario.SoilProfile1D, subSoilScenario.SoilProfile2D, null); kernelWrapper.PostProcess(damKernelInput, kernelDataOutput, designScenario, errorMessage, out designResults); designCalculations.AddRange(designResults); throw new DesignCalculatorException(Resources.DesignUnsuccessful + " " + errorMessage); } } }