using System; using System.Collections.Generic; using System.Data; using System.Linq; using Deltares.DamEngine.Calculators.Properties; using Deltares.DamEngine.Data.General; using Deltares.DamEngine.Data.General.PlLines; using Deltares.DamEngine.Data.Geometry; using Deltares.DamEngine.Data.Geotechnics; using Deltares.DamEngine.Data.Standard; namespace Deltares.DamEngine.Calculators.KernelWrappers.MacroStabilityCommon { public static class PlLinesToWaternetConverter { /// /// Converts the pl lines to a waternet. /// /// The pl lines. /// The 1D soil profile. /// Length of the penetration. /// Left side of the 2D profile. /// Right side of the 2D profile. /// public static Waternet ConvertPlLineToWaternet(PlLines plLines, SoilProfile1D soilProfile1D, double penetrationLength, double xLeft, double xRight) { ThrowWhenPlLinesIsNull(plLines); ThrowWhenSoilProfileIsNull(soilProfile1D); var waternet = new Waternet { IsGenerated = false }; PlLine plLine = plLines.Lines[PlLineType.Pl1]; if (plLine != null && !IsBelowSoilProfile(soilProfile1D, plLine)) { waternet.PhreaticLine = CreateLine(plLine); waternet.PhreaticLine.SyncCalcPoints(); } plLine = plLines.Lines[PlLineType.Pl2]; var headLine = CreateLine(plLine); if (headLine != null && !IsBelowSoilProfile(soilProfile1D, plLine)) { waternet.HeadLineList.Add(headLine); if (soilProfile1D.BottomAquiferLayer != null) { var level = soilProfile1D.BottomAquiferLayer.TopLevel + penetrationLength; var waternetLine = CreateWaternetLine(level, xLeft, xRight); waternetLine.HeadLine = headLine; waternetLine.HeadLine.SyncCalcPoints(); waternet.WaternetLineList.Add(waternetLine); } } plLine = plLines.Lines[PlLineType.Pl3]; headLine = CreateLine(plLine); if (headLine != null && !IsBelowSoilProfile(soilProfile1D, plLine)) { waternet.HeadLineList.Add(headLine); if (soilProfile1D.BottomAquiferLayer != null) { var level = soilProfile1D.BottomAquiferLayer.TopLevel; var waternetLine = CreateWaternetLine(level, xLeft, xRight); waternetLine.HeadLine = headLine; waternetLine.HeadLine.SyncCalcPoints(); waternet.WaternetLineList.Add(waternetLine); } } plLine = plLines.Lines[PlLineType.Pl4]; headLine = CreateLine(plLine); if (headLine != null && !IsBelowSoilProfile(soilProfile1D, plLine)) { waternet.HeadLineList.Add(headLine); if (soilProfile1D.InBetweenAquiferLayer != null) { var level = soilProfile1D.InBetweenAquiferLayer.TopLevel; var waternetLine = CreateWaternetLine(level, xLeft, xRight); waternetLine.HeadLine = headLine; waternetLine.HeadLine.SyncCalcPoints(); waternet.WaternetLineList.Add(waternetLine); } } return waternet; } /// /// Converts the to a based on a 2D profile. /// /// The to convert. /// The to convert the with. /// The penetration length. /// A . /// Thrown when or /// is null. public static Waternet ConvertPlLineToWaternet(PlLines plLines, SoilProfile2D soilProfile, double penetrationLength) { ThrowWhenPlLinesIsNull(plLines); ThrowWhenSoilProfileIsNull(soilProfile); // Get all the xCoordinates to make cross sections IEnumerable points = soilProfile.Surfaces.SelectMany(surf => surf.GeometrySurface.OuterLoop.CalcPoints); var xCoordinates = points.Select(point => point.X).OrderBy(x => x).Distinct().ToArray(); var bottomAquiferCoordinates = GetAquiferCoordinates(sp => sp.BottomAquiferLayer, xCoordinates, soilProfile).ToArray(); var inBetweenAquiferCoordinates = GetAquiferCoordinates(sp => sp.InBetweenAquiferLayer, xCoordinates, soilProfile).ToArray(); var waternet = new Waternet(); PlLine plLine = plLines.Lines[PlLineType.Pl1]; if (plLine != null) { waternet.PhreaticLine = CreateLine(plLine); } plLine = plLines.Lines[PlLineType.Pl2]; if (plLine != null) { var headLine = CreateLine(plLine); waternet.HeadLineList.Add(headLine); if (bottomAquiferCoordinates.Any()) { WaternetLine waternetLine = CreateWaternetLine(bottomAquiferCoordinates, penetrationLength); waternetLine.HeadLine = headLine; waternet.WaternetLineList.Add(waternetLine); } } plLine = plLines.Lines[PlLineType.Pl3]; if (plLine != null) { var headLine = CreateLine(plLine); waternet.HeadLineList.Add(headLine); if (bottomAquiferCoordinates.Any()) { WaternetLine waternetLine = CreateWaternetLine(bottomAquiferCoordinates); waternetLine.HeadLine = headLine; waternet.WaternetLineList.Add(waternetLine); } } plLine = plLines.Lines[PlLineType.Pl4]; if (plLine != null) { var headLine = CreateLine(plLine); waternet.HeadLineList.Add(headLine); if (inBetweenAquiferCoordinates.Any()) { WaternetLine waternetLine = CreateWaternetLine(inBetweenAquiferCoordinates); waternetLine.HeadLine = headLine; waternet.WaternetLineList.Add(waternetLine); } } return waternet; } private static TLineType CreateLine(PlLine plLine) where TLineType : GeometryPointString, new() { if (plLine == null || !plLine.Points.Any()) { return null; } var line = new TLineType(); line.Points.AddRange(plLine.Points); return line; } internal static WaternetLine CreateWaternetLine(double level, double xLeft, double xRight) { WaternetLine waternetLine = new WaternetLine(); waternetLine.Points.Add(new GeometryPoint(xLeft, level)); waternetLine.Points.Add(new GeometryPoint(xRight, level)); waternetLine.SyncCalcPoints(); return waternetLine; } private static WaternetLine CreateWaternetLine(IEnumerable coordinates) { return CreateWaternetLine(coordinates, 0); } private static WaternetLine CreateWaternetLine(IEnumerable coordinates, double zOffSet) { var line = new WaternetLine(); foreach (Point2D coordinate in coordinates) { var point = new GeometryPoint(coordinate.X, coordinate.Z + zOffSet); line.Points.Add(point); } line.SyncCalcPoints(); return line; } private static IEnumerable GetAquiferCoordinates(Func getSoilLayerFunc, IEnumerable xCoordinates, SoilProfile2D soilProfile) { SoilLayer1D previousAquiferLayer = null; var coordinates = new List(); foreach (double xCoordinate in xCoordinates) { SoilProfile1D crossSection = soilProfile.GetSoilProfile1D(xCoordinate); // Determine if the bottom aquifer layer is in range of the previous aquifer layer // If not, return empty coordinates, because the aquifer layer is interrupted SoilLayer1D currentAquifer = getSoilLayerFunc(crossSection); if (previousAquiferLayer != null && currentAquifer != null && !AreHorizontallyConnected(previousAquiferLayer, currentAquifer)) { return Enumerable.Empty(); } if (currentAquifer != null) { previousAquiferLayer = currentAquifer; coordinates.Add(new Point2D(xCoordinate, currentAquifer.TopLevel)); } } // Perform a short validation that the coordinates are fully defined from the beginning to the end // of the profile. If not, the aquifer is not continuous. if (!coordinates.Any() || coordinates.First().X != xCoordinates.First() || coordinates.Last().X != xCoordinates.Last()) { return Enumerable.Empty(); } return coordinates; } private static bool AreHorizontallyConnected(SoilLayer1D leftSoilLayer, SoilLayer1D rightSoilLayer) { // The layers are identical if (ReferenceEquals(leftSoilLayer, rightSoilLayer)) { return true; } // Left soil layer envelopes whole right soil layer if (leftSoilLayer.BottomLevel <= rightSoilLayer.BottomLevel && leftSoilLayer.TopLevel >= rightSoilLayer.TopLevel) { return true; } // Right soil layer envelopes whole left soil layer if (rightSoilLayer.BottomLevel <= leftSoilLayer.BottomLevel && rightSoilLayer.TopLevel >= leftSoilLayer.TopLevel) { return true; } return (rightSoilLayer.TopLevel <= leftSoilLayer.TopLevel && rightSoilLayer.TopLevel >= leftSoilLayer.BottomLevel) // Top level lies inbetween the left soil layer || (rightSoilLayer.BottomLevel >= leftSoilLayer.BottomLevel && rightSoilLayer.BottomLevel <= leftSoilLayer.TopLevel); // Bottom level lies inbetween the left soil layer } private static bool IsBelowSoilProfile(SoilProfile1D soilProfile, PlLine line) { double bottomSoilProfileLevel = soilProfile.BottomLevel; return line.Points.Any(point => point.Z <= bottomSoilProfileLevel); } /// /// Throws when the soil profile is not assigned. /// /// The soil profile. /// private static void ThrowWhenSoilProfileIsNull(SoilProfile soilProfile) { if (soilProfile == null) { throw new NoNullAllowedException(Resources.PlLinesToWaternetConverter_NoSoilProfileDefined); } } /// /// Throws when the pl lines object is not assigned. /// /// The pl lines. /// private static void ThrowWhenPlLinesIsNull(PlLines plLines) { if (plLines == null) { throw new NoNullAllowedException(Resources.PlLinesToWaternetConverter_NoPlLinesDefined); } } } }