// Copyright (C) Stichting Deltares 2025. 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.Linq;
using Deltares.DamEngine.Calculators.KernelWrappers.MacroStabilityCommon;
using Deltares.DamEngine.Data.General;
using Deltares.DamEngine.Data.Geometry;
using Deltares.DamEngine.Data.Geotechnics;
namespace Deltares.DamEngine.Calculators.KernelWrappers.MacroStabilityInwards;
public class UpliftVanGridCreator
{
/// Determines the UpliftVan grid from settings.
/// the slip circle definition
/// The surface line.
///
public static UpliftVanCalculationGrid DetermineGridsFromSettings(
SlipCircleDefinition slipCircleDefinition, SurfaceLine2 surfaceLine)
{
var upliftVanCalculationGrid = new UpliftVanCalculationGrid
{
IsGridsAutomatic = slipCircleDefinition.UpliftVanGridSizeDetermination == GridSizeDetermination.Automatic,
TangentLinesCreationMethod = slipCircleDefinition.UpliftVanTangentLinesDefinition,
RightGridXLeft = 0,
RightGridXRight = 0,
RightGridXCount = 0,
RightGridZTop = 0,
RightGridZBottom = 0,
RightGridZCount = 0,
LeftGridXLeft = 0,
LeftGridXRight = 0,
LeftGridXCount = 0,
LeftGridZBottom = 0,
LeftGridZTop = 0,
LeftGridZCount = 0,
TangentLineZTop = 0,
TangentLineZBottom = 0,
TangentLineCount = 0
};
if (slipCircleDefinition.UpliftVanGridSizeDetermination == GridSizeDetermination.Automatic)
{
return upliftVanCalculationGrid;
}
// Define specified active (left) grid
if (surfaceLine != null)
{
// Use middle of the dike for X-coordinate
Point2D dikeTopAtRiverPoint = surfaceLine.CharacteristicPoints.GetPoint2D(CharacteristicPointType.DikeTopAtRiver);
Point2D dikeTopAtPolderPoint = surfaceLine.CharacteristicPoints.GetPoint2D(CharacteristicPointType.DikeTopAtPolder);
double gridXCoordinate = (dikeTopAtRiverPoint.X + dikeTopAtPolderPoint.X) * 0.5;
double gridYCoordinate = surfaceLine.Geometry.GetZatX(gridXCoordinate);
double gridWidth = slipCircleDefinition.UpliftVanLeftGridHorizontalPointDistance *
(slipCircleDefinition.UpliftVanLeftGridHorizontalPointCount - 1);
double gridHeight = slipCircleDefinition.UpliftVanLeftGridVerticalPointDistance *
(slipCircleDefinition.UpliftVanLeftGridVerticalPointCount - 1);
upliftVanCalculationGrid.LeftGridXLeft = gridXCoordinate;
upliftVanCalculationGrid.LeftGridXRight = gridXCoordinate + gridWidth;
upliftVanCalculationGrid.LeftGridXCount = slipCircleDefinition.UpliftVanLeftGridHorizontalPointCount;
upliftVanCalculationGrid.LeftGridZBottom = gridYCoordinate;
upliftVanCalculationGrid.LeftGridZTop = gridYCoordinate + gridHeight;
upliftVanCalculationGrid.LeftGridZCount = slipCircleDefinition.UpliftVanLeftGridVerticalPointCount;
}
// Define specified passive (right) grid
if (surfaceLine != null)
{
const double gridOffset = 0.2;
Point2D dikeToeAtPolder = surfaceLine.CharacteristicPoints.GetPoint2D(CharacteristicPointType.DikeToeAtPolder);
// X-coordinates settings of the grid
double gridWidth = slipCircleDefinition.UpliftVanRightGridHorizontalPointDistance *
(slipCircleDefinition.UpliftVanRightGridHorizontalPointCount - 1);
// The grid starts at either lowest uplift factor point X-coordinate - gridWidth or dike toe at polder X-coordinate, whichever is largest
double gridXCoordinate = Math.Max(slipCircleDefinition.XCoordinateLowestUpliftFactorPoint - gridWidth, dikeToeAtPolder.X);
upliftVanCalculationGrid.RightGridXLeft = gridXCoordinate;
// The grid is limited to the right boundary of the surface line
double boundaryRight = surfaceLine.CharacteristicPoints.Geometry.GetGeometryBounds().Right;
upliftVanCalculationGrid.RightGridXRight = Math.Min(gridXCoordinate + gridWidth, boundaryRight);
upliftVanCalculationGrid.RightGridXCount = slipCircleDefinition.UpliftVanRightGridHorizontalPointCount;
// Z-coordinates settings of the grid
double gridHeight = slipCircleDefinition.UpliftVanRightGridVerticalPointDistance *
(slipCircleDefinition.UpliftVanRightGridVerticalPointCount - 1);
upliftVanCalculationGrid.RightGridZBottom = dikeToeAtPolder.Z + gridOffset;
upliftVanCalculationGrid.RightGridZTop = upliftVanCalculationGrid.RightGridZBottom + gridHeight;
upliftVanCalculationGrid.RightGridZCount = slipCircleDefinition.UpliftVanRightGridVerticalPointCount;
}
// Tangent lines are defined in another method
return upliftVanCalculationGrid;
}
/// Determines the tangent lines.
/// The uplift van calculation grid.
/// The slip circle definition.
/// The soil profile1 d.
public static void DetermineTangentLines(UpliftVanCalculationGrid upliftVanCalculationGrid, SlipCircleDefinition slipCircleDefinition,
SoilProfile1D soilProfile1D)
{
upliftVanCalculationGrid.TangentLinesCreationMethod = slipCircleDefinition.UpliftVanTangentLinesDefinition;
if (slipCircleDefinition.UpliftVanTangentLinesDefinition == TangentLinesDefinition.Specified)
{
DetermineTangentLinesSpecified(upliftVanCalculationGrid, soilProfile1D,
slipCircleDefinition.UpliftVanTangentLinesDistance);
}
}
private static void DetermineTangentLinesSpecified(UpliftVanCalculationGrid upliftVanCalculationGrid,
SoilProfile1D soilProfile1D, double distance)
{
if (!(distance > 0))
{
throw new ArgumentException($"Vertical distance should be > 0 but is {distance}");
}
double topOfBottomLayer = soilProfile1D.Layers.Last().TopLevel;
if (soilProfile1D.LayerCount == 1)
{
topOfBottomLayer = 0.5 * (soilProfile1D.Layers.Last().TopLevel + soilProfile1D.Layers.Last().BottomLevel);
}
double surfaceLevel = soilProfile1D.Layers.First().TopLevel;
double bottomTangentLines = topOfBottomLayer - distance;
bottomTangentLines = Math.Min(bottomTangentLines, surfaceLevel);
double topTangentLines = bottomTangentLines;
var tangentLinesCount = 1;
upliftVanCalculationGrid.TangentLineLevels.Add(topTangentLines);
while (topTangentLines < surfaceLevel)
{
topTangentLines += distance;
upliftVanCalculationGrid.TangentLineLevels.Add(topTangentLines);
tangentLinesCount++;
}
upliftVanCalculationGrid.TangentLineLevels.Reverse();
upliftVanCalculationGrid.TangentLineCount = tangentLinesCount;
upliftVanCalculationGrid.TangentLineZTop = topTangentLines;
upliftVanCalculationGrid.TangentLineZBottom = bottomTangentLines;
}
}