Index: DamEngine/trunk/src/Deltares.DamEngine.Calculators/KernelWrappers/MacroStabilityCommon/PlLinesToWaternetConverter.cs =================================================================== diff -u -r5033 -r5044 --- DamEngine/trunk/src/Deltares.DamEngine.Calculators/KernelWrappers/MacroStabilityCommon/PlLinesToWaternetConverter.cs (.../PlLinesToWaternetConverter.cs) (revision 5033) +++ DamEngine/trunk/src/Deltares.DamEngine.Calculators/KernelWrappers/MacroStabilityCommon/PlLinesToWaternetConverter.cs (.../PlLinesToWaternetConverter.cs) (revision 5044) @@ -466,6 +466,9 @@ case IntrusionVerticalWaterPressureType.SemiTimeDependent: { double level = soilProfile1D.GetLayerAt(phreaticLine.GetMinZ()).BottomLevel; + // Make sure the waternet line for PL 1 is not below the one for PL 3 + double bottomAquiferLevel = soilProfile1D.BottomAquiferLayer.TopLevel; + level = Math.Max(level, bottomAquiferLevel); return CreateWaternetLine(level, xLeft, xRight); } case null: @@ -560,6 +563,16 @@ top.SortPointsByXAscending(); curves.Add(top); } + + // For lowest layers that intersect the phreatic line the bottom of these layers is kept + if (intersectionPoints.Count > 0 && outerLoop.Points.Any(p => Math.Abs(p.Z - soilProfile2D.GetSoilProfile1D(p.X).BottomLevel) < epsilon)) + { + var geometrySurface = new GeometrySurface(outerLoop); + GeometryPointString bottom = geometrySurface.DetermineBottomGeometrySurface(); + bottom.SyncPoints(); + bottom.SortPointsByXAscending(); + curves.Add(bottom); + } } // The waternet line is the polyline formed with the highest lines connected to each other. @@ -575,6 +588,13 @@ waternetLine.Points.Add(new GeometryPoint(relevantLine.BeginPoint.X, relevantLine.BeginPoint.Z)); waternetLine.Points.Add(new GeometryPoint(relevantLine.EndPoint.X, relevantLine.EndPoint.Z)); } + + // Make sure the waternet line for PL 1 is not in the bottom aquifer. + foreach (GeometryPoint waternetLinePoint in waternetLine.Points) + { + double bottomAquiferLevel = soilProfile2D.GetSoilProfile1D(waternetLinePoint.X).BottomAquiferLayer.TopLevel; + waternetLinePoint.Z = Math.Max(waternetLinePoint.Z, bottomAquiferLevel); + } waternetLine.SyncCalcPoints(); LineHelper.RemoveDuplicatedPoints(waternetLine.CalcPoints, epsilon); Index: DamEngine/trunk/src/Deltares.DamEngine.Data/Standard/ComputeDoubles.cs =================================================================== diff -u -r5043 -r5044 --- DamEngine/trunk/src/Deltares.DamEngine.Data/Standard/ComputeDoubles.cs (.../ComputeDoubles.cs) (revision 5043) +++ DamEngine/trunk/src/Deltares.DamEngine.Data/Standard/ComputeDoubles.cs (.../ComputeDoubles.cs) (revision 5044) @@ -68,9 +68,9 @@ /// less than another value. /// /// Uses a tolerance of 1e-3. - public static bool IsLessThanOrEqualTo(this double aValue1, double aValue2) + public static bool IsLessThanOrEqualTo(this double aValue1, double aValue2, double tolerance = cEpsilon) { - return !IsGreaterThan(aValue1, aValue2); + return !IsGreaterThan(aValue1, aValue2, tolerance); } /// @@ -91,9 +91,9 @@ /// Determines whether the specified value is significantly greater than another value. /// /// Uses a tolerance of 1e-3. - private static bool IsGreaterThan(this double aValue1, double aValue2) + private static bool IsGreaterThan(this double aValue1, double aValue2, double tolerance = cEpsilon) { - if (aValue1 - aValue2 > cEpsilon) + if (aValue1 - aValue2 > tolerance) { return true; } Index: DamEngine/trunk/src/Deltares.DamEngine.Calculators.Tests/KernelWrappers/MacroStabilityCommon/PlLinesToWaternetConverterTests.cs =================================================================== diff -u -r5020 -r5044 --- DamEngine/trunk/src/Deltares.DamEngine.Calculators.Tests/KernelWrappers/MacroStabilityCommon/PlLinesToWaternetConverterTests.cs (.../PlLinesToWaternetConverterTests.cs) (revision 5020) +++ DamEngine/trunk/src/Deltares.DamEngine.Calculators.Tests/KernelWrappers/MacroStabilityCommon/PlLinesToWaternetConverterTests.cs (.../PlLinesToWaternetConverterTests.cs) (revision 5044) @@ -74,21 +74,25 @@ // Call Waternet waternet = PlLinesToWaternetConverter.CreateWaternetBasedOnPlLines(plLines, soilProfile, surfaceLine, penetrationLength, leftCoordinate, rightCoordinate, IntrusionVerticalWaterPressureType.Standard); - // Assert - Assert.That(waternet.PhreaticLine, Is.Null); - Assert.That(waternet.HeadLineList, Is.Empty); - Assert.That(waternet.WaternetLineList, Is.Empty); + 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)] - [TestCase(IntrusionVerticalWaterPressureType.Linear, 1.212, 6)] - [TestCase(IntrusionVerticalWaterPressureType.HydroStatic, -2.110, 6)] - [TestCase(IntrusionVerticalWaterPressureType.FullHydroStatic, -30.000, 1)] - [TestCase(IntrusionVerticalWaterPressureType.SemiTimeDependent, -2.110, 7)] - [TestCase(IntrusionVerticalWaterPressureType.SemiTimeDependent, -2.110, 7)] - public void Given1DSoilProfileWithTwoInBetweenAquifers_WhenCreatingWaternetBasedOnPlLinesAnd1DSoilProfile_ThenReturnsValidWaternet(IntrusionVerticalWaterPressureType? pressureType, double levelWaternetPl1, int waternetLineCount) + [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 = CreatePlLinesForTest(); + PlLines plLines = CreateAllPlLines(pL1Level); SoilProfile1D soilProfile1D = CreateSoilProfile1DForTest(out GeometryPointString surfaceLine); Assert.Multiple(() => @@ -115,13 +119,11 @@ Assert.Multiple(() => { // phreatic line (PL 1) - Assert.That(waternet.PhreaticLine.Points, Has.Count.EqualTo(3)); - Assert.That(waternet.PhreaticLine.Points[0].X, Is.EqualTo(0).Within(precision3Decimals)); - Assert.That(waternet.PhreaticLine.Points[0].Z, Is.EqualTo(0).Within(precision3Decimals)); - Assert.That(waternet.PhreaticLine.Points[1].X, Is.EqualTo(50).Within(precision3Decimals)); - Assert.That(waternet.PhreaticLine.Points[1].Z, Is.EqualTo(1).Within(precision3Decimals)); - Assert.That(waternet.PhreaticLine.Points[2].X, Is.EqualTo(100).Within(precision3Decimals)); - Assert.That(waternet.PhreaticLine.Points[2].Z, Is.EqualTo(1).Within(precision3Decimals)); + 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: @@ -148,10 +150,10 @@ 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(0).Within(precision3Decimals)); - Assert.That(waternet.HeadLineList[0].Points[0].Z, Is.EqualTo(0).Within(precision3Decimals)); - Assert.That(waternet.HeadLineList[0].Points[1].X, Is.EqualTo(100).Within(precision3Decimals)); - Assert.That(waternet.HeadLineList[0].Points[1].Z, Is.EqualTo(-1).Within(precision3Decimals)); + 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)); @@ -236,18 +238,18 @@ [Test] public void GivenNullPlLines_WhenCreatingWaternetBasedOnPlLinesAnd1DSoilProfile_ThenReturnsNoHeadLines() { - PlLines plLines = CreatePlLinesForTest(); + 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.Count, Is.EqualTo(2)); - Assert.That(waternet.HeadLineList[1].Points.Count, Is.EqualTo(3)); + Assert.That(waternet.HeadLineList[1].Points.Count, Is.EqualTo(2)); Assert.That(waternet.HeadLineList[2].Points.Count, Is.EqualTo(2)); // phreatic line - Assert.That(waternet.PhreaticLine.Points.Count, Is.EqualTo(3)); + Assert.That(waternet.PhreaticLine.Points.Count, Is.EqualTo(2)); }); // check that no headline are added when Pl2, Pl3 or Pl4 does not exist or has no points @@ -260,15 +262,15 @@ { Assert.That(waternet.HeadLineList[0].Points, Has.Count.EqualTo(2)); // phreatic line - Assert.That(waternet.PhreaticLine.Points, Has.Count.EqualTo(3)); + Assert.That(waternet.PhreaticLine.Points, Has.Count.EqualTo(2)); }); } [Test] [SetUICulture("en-EN")] public void Given1DSoilProfileWithoutAquifer_WhenCreatingWaternetBasedOnPlLinesAnd1DSoilProfile_ThenReturnsException() { - PlLines plLines = CreatePlLinesForTest(); + 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); @@ -320,13 +322,14 @@ /// Aquifer 7a | Aquifer 7b | Aquifer 7c /// --------------------------------------------------- Level -35 m /// - [TestCase(IntrusionVerticalWaterPressureType.Standard, -9.999, 6, 2)] - [TestCase(IntrusionVerticalWaterPressureType.Linear, 20.000, 6, 2)] - [TestCase(IntrusionVerticalWaterPressureType.HydroStatic, 10.001, 6, 2)] - [TestCase(IntrusionVerticalWaterPressureType.FullHydroStatic, -35.000, 1, 0)] - [TestCase(IntrusionVerticalWaterPressureType.SemiTimeDependent, -9.999, 7, 3, penetrationLength)] - [TestCase(IntrusionVerticalWaterPressureType.SemiTimeDependent, -9.999, 6, 2, 0)] - public void Given2DSoilProfileWithTwoInBetweenAquifers_WhenCreatingWaternetBasedOnPlLinesAnd2DSoilProfile_ThenReturnsValidWaternet(IntrusionVerticalWaterPressureType? pressureType, double levelWaternetPl1, int waternetLineCount, int headlineCount, double penetrationZone = double.NaN) + [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; @@ -376,7 +379,7 @@ soilProfile.Geometry.SurfaceLine.CalcPoints.Add(new Point2D(rightCoordinate, 20)); soilProfile.Geometry.SurfaceLine.SyncPoints(); - PlLines plLines = CreateAllPlLines(); + PlLines plLines = CreateAllPlLines(pL1Level); // Call Waternet waternet = PlLinesToWaternetConverter.CreateWaternetBasedOnPlLines(plLines, soilProfile, penetrationZone, pressureType); @@ -1229,32 +1232,6 @@ Assert.That(() => PlLinesToWaternetConverter.CreateWaternetBasedOnPlLines(null, soilProfile, 0, IntrusionVerticalWaterPressureType.Standard), Throws.InstanceOf().With.Message.EqualTo("Geen object voor pn-lijnen gedefinieerd")); } - private static PlLines CreatePlLinesForTest() - { - var plLines = new PlLines(); - // pl 1 is phreatic line - PlLine plLine = plLines.Lines[PlLineType.Pl1]; - plLine.IsPhreatic = true; - plLine.Points.Add(new PlLinePoint(0, 0)); - plLine.Points.Add(new PlLinePoint(50, 1)); - plLine.Points.Add(new PlLinePoint(100, 1)); - // pl 2 first equal to point of pl 1 - plLine = plLines.Lines[PlLineType.Pl2]; - plLine.Points.Add(new PlLinePoint(0, 0)); - plLine.Points.Add(new PlLinePoint(100, -1)); - // pl 3 - plLine = plLines.Lines[PlLineType.Pl3]; - plLine.Points.Add(new PlLinePoint(0, 1)); - plLine.Points.Add(new PlLinePoint(50, 0)); - plLine.Points.Add(new PlLinePoint(100, -1)); - // pl 4 - plLine = plLines.Lines[PlLineType.Pl4]; - plLine.Points.Add(new PlLinePoint(0, -5)); - plLine.Points.Add(new PlLinePoint(100, -5)); - - return plLines; - } - private static SoilProfile1D CreateSoilProfile1DForTest(out GeometryPointString surfaceLine) { const double topLevel = 1.212;