using System;
using System.Collections.Generic;
using System.Linq;
using Deltares.Geometry;
using Deltares.Geotechnics;
using Deltares.Geotechnics.Soils;
using Deltares.Geotechnics.SurfaceLines;
using Deltares.Mathematics;
using Deltares.Standard.EventPublisher;
using Deltares.Standard.Language;
using Deltares.Standard.Logging;
namespace Deltares.Stability
{
public class RTOCalculationgrid
{
private const bool isGridSearch = false;
private GeometryPoint dikeShoulderLeft;
private GeometryPoint dikeShoulderRight;
private GeometryPoint ditchTop;
private SoilProfile2D profile2D; // Aggregation
private SurfaceLine2 surfaceLine; // Aggregation, not, is composition (see contracts)
private Waternet waternet;
public RTOCalculationgrid() { }
///
/// Initializes a new instance of the class.
///
/// The stability model.
/// cannot be null,
/// and its , ,
/// cannot be null.
/// is not null.
public RTOCalculationgrid(StabilityModel stabilityModel)
{
profile2D = stabilityModel.SoilProfile;
surfaceLine = stabilityModel.SurfaceLine2;
waternet = stabilityModel.GeotechnicsData.CurrentWaternet;
// remove the Nan
RemoveNaNFromSurfaceLinePoints(surfaceLine);
InwardStability = stabilityModel.SlipCircle.Orientation == GridOrientation.Inwards;
}
public bool InwardStability { get; set; }
public SurfaceLine2 SurfaceLine // Aggregation, not at all: composition -> see contracts
{
get
{
return surfaceLine;
}
set
{
surfaceLine = value;
}
}
///
/// Sets the soil profile2 d.
///
/// The profile.
/// cannot be null.
public void SetSoilProfile2D(SoilProfile2D profile)
{
profile2D = profile;
}
///
/// Determines outward space to be filled with grids
///
///
///
/// not null, its not null,
/// and should contain characteristic points and
/// .
///
public void DetermineOutwardBishopGrid(SlipCircle slipCircle)
{
GeometryPoint dikeTopRiver = SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver);
GeometryPoint dikeToeRiver = SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtRiver);
GeometryPoint dikeTopPolder = SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder);
double xMiddleDike = (dikeTopPolder.X + dikeTopRiver.X) / 2;
slipCircle.SlipCircleGrid.GridXRight = dikeTopRiver.X;
slipCircle.SlipCircleGrid.GridZBottom = dikeTopRiver.Z + 1.0;
double extraheight = 0;
if (IsOutsideShoulderPresent())
{
if (isGridSearch)
{
slipCircle.SlipCircleGrid.GridZBottom = dikeShoulderLeft.Z;
extraheight = dikeTopRiver.Z - dikeShoulderLeft.Z;
}
else
{
slipCircle.SlipCircleGrid.GridZBottom = dikeShoulderLeft.Z;
}
}
slipCircle.SlipCircleGrid.GridXLeft = dikeToeRiver.X;
double height = dikeTopRiver.Z - GetTopPleistoceen(xMiddleDike) + extraheight;
slipCircle.SlipCircleGrid.GridZTop = slipCircle.SlipCircleGrid.GridZBottom + height;
slipCircle.SlipCircleTangentLine.TangentLineZTop = dikeToeRiver.Z + 2.0;
slipCircle.SlipCircleTangentLine.TangentLineZBottom = Math.Min(GetTopPleistoceen(xMiddleDike), dikeToeRiver.Z);
}
///
/// Create the grid boundaries for a grid calculation with search minimum
///
///
///
/// cannot be null, its cannot be null
/// and should have points.
///
public void UpdateBishopGrid(SlipCircle slipCircle)
{
if (slipCircle == null)
{
throw new ArgumentNullException("slipCircle");
}
if (SurfaceLine == null)
{
throw new InvalidOperationException("Grid can not be generated / updated when surface line is not present.");
}
if (InwardStability)
{
DetermineInwardBishopGrid(slipCircle);
}
else
// outward stability = river side
{
DetermineOutwardBishopGrid(slipCircle);
}
// determine the intervalls
slipCircle.SlipCircleGrid.XIntervalNumber = 0;
if (Math.Abs(slipCircle.SlipCircleGrid.GridXLeft - slipCircle.SlipCircleGrid.GridXRight) >
Constants.CGeoAccu)
{
slipCircle.SlipCircleGrid.XIntervalNumber =
(int)Math.Max(Math.Round(Math.Abs(slipCircle.SlipCircleGrid.GridXRight - slipCircle.SlipCircleGrid.GridXLeft)), 2);
}
slipCircle.SlipCircleGrid.ZIntervalNumber = 0;
if (Math.Abs(slipCircle.SlipCircleGrid.GridZTop - slipCircle.SlipCircleGrid.GridZBottom) >
Constants.CGeoAccu)
{
slipCircle.SlipCircleGrid.ZIntervalNumber =
(int)Math.Max(Math.Round(Math.Abs(slipCircle.SlipCircleGrid.GridZTop - slipCircle.SlipCircleGrid.GridZBottom)), 2);
}
slipCircle.SlipCircleTangentLine.TangentLineNumber = 0;
if (
Math.Abs(slipCircle.SlipCircleTangentLine.TangentLineZTop -
slipCircle.SlipCircleTangentLine.TangentLineZBottom) > Constants.CGeoAccu)
{
slipCircle.SlipCircleTangentLine.TangentLineNumber =
(int)
Math.Max(
Math.Round(
Math.Abs(slipCircle.SlipCircleTangentLine.TangentLineZTop -
slipCircle.SlipCircleTangentLine.TangentLineZBottom)), 3);
}
}
public void CreateZone(StabilityModel model)
{
model.SlipPlaneConstraints.XEntryMin = double.NaN;
model.SlipPlaneConstraints.XEntryMax = double.NaN;
if (surfaceLine.IsDefined(CharacteristicPointType.DikeToeAtRiver))
{
model.SlipPlaneConstraints.XEntryMin = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtRiver).X;
}
if (surfaceLine.IsDefined(CharacteristicPointType.DikeTopAtPolder)
&& surfaceLine.IsDefined(CharacteristicPointType.DikeToeAtPolder))
{
GeometryPoint top = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder);
GeometryPoint toe = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder);
double zEnd = 0.5 * (top.Z + toe.Z);
if (surfaceLine.IsDefined(CharacteristicPointType.ShoulderBaseInside))
{
GeometryPoint shoulder = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder);
if (zEnd < shoulder.Z)
{
model.SlipPlaneConstraints.XEntryMax = shoulder.X;
}
else
{
model.SlipPlaneConstraints.XEntryMax = FindXAtSurface(top.X, toe.X, zEnd);
}
}
else
{
model.SlipPlaneConstraints.XEntryMax = FindXAtSurface(top.X, toe.X, zEnd);
}
}
}
///
/// Creates a calculation grid if autogeneration is requested.
///
/// Model with data to use for generating the grid.
/// if has no soil layers and grid should be generated.
public void CreateGrid(StabilityModel model)
{
if (!model.SoilProfile.Surfaces.Any())
{
return;
}
bool autoGenerate = false;
switch (model.ModelOption)
{
case ModelOptions.Bishop:
case ModelOptions.UpliftVan:
autoGenerate = model.SlipCircle.Auto;
break;
case ModelOptions.Spencer:
autoGenerate = model.AutoGenerateGeneticSpencer;
break;
}
if (autoGenerate)
{
waternet = model.GeotechnicsData.CurrentWaternet;
if (StabilityModelHasLayers(model))
{
if (model.SearchAlgorithm == SearchAlgorithm.Genetic ||
model.SearchAlgorithm == SearchAlgorithm.LevenbergMarquardt ||
model.SearchAlgorithm == SearchAlgorithm.GeneticAndLevenbergMarquardt)
{
switch (model.ModelOption)
{
case ModelOptions.Spencer:
UpdateSpencerGA(model);
break;
}
}
else if (model.SearchAlgorithm == SearchAlgorithm.Grid)
{
switch (model.ModelOption)
{
case ModelOptions.Bishop:
UpdateBishopGrid(model.SlipCircle);
break;
case ModelOptions.UpliftVan:
UpdateUpliftGrid(model.SlipPlaneUpliftVan);
break;
case ModelOptions.Spencer:
UpdateSpencerGA(model);
break;
}
}
}
}
}
public void GenerateSpencerSlipPlanes(StabilityModel model)
{
if (model.IsHighSlipPlanes)
{
CreateInwardSpencerPlanesHigh(model);
}
else
{
CreateInwardSpencerPlanesLow(model);
}
}
public void ReplaceSlipPlanesObject(object target)
{
if (target is StabilityModel)
{
ReplaceSlipPlanes(target as StabilityModel);
}
}
public void ReplaceSlipPlanes(StabilityModel stabilityModel)
{
DataEventPublisher.BeforeChange(this, "SlipPlanes");
ResetSlipPlanes(stabilityModel);
if (stabilityModel.SurfaceLine2 != null)
{
DataEventPublisher.InvokeWithoutPublishingEvents(() =>
{
try
{
var rtoCalculationGrid = new RTOCalculationgrid(stabilityModel);
rtoCalculationGrid.CreateGrid(stabilityModel);
foreach (var slipPlane in stabilityModel.SlipPlanes)
{
slipPlane.Name = LocalizationManager.GetTranslatedText(typeof(StabilityDikeLocationInfo), "SlipPlane");
}
}
catch (Exception)
{
ResetSlipPlanes(stabilityModel);
if (stabilityModel.SurfaceLine2.CharacteristicPoints.Any() && stabilityModel.SoilProfile.Surfaces.Any()) // Only add log message when no log message is already generated via validation
{
var logMessage = new LogMessage(LogMessageType.Warning, this, string.Format(LocalizationManager.GetTranslatedText(typeof(StabilityDikeLocationInfo), "CannotCreateSlipPlanes")));
if (LogManager.Messages.All(m => m.Message != logMessage.Message)) // Only add log message once
{
LogManager.Add(logMessage);
}
}
}
});
}
DataEventPublisher.AfterChange(this, "SlipPlanes");
}
///
/// Find level from pleistocene at X.
/// If no aquitard is found, it is assumed that the bottom layer is the pleistocene level.
/// This is done by creating a 1D geometry at point X. Take the bottom level as first guess.
///
/// or are not null, and
/// has the following characteristic points: and
/// . 1D profile corresponding to
/// for the given characteristic points has layers.
private double GetTopPleistoceen(double x)
{
SoilProfile1D helpProfile = profile2D.GetSoilProfile1D(x);
if (helpProfile.Layers.Count == 0)
{
return double.NaN;
}
double result = helpProfile.Layers[helpProfile.LayerCount - 1].TopLevel;
for (int i = helpProfile.LayerCount - 2; i > -1; i--)
{
if (!helpProfile.Layers[i].IsAquifer)
{
result = helpProfile.Layers[i + 1].TopLevel;
break;
}
}
return result;
}
///
/// Fins out if there is a shoulder is knwn at the polder side
///
///
private bool IsInsideShoulderPresent()
{
bool result = false;
dikeShoulderLeft = surfaceLine.IsDefined(CharacteristicPointType.ShoulderBaseInside)
? surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.ShoulderBaseInside)
: null;
dikeShoulderRight = surfaceLine.IsDefined(CharacteristicPointType.ShoulderTopInside)
? surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.ShoulderTopInside)
: null;
if ((dikeShoulderLeft != null) && (dikeShoulderRight != null))
{
result = (dikeShoulderLeft.X < dikeShoulderRight.X);
}
return result;
}
///
/// find out if a ditch is given (only at polder side)
///
///
private bool IsDitchPresent()
{
bool result = false;
ditchTop = surfaceLine.IsDefined(CharacteristicPointType.DitchPolderSide)
? surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DitchPolderSide)
: null;
GeometryPoint ditchBot = surfaceLine.IsDefined(CharacteristicPointType.BottomDitchPolderSide)
? surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.BottomDitchPolderSide)
: null;
if ((ditchTop != null) && (ditchBot != null))
{
if ((!double.IsNaN(ditchTop.X)) && (!double.IsNaN(ditchBot.X)))
{
result = true;
}
}
return result;
}
///
/// find out if a ditch is given (only at polder side)
///
///
private bool IsChannelPresent()
{
return surfaceLine.IsDefined(CharacteristicPointType.InsertRiverChannel);
}
///
/// Check if a shoulder is fiven at de river side
///
///
private bool IsOutsideShoulderPresent()
{
bool result = false;
dikeShoulderLeft = surfaceLine.IsDefined(CharacteristicPointType.ShoulderTopOutside)
? surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.ShoulderTopOutside)
: null;
dikeShoulderRight = surfaceLine.IsDefined(CharacteristicPointType.ShoulderBaseOutside)
? surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.ShoulderBaseOutside)
: null;
if ((dikeShoulderLeft != null) && (dikeShoulderRight != null))
{
result = (dikeShoulderLeft.X < dikeShoulderRight.X);
}
return result;
}
///
/// Determines inward space to be filled with grids
///
///
///
/// not null, its not null,
/// and should contain characteristic points and
/// .
///
private void DetermineInwardBishopGrid(SlipCircle slipCircle)
{
GeometryPoint dikeTopPolder = SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder);
GeometryPoint dikeToe = SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder);
GeometryPoint dikeTopRiver = SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver);
double xMiddleDike = (dikeTopPolder.X + dikeTopRiver.X) / 2;
slipCircle.SlipCircleGrid.GridXLeft = dikeTopPolder.X;
slipCircle.SlipCircleGrid.GridZBottom = dikeTopPolder.Z + 1.0;
double extraheight = 0;
if (IsInsideShoulderPresent())
{
if (isGridSearch)
{
slipCircle.SlipCircleGrid.GridZBottom = dikeShoulderRight.Z;
extraheight = dikeTopPolder.Z - dikeShoulderRight.Z;
}
else
{
slipCircle.SlipCircleGrid.GridZBottom = dikeShoulderRight.Z;
}
}
double height = dikeTopPolder.Z - GetTopPleistoceen(xMiddleDike) + extraheight;
slipCircle.SlipCircleGrid.GridZTop = slipCircle.SlipCircleGrid.GridZBottom + height;
slipCircle.SlipCircleGrid.GridXRight = dikeToe.X;
slipCircle.SlipCircleTangentLine.TangentLineZTop = dikeToe.Z + 2.0;
slipCircle.SlipCircleTangentLine.TangentLineZBottom = Math.Min(GetTopPleistoceen(xMiddleDike), dikeToe.Z);
}
///
/// Determine space to be filled with grid (only polderside)
///
///
private void UpdateUpliftGrid(SlipPlaneUpliftVan slipPlaneUpliftVan)
{
InwardStability = true;
// ACTIVE GRID is the same as Bishop
var tempCircle = new SlipCircle();
UpdateBishopGrid(tempCircle);
slipPlaneUpliftVan.SlipPlaneLeftGrid = tempCircle.SlipCircleGrid;
slipPlaneUpliftVan.SlipPlaneLeftGrid.XIntervalNumber = (int)Math.Max(
Math.Round(Math.Abs((slipPlaneUpliftVan.SlipPlaneLeftGrid.GridXRight -
slipPlaneUpliftVan.SlipPlaneLeftGrid.GridXLeft) / 1.5)), 2);
slipPlaneUpliftVan.SlipPlaneLeftGrid.ZIntervalNumber = (int)Math.Max(
Math.Round(Math.Abs((slipPlaneUpliftVan.SlipPlaneLeftGrid.GridZTop -
slipPlaneUpliftVan.SlipPlaneLeftGrid.GridZBottom) / 1.5)), 2);
// PASSIVE GRID
GeometryPoint dikeToe = SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder);
GeometryPoint rightBoundary = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.SurfaceLevelInside);
GeometryPoint ditchDikeSide = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DitchDikeSide);
slipPlaneUpliftVan.SlipPlaneRightGrid.GridXLeft = dikeToe.X;
if (IsDitchPresent())
{
slipPlaneUpliftVan.SlipPlaneRightGrid.GridXRight = ditchDikeSide.X;
slipPlaneUpliftVan.SlipPlaneRightGrid.GridZBottom = ditchDikeSide.Z;
}
else
{
double xCoordAtWhichUpliftEnds = SearchXcoordinateOfEndOfUpliftAtPolderSide();
// If no uplift occurs, Xright of passive grid is the dike toe + 8 m
if (Math.Abs(xCoordAtWhichUpliftEnds - rightBoundary.X) < Constants.CGeoAccu)
{
slipPlaneUpliftVan.SlipPlaneRightGrid.GridXRight = Math.Min(dikeToe.X + 8.0, rightBoundary.X);
}
else
{
slipPlaneUpliftVan.SlipPlaneRightGrid.GridXRight = xCoordAtWhichUpliftEnds;
}
slipPlaneUpliftVan.SlipPlaneRightGrid.GridZBottom = dikeToe.Z;
}
slipPlaneUpliftVan.SlipPlaneRightGrid.GridZTop = slipPlaneUpliftVan.SlipPlaneRightGrid.GridZBottom + 4.0;
slipPlaneUpliftVan.SlipPlaneRightGrid.XIntervalNumber = 0;
if (Math.Abs(slipPlaneUpliftVan.SlipPlaneRightGrid.GridXLeft - slipPlaneUpliftVan.SlipPlaneRightGrid.GridXRight) > Constants.CGeoAccu)
{
slipPlaneUpliftVan.SlipPlaneRightGrid.XIntervalNumber = (int)Math.Max(Math.Round((slipPlaneUpliftVan.SlipPlaneRightGrid.GridXRight -
slipPlaneUpliftVan.SlipPlaneRightGrid.GridXLeft) / 2.0), 2);
}
slipPlaneUpliftVan.SlipPlaneRightGrid.ZIntervalNumber = 0;
if (Math.Abs(slipPlaneUpliftVan.SlipPlaneRightGrid.GridZTop - slipPlaneUpliftVan.SlipPlaneRightGrid.GridZBottom) > Constants.CGeoAccu)
{
slipPlaneUpliftVan.SlipPlaneRightGrid.ZIntervalNumber = 2;
}
// TANGENT LINES
slipPlaneUpliftVan.SlipCircleTangentLine.AutomaticAtBoundaries = true;
slipPlaneUpliftVan.SlipCircleTangentLine.MaxSpacingBetweenBoundaries = 1;
slipPlaneUpliftVan.SlipPlaneTangentLine.UpdateBoundaries();
slipPlaneUpliftVan.SlipCircleTangentLine.TangentLineZBottom = slipPlaneUpliftVan.SlipCircleTangentLine.BoundaryHeights.Max().Height;
slipPlaneUpliftVan.SlipCircleTangentLine.TangentLineZTop = slipPlaneUpliftVan.SlipCircleTangentLine.BoundaryHeights.Min().Height;
}
private void RemoveNaNFromSurfaceLinePoints(SurfaceLine2 line)
{
if (line != null)
{
var pointsToRemove = line.Geometry.Points.Where(p => double.IsNaN(p.X) || double.IsNaN(p.Z)).ToList();
foreach (var geometryPoint in pointsToRemove)
{
line.Geometry.Points.Remove(geometryPoint);
}
}
}
private double FindXAtSurface(double startX, double endX, double level)
{
double result = Double.NaN;
for (int i = 0; i < surfaceLine.Geometry.Count - 2; i++)
{
if ((surfaceLine.Geometry.Points[i].X >= startX) && (surfaceLine.Geometry.Points[i + 1].X <= endX))
{
if ((Math.Max(surfaceLine.Geometry.Points[i].Z, surfaceLine.Geometry.Points[i + 1].Z) >= level) &&
(Math.Min(surfaceLine.Geometry.Points[i].Z, surfaceLine.Geometry.Points[i + 1].Z) <= level))
{
result = Routines2D.LinInpolY(surfaceLine.Geometry.Points[i].Z, surfaceLine.Geometry.Points[i].X,
surfaceLine.Geometry.Points[i + 1].Z, surfaceLine.Geometry.Points[i + 1].X, level);
break;
}
}
}
return result;
}
private static bool StabilityModelHasLayers(StabilityModel model)
{
return model.SoilProfile.Surfaces.Any();
}
private void CreateInwardSpencerInnerSlipPlaneLow(GeometryPointString innerSlipPlane)
{
innerSlipPlane.Points.Clear();
var entryPoint = new GeometryPoint();
var exitPoint = new GeometryPoint();
GeometryPoint dikeTopPolder = SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder);
GeometryPoint dikeToe = SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder);
GeometryPoint ditchDikeSide = SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DitchDikeSide);
if (IsInsideShoulderPresent())
{
dikeShoulderLeft = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.ShoulderBaseInside);
entryPoint.X = 0.5 * (dikeTopPolder.X + dikeShoulderLeft.X);
entryPoint.Z = surfaceLine.Geometry.GetZAtX(entryPoint.X);
}
else
{
GeometryPoint diketoe = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder);
entryPoint.X = 0.5 * (dikeTopPolder.X + diketoe.X);
entryPoint.Z = surfaceLine.Geometry.GetZAtX(entryPoint.X);
}
innerSlipPlane.Points.Add(entryPoint);
// Exit point (9in) = rightest point
if (IsDitchPresent())
{
exitPoint.X = Math.Min(dikeToe.X + 5, ditchDikeSide.X);
exitPoint.Z = surfaceLine.Geometry.GetZAtX(exitPoint.X);
}
else
{
exitPoint.X = dikeToe.X + 5;
exitPoint.Z = surfaceLine.Geometry.GetZAtX(exitPoint.X);
}
// Height h is calculated at exit point (9in)
double h = exitPoint.Z - GetTopPleistoceen(exitPoint.X);
// First determine if point 6in is situated after the exit point. In such case, point 6in is the middle of the entry and exit point.
bool point6inIsAtRightSideOfExitPoint = entryPoint.X + entryPoint.Z - (exitPoint.Z - h / 2) > exitPoint.X;
var point6in = new GeometryPoint();
if (point6inIsAtRightSideOfExitPoint)
{
point6in.X = (entryPoint.X + exitPoint.X) / 2;
}
else
{
point6in.X = entryPoint.X + entryPoint.Z - (exitPoint.Z - h / 2);
}
point6in.Z = exitPoint.Z - h / 2;
// Then determine if left and right slopes (1:1) of the inner plane intersect above level Z_exit - h/2
bool bothSlopesIntersect = point6in.X > exitPoint.X - h / 2;
// Case 1: left and right slopes (1:1) of the inner plane do not intersect above level Z_exit - h/2
if (!bothSlopesIntersect)
{
double deltaX = point6in.X - entryPoint.X;
double deltaZ = entryPoint.Z - point6in.Z;
// the 6 points on the left slope 1:1
for (int i = 1; i < 6; i++)
{
var nextPoint = new GeometryPoint();
nextPoint.X = entryPoint.X + i * deltaX / 5;
nextPoint.Z = entryPoint.Z - i * deltaZ / 5;
innerSlipPlane.Points.Add(nextPoint);
}
// point 8in
var point8in = new GeometryPoint();
if (h < Constants.CAlmostZero)
{
point8in.X = exitPoint.X - (exitPoint.X - point6in.X) / 3;
point8in.Z = exitPoint.Z;
}
else
{
point8in.X = exitPoint.X - h / 2;
point8in.Z = exitPoint.Z - h / 2;
}
// point 7in = middle of point 6in and 8 in
var point7in = new GeometryPoint();
point7in.X = (entryPoint.X + deltaX + point8in.X) / 2;
point7in.Z = point8in.Z;
innerSlipPlane.Points.Add(point7in);
innerSlipPlane.Points.Add(point8in);
}
// Case 2: left and right slopes (1:1) of the hight inner plane do intersect
else
{
// point 7in = intersection point of left and right slopes
var point7in = new GeometryPoint();
point7in.X = (entryPoint.Z + entryPoint.X - exitPoint.Z + exitPoint.X) / 2;
point7in.Z = exitPoint.Z - (exitPoint.X - point7in.X);
// point 8in = between 7in and 9in
var point8in = new GeometryPoint();
point8in.X = (exitPoint.X + point7in.X) / 2;
point8in.Z = (exitPoint.Z + point7in.Z) / 2;
// the 6 points (2in until 7in) on the left slope 1:1 are added
double delta = point7in.X - entryPoint.X;
for (int i = 1; i < 7; i++)
{
var nextPoint = new GeometryPoint();
nextPoint.X = entryPoint.X + i * delta / 6;
nextPoint.Z = entryPoint.Z - i * delta / 6;
innerSlipPlane.Points.Add(nextPoint);
}
innerSlipPlane.Points.Add(point8in);
}
// exit point 9in
innerSlipPlane.Points.Add(exitPoint);
innerSlipPlane = EnsureThatPointsOfTheSlipPlaneAreNotAboveSurfaceLine(innerSlipPlane);
DataEventPublisher.DataListModified(innerSlipPlane.Points);
}
private void CreateInwardSpencerInnerSlipPlaneHigh(GeometryPointString innerSlipPlane)
{
innerSlipPlane.Points.Clear();
var exitPoint = new GeometryPoint();
var entryPoint = new GeometryPoint();
GeometryPoint dikeTopAtPolder = SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder);
GeometryPoint dikeToeAtPolder = SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder);
GeometryPoint dikeTopAtRiver = SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver);
double height = (dikeTopAtPolder.Z - dikeToeAtPolder.Z) / 3;
// Exit point (9in) = rightest point
exitPoint.X = dikeToeAtPolder.X;
exitPoint.Z = dikeToeAtPolder.Z;
// Entry point (1in) = leftest point
entryPoint.Z = exitPoint.Z + height;
entryPoint.X = surfaceLine.Geometry.GetXAtZ(entryPoint.Z, dikeTopAtRiver.X);
// Intersection point
var intersectionPoint = new GeometryPoint();
intersectionPoint.X = entryPoint.X + (entryPoint.Z - exitPoint.Z);
intersectionPoint.Z = Math.Min(surfaceLine.Geometry.GetZAtX(intersectionPoint.X), exitPoint.Z);
innerSlipPlane.Points.Add(entryPoint);
// Point 7in
var point7in = new GeometryPoint();
if (intersectionPoint.X > exitPoint.X)
{
point7in.X = (entryPoint.X + exitPoint.X) / 2;
point7in.Z = Math.Min(surfaceLine.Geometry.GetZAtX(point7in.X), exitPoint.Z);
}
else
{
point7in = intersectionPoint;
}
// the seven points on the line 1:1
for (int i = 1; i < 7; i++)
{
var nextPoint = new GeometryPoint();
nextPoint.X = entryPoint.X + i / 6.0 * Math.Abs(point7in.X - entryPoint.X);
nextPoint.Z = entryPoint.Z - i / 6.0 * Math.Abs(point7in.Z - entryPoint.Z);
innerSlipPlane.Points.Add(nextPoint);
}
// Point 8in
var point8in = new GeometryPoint();
point8in.X = (point7in.X + exitPoint.X) / 2;
point8in.Z = Math.Min(surfaceLine.Geometry.GetZAtX(point8in.X), exitPoint.Z);
innerSlipPlane.Points.Add(point8in);
innerSlipPlane.Points.Add(exitPoint);
innerSlipPlane = EnsureThatPointsOfTheSlipPlaneAreNotAboveSurfaceLine(innerSlipPlane);
DataEventPublisher.DataListModified(innerSlipPlane.Points);
}
/*
start (point 1) end (point 10)
| / | / | /
| / | / | /
| / | / | /
1 | 2 / | / | /
| / | / | /
| / | / | /
| / | / ------------- bottom pleistoceen
| / | / | /
| / | / | /
| / | / | /
| / ------------ bottom pleistoceen | /
| / | / | /
|/ |/ |/
intersection
*/
private void CreateInwardSpencerOuterSlipPlaneLow(GeometryPointString outerSlipPlane)
{
outerSlipPlane.Points.Clear();
bool isDitchPresent = IsDitchPresent();
GeometryPoint dikeTopRiver =
SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver);
GeometryPoint dikeToePolder =
SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder);
GeometryPoint dikeTopPolder =
SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder);
GeometryPoint ditchDikeSide =
SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DitchDikeSide);
GeometryPoint bottomDitchDikeSide =
SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.BottomDitchDikeSide);
GeometryPoint bottomDitchPolderSide =
SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.BottomDitchPolderSide);
GeometryPoint ditchPolderSide =
SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DitchPolderSide);
GeometryPoint surfaceLevelInside =
SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.SurfaceLevelInside);
// Height h is calculated at exit point of the inner plane (Low) : 9in = min (N; M + 5m)
var exitPointInnerPlane = new GeometryPoint();
double d = 0;
if (isDitchPresent)
{
exitPointInnerPlane.X = Math.Min(dikeToePolder.X + 5, ditchDikeSide.X);
exitPointInnerPlane.Z = surfaceLine.Geometry.GetZAtX(exitPointInnerPlane.X);
d = (ditchDikeSide.Z + ditchPolderSide.Z) / 2 - (bottomDitchDikeSide.Z + bottomDitchPolderSide.Z) / 2;
}
else
{
exitPointInnerPlane.X = dikeToePolder.X + 5;
exitPointInnerPlane.Z = surfaceLine.Geometry.GetZAtX(exitPointInnerPlane.X);
}
double h = exitPointInnerPlane.Z - GetTopPleistoceen(exitPointInnerPlane.X);
double bottom;
if (h < 2) // Case 3
{
bottom = dikeToePolder.Z - 5.0;
}
else // Cases 1 and 2
{
bottom = GetTopPleistoceen(exitPointInnerPlane.X) - 1;
}
// Determine the exit point (9out)
var exitPoint = new GeometryPoint();
if (h < 2) // case 3
{
exitPoint.X = Math.Min(dikeToePolder.X + 32.5, surfaceLevelInside.X - 0.01);
exitPoint.Z = surfaceLine.Geometry.GetZAtX(exitPoint.X);
}
else // h > 2 m
{
if ((!isDitchPresent) || (isDitchPresent && (h / d > 5))) // Case 2 (shallow ditch or no ditch)
{
exitPoint.X = Math.Min(dikeToePolder.X + 5.5 * (h + 1), surfaceLevelInside.X - 0.01);
exitPoint.Z = surfaceLine.Geometry.GetZAtX(exitPoint.X);
}
else // case 1: deep ditch (h / d < 5)
{
exitPoint.X = bottomDitchPolderSide.X;
exitPoint.Z = bottomDitchPolderSide.Z;
}
}
// Slope of the exit line
double finalSlope;
if (h < 2) // case 3
{
finalSlope = 2.5;
}
else
{
if (h / d < 5) // case 1
{
finalSlope = 1;
}
else // case 2
{
finalSlope = 2.5;
}
}
// Determine the intersection of the final slope and the vertical part
var intersection = new GeometryPoint();
intersection.X = dikeTopRiver.X;
intersection.Z = exitPoint.Z - (exitPoint.X - dikeTopRiver.X) / finalSlope;
bool isDeepPleistocene = intersection.Z >= bottom;
double vertLength;
if (!isDeepPleistocene)
{
vertLength = dikeTopRiver.Z - bottom;
}
else
{
vertLength = dikeTopRiver.Z - intersection.Z;
}
var vertSegmentLength = vertLength / 4;
// Entry point (1out) = intersection with line under 45 degrees starting at point 2out
var fictivePoint1 = new GeometryPoint(); // = point 2out
fictivePoint1.X = dikeTopRiver.X;
fictivePoint1.Z = dikeTopRiver.Z - vertSegmentLength;
var fictivePoint2 = new GeometryPoint();
fictivePoint2.X = fictivePoint1.X;
fictivePoint2.Z = fictivePoint1.Z;
while (fictivePoint2.Z <= surfaceLine.Geometry.GetMaxZ())
{
fictivePoint2.X = fictivePoint2.X - vertSegmentLength;
fictivePoint2.Z = fictivePoint2.Z + vertSegmentLength;
}
var obliqueLine = new Line(fictivePoint1, fictivePoint2);
GeometryPoint entryPoint = DetermineIntersectionBetweenDikeSlopeAtRiverAndAnObliqueLine(surfaceLine, obliqueLine);
outerSlipPlane.Points.Add(entryPoint);
if (!isDeepPleistocene)
{
// The 3 points on the vertical line
for (int i = 1; i < 4; i++)
{
var nextPoint = new GeometryPoint();
nextPoint.X = dikeTopRiver.X;
nextPoint.Z = dikeTopRiver.Z - i * vertSegmentLength;
outerSlipPlane.Points.Add(nextPoint);
}
// Point 8out
var point8out = new GeometryPoint();
point8out.Z = bottom;
point8out.X = exitPoint.X - finalSlope * (exitPoint.Z - point8out.Z);
// Point 6out
var point6out = new GeometryPoint();
var horLength = point8out.X - dikeTopRiver.X;
var horSegmLength = horLength / 3;
point6out.X = dikeTopRiver.X + horSegmLength;
point6out.Z = point8out.Z;
// Point 5out
var point5out = new GeometryPoint();
point5out.X = (point6out.X + dikeTopRiver.X) / 2;
point5out.Z = (point6out.Z + dikeTopRiver.Z - 3.0 * vertSegmentLength) / 2;
// Point 7out
var point7out = new GeometryPoint();
point7out.X = point6out.X + horSegmLength;
point7out.Z = point8out.Z;
outerSlipPlane.Points.Add(point5out);
outerSlipPlane.Points.Add(point6out);
outerSlipPlane.Points.Add(point7out);
outerSlipPlane.Points.Add(point8out);
outerSlipPlane.Points.Add(exitPoint);
}
// Other configuration (i.e. deep Pleistocene): Outer slip plane has no horizontal bottom part,
// but only a first vertical part and an oblique part
else
{
// The 4 points on the vertical line (2out to 5out)
for (int i = 1; i < 5; i++)
{
var nextPoint = new GeometryPoint();
nextPoint.X = dikeTopRiver.X;
nextPoint.Z = dikeTopRiver.Z - i * (dikeTopRiver.Z - intersection.Z) / 4;
outerSlipPlane.Points.Add(nextPoint);
}
// The 4 points on the final slope (6out to 9out)
for (int i = 1; i < 5; i++)
{
var nextPoint = new GeometryPoint();
nextPoint.X = intersection.X + i * (exitPoint.X - intersection.X) / 4;
nextPoint.Z = intersection.Z + i * (exitPoint.Z - intersection.Z) / 4;
outerSlipPlane.Points.Add(nextPoint);
}
}
outerSlipPlane = EnsureThatPointsOfTheSlipPlaneAreNotAboveSurfaceLine(outerSlipPlane);
DataEventPublisher.DataListModified(outerSlipPlane.Points);
}
private void CreateInwardSpencerOuterSlipPlaneHigh(GeometryPointString outerSlipPlane)
{
outerSlipPlane.Points.Clear();
GeometryPoint dikeTopRiver = SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver);
GeometryPoint dikeToePolder = SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder);
GeometryPoint bottomDitchPolderSide = SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.BottomDitchPolderSide);
GeometryPoint bottomDitchDikeSide = SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.BottomDitchDikeSide);
GeometryPoint surfaceLevelInside = SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.SurfaceLevelInside);
var exitPoint = new GeometryPoint();
bool isDitchPresent = IsDitchPresent();
// Entry point (1out)
GeometryPoint entryPoint = dikeTopRiver;
// Height h is calculated at DikeToeAtPolder
var h = dikeToePolder.Z - GetTopPleistoceen(dikeToePolder.X);
// If h is nul, the height between surface line and bottom boundary is used
if (h < Constants.CAlmostZero)
{
h = dikeToePolder.Z - profile2D.Geometry.Bottom;
}
// Exit point (9out) and level of the bottom part (6out to 8out)
double bottom;
if (isDitchPresent)
{
if (dikeToePolder.Z - 2 * h / 3 > bottomDitchDikeSide.Z || dikeToePolder.Z - 2 * h / 3 > bottomDitchPolderSide.Z)
{
exitPoint = bottomDitchDikeSide; // point O
bottom = bottomDitchDikeSide.Z; // point O
}
else
{
exitPoint = bottomDitchPolderSide; // point P
bottom = dikeToePolder.Z - 2 * h / 3;
}
}
else
{
exitPoint.X = Math.Min(dikeToePolder.X + 20.0, surfaceLevelInside.X - 0.01);
exitPoint.Z = surfaceLine.Geometry.GetZAtX(exitPoint.X);
bottom = Math.Min(exitPoint.Z, dikeToePolder.Z - 2 * h / 3);
}
// determine corner point: intersection point between line 1 (vertical) and the horizontal line
var cornerPoint = new GeometryPoint();
var vertLength = entryPoint.Z - bottom;
var vertSegmentLength = vertLength / 4;
cornerPoint.X = entryPoint.X;
cornerPoint.Z = entryPoint.Z - 4 * vertSegmentLength;
outerSlipPlane.Points.Add(entryPoint);
// Determine the intersection of the final slope and the vertical part
var intersection = new GeometryPoint();
intersection.Z = exitPoint.Z - (exitPoint.X - entryPoint.X);
bool isDeepPleistocene = intersection.Z >= bottom;
// Normal configuration: Outer slip plane has an horizontal bottom part
if (!isDeepPleistocene)
{
// The 4 points on the first (vertical) line
for (int i = 1; i < 4; i++)
{
var nextPoint = new GeometryPoint();
nextPoint.X = entryPoint.X;
nextPoint.Z = entryPoint.Z - i * vertSegmentLength;
outerSlipPlane.Points.Add(nextPoint);
}
// Point 8out
var point8out = new GeometryPoint();
if (Math.Abs(exitPoint.Z - bottom) < Constants.CGeoAccu)
{
point8out.X = exitPoint.X - (exitPoint.X - entryPoint.X) / 4;
}
else
{
point8out.X = exitPoint.X - (exitPoint.Z - bottom); // last part has a slope 1:1
}
point8out.Z = bottom;
// Point 6out
var point6out = new GeometryPoint();
var horLength = point8out.X - entryPoint.X;
var horSegmLength = horLength / 3;
point6out.X = entryPoint.X + horSegmLength;
point6out.Z = bottom;
// Point 5out
var point5out = new GeometryPoint();
point5out.X = entryPoint.X + horSegmLength / 2;
point5out.Z = bottom + vertSegmentLength / 2;
// Point 7out
var point7out = new GeometryPoint();
point7out.X = point6out.X + horSegmLength;
point7out.Z = bottom;
outerSlipPlane.Points.Add(point5out);
outerSlipPlane.Points.Add(point6out);
outerSlipPlane.Points.Add(point7out);
outerSlipPlane.Points.Add(point8out);
outerSlipPlane.Points.Add(exitPoint);
}
// Other configuration (i.e. deep Pleistocene): Outer slip plane has no horizontal bottom part, but only a first vertical part and an oblique part with slope 1:1
else
{
// The 5 points on the first vertical line (= points 1out to 5out included)
for (int i = 1; i < 5; i++)
{
var nextPoint = new GeometryPoint();
nextPoint.X = entryPoint.X;
nextPoint.Z = entryPoint.Z - i * (entryPoint.Z - intersection.Z) / 4;
outerSlipPlane.Points.Add(nextPoint);
}
double vertSegmentLengthForLastSlope = (exitPoint.Z - intersection.Z) / 4;
// The 4 last points (i.e. 6out to 9out)
for (int i = 1; i < 5; i++)
{
var nextPoint = new GeometryPoint();
nextPoint.X = entryPoint.X + i * vertSegmentLengthForLastSlope;
nextPoint.Z = intersection.Z + i * vertSegmentLengthForLastSlope;
outerSlipPlane.Points.Add(nextPoint);
}
}
outerSlipPlane = EnsureThatPointsOfTheSlipPlaneAreNotAboveSurfaceLine(outerSlipPlane);
DataEventPublisher.DataListModified(outerSlipPlane.Points);
}
///
/// If points of the Spencer slip plane are above the surface line, they are shifted 10 cm below the surface line
///
/// Slip plane
/// Updated slip plane
private GeometryPointString EnsureThatPointsOfTheSlipPlaneAreNotAboveSurfaceLine(GeometryPointString slipPlane)
{
foreach (var points in slipPlane.Points)
{
double surfaceLevel = surfaceLine.Geometry.GetZAtX(points.X);
if (points.Z - surfaceLevel > Constants.CGeoAccu)
{
points.Z = surfaceLevel - 0.1;
}
}
return slipPlane;
}
private void UpdateSpencerGA(StabilityModel model)
{
GeometryPoint dikeTopRiver = SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver);
GeometryPoint dikeTopPolder = SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver);
double xMiddleDike = (dikeTopPolder.X + dikeTopRiver.X) / 2;
if (!double.IsNaN(GetTopPleistoceen(xMiddleDike)))
{
if (model.IsHighSlipPlanes)
{
CreateInwardSpencerPlanesHigh(model);
}
else
{
CreateInwardSpencerPlanesLow(model);
}
}
}
private void CreateInwardSpencerPlanesHigh(StabilityModel model)
{
CreateSlipPlanes(model);
CreateInwardSpencerInnerSlipPlaneHigh(model.SlipPlanes[0]);
CreateInwardSpencerOuterSlipPlaneHigh(model.SlipPlanes[1]);
}
private void CreateSlipPlanes(StabilityModel model)
{
while (model.SlipPlanes.Count < 2)
{
model.CreateSlipPlane(new List(), true);
}
}
private void CreateInwardSpencerPlanesLow(StabilityModel model)
{
CreateSlipPlanes(model);
CreateInwardSpencerInnerSlipPlaneLow(model.SlipPlanes[0]);
CreateInwardSpencerOuterSlipPlaneLow(model.SlipPlanes[1]);
}
///
/// Finds the intersection point of a given horizontal line and the river side talud.
///
/// The evaluated surfaceline.
/// The oblique line.
/// The intersection point, or null in case no intersection was found.
private static GeometryPoint DetermineIntersectionBetweenDikeSlopeAtRiverAndAnObliqueLine(SurfaceLine2 surfaceLine, Line obliqueLine)
{
var list = surfaceLine.Geometry.Points.Where(point =>
point.X >= surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.SurfaceLevelOutside).X &&
point.X <= surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver).X).ToList();
list.Insert(0, surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.SurfaceLevelOutside));
list.Add(surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver));
list.Sort();
for (int i = 1; i < list.Count; i++)
{
var surfaceLineSegment = new Line();
surfaceLineSegment.SetBeginAndEndPoints(
new GeometryPoint(list[i - 1].X, 0, list[i - 1].Z),
new GeometryPoint(list[i].X, 0, list[i].Z));
var intersectPoint = surfaceLineSegment.GetIntersectPointXZ(obliqueLine);
if (intersectPoint != null)
{
return GeometryPoint.CreateNewXZPoint(intersectPoint.X, intersectPoint.Z);
}
}
return null;
}
private void ResetSlipPlanes(StabilityModel stabilityModel)
{
stabilityModel.SlipPlanes.Clear();
stabilityModel.SlipPlanes.Add(new SlipPlane
{
Name = LocalizationManager.GetTranslatedText(typeof(StabilityDikeLocationInfo), "SlipPlane")
}); // One empty slip plane is expected to be present by default
}
///
/// Search the X coordinate at which the uplift ends, starting the search at Dike Toe At Polder with an increment of 50 cm.
/// If uplift does not occurs, this procedure returns the X coordinate at Surface Level Inside.
///
/// X coordinate at which uplift ends
private double SearchXcoordinateOfEndOfUpliftAtPolderSide()
{
const double searchUpliftIncrement = 0.5;
double xStart = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder).X;
double xLast = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.SurfaceLevelInside).X;
bool isUplift = false;
var upliftCalculator = new UpliftCalculator();
upliftCalculator.SoilProfile2D = profile2D;
upliftCalculator.Waternet = waternet;
// First search at which X coordinate uplift starts
while ((!isUplift) && ((xStart + searchUpliftIncrement) < xLast))
{
xStart += searchUpliftIncrement;
double upliftPotential = upliftCalculator.DetermineUpliftPotentialAtXAtTopOfHighestAquiferFromA2DProfile(xStart);
isUplift = (upliftPotential < 1.0);
}
// If no uplift occurs, return the X coordinate at Surface Level Inside.
if (isUplift == false)
{
return xLast;
}
// If uplift occurs, search the X coordinate at which uplift ends
while ((isUplift) && ((xStart + searchUpliftIncrement) < xLast))
{
xStart += searchUpliftIncrement;
double upliftPotential = upliftCalculator.DetermineUpliftPotentialAtXAtTopOfHighestAquiferFromA2DProfile(xStart);
isUplift = (upliftPotential < 1.0);
}
return xStart;
}
}
}