// 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;
}
}