Index: DamEngine/trunk/src/Deltares.DamEngine.Calculators.Tests/KernelWrappers/MacroStabilityCommon/PlLinesToWaternetConverterTests.cs =================================================================== diff -u -r2962 -r2971 --- DamEngine/trunk/src/Deltares.DamEngine.Calculators.Tests/KernelWrappers/MacroStabilityCommon/PlLinesToWaternetConverterTests.cs (.../PlLinesToWaternetConverterTests.cs) (revision 2962) +++ DamEngine/trunk/src/Deltares.DamEngine.Calculators.Tests/KernelWrappers/MacroStabilityCommon/PlLinesToWaternetConverterTests.cs (.../PlLinesToWaternetConverterTests.cs) (revision 2971) @@ -1,8 +1,12 @@ using System; +using System.Collections.Generic; using System.Data; +using System.Linq; using Deltares.DamEngine.Data.General; using Deltares.DamEngine.Data.General.PlLines; using Deltares.DamEngine.Calculators.KernelWrappers.MacroStabilityCommon; +using Deltares.DamEngine.Calculators.Tests.KernelWrappers.TestHelpers; +using Deltares.DamEngine.Data.Geometry; using Deltares.DamEngine.Data.Geotechnics; using NUnit.Framework; @@ -203,12 +207,148 @@ } [Test] + [TestCaseSource(nameof(GetSoilProfilesWithContinuousBottomAquiferLayer))] + public void ConvertPlLineToWaternet_ValidPLLinesAndSoilProfile2DWithContinuousAquiferLayers_ReturnsExpectedWaternet( + SoilProfile2D soilProfile, IEnumerable expectedBottomAquiferCoordinates) + { + // Setup + var random = new Random(21); + double leftCoordinate = soilProfile.Geometry.Left; + double rightCoordinate = soilProfile.Geometry.Right; + double penetrationLength = random.NextDouble(); + + var plLines = new PlLines(); + PlLine plLine = plLines.Lines[PlLineType.Pl1]; + plLine.Points.Add(new PlLinePoint(leftCoordinate, -5)); + plLine.Points.Add(new PlLinePoint(rightCoordinate, -5)); + + plLine = plLines.Lines[PlLineType.Pl2]; + plLine.Points.Add(new PlLinePoint(leftCoordinate, -6)); + plLine.Points.Add(new PlLinePoint(rightCoordinate, -6)); + + plLine = plLines.Lines[PlLineType.Pl3]; + plLine.Points.Add(new PlLinePoint(leftCoordinate, -7)); + plLine.Points.Add(new PlLinePoint(rightCoordinate, -7)); + + plLine = plLines.Lines[PlLineType.Pl4]; + plLine.Points.Add(new PlLinePoint(leftCoordinate, -8)); + plLine.Points.Add(new PlLinePoint(rightCoordinate, -8)); + + // Call + Waternet waternet = PlLinesToWaternetConverter.ConvertPlLineToWaternet(plLines, soilProfile, penetrationLength, leftCoordinate, rightCoordinate); + + // Assert + AssertGeometry(plLines.Lines[PlLineType.Pl1].Points, waternet.PhreaticLine.Points); + + AssertGeometry(plLines.Lines[PlLineType.Pl2].Points, waternet.HeadLineList[0].Points); + AssertGeometry(plLines.Lines[PlLineType.Pl3].Points, waternet.HeadLineList[1].Points); + AssertGeometry(plLines.Lines[PlLineType.Pl4].Points, waternet.HeadLineList[2].Points); + + Assert.AreEqual(2, waternet.WaternetLineList.Count); + + WaternetLine pl2WaternetLine = waternet.WaternetLineList[0]; + Assert.AreSame(waternet.HeadLineList[0], pl2WaternetLine.HeadLine); + var offSetAquiferCoordinates = expectedBottomAquiferCoordinates.Select(aquiferCoordinate => new GeometryPoint(aquiferCoordinate.X, aquiferCoordinate.Z + penetrationLength)) + .ToArray(); + AssertGeometry(offSetAquiferCoordinates, pl2WaternetLine.Points); + + WaternetLine pl3WaternetLine = waternet.WaternetLineList[1]; + Assert.AreSame(waternet.HeadLineList[1], pl3WaternetLine.HeadLine); + AssertGeometry(expectedBottomAquiferCoordinates, pl3WaternetLine.Points); + } + + [Test] + public void ConvertPlLineToWaternet_ValidPLLinesAndSoilProfile2DWithDiscontinuousBottomAquiferLayer_ReturnsExpectedWaternet() + { + // Setup + var random = new Random(21); + double leftCoordinate = random.NextDouble(); + double rightCoordinate = leftCoordinate + 1; + double penetrationLength = random.NextDouble(); + + var pointOne = new Point2D(leftCoordinate, 0); + var pointTwo = new Point2D(rightCoordinate, 0); + var pointThree = new Point2D(leftCoordinate, -10); + var pointFour = new Point2D(rightCoordinate, -10); + SoilLayer2D soilLayer = CreateSoilLayer2D(pointOne, pointTwo, pointThree, pointFour); + + var pointFive = new Point2D(rightCoordinate / 2, -10); + var pointSix = new Point2D(rightCoordinate / 2, -20); + var pointSeven = new Point2D(leftCoordinate, -20); + SoilLayer2D soilLayerAquiferPartOne = CreateSoilLayer2D(pointThree, pointFive, pointSix, pointSeven); + soilLayerAquiferPartOne.IsAquifer = true; + + var pointEight = new Point2D(rightCoordinate, -5); + var pointNine = new Point2D(rightCoordinate, -9); + var pointTen = new Point2D(rightCoordinate / 2, -5); + var pointEleven = new Point2D(rightCoordinate / 2, -9); + SoilLayer2D soilLayerAquiferPartTwo = CreateSoilLayer2D(pointTen, pointEight, pointNine, pointEleven); + soilLayerAquiferPartTwo.IsAquifer = true; + + var soilProfile = new SoilProfile2D + { + Geometry = new GeometryData + { + Left = leftCoordinate, + Right = rightCoordinate, + Bottom = -20 + } + }; + soilProfile.Surfaces.Add(soilLayer); + soilProfile.Surfaces.Add(soilLayerAquiferPartOne); + soilProfile.Surfaces.Add(soilLayerAquiferPartTwo); + + var plLines = new PlLines(); + PlLine plLine = plLines.Lines[PlLineType.Pl1]; + plLine.Points.Add(new PlLinePoint(leftCoordinate, -5)); + plLine.Points.Add(new PlLinePoint(rightCoordinate, -5)); + + plLine = plLines.Lines[PlLineType.Pl2]; + plLine.Points.Add(new PlLinePoint(leftCoordinate, -6)); + plLine.Points.Add(new PlLinePoint(rightCoordinate, -6)); + + plLine = plLines.Lines[PlLineType.Pl3]; + plLine.Points.Add(new PlLinePoint(leftCoordinate, -7)); + plLine.Points.Add(new PlLinePoint(rightCoordinate, -7)); + + plLine = plLines.Lines[PlLineType.Pl4]; + plLine.Points.Add(new PlLinePoint(leftCoordinate, -8)); + plLine.Points.Add(new PlLinePoint(rightCoordinate, -8)); + + // Call + Waternet waternet = PlLinesToWaternetConverter.ConvertPlLineToWaternet(plLines, soilProfile, penetrationLength, leftCoordinate, rightCoordinate); + + // Assert + AssertGeometry(plLines.Lines[PlLineType.Pl1].Points, waternet.PhreaticLine.Points); + + AssertGeometry(plLines.Lines[PlLineType.Pl2].Points, waternet.HeadLineList[0].Points); + AssertGeometry(plLines.Lines[PlLineType.Pl3].Points, waternet.HeadLineList[1].Points); + AssertGeometry(plLines.Lines[PlLineType.Pl4].Points, waternet.HeadLineList[2].Points); + + CollectionAssert.IsEmpty(waternet.WaternetLineList); + } + + private static void AssertGeometry(IEnumerable expectedPoints, IEnumerable actualPoints) + { + int expectedNrOfPoints = expectedPoints.Count(); + Assert.AreEqual(expectedNrOfPoints, actualPoints.Count()); + + for (int i = 0; i < expectedNrOfPoints; i++) + { + GeometryPoint expectedPoint = expectedPoints.ElementAt(i); + GeometryPoint actualPoint = actualPoints.ElementAt(i); + Assert.AreEqual(expectedPoint.X, actualPoint.X); + Assert.AreEqual(expectedPoint.Z, actualPoint.Z); + } + } + + [Test] [ExpectedException(typeof(NoNullAllowedException), ExpectedMessage = "Geen 1D ondergrond profiel gedefinieerd")] [SetUICulture("nl-NL")] public void TestLanguageNLThrowsExceptionWhenSoilProfile1DIsNull() { var plLines = new PlLines(); - PlLinesToWaternetConverter.ConvertPlLineToWaternet(plLines, null, 0, 0, 0); + PlLinesToWaternetConverter.ConvertPlLineToWaternet(plLines,(SoilProfile1D) null, 0, 0, 0); } [Test] @@ -339,5 +479,199 @@ return soilProfile1D; } + + private static IEnumerable GetSoilProfilesWithContinuousBottomAquiferLayer() + { + var random = new Random(21); + double leftCoordinate = random.NextDouble(); + double rightCoordinate = leftCoordinate + 1; + + var topLeftUpperLayer = new Point2D(leftCoordinate, 0); + var topRightUpperLayer = new Point2D(rightCoordinate, 0); + var bottomLeftUpperLayer = new Point2D(leftCoordinate, -10); + var bottomRightUpperLayer = new Point2D(rightCoordinate, -10); + SoilLayer2D soilLayer = CreateSoilLayer2D(topLeftUpperLayer, topRightUpperLayer, bottomRightUpperLayer, bottomLeftUpperLayer); + + var topRightLeftBottomLayer = new Point2D(rightCoordinate / 2, -10); + var bottomRightLeftBottomLayer = new Point2D(rightCoordinate / 2, -20); + var bottomLeftLeftBottomLayer = new Point2D(leftCoordinate, -20); + SoilLayer2D soilLayerAquiferPartOne = CreateSoilLayer2D(bottomLeftUpperLayer, topRightLeftBottomLayer, bottomRightLeftBottomLayer, bottomLeftLeftBottomLayer); + soilLayerAquiferPartOne.IsAquifer = true; + + var topRightRightBottomLayer = new Point2D(rightCoordinate, -10); + var bottomRightRightBottomLayer = new Point2D(rightCoordinate, -20); + SoilLayer2D soilLayerAquiferPartTwo = CreateSoilLayer2D(topRightLeftBottomLayer, topRightRightBottomLayer, bottomRightRightBottomLayer, bottomRightLeftBottomLayer); + soilLayerAquiferPartTwo.IsAquifer = true; + + var soilProfileFullAdjoin = new SoilProfile2D + { + Geometry = new GeometryData + { + Left = leftCoordinate, + Right = rightCoordinate, + Bottom = -20 + } + }; + soilProfileFullAdjoin.Surfaces.Add(soilLayer); + soilProfileFullAdjoin.Surfaces.Add(soilLayerAquiferPartOne); + soilProfileFullAdjoin.Surfaces.Add(soilLayerAquiferPartTwo); + + yield return new TestCaseData(soilProfileFullAdjoin, new[] + { + new GeometryPoint(leftCoordinate, -10), + new GeometryPoint(rightCoordinate / 2, -10), + new GeometryPoint(rightCoordinate, -10) + }).SetName("Right aquifer fully adjoins left aquifer"); + + var topRightBottomLayer = new Point2D(rightCoordinate, -10); + var bottomRightBottomLayer = new Point2D(rightCoordinate, -20); + var bottomLeftBottomLayer = new Point2D(leftCoordinate, -20); + SoilLayer2D soilLayerAquifer = CreateSoilLayer2D(bottomLeftUpperLayer, topRightBottomLayer, bottomRightBottomLayer, bottomLeftBottomLayer); + soilLayerAquifer.IsAquifer = true; + + var soilProfileOneBottomAquiferLayer = new SoilProfile2D + { + Geometry = new GeometryData + { + Left = leftCoordinate, + Right = rightCoordinate, + Bottom = -20 + } + }; + soilProfileOneBottomAquiferLayer.Surfaces.Add(soilLayer); + soilProfileOneBottomAquiferLayer.Surfaces.Add(soilLayerAquifer); + + yield return new TestCaseData(soilProfileOneBottomAquiferLayer, new[] + { + new GeometryPoint(leftCoordinate, -10), + new GeometryPoint(rightCoordinate, -10) + }).SetName("One aquifer bottom layer"); + + var topLeftRightBottomLayer = new Point2D(rightCoordinate / 2, -5); + topRightRightBottomLayer = new Point2D(rightCoordinate, -5); + bottomRightRightBottomLayer = new Point2D(rightCoordinate, -15); + var bottomLeftRightBottomLayer = new Point2D(rightCoordinate / 2, -15); + soilLayerAquiferPartTwo = CreateSoilLayer2D(topLeftRightBottomLayer, topRightRightBottomLayer, bottomRightRightBottomLayer, bottomLeftRightBottomLayer); + soilLayerAquiferPartTwo.IsAquifer = true; + + var soilProfileRightSoilLayerBottomInRange = new SoilProfile2D + { + Geometry = new GeometryData + { + Left = leftCoordinate, + Right = rightCoordinate, + Bottom = -20 + } + }; + soilProfileRightSoilLayerBottomInRange.Surfaces.Add(soilLayer); + soilProfileRightSoilLayerBottomInRange.Surfaces.Add(soilLayerAquiferPartOne); + soilProfileRightSoilLayerBottomInRange.Surfaces.Add(soilLayerAquiferPartTwo); + yield return new TestCaseData(soilProfileRightSoilLayerBottomInRange, new[] + { + new GeometryPoint(leftCoordinate, -10), + new GeometryPoint(rightCoordinate / 2, -5), + new GeometryPoint(rightCoordinate, -5) + }).SetName("Right aquifer only bottom in range"); + + topLeftRightBottomLayer = new Point2D(rightCoordinate / 2, -15); + topRightRightBottomLayer = new Point2D(rightCoordinate, -15); + bottomRightRightBottomLayer = new Point2D(rightCoordinate, -25); + bottomLeftRightBottomLayer = new Point2D(rightCoordinate / 2, -25); + soilLayerAquiferPartTwo = CreateSoilLayer2D(topLeftRightBottomLayer, topRightRightBottomLayer, bottomRightRightBottomLayer, bottomLeftRightBottomLayer); + soilLayerAquiferPartTwo.IsAquifer = true; + + var soilProfileRightSoilLayerTopInRange = new SoilProfile2D + { + Geometry = new GeometryData + { + Left = leftCoordinate, + Right = rightCoordinate, + Bottom = -20 + } + }; + soilProfileRightSoilLayerTopInRange.Surfaces.Add(soilLayer); + soilProfileRightSoilLayerTopInRange.Surfaces.Add(soilLayerAquiferPartOne); + soilProfileRightSoilLayerTopInRange.Surfaces.Add(soilLayerAquiferPartTwo); + yield return new TestCaseData(soilProfileRightSoilLayerTopInRange, new[] + { + new GeometryPoint(leftCoordinate, -10), + new GeometryPoint(rightCoordinate / 2, -10), + new GeometryPoint(rightCoordinate, -15) + }).SetName("Right aquifer only top in range"); + + topLeftRightBottomLayer = new Point2D(rightCoordinate / 2, -5); + topRightRightBottomLayer = new Point2D(rightCoordinate, -5); + bottomRightRightBottomLayer = new Point2D(rightCoordinate, -25); + bottomLeftRightBottomLayer = new Point2D(rightCoordinate / 2, -25); + soilLayerAquiferPartTwo = CreateSoilLayer2D(topLeftRightBottomLayer, topRightRightBottomLayer, bottomRightRightBottomLayer, bottomLeftRightBottomLayer); + soilLayerAquiferPartTwo.IsAquifer = true; + + var soilProfileRightAquiferLayerFullyEnvelopsLeft = new SoilProfile2D + { + Geometry = new GeometryData + { + Left = leftCoordinate, + Right = rightCoordinate, + Bottom = -20 + } + }; + soilProfileRightAquiferLayerFullyEnvelopsLeft.Surfaces.Add(soilLayer); + soilProfileRightAquiferLayerFullyEnvelopsLeft.Surfaces.Add(soilLayerAquiferPartOne); + soilProfileRightAquiferLayerFullyEnvelopsLeft.Surfaces.Add(soilLayerAquiferPartTwo); + yield return new TestCaseData(soilProfileRightAquiferLayerFullyEnvelopsLeft, new[] + { + new GeometryPoint(leftCoordinate, -10), + new GeometryPoint(rightCoordinate / 2, -5), + new GeometryPoint(rightCoordinate, -5) + }).SetName("Right aquifer fully envelopes left aquifer"); + + topLeftRightBottomLayer = new Point2D(rightCoordinate / 2, -15); + topRightRightBottomLayer = new Point2D(rightCoordinate, -15); + bottomRightRightBottomLayer = new Point2D(rightCoordinate, -17); + bottomLeftRightBottomLayer = new Point2D(rightCoordinate / 2, -17); + soilLayerAquiferPartTwo = CreateSoilLayer2D(topLeftRightBottomLayer, topRightRightBottomLayer, bottomRightRightBottomLayer, bottomLeftRightBottomLayer); + soilLayerAquiferPartTwo.IsAquifer = true; + + var soilProfileRightAquiferLayerFullyEnvelopedByLeft = new SoilProfile2D + { + Geometry = new GeometryData + { + Left = leftCoordinate, + Right = rightCoordinate, + Bottom = -20 + } + }; + soilProfileRightAquiferLayerFullyEnvelopedByLeft.Surfaces.Add(soilLayer); + soilProfileRightAquiferLayerFullyEnvelopedByLeft.Surfaces.Add(soilLayerAquiferPartOne); + soilProfileRightAquiferLayerFullyEnvelopedByLeft.Surfaces.Add(soilLayerAquiferPartTwo); + yield return new TestCaseData(soilProfileRightAquiferLayerFullyEnvelopedByLeft, new[] + { + new GeometryPoint(leftCoordinate, -10), + new GeometryPoint(rightCoordinate / 2, -10), + new GeometryPoint(rightCoordinate, -15) + }).SetName("Right aquifer fully enveloped by left aquifer"); + } + + private static SoilLayer2D CreateSoilLayer2D(Point2D topLeftCoordinate, + Point2D topRightCoordinate, Point2D bottomRightCoordinate, Point2D bottomLeftCoordinate) + { + var soilLayer = new SoilLayer2D + { + GeometrySurface = new GeometrySurface + { + OuterLoop = new GeometryLoop + { + CurveList = + { + new GeometryCurve(topLeftCoordinate, topRightCoordinate), + new GeometryCurve(topRightCoordinate, bottomRightCoordinate), + new GeometryCurve(bottomRightCoordinate, bottomLeftCoordinate), + new GeometryCurve(bottomLeftCoordinate, topLeftCoordinate) + } + } + } + }; + return soilLayer; + } } } Index: DamEngine/trunk/src/Deltares.DamEngine.Calculators/KernelWrappers/MacroStabilityCommon/PlLinesToWaternetConverter.cs =================================================================== diff -u -r2962 -r2971 --- DamEngine/trunk/src/Deltares.DamEngine.Calculators/KernelWrappers/MacroStabilityCommon/PlLinesToWaternetConverter.cs (.../PlLinesToWaternetConverter.cs) (revision 2962) +++ DamEngine/trunk/src/Deltares.DamEngine.Calculators/KernelWrappers/MacroStabilityCommon/PlLinesToWaternetConverter.cs (.../PlLinesToWaternetConverter.cs) (revision 2971) @@ -1,9 +1,14 @@ -using System.Data; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Runtime.InteropServices.WindowsRuntime; +using Deltares.DamEngine.Calculators.Interfaces; 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 { @@ -82,6 +87,146 @@ return waternet; } + public static Waternet ConvertPlLineToWaternet(PlLines plLines, SoilProfile2D soilProfile, double penetrationLength, double xLeft, double xRight) + { + // 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(xCoordinates, soilProfile).ToArray(); + + var waternet = new Waternet(); + var 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()) + { + var 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()) + { + var 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); + } + + return waternet; + } + + private static TLineType CreateLine(PlLine plLine) + where TLineType : GeometryPointString, new() + { + var line = new TLineType(); + line.Points.AddRange(plLine.Points); + + return line; + } + + 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); + } + + return line; + } + + private static IEnumerable GetAquiferCoordinates(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 = crossSection.BottomAquiferLayer; + if (previousAquiferLayer != null && + currentAquifer != null + && !AreVerticallyConnected(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.First().X != xCoordinates.First() || coordinates.Last().X != xCoordinates.Last()) + { + return Enumerable.Empty(); + } + return coordinates; + } + + private static bool AreVerticallyConnected(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;