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