Index: DamEngine/trunk/src/Deltares.DamEngine.Calculators.Tests/PlLinesCreator/SoilProfileValidatorTests.cs =================================================================== diff -u -r5417 -r5427 --- DamEngine/trunk/src/Deltares.DamEngine.Calculators.Tests/PlLinesCreator/SoilProfileValidatorTests.cs (.../SoilProfileValidatorTests.cs) (revision 5417) +++ DamEngine/trunk/src/Deltares.DamEngine.Calculators.Tests/PlLinesCreator/SoilProfileValidatorTests.cs (.../SoilProfileValidatorTests.cs) (revision 5427) @@ -1,4 +1,4 @@ -// Copyright (C) Stichting Deltares 2025. All rights reserved. +// Copyright (C) Stichting Deltares 2024. All rights reserved. // // This file is part of the Dam Engine. // @@ -19,7 +19,6 @@ // Stichting Deltares and remain full property of Stichting Deltares at all times. // All rights reserved. -using System; using System.Linq; using Deltares.DamEngine.Calculators.PlLinesCreator; using Deltares.DamEngine.Data.General; @@ -45,7 +44,7 @@ [SetUp] public void TestSetup() {} - + [Test] [SetUICulture("nl-NL")] public void GivenSurfaceLineIsNull_WhenValidating_ThenLanguageNLThrowsException() @@ -57,7 +56,7 @@ Assert.That(() => soilProfileValidator.ValidateSoilProfileForPlLinesCreator(), Throws.InstanceOf().With.Message.EqualTo(generalMessage + "Geen hoogtegeometrie gedefinieerd.")); } - + [Test] [TestCase(CharacteristicPointType.DikeTopAtRiver)] [TestCase(CharacteristicPointType.DikeTopAtPolder)] @@ -66,20 +65,20 @@ public void GivenSurfaceLineWhereRequiredCharacteristicPointsAreMissing_WhenValidating_ThenLanguageNLThrowsException(CharacteristicPointType missingPointType) { SurfaceLine2 surfaceLine = FactoryForSurfaceLines.CreateSurfacelineSimpleDike(); - CharacteristicPoint pointToBeRemoved = surfaceLine.CharacteristicPoints.First(point => point.CharacteristicPointType == missingPointType ); + CharacteristicPoint pointToBeRemoved = surfaceLine.CharacteristicPoints.First(point => point.CharacteristicPointType == missingPointType); surfaceLine.CharacteristicPoints.Remove(pointToBeRemoved); - + var soilProfileValidator = new SoilProfileValidator { SurfaceLine = surfaceLine }; - + Assert.That(() => soilProfileValidator.ValidateSoilProfileForPlLinesCreator(), Throws.InstanceOf().With.Message.EqualTo - (generalMessage - + "Er ontbreekt tenminste één van de volgende verplichte karakteristieke punten: Kruin buitentalud, Kruin binnentalud, Teen dijk binnenwaarts.")); + (generalMessage + + "Er ontbreekt tenminste één van de volgende verplichte karakteristieke punten: Kruin buitentalud, Kruin binnentalud, Teen dijk binnenwaarts.")); } - + [Test] [SetUICulture("nl-NL")] public void GivenSurfaceLineWithOnlyOnePoint_WhenValidating_ThenLanguageNLThrowsException() @@ -89,12 +88,12 @@ SurfaceLine = new SurfaceLine2() }; soilProfileValidator.SurfaceLine.Geometry.Points.Add(new GeometryPoint(0, 0)); - + Assert.That(() => soilProfileValidator.ValidateSoilProfileForPlLinesCreator(), Throws.InstanceOf().With.Message.EqualTo - (generalMessage +"Ten minste twee hoogtegeometrie punten zijn vereist.")); + (generalMessage + "Ten minste twee hoogtegeometrie punten zijn vereist.")); } - + [Test] [SetUICulture("nl-NL")] public void GivenSoilProfile1DIsNull_WhenValidating_ThenLanguageNLThrowsException() @@ -107,10 +106,10 @@ }; Assert.That(() => soilProfileValidator.ValidateSoilProfileForPlLinesCreator(), Throws.InstanceOf().With.Message.EqualTo - (generalMessage - + "Er is niet voldoende informatie over het ondergrondprofiel (Profiel 1D, Profiel 2D of Ophoogmateriaal dijk) beschikbaar voor de PL-lijnen te maken.")); + (generalMessage + + "Er is niet voldoende informatie over het ondergrondprofiel (Profiel 1D, Profiel 2D of Ophoogmateriaal dijk) beschikbaar voor de PL-lijnen te maken.")); } - + [Test] [SetUICulture("nl-NL")] public void GivenSoilProfile1DWithoutDikeEmbankmentMaterial_WhenValidating_ThenLanguageNLThrowsException() @@ -124,10 +123,10 @@ }; Assert.That(() => soilProfileValidator.ValidateSoilProfileForPlLinesCreator(), Throws.InstanceOf().With.Message.EqualTo - (generalMessage + (generalMessage + "Er is niet voldoende informatie over het ondergrondprofiel (Profiel 1D, Profiel 2D of Ophoogmateriaal dijk) beschikbaar voor de PL-lijnen te maken.")); } - + [Test] [SetUICulture("nl-NL")] public void GivenSoilProfile2DIsNull_WhenValidating_ThenLanguageNLThrowsException() @@ -140,10 +139,10 @@ }; Assert.That(() => soilProfileValidator.ValidateSoilProfileForPlLinesCreator(), Throws.InstanceOf().With.Message.EqualTo - (generalMessage - + "Er is niet voldoende informatie over het ondergrondprofiel (Profiel 1D, Profiel 2D of Ophoogmateriaal dijk) beschikbaar voor de PL-lijnen te maken.")); + (generalMessage + + "Er is niet voldoende informatie over het ondergrondprofiel (Profiel 1D, Profiel 2D of Ophoogmateriaal dijk) beschikbaar voor de PL-lijnen te maken.")); } - + /// /// --------------------------------------------------- Level 0 m /// top layer @@ -177,7 +176,7 @@ soilProfile.Surfaces.Add(soilLayer); soilProfile.Surfaces.Add(soilLayerAquiferPartOne); soilProfile.Surfaces.Add(soilLayerAquiferPartTwo); - + var soilProfileValidator = new SoilProfileValidator { SurfaceLine = FactoryForSurfaceLines.CreateHorizontalSurfaceLine(0, leftCoordinate, rightCoordinate), @@ -187,13 +186,12 @@ }; // Call and assert - Assert.That(() => soilProfileValidator.ValidateSoilProfileForPlLinesCreator(), + Assert.That(() => soilProfileValidator.ValidateSoilProfileForPlLinesCreator(), Throws.InstanceOf().With.Message.EqualTo - (generalMessage - + "De onderste laag is geen (continue) watervoerende laag in ondergrondprofiel 'SoilProfileValidatorTest'.")); - + (generalMessage + + "De onderste laag is geen (continue) watervoerende laag in ondergrondprofiel 'SoilProfileValidatorTest'.")); } - + /// /// --------------------------------------------------- Level 0 m /// @@ -211,8 +209,8 @@ { // Setup SoilLayer2D soilLayer = FactoryForSoilProfiles.CreateRectangularSoilLayer2D(0, -10, leftCoordinate, rightCoordinate); - SoilLayer2D soilLayerAquiferPartOne = FactoryForSoilProfiles.CreateRectangularSoilLayer2D(-10, -20, leftCoordinate, middleXCoordinate, null, null,true); - SoilLayer2D soilLayerAquiferPartTwo = FactoryForSoilProfiles.CreateRectangularSoilLayer2D(-5, -9, middleXCoordinate, rightCoordinate, null,null, true); + SoilLayer2D soilLayerAquiferPartOne = FactoryForSoilProfiles.CreateRectangularSoilLayer2D(-10, -20, leftCoordinate, middleXCoordinate, null, null, true); + SoilLayer2D soilLayerAquiferPartTwo = FactoryForSoilProfiles.CreateRectangularSoilLayer2D(-5, -9, middleXCoordinate, rightCoordinate, null, null, true); var soilProfile = new SoilProfile2D { Geometry = new GeometryData @@ -226,6 +224,10 @@ soilProfile.Surfaces.Add(soilLayer); soilProfile.Surfaces.Add(soilLayerAquiferPartOne); soilProfile.Surfaces.Add(soilLayerAquiferPartTwo); + + soilProfile.Geometry.Surfaces.Add(soilLayer.GeometrySurface); + soilProfile.Geometry.Surfaces.Add(soilLayerAquiferPartOne.GeometrySurface); + soilProfile.Geometry.Surfaces.Add(soilLayerAquiferPartTwo.GeometrySurface); var soilProfileValidator = new SoilProfileValidator { @@ -236,45 +238,72 @@ }; // Call and assert - Assert.That(() => soilProfileValidator.ValidateSoilProfileForPlLinesCreator(), + Assert.That(() => soilProfileValidator.ValidateSoilProfileForPlLinesCreator(), Throws.InstanceOf().With.Message.EqualTo - (generalMessage - + "De onderste laag is geen (continue) watervoerende laag in ondergrondprofiel 'SoilProfileTest'.")); + (generalMessage + + "De onderste laag is geen (continue) watervoerende laag in ondergrondprofiel 'SoilProfileTest'.")); } + /// + /// -------------------------|------------------------- Level 0 m + /// | aquitard 2 + /// |------------------------- Level -5 m + /// aquitard | aquifer 1 + /// |------------------------- Level -9 m + /// | aquitard 3 + /// -------------------------|------------------------- Level -10 m + /// bottom aquifer + /// --------------------------------------------------- Level -20 m + /// [Test] - [TestCase(true)] - [TestCase(false)] [SetUICulture("nl-NL")] - public void GivenSoilProfile2DWithUniqueLayerType_WhenValidating_ThenLanguageNLThrowsException(bool areAllLayersAquifer) + public void GivenSoilProfile2DWithIsolatedInBetweenAquifer_WhenValidating_ThenLanguageNLThrowsException() { - SurfaceLine2 surfaceLine = FactoryForSurfaceLines.CreateSurfacelineSimpleDike(); - SoilProfile1D soilProfile1D = FactoryForSoilProfiles.CreateClaySandProfile(out _,surfaceLine.CharacteristicPoints.Select(p => p.Z).Max() - 1); - soilProfile1D.Layers[0].IsAquifer = areAllLayersAquifer; - soilProfile1D.Layers[1].IsAquifer = areAllLayersAquifer; - var soilSurfaceProfile = new SoilSurfaceProfile + // Setup + var soilProfile = new SoilProfile2D { - SoilProfile = soilProfile1D, - SurfaceLine2 = surfaceLine, - DikeEmbankmentMaterial = new Soil(), - Name = "Only sand" + Geometry = new GeometryData + { + Left = leftCoordinate, + Right = rightCoordinate, + Bottom = -20 + }, + Name = "SoilProfileTest" }; - SoilProfile2D soilProfile2D = soilSurfaceProfile.ConvertToSoilProfile2D(); + SoilLayer2D aquitard1 = FactoryForSoilProfiles.CreateRectangularSoilLayer2D(0, -10, leftCoordinate, middleXCoordinate); + SoilLayer2D aquitard2 = FactoryForSoilProfiles.CreateRectangularSoilLayer2D(0, -5, middleXCoordinate, rightCoordinate); + SoilLayer2D aquifer1 = FactoryForSoilProfiles.CreateRectangularSoilLayer2D(-5, -9, middleXCoordinate, rightCoordinate, null, soilProfile, true); + SoilLayer2D aquitard3 = FactoryForSoilProfiles.CreateRectangularSoilLayer2D(-9, -10, middleXCoordinate, rightCoordinate); + SoilLayer2D bottomAquifer = FactoryForSoilProfiles.CreateRectangularSoilLayer2D(-10, -20, leftCoordinate, rightCoordinate, null, null, true); + + soilProfile.Surfaces.Add(aquitard1); + soilProfile.Surfaces.Add(aquitard2); + soilProfile.Surfaces.Add(aquifer1); + soilProfile.Surfaces.Add(aquitard3); + soilProfile.Surfaces.Add(bottomAquifer); + soilProfile.Surfaces.Add(aquitard1); + + soilProfile.Geometry.Surfaces.Add(aquitard1.GeometrySurface); + soilProfile.Geometry.Surfaces.Add(aquitard2.GeometrySurface); + soilProfile.Geometry.Surfaces.Add(aquifer1.GeometrySurface); + soilProfile.Geometry.Surfaces.Add(aquitard3.GeometrySurface); + soilProfile.Geometry.Surfaces.Add(bottomAquifer.GeometrySurface); + soilProfile.Geometry.Surfaces.Add(aquitard1.GeometrySurface); + var soilProfileValidator = new SoilProfileValidator { + SurfaceLine = FactoryForSurfaceLines.CreateHorizontalSurfaceLine(0, leftCoordinate, rightCoordinate), SoilProfileType = SoilProfileType.ProfileType2D, - SurfaceLine = surfaceLine, - SoilProfile2D = soilProfile2D, - DikeEmbankmentMaterial = new Soil() + SoilProfile2D = soilProfile }; - - string layerTypeMissing = areAllLayersAquifer ? "waterkerende" : "watervoerende"; + + // Call and assert Assert.That(() => soilProfileValidator.ValidateSoilProfileForPlLinesCreator(), - Throws.InstanceOf().With.Message.EqualTo - (generalMessage + "Het ondergrondprofiel bevat helemaal geen " + layerTypeMissing + " laag.")); + Throws.InstanceOf().With.Message.EqualTo + (generalMessage + + "Ten minste één losse watervoerende laag aanwezig.")); } - [Test] public void GivenClayDikeBodyOnSand_WhenValidating_ThenNoExceptionReturned() @@ -307,9 +336,9 @@ Assert.That(isException, Is.False, "No exception was expected however the following exception was thrown: " + e.Message); } } - + [Test] - public void GivenSoilProfileWithTwoInBetweenAquifer_WhenValidating_ThenNoExceptionReturned() + public void GivenSoilProfileWithTwoClustersOfInBetweenAquifer_WhenValidating_ThenNoExceptionReturned() { const bool isException = true; try @@ -338,21 +367,37 @@ Assert.That(isException, Is.False, "No exception was expected however the following exception was thrown: " + e.Message); } } - + + /// + /// _______ Level 10 m + /// / Clay \ + /// /---------\ Level 5 m + /// / Aquifer \ + /// /-------------\ Level 2 m + /// -----------/ Clay \------\ /-------- Level 0 m + /// -----------------------------------\ /--------- Level -2 m + /// Aquifer \ / Aquifer + /// -------------------------------------\ /----------- Level -5 m + /// Clay \______/ Level -6 m + /// ---------------------------------------------------------- Level -7 m + /// Bottom aquifer + /// ---------------------------------------------------------- Level -10 m + /// [Test] - public void GivenDikeBodyWithInBetweenAquifer_WhenValidating_ThenNoExceptionReturned() + public void GivenSoilProfile2DWithInBetweenAquifersCuttingTheSurfaceLineAtDikeBodyAndAtDitch_WhenValidating_ThenNoExceptionReturned() { const bool isException = true; try { - SurfaceLine2 surfaceLine = FactoryForSurfaceLines.CreateSurfacelineSimpleDike(); - SoilProfile1D soilProfile1D = FactoryForSoilProfiles.CreateClaySandClaySandProfile(5, 4, 3, 0); + SurfaceLine2 surfaceLine = FactoryForSurfaceLines.CreateSurfaceLineWithDikeAndDitch(10, -6); + SoilProfile1D soilProfile1D = FactoryForSoilProfiles.CreateClaySandClaySandClaySandProfile(10, 5, 2, -2, -5, -7); + soilProfile1D.BottomLevel = -10; var soilSurfaceProfile = new SoilSurfaceProfile { SoilProfile = soilProfile1D, SurfaceLine2 = surfaceLine, DikeEmbankmentMaterial = new Soil(), - Name = "DikeBodyWithInBetweenAquifer" + Name = "Test" }; SoilProfile2D soilProfile2D = soilSurfaceProfile.ConvertToSoilProfile2D(); @@ -363,6 +408,7 @@ SoilProfile2D = soilProfile2D, DikeEmbankmentMaterial = new Soil() }; + soilProfileValidator.ValidateSoilProfileForPlLinesCreator(); } catch (Exception e) Index: DamEngine/trunk/src/Deltares.DamEngine.Calculators/Properties/Resources.Designer.cs =================================================================== diff -u -r5404 -r5427 --- DamEngine/trunk/src/Deltares.DamEngine.Calculators/Properties/Resources.Designer.cs (.../Resources.Designer.cs) (revision 5404) +++ DamEngine/trunk/src/Deltares.DamEngine.Calculators/Properties/Resources.Designer.cs (.../Resources.Designer.cs) (revision 5427) @@ -336,6 +336,12 @@ } } + internal static string SoilProfileValidator_IsolatedAquiferPresent { + get { + return ResourceManager.GetString("SoilProfileValidator_IsolatedAquiferPresent", resourceCulture); + } + } + internal static string SoilProfileValidator_NoAquifer { get { return ResourceManager.GetString("SoilProfileValidator_NoAquifer", resourceCulture); Index: DamEngine/trunk/src/Deltares.DamEngine.TestHelpers/Factories/FactoryForSurfaceLines.cs =================================================================== diff -u -r5404 -r5427 --- DamEngine/trunk/src/Deltares.DamEngine.TestHelpers/Factories/FactoryForSurfaceLines.cs (.../FactoryForSurfaceLines.cs) (revision 5404) +++ DamEngine/trunk/src/Deltares.DamEngine.TestHelpers/Factories/FactoryForSurfaceLines.cs (.../FactoryForSurfaceLines.cs) (revision 5427) @@ -553,7 +553,7 @@ /// Creates a surface line, that contains a dike and a ditch on the polder side. /// /// surface line - public static SurfaceLine2 CreateSurfaceLineWithDikeAndDitch() + public static SurfaceLine2 CreateSurfaceLineWithDikeAndDitch(double dikeTopLevel = 5, double ditchBottomLevel = -2) { var surfaceLine = new SurfaceLine2 { @@ -567,13 +567,12 @@ surfaceLine.EnsurePointOfType(0.0, 0, CharacteristicPointType.SurfaceLevelOutside); surfaceLine.EnsurePointOfType(10.0, 0, CharacteristicPointType.DikeToeAtRiver); - surfaceLine.EnsurePointOfType(34.5, 5, CharacteristicPointType.DikeTopAtRiver); - - surfaceLine.EnsurePointOfType(40.5, 5, CharacteristicPointType.DikeTopAtPolder); + surfaceLine.EnsurePointOfType(34.5, dikeTopLevel, CharacteristicPointType.DikeTopAtRiver); + surfaceLine.EnsurePointOfType(40.5, dikeTopLevel, CharacteristicPointType.DikeTopAtPolder); surfaceLine.EnsurePointOfType(50.5, 0, CharacteristicPointType.DikeToeAtPolder); surfaceLine.EnsurePointOfType(58.5, 0, CharacteristicPointType.DitchDikeSide); - surfaceLine.EnsurePointOfType(59.5, -2, CharacteristicPointType.BottomDitchDikeSide); - surfaceLine.EnsurePointOfType(61.5, -2, CharacteristicPointType.BottomDitchPolderSide); + surfaceLine.EnsurePointOfType(59.5, ditchBottomLevel, CharacteristicPointType.BottomDitchDikeSide); + surfaceLine.EnsurePointOfType(61.5, ditchBottomLevel, CharacteristicPointType.BottomDitchPolderSide); surfaceLine.EnsurePointOfType(62.5, 0, CharacteristicPointType.DitchPolderSide); surfaceLine.EnsurePointOfType(75.0, 0, CharacteristicPointType.SurfaceLevelInside); Index: DamEngine/trunk/src/Deltares.DamEngine.Calculators/Properties/Resources.resx =================================================================== diff -u -r5404 -r5427 --- DamEngine/trunk/src/Deltares.DamEngine.Calculators/Properties/Resources.resx (.../Resources.resx) (revision 5404) +++ DamEngine/trunk/src/Deltares.DamEngine.Calculators/Properties/Resources.resx (.../Resources.resx) (revision 5427) @@ -283,6 +283,9 @@ The deepest layer is not a (continuous) aquifer in soil profile '{0}'. + + At least one isolated aquifer is present. + The soil profile contains no aquifer layer at all. Index: DamEngine/trunk/src/Deltares.DamEngine.Calculators/PlLinesCreator/SoilProfileValidator.cs =================================================================== diff -u -r5415 -r5427 --- DamEngine/trunk/src/Deltares.DamEngine.Calculators/PlLinesCreator/SoilProfileValidator.cs (.../SoilProfileValidator.cs) (revision 5415) +++ DamEngine/trunk/src/Deltares.DamEngine.Calculators/PlLinesCreator/SoilProfileValidator.cs (.../SoilProfileValidator.cs) (revision 5427) @@ -56,6 +56,7 @@ ThrowsIfNoLayerWithType(LayerType.Aquifer); ThrowsIfNoLayerWithType(LayerType.Aquitard); ThrowIfNoBottomAquifer(); + ThrowIfIsolatedInBetweenAquifer(); } /// @@ -85,7 +86,26 @@ + string.Format(Resources.SoilProfileValidator_NoBottomAquiferLayer, SoilProfile2D.Name)); } } + + /// + /// Check if no isolated in-between aquifer(s) are present, which means that all the in-between aquifers must be continuous + /// aquifers from left to right of the geometry or of the surface line. + /// + /// + private void ThrowIfIsolatedInBetweenAquifer() + { + if (SoilProfileType != SoilProfileType.ProfileType2D) + { + return; + } + if (SoilProfile2DHelper.IsAtLeastOneIsolatedInBetweenAquiferPresent(SoilProfile2D, out _)) + { + throw new PlLinesCreatorException(Resources.SoilProfileValidator_General + + string.Format(Resources.SoilProfileValidator_IsolatedAquiferPresent, SoilProfile2D.Name)); + } + } + /// /// Check if at least one layer with the given type is present in the soil profile. /// Index: DamEngine/trunk/src/Deltares.DamEngine.TestHelpers/Factories/FactoryForSoilProfiles.cs =================================================================== diff -u -r5416 -r5427 --- DamEngine/trunk/src/Deltares.DamEngine.TestHelpers/Factories/FactoryForSoilProfiles.cs (.../FactoryForSoilProfiles.cs) (revision 5416) +++ DamEngine/trunk/src/Deltares.DamEngine.TestHelpers/Factories/FactoryForSoilProfiles.cs (.../FactoryForSoilProfiles.cs) (revision 5427) @@ -218,15 +218,15 @@ /// Create six layer soil profile with 3 aquifers /// /// soil profile - public static SoilProfile1D CreateClaySandClaySandClaySandProfile() + public static SoilProfile1D CreateClaySandClaySandClaySandProfile(double level1 = 10, double level2= 1, double level3 = -1.5, double level4 = -5, double level5 = -7, double level6 = -5) { var soilProfile = new SoilProfile1D(); var layer = new SoilLayer1D { Name = GetNewUniqueLayerId(soilProfile) }; - layer.TopLevel = 10.0; + layer.TopLevel = level1; layer.Soil = new Soil("HW-OBO", 12.0, 10.0); layer.Soil.DryUnitWeight = 0.01; layer.IsAquifer = false; @@ -236,7 +236,7 @@ { Name = GetNewUniqueLayerId(soilProfile) }; - layer.TopLevel = 1.0; + layer.TopLevel = level2; layer.Soil = new Soil("Alg-zand (0-30)", 22.0, 20.0); layer.Soil.DryUnitWeight = 0.01; layer.IsAquifer = true; @@ -246,7 +246,7 @@ { Name = GetNewUniqueLayerId(soilProfile) }; - layer.TopLevel = -1.5; + layer.TopLevel = level3; layer.Soil = new Soil("HW-DUN", 16.8, 15.8); layer.Soil.DryUnitWeight = 0.01; layer.IsAquifer = false; @@ -256,7 +256,7 @@ { Name = GetNewUniqueLayerId(soilProfile) }; - layer.TopLevel = -5.0; + layer.TopLevel = level4; layer.Soil = new Soil("Alg-zand (0-30)", 22.0, 20.0); layer.Soil.DryUnitWeight = 0.01; layer.IsAquifer = true; @@ -266,7 +266,7 @@ { Name = GetNewUniqueLayerId(soilProfile) }; - layer.TopLevel = -7.0; + layer.TopLevel = level5; layer.Soil = new Soil("HW-DUN", 16.8, 15.8); layer.Soil.DryUnitWeight = 0.01; layer.IsAquifer = false; @@ -276,13 +276,13 @@ { Name = GetNewUniqueLayerId(soilProfile) }; - layer.TopLevel = -9.0; + layer.TopLevel = level6; layer.Soil = new Soil("Alg-zand (0-30)", 22.0, 20.0); layer.Soil.DryUnitWeight = 0.01; layer.IsAquifer = true; soilProfile.Layers.Add(layer); - soilProfile.BottomLevel = -10.0; + soilProfile.BottomLevel = level6 - 10; return soilProfile; } Index: DamEngine/trunk/src/Deltares.DamEngine.Calculators/Properties/Resources.nl-NL.resx =================================================================== diff -u -r5404 -r5427 --- DamEngine/trunk/src/Deltares.DamEngine.Calculators/Properties/Resources.nl-NL.resx (.../Resources.nl-NL.resx) (revision 5404) +++ DamEngine/trunk/src/Deltares.DamEngine.Calculators/Properties/Resources.nl-NL.resx (.../Resources.nl-NL.resx) (revision 5427) @@ -285,6 +285,9 @@ De onderste laag is geen (continue) watervoerende laag in ondergrondprofiel '{0}'. + + Ten minste één losse watervoerende laag aanwezig. + Het ondergrondprofiel bevat helemaal geen watervoerende laag. Index: DamEngine/trunk/src/Deltares.DamEngine.Calculators/KernelWrappers/Common/SoilProfile2DHelper.cs =================================================================== diff -u -r5382 -r5427 --- DamEngine/trunk/src/Deltares.DamEngine.Calculators/KernelWrappers/Common/SoilProfile2DHelper.cs (.../SoilProfile2DHelper.cs) (revision 5382) +++ DamEngine/trunk/src/Deltares.DamEngine.Calculators/KernelWrappers/Common/SoilProfile2DHelper.cs (.../SoilProfile2DHelper.cs) (revision 5427) @@ -42,22 +42,10 @@ Top, Bottom } - + private const double deviationX = 1e-06; private const double toleranceAlmostEqual = 1e-09; - /// - /// Determine all the xCoordinates to make cross-sections. - /// - /// The soil profile 2D. - /// All the xCoordinates of the soil profile 2D. - private static double[] DetermineAllXCoordinatesOfSoilProfile(SoilProfile2D soilProfile) - { - IEnumerable points = soilProfile.Surfaces.SelectMany(surf => surf.GeometrySurface.OuterLoop.CalcPoints); - double[] xCoordinates = points.Select(point => point.X).OrderBy(x => x).Distinct().ToArray(); - return xCoordinates; - } - internal static bool AreInBetweenAquiferClustersPresent(SoilProfile2D soilProfile, out int count) { double[] xCoordinates = DetermineAllXCoordinatesOfSoilProfile(soilProfile); @@ -79,7 +67,59 @@ count = currentCount; return count > 0; } + + public static bool IsAtLeastOneIsolatedInBetweenAquiferPresent(SoilProfile2D soilProfile, out int count) + { + double[] xCoordinates = DetermineAllXCoordinatesOfSoilProfile(soilProfile); + var previousCount = 0; + count = 0; + SoilProfile1D previousCrossSection = null; + for (var i = 0; i < xCoordinates.Length; i++) + { + SoilProfile1D crossSection = soilProfile.GetSoilProfile1D(xCoordinates[i]); + int currentCount = crossSection.GetInBetweenAquiferClusters?.Count ?? 0; + count = i == 0 ? currentCount : count; + if (i > 0 && currentCount != previousCount) + { + // If more than one new or one less in-between aquifers are found, at least one is an isolated aquifer. + if (Math.Abs(currentCount - previousCount) > 1) + { + count = -1; + return true; + } + + if (currentCount > 0 && crossSection.GetInBetweenAquiferClusters != null) + { + // If one new in-between aquifer is found, the top layer in the previous cross-section must be an aquifer. + // If not, it is an isolated aquifer. + if (currentCount - previousCount == 1) + { + if (!previousCrossSection.Layers[0].IsAquifer) + { + count = -1; + return true; + } + count++; + } + + // If one less in-between aquifer is found, the top layer in the current section must be an aquifer. + // If not, it is an isolated aquifer. + if (previousCount - currentCount == 1 && !crossSection.Layers[0].IsAquifer) + { + count = -1; + return true; + } + } + } + + previousCount = currentCount; + previousCrossSection = crossSection; + } + + return false; + } + /// /// Determines all the points of the layer boundary for the specified layer type: /// - For LayerType = BottomAquiferCluster, layerBoundaryTop is the top boundary of the bottom aquifer (= waternet line for PL3) @@ -123,17 +163,17 @@ // If not, return empty coordinates, because the cluster of layers is interrupted. double currentAquiferTop = GetLevel(layerType, BoundaryType.Top, crossSection, indexInBetweenAquifer); double currentAquiferBottom = GetLevel(layerType, BoundaryType.Bottom, crossSection, indexInBetweenAquifer); - - if (!double.IsNaN(previousAquiferTop) && !double.IsNaN(previousAquiferBottom) - && !double.IsNaN(currentAquiferTop) + + if (!double.IsNaN(previousAquiferTop) && !double.IsNaN(previousAquiferBottom) + && !double.IsNaN(currentAquiferTop) && !double.IsNaN(currentAquiferBottom) && !AreHorizontallyConnected(previousAquiferTop, previousAquiferBottom, currentAquiferTop, currentAquiferBottom)) { layerBoundaryTop = null; layerBoundaryBottom = null; return; } - + if (!double.IsNaN(currentAquiferTop) && !double.IsNaN(currentAquiferBottom)) { previousAquiferTop = currentAquiferTop; @@ -152,10 +192,23 @@ layerBoundaryBottom = null; return; } + layerBoundaryTop = layerBoundaryTopPoints.ToArray(); layerBoundaryBottom = layerBoundaryBottomPoints.ToArray(); } + /// + /// Determine all the xCoordinates to make cross-sections. + /// + /// The soil profile 2D. + /// All the xCoordinates of the soil profile 2D. + private static double[] DetermineAllXCoordinatesOfSoilProfile(SoilProfile2D soilProfile) + { + IEnumerable points = soilProfile.Surfaces.SelectMany(surf => surf.GeometrySurface.OuterLoop.CalcPoints); + double[] xCoordinates = points.Select(point => point.X).OrderBy(x => x).Distinct().ToArray(); + return xCoordinates; + } + private static bool IsLayerBoundaryContinuous(IEnumerable boundaryPoints, double leftGeometryBoundary, double rightGeometryBoundary) { IEnumerable point2Ds = boundaryPoints.ToList(); @@ -173,7 +226,7 @@ return double.NaN; } - + private static SoilLayer1D GetLayer(LayerType layerType, BoundaryType boundaryType, SoilProfile1D soilProfile1D, int indexInBetweenAquifer) { switch (layerType) @@ -190,7 +243,7 @@ return null; } - + private static bool HasAquiferAVerticalPartAtGivenX(LayerType layerType, double xCoordinate, SoilProfile2D soilProfile, int indexInBetweenAquifer) { SoilProfile1D crossSectionLeft = soilProfile.GetSoilProfile1D(xCoordinate - deviationX);