// 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.Globalization; using System.IO; using System.Linq; using System.Threading; 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 Deltares.DamEngine.Interface; using Deltares.DamEngine.TestHelpers.Factories; using NUnit.Framework; namespace Deltares.DamEngine.Calculators.Tests.KernelWrappers.MacroStabilityCommon; public class PlLinesToWaternetConverterTests { private const string mapTestFiles = @"KernelWrappers\MacroStabilityCommon\TestFiles\"; private const double precision3Decimals = 0.00051; private const double precision6Decimals = 0.00000051; private const double penetrationLength = 0.5; 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); [Test] public void GivenALine_WhenSplittingAtTwoPoints_ThenReturnsThreeNewLines() { // Setup var line = new Line(new Point2D(0, 0), new Point2D(90, 9)); var xCoordinatesToBeAdded = new List() { 30, 60 }; List splitLines = []; // Call PlLinesToWaternetConverter.SplitLineAtXCoordinate(xCoordinatesToBeAdded, line, splitLines); // Assert Assert.That(splitLines, Has.Count.EqualTo(3)); Assert.Multiple(() => { Assert.That(splitLines[0].BeginPoint.X, Is.EqualTo(0)); Assert.That(splitLines[0].BeginPoint.Z, Is.EqualTo(0)); Assert.That(splitLines[0].EndPoint.X, Is.EqualTo(30)); Assert.That(splitLines[0].EndPoint.Z, Is.EqualTo(3)); Assert.That(splitLines[1].BeginPoint.X, Is.EqualTo(30)); Assert.That(splitLines[1].BeginPoint.Z, Is.EqualTo(3)); Assert.That(splitLines[1].EndPoint.X, Is.EqualTo(60)); Assert.That(splitLines[1].EndPoint.Z, Is.EqualTo(6)); Assert.That(splitLines[2].BeginPoint.X, Is.EqualTo(60)); Assert.That(splitLines[2].BeginPoint.Z, Is.EqualTo(6)); Assert.That(splitLines[2].EndPoint.X, Is.EqualTo(90)); Assert.That(splitLines[2].EndPoint.Z, Is.EqualTo(9)); }); } [Test] [TestCase(0)] [TestCase(0.01)] [TestCase(10)] public void GivenPlLinesFullyDefinedAtOrBelowBottomSoil1DProfile_WhenCreatingWaternetBasedOnPlLinesAnd1DSoilProfile_ThenReturnsEmptyWaternet(double offsetFromBottomOfProfile) { // Setup SoilProfile1D soilProfile = CreateSoilProfile1DForTest(out GeometryPointString surfaceLine); 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.CreateWaternetBasedOnPlLines(plLines, soilProfile, surfaceLine, penetrationLength, leftCoordinate, rightCoordinate, IntrusionVerticalWaterPressureType.Standard); Assert.Multiple(() => { // Assert Assert.That(waternet.PhreaticLine, Is.Null); Assert.That(waternet.HeadLineList, Is.Empty); Assert.That(waternet.WaternetLineList, Is.Empty); }); } [TestCase(IntrusionVerticalWaterPressureType.Standard, -2.110, 6, 0)] [TestCase(IntrusionVerticalWaterPressureType.Standard, -6.110, 6, -29)] [TestCase(IntrusionVerticalWaterPressureType.Linear, 1.212, 6, 0)] [TestCase(IntrusionVerticalWaterPressureType.HydroStatic, -2.110, 6, 0)] [TestCase(IntrusionVerticalWaterPressureType.FullHydroStatic, -30.000, 1, 0)] [TestCase(IntrusionVerticalWaterPressureType.SemiTimeDependent, -2.110, 7, 0)] [TestCase(IntrusionVerticalWaterPressureType.SemiTimeDependent, -2.110, 7, 0)] public void Given1DSoilProfileWithTwoInBetweenAquifers_WhenCreatingWaternetBasedOnPlLinesAnd1DSoilProfile_ThenReturnsValidWaternet(IntrusionVerticalWaterPressureType? pressureType, double levelWaternetPl1, int waternetLineCount, double pL1Level) { PlLines plLines = CreateAllPlLines(pL1Level); SoilProfile1D soilProfile1D = CreateSoilProfile1DForTest(out GeometryPointString surfaceLine); Assert.Multiple(() => { Assert.That(soilProfile1D.GetInBetweenAquiferClusters, Has.Count.EqualTo(2).Within(precision3Decimals)); Assert.That(soilProfile1D.GetInBetweenAquiferClusters[0].Item1.TopLevel, Is.EqualTo(-2.111).Within(precision3Decimals)); Assert.That(soilProfile1D.GetInBetweenAquiferClusters[0].Item2.BottomLevel, Is.EqualTo(-3.373).Within(precision3Decimals)); Assert.That(soilProfile1D.GetInBetweenAquiferClusters[1].Item1.TopLevel, Is.EqualTo(-4.151).Within(precision3Decimals)); Assert.That(soilProfile1D.GetInBetweenAquiferClusters[1].Item2.BottomLevel, Is.EqualTo(-5.373).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.CreateWaternetBasedOnPlLines(plLines, soilProfile1D, surfaceLine, penetrateLength, left, right, pressureType); // Pl 1 is the phreatic line and gets waternet line to bottom level of the deepest layer where PL 1 lies // Pl 2 gets waternet line to level of BottomAquiferLayer.TopLevel + penetrationLength // Pl 3 gets waternet line to level of BottomAquiferLayer // Pl 4 gets 4 waternet lines to level of InBetweenAquiferLayer.TopLevel and InBetweenAquiferLayer.BottomLevel for both in-between aquifers Assert.That(waternet.WaternetLineList, Has.Count.EqualTo(waternetLineCount)); Assert.Multiple(() => { // phreatic line (PL 1) Assert.That(waternet.PhreaticLine.Points, Has.Count.EqualTo(2)); Assert.That(waternet.PhreaticLine.Points[0].X, Is.EqualTo(leftCoordinate).Within(precision3Decimals)); Assert.That(waternet.PhreaticLine.Points[0].Z, Is.EqualTo(pL1Level).Within(precision3Decimals)); Assert.That(waternet.PhreaticLine.Points[1].X, Is.EqualTo(rightCoordinate).Within(precision3Decimals)); Assert.That(waternet.PhreaticLine.Points[1].Z, Is.EqualTo(pL1Level).Within(precision3Decimals)); WaternetLine waternetLinePl1 = waternet.WaternetLineList.Find(waternetLine => waternetLine.Name == "Waternet line phreatic line"); // expected: waternet line connected to pl1 has level: // - for DAM Standard and Semi time dependent types, -2.111 m + 1 mm (Pl1 is in layer 2 from 0 m to -2.111 m) // - for Linear type, 1.212 (the surface level) // - for Hydrostatic type, -2.111 m + 1 mm (Pl1 is in layer 2 from 0 m to -2.111 m) // - for Full hydrostatic, -30 (the bottom of the geometry) Assert.That(waternetLinePl1.HeadLine.Points, Is.EqualTo(waternet.PhreaticLine.Points)); Assert.That(waternetLinePl1.HeadLine.Name, Is.EqualTo(waternet.PhreaticLine.Name)); Assert.That(waternetLinePl1.Points, Has.Count.EqualTo(2)); Assert.That(waternetLinePl1.Points[0].X, Is.EqualTo(0).Within(precision3Decimals)); Assert.That(waternetLinePl1.Points[0].Z, Is.EqualTo(levelWaternetPl1).Within(precision3Decimals)); Assert.That(waternetLinePl1.Points[1].X, Is.EqualTo(100).Within(precision3Decimals)); Assert.That(waternetLinePl1.Points[1].Z, Is.EqualTo(levelWaternetPl1).Within(precision3Decimals)); }); // PL 2 WaternetLine waternetLinePl2 = waternet.WaternetLineList.Find(waternetLine => waternetLine.Name == "Penetration zone lower aquifer"); if (pressureType == IntrusionVerticalWaterPressureType.SemiTimeDependent) { Assert.Multiple(() => { Assert.That(waternet.HeadLineList[0].Points, Has.Count.EqualTo(2)); Assert.That(waternet.HeadLineList[0].Name, Is.EqualTo("Head line 2 (PL 2)")); // check the points of first headline that represents pl 2 Assert.That(waternet.HeadLineList[0].Points[0].X, Is.EqualTo(leftCoordinate).Within(precision3Decimals)); Assert.That(waternet.HeadLineList[0].Points[0].Z, Is.EqualTo(-6).Within(precision3Decimals)); Assert.That(waternet.HeadLineList[0].Points[1].X, Is.EqualTo(rightCoordinate).Within(precision3Decimals)); Assert.That(waternet.HeadLineList[0].Points[1].Z, Is.EqualTo(-6).Within(precision3Decimals)); // expected: waternet line connected to pl2 has level -6.111 + 2.1 = -4.011 Assert.That(waternetLinePl2.HeadLine, Is.EqualTo(waternet.HeadLineList[0])); Assert.That(waternetLinePl2.Points, Has.Count.EqualTo(2)); Assert.That(waternetLinePl2.Points[0].X, Is.EqualTo(0).Within(precision3Decimals)); Assert.That(waternetLinePl2.Points[0].Z, Is.EqualTo(-4.011).Within(precision3Decimals)); Assert.That(waternetLinePl2.Points[1].X, Is.EqualTo(100).Within(precision3Decimals)); Assert.That(waternetLinePl2.Points[1].Z, Is.EqualTo(-4.011).Within(precision3Decimals)); }); } else { Assert.That(waternetLinePl2, Is.Null); } // PL 3 and PL 4 WaternetLine waternetLinePl3 = waternet.WaternetLineList.Find(waternetLine => waternetLine.Name == "Waternet line lower aquifer"); WaternetLine waternetLinePl4TopInBetweenAquiferTop = waternet.WaternetLineList.Find(waternetLine => waternetLine.Name == "Waternet line in-between aquifer top (1)"); WaternetLine waternetLinePl4TopInBetweenAquiferBottom = waternet.WaternetLineList.Find(waternetLine => waternetLine.Name == "Waternet line in-between aquifer bottom (1)"); WaternetLine waternetLinePl4BottomInBetweenAquiferTop = waternet.WaternetLineList.Find(waternetLine => waternetLine.Name == "Waternet line in-between aquifer top (2)"); WaternetLine waternetLinePl4BottomInBetweenAquiferBottom = waternet.WaternetLineList.Find(waternetLine => waternetLine.Name == "Waternet line in-between aquifer bottom (2)"); if (pressureType != IntrusionVerticalWaterPressureType.FullHydroStatic) { Assert.Multiple(() => { // expected: waternet line connected to pl3 has level -6.111 Assert.That(waternetLinePl3.HeadLine.Name, Is.EqualTo("Head line 3 (PL 3)")); Assert.That(waternetLinePl3.Points, Has.Count.EqualTo(2)); }); Assert.Multiple(() => { Assert.That(waternetLinePl3.Points[0].Z, Is.EqualTo(-6.111).Within(precision3Decimals)); // expected: highest waternet lines connected to pl4 have levels -2.111 and -3.373 Assert.That(waternetLinePl4TopInBetweenAquiferTop.HeadLine.Name, Is.EqualTo("Head line 4 (PL 4)")); Assert.That(waternetLinePl4TopInBetweenAquiferTop.Points, Has.Count.EqualTo(2)); Assert.That(waternetLinePl4TopInBetweenAquiferBottom.HeadLine.Name, Is.EqualTo("Head line 4 (PL 4)")); Assert.That(waternetLinePl4TopInBetweenAquiferBottom.Points, Has.Count.EqualTo(2)); }); Assert.Multiple(() => { Assert.That(waternetLinePl4TopInBetweenAquiferTop.Points[0].X, Is.EqualTo(0).Within(precision3Decimals)); Assert.That(waternetLinePl4TopInBetweenAquiferTop.Points[0].Z, Is.EqualTo(-2.111).Within(precision3Decimals)); Assert.That(waternetLinePl4TopInBetweenAquiferTop.Points[1].X, Is.EqualTo(100).Within(precision3Decimals)); Assert.That(waternetLinePl4TopInBetweenAquiferTop.Points[1].Z, Is.EqualTo(-2.111).Within(precision3Decimals)); Assert.That(waternetLinePl4TopInBetweenAquiferBottom.Points[0].X, Is.EqualTo(0).Within(precision3Decimals)); Assert.That(waternetLinePl4TopInBetweenAquiferBottom.Points[0].Z, Is.EqualTo(-3.373).Within(precision3Decimals)); Assert.That(waternetLinePl4TopInBetweenAquiferBottom.Points[1].X, Is.EqualTo(100).Within(precision3Decimals)); Assert.That(waternetLinePl4TopInBetweenAquiferBottom.Points[1].Z, Is.EqualTo(-3.373).Within(precision3Decimals)); // expected: lowest waternet lines 4 connected to pl4 have levels -4.151 and -5.373 Assert.That(waternetLinePl4BottomInBetweenAquiferTop.HeadLine.Name, Is.EqualTo("Head line 4 (PL 4)")); Assert.That(waternetLinePl4BottomInBetweenAquiferTop.Points, Has.Count.EqualTo(2)); Assert.That(waternetLinePl4BottomInBetweenAquiferBottom.HeadLine.Name, Is.EqualTo("Head line 4 (PL 4)")); Assert.That(waternetLinePl4BottomInBetweenAquiferBottom.Points, Has.Count.EqualTo(2)); }); Assert.Multiple(() => { Assert.That(waternetLinePl4BottomInBetweenAquiferTop.Points[0].X, Is.EqualTo(0).Within(precision3Decimals)); Assert.That(waternetLinePl4BottomInBetweenAquiferTop.Points[0].Z, Is.EqualTo(-4.151).Within(precision3Decimals)); Assert.That(waternetLinePl4BottomInBetweenAquiferTop.Points[1].X, Is.EqualTo(100).Within(precision3Decimals)); Assert.That(waternetLinePl4BottomInBetweenAquiferTop.Points[1].Z, Is.EqualTo(-4.151).Within(precision3Decimals)); Assert.That(waternetLinePl4BottomInBetweenAquiferBottom.Points[0].X, Is.EqualTo(0).Within(precision3Decimals)); Assert.That(waternetLinePl4BottomInBetweenAquiferBottom.Points[0].Z, Is.EqualTo(-5.373).Within(precision3Decimals)); Assert.That(waternetLinePl4BottomInBetweenAquiferBottom.Points[1].X, Is.EqualTo(100).Within(precision3Decimals)); Assert.That(waternetLinePl4BottomInBetweenAquiferBottom.Points[1].Z, Is.EqualTo(-5.373).Within(precision3Decimals)); }); } else { Assert.Multiple(() => { Assert.That(waternetLinePl3, Is.Null); Assert.That(waternetLinePl4TopInBetweenAquiferTop, Is.Null); Assert.That(waternetLinePl4TopInBetweenAquiferBottom, Is.Null); Assert.That(waternetLinePl4BottomInBetweenAquiferTop, Is.Null); Assert.That(waternetLinePl4BottomInBetweenAquiferBottom, Is.Null); }); } } [Test] public void GivenNullPlLines_WhenCreatingWaternetBasedOnPlLinesAnd1DSoilProfile_ThenReturnsNoHeadLines() { PlLines plLines = CreateAllPlLines(); SoilProfile1D soilProfile1D = CreateSoilProfile1DForTest(out GeometryPointString surfaceLine); Waternet waternet = PlLinesToWaternetConverter.CreateWaternetBasedOnPlLines(plLines, soilProfile1D, surfaceLine, 0.5, 0, 0, IntrusionVerticalWaterPressureType.SemiTimeDependent); // head lines Assert.That(waternet.HeadLineList, Has.Count.EqualTo(3)); Assert.Multiple(() => { Assert.That(waternet.HeadLineList[0].Points, Has.Count.EqualTo(2)); Assert.That(waternet.HeadLineList[1].Points, Has.Count.EqualTo(2)); Assert.That(waternet.HeadLineList[2].Points, Has.Count.EqualTo(2)); // phreatic line Assert.That(waternet.PhreaticLine.Points, Has.Count.EqualTo(2)); }); // 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.CreateWaternetBasedOnPlLines(plLines, soilProfile1D, surfaceLine, 0.5, 0, 0, IntrusionVerticalWaterPressureType.SemiTimeDependent); // 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(2)); }); } [Test] [SetUICulture("en-EN")] public void Given1DSoilProfileWithoutAquifer_WhenCreatingWaternetBasedOnPlLinesAnd1DSoilProfile_ThenReturnsException() { PlLines plLines = CreateAllPlLines(); SoilProfile1D soilProfile1D = CreateSoilProfile1DForTest(out GeometryPointString surfaceLine); const double penetrateLength = 2.1; Waternet waternet = PlLinesToWaternetConverter.CreateWaternetBasedOnPlLines(plLines, soilProfile1D, surfaceLine, penetrateLength, 0, 0, IntrusionVerticalWaterPressureType.SemiTimeDependent); Assert.Multiple(() => { Assert.That(waternet.HeadLineList, Has.Count.EqualTo(3)); Assert.That(waternet.WaternetLineList, Has.Count.EqualTo(7)); }); // check that no waternet lines are added for pl4 when InBetweenAquiferLayer is null soilProfile1D = CreateSoilProfile1DWith1AquiferForTest(); waternet = PlLinesToWaternetConverter.CreateWaternetBasedOnPlLines(plLines, soilProfile1D, surfaceLine, penetrateLength, 0, 0, IntrusionVerticalWaterPressureType.SemiTimeDependent); Assert.Multiple(() => { Assert.That(waternet.HeadLineList, Has.Count.EqualTo(3)); Assert.That(waternet.WaternetLineList, Has.Count.EqualTo(3)); }); Assert.Multiple(() => { // expected waternet line 0 is connected to pl2 with level -6.111 + 2.1 = -4.011 Assert.That(waternet.WaternetLineList[1].HeadLine, Is.EqualTo(waternet.HeadLineList[0])); Assert.That(waternet.WaternetLineList[1].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[2].HeadLine, Is.EqualTo(waternet.HeadLineList[1])); Assert.That(waternet.WaternetLineList[2].Points[0].Z, Is.EqualTo(-6.111).Within(precision3Decimals)); }); // check that an exception is raised when no aquifer present soilProfile1D = CreateSoilProfile1DWithoutAquifersForTest(); Assert.That(() => PlLinesToWaternetConverter.CreateWaternetBasedOnPlLines(plLines, soilProfile1D, surfaceLine, penetrationLength, 0, 0, IntrusionVerticalWaterPressureType.Standard), Throws.InstanceOf().With.Message.EqualTo("The deepest layer is not an aquifer in soilprofile 'DefaultNameSoilProfile1D'.")); } /// X_a X_b /// --------------------------------------------------- Level 20 m /// Aquitard 1 /// --------------------------------------------------- Level 10 m /// Aquifer 2a | Aquifer 2b | Aquifer 2c /// --------------------------------------------------- Level 0 m /// Aquitard 3 /// --------------------------------------------------- Level -10 m /// Aquifer 4a | Aquifer 4b | Aquifer 4c /// --------------------------------------------------- Level -20 m /// Aquitard 5 /// --------------------------------------------------- Level -25 m /// Aquifer 6a | Aquifer 6b | Aquifer 6c /// --------------------------------------------------- Level -30 m /// Aquifer 7a | Aquifer 7b | Aquifer 7c /// --------------------------------------------------- Level -35 m /// [TestCase(IntrusionVerticalWaterPressureType.Standard, -9.999, 6, 2, -5)] [TestCase(IntrusionVerticalWaterPressureType.Standard, -24.999, 6, 2, -32)] [TestCase(IntrusionVerticalWaterPressureType.Linear, 20.000, 6, 2, -5)] [TestCase(IntrusionVerticalWaterPressureType.HydroStatic, 10.001, 6, 2, -5)] [TestCase(IntrusionVerticalWaterPressureType.FullHydroStatic, -35.000, 1, 0, -5)] [TestCase(IntrusionVerticalWaterPressureType.SemiTimeDependent, -24.999, 7, 3, -28, penetrationLength)] [TestCase(IntrusionVerticalWaterPressureType.SemiTimeDependent, 10.001, 6, 2, 15, 0)] public void Given2DSoilProfileWithTwoInBetweenAquifers_WhenCreatingWaternetBasedOnPlLinesAnd2DSoilProfile_ThenReturnsValidWaternet(IntrusionVerticalWaterPressureType? pressureType, double levelWaternetPl1, int waternetLineCount, int headlineCount, double pL1Level, double penetrationZone = double.NaN) { double xA = leftCoordinate + (rightCoordinate - leftCoordinate) / 3; double xB = rightCoordinate - (rightCoordinate - leftCoordinate) / 3; // Setup SoilLayer2D aquitard1 = CreateRectangularSoilLayer2D(20, 10, leftCoordinate, rightCoordinate, false); SoilLayer2D aquifer2A = CreateRectangularSoilLayer2D(10, 0, leftCoordinate, xA, true); SoilLayer2D aquifer2B = CreateRectangularSoilLayer2D(10, 0, xA, xB, true); SoilLayer2D aquifer2C = CreateRectangularSoilLayer2D(10, 0, xB, rightCoordinate, true); SoilLayer2D aquitard3 = CreateRectangularSoilLayer2D(0, -10, leftCoordinate, rightCoordinate, false); SoilLayer2D aquifer4A = CreateRectangularSoilLayer2D(-10, -20, leftCoordinate, xA, true); SoilLayer2D aquifer4B = CreateRectangularSoilLayer2D(-10, -20, xA, xB, true); SoilLayer2D aquifer4C = CreateRectangularSoilLayer2D(-10, -20, xB, rightCoordinate, true); SoilLayer2D aquitard5 = CreateRectangularSoilLayer2D(-20, -25, leftCoordinate, rightCoordinate, false); SoilLayer2D aquifer6A = CreateRectangularSoilLayer2D(-25, -30, leftCoordinate, xA, true); SoilLayer2D aquifer6B = CreateRectangularSoilLayer2D(-25, -30, xA, xB, true); SoilLayer2D aquifer6C = CreateRectangularSoilLayer2D(-25, -30, xB, rightCoordinate, true); SoilLayer2D aquifer7A = CreateRectangularSoilLayer2D(-30, -35, leftCoordinate, xA, true); SoilLayer2D aquifer7B = CreateRectangularSoilLayer2D(-30, -35, xA, xB, true); SoilLayer2D aquifer7C = CreateRectangularSoilLayer2D(-30, -35, xB, rightCoordinate, true); var soilProfile = new SoilProfile2D { Geometry = new GeometryData { Left = leftCoordinate, Right = rightCoordinate, Bottom = -35 } }; soilProfile.Surfaces.Add(aquitard1); soilProfile.Surfaces.Add(aquifer2A); soilProfile.Surfaces.Add(aquifer2B); soilProfile.Surfaces.Add(aquifer2C); soilProfile.Surfaces.Add(aquitard3); soilProfile.Surfaces.Add(aquifer4A); soilProfile.Surfaces.Add(aquifer4B); soilProfile.Surfaces.Add(aquifer4C); soilProfile.Surfaces.Add(aquitard5); soilProfile.Surfaces.Add(aquifer6A); soilProfile.Surfaces.Add(aquifer6B); soilProfile.Surfaces.Add(aquifer6C); soilProfile.Surfaces.Add(aquifer7A); soilProfile.Surfaces.Add(aquifer7B); soilProfile.Surfaces.Add(aquifer7C); soilProfile.Geometry.Surfaces.Add(new GeometrySurface()); soilProfile.Geometry.SurfaceLine.CalcPoints.Add(new Point2D(leftCoordinate, 20)); soilProfile.Geometry.SurfaceLine.CalcPoints.Add(new Point2D(rightCoordinate, 20)); soilProfile.Geometry.SurfaceLine.SyncPoints(); PlLines plLines = CreateAllPlLines(pL1Level); // Call Waternet waternet = PlLinesToWaternetConverter.CreateWaternetBasedOnPlLines(plLines, soilProfile, penetrationZone, pressureType); // Assert AssertGeometry(plLines.Lines[PlLineType.Pl1].Points, waternet.PhreaticLine.Points); Assert.That(waternet.HeadLineList, Has.Count.EqualTo(headlineCount)); var indexHeadlinePl3 = 0; var indexHeadlinePl4 = 1; if (pressureType == IntrusionVerticalWaterPressureType.SemiTimeDependent && penetrationZone > 0) { AssertGeometry(plLines.Lines[PlLineType.Pl2].Points, waternet.HeadLineList[0].Points); indexHeadlinePl3 += 1; indexHeadlinePl4 += 1; } if (pressureType != IntrusionVerticalWaterPressureType.FullHydroStatic) { AssertGeometry(plLines.Lines[PlLineType.Pl3].Points, waternet.HeadLineList[indexHeadlinePl3].Points); AssertGeometry(plLines.Lines[PlLineType.Pl4].Points, waternet.HeadLineList[indexHeadlinePl4].Points); } Assert.That(waternet.WaternetLineList, Has.Count.EqualTo(waternetLineCount)); WaternetLine pl1WaternetLine = waternet.WaternetLineList.Find(w => w.HeadLine.Name == waternet.PhreaticLine.Name); Assert.That(pl1WaternetLine.HeadLine.Name, Is.SameAs(waternet.PhreaticLine.Name)); Point2D[] expectedWaternetLine1 = [ new(leftCoordinate, levelWaternetPl1), new(rightCoordinate, levelWaternetPl1) ]; AssertGeometry(expectedWaternetLine1, pl1WaternetLine.Points); Point2D[] expectedBottomAquiferCoordinates = [ new(leftCoordinate, -25), new(rightCoordinate, -25) ]; WaternetLine pl2WaternetLine = waternet.WaternetLineList.Find(w => w.HeadLine.Name == "Head line 2 (PL 2)"); if (pressureType == IntrusionVerticalWaterPressureType.SemiTimeDependent && penetrationZone > 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); } else { Assert.That(pl2WaternetLine, Is.Null); } if (waternetLineCount > 1) { WaternetLine pl3WaternetLine = waternet.WaternetLineList.Find(w => w.HeadLine.Name == "Head line 3 (PL 3)"); Assert.That(pl3WaternetLine.HeadLine, Is.SameAs(waternet.HeadLineList[indexHeadlinePl3])); AssertGeometry(expectedBottomAquiferCoordinates, pl3WaternetLine.Points); WaternetLine pl4WaternetLine1Top = waternet.WaternetLineList.Find(w => w.Name == "Waternet line in-between aquifer top (1)"); Assert.That(pl4WaternetLine1Top.HeadLine, Is.SameAs(waternet.HeadLineList[indexHeadlinePl4])); AssertGeometry([ new Point2D(leftCoordinate, 10), new Point2D(rightCoordinate, 10) ], pl4WaternetLine1Top.Points); WaternetLine pl4WaternetLineBottom = waternet.WaternetLineList.Find(w => w.Name == "Waternet line in-between aquifer bottom (1)"); Assert.That(pl4WaternetLineBottom.HeadLine, Is.SameAs(waternet.HeadLineList[indexHeadlinePl4])); AssertGeometry([ new Point2D(leftCoordinate, 0), new Point2D(rightCoordinate, 0) ], pl4WaternetLineBottom.Points); WaternetLine pl4WaternetLine2Top = waternet.WaternetLineList.Find(w => w.Name == "Waternet line in-between aquifer top (2)"); Assert.That(pl4WaternetLine2Top.HeadLine, Is.SameAs(waternet.HeadLineList[indexHeadlinePl4])); AssertGeometry([ new Point2D(leftCoordinate, -10), new Point2D(rightCoordinate, -10) ], pl4WaternetLine2Top.Points); WaternetLine pl4WaternetLine2Bottom = waternet.WaternetLineList.Find(w => w.Name == "Waternet line in-between aquifer bottom (2)"); Assert.That(pl4WaternetLine2Bottom.HeadLine, Is.SameAs(waternet.HeadLineList[indexHeadlinePl4])); AssertGeometry([ new Point2D(leftCoordinate, -20), new Point2D(rightCoordinate, -20) ], pl4WaternetLine2Bottom.Points); } } [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. /// As there is only one aquifer, then the BottomAquifer is also the HighestAquifer. /// /// /// [Test] [TestCaseSource(nameof(GetSoilProfilesWithContinuousBottomAquiferLayer))] public void Given2DSoilProfileWithContinuousBottomAquifer_WhenDeterminingLayerBoundaryPointsOfBottomAquifer_ThenExpectedCoordinatesReturned( SoilProfile2D soilProfile, IEnumerable expectedBottomAquiferCoordinates) { // Call IEnumerable bottomAquifer = PlLinesToWaternetConverter.DetermineLayerBoundaryPoints(PlLinesToWaternetConverter.LayerType.BottomAquifer, soilProfile); IEnumerable highestAquifer = PlLinesToWaternetConverter.DetermineLayerBoundaryPoints(PlLinesToWaternetConverter.LayerType.HighestAquifer, soilProfile); // Assert AssertGeometry(bottomAquifer, expectedBottomAquiferCoordinates); AssertGeometry(highestAquifer, expectedBottomAquiferCoordinates); } /// /// --------------------------------------------------------------- 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 Given2DSoilProfileWithContinuousInBetweenAquiferLayerConsistingOfTwoParts_WhenDeterminingLayerBoundaryPointsOfInBetweenAquifer_ThenExpectedCoordinatesReturned() { // 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); soilProfile.Geometry.Surfaces.Add(new GeometrySurface()); // Call bool isInBetweenLayerPresent = PlLinesToWaternetConverter.AreInBetweenAquiferClustersPresent(soilProfile, out int count); IEnumerable topLevelInBetweenAquifer = PlLinesToWaternetConverter.DetermineLayerBoundaryPoints(PlLinesToWaternetConverter.LayerType.TopLayerInBetweenAquiferCluster, soilProfile, 0); IEnumerable bottomLevelInBetweenAquifer = PlLinesToWaternetConverter.DetermineLayerBoundaryPoints(PlLinesToWaternetConverter.LayerType.BottomLayerInBetweenAquiferCluster, soilProfile, 0); // Assert Assert.Multiple(() => { Assert.That(isInBetweenLayerPresent, Is.True); Assert.That(count, Is.EqualTo(1)); }); GeometryPoint[] expectedTop = [ new(leftCoordinate, -10), new(middleXCoordinate, -10), new(rightCoordinate, -10) ]; GeometryPoint[] expectedBottom = [ new(leftCoordinate, -20), new(middleXCoordinate, -20), new(rightCoordinate, -20) ]; AssertGeometry(topLevelInBetweenAquifer, expectedTop); AssertGeometry(bottomLevelInBetweenAquifer, expectedBottom); } /// /// --------------------------------------------------- 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 Given2DSoilProfileWithContinuousInBetweenAquiferLayerConsistingOfOnePart_WhenDeterminingLayerBoundaryPointsOfInBetweenAquifer_ThenExpectedCoordinatesReturned() { // 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); soilProfile.Geometry.Surfaces.Add(new GeometrySurface()); // Call bool isInBetweenLayerPresent = PlLinesToWaternetConverter.AreInBetweenAquiferClustersPresent(soilProfile, out int count); IEnumerable topLevelInBetweenAquifer = PlLinesToWaternetConverter.DetermineLayerBoundaryPoints(PlLinesToWaternetConverter.LayerType.TopLayerInBetweenAquiferCluster, soilProfile, 0); IEnumerable bottomLevelInBetweenAquifer = PlLinesToWaternetConverter.DetermineLayerBoundaryPoints(PlLinesToWaternetConverter.LayerType.BottomLayerInBetweenAquiferCluster, soilProfile, 0); // Assert Assert.Multiple(() => { Assert.That(isInBetweenLayerPresent, Is.True); Assert.That(count, Is.EqualTo(1)); }); GeometryPoint[] expectedTop = [ new(leftCoordinate, -10), new(rightCoordinate, -10) ]; GeometryPoint[] expectedBottom = [ new(leftCoordinate, -20), new(rightCoordinate, -20) ]; AssertGeometry(topLevelInBetweenAquifer, expectedTop); AssertGeometry(bottomLevelInBetweenAquifer, expectedBottom); } /// /// ------------------------------------------------------------- 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 Given2DSoilProfileWithContinuousInBetweenAquiferConsistingOfTwoLayersWithRightLayerTopLevelInRangeLeftLayer_WhenDeterminingLayerBoundaryPointsOfInBetweenAquifer_ThenExpectedCoordinatesReturned() { // 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); soilProfile.Geometry.Surfaces.Add(new GeometrySurface()); // Call bool isInBetweenLayerPresent = PlLinesToWaternetConverter.AreInBetweenAquiferClustersPresent(soilProfile, out int count); IEnumerable topLevelInBetweenAquifer = PlLinesToWaternetConverter.DetermineLayerBoundaryPoints(PlLinesToWaternetConverter.LayerType.TopLayerInBetweenAquiferCluster, soilProfile, 0); IEnumerable bottomLevelInBetweenAquifer = PlLinesToWaternetConverter.DetermineLayerBoundaryPoints(PlLinesToWaternetConverter.LayerType.BottomLayerInBetweenAquiferCluster, soilProfile, 0); // Assert Assert.Multiple(() => { Assert.That(isInBetweenLayerPresent, Is.True); Assert.That(count, Is.EqualTo(1)); }); GeometryPoint[] expectedTop = [ new(leftCoordinate, -10), new(middleXCoordinate, -10), new(middleXCoordinate, -15), new(rightCoordinate, -15) ]; GeometryPoint[] expectedBottom = [ new(leftCoordinate, -20), new(middleXCoordinate, -20), new(middleXCoordinate, -21), new(rightCoordinate, -21) ]; AssertGeometry(topLevelInBetweenAquifer, expectedTop); AssertGeometry(bottomLevelInBetweenAquifer, expectedBottom); } /// /// -------------------------------------------------------------- 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 Given2DSoilProfileWithContinuousInBetweenAquiferConsistingOfTwoLayersWithRightLayerBottomLevelInRangeLeftLayer_WhenDeterminingLayerBoundaryPointsOfInBetweenAquifer_ThenExpectedCoordinatesReturned() { // 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); soilProfile.Geometry.Surfaces.Add(new GeometrySurface()); // Call bool isInBetweenLayerPresent = PlLinesToWaternetConverter.AreInBetweenAquiferClustersPresent(soilProfile, out int count); IEnumerable topLevelInBetweenAquifer = PlLinesToWaternetConverter.DetermineLayerBoundaryPoints(PlLinesToWaternetConverter.LayerType.TopLayerInBetweenAquiferCluster, soilProfile, 0); IEnumerable bottomLevelInBetweenAquifer = PlLinesToWaternetConverter.DetermineLayerBoundaryPoints(PlLinesToWaternetConverter.LayerType.BottomLayerInBetweenAquiferCluster, soilProfile, 0); // Assert Assert.Multiple(() => { Assert.That(isInBetweenLayerPresent, Is.True); Assert.That(count, Is.EqualTo(1)); }); GeometryPoint[] expectedTop = [ new(leftCoordinate, -10), new(middleXCoordinate, -10), new(middleXCoordinate, -5), new(rightCoordinate, -5) ]; GeometryPoint[] expectedBottom = [ new(leftCoordinate, -20), new(middleXCoordinate, -20), new(rightCoordinate, -20) ]; AssertGeometry(topLevelInBetweenAquifer, expectedTop); AssertGeometry(bottomLevelInBetweenAquifer, expectedBottom); } /// /// ------------------------------------------------------------- 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 Given2DSoilProfileWithContinuousInBetweenAquiferConsistingOfTwoLayersWithRightLayerEnvelopedByLeftLayer_WhenDeterminingLayerBoundaryPointsOfInBetweenAquifer_ThenExpectedCoordinatesReturned() { // 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); soilProfile.Geometry.Surfaces.Add(new GeometrySurface()); // Call bool isInBetweenLayerPresent = PlLinesToWaternetConverter.AreInBetweenAquiferClustersPresent(soilProfile, out int count); IEnumerable topLevelInBetweenAquifer = PlLinesToWaternetConverter.DetermineLayerBoundaryPoints(PlLinesToWaternetConverter.LayerType.TopLayerInBetweenAquiferCluster, soilProfile, 0); IEnumerable bottomLevelInBetweenAquifer = PlLinesToWaternetConverter.DetermineLayerBoundaryPoints(PlLinesToWaternetConverter.LayerType.BottomLayerInBetweenAquiferCluster, soilProfile, 0); // Assert Assert.Multiple(() => { Assert.That(isInBetweenLayerPresent, Is.True); Assert.That(count, Is.EqualTo(1)); }); GeometryPoint[] expectedTop = [ new(leftCoordinate, -10), new(middleXCoordinate, -10), new(middleXCoordinate, -15), new(rightCoordinate, -15) ]; GeometryPoint[] expectedBottom = [ new(leftCoordinate, -20), new(middleXCoordinate, -20), new(middleXCoordinate, -17), new(rightCoordinate, -17) ]; AssertGeometry(topLevelInBetweenAquifer, expectedTop); AssertGeometry(bottomLevelInBetweenAquifer, expectedBottom); } /// /// ------------------------------------------------------------- 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 Given2DSoilProfileWithContinuousInBetweenAquiferConsistingOfTwoLayersWithLeftLayerEnvelopedByRightLayer_WhenDeterminingLayerBoundaryPointsOfInBetweenAquifer_ThenExpectedCoordinatesReturned() { // 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); soilProfile.Geometry.Surfaces.Add(new GeometrySurface()); // Call bool isInBetweenLayerPresent = PlLinesToWaternetConverter.AreInBetweenAquiferClustersPresent(soilProfile, out int count); IEnumerable topLevelInBetweenAquifer = PlLinesToWaternetConverter.DetermineLayerBoundaryPoints(PlLinesToWaternetConverter.LayerType.TopLayerInBetweenAquiferCluster, soilProfile, 0); IEnumerable bottomLevelInBetweenAquifer = PlLinesToWaternetConverter.DetermineLayerBoundaryPoints(PlLinesToWaternetConverter.LayerType.BottomLayerInBetweenAquiferCluster, soilProfile, 0); // Assert Assert.Multiple(() => { Assert.That(isInBetweenLayerPresent, Is.True); Assert.That(count, Is.EqualTo(1)); }); GeometryPoint[] expectedTop = [ new(leftCoordinate, -10), new(middleXCoordinate, -10), new(middleXCoordinate, -5), new(rightCoordinate, -5) ]; GeometryPoint[] expectedBottom = [ new(leftCoordinate, -20), new(middleXCoordinate, -20), new(middleXCoordinate, -21), new(rightCoordinate, -21) ]; AssertGeometry(topLevelInBetweenAquifer, expectedTop); AssertGeometry(bottomLevelInBetweenAquifer, expectedBottom); } /// /// --------------------------------------------------- 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 Given2DSoilProfileWithDiscontinuousInBetweenAquifer_WhenDeterminingInBetweenAquiferCount_ThenReturns0( 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); // Call bool isInBetweenLayerPresent = PlLinesToWaternetConverter.AreInBetweenAquiferClustersPresent(soilProfile, out int count); // Assert Assert.Multiple(() => { Assert.That(isInBetweenLayerPresent, Is.False); Assert.That(count, Is.EqualTo(0)); }); } /// /// --------------------------------------------------- Level 0 m /// /// |------------------------- Level -5 m /// top layer | right aquifer /// |------------------------- Level -9 m /// /// -------------------------|------------------------- Level -10 m /// left aquifer | /// -------------------------| Level -20 m /// [Test] [SetUICulture("nl-NL")] public void CreateWaternetBasedOnPlLines_ValidPLLinesAndSoilProfile2DWithDiscontinuousBottomAquiferLayer_ReturnsException() { // 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 }, Name = "SoilProfileTest" }; soilProfile.Surfaces.Add(soilLayer); soilProfile.Surfaces.Add(soilLayerAquiferPartOne); soilProfile.Surfaces.Add(soilLayerAquiferPartTwo); PlLines plLines = CreateAllPlLines(); // Call and assert Assert.That(() => PlLinesToWaternetConverter.CreateWaternetBasedOnPlLines(plLines, soilProfile, penetrationLength, IntrusionVerticalWaterPressureType.Standard), Throws.InstanceOf().With.Message.EqualTo("De onderste laag is geen watervoerende laag in grondprofiel 'SoilProfileTest'.")); } /// /// --------------------------------------------------- Level 0 m /// top layer /// -------------------------|------------------------- Level -10 m /// bottom layer left | bottom layer right /// -------------------------|------------------------- Level -20 m /// [Test] [SetUICulture("nl-NL")] [TestCase(true, false)] [TestCase(false, true)] public void CreateWaternetBasedOnPlLines_ValidPLLinesAndSoilProfile2DWithBottomAquiferLayerNotSpanningWholeInterval_ReturnsException( 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 }, Name = "SoilProfileTest" }; soilProfile.Surfaces.Add(soilLayer); soilProfile.Surfaces.Add(soilLayerAquiferPartOne); soilProfile.Surfaces.Add(soilLayerAquiferPartTwo); PlLines plLines = CreateAllPlLines(); // Call and assert Assert.That(() => PlLinesToWaternetConverter.CreateWaternetBasedOnPlLines(plLines, soilProfile, penetrationLength, IntrusionVerticalWaterPressureType.Standard), Throws.InstanceOf().With.Message.EqualTo("De onderste laag is geen watervoerende laag in grondprofiel 'SoilProfileTest'.")); } [Test] [SetUICulture("nl-NL")] public void GivenSoilProfile1DIsNull_WhenCreatingWaternetBasedOnPlLinesAndOn1DProfile_ThenLanguageNLThrowsException() { var plLines = new PlLines(); Assert.That(() => PlLinesToWaternetConverter.CreateWaternetBasedOnPlLines(plLines, null, null, 0, 0, 0, IntrusionVerticalWaterPressureType.Standard), Throws.InstanceOf().With.Message.EqualTo("Geen ondergrond profiel gedefinieerd")); } [Test] [SetUICulture("nl-NL")] public void GivenPlLinesIsNull_WhenCreatingWaternetBasedOnPlLinesAndOn1DProfile_ThenLanguageNLThrowsException() { var soilProfile1D = new SoilProfile1D(); Assert.That(() => PlLinesToWaternetConverter.CreateWaternetBasedOnPlLines(null, soilProfile1D, null, 0, 0, 0, IntrusionVerticalWaterPressureType.Standard), Throws.InstanceOf().With.Message.EqualTo("Geen object voor pn-lijnen gedefinieerd")); } [Test] [SetUICulture("nl-NL")] public void GivenSurfaceLineIsNull_WhenCreatingWaternetBasedOnPlLinesAndOn1DProfile_ThenLanguageNLThrowsException() { var soilProfile1D = new SoilProfile1D(); var plLines = new PlLines(); Assert.That(() => PlLinesToWaternetConverter.CreateWaternetBasedOnPlLines(plLines, soilProfile1D, null, 0, 0, 0, IntrusionVerticalWaterPressureType.Standard), Throws.InstanceOf().With.Message.EqualTo("Geen object voor maaiveld gedefinieerd")); } [Test] [SetUICulture("nl-NL")] public void GivenSoilProfile2DIsNull_WhenCreatingWaternetBasedOnPlLinesAnd2DProfile_ThenLanguageNLThrowsException() { var plLines = new PlLines(); Assert.That(() => PlLinesToWaternetConverter.CreateWaternetBasedOnPlLines(plLines, null, 0, IntrusionVerticalWaterPressureType.Standard), Throws.InstanceOf().With.Message.EqualTo("Geen ondergrond profiel gedefinieerd")); } [Test] [SetUICulture("nl-NL")] public void GivenPlLinesIsNull_WhenCreatingWaternetBasedOnPlLinesAndOn2DProfile_ThenLanguageNLThrowsException() { var soilProfile = new SoilProfile2D(); Assert.That(() => PlLinesToWaternetConverter.CreateWaternetBasedOnPlLines(null, soilProfile, 0, IntrusionVerticalWaterPressureType.Standard), Throws.InstanceOf().With.Message.EqualTo("Geen object voor pn-lijnen gedefinieerd")); } [Test] public void Given2DProfileDWP1AndPl1FromTutorialStability_WhenCreatingTheWaternetLineForPL1ForDAMStandard_ThenExpectedWaternetLineReturned() { // Setup const string inputFilename = "InputTutorialStabilitySoilProfileDWP1.xml"; string fullInputFilename = Path.Combine(mapTestFiles, inputFilename); Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; string inputString = File.ReadAllText(fullInputFilename); var engineInterface = new EngineInterface(inputString); SoilProfile2D soilProfile = engineInterface.DamProjectData.Dike.SoilProfiles2D[0]; var pL1 = new PlLine(); pL1.Points.Add(new PlLinePoint(0, 4.4)); pL1.Points.Add(new PlLinePoint(43.51, 4.4)); pL1.Points.Add(new PlLinePoint(46.42, 3.9)); pL1.Points.Add(new PlLinePoint(50.59, 3.9)); pL1.Points.Add(new PlLinePoint(60.76, 2.69)); pL1.Points.Add(new PlLinePoint(69.06, 1.6)); pL1.Points.Add(new PlLinePoint(74.75, 1.6)); pL1.Points.Add(new PlLinePoint(80.78, 1.6)); // Call WaternetLine waternetLine = PlLinesToWaternetConverter.CreateWaternetLineForPhreaticLineForDamStandard(soilProfile, pL1); // Assert Assert.That(waternetLine, Has.Count.EqualTo(9)); Assert.Multiple(() => { Assert.That(waternetLine.Points[0].X, Is.EqualTo(0).Within(precision3Decimals)); Assert.That(waternetLine.Points[0].Z, Is.EqualTo(0.92).Within(precision3Decimals)); Assert.That(waternetLine.Points[1].X, Is.EqualTo(10.14).Within(precision3Decimals)); Assert.That(waternetLine.Points[1].Z, Is.EqualTo(0.95).Within(precision3Decimals)); Assert.That(waternetLine.Points[2].X, Is.EqualTo(17.08).Within(precision3Decimals)); Assert.That(waternetLine.Points[2].Z, Is.EqualTo(0.88).Within(precision3Decimals)); Assert.That(waternetLine.Points[3].X, Is.EqualTo(19.45).Within(precision3Decimals)); Assert.That(waternetLine.Points[3].Z, Is.EqualTo(0.81).Within(precision3Decimals)); Assert.That(waternetLine.Points[4].X, Is.EqualTo(20.62).Within(precision3Decimals)); Assert.That(waternetLine.Points[4].Z, Is.EqualTo(0.3).Within(precision3Decimals)); Assert.That(waternetLine.Points[5].X, Is.EqualTo(21.84).Within(precision3Decimals)); Assert.That(waternetLine.Points[5].Z, Is.EqualTo(-0.61).Within(precision3Decimals)); Assert.That(waternetLine.Points[6].X, Is.EqualTo(23.08).Within(precision3Decimals)); Assert.That(waternetLine.Points[6].Z, Is.EqualTo(-0.38).Within(precision3Decimals)); Assert.That(waternetLine.Points[7].X, Is.EqualTo(24.61).Within(precision3Decimals)); Assert.That(waternetLine.Points[7].Z, Is.EqualTo(0.63).Within(precision3Decimals)); Assert.That(waternetLine.Points[8].X, Is.EqualTo(80.78).Within(precision3Decimals)); Assert.That(waternetLine.Points[8].Z, Is.EqualTo(0.63).Within(precision3Decimals)); }); } /// /// E I /// A |--------------------\------------------\-------------------| M Level 0 m /// | Aquitard 1 \ F Aquitard 2 \ J Aquitard 3 | /// B |----------------------\------------------\-----------------| N Level -8 m /// | Aquitard 4 \ G Aquitard 5 \ K Aquitard 6 | /// C |------------------------\------------------\---------------| O Level -12 m /// | Aquitard 7 \ H Aquitard 8 \ L Aquit. 9 | /// D |--------------------------\------------------\-------------| P Level -15 m /// | | /// | bottom aquifer layer | /// |-----------------------------------------------------------| Level -20 m /// [Test] [TestCase(-5, -8)] [TestCase(-10, -12)] [TestCase(-13, -15)] public void Given2DProfileWithInclinedLayerSeparations_WhenCreatingTheWaternetLineForPL1ForDAMStandardOption_ThenExpectedWaternetLineReturned(double pL1Level, double expectedWaternetLineLevel) { // Setup double xMiddle1 = leftCoordinate + (rightCoordinate - leftCoordinate) / 3; double xMiddle2 = leftCoordinate + 2 * (rightCoordinate - leftCoordinate) / 3; var pointA = new Point2D(leftCoordinate, 0); var pointB = new Point2D(leftCoordinate, -8); var pointC = new Point2D(leftCoordinate, -12); var pointD = new Point2D(leftCoordinate, -15); var pointE = new Point2D(xMiddle1, 0); var pointF = new Point2D(xMiddle1 + 0.0001, -8); var pointG = new Point2D(xMiddle1 + 0.0002, -12); var pointH = new Point2D(xMiddle1 + 0.0003, -15); var pointI = new Point2D(xMiddle2, 0); var pointJ = new Point2D(xMiddle2 + 0.0001, -8); var pointK = new Point2D(xMiddle2 + 0.0002, -12); var pointL = new Point2D(xMiddle2 + 0.0003, -15); var pointM = new Point2D(rightCoordinate, 0); var pointN = new Point2D(rightCoordinate, -8); var pointO = new Point2D(rightCoordinate, -12); var pointP = new Point2D(rightCoordinate, -15); SoilLayer2D soilLayer1 = FactoryForSoilProfiles.CreateQuadrilateralSoilLayer2D(pointA, pointE, pointF, pointB, "Layer1"); SoilLayer2D soilLayer2 = FactoryForSoilProfiles.CreateQuadrilateralSoilLayer2D(pointE, pointI, pointJ, pointF, "Layer2"); SoilLayer2D soilLayer3 = FactoryForSoilProfiles.CreateQuadrilateralSoilLayer2D(pointI, pointM, pointN, pointJ, "Layer3"); SoilLayer2D soilLayer4 = FactoryForSoilProfiles.CreateQuadrilateralSoilLayer2D(pointB, pointF, pointG, pointC, "Layer4"); SoilLayer2D soilLayer5 = FactoryForSoilProfiles.CreateQuadrilateralSoilLayer2D(pointF, pointJ, pointK, pointG, "Layer5"); SoilLayer2D soilLayer6 = FactoryForSoilProfiles.CreateQuadrilateralSoilLayer2D(pointJ, pointN, pointO, pointK, "Layer6"); SoilLayer2D soilLayer7 = FactoryForSoilProfiles.CreateQuadrilateralSoilLayer2D(pointC, pointG, pointH, pointD, "Layer7"); SoilLayer2D soilLayer8 = FactoryForSoilProfiles.CreateQuadrilateralSoilLayer2D(pointG, pointK, pointL, pointH, "Layer8"); SoilLayer2D soilLayer9 = FactoryForSoilProfiles.CreateQuadrilateralSoilLayer2D(pointK, pointO, pointP, pointL, "Layer9"); SoilLayer2D soilLayerBottom = CreateRectangularSoilLayer2D(-15, -20, leftCoordinate, rightCoordinate, true); var soilProfile = new SoilProfile2D { Geometry = new GeometryData { Left = leftCoordinate, Right = rightCoordinate, Bottom = -20 }, Name = "SoilProfileTest" }; soilProfile.Surfaces.Add(soilLayer1); soilProfile.Surfaces.Add(soilLayer2); soilProfile.Surfaces.Add(soilLayer3); soilProfile.Surfaces.Add(soilLayer4); soilProfile.Surfaces.Add(soilLayer5); soilProfile.Surfaces.Add(soilLayer6); soilProfile.Surfaces.Add(soilLayer7); soilProfile.Surfaces.Add(soilLayer8); soilProfile.Surfaces.Add(soilLayer9); soilProfile.Surfaces.Add(soilLayerBottom); soilProfile.Geometry.Surfaces.Add(new GeometrySurface()); PlLines plLines = CreateAllPlLines(pL1Level); // Call WaternetLine waternetLine = PlLinesToWaternetConverter.CreateWaternetLineForPhreaticLineForDamStandard(soilProfile, plLines.Lines[PlLineType.Pl1]); // Assert Assert.That(waternetLine, Has.Count.EqualTo(2)); Assert.Multiple(() => { Assert.That(waternetLine.Points[0].X, Is.EqualTo(leftCoordinate).Within(precision3Decimals)); Assert.That(waternetLine.Points[0].Z, Is.EqualTo(expectedWaternetLineLevel).Within(precision3Decimals)); Assert.That(waternetLine.Points[1].X, Is.EqualTo(rightCoordinate).Within(precision3Decimals)); Assert.That(waternetLine.Points[1].Z, Is.EqualTo(expectedWaternetLineLevel).Within(precision3Decimals)); }); } private static SoilProfile1D CreateSoilProfile1DForTest(out GeometryPointString surfaceLine) { const double topLevel = 1.212; surfaceLine = new GeometryPointString(); surfaceLine.Points.Add(new PlLinePoint(0, topLevel)); surfaceLine.Points.Add(new PlLinePoint(100, topLevel)); var soilProfile1D = new SoilProfile1D { BottomLevel = -30.0 }; var layer = new SoilLayer1D { Name = "L1a", TopLevel = topLevel, IsAquifer = true // aquifer at top }; soilProfile1D.Layers.Add(layer); layer = new SoilLayer1D { Name = "L1b", TopLevel = 0, IsAquifer = false }; soilProfile1D.Layers.Add(layer); layer = new SoilLayer1D { Name = "L2a", TopLevel = -2.111, // top of highest 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, // top of lowest in-between aquifer 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); soilProfileFullAdjoin.Geometry.Surfaces.Add(new GeometrySurface()); 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); soilProfileOneBottomAquiferLayer.Geometry.Surfaces.Add(new GeometrySurface()); 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, -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(middleXCoordinate, -15), 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, -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(middleXCoordinate, -15), 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).Within(precision6Decimals)); Assert.That(actualPoint.Z, Is.EqualTo(expectedPoint.Z).Within(precision6Decimals)); }); } } private static PlLines CreateAllPlLines(double pl1Level = -5) { var plLines = new PlLines(); PlLine plLine = plLines.Lines[PlLineType.Pl1]; plLine.Name = "Phreatic line"; plLine.Points.Add(new PlLinePoint(leftCoordinate, pl1Level)); plLine.Points.Add(new PlLinePoint(rightCoordinate, pl1Level)); 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; } }