// 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.Collections.Generic; using System.Data; using System.Linq; using Deltares.DamEngine.Calculators.KernelWrappers.MacroStabilityCommon; using Deltares.DamEngine.Data.General; using Deltares.DamEngine.Data.General.PlLines; using Deltares.DamEngine.Data.Geometry; using Deltares.DamEngine.Data.Geotechnics; using NUnit.Framework; namespace Deltares.DamEngine.Calculators.Tests.KernelWrappers.MacroStabilityCommon; public class PlLinesToWaternetConverterTests { private const double precision3Decimals = 0.00051; private static readonly Random random = new(21); private static readonly double leftCoordinate = random.NextDouble(); private static readonly double rightCoordinate = leftCoordinate + 1; private static readonly double middleXCoordinate = 0.5 * (leftCoordinate + rightCoordinate); private const double penetrationLength = 0.5; [Test] [TestCase(0)] [TestCase(0.01)] [TestCase(10)] public void ConvertPlLineToWaternet_PlLinesFullyDefinedAtOrBelowBottomSoil1DProfile_ReturnsEmptyWaternet(double offsetFromBottomOfProfile) { // Setup SoilProfile1D soilProfile = CreateSoilProfile1DForTest(); double bottomLevel = soilProfile.BottomLevel; double plLineZCoordinate = bottomLevel - offsetFromBottomOfProfile; var plLines = new PlLines(); PlLine plLine = plLines.Lines[PlLineType.Pl1]; plLine.Points.Add(new PlLinePoint(leftCoordinate, plLineZCoordinate)); plLine.Points.Add(new PlLinePoint(rightCoordinate, plLineZCoordinate)); plLine = plLines.Lines[PlLineType.Pl2]; plLine.Points.Add(new PlLinePoint(leftCoordinate, plLineZCoordinate)); plLine.Points.Add(new PlLinePoint(rightCoordinate, plLineZCoordinate)); plLine = plLines.Lines[PlLineType.Pl3]; plLine.Points.Add(new PlLinePoint(leftCoordinate, plLineZCoordinate)); plLine.Points.Add(new PlLinePoint(rightCoordinate, plLineZCoordinate)); plLine = plLines.Lines[PlLineType.Pl4]; plLine.Points.Add(new PlLinePoint(leftCoordinate, plLineZCoordinate)); plLine.Points.Add(new PlLinePoint(rightCoordinate, plLineZCoordinate)); // Call Waternet waternet = PlLinesToWaternetConverter.ConvertPlLineToWaternet(plLines, soilProfile, penetrationLength, leftCoordinate, rightCoordinate); // Assert Assert.That(waternet.PhreaticLine, Is.Null); Assert.That(waternet.HeadLineList, Is.Empty); Assert.That(waternet.WaternetLineList, Is.Empty); } [Test] public void TestConvertPlLinesToWaternet() { PlLines plLines = CreatePlLinesForTest(); SoilProfile1D soilProfile1D = CreateSoilProfile1DForTest(); Assert.Multiple(() => { Assert.That(soilProfile1D.InBetweenAquiferLayer.TopLevel, Is.EqualTo(-2.111).Within(precision3Decimals)); Assert.That(soilProfile1D.BottomAquiferLayer.TopLevel, Is.EqualTo(-6.111).Within(precision3Decimals)); }); const double penetrateLength = 2.1; const double left = 0; const double right = 100; Waternet waternet = PlLinesToWaternetConverter.ConvertPlLineToWaternet(plLines, soilProfile1D, penetrateLength, left, right); // Pl 1 is only the phreatic line, a headline or waternet line does not have to be created // Pl 2 gets waternet line to level of BottomAquiferLayer.TopLevel + penetrationLength // Pl 3 gets waternet line to level of InBetweenAquiferLayer.TopLevel // Pl 4 gets waternet line to level of BottomAquiferLayer.TopLevel // expected phreatic line from pl 1 Assert.That(waternet.PhreaticLine.Points, Has.Count.EqualTo(3)); Assert.Multiple(() => { Assert.That(waternet.PhreaticLine.Points[0].X, Is.EqualTo(0).Within(precision3Decimals)); Assert.That(waternet.PhreaticLine.Points[0].Z, Is.EqualTo(0).Within(precision3Decimals)); Assert.That(waternet.PhreaticLine.Points[1].X, Is.EqualTo(50).Within(precision3Decimals)); Assert.That(waternet.PhreaticLine.Points[1].Z, Is.EqualTo(1).Within(precision3Decimals)); Assert.That(waternet.PhreaticLine.Points[2].X, Is.EqualTo(100).Within(precision3Decimals)); Assert.That(waternet.PhreaticLine.Points[2].Z, Is.EqualTo(1).Within(precision3Decimals)); // expected head lines from pl 2, 3 and 4 Assert.That(waternet.HeadLineList, Has.Count.EqualTo(3)); }); Assert.Multiple(() => { Assert.That(waternet.HeadLineList[0].Points.Count, Is.EqualTo(2)); Assert.That(waternet.HeadLineList[1].Points.Count, Is.EqualTo(3)); Assert.That(waternet.HeadLineList[2].Points.Count, Is.EqualTo(2)); // check the points of first head line that represents pl 2 Assert.That(waternet.HeadLineList[0].Points[0].X, Is.EqualTo(0).Within(precision3Decimals)); Assert.That(waternet.HeadLineList[0].Points[0].Z, Is.EqualTo(0).Within(precision3Decimals)); Assert.That(waternet.HeadLineList[0].Points[1].X, Is.EqualTo(100).Within(precision3Decimals)); Assert.That(waternet.HeadLineList[0].Points[1].Z, Is.EqualTo(-1).Within(precision3Decimals)); // expected waternet lines from pl 2, 3 and 4 Assert.That(waternet.WaternetLineList.Count, Is.EqualTo(3)); }); Assert.Multiple(() => { // expected waternet line 0 is connected to pl2 with level -6.111 + 2.1 = -4.011 Assert.That(waternet.WaternetLineList[0].HeadLine, Is.EqualTo(waternet.HeadLineList[0])); Assert.That(waternet.WaternetLineList[0].Points[0].X, Is.EqualTo(0).Within(precision3Decimals)); Assert.That(waternet.WaternetLineList[0].Points[0].Z, Is.EqualTo(-4.011).Within(precision3Decimals)); Assert.That(waternet.WaternetLineList[0].Points[1].X, Is.EqualTo(100).Within(precision3Decimals)); Assert.That(waternet.WaternetLineList[0].Points[1].Z, Is.EqualTo(-4.011).Within(precision3Decimals)); // expected waternet line 1 is connected to pl3 with level -6.111 Assert.That(waternet.WaternetLineList[1].HeadLine, Is.EqualTo(waternet.HeadLineList[1])); Assert.That(waternet.WaternetLineList[1].Points[0].Z, Is.EqualTo(-6.111).Within(precision3Decimals)); // expected waternet line 2 is connected to pl4 with level -2.111 Assert.That(waternet.WaternetLineList[2].HeadLine, Is.EqualTo(waternet.HeadLineList[2])); Assert.That(waternet.WaternetLineList[2].Points[0].Z, Is.EqualTo(-2.111).Within(precision3Decimals)); }); } [Test] public void TestConvertPlLinesToWaternetWhenNoHeadLinesExpected() { PlLines plLines = CreatePlLinesForTest(); SoilProfile1D soilProfile1D = CreateSoilProfile1DForTest(); Waternet waternet = PlLinesToWaternetConverter.ConvertPlLineToWaternet(plLines, soilProfile1D, 0, 0, 0); // head lines Assert.That(waternet.HeadLineList, Has.Count.EqualTo(3)); Assert.Multiple(() => { Assert.That(waternet.HeadLineList[0].Points.Count, Is.EqualTo(2)); Assert.That(waternet.HeadLineList[1].Points.Count, Is.EqualTo(3)); Assert.That(waternet.HeadLineList[2].Points.Count, Is.EqualTo(2)); // phreatic line Assert.That(waternet.PhreaticLine.Points.Count, Is.EqualTo(3)); }); // check that no headline are added when Pl2, Pl3 or Pl4 does not exist or has no points plLines.Lines[PlLineType.Pl3] = null; plLines.Lines[PlLineType.Pl4].Points.Clear(); waternet = PlLinesToWaternetConverter.ConvertPlLineToWaternet(plLines, soilProfile1D, 0, 0, 0); // head lines Assert.That(waternet.HeadLineList, Has.Count.EqualTo(1)); Assert.Multiple(() => { Assert.That(waternet.HeadLineList[0].Points, Has.Count.EqualTo(2)); // phreatic line Assert.That(waternet.PhreaticLine.Points, Has.Count.EqualTo(3)); }); } [Test] public void TestConvertPlLinesToWaternetWhenNoWaternetLinesExpected() { PlLines plLines = CreatePlLinesForTest(); SoilProfile1D soilProfile1D = CreateSoilProfile1DForTest(); const double penetrateLength = 2.1; Waternet waternet = PlLinesToWaternetConverter.ConvertPlLineToWaternet(plLines, soilProfile1D, penetrateLength, 0, 0); Assert.Multiple(() => { Assert.That(waternet.HeadLineList, Has.Count.EqualTo(3)); Assert.That(waternet.WaternetLineList, Has.Count.EqualTo(3)); }); // check that no waternetlines are added for pl3 when InBetweenAquiferLayer is null soilProfile1D = CreateSoilProfile1DWith1AquiferForTest(); waternet = PlLinesToWaternetConverter.ConvertPlLineToWaternet(plLines, soilProfile1D, penetrateLength, 0, 0); Assert.Multiple(() => { Assert.That(waternet.HeadLineList, Has.Count.EqualTo(3)); Assert.That(waternet.WaternetLineList, Has.Count.EqualTo(2)); }); Assert.Multiple(() => { // expected waternet line 0 is connected to pl2 with level -6.111 + 2.1 = -4.011 Assert.That(waternet.WaternetLineList[0].HeadLine, Is.EqualTo(waternet.HeadLineList[0])); Assert.That(waternet.WaternetLineList[0].Points[0].Z, Is.EqualTo(-4.011).Within(precision3Decimals)); // expected waternet line 1 is connected to pl3 with level -6.111 Assert.That(waternet.WaternetLineList[1].HeadLine, Is.EqualTo(waternet.HeadLineList[1])); Assert.That(waternet.WaternetLineList[1].Points[0].Z, Is.EqualTo(-6.111).Within(precision3Decimals)); }); // check that no waternetlines are added for pl2, pl3 and pl4 when BottomAquiferLayer is null soilProfile1D = CreateSoilProfile1DWithoutAquifersForTest(); waternet = PlLinesToWaternetConverter.ConvertPlLineToWaternet(plLines, soilProfile1D, penetrateLength, 0, 0); Assert.Multiple(() => { Assert.That(waternet.HeadLineList, Has.Count.EqualTo(3)); Assert.That(waternet.WaternetLineList, Is.Empty); }); } [Test] public void TestConvertLevelToWaternetLine() { const double level = 1.234; const double left = -50.111; const double right = 50.123; WaternetLine waternetLine = PlLinesToWaternetConverter.CreateWaternetLine(level, left, right); Assert.That(waternetLine.Points, Has.Count.EqualTo(2)); Assert.Multiple(() => { Assert.That(waternetLine.Points[0].X, Is.EqualTo(-50.111).Within(precision3Decimals)); Assert.That(waternetLine.Points[0].Z, Is.EqualTo(1.234).Within(precision3Decimals)); Assert.That(waternetLine.Points[1].X, Is.EqualTo(50.123).Within(precision3Decimals)); Assert.That(waternetLine.Points[1].Z, Is.EqualTo(1.234).Within(precision3Decimals)); }); } /// /// Different soil profiles 2D are tested, see the pictures in method GetSoilProfilesWithContinuousBottomAquiferLayer, /// with a top clay layer and bottom aquifer layers always forming a continuous bottom layer. /// Expected is that: /// - PL3 is connected to the top of the bottom aquifer layer /// - PL2 is connected to the line parallel to the top of the bottom aquifer layer but shifted by 0.5 m (penetration length) upwards /// - PL4 is not used because no in-between aquifer is present /// /// /// [Test] [TestCaseSource(nameof(GetSoilProfilesWithContinuousBottomAquiferLayer))] public void ConvertPlLineToWaternet_ValidPLLinesAndSoilProfile2DWithContinuousAquiferLayers_ReturnsExpectedWaternet( SoilProfile2D soilProfile, IEnumerable expectedBottomAquiferCoordinates) { // Setup PlLines plLines = CreateAllPlLines(); // Call Waternet waternet = PlLinesToWaternetConverter.ConvertPlLineToWaternet(plLines, soilProfile, penetrationLength); // Assert AssertGeometry(plLines.Lines[PlLineType.Pl1].Points, waternet.PhreaticLine.Points); Assert.That(waternet.HeadLineList, Has.Count.EqualTo(3)); 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.That(waternet.WaternetLineList, Has.Count.EqualTo(2)); WaternetLine pl2WaternetLine = waternet.WaternetLineList[0]; Assert.That(pl2WaternetLine.HeadLine, Is.SameAs(waternet.HeadLineList[0])); GeometryPoint[] offSetAquiferCoordinates = expectedBottomAquiferCoordinates.Select(aquiferCoordinate => new GeometryPoint(aquiferCoordinate.X, aquiferCoordinate.Z + penetrationLength)) .ToArray(); AssertGeometry(offSetAquiferCoordinates, pl2WaternetLine.Points); WaternetLine pl3WaternetLine = waternet.WaternetLineList[1]; Assert.That(pl3WaternetLine.HeadLine, Is.SameAs(waternet.HeadLineList[1])); AssertGeometry(expectedBottomAquiferCoordinates, pl3WaternetLine.Points); } /// /// --------------------------------------------------------------- Level 0 m /// top layer /// --------------------------------------------------------------- Level -10 m /// in-between aquifer layer left | in-between aquifer layer right /// --------------------------------------------------------------- Level -20 m /// in-between layer /// --------------------------------------------------------------- Level -25 m /// bottom aquifer layer /// --------------------------------------------------------------- Level -30 m /// [Test] public void ConvertPlLineToWaternet_ValidPLLinesAndSoilProfile2DWithContinuousInBetweenAquiferLayerConsistOfTwoParts_ReturnsExpectedWaternet() { // Setup SoilLayer2D soilLayer = CreateRectangularSoilLayer2D(0, -10, leftCoordinate, rightCoordinate, false); SoilLayer2D soilLayerAquiferInBetweenLeft = CreateRectangularSoilLayer2D(-10, -20, leftCoordinate, middleXCoordinate, true); SoilLayer2D soilLayerAquiferInBetweenRight = CreateRectangularSoilLayer2D(-10, -20, middleXCoordinate, rightCoordinate, true); SoilLayer2D soilLayerInBetween = CreateRectangularSoilLayer2D(-20, -25, leftCoordinate, rightCoordinate, false); SoilLayer2D soilLayerAquiferBottom = CreateRectangularSoilLayer2D(-25, -30, leftCoordinate, rightCoordinate, true); var soilProfile = new SoilProfile2D { Geometry = new GeometryData { Left = leftCoordinate, Right = rightCoordinate, Bottom = -30 } }; soilProfile.Surfaces.Add(soilLayer); soilProfile.Surfaces.Add(soilLayerAquiferInBetweenLeft); soilProfile.Surfaces.Add(soilLayerAquiferInBetweenRight); soilProfile.Surfaces.Add(soilLayerInBetween); soilProfile.Surfaces.Add(soilLayerAquiferBottom); PlLines plLines = CreateAllPlLines(); // Call Waternet waternet = PlLinesToWaternetConverter.ConvertPlLineToWaternet(plLines, soilProfile, penetrationLength); // Assert AssertGeometry(plLines.Lines[PlLineType.Pl1].Points, waternet.PhreaticLine.Points); Assert.That(waternet.HeadLineList, Has.Count.EqualTo(3)); 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.That(waternet.WaternetLineList, Has.Count.EqualTo(3)); Point2D[] expectedBottomAquiferCoordinates = [ new Point2D(leftCoordinate, -25), new Point2D(middleXCoordinate, -25), new Point2D(rightCoordinate, -25) ]; WaternetLine pl2WaternetLine = waternet.WaternetLineList[0]; Assert.That(pl2WaternetLine.HeadLine, Is.SameAs(waternet.HeadLineList[0])); GeometryPoint[] offSetAquiferCoordinates = expectedBottomAquiferCoordinates.Select(aquiferCoordinate => new GeometryPoint(aquiferCoordinate.X, aquiferCoordinate.Z + penetrationLength)) .ToArray(); AssertGeometry(offSetAquiferCoordinates, pl2WaternetLine.Points); WaternetLine pl3WaternetLine = waternet.WaternetLineList[1]; Assert.That(pl3WaternetLine.HeadLine, Is.SameAs(waternet.HeadLineList[1])); AssertGeometry(expectedBottomAquiferCoordinates, pl3WaternetLine.Points); WaternetLine pl4WaternetLine = waternet.WaternetLineList[2]; Assert.That(pl4WaternetLine.HeadLine, Is.SameAs(waternet.HeadLineList[2])); AssertGeometry([ new Point2D(leftCoordinate, -10), new Point2D(middleXCoordinate, -10), new Point2D(rightCoordinate, -10) ], pl4WaternetLine.Points); } /// /// --------------------------------------------------- Level 0 m /// top layer /// --------------------------------------------------- Level -10 m /// in-between aquifer layer /// --------------------------------------------------- Level -20 m /// in-between layer /// --------------------------------------------------- Level -25 m /// bottom aquifer layer /// --------------------------------------------------- Level -30 m /// [Test] public void ConvertPlLineToWaternet_ValidPLLinesAndSoilProfile2DWithContinuousInBetweenAquiferLayerConsistOfOnePart_ReturnsExpectedWaternet() { // Setup SoilLayer2D soilLayer = CreateRectangularSoilLayer2D(0, -10, leftCoordinate, rightCoordinate, false); SoilLayer2D soilLayerAquiferInBetween = CreateRectangularSoilLayer2D(-10, -20, leftCoordinate, rightCoordinate, true); SoilLayer2D soilLayerInBetween = CreateRectangularSoilLayer2D(-20, -25, leftCoordinate, rightCoordinate, false); SoilLayer2D soilLayerAquiferBottom = CreateRectangularSoilLayer2D(-25, -30, leftCoordinate, rightCoordinate, true); var soilProfile = new SoilProfile2D { Geometry = new GeometryData { Left = leftCoordinate, Right = rightCoordinate, Bottom = -30 } }; soilProfile.Surfaces.Add(soilLayer); soilProfile.Surfaces.Add(soilLayerAquiferInBetween); soilProfile.Surfaces.Add(soilLayerInBetween); soilProfile.Surfaces.Add(soilLayerAquiferBottom); PlLines plLines = CreateAllPlLines(); // Call Waternet waternet = PlLinesToWaternetConverter.ConvertPlLineToWaternet(plLines, soilProfile, penetrationLength); // Assert AssertGeometry(plLines.Lines[PlLineType.Pl1].Points, waternet.PhreaticLine.Points); Assert.That(waternet.HeadLineList, Has.Count.EqualTo(3)); 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.That(waternet.WaternetLineList, Has.Count.EqualTo(3)); var bottomRightInBetweenLayer = new Point2D(rightCoordinate, -25); var bottomLeftInBetweenLayer = new Point2D(leftCoordinate, -25); Point2D[] expectedBottomAquiferCoordinates = [ bottomLeftInBetweenLayer, bottomRightInBetweenLayer ]; WaternetLine pl2WaternetLine = waternet.WaternetLineList[0]; Assert.That(pl2WaternetLine.HeadLine, Is.SameAs(waternet.HeadLineList[0])); GeometryPoint[] offSetAquiferCoordinates = expectedBottomAquiferCoordinates.Select(aquiferCoordinate => new GeometryPoint(aquiferCoordinate.X, aquiferCoordinate.Z + penetrationLength)) .ToArray(); AssertGeometry(offSetAquiferCoordinates, pl2WaternetLine.Points); WaternetLine pl3WaternetLine = waternet.WaternetLineList[1]; Assert.That(pl3WaternetLine.HeadLine, Is.SameAs(waternet.HeadLineList[1])); AssertGeometry(expectedBottomAquiferCoordinates, pl3WaternetLine.Points); WaternetLine pl4WaternetLine = waternet.WaternetLineList[2]; Assert.That(pl4WaternetLine.HeadLine, Is.SameAs(waternet.HeadLineList[2])); var bottomRightUpperLayer = new Point2D(rightCoordinate, -10); var bottomLeftUpperLayer = new Point2D(leftCoordinate, -10); AssertGeometry([ bottomLeftUpperLayer, bottomRightUpperLayer ], pl4WaternetLine.Points); } /// /// ------------------------------------------------------------- Level 0 m /// top layer /// ------------------------------------------------------------- Level -10 m /// | Gap layer /// in-between aquifer |------------------------------- Level -15 m /// layer left | /// | in-between aquifer /// -----------------------------| layer right Level -20 m /// in-between layer | /// |------------------------------- Level -21 m /// /// ------------------------------------------------------------- Level -25 m /// bottom aquifer layer /// ------------------------------------------------------------- Level -30 m /// [Test] public void ConvertPlLineToWaternet_ValidPLLinesAndSoilProfile2DWithContinuousInBetweenAquiferLayerRightLayerTopLevelInRangeLeftLayer_ReturnsExpectedWaternet() { // Setup SoilLayer2D soilLayer = CreateRectangularSoilLayer2D(0, -10, leftCoordinate, rightCoordinate, false); SoilLayer2D soilLayerAquiferInBetweenLeft = CreateRectangularSoilLayer2D(-10, -20, leftCoordinate, middleXCoordinate, true); // Add a layer to fill the gap between the right aquifer layer and the upper layer SoilLayer2D soilLayerGap = CreateRectangularSoilLayer2D(-10, -15, middleXCoordinate, rightCoordinate, false); SoilLayer2D soilLayerAquiferInBetweenRight = CreateRectangularSoilLayer2D(-15, -21, middleXCoordinate, rightCoordinate, true); // Add continuous in-between layer var bottomLeftInBetweenAquiferLayerLeft = new Point2D(leftCoordinate, -20); var bottomRightInBetweenAquiferLayerLeft = new Point2D(middleXCoordinate, -20); var bottomLeftInBetweenAquiferLayerRight = new Point2D(middleXCoordinate, -21); var bottomRightInBetweenAquiferLayerRight = new Point2D(rightCoordinate, -21); var bottomRightInBetweenLayer = new Point2D(rightCoordinate, -25); var bottomLeftInBetweenLayer = new Point2D(leftCoordinate, -25); var soilLayerInBetween = new SoilLayer2D { GeometrySurface = new GeometrySurface { OuterLoop = new GeometryLoop { CurveList = { new GeometryCurve(bottomLeftInBetweenAquiferLayerLeft, bottomRightInBetweenAquiferLayerLeft), new GeometryCurve(bottomRightInBetweenAquiferLayerLeft, bottomLeftInBetweenAquiferLayerRight), new GeometryCurve(bottomLeftInBetweenAquiferLayerRight, bottomRightInBetweenAquiferLayerRight), new GeometryCurve(bottomRightInBetweenAquiferLayerRight, bottomRightInBetweenLayer), new GeometryCurve(bottomRightInBetweenLayer, bottomLeftInBetweenLayer) } } } }; SoilLayer2D soilLayerAquiferBottom = CreateRectangularSoilLayer2D(-25, -30, leftCoordinate, rightCoordinate, true); var soilProfile = new SoilProfile2D { Geometry = new GeometryData { Left = leftCoordinate, Right = rightCoordinate, Bottom = -30 } }; soilProfile.Surfaces.Add(soilLayer); soilProfile.Surfaces.Add(soilLayerAquiferInBetweenLeft); soilProfile.Surfaces.Add(soilLayerGap); soilProfile.Surfaces.Add(soilLayerAquiferInBetweenRight); soilProfile.Surfaces.Add(soilLayerInBetween); soilProfile.Surfaces.Add(soilLayerAquiferBottom); PlLines plLines = CreateAllPlLines(); // Call Waternet waternet = PlLinesToWaternetConverter.ConvertPlLineToWaternet(plLines, soilProfile, penetrationLength); // Assert AssertGeometry(plLines.Lines[PlLineType.Pl1].Points, waternet.PhreaticLine.Points); Assert.That(waternet.HeadLineList, Has.Count.EqualTo(3)); 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.That(waternet.WaternetLineList, Has.Count.EqualTo(3)); Point2D[] expectedBottomAquiferCoordinates = { bottomLeftInBetweenLayer, new(middleXCoordinate, -25), bottomRightInBetweenLayer }; WaternetLine pl2WaternetLine = waternet.WaternetLineList[0]; Assert.That(pl2WaternetLine.HeadLine, Is.SameAs(waternet.HeadLineList[0])); GeometryPoint[] offSetAquiferCoordinates = expectedBottomAquiferCoordinates.Select(aquiferCoordinate => new GeometryPoint(aquiferCoordinate.X, aquiferCoordinate.Z + penetrationLength)) .ToArray(); AssertGeometry(offSetAquiferCoordinates, pl2WaternetLine.Points); WaternetLine pl3WaternetLine = waternet.WaternetLineList[1]; Assert.That(pl3WaternetLine.HeadLine, Is.SameAs(waternet.HeadLineList[1])); AssertGeometry(expectedBottomAquiferCoordinates, pl3WaternetLine.Points); WaternetLine pl4WaternetLine = waternet.WaternetLineList[2]; Assert.That(pl4WaternetLine.HeadLine, Is.SameAs(waternet.HeadLineList[2])); AssertGeometry([ new GeometryPoint(leftCoordinate, -10), new GeometryPoint(middleXCoordinate, -10), new GeometryPoint(rightCoordinate, -15) ], pl4WaternetLine.Points); } /// /// -------------------------------------------------------------- Level 0 m /// top layer /// |------------------------------- Level -5 m /// | /// | in-between aquifer /// ------------------------------| layer right Level -10 m /// in-between aquifer layer left | /// ------------------------------------------------------------- Level -20 m /// in-between layer /// -------------------------------------------------------------- Level -25 m /// bottom aquifer layer /// -------------------------------------------------------------- Level -30 m /// [Test] public void ConvertPlLineToWaternet_ValidPLLinesAndSoilProfile2DWithContinuousInBetweenAquiferLayerRightLayerBottomLevelInRangeLeftLayer_ReturnsExpectedWaternet() { // Setup var topLeftUpperLayer = new Point2D(leftCoordinate, 0); var topRightUpperLayer = new Point2D(rightCoordinate, 0); var bottomRightUpperLayer = new Point2D(rightCoordinate, -5); var bottomIntermediateUpperUpperLayer = new Point2D(middleXCoordinate, -5); var bottomIntermediateLowerUpperLayer = new Point2D(middleXCoordinate, -10); var bottomLeftUpperLayer = new Point2D(leftCoordinate, -10); var soilLayer = new SoilLayer2D { GeometrySurface = new GeometrySurface { OuterLoop = new GeometryLoop { CurveList = { new GeometryCurve(topLeftUpperLayer, topRightUpperLayer), new GeometryCurve(topRightUpperLayer, bottomRightUpperLayer), new GeometryCurve(bottomRightUpperLayer, bottomIntermediateUpperUpperLayer), new GeometryCurve(bottomIntermediateUpperUpperLayer, bottomIntermediateLowerUpperLayer), new GeometryCurve(bottomIntermediateLowerUpperLayer, bottomLeftUpperLayer), new GeometryCurve(bottomLeftUpperLayer, topLeftUpperLayer) } } } }; SoilLayer2D soilLayerAquiferInBetweenLeft = CreateRectangularSoilLayer2D(-10, -20, leftCoordinate, middleXCoordinate, true); SoilLayer2D soilLayerAquiferInBetweenRight = CreateRectangularSoilLayer2D(-5, -20, middleXCoordinate, rightCoordinate, true); SoilLayer2D soilLayerInBetween = CreateRectangularSoilLayer2D(-20, -25, leftCoordinate, rightCoordinate, false); SoilLayer2D soilLayerAquiferBottom = CreateRectangularSoilLayer2D(-25, -30, leftCoordinate, rightCoordinate, true); soilLayerAquiferBottom.IsAquifer = true; var soilProfile = new SoilProfile2D { Geometry = new GeometryData { Left = leftCoordinate, Right = rightCoordinate, Bottom = -30 } }; soilProfile.Surfaces.Add(soilLayer); soilProfile.Surfaces.Add(soilLayerAquiferInBetweenLeft); soilProfile.Surfaces.Add(soilLayerAquiferInBetweenRight); soilProfile.Surfaces.Add(soilLayerInBetween); soilProfile.Surfaces.Add(soilLayerAquiferBottom); PlLines plLines = CreateAllPlLines(); // Call Waternet waternet = PlLinesToWaternetConverter.ConvertPlLineToWaternet(plLines, soilProfile, penetrationLength); // Assert AssertGeometry(plLines.Lines[PlLineType.Pl1].Points, waternet.PhreaticLine.Points); Assert.That(waternet.HeadLineList, Has.Count.EqualTo(3)); 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.That(waternet.WaternetLineList, Has.Count.EqualTo(3)); var bottomRightInBetweenLayer = new Point2D(rightCoordinate, -25); var bottomLeftInBetweenLayer = new Point2D(leftCoordinate, -25); Point2D[] expectedBottomAquiferCoordinates = { bottomLeftInBetweenLayer, new Point2D(middleXCoordinate, -25), bottomRightInBetweenLayer }; WaternetLine pl2WaternetLine = waternet.WaternetLineList[0]; Assert.That(pl2WaternetLine.HeadLine, Is.SameAs(waternet.HeadLineList[0])); GeometryPoint[] offSetAquiferCoordinates = expectedBottomAquiferCoordinates.Select(aquiferCoordinate => new GeometryPoint(aquiferCoordinate.X, aquiferCoordinate.Z + penetrationLength)) .ToArray(); AssertGeometry(offSetAquiferCoordinates, pl2WaternetLine.Points); WaternetLine pl3WaternetLine = waternet.WaternetLineList[1]; Assert.That(pl3WaternetLine.HeadLine, Is.SameAs(waternet.HeadLineList[1])); AssertGeometry(expectedBottomAquiferCoordinates, pl3WaternetLine.Points); WaternetLine pl4WaternetLine = waternet.WaternetLineList[2]; Assert.That(pl4WaternetLine.HeadLine, Is.SameAs(waternet.HeadLineList[2])); AssertGeometry(new[] { bottomLeftUpperLayer, bottomIntermediateUpperUpperLayer, bottomRightUpperLayer }, pl4WaternetLine.Points); } /// /// ------------------------------------------------------------- Level 0 m /// top layer /// /// -----------------------------| Level -10 m /// in-between aquifer | /// layer left |------------------------------- Level -15 m /// | in-between aquifer layer right /// | ------------------------------ Level -17 m /// | /// | /// -----------------------------| Level -20 m /// in-between layer /// ------------------------------------------------------------- Level -25 m /// bottom aquifer layer /// ------------------------------------------------------------- Level -30 m /// [Test] public void ConvertPlLineToWaternet_ValidPLLinesAndSoilProfile2DWithContinuousInBetweenAquiferLayerRightLayerEnvelopedByLeftLayer_ReturnsExpectedWaternet() { // Setup var topLeftUpperLayer = new Point2D(leftCoordinate, 0); var topRightUpperLayer = new Point2D(rightCoordinate, 0); var bottomRightUpperLayer = new Point2D(rightCoordinate, -15); var bottomIntermediateLowerUpperLayer = new Point2D(middleXCoordinate, -15); var bottomIntermediateUpperUpperLayer = new Point2D(middleXCoordinate, -10); var bottomLeftUpperLayer = new Point2D(leftCoordinate, -10); var soilLayer = new SoilLayer2D { GeometrySurface = new GeometrySurface { OuterLoop = new GeometryLoop { CurveList = { new GeometryCurve(topLeftUpperLayer, topRightUpperLayer), new GeometryCurve(topRightUpperLayer, bottomRightUpperLayer), new GeometryCurve(bottomRightUpperLayer, bottomIntermediateLowerUpperLayer), new GeometryCurve(bottomIntermediateLowerUpperLayer, bottomIntermediateUpperUpperLayer), new GeometryCurve(bottomIntermediateUpperUpperLayer, bottomLeftUpperLayer), new GeometryCurve(bottomLeftUpperLayer, topLeftUpperLayer) } } } }; SoilLayer2D soilLayerAquiferInBetweenLeft = CreateRectangularSoilLayer2D(-10, -20, leftCoordinate, middleXCoordinate, true); SoilLayer2D soilLayerAquiferInBetweenRight = CreateRectangularSoilLayer2D(-15, -17, middleXCoordinate, rightCoordinate, true); var bottomLeftInBetweenAquiferLayerLeft = new Point2D(leftCoordinate, -20); var bottomRightInBetweenAquiferLayerLeft = new Point2D(middleXCoordinate, -20); var bottomLeftInBetweenAquiferLayerRight = new Point2D(middleXCoordinate, -17); var bottomRightInBetweenAquiferLayerRight = new Point2D(rightCoordinate, -17); var bottomRightInBetweenLayer = new Point2D(rightCoordinate, -25); var bottomLeftInBetweenLayer = new Point2D(leftCoordinate, -25); var soilLayerInBetween = new SoilLayer2D { GeometrySurface = new GeometrySurface { OuterLoop = new GeometryLoop { CurveList = { new GeometryCurve(bottomLeftInBetweenAquiferLayerLeft, bottomRightInBetweenAquiferLayerLeft), new GeometryCurve(bottomRightInBetweenAquiferLayerLeft, bottomLeftInBetweenAquiferLayerRight), new GeometryCurve(bottomLeftInBetweenAquiferLayerRight, bottomRightInBetweenAquiferLayerRight), new GeometryCurve(bottomRightInBetweenAquiferLayerRight, bottomRightInBetweenLayer), new GeometryCurve(bottomRightInBetweenLayer, bottomLeftInBetweenLayer), new GeometryCurve(bottomLeftInBetweenLayer, bottomLeftInBetweenAquiferLayerLeft) } } } }; SoilLayer2D soilLayerAquiferBottom = CreateRectangularSoilLayer2D(-25, -30, leftCoordinate, rightCoordinate, true); var soilProfile = new SoilProfile2D { Geometry = new GeometryData { Left = leftCoordinate, Right = rightCoordinate, Bottom = -30 } }; soilProfile.Surfaces.Add(soilLayer); soilProfile.Surfaces.Add(soilLayerAquiferInBetweenLeft); soilProfile.Surfaces.Add(soilLayerAquiferInBetweenRight); soilProfile.Surfaces.Add(soilLayerInBetween); soilProfile.Surfaces.Add(soilLayerAquiferBottom); PlLines plLines = CreateAllPlLines(); // Call Waternet waternet = PlLinesToWaternetConverter.ConvertPlLineToWaternet(plLines, soilProfile, penetrationLength); // Assert AssertGeometry(plLines.Lines[PlLineType.Pl1].Points, waternet.PhreaticLine.Points); Assert.That(waternet.HeadLineList, Has.Count.EqualTo(3)); 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.That(waternet.WaternetLineList.Count, Is.EqualTo(3)); Point2D[] expectedBottomAquiferCoordinates = { bottomLeftInBetweenLayer, new Point2D(middleXCoordinate, -25), bottomRightInBetweenLayer }; WaternetLine pl2WaternetLine = waternet.WaternetLineList[0]; Assert.That(pl2WaternetLine.HeadLine, Is.SameAs(waternet.HeadLineList[0])); GeometryPoint[] offSetAquiferCoordinates = expectedBottomAquiferCoordinates.Select(aquiferCoordinate => new GeometryPoint(aquiferCoordinate.X, aquiferCoordinate.Z + penetrationLength)) .ToArray(); AssertGeometry(offSetAquiferCoordinates, pl2WaternetLine.Points); WaternetLine pl3WaternetLine = waternet.WaternetLineList[1]; Assert.That(pl3WaternetLine.HeadLine, Is.SameAs(waternet.HeadLineList[1])); AssertGeometry(expectedBottomAquiferCoordinates, pl3WaternetLine.Points); WaternetLine pl4WaternetLine = waternet.WaternetLineList[2]; Assert.That(pl4WaternetLine.HeadLine, Is.SameAs(waternet.HeadLineList[2])); AssertGeometry(new[] { bottomLeftUpperLayer, bottomIntermediateUpperUpperLayer, bottomRightUpperLayer }, pl4WaternetLine.Points); } /// /// ------------------------------------------------------------- Level 0 m /// top layer /// |------------------------------ Level -5 m /// | in-between aquifer /// ------------------------------| layer right Level -10 m /// in-between aquifer layer left | /// | /// ------------------------------| Level -20 m /// in-between layer | /// |------------------------------ Level -21 m /// /// ------------------------------------------------------------- Level -25 m /// bottom aquifer layer /// ------------------------------------------------------------- Level -30 m /// [Test] public void ConvertPlLineToWaternet_ValidPLLinesAndSoilProfile2DWithContinuousInBetweenAquiferLayerRightLayerEnvelopesLeftLayer_ReturnsExpectedWaternet() { // Setup var topLeftUpperLayer = new Point2D(leftCoordinate, 0); var topRightUpperLayer = new Point2D(rightCoordinate, 0); var bottomRightUpperLayer = new Point2D(rightCoordinate, -5); var bottomIntermediateLowerUpperLayer = new Point2D(middleXCoordinate, -5); var bottomIntermediateUpperUpperLayer = new Point2D(middleXCoordinate, -10); var bottomLeftUpperLayer = new Point2D(leftCoordinate, -10); var soilLayer = new SoilLayer2D { GeometrySurface = new GeometrySurface { OuterLoop = new GeometryLoop { CurveList = { new GeometryCurve(topLeftUpperLayer, topRightUpperLayer), new GeometryCurve(topRightUpperLayer, bottomRightUpperLayer), new GeometryCurve(bottomRightUpperLayer, bottomIntermediateLowerUpperLayer), new GeometryCurve(bottomIntermediateLowerUpperLayer, bottomIntermediateUpperUpperLayer), new GeometryCurve(bottomIntermediateUpperUpperLayer, bottomLeftUpperLayer), new GeometryCurve(bottomLeftUpperLayer, topLeftUpperLayer) } } } }; SoilLayer2D soilLayerAquiferInBetweenLeft = CreateRectangularSoilLayer2D(-10, -20, leftCoordinate, middleXCoordinate, true); SoilLayer2D soilLayerAquiferInBetweenRight = CreateRectangularSoilLayer2D(-5, -21, middleXCoordinate, rightCoordinate, true); var bottomLeftInBetweenAquiferLayerLeft = new Point2D(leftCoordinate, -20); var bottomRightInBetweenAquiferLayerLeft = new Point2D(middleXCoordinate, -20); var bottomLeftInBetweenAquiferLayerRight = new Point2D(middleXCoordinate, -21); var bottomRightInBetweenAquiferLayerRight = new Point2D(rightCoordinate, -21); var bottomRightInBetweenLayer = new Point2D(rightCoordinate, -25); var bottomLeftInBetweenLayer = new Point2D(leftCoordinate, -25); var soilLayerInBetween = new SoilLayer2D { GeometrySurface = new GeometrySurface { OuterLoop = new GeometryLoop { CurveList = { new GeometryCurve(bottomLeftInBetweenAquiferLayerLeft, bottomRightInBetweenAquiferLayerLeft), new GeometryCurve(bottomRightInBetweenAquiferLayerLeft, bottomLeftInBetweenAquiferLayerRight), new GeometryCurve(bottomLeftInBetweenAquiferLayerRight, bottomRightInBetweenAquiferLayerRight), new GeometryCurve(bottomRightInBetweenAquiferLayerRight, bottomRightInBetweenLayer), new GeometryCurve(bottomRightInBetweenLayer, bottomLeftInBetweenLayer), new GeometryCurve(bottomLeftInBetweenLayer, bottomLeftInBetweenAquiferLayerLeft) } } } }; SoilLayer2D soilLayerAquiferBottom = CreateRectangularSoilLayer2D(-25, -30, leftCoordinate, rightCoordinate, true); var soilProfile = new SoilProfile2D { Geometry = new GeometryData { Left = leftCoordinate, Right = rightCoordinate, Bottom = -30 } }; soilProfile.Surfaces.Add(soilLayer); soilProfile.Surfaces.Add(soilLayerAquiferInBetweenLeft); soilProfile.Surfaces.Add(soilLayerAquiferInBetweenRight); soilProfile.Surfaces.Add(soilLayerInBetween); soilProfile.Surfaces.Add(soilLayerAquiferBottom); PlLines plLines = CreateAllPlLines(); // Call Waternet waternet = PlLinesToWaternetConverter.ConvertPlLineToWaternet(plLines, soilProfile, penetrationLength); // Assert AssertGeometry(plLines.Lines[PlLineType.Pl1].Points, waternet.PhreaticLine.Points); Assert.That(waternet.HeadLineList, Has.Count.EqualTo(3)); 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.That(waternet.WaternetLineList, Has.Count.EqualTo(3)); Point2D[] expectedBottomAquiferCoordinates = { bottomLeftInBetweenLayer, new Point2D(middleXCoordinate, -25), bottomRightInBetweenLayer }; WaternetLine pl2WaternetLine = waternet.WaternetLineList[0]; Assert.That(pl2WaternetLine.HeadLine, Is.SameAs(waternet.HeadLineList[0])); GeometryPoint[] offSetAquiferCoordinates = expectedBottomAquiferCoordinates.Select(aquiferCoordinate => new GeometryPoint(aquiferCoordinate.X, aquiferCoordinate.Z + penetrationLength)) .ToArray(); AssertGeometry(offSetAquiferCoordinates, pl2WaternetLine.Points); WaternetLine pl3WaternetLine = waternet.WaternetLineList[1]; Assert.That(pl3WaternetLine.HeadLine, Is.SameAs(waternet.HeadLineList[1])); AssertGeometry(expectedBottomAquiferCoordinates, pl3WaternetLine.Points); WaternetLine pl4WaternetLine = waternet.WaternetLineList[2]; Assert.That(pl4WaternetLine.HeadLine, Is.SameAs(waternet.HeadLineList[2])); AssertGeometry(new[] { bottomLeftUpperLayer, bottomIntermediateLowerUpperLayer, bottomRightUpperLayer }, pl4WaternetLine.Points); } /// /// --------------------------------------------------- Level 0 m /// top layer /// -------------------------|------------------------- Level -10 m /// in-between layer left | in-between layer right /// -------------------------|------------------------- Level -20 m /// in-between layer /// --------------------------------------------------- Level -25 m /// bottom aquifer layer /// --------------------------------------------------- Level -30 m /// [Test] [TestCase(true, false)] [TestCase(false, true)] public void ConvertPlLineToWaternet_ValidPLLinesAndSoilProfile2DWithDiscontinuousInBetweenAquiferLayer_ReturnsExpectedWaternet( bool isLeftInBetweenLayerAquifer, bool isRightInBetweenLayerAquifer) { // Setup SoilLayer2D soilLayer = CreateRectangularSoilLayer2D(0, -10, leftCoordinate, rightCoordinate, false); SoilLayer2D soilLayerAquiferInBetweenLeft = CreateRectangularSoilLayer2D(-10, -20, leftCoordinate, middleXCoordinate, isLeftInBetweenLayerAquifer); SoilLayer2D soilLayerAquiferInBetweenRight = CreateRectangularSoilLayer2D(-10, -20, middleXCoordinate, rightCoordinate, isRightInBetweenLayerAquifer); SoilLayer2D soilLayerInBetween = CreateRectangularSoilLayer2D(-20, -25, leftCoordinate, rightCoordinate, false); SoilLayer2D soilLayerAquiferBottom = CreateRectangularSoilLayer2D(-25, -30, leftCoordinate, rightCoordinate, true); var soilProfile = new SoilProfile2D { Geometry = new GeometryData { Left = leftCoordinate, Right = rightCoordinate, Bottom = -30 } }; soilProfile.Surfaces.Add(soilLayer); soilProfile.Surfaces.Add(soilLayerAquiferInBetweenLeft); soilProfile.Surfaces.Add(soilLayerAquiferInBetweenRight); soilProfile.Surfaces.Add(soilLayerInBetween); soilProfile.Surfaces.Add(soilLayerAquiferBottom); PlLines plLines = CreateAllPlLines(); // Call Waternet waternet = PlLinesToWaternetConverter.ConvertPlLineToWaternet(plLines, soilProfile, penetrationLength); // Assert AssertGeometry(plLines.Lines[PlLineType.Pl1].Points, waternet.PhreaticLine.Points); Assert.That(waternet.HeadLineList, Has.Count.EqualTo(3)); 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.That(waternet.WaternetLineList, Has.Count.EqualTo(2)); var bottomRightInBetweenLayer = new Point2D(rightCoordinate, -25); var bottomLeftInBetweenLayer = new Point2D(leftCoordinate, -25); Point2D[] expectedBottomAquiferCoordinates = { bottomLeftInBetweenLayer, new Point2D(middleXCoordinate, -25), bottomRightInBetweenLayer }; WaternetLine pl2WaternetLine = waternet.WaternetLineList[0]; Assert.That(pl2WaternetLine.HeadLine, Is.SameAs(waternet.HeadLineList[0])); GeometryPoint[] offSetAquiferCoordinates = expectedBottomAquiferCoordinates.Select(aquiferCoordinate => new GeometryPoint(aquiferCoordinate.X, aquiferCoordinate.Z + penetrationLength)) .ToArray(); AssertGeometry(offSetAquiferCoordinates, pl2WaternetLine.Points); WaternetLine pl3WaternetLine = waternet.WaternetLineList[1]; Assert.That(pl3WaternetLine.HeadLine, Is.SameAs(waternet.HeadLineList[1])); AssertGeometry(expectedBottomAquiferCoordinates, pl3WaternetLine.Points); } /// /// --------------------------------------------------- Level 0 m /// /// |------------------------- Level -5 m /// top layer | right aquifer /// |------------------------- Level -9 m /// /// -------------------------|------------------------- Level -10 m /// left aquifer | /// -------------------------| Level -20 m /// [Test] public void ConvertPlLineToWaternet_ValidPLLinesAndSoilProfile2DWithDiscontinuousBottomAquiferLayer_ReturnsEmptyWaternet() { // Setup SoilLayer2D soilLayer = CreateRectangularSoilLayer2D(0, -10, leftCoordinate, rightCoordinate, false); SoilLayer2D soilLayerAquiferPartOne = CreateRectangularSoilLayer2D(-10, -20, leftCoordinate, middleXCoordinate, true); SoilLayer2D soilLayerAquiferPartTwo = CreateRectangularSoilLayer2D(-5, -9, middleXCoordinate, rightCoordinate, 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); PlLines plLines = CreateAllPlLines(); // Call Waternet waternet = PlLinesToWaternetConverter.ConvertPlLineToWaternet(plLines, soilProfile, penetrationLength); // 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.That(waternet.WaternetLineList, Is.Empty); } /// /// --------------------------------------------------- Level 0 m /// top layer /// -------------------------|------------------------- Level -10 m /// bottom layer left | bottom layer right /// -------------------------|------------------------- Level -20 m /// [Test] [TestCase(true, false)] [TestCase(false, true)] public void ConvertPlLineToWaternet_ValidPLLinesAndSoilProfile2DWithBottomAquiferLayerNotSpanningWholeInterval_ReturnsEmptyWaternet( bool isLeftBottomLayerAquifer, bool isRightBottomLayerAquifer) { // Setup SoilLayer2D soilLayer = CreateRectangularSoilLayer2D(0, -10, leftCoordinate, rightCoordinate, false); SoilLayer2D soilLayerAquiferPartOne = CreateRectangularSoilLayer2D(-10, -20, leftCoordinate, middleXCoordinate, isLeftBottomLayerAquifer); SoilLayer2D soilLayerAquiferPartTwo = CreateRectangularSoilLayer2D(-10, -20, middleXCoordinate, rightCoordinate, isRightBottomLayerAquifer); 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); PlLines plLines = CreateAllPlLines(); // Call Waternet waternet = PlLinesToWaternetConverter.ConvertPlLineToWaternet(plLines, soilProfile, penetrationLength); // 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.That(waternet.WaternetLineList, Is.Empty); } [Test] [SetUICulture("nl-NL")] public void TestLanguageNLThrowsExceptionWhenSoilProfile1DIsNull() { var plLines = new PlLines(); Assert.That(() => PlLinesToWaternetConverter.ConvertPlLineToWaternet(plLines, null, 0, 0, 0), Throws.InstanceOf().With.Message.EqualTo("Geen ondergrond profiel gedefinieerd")); } [Test] [SetUICulture("nl-NL")] public void TestLanguageNLThrowsExceptionWhenPlLinesIsNull() { var soilProfile1D = new SoilProfile1D(); Assert.That(() => PlLinesToWaternetConverter.ConvertPlLineToWaternet(null, soilProfile1D, 0, 0, 0), Throws.InstanceOf().With.Message.EqualTo("Geen object voor pn-lijnen gedefinieerd")); } [Test] [SetUICulture("nl-NL")] public void ConvertPlLineToWaternet_SoilProfileNull_ThrowsException() { var plLines = new PlLines(); Assert.That(() => PlLinesToWaternetConverter.ConvertPlLineToWaternet(plLines, null, 0), Throws.InstanceOf().With.Message.EqualTo("Geen ondergrond profiel gedefinieerd")); } [Test] [SetUICulture("nl-NL")] public void ConvertPlLineToWaternet_ProfileLinesNull_ThrowsException() { var soilProfile = new SoilProfile2D(); Assert.That(() => PlLinesToWaternetConverter.ConvertPlLineToWaternet(null, soilProfile, 0), Throws.InstanceOf().With.Message.EqualTo("Geen object voor pn-lijnen gedefinieerd")); } private static PlLines CreatePlLinesForTest() { var plLines = new PlLines(); // pl 1 is phreatic line PlLine plLine = plLines.Lines[PlLineType.Pl1]; plLine.IsPhreatic = true; plLine.Points.Add(new PlLinePoint(0, 0)); plLine.Points.Add(new PlLinePoint(50, 1)); plLine.Points.Add(new PlLinePoint(100, 1)); // pl 2 first equal to point of pl 1 plLine = plLines.Lines[PlLineType.Pl2]; plLine.Points.Add(new PlLinePoint(0, 0)); plLine.Points.Add(new PlLinePoint(100, -1)); // pl 3 plLine = plLines.Lines[PlLineType.Pl3]; plLine.Points.Add(new PlLinePoint(0, 1)); plLine.Points.Add(new PlLinePoint(50, 0)); plLine.Points.Add(new PlLinePoint(100, -1)); // pl 4 plLine = plLines.Lines[PlLineType.Pl4]; plLine.Points.Add(new PlLinePoint(0, -5)); plLine.Points.Add(new PlLinePoint(100, -5)); return plLines; } private static SoilProfile1D CreateSoilProfile1DForTest() { var soilProfile1D = new SoilProfile1D { BottomLevel = -30.0 }; var layer = new SoilLayer1D { Name = "L1a", TopLevel = 1.212, IsAquifer = true // aquifer at top }; soilProfile1D.Layers.Add(layer); layer = new SoilLayer1D { Name = "L1b", TopLevel = 1.212, IsAquifer = false }; soilProfile1D.Layers.Add(layer); layer = new SoilLayer1D { Name = "L2a", TopLevel = -2.111, // top of in-between aquifer IsAquifer = true }; soilProfile1D.Layers.Add(layer); layer = new SoilLayer1D { Name = "L2b", TopLevel = -2.151, IsAquifer = true }; soilProfile1D.Layers.Add(layer); layer = new SoilLayer1D { Name = "L3", TopLevel = -3.373, IsAquifer = false }; soilProfile1D.Layers.Add(layer); layer = new SoilLayer1D { Name = "L4", TopLevel = -4.151, IsAquifer = true }; soilProfile1D.Layers.Add(layer); layer = new SoilLayer1D { Name = "L5", TopLevel = -5.373, IsAquifer = false }; soilProfile1D.Layers.Add(layer); layer = new SoilLayer1D { Name = "L6a", TopLevel = -6.111, // top of bottom aquifer IsAquifer = true }; soilProfile1D.Layers.Add(layer); layer = new SoilLayer1D { Name = "L6b", TopLevel = -6.151, IsAquifer = true }; soilProfile1D.Layers.Add(layer); layer = new SoilLayer1D { Name = "L7", TopLevel = -7.373, IsAquifer = false }; soilProfile1D.Layers.Add(layer); return soilProfile1D; } private static SoilProfile1D CreateSoilProfile1DWith1AquiferForTest() { var soilProfile1D = new SoilProfile1D { BottomLevel = -30.0 }; var layer = new SoilLayer1D { Name = "L1b", TopLevel = 1.212, IsAquifer = false }; soilProfile1D.Layers.Add(layer); layer = new SoilLayer1D { Name = "L6a", TopLevel = -6.111, // top of bottom aquifer IsAquifer = true }; soilProfile1D.Layers.Add(layer); return soilProfile1D; } private static SoilProfile1D CreateSoilProfile1DWithoutAquifersForTest() { var soilProfile1D = new SoilProfile1D { BottomLevel = -30.0 }; var layer = new SoilLayer1D { Name = "L1b", TopLevel = 1.212, IsAquifer = false }; soilProfile1D.Layers.Add(layer); return soilProfile1D; } /// /// Many test cases are considered using a different soil profile 2D: /// Within the method below, pictures of these soil profiles 2D are drawn to get a better idea of the test. /// private static IEnumerable GetSoilProfilesWithContinuousBottomAquiferLayer() { // TEST CASE 1: "Right aquifer fully adjoins left aquifer" // // ------------------------------------------------------------- Level 0 m // Upper layer (not aquifer) // -----------------------------|------------------------------- Level -10 m // Bottom aquifer layer left | Bottom aquifer layer right // -----------------------------|------------------------------- Level -20 m SoilLayer2D soilUpperLayer = CreateRectangularSoilLayer2D(0, -10, leftCoordinate, rightCoordinate, false); SoilLayer2D soilBottomLayerAquiferPartLeft = CreateRectangularSoilLayer2D(-10, -20, leftCoordinate, middleXCoordinate, true); SoilLayer2D soilBottomLayerAquiferPartRight = CreateRectangularSoilLayer2D(-10, -20, middleXCoordinate, rightCoordinate, true); var soilProfileFullAdjoin = new SoilProfile2D { Geometry = new GeometryData { Left = leftCoordinate, Right = rightCoordinate, Bottom = -20 } }; soilProfileFullAdjoin.Surfaces.Add(soilUpperLayer); soilProfileFullAdjoin.Surfaces.Add(soilBottomLayerAquiferPartLeft); soilProfileFullAdjoin.Surfaces.Add(soilBottomLayerAquiferPartRight); yield return new TestCaseData(soilProfileFullAdjoin, new[] { new GeometryPoint(leftCoordinate, -10), new GeometryPoint(middleXCoordinate, -10), new GeometryPoint(rightCoordinate, -10) }).SetName("Right aquifer fully adjoins left aquifer"); // TEST CASE 2: "One aquifer bottom layer" // // ------------------------------------------------------------- Level 0 m // Upper layer (not aquifer) // ------------------------------------------------------------- Level -10 m // Bottom aquifer layer // ------------------------------------------------------------- Level -20 m SoilLayer2D soilBottomLayerAquifer = CreateRectangularSoilLayer2D(-10, -20, leftCoordinate, rightCoordinate, true); var soilProfileOneBottomAquiferLayer = new SoilProfile2D { Geometry = new GeometryData { Left = leftCoordinate, Right = rightCoordinate, Bottom = -20 } }; soilProfileOneBottomAquiferLayer.Surfaces.Add(soilUpperLayer); soilProfileOneBottomAquiferLayer.Surfaces.Add(soilBottomLayerAquifer); yield return new TestCaseData(soilProfileOneBottomAquiferLayer, new[] { new GeometryPoint(leftCoordinate, -10), new GeometryPoint(rightCoordinate, -10) }).SetName("One aquifer bottom layer"); // TEST CASE 3: "Right aquifer only bottom in range" // // ------------------------------------------------------------- Level 0 m // Upper layer (not aquifer) |------------------------------ Level -5 m // ------------------------------| Right bottom aquifer layer Level -10 m // Left bottom aquifer layer |------------------------------ Level -15 m // ------------------------------| Level -20 m soilBottomLayerAquiferPartRight = CreateRectangularSoilLayer2D(-5, -15, middleXCoordinate, rightCoordinate, true); var soilProfileRightSoilLayerBottomInRange = new SoilProfile2D { Geometry = new GeometryData { Left = leftCoordinate, Right = rightCoordinate, Bottom = -20 } }; soilProfileRightSoilLayerBottomInRange.Surfaces.Add(soilUpperLayer); soilProfileRightSoilLayerBottomInRange.Surfaces.Add(soilBottomLayerAquiferPartLeft); soilProfileRightSoilLayerBottomInRange.Surfaces.Add(soilBottomLayerAquiferPartRight); soilProfileRightSoilLayerBottomInRange.Geometry.Surfaces.Add(new GeometrySurface()); yield return new TestCaseData(soilProfileRightSoilLayerBottomInRange, new[] { new GeometryPoint(leftCoordinate, -10), new GeometryPoint(middleXCoordinate, -5), new GeometryPoint(rightCoordinate, -5) }).SetName("Right aquifer only bottom in range"); // TEST CASE 4: "Right aquifer only top in range" // // ------------------------------------------------------------- Level 0 m // Upper layer (not aquifer) | // ------------------------------|------------------------------ Level -10 m // Left bottom aquifer layer |------------------------------ Level -15 m // ------------------------------| Right bottom aquifer layer | Level -20 m // |------------------------------ Level -25 m soilBottomLayerAquiferPartRight = CreateRectangularSoilLayer2D(-15, -25, middleXCoordinate, rightCoordinate, true); var soilProfileRightSoilLayerTopInRange = new SoilProfile2D { Geometry = new GeometryData { Left = leftCoordinate, Right = rightCoordinate, Bottom = -25 } }; soilProfileRightSoilLayerTopInRange.Surfaces.Add(soilUpperLayer); soilProfileRightSoilLayerTopInRange.Surfaces.Add(soilBottomLayerAquiferPartLeft); soilProfileRightSoilLayerTopInRange.Surfaces.Add(soilBottomLayerAquiferPartRight); soilProfileRightSoilLayerTopInRange.Geometry.Surfaces.Add(new GeometrySurface()); yield return new TestCaseData(soilProfileRightSoilLayerTopInRange, new[] { new GeometryPoint(leftCoordinate, -10), new GeometryPoint(middleXCoordinate, -10), new GeometryPoint(rightCoordinate, -15) }).SetName("Right aquifer only top in range"); // TEST CASE 5: "Right aquifer fully envelopes left aquifer" // // ------------------------------------------------------------- Level 0 m // Upper layer (not aquifer) |------------------------------ Level -5 m // ------------------------------| Level -10 m // Left bottom aquifer layer | Right bottom aquifer layer Level -15 m // ------------------------------| Level -20 m // |------------------------------ Level -25 m soilBottomLayerAquiferPartRight = CreateRectangularSoilLayer2D(-5, -25, middleXCoordinate, rightCoordinate, true); var soilProfileRightAquiferLayerFullyEnvelopsLeft = new SoilProfile2D { Geometry = new GeometryData { Left = leftCoordinate, Right = rightCoordinate, Bottom = -25 } }; soilProfileRightAquiferLayerFullyEnvelopsLeft.Surfaces.Add(soilUpperLayer); soilProfileRightAquiferLayerFullyEnvelopsLeft.Surfaces.Add(soilBottomLayerAquiferPartLeft); soilProfileRightAquiferLayerFullyEnvelopsLeft.Surfaces.Add(soilBottomLayerAquiferPartRight); soilProfileRightAquiferLayerFullyEnvelopsLeft.Geometry.Surfaces.Add(new GeometrySurface()); yield return new TestCaseData(soilProfileRightAquiferLayerFullyEnvelopsLeft, new[] { new GeometryPoint(leftCoordinate, -10), new GeometryPoint(middleXCoordinate, -5), new GeometryPoint(rightCoordinate, -5) }).SetName("Right aquifer fully envelopes left aquifer"); // TEST CASE 6: "Right aquifer fully enveloped by left aquifer" // // ------------------------------------------------------------- Level 0 m // Upper layer (not aquifer) | // ------------------------------|------------------------------ Level -10 m // Left bottom aquifer layer |------------------------------ Level -15 m // | Right bottom aquifer layer | // |------------------------------ Level -17 m // ------------------------------| Level -20 m soilBottomLayerAquiferPartRight = CreateRectangularSoilLayer2D(-15, -17, middleXCoordinate, rightCoordinate, true); var soilProfileRightAquiferLayerFullyEnvelopedByLeft = new SoilProfile2D { Geometry = new GeometryData { Left = leftCoordinate, Right = rightCoordinate, Bottom = -20 } }; soilProfileRightAquiferLayerFullyEnvelopedByLeft.Surfaces.Add(soilUpperLayer); soilProfileRightAquiferLayerFullyEnvelopedByLeft.Surfaces.Add(soilBottomLayerAquiferPartLeft); soilProfileRightAquiferLayerFullyEnvelopedByLeft.Surfaces.Add(soilBottomLayerAquiferPartRight); soilProfileRightAquiferLayerFullyEnvelopedByLeft.Geometry.Surfaces.Add(new GeometrySurface()); yield return new TestCaseData(soilProfileRightAquiferLayerFullyEnvelopedByLeft, new[] { new GeometryPoint(leftCoordinate, -10), new GeometryPoint(middleXCoordinate, -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, bool isAquifer) { return 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) } } }, IsAquifer = isAquifer }; } /// /// Creates a rectangular . /// /// /// /// /// /// /// A rectangular . private static SoilLayer2D CreateRectangularSoilLayer2D(double topCoord, double bottomCoord, double leftCoord, double rightCoord, bool isAquifer) { var topLeftPoint = new Point2D(leftCoord, topCoord); var topRightPoint= new Point2D(rightCoord, topCoord); var bottomRightPoint = new Point2D(rightCoord, bottomCoord); var bottomLeftPoint = new Point2D(leftCoord, bottomCoord); return CreateSoilLayer2D(topLeftPoint, topRightPoint, bottomRightPoint, bottomLeftPoint, isAquifer); } private static void AssertGeometry(IEnumerable expectedPoints, IEnumerable actualPoints) { GeometryPoint[] convertedPoints = expectedPoints.Select(p => new GeometryPoint(p.X, p.Z)).ToArray(); AssertGeometry(convertedPoints, actualPoints); } private static void AssertGeometry(IEnumerable expectedPoints, IEnumerable actualPoints) { int expectedNrOfPoints = expectedPoints.Count(); Assert.That(actualPoints.Count(), Is.EqualTo(expectedNrOfPoints)); for (var i = 0; i < expectedNrOfPoints; i++) { GeometryPoint expectedPoint = expectedPoints.ElementAt(i); GeometryPoint actualPoint = actualPoints.ElementAt(i); Assert.Multiple(() => { Assert.That(actualPoint.X, Is.EqualTo(expectedPoint.X)); Assert.That(actualPoint.Z, Is.EqualTo(expectedPoint.Z)); }); } } private static PlLines CreateAllPlLines() { var plLines = new PlLines(); PlLine plLine = plLines.Lines[PlLineType.Pl1]; plLine.Name = "Phreatic line"; plLine.Points.Add(new PlLinePoint(leftCoordinate, -5)); plLine.Points.Add(new PlLinePoint(rightCoordinate, -5)); plLine = plLines.Lines[PlLineType.Pl2]; plLine.Name = "PL 2"; plLine.Points.Add(new PlLinePoint(leftCoordinate, -6)); plLine.Points.Add(new PlLinePoint(rightCoordinate, -6)); plLine = plLines.Lines[PlLineType.Pl3]; plLine.Name = "PL 3"; plLine.Points.Add(new PlLinePoint(leftCoordinate, -7)); plLine.Points.Add(new PlLinePoint(rightCoordinate, -7)); plLine = plLines.Lines[PlLineType.Pl4]; plLine.Name = "PL 4"; plLine.Points.Add(new PlLinePoint(leftCoordinate, -8)); plLine.Points.Add(new PlLinePoint(rightCoordinate, -8)); return plLines; } }