using System; using System.Collections.Generic; using Deltares.Geometry; using Deltares.Mathematics; using Deltares.Standard; namespace Deltares.Stability.Calculation2 { public class GeneticAlgorithmFreePlaneCalculation : SlidingCurvesProcessor, IExtremeCalculation { private List calculationSequence = new List(); private bool genCalculated = false; private GeneticAlgorithm geneticAlgorithm = new GeneticAlgorithm(); private GeometryPointString innerSlipPlane; private bool isLMCalculation; private bool isSinglePlanecalculation; private Stability.Calculation2.Levenberg.LevenbergMarquardtExtreme levenbergMarquardtExtreme = new Stability.Calculation2.Levenberg.LevenbergMarquardtExtreme(); private double[] mingenome; private SlidingCurve minimumSlidingCurve = null; private GeometryPointString outerSlipPlane; private GeometryPointString surfaceLine; public GeneticAlgorithmFreePlaneCalculation(StabilityModel stabilityModel) { if (stabilityModel.SlipPlanes.Count > 1) { isSinglePlanecalculation = false; if (stabilityModel.SlipPlanes[0].Points[0].X < stabilityModel.SlipPlanes[1].Points[0].X) { innerSlipPlane = stabilityModel.SlipPlanes[1]; outerSlipPlane = stabilityModel.SlipPlanes[0]; } else { innerSlipPlane = stabilityModel.SlipPlanes[0]; outerSlipPlane = stabilityModel.SlipPlanes[1]; } } else { if (stabilityModel.SlipPlanes.Count == 1) { innerSlipPlane = stabilityModel.SlipPlanes[0]; outerSlipPlane = stabilityModel.SlipPlanes[0]; isSinglePlanecalculation = true; } } } public List CalculationSequence { get { return calculationSequence; } } public bool IsLMCalculation { get { return isLMCalculation; } set { isLMCalculation = value; } } public GeometryPointString SurfaceLine { get { return surfaceLine; } set { surfaceLine = value; } } public override void Initialize(StabilityModel stabilityModel) { base.Initialize(stabilityModel); TBounds bounds; surfaceLine = stabilityModel.GeometryData.SurfaceLine; levenbergMarquardtExtreme.LevenbergMarquardtOptions = stabilityModel.LevenbergMarquardtOptions; levenbergMarquardtExtreme.ParameterCount = innerSlipPlane.Points.Count; levenbergMarquardtExtreme.VariableCount = innerSlipPlane.Points.Count; levenbergMarquardtExtreme.IterationCount = 100; levenbergMarquardtExtreme.Shift = 0.01; levenbergMarquardtExtreme.DriftGrant = 0.01; levenbergMarquardtExtreme.LambdaLower = 1; levenbergMarquardtExtreme.LambdaUpper = 4096; levenbergMarquardtExtreme.LambdaBoost = 4; for (int genIndex = 0; genIndex < levenbergMarquardtExtreme.ParameterCount; genIndex++) { bounds.Min = 0; bounds.Inc = 1; levenbergMarquardtExtreme.SetBounds(genIndex, bounds); } levenbergMarquardtExtreme.LevenbergMarquardtCalculation = this; geneticAlgorithm.GeneticAlgorithmOptions = stabilityModel.GeneticAlgorithmOptions; geneticAlgorithm.InitializePopulationMethod = InitializePopulationMethod.Parabolic; geneticAlgorithm.CrossOverRandomFrequency = RandomFrequency.Never; geneticAlgorithm.MutationRandomFrequency = RandomFrequency.Never; // { Set the bounds for the genetic algorithm } geneticAlgorithm.GenomeCount = innerSlipPlane.Points.Count; for (int genIndex = 0; genIndex < geneticAlgorithm.GenomeCount; genIndex++) { bounds.Min = 0; bounds.Inc = 1; geneticAlgorithm.SetBounds(genIndex, bounds); } // Communicate the address of the calculation geneticAlgorithm.GeneticCalculation = this; minimumSlidingCurve = null; } public override SlidingCurve Calculate() { minimumSlidingCurve = null; if (isSinglePlanecalculation) { minimumSlidingCurve = SingleSpencer(); } else { genCalculated = false; for (int i = 0; i < calculationSequence.Count; i++) { if (calculationSequence[i] == SearchAlgorithm.LevenbergMarquardt) { isLMCalculation = true; if (genCalculated) { for (int j = 0; j < levenbergMarquardtExtreme.ParameterCount; j++) { levenbergMarquardtExtreme.Parameters[j] = mingenome[j]; } } levenbergMarquardtExtreme.Calculation(); } if (calculationSequence[i] == SearchAlgorithm.Genetic) { isLMCalculation = false; geneticAlgorithm.Calculation(); genCalculated = true; } } } return minimumSlidingCurve; } public double ComputeExtremeResult(double[] genome) { SlidingPlane spencerPlane = CreateSlipPoints(genome); double stabilityFactor = GetSafetyFactor(spencerPlane); if (minimumSlidingCurve == null || stabilityFactor < minimumSlidingCurve.SafetyFactor) { mingenome = genome; if (stabilityFactor != Double.MaxValue) { minimumSlidingCurve = spencerPlane; } } return stabilityFactor; } private GeometryPoint SurfacePointsDetermination(GeometryPoint minPoint, GeometryPoint maxPoint, double intervalRatio) { // determine distance on surface betwee the two points double distance = MStabDatafunctions.GetSignedDistanceOnBoundary(minPoint, maxPoint, surfaceLine); //Get the requested distance double deltaDistance = distance * intervalRatio; var newPoint = new GeometryPoint(); // create a point at the requested distance MStabDatafunctions.GetPointOnBoundaryAtDistance(ref newPoint, minPoint, deltaDistance, surfaceLine); return newPoint; } private GeometryPoint GetIntervalPoint(GeometryPoint outerPoint, GeometryPoint innerPoint, double intervalRatio) { double x = outerPoint.X + intervalRatio * (innerPoint.X - outerPoint.X); double z = outerPoint.Z + intervalRatio * (innerPoint.Z - outerPoint.Z); return new GeometryPoint(x, 0, z); } private void ForceAscendingPositions(SlidingPlane spencerPlane, double[] genome) { // Mirror positions in case of reverse geometry List slipSpencer = spencerPlane.SpencerSlipPlane; int lastCorrectIndex = 0; int nextCorrectIndex = slipSpencer.Count - 1; double lastCorrectX = slipSpencer[0].X; double nextCorrectX = slipSpencer[slipSpencer.Count - 1].X; // Correct x values beyond the last point for (int i = 1; i < slipSpencer.Count - 1; i++) { if (slipSpencer[i].X + Slice.CMinSliceWidth >= slipSpencer[slipSpencer.Count - 1].X) { double newX = lastCorrectX + (nextCorrectX - lastCorrectX) * (i - lastCorrectIndex) / (nextCorrectIndex - lastCorrectIndex); genome[i] = AdaptPosition(newX, innerSlipPlane.Points[i], outerSlipPlane.Points[i], slipSpencer[i], i == 0 || i == slipSpencer.Count - 1); } else { lastCorrectIndex = i; lastCorrectX = slipSpencer[i].X; } } // Correct x values which are smaller than the previous x lastCorrectIndex = 0; nextCorrectIndex = 0; lastCorrectX = slipSpencer[0].X; nextCorrectX = double.NaN; for (int i = 1; i < slipSpencer.Count - 1; i++) { if (slipSpencer[i].X < lastCorrectX) { if (nextCorrectIndex <= i) { // Find the next correct x for (int j = i + 1; j < slipSpencer.Count; j++) { if (slipSpencer[j].X >= lastCorrectX) { nextCorrectIndex = j; nextCorrectX = slipSpencer[j].X; break; } } } double newX = lastCorrectX + (nextCorrectX - lastCorrectX) * (i - lastCorrectIndex) / (nextCorrectIndex - lastCorrectIndex); // Adapt position and level to the changed gen value genome[i] = AdaptPosition(newX, innerSlipPlane.Points[i], outerSlipPlane.Points[i], slipSpencer[i], i == 0 || i == slipSpencer.Count - 1); } else { lastCorrectIndex = i; lastCorrectX = slipSpencer[i].X; } } } private double AdaptPosition(double newX, GeometryPoint innerPoint, GeometryPoint outerPoint, Point2D point, bool isBoundaryPoint) { double innerValueX = innerPoint.X; double outerValueX = outerPoint.X; double newGenome = (newX - outerValueX) / (innerValueX - outerValueX); newGenome = Math.Min(Math.Max(SpencerCalculation.CBoundsMin, newGenome), SpencerCalculation.CBoundsMin + SpencerCalculation.CBoundsInc); point.X = outerValueX + newGenome * (innerValueX - outerValueX); if (isBoundaryPoint) { point.Y = surfaceLine.GetZAtX(point.X); } else { double innerValueZ = innerPoint.Z; double outerValueZ = outerPoint.Z; point.Y = outerValueZ + newGenome * (innerValueZ - outerValueZ); } return newGenome; } /// /// Creates a sliding curve based on the genome. Ensures that the sliding plane is valid /// /// /// This method is public only for unit testing /// /// Genome values /// Sliding plane public SlidingPlane CreateSlipPoints(double[] genome) { int slipPointCount = innerSlipPlane.Points.Count; SlidingPlane spencerPlane = new SlidingPlane(); double[] intervalRatio = genome; // Entrance surface starting from left to right GeometryPoint surfacePoint = SurfacePointsDetermination(innerSlipPlane.Points[0], outerSlipPlane.Points[0], intervalRatio[0]); if (surfacePoint != null) { spencerPlane.SpencerSlipPlane.Add(surfacePoint.GetPointXz()); } // Enclosed area for (int i = 1; i < slipPointCount - 1; i++) { GeometryPoint soilPoint = GetIntervalPoint(innerSlipPlane.Points[i], outerSlipPlane.Points[i], intervalRatio[i]); if (soilPoint != null) { spencerPlane.SpencerSlipPlane.Add(soilPoint.GetPointXz()); } } // Exit surface the minimum x el is now at the outerplane surfacePoint = SurfacePointsDetermination(outerSlipPlane.Points[slipPointCount - 1], innerSlipPlane.Points[slipPointCount - 1], 1 - intervalRatio[slipPointCount - 1]); if (surfacePoint != null) { spencerPlane.SpencerSlipPlane.Add(surfacePoint.GetPointXz()); } // The positions of the free slipcircle must be ascending. Correct in case of genetic algorithm ForceAscendingPositions(spencerPlane, genome); return spencerPlane; } private SlidingPlane SingleSpencer() { SlidingPlane spencerPlane = new SlidingPlane(); for (int i = 0; i < innerSlipPlane.Points.Count; i++) { spencerPlane.SpencerSlipPlane.Add(new Point2D(innerSlipPlane.Points[i].X, innerSlipPlane.Points[i].Z)); } GetSafetyFactor(spencerPlane); return spencerPlane; } } }