// 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.Data.General; using Deltares.DamEngine.Data.Geometry; using Deltares.DamEngine.Data.Geotechnics; using Deltares.MacroStability.CSharpWrapper; using Deltares.MacroStability.CSharpWrapper.Input; using Deltares.MacroStability.CSharpWrapper.Water; using CharacteristicPointType = Deltares.DamEngine.Data.Geotechnics.CharacteristicPointType; using HeadLine = Deltares.DamEngine.Data.Geometry.HeadLine; using KernelUpliftVanCalculationGrid = Deltares.MacroStability.CSharpWrapper.UpliftVanCalculationGrid; using KernelWaternet = Deltares.MacroStability.CSharpWrapper.Water.Waternet; using KernelMacroStabilityInput = Deltares.MacroStability.CSharpWrapper.Input.MacroStabilityInput; using KernelPoint2D = Deltares.MacroStability.CSharpWrapper.Point2D; using KernelWaternetLine = Deltares.MacroStability.CSharpWrapper.Water.WaternetLine; using KernelHeadLine = Deltares.MacroStability.CSharpWrapper.Water.HeadLine; using Point2D = Deltares.DamEngine.Data.Geometry.Point2D; using Soil = Deltares.MacroStability.CSharpWrapper.Input.Soil; using SoilProfile = Deltares.MacroStability.CSharpWrapper.Input.SoilProfile; using Waternet = Deltares.DamEngine.Data.Geometry.Waternet; using WaternetLine = Deltares.DamEngine.Data.Geometry.WaternetLine; namespace Deltares.DamEngine.Calculators.KernelWrappers.MacroStabilityCommon.MacroStabilityIo; /// /// Fills the Macro Stability Wrapper from the DAM Engine data /// public class FillMacroStabilityWrapperInputFromEngine { private readonly Dictionary soilsDictionary = new Dictionary(); /// Gets or sets the UpliftVan calculation grid. /// The uplift van calculation grid. public UpliftVanCalculationGrid UpliftVanCalculationGrid { get; set; } /// Gets or sets the Bishop calculation grid. /// The bishop calculation grid. public BishopCalculationGrid BishopCalculationGrid { get; set; } /// Gets or sets the traffic load. /// The traffic load. public TrafficLoad TrafficLoad { get; set; } /// /// Creates the macro stability input. /// /// The dam kernel input. /// The parameters for MStab. /// The WaterNet. /// public KernelMacroStabilityInput CreateMacroStabilityInput(DamKernelInput damKernelInput, MStabParameters mStabParameters, Waternet waterNet) { soilsDictionary.Clear(); var macroStabilityInput = new KernelMacroStabilityInput { StabilityModel = new StabilityInput(), PreprocessingInput = new PreprocessingInput() }; macroStabilityInput.StabilityModel.UpliftVanCalculationGrid = new KernelUpliftVanCalculationGrid(); macroStabilityInput.StabilityModel.ConstructionStages.Add(new ConstructionStage()); ConstructionStage lastStage = macroStabilityInput.StabilityModel.ConstructionStages.Last(); TransferStabilityModelProperties(mStabParameters, macroStabilityInput.StabilityModel); TransferSlipPlaneConstraints(damKernelInput.Location, macroStabilityInput.StabilityModel.SlipPlaneConstraints); TransferSoils(damKernelInput.Location.SoilList, macroStabilityInput.StabilityModel.Soils, lastStage.FixedSoilStresses); lastStage.SoilProfile = new SoilProfile(); lastStage.PreconsolidationStresses = new List(); lastStage.WaterDefinition = WaterDefinition.WaterNet; TransferSoilProfile(damKernelInput.SubSoilScenario.SoilProfile2D, lastStage.SoilProfile, lastStage.PreconsolidationStresses); macroStabilityInput.PreprocessingInput.PreConstructionStages.Add(new PreConstructionStage()); PreConstructionStage preConstructionLastStage = macroStabilityInput.PreprocessingInput.PreConstructionStages.Last(); preConstructionLastStage.SurfaceLine = new SurfaceLine(); TransferSurfaceLine(damKernelInput.Location.SurfaceLine, preConstructionLastStage.SurfaceLine); lastStage.Waternet = new KernelWaternet(); TransferWaternet(waterNet, lastStage.Waternet); double top = damKernelInput.Location.SurfaceLine.CharacteristicPoints .GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder).Z; double bottom = damKernelInput.SubSoilScenario.SoilProfile2D.Geometry.MinGeometryPointsZ; SlipCircleDefinition slipCircleDefinition = damKernelInput.DamFailureMechanismeCalculationSpecification .FailureMechanismParametersMStab.MStabParameters.SlipCircleDefinition; SearchAreaConditions preprocessingSearchAreaConditions = macroStabilityInput.PreprocessingInput.SearchAreaConditions; switch (mStabParameters.Model) { case MStabModelType.Bishop: TransferBishopCalculationGridSettings(slipCircleDefinition, top, bottom, preprocessingSearchAreaConditions); TransferBishopCalculationCircle(BishopCalculationGrid, macroStabilityInput.StabilityModel.BishopCalculationCircle, preprocessingSearchAreaConditions.AutoTangentLines); break; case MStabModelType.UpliftVan: TransferUpliftVanCalculationGridSettings(slipCircleDefinition, top, bottom, preprocessingSearchAreaConditions); TransferUpliftVanCalculationGrid(UpliftVanCalculationGrid, macroStabilityInput.StabilityModel.UpliftVanCalculationGrid, preprocessingSearchAreaConditions.AutoTangentLines); break; default: throw new NotImplementedException(nameof(mStabParameters.Model)); } lastStage.UniformLoads = new List(); TransferUniformLoads(TrafficLoad, lastStage.UniformLoads); return macroStabilityInput; } private void TransferStabilityModelProperties(MStabParameters mStabParameters, StabilityInput kernelStabilityInput) { kernelStabilityInput.MoveGrid = true; // is not in DamEngine but MUST be true as we use the brute force approach. kernelStabilityInput.MaximumSliceWidth = 1.0; // is not in DamEngine datamodel // For Bishop, only Grid is possible however if Bishop/UpliftVan was selected, then the SearchAlgorithm concerns only Uplift-Van kernelStabilityInput.SearchAlgorithm = mStabParameters.Model == MStabModelType.Bishop ? SearchAlgorithm.Grid: ConversionHelper.ConvertToMacroStabilitySearchMethod(mStabParameters.SearchMethod); if (kernelStabilityInput.SearchAlgorithm == SearchAlgorithm.BeeswarmAndLevenbergMarquardt) { CreateDefaultBeeSwarmOptions(kernelStabilityInput); } kernelStabilityInput.ModelOption = ConversionHelper.ConvertToModelOptions(mStabParameters.Model); kernelStabilityInput.Orientation = ConversionHelper.ConvertToGridOrientation(mStabParameters.GridPosition); } protected internal static void TransferSlipPlaneConstraints(Location location, SlipPlaneConstraints slipPlaneConstraints) { if (location.StabilityOptions == null) { return; } slipPlaneConstraints.SlipPlaneMinDepth = location.StabilityOptions.MinimalCircleDepth?? 0.0; if ((location.StabilityOptions.StabilityZoneType == MStabZonesType.ForbiddenZone) && location.StabilityOptions.ForbiddenZoneFactor.HasValue) { CharacteristicPointSet characteristicPoints = location.SurfaceLine.CharacteristicPoints; slipPlaneConstraints.XEntryMin = characteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver).X; double xDikeTopAtPolder = characteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder).X; double xDikeToeAtPolder = characteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder).X; double factor = location.StabilityOptions.ForbiddenZoneFactor.Value; slipPlaneConstraints.XEntryMax = (xDikeToeAtPolder * factor) + ((1 - factor) * xDikeTopAtPolder); } } private void CreateDefaultBeeSwarmOptions(StabilityInput kernelStabilityInput) { kernelStabilityInput.BeeswarmAlgorithmOptions = new BeeSwarmAlgorithmOptions { EliteCount = 2, Seed = 1, CrossOver = 0.3, Beta = 0.5, Delta = 0.7, DifferentialWeight = 0.3, MaximumNonImprovingGenerations = 10, PopulationCount = 125, GenerationCount = 25 }; } private void TransferSoils(SoilList damSoilList, ICollection kernelSoils, ICollection kernelFixedSoilStresses) { // Transfer all soils if (damSoilList != null) { foreach (Data.Geotechnics.Soil damSoil in damSoilList.Soils) { Soil kernelSoil = ConversionHelper.ConvertToMacroStabilitySoil(damSoil); kernelSoils.Add(kernelSoil); soilsDictionary.Add(damSoil.Name, kernelSoil); kernelFixedSoilStresses.Add(new FixedSoilStress { POP = damSoil.PoP, Soil = kernelSoil }); } } } private void TransferSoilProfile(SoilProfile2D damSoilProfile2D, SoilProfile kernelSoilProfile, ICollection preconsolidationStresses) { // Add points var pointsDictionary = new Dictionary(); kernelSoilProfile.Geometry = new Geometry(); kernelSoilProfile.Geometry.Points = new List(); foreach (Point2D damPoint in damSoilProfile2D.Geometry.Points) { var kernelPoint = new KernelPoint2D(damPoint.X, damPoint.Z); kernelSoilProfile.Geometry.Points.Add(kernelPoint); pointsDictionary.Add(damPoint, kernelPoint); } // Add curves var curvesDictionary = new Dictionary(); kernelSoilProfile.Geometry.Curves = new List(); foreach (GeometryCurve damCurve in damSoilProfile2D.Geometry.Curves) { var kernelCurve = new Curve { HeadPoint = pointsDictionary[damCurve.HeadPoint], EndPoint = pointsDictionary[damCurve.EndPoint] }; kernelSoilProfile.Geometry.Curves.Add(kernelCurve); curvesDictionary.Add(damCurve, kernelCurve); } // Add loops var loopsDictionary = new Dictionary(); kernelSoilProfile.Geometry.Loops = new List(); foreach (GeometryLoop damLoop in damSoilProfile2D.Geometry.Loops) { var kernelLoop = new Loop(); kernelLoop.Curves = new List(); foreach (GeometryCurve geometryCurve in damLoop.CurveList) { kernelLoop.Curves.Add(curvesDictionary[geometryCurve]); } kernelSoilProfile.Geometry.Loops.Add(kernelLoop); loopsDictionary.Add(damLoop, kernelLoop); } // Add geometry surfaces var geometrySurfacesDictionary = new Dictionary(); kernelSoilProfile.Geometry.Surfaces = new List(); foreach (SoilLayer2D damSurface in damSoilProfile2D.Surfaces) { var kernelGeometrySurface = new Surface(); GeometrySurface damGeometrySurface = damSurface.GeometrySurface; kernelGeometrySurface.OuterLoop = loopsDictionary[damGeometrySurface.OuterLoop]; geometrySurfacesDictionary.Add(damGeometrySurface, kernelGeometrySurface); kernelGeometrySurface.InnerLoops = new List(damGeometrySurface.InnerLoops.Count); foreach (GeometryLoop damSurfaceInnerLoop in damGeometrySurface.InnerLoops) { kernelGeometrySurface.InnerLoops.Add(loopsDictionary[damSurfaceInnerLoop]); } kernelSoilProfile.Geometry.Surfaces.Add(kernelGeometrySurface); } // Add soil surfaces kernelSoilProfile.SoilSurfaces = new List(); foreach (SoilLayer2D damSoilLayer2D in damSoilProfile2D.Surfaces) { var kernelSoilLayer2D = new SoilProfileSurface(); kernelSoilLayer2D.Surface = geometrySurfacesDictionary[damSoilLayer2D.GeometrySurface]; kernelSoilLayer2D.Soil = soilsDictionary[damSoilLayer2D.Soil.Name]; kernelSoilLayer2D.IsAquifer = damSoilLayer2D.IsAquifer; kernelSoilLayer2D.WaterPressureInterpolationModel = ConversionHelper.ConvertToMacroStabilityWaterpressureInterpolationModel(damSoilLayer2D .WaterpressureInterpolationModel); kernelSoilProfile.SoilSurfaces.Add(kernelSoilLayer2D); } // Add the preconsolidation stresses foreach (PreConsolidationStress preconsolidationStress in damSoilProfile2D.PreconsolidationStresses) { var kernelPrecon = new PreconsolidationStress(); kernelPrecon.Point = new KernelPoint2D(preconsolidationStress.X, preconsolidationStress.Z); kernelPrecon.StressValue = preconsolidationStress.StressValue; preconsolidationStresses.Add(kernelPrecon); } } private void TransferSurfaceLine(SurfaceLine2 damSurfaceLine, SurfaceLine kernelSurfaceLine) { kernelSurfaceLine.CharacteristicPoints = new List(); foreach (CharacteristicPoint damCharPoint in damSurfaceLine.CharacteristicPoints) { var kernelCharPoint = new SurfaceLineCharacteristicPoint(); kernelCharPoint.CharacteristicPointType = ConversionHelper.ConvertToMacroStabilityCharacteristicPointType(damCharPoint.CharacteristicPointType); kernelCharPoint.GeometryPoint = new KernelPoint2D(damCharPoint.X, damCharPoint.Z); kernelSurfaceLine.CharacteristicPoints.Add(kernelCharPoint); } } private static void TransferWaternet(Waternet damWaternet, KernelWaternet kernelWaternet) { var headLineMapping = new Dictionary(); kernelWaternet.Name = damWaternet.Name; // Phreatic Line PhreaticLine phreaticLine = damWaternet.PhreaticLine; kernelWaternet.PhreaticLine = CreateLine(phreaticLine); headLineMapping.Add(damWaternet.PhreaticLine, kernelWaternet.PhreaticLine); // Head Lines foreach (HeadLine damHeadLine in damWaternet.HeadLineList) { var kernelHeadLine = CreateLine(damHeadLine); kernelWaternet.HeadLines.Add(kernelHeadLine); headLineMapping.Add(damHeadLine, kernelHeadLine); } // Waternet Lines foreach (WaternetLine damWaternetLine in damWaternet.WaternetLineList) { var kernelWaternetLine = CreateLine(damWaternetLine); kernelWaternetLine.AssociatedHeadLine = damWaternetLine.HeadLine.Name.Contains("PL 1") ? headLineMapping[damWaternet.PhreaticLine] : headLineMapping[damWaternetLine.HeadLine]; kernelWaternet.ReferenceLines.Add(kernelWaternetLine); } } private static TKernelLineType CreateLine(GeometryPointString geometry) where TKernelLineType : KernelWaternetLine, new() { var line = new TKernelLineType { Name = geometry.Name, Points = geometry.CalcPoints.Select(p => new KernelPoint2D(p.X, p.Z)).ToList() }; return line; } private void TransferBishopCalculationGridSettings(SlipCircleDefinition slipCircleDefinition, double top, double bottom, SearchAreaConditions kernelSearchAreaConditions) { kernelSearchAreaConditions.AutoSearchArea = slipCircleDefinition.GridSizeDetermination == GridSizeDetermination.Automatic; kernelSearchAreaConditions.AutoTangentLines = slipCircleDefinition.BishopTangentLinesDefinition == TangentLinesDefinition.OnBoundaryLines; if (kernelSearchAreaConditions.AutoTangentLines) { kernelSearchAreaConditions.TangentLineNumber = Convert.ToInt32(Math.Floor((top - bottom) / slipCircleDefinition.BishopTangentLinesDistance) + 1); kernelSearchAreaConditions.TangentLineZTop = top; kernelSearchAreaConditions.TangentLineZBottom = bottom; } else { kernelSearchAreaConditions.TangentLineNumber = BishopCalculationGrid.TangentLineCount; kernelSearchAreaConditions.TangentLineZTop = BishopCalculationGrid.TangentLineZTop; kernelSearchAreaConditions.TangentLineZBottom = BishopCalculationGrid.TangentLineZBottom; } } private void TransferUpliftVanCalculationGridSettings(SlipCircleDefinition slipCircleDefinition, double top, double bottom, SearchAreaConditions kernelSearchAreaConditions) { kernelSearchAreaConditions.AutoSearchArea = slipCircleDefinition.GridSizeDetermination == GridSizeDetermination.Automatic; kernelSearchAreaConditions.AutoTangentLines = slipCircleDefinition.UpliftVanTangentLinesDefinition == TangentLinesDefinition.OnBoundaryLines; if (kernelSearchAreaConditions.AutoTangentLines) { kernelSearchAreaConditions.TangentLineNumber = Convert.ToInt32(Math.Floor((top - bottom) / slipCircleDefinition.UpliftVanTangentLinesDistance) + 1); kernelSearchAreaConditions.TangentLineZTop = top; kernelSearchAreaConditions.TangentLineZBottom = bottom; } else { kernelSearchAreaConditions.TangentLineNumber = UpliftVanCalculationGrid.TangentLineCount; kernelSearchAreaConditions.TangentLineZTop = UpliftVanCalculationGrid.TangentLineZTop; kernelSearchAreaConditions.TangentLineZBottom = UpliftVanCalculationGrid.TangentLineZBottom; } } private void TransferBishopCalculationCircle(BishopCalculationGrid damBishopCalculationGrid, BishopCalculationCircle kernelBishopCalculationCircle, bool isAutoTangentLines) { if (damBishopCalculationGrid == null) { throw new ArgumentNullException(nameof(damBishopCalculationGrid)); } if (kernelBishopCalculationCircle == null) { throw new ArgumentNullException(nameof(kernelBishopCalculationCircle)); } kernelBishopCalculationCircle.Grid = new CalculationGrid { GridXNumber = damBishopCalculationGrid.GridXCount, GridXLeft = damBishopCalculationGrid.GridXLeft, GridXRight = damBishopCalculationGrid.GridXRight, GridZNumber = damBishopCalculationGrid.GridZCount, GridZTop = damBishopCalculationGrid.GridZTop, GridZBottom = damBishopCalculationGrid.GridZBottom }; if (!isAutoTangentLines) { kernelBishopCalculationCircle.TangentLines = damBishopCalculationGrid.TangentLineLevels.ToArray(); } } private void TransferUpliftVanCalculationGrid(UpliftVanCalculationGrid damUpliftVanCalculationGrid, KernelUpliftVanCalculationGrid kernelUpliftVanCalculationGrid, bool isAutoTangentLines) { if (damUpliftVanCalculationGrid == null) { throw new ArgumentNullException(nameof(damUpliftVanCalculationGrid)); } if (kernelUpliftVanCalculationGrid == null) { throw new ArgumentNullException(nameof(kernelUpliftVanCalculationGrid)); } kernelUpliftVanCalculationGrid.LeftGrid = new CalculationGrid { GridXNumber = damUpliftVanCalculationGrid.LeftGridXCount, GridXLeft = damUpliftVanCalculationGrid.LeftGridXLeft, GridXRight = damUpliftVanCalculationGrid.LeftGridXRight, GridZNumber = damUpliftVanCalculationGrid.LeftGridZCount, GridZTop = damUpliftVanCalculationGrid.LeftGridZTop, GridZBottom = damUpliftVanCalculationGrid.LeftGridZBottom }; kernelUpliftVanCalculationGrid.RightGrid = new CalculationGrid { GridXNumber = damUpliftVanCalculationGrid.RightGridXCount, GridXLeft = damUpliftVanCalculationGrid.RightGridXLeft, GridXRight = damUpliftVanCalculationGrid.RightGridXRight, GridZNumber = damUpliftVanCalculationGrid.RightGridZCount, GridZTop = damUpliftVanCalculationGrid.RightGridZTop, GridZBottom = damUpliftVanCalculationGrid.RightGridZBottom }; if (!isAutoTangentLines) { kernelUpliftVanCalculationGrid.TangentLines = damUpliftVanCalculationGrid.TangentLineLevels.ToArray(); } } private void TransferUniformLoads(TrafficLoad damTrafficLoad, ICollection kernelUniformLoads) { if (damTrafficLoad != null) { kernelUniformLoads.Add(new UniformLoad { XStart = damTrafficLoad.XStart, XEnd = damTrafficLoad.XEnd, Pressure = damTrafficLoad.Pressure, DistributionAngle = 0.0 }); } } }