// Copyright (C) Stichting Deltares 2018. 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.Collections.Generic; using System.Data; using System.Diagnostics; using System.IO; using System.Linq; using System.Xml.Linq; using Deltares.DamEngine.Calculators.KernelWrappers.Common; using Deltares.DamEngine.Calculators.KernelWrappers.DamMacroStabilityCommon; using Deltares.DamEngine.Calculators.KernelWrappers.DamMacroStabilityCommon.Assemblers; using Deltares.DamEngine.Calculators.KernelWrappers.DamMacroStabilityOutwards; using Deltares.DamEngine.Calculators.KernelWrappers.Interfaces; using Deltares.DamEngine.Calculators.Tests.KernelWrappers.DamMacroStabilityCommon; using Deltares.DamEngine.Data.Design; using Deltares.DamEngine.Data.General; using Deltares.DamEngine.Data.General.Results; using Deltares.DamEngine.Data.Standard.Calculation; using Deltares.DamEngine.Data.Standard.Logging; using Deltares.DamEngine.TestHelpers.Factories; using NUnit.Framework; namespace Deltares.DamEngine.Calculators.Tests.KernelWrappers.DamMacroStabilityOutwards { [TestFixture] public class DamMacroStabilityOutwardsKernelWrapperTests { private const string testFolder = @"KernelWrappers\DamMacroStabilityCommon\TestData"; [Test] public void TestObsoleteCalculationForProcess() { // expected is that preparation of this calculation is not done. var absoluteFolder = Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), testFolder)); var workingDir = Path.Combine(absoluteFolder, "FullOut"); // Relative paths in ini file do not work yet in DGeoStability 16.2. This is fixed in 18.1. if (Directory.Exists(workingDir)) { Directory.Delete(workingDir, true); } var damKernelInput = CreateDamKernelInput(); damKernelInput.CalculationDir = workingDir; var failureMechanismParametersMStab = new FailureMechanismParametersMStab { MStabParameters = { GridPosition = MStabGridPosition.Left, SearchMethod = MStabSearchMethod.Grid, CalculationOptions = { MinimalCircleDepth = 1.0 } }, ProjectWorkingPath = workingDir }; var kernelWrapper = new DamMacroStabilityOutwardsKernelWrapper { FailureMechanismParametersMStab = failureMechanismParametersMStab }; // Set the requested mechanism for this subsoil to Piping to make it irrelevant damKernelInput.SubSoilScenario.SegmentFailureMechanismType = FailureMechanismSystemType.Piping; // Prepare the wrapper. This should fail as the given mechanism is not relevant for this kernel IKernelDataInput damStabilityInput; IKernelDataOutput kernelOutput; var result = kernelWrapper.Prepare(damKernelInput, 0, out damStabilityInput, out kernelOutput); Assert.AreEqual(result, PrepareResult.NotRelevant); } [Test] public void TestFullCalculationForProcess() { // expected results are based on first run of this test as the actual values are irrelevant. const double diff = 0.01; var absoluteFolder = Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), testFolder)); var workingDir = Path.Combine(absoluteFolder, "FullOut"); // Relative paths in ini file do not work yet in DGeoStability 16.2. This is fixed in 18.1. if (Directory.Exists(workingDir)) { Directory.Delete(workingDir, true); } var damKernelInput = CreateDamKernelInput(); damKernelInput.ProjectDir = absoluteFolder; damKernelInput.CalculationDir = workingDir; var failureMechanismParametersMStab = new FailureMechanismParametersMStab { MStabParameters = { GridPosition = MStabGridPosition.Left, SearchMethod = MStabSearchMethod.Grid, CalculationOptions = { MinimalCircleDepth = 1.0 } }, ProjectWorkingPath = workingDir }; var kernelWrapper = new DamMacroStabilityOutwardsKernelWrapper { FailureMechanismParametersMStab = failureMechanismParametersMStab }; // Prepare the wrapper. Result is input for the calculation dll IKernelDataInput damStabilityInput; IKernelDataOutput kernelOutput; var result = kernelWrapper.Prepare(damKernelInput, 0, out damStabilityInput, out kernelOutput); Assert.AreEqual(result, PrepareResult.Successful); // Validate the input List messages; kernelWrapper.Validate(damStabilityInput, kernelOutput, out messages); Assert.AreEqual(0, messages.Count); // Run the dll kernelWrapper.Execute(damStabilityInput, kernelOutput, out messages); DamMacroStabilityOutput damMacroStabilityOutput = (DamMacroStabilityOutput) kernelOutput; Assert.AreEqual(0, messages.Count); Assert.AreEqual(2.935, damMacroStabilityOutput.StabilityOutputItems[0].Zone1Results.SafetyFactor, diff); Assert.IsNull(damMacroStabilityOutput.StabilityOutputItems[0].Zone2Results); // Fill the design results var designScenario = DamMacroStabilityTestHelper.CreateScenario(damKernelInput.Location); List results; kernelWrapper.PostProcess(damKernelInput, damMacroStabilityOutput, designScenario, "", out results); Assert.AreEqual(2.935, results[0].StabilityDesignResults.SafetyFactor, diff); Assert.AreEqual("", results[0].StabilityDesignResults.ResultMessage); Assert.AreEqual(CalculationResult.Succeeded, results[0].CalculationResult); Assert.AreEqual("_Pro(1D1)", results[0].BaseFileName); } [Test] public void TestValidate() { // expected result is one message var absoluteFolder = Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), testFolder)); var workingDir = Path.Combine(absoluteFolder, "FullOut"); // Relative paths in ini file do not work yet in DGeoStability 16.2. This is fixed in 18.1. if (Directory.Exists(workingDir)) { Directory.Delete(workingDir, true); } var damKernelInput = CreateDamKernelInput(true); damKernelInput.ProjectDir = absoluteFolder; damKernelInput.CalculationDir = workingDir; damKernelInput.Location.DikeEmbankmentMaterial = "Del_Ppp"; damKernelInput.Location.ShoulderEmbankmentMaterial = "Del_Ppp"; damKernelInput.Location.StabilityOptions.MinimalCircleDepth = 1.0; damKernelInput.Location.StabilityOptions.StabilityZoneType = MStabZonesType.ZoneAreas; var failureMechanismParametersMStab = new FailureMechanismParametersMStab { MStabParameters = { GridPosition = MStabGridPosition.Left, SearchMethod = MStabSearchMethod.Grid, ZonesType = MStabZonesType.ZoneAreas, ZoneAreas = new MStabZoneAreas() { DikeTableHeight = -1.70, DikeTableWidth = 3, XCoordinateStartRestProfile = 10 } }, ProjectWorkingPath = workingDir }; var kernelWrapper = new DamMacroStabilityOutwardsKernelWrapper { FailureMechanismParametersMStab = failureMechanismParametersMStab }; // Prepare the wrapper. Result is input for the calculation dll IKernelDataInput damStabilityInput; IKernelDataOutput kernelOutput; var result = kernelWrapper.Prepare(damKernelInput, 0, out damStabilityInput, out kernelOutput); Assert.AreEqual(result, PrepareResult.Successful); // Validate the input List messages; kernelWrapper.Validate(damStabilityInput, kernelOutput, out messages); // Outside in combination with ZoneTypes = areas is not allowed so 1 error expected. Assert.AreEqual(1, messages.Count); Assert.AreEqual(LogMessageType.Error, messages[0].MessageType); } private static DesignScenario CreateDesignScenario(Location location) { var scenario = DamMacroStabilityTestHelper.CreateScenario(location); scenario.Location.StabilityOptions = new StabilityOptions { TrafficLoad = 10.0, SoilGeometries2DPath = GetAbsoluteFolder(), SoilDatabaseName = Path.Combine(testFolder, "soilmaterials.mdb") }; return scenario; } private static string GetAbsoluteFolder() { var absoluteFolder = Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), testFolder)); return absoluteFolder; } private static DamKernelInput CreateDamKernelInput(bool realOut = false) { var absoluteFolder = GetAbsoluteFolder(); var soilDbName = Path.Combine(testFolder, "soilmaterials.mdb"); var soilGeometry2DName = "1D1.sti"; var surfaceLine = FactoryForSurfaceLines.CreateSurfaceLineTutorial1(); var location = DamMacroStabilityTestHelper.CreateLocation(surfaceLine); location.DamType = DamType.Regional; location.Name = "LocationName"; location.DikeEmbankmentMaterial = "OB1"; location.ShoulderEmbankmentMaterial = "OB2"; location.SoilList = DamMacroStabilityTestHelper.CreateSoilList(); location.SurfaceLine = surfaceLine; location.ModelFactors.RequiredSafetyFactorStabilityOuterSlope = 1.1; location.ModelFactors.UpliftCriterionStability = 1.2; if (realOut) { soilDbName = Path.Combine(absoluteFolder, "soilmaterialsOutwards.mdb"); soilGeometry2DName = "OutwardsZones.sti"; foreach (var characteristicPoint in surfaceLine.CharacteristicPoints) { characteristicPoint.Z = characteristicPoint.Z - 3; } location.PolderLevel = -11; } location.StabilityOptions = new StabilityOptions { TrafficLoad = 10.0, SoilGeometries2DPath = GetAbsoluteFolder(), SoilDatabaseName = soilDbName }; var subSoilScenario = new SoilGeometryProbability { StiFileName = soilGeometry2DName, SoilProfileType = SoilProfileType.ProfileTypeStiFile, SegmentFailureMechanismType = FailureMechanismSystemType.StabilityOutside }; var damFailureMechanismeCalculationSpecification = new DamFailureMechanismeCalculationSpecification() { FailureMechanismSystemType = FailureMechanismSystemType.StabilityOutside, StabilityModelType = MStabModelType.Bishop }; var damKernelInput = new DamKernelInput { DamFailureMechanismeCalculationSpecification = damFailureMechanismeCalculationSpecification, Location = location, SubSoilScenario = subSoilScenario }; return damKernelInput; } public XDocument ModifiedXmlDocument(string stiFileName) { var xmlFileName = Path.Combine(testFolder, "test.xml"); var geometryFileName = Path.Combine(testFolder, "DWP_1.sti"); var soilDbName = Path.Combine(testFolder, "DAM Tutorial Design0.soilmaterials.mdb"); // modify name of output sti file XDocument xDocument = XDocument.Load(xmlFileName); if (xDocument.Root != null) { XElement inputElement = (from element in xDocument.Root.Descendants() where element.Name.LocalName == DamMStabAssembler.XmlElementNameInput select element).Single(); XAttribute mstabFileName = inputElement.Attribute(DamMStabAssembler.XmlAttributeMStabFileName); Debug.Assert(mstabFileName != null, "mstabFileName != null"); mstabFileName.Value = stiFileName; // modify name of Soil DB Name XAttribute dbName = inputElement.Attribute(DamMStabAssembler.XmlAttributeSoilDBName); Debug.Assert(dbName != null, "dbName != null"); dbName.Value = soilDbName; // modify name of geometry input file XElement geometryOptionsElement = (from element in inputElement.Descendants() where element.Name.LocalName == DamMStabAssembler.XmlElementGeometryCreationOptions select element).Single(); XAttribute geomFileName = geometryOptionsElement.Attribute(DamMStabAssembler.XmlAttributeSoilGeometry2DFilename); Debug.Assert(geomFileName != null, "geomFileName != null"); geomFileName.Value = geometryFileName; } return xDocument; } [Test] public void TestCreateDGeoStabilityInputFile() { var stiFileName = Path.Combine(testFolder, "test.sti"); var expectedStiFileName = Path.Combine(testFolder, "expectedTest.sti"); if (File.Exists(stiFileName)) { File.Delete(stiFileName); } var xDocument = ModifiedXmlDocument(stiFileName); var kernelWrapper = new DamMacroStabilityOutwardsKernelWrapper(); kernelWrapper.CreateStiFile(xDocument); Assert.IsTrue(File.Exists(stiFileName)); Assert.AreEqual(ContentOfStiFile(expectedStiFileName), ContentOfStiFile(stiFileName)); } [Test] [ExpectedException(typeof(MacroStabilityException))] public void TestThrowsExceptionXmlFileNotValid() { var kernelWrapper = new DamMacroStabilityOutwardsKernelWrapper(); XDocument xDocument = new XDocument(); kernelWrapper.CreateStiFile(xDocument); } private string ContentOfStiFile(string stiFileName) { try { StreamReader stream = File.OpenText(stiFileName); for (int i = 1; i <= 7; i++) { stream.ReadLine(); // skip first 7 lines with date, time and filename } string text = stream.ReadToEnd(); stream.Close(); return text; } catch { return null; } } [Test] public void TestPostProcess() { var kernelWrapper = new DamMacroStabilityOutwardsKernelWrapper(); var damKernelInput = CreateDamKernelInput(); DamMacroStabilityOutputItem outputItem = new DamMacroStabilityOutputItem(); var zone1 = new DamMacroStabilityOutputItem.ResultsSingleZone { SafetyFactor = 1.1, CircleSurfacePointLeftXCoordinate = 1.2, CircleSurfacePointRightXCoordinate = 1.3 }; outputItem.Zone1Results = zone1; var zone2 = new DamMacroStabilityOutputItem.ResultsSingleZone { SafetyFactor = 0.9, CircleSurfacePointLeftXCoordinate = 2.2, CircleSurfacePointRightXCoordinate = 2.3 }; outputItem.Zone2Results = zone2; DamMacroStabilityOutput output = new DamMacroStabilityOutput { StabilityOutputItems = new List { outputItem } }; DesignScenario designScenario = CreateDesignScenario(damKernelInput.Location); List results; kernelWrapper.PostProcess(damKernelInput, output, designScenario, "", out results); Assert.AreEqual(1.1, results[0].StabilityDesignResults.SafetyFactor); Assert.AreEqual(1.1, results[0].StabilityDesignResults.Zone1SafetyFactor); Assert.AreEqual(1.3, results[0].StabilityDesignResults.LocalZone1EntryPointX); Assert.AreEqual(1.2, results[0].StabilityDesignResults.LocalZone1ExitPointX); Assert.AreEqual(0.9, results[0].StabilityDesignResults.Zone2SafetyFactor); Assert.AreEqual(2.3, results[0].StabilityDesignResults.LocalZone2EntryPointX); Assert.AreEqual(2.2, results[0].StabilityDesignResults.LocalZone2ExitPointX); } [Test] [ExpectedException(typeof(NoNullAllowedException), ExpectedMessage = "Geen invoer object gedefinieerd voor Macrostabiliteit")] [SetUICulture("nl-NL")] public void TestLanguageNLThrowsExceptionWhenInputIsNull() { DamMacroStabilityOutwardsKernelWrapper.StabilityCalculator(null); } [Test] [ExpectedException(typeof(NoNullAllowedException), ExpectedMessage = "No input object defined for Macro Stability")] [SetUICulture("en-US")] public void TestLanguageENThrowsExceptionWhenInputIsNull() { DamMacroStabilityOutwardsKernelWrapper.StabilityCalculator(null); } [Test] [ExpectedException(typeof(NoNullAllowedException), ExpectedMessage = "No input object defined for Macro Stability")] [SetUICulture("en-US")] public void PostProcessTestLanguageENThrowsExceptionWhenInputIsNull() { var kernelWrapper = new DamMacroStabilityOutwardsKernelWrapper(); List results; kernelWrapper.PostProcess(null, null, null, "", out results); } [Test] [ExpectedException(typeof(NoNullAllowedException), ExpectedMessage = "Geen uitvoer object gedefinieerd voor Macrostabiliteit")] [SetUICulture("nl-NL")] public void PostProcessTestThrowsExceptionWhenOutputIsNull() { var kernelWrapper = new DamMacroStabilityOutwardsKernelWrapper(); List results; var damKernelInput = CreateDamKernelInput(); kernelWrapper.PostProcess(damKernelInput, null, null, "", out results); } [Test] [ExpectedException(typeof(MacroStabilityException), ExpectedMessage = "De vereiste veiligheidsfactor ontbreekt")] [SetUICulture("nl-NL")] public void TestThrowsExceptionWhenRequiredSafetyFactorIsMissingNL() { PrepareWithInvalidFile(); } [Test] [ExpectedException(typeof(MacroStabilityException), ExpectedMessage = "Required safety factor must be specified")] [SetUICulture("en-US")] public void TestThrowsExceptionWhenRequiredSafetyFactorIsMissingEN() { PrepareWithInvalidFile(); } private void PrepareWithInvalidFile() { // expected results are based on test CanCalculateStabilitySafetyFactorGeometry2D // in 'https://repos.deltares.nl/repos/dam/dam classic' revision 190 var soilDbName = Path.Combine(testFolder, "soilmaterials.mdb"); var soilGeometry2DName = "1D1.sti"; var absoluteFolder = Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), testFolder)); var workingDir = Path.Combine(absoluteFolder, "FullOut"); // Relative paths in ini file do not work yet in DGeoStability 16.2. This is fixed in 18.1. if (Directory.Exists(workingDir)) { Directory.Delete(workingDir, true); } var surfaceLine = FactoryForSurfaceLines.CreateSurfaceLineTutorial1(); var location = DamMacroStabilityTestHelper.CreateLocation(surfaceLine); location.StabilityOptions = new StabilityOptions { TrafficLoad = 10.0, SoilGeometries2DPath = "", SoilDatabaseName = soilDbName }; location.ModelFactors.RequiredSafetyFactorStabilityInnerSlope = 1.1; location.ModelFactors.UpliftCriterionStability = 1.2; var subSoilScenario = new SoilGeometryProbability { StiFileName = soilGeometry2DName, SoilProfileType = SoilProfileType.ProfileTypeStiFile, SegmentFailureMechanismType = FailureMechanismSystemType.StabilityOutside }; var failureMechanismParametersMStab = new FailureMechanismParametersMStab { MStabParameters = { GridPosition = MStabGridPosition.Left, SearchMethod = MStabSearchMethod.GeneticAlgorithm, CalculationOptions = { MinimalCircleDepth = 1.0 } }, ProjectWorkingPath = workingDir }; var damKernelInput = new DamKernelInput { Location = location, SubSoilScenario = subSoilScenario, ProjectDir = absoluteFolder, CalculationDir = workingDir }; var kernelWrapper = new DamMacroStabilityOutwardsKernelWrapper { FailureMechanismParametersMStab = failureMechanismParametersMStab }; // Prepare the wrapper. Result is input for the calculation dll IKernelDataInput damStabilityInput; IKernelDataOutput kernelOutput; damKernelInput.DamFailureMechanismeCalculationSpecification = new DamFailureMechanismeCalculationSpecification(); kernelWrapper.Prepare(damKernelInput, 0, out damStabilityInput, out kernelOutput); } } }