// 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.Linq; using Deltares.DamEngine.Calculators.PlLinesCreator; using Deltares.DamEngine.Data.General; using Deltares.DamEngine.Data.Geometry; using Deltares.DamEngine.Data.Geotechnics; using Deltares.DamEngine.TestHelpers.Factories; using NUnit.Framework; using Exception = System.Exception; namespace Deltares.DamEngine.Calculators.Tests.PlLinesCreator; [TestFixture] public class SoilProfileValidatorTests { private const double leftCoordinate = -50; private const double rightCoordinate = 50; private const double middleXCoordinate = 0.5 * (leftCoordinate + rightCoordinate); private const string generalMessage = "Voor dit scenario wordt geen berekening uitgevoerd " + "omdat het ondergrondprofiel niet voldoet aan de eisen die aan de aanleg van het waternet worden gesteld: "; [SetUp] public void TestFixtureSetup() {} [SetUp] public void TestSetup() {} [Test] [SetUICulture("nl-NL")] public void GivenSurfaceLineIsNull_WhenValidating_ThenLanguageNLThrowsException() { var soilProfileValidator = new SoilProfileValidator { SurfaceLine = null }; Assert.That(() => soilProfileValidator.ValidateSoilProfileForPlLinesCreator(), Throws.InstanceOf().With.Message.EqualTo(generalMessage + "Geen hoogtegeometrie gedefinieerd.")); } [Test] [TestCase(CharacteristicPointType.DikeTopAtRiver)] [TestCase(CharacteristicPointType.DikeTopAtPolder)] [TestCase(CharacteristicPointType.DikeToeAtPolder)] [SetUICulture("nl-NL")] public void GivenSurfaceLineWhereRequiredCharacteristicPointsAreMissing_WhenValidating_ThenLanguageNLThrowsException(CharacteristicPointType missingPointType) { SurfaceLine2 surfaceLine = FactoryForSurfaceLines.CreateSurfacelineSimpleDike(); 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.")); } [Test] [SetUICulture("nl-NL")] public void GivenSurfaceLineWithOnlyOnePoint_WhenValidating_ThenLanguageNLThrowsException() { var soilProfileValidator = new SoilProfileValidator { 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.")); } [Test] [SetUICulture("nl-NL")] public void GivenSoilProfile1DIsNull_WhenValidating_ThenLanguageNLThrowsException() { var soilProfileValidator = new SoilProfileValidator { SurfaceLine = FactoryForSurfaceLines.CreateSurfacelineSimpleDike(), SoilProfileType = SoilProfileType.ProfileType1D, SoilProfile1D = null }; 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 om de PL-lijnen te maken.")); } [Test] [SetUICulture("nl-NL")] public void GivenSoilProfile1DWithoutDikeEmbankmentMaterial_WhenValidating_ThenLanguageNLThrowsException() { var soilProfileValidator = new SoilProfileValidator { SurfaceLine = FactoryForSurfaceLines.CreateSurfacelineSimpleDike(), SoilProfileType = SoilProfileType.ProfileType1D, SoilProfile1D = FactoryForSoilProfiles.CreateClaySandProfile(out _), DikeEmbankmentMaterial = null }; 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 om de PL-lijnen te maken.")); } [Test] [SetUICulture("nl-NL")] public void GivenSoilProfile2DIsNull_WhenValidating_ThenLanguageNLThrowsException() { var soilProfileValidator = new SoilProfileValidator { SurfaceLine = FactoryForSurfaceLines.CreateSurfacelineSimpleDike(), SoilProfileType = SoilProfileType.ProfileType2D, SoilProfile2D = null }; 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 om de PL-lijnen te maken.")); } /// /// --------------------------------------------------- Level 0 m /// top layer /// --------------------------------------------------- Level -10 m /// bottom layer /// --------------------------------------------------- Level -20 m /// [Test] [SetUICulture("nl-NL")] [TestCase(true)] [TestCase(false)] public void GivenSoilProfile2DWithOnlyOneLayerType_WhenValidating_ThenLanguageNLThrowsException(bool areAllLayersAquifers) { // Setup SoilLayer2D soilLayerTop = FactoryForSoilProfiles.CreateRectangularSoilLayer2D(0, -10, leftCoordinate, rightCoordinate, null, null, areAllLayersAquifers); SoilLayer2D soilLayerBottom = FactoryForSoilProfiles.CreateRectangularSoilLayer2D(-10, -20, leftCoordinate, rightCoordinate, null, null, areAllLayersAquifers); var soilProfile = new SoilProfile2D { Geometry = new GeometryData { Left = leftCoordinate, Right = rightCoordinate, Bottom = -20 }, Name = "SoilProfileValidatorTest" }; soilProfile.Surfaces.Add(soilLayerTop); soilProfile.Surfaces.Add(soilLayerBottom); var soilProfileValidator = new SoilProfileValidator { SurfaceLine = FactoryForSurfaceLines.CreateHorizontalSurfaceLine(0, leftCoordinate, rightCoordinate), SoilProfileType = SoilProfileType.ProfileType2D, SoilProfile2D = soilProfile, DikeEmbankmentMaterial = new Soil() }; // Call and assert string missingLayerType = areAllLayersAquifers ? "waterkerende" : "watervoerende"; Assert.That(() => soilProfileValidator.ValidateSoilProfileForPlLinesCreator(), Throws.InstanceOf().With.Message.EqualTo (generalMessage + "Het ondergrondprofiel bevat geen " + missingLayerType + " laag.")); } /// /// --------------------------------------------------- Level 0 m /// top layer /// -------------------------|------------------------- Level -10 m /// bottom layer left | bottom layer right /// -------------------------|------------------------- Level -20 m /// [Test] [SetUICulture("nl-NL")] [TestCase(false, true, false)] [TestCase(false, false, true)] [TestCase(true, false, false)] public void GivenSoilProfile2DWithNoContinuousBottomAquiferLayer_WhenValidating_ThenLanguageNLThrowsException( bool isTopLayerAquifer, bool isLeftBottomLayerAquifer, bool isRightBottomLayerAquifer) { // Setup SoilLayer2D soilLayer = FactoryForSoilProfiles.CreateRectangularSoilLayer2D(0, -10, leftCoordinate, rightCoordinate, null, null, isTopLayerAquifer); SoilLayer2D soilLayerAquiferPartOne = FactoryForSoilProfiles.CreateRectangularSoilLayer2D(-10, -20, leftCoordinate, middleXCoordinate, null, null, isLeftBottomLayerAquifer); SoilLayer2D soilLayerAquiferPartTwo = FactoryForSoilProfiles.CreateRectangularSoilLayer2D(-10, -20, middleXCoordinate, rightCoordinate, null, null, isRightBottomLayerAquifer); var soilProfile = new SoilProfile2D { Geometry = new GeometryData { Left = leftCoordinate, Right = rightCoordinate, Bottom = -20 }, Name = "SoilProfileValidatorTest" }; soilProfile.Surfaces.Add(soilLayer); soilProfile.Surfaces.Add(soilLayerAquiferPartOne); soilProfile.Surfaces.Add(soilLayerAquiferPartTwo); var soilProfileValidator = new SoilProfileValidator { SurfaceLine = FactoryForSurfaceLines.CreateHorizontalSurfaceLine(0, leftCoordinate, rightCoordinate), SoilProfileType = SoilProfileType.ProfileType2D, SoilProfile2D = soilProfile, DikeEmbankmentMaterial = new Soil() }; // Call and assert Assert.That(() => soilProfileValidator.ValidateSoilProfileForPlLinesCreator(), Throws.InstanceOf().With.Message.EqualTo (generalMessage + "De onderste laag is geen (doorlopende) watervoerende laag in ondergrondprofiel 'SoilProfileValidatorTest'.")); } /// /// --------------------------------------------------- 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 GivenSoilProfile2DWithDiscontinuousBottomAquiferLayer_WhenValidating_ThenLanguageNLThrowsException() { // 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); 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); soilProfile.Geometry.Surfaces.Add(soilLayer.GeometrySurface); soilProfile.Geometry.Surfaces.Add(soilLayerAquiferPartOne.GeometrySurface); soilProfile.Geometry.Surfaces.Add(soilLayerAquiferPartTwo.GeometrySurface); var soilProfileValidator = new SoilProfileValidator { SurfaceLine = FactoryForSurfaceLines.CreateHorizontalSurfaceLine(0, leftCoordinate, rightCoordinate), SoilProfileType = SoilProfileType.ProfileType2D, SoilProfile2D = soilProfile, DikeEmbankmentMaterial = new Soil() }; // Call and assert Assert.That(() => soilProfileValidator.ValidateSoilProfileForPlLinesCreator(), Throws.InstanceOf().With.Message.EqualTo (generalMessage + "De onderste laag is geen (doorlopende) 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] [SetUICulture("nl-NL")] public void GivenSoilProfile2DWithIsolatedInBetweenAquifer_WhenValidating_ThenLanguageNLThrowsException() { // Setup var soilProfile = new SoilProfile2D { Geometry = new GeometryData { Left = leftCoordinate, Right = rightCoordinate, Bottom = -20 }, Name = "SoilProfileTest" }; 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, SoilProfile2D = soilProfile }; // Call and assert Assert.That(() => soilProfileValidator.ValidateSoilProfileForPlLinesCreator(), Throws.InstanceOf().With.Message.EqualTo (generalMessage + "Ten minste één niet doorlopende watervoerende laag aanwezig.")); } /// /// _______ Level 5 m /// / Clay \ /// /---------\ Level 4 m /// / \ /// ------------/ \ Level 2 m /// \--------------- Level 1 m /// Bottom aquifer /// ------------------------------------------- Level -10 m /// [Test] public void GivenClayDikeBodyOnSand_WhenValidating_ThenNoExceptionReturned() { const bool isException = true; try { SurfaceLine2 surfaceLine = FactoryForSurfaceLines.CreateSurfacelineSimpleDike(); SoilProfile1D soilProfile1D = FactoryForSoilProfiles.CreateClaySandProfile(out _, 4); var soilSurfaceProfile = new SoilSurfaceProfile { SoilProfile = soilProfile1D, SurfaceLine2 = surfaceLine, DikeEmbankmentMaterial = new Soil(), Name = "Clay dike on Sand" }; SoilProfile2D soilProfile2D = soilSurfaceProfile.ConvertToSoilProfile2D(); var soilProfileValidator = new SoilProfileValidator { SoilProfileType = SoilProfileType.ProfileType2D, SurfaceLine = surfaceLine, SoilProfile2D = soilProfile2D, DikeEmbankmentMaterial = new Soil() }; soilProfileValidator.ValidateSoilProfileForPlLinesCreator(); } catch (Exception e) { 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 GivenSoilProfile2DWithInBetweenAquifersCuttingTheSurfaceLineAtDikeBodyAndAtDitch_WhenValidating_ThenNoExceptionReturned() { const bool isException = true; try { 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 = "Test" }; SoilProfile2D soilProfile2D = soilSurfaceProfile.ConvertToSoilProfile2D(); var soilProfileValidator = new SoilProfileValidator { SoilProfileType = SoilProfileType.ProfileType2D, SurfaceLine = surfaceLine, SoilProfile2D = soilProfile2D, DikeEmbankmentMaterial = new Soil() }; soilProfileValidator.ValidateSoilProfileForPlLinesCreator(); } catch (Exception e) { Assert.That(isException, Is.False, "No exception was expected however the following exception was thrown: " + e.Message); } } }