// 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.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 = false,
IsTangentLinesAutomatic = false
};
if (slipCircleDefinition.GridSizeDetermination == GridSizeDetermination.Specified)
{
// Define specified active (left) grid
if (surfaceLine != null)
{
// Use middle of the dike for X-coordinate
GeometryPoint dikeTopAtRiverPoint = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver);
GeometryPoint dikeTopAtPolderPoint = surfaceLine.CharacteristicPoints.GetGeometryPoint(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;
GeometryPoint dikeToeAtPolder = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder);
// X-coordinates settings of the grid
double gridWidth = slipCircleDefinition.UpliftVanRightGridHorizontalPointDistance *
(slipCircleDefinition.UpliftVanRightGridHorizontalPointCount - 1);
// The grid starts at either last uplift point X-coordinate - gridWidth or dike toe at polder X-coordinate, whichever is largest
double gridXCoordinate = Math.Max(slipCircleDefinition.XCoordinateLastUpliftPoint - gridWidth, dikeToeAtPolder.X);
upliftVanCalculationGrid.RightGridXLeft = gridXCoordinate;
// The grid is limited to the right boundary of the surfaceline
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
}
else
{
// code for slipCircleDefinition.GridSizeDetermination == GridSizeDetermination.Automatic
upliftVanCalculationGrid.IsGridsAutomatic = true;
}
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)
{
switch (slipCircleDefinition.UpliftVanTangentLinesDefinition)
{
case TangentLinesDefinition.OnBoundaryLines:
// In the kernel, the tangent lines are set to the boundaries, no need to do anything here.
upliftVanCalculationGrid.IsTangentLinesAutomatic = false;
break;
case TangentLinesDefinition.Specified:
DetermineTangentLinesSpecified(upliftVanCalculationGrid, soilProfile1D,
slipCircleDefinition.UpliftVanTangentLinesDistance);
break;
}
}
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;
}
}