// Copyright (C) Stichting Deltares 2019. 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.DamMacroStabilityInwards; 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.Logging; using Deltares.DamEngine.TestHelpers.Factories; using NUnit.Framework; namespace Deltares.DamEngine.Calculators.Tests.KernelWrappers.DamMacroStabilityInwards { [TestFixture] public class DamMacroStabilityInwardsKernelWrapperTests { private const string TestFolder = @"..\..\Deltares.DamEngine.Calculators.Tests\KernelWrappers\DamMacroStabilityCommon\TestData"; [Test] public void TestFullCalculationBishop() { // expected results are based on test CanCalculateStabilitySafetyFactorGeometry2D // in 'https://repos.deltares.nl/repos/dam/dam classic' revision 190 var expectedValues = new List { 1.5570 }; FullCalculation(MStabModelType.Bishop, expectedValues, expectedValues); } [Test, Category("Slow")] public void TestFullCalculationUpliftVan() { // expected results are based on test CanCalculateStabilitySafetyFactorGeometry2D // in 'https://repos.deltares.nl/repos/dam/dam classic' revision 190 // but I changed (in dam classic) the model to UpliftVan // and added UpliftCriterionStability = 1.2 // result in dam classic = 1.0610 var expectedValues = new List { 1.0610 }; FullCalculation(MStabModelType.UpliftVan, expectedValues, expectedValues); } [Test, Category("Slow")] public void TestFullCalculationBishopUpliftVan() { // expected result is worst of Bishop (1.5570) and UpliftVan (1.0610) var expectedValues = new List { 1.5570, 1.0610 }; var expectedOutputValues = new List { 1.5570, 1.0610, 1.0610 }; FullCalculation(MStabModelType.BishopUpliftVan, expectedValues, expectedOutputValues); } private static DamKernelInput CreateDamKernelInput(string calculationMap) { // Relative paths in ini file do not work yet in DGeoStability 16.2. This is fixed in 18.1. var absoluteFolder = Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), TestFolder)); var projectPath = Path.Combine(absoluteFolder, "testProjectMap"); var soilDbName = Path.Combine(projectPath, "testSoilMaterials.mdb"); var geometryFolder = "testGeomMap"; var geometryPath = Path.Combine(projectPath, geometryFolder); var soilGeometry2DName = "test1D1.sti"; var workingDir = Path.Combine(projectPath, calculationMap); if (Directory.Exists(workingDir)) { Directory.Delete(workingDir, true); } Directory.CreateDirectory(workingDir); var location = DamMacroStabilityTestHelper.CreateLocation(FactoryForSurfaceLines.CreateSurfaceLineTutorial1()); location.Scenarios.Add(new DesignScenario()); location.StabilityOptions = new StabilityOptions(); location.StabilityOptions.TrafficLoad = 10.0; location.StabilityOptions.SoilGeometries2DPath = geometryPath; location.StabilityOptions.SoilDatabaseName = soilDbName; location.ModelFactors.RequiredSafetyFactorStabilityInnerSlope = 1.1; location.ModelFactors.UpliftCriterionStability = 1.2; var subSoilScenario = new SoilGeometryProbability(); subSoilScenario.StiFileName = soilGeometry2DName; subSoilScenario.SoilProfileType = SoilProfileType.ProfileTypeStiFile; subSoilScenario.SegmentFailureMechanismType = SegmentFailureMechanismType.Stability; var damKernelInput = new DamKernelInput(); damKernelInput.Location = location; damKernelInput.SubSoilScenario = subSoilScenario; damKernelInput.ProjectDir = projectPath; damKernelInput.CalculationDir = workingDir; return damKernelInput; } public void FullCalculation(MStabModelType model, List expectedCalculationValues, List expectedOutputValues) { const double diff = 0.01; var damKernelInput = CreateDamKernelInput("Calc" + model); var failureMechanismParametersMStab = new FailureMechanismParametersMStab(); failureMechanismParametersMStab.MStabParameters.GridPosition = MStabGridPosition.Right; failureMechanismParametersMStab.MStabParameters.SearchMethod = MStabSearchMethod.GeneticAlgorithm; failureMechanismParametersMStab.MStabParameters.CalculationOptions.MinimalCircleDepth = 1.0; failureMechanismParametersMStab.MStabParameters.Model = model; var kernelWrapper = new DamMacroStabilityInwardsKernelWrapper(); kernelWrapper.FailureMechanismParametersMStab = failureMechanismParametersMStab; // Prepare the wrapper. Result is input for the calculation dll IKernelDataInput damStabilityInput; IKernelDataOutput kernelOutput; kernelWrapper.Prepare(damKernelInput, 0, out damStabilityInput, out kernelOutput); // 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(expectedCalculationValues.Count, damMacroStabilityOutput.StabilityOutputItems.Count); for (int index = 0; index < expectedCalculationValues.Count; index++) { Assert.AreEqual(expectedCalculationValues[0], 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(expectedOutputValues.Count, results.Count); for (int index = 0; index < expectedOutputValues.Count; index++) { Assert.AreEqual(expectedOutputValues[index], results[index].StabilityDesignResults.SafetyFactor, diff); Assert.IsNotEmpty(results[index].BaseFileName); } } private XDocument ModifiedXmlDocument(string xmlFileName, string stiFileName, string soilDbName, string geometryFileName) { // modify name of output sti file XDocument xDocument = XDocument.Load(xmlFileName); 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, Ignore("Fails due to conversion from dll to exe; try to fix later only when it becomes relevant")] public void TestCreateDGeoStabilityInputFile() { var xmlFileName = Path.Combine(TestFolder, "test.xml"); var soilDbName = Path.Combine(TestFolder, "DAM Tutorial Design0.soilmaterials.mdb"); var geometryFileName = Path.Combine(TestFolder, "DWP_1.sti"); var stiFileName = Path.Combine(TestFolder, "test.sti"); var expectedStiFileName = Path.Combine(TestFolder, "expectedTest.sti"); if (File.Exists(stiFileName)) { File.Delete(stiFileName); } //var xDocument = ModifiedXmlDocument(xmlFileName, stiFileName, soilDbName, geometryFileName); var kernelWrapper = new DamMacroStabilityInwardsKernelWrapper(); kernelWrapper.CreateStiFile(Path.GetDirectoryName(xmlFileName) + "\\" + Path.GetFileNameWithoutExtension(xmlFileName), Directory.GetCurrentDirectory()); Assert.IsTrue(File.Exists(stiFileName)); Assert.AreEqual(ContentOfStiFile(expectedStiFileName), ContentOfStiFile(stiFileName)); } [Test] [ExpectedException(typeof(MacroStabilityException))] public void TestThrowsExceptionXmlFileNotValid() { var kernelWrapper = new DamMacroStabilityInwardsKernelWrapper(); string xDocument = "Empty.xml"; kernelWrapper.CreateStiFile(xDocument, Directory.GetCurrentDirectory()); } 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; } } /// /// Tests validation of input for the DamMacroStabilityInwardsKernelWrapper /// But calculator has no validator (yet) /// Therefore Validate returns always true now /// [Test] public void TestValidate() { var kernelWrapper = new DamMacroStabilityInwardsKernelWrapper(); // Validate without setting values. var damStabilityInput = new DamMacroStabilityInput(); List messages; kernelWrapper.Validate(damStabilityInput, null, out messages); // When validator is implemented, expect error messages: messages.Count > 0 // But now no validator, therefore no messages. Assert.AreEqual(0, messages.Count); // Validate the input when valid input is provided. Expected no messages. // Fill the missing input needed to let Validate succeed // Currently Validate always return true, so no input to set yet damStabilityInput = new DamMacroStabilityInput(); kernelWrapper.Validate(damStabilityInput, null, out messages); Assert.AreEqual(0, messages.Count); } [Test] public void TestPostProcess() { var kernelWrapper = new DamMacroStabilityInwardsKernelWrapper(); var damKernelInput = CreateDamKernelInput("TestPostProcess"); damKernelInput.DamFailureMechanismeCalculationSpecification = new DamFailureMechanismeCalculationSpecification(); DamMacroStabilityOutputItem outputItem = new DamMacroStabilityOutputItem(); var zone1 = new DamMacroStabilityOutputItem.ResultsSingleZone(); zone1.SafetyFactor = 1.1; zone1.CircleSurfacePointLeftXCoordinate = 1.2; zone1.CircleSurfacePointRightXCoordinate = 1.3; outputItem.Zone1Results = zone1; var zone2 = new DamMacroStabilityOutputItem.ResultsSingleZone(); zone2.SafetyFactor = 0.9; zone2.CircleSurfacePointLeftXCoordinate = 2.2; zone2.CircleSurfacePointRightXCoordinate = 2.3; outputItem.Zone2Results = zone2; outputItem.StabilityModelType = MStabModelType.UpliftVan; DamMacroStabilityOutput output = new DamMacroStabilityOutput(); output.StabilityOutputItems = new List(); output.StabilityOutputItems.Add(outputItem); List results; var failureMechanismParametersMStab = new FailureMechanismParametersMStab(); failureMechanismParametersMStab.MStabParameters.GridPosition = MStabGridPosition.Right; failureMechanismParametersMStab.MStabParameters.SearchMethod = MStabSearchMethod.GeneticAlgorithm; failureMechanismParametersMStab.MStabParameters.CalculationOptions.MinimalCircleDepth = 1.0; kernelWrapper.FailureMechanismParametersMStab = failureMechanismParametersMStab; DesignScenario designScenario = new DesignScenario { Location = damKernelInput.Location }; 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.2, results[0].StabilityDesignResults.LocalZone1EntryPointX); Assert.AreEqual(1.3, results[0].StabilityDesignResults.LocalZone1ExitPointX); Assert.AreEqual(0.9, results[0].StabilityDesignResults.Zone2SafetyFactor); Assert.AreEqual(2.2, results[0].StabilityDesignResults.LocalZone2EntryPointX); Assert.AreEqual(2.3, results[0].StabilityDesignResults.LocalZone2ExitPointX); Assert.AreEqual(MStabModelType.UpliftVan, results[0].StabilityDesignResults.StabilityModelType); } [Test] [ExpectedException(typeof(NoNullAllowedException), ExpectedMessage = "Geen invoer object gedefinieerd voor Macrostabiliteit")] [SetUICulture("nl-NL")] public void TestLanguageNLThrowsExceptionWhenInputIsNull() { DamMacroStabilityInwardsKernelWrapper.StabilityCalculator(null); } [Test] [ExpectedException(typeof(NoNullAllowedException), ExpectedMessage = "No input object defined for Macro Stability")] [SetUICulture("en-US")] public void TestLanguageENThrowsExceptionWhenInputIsNull() { DamMacroStabilityInwardsKernelWrapper.StabilityCalculator(null); } [Test] [ExpectedException(typeof(NoNullAllowedException), ExpectedMessage = "Geen uitvoer object gedefinieerd voor Macrostabiliteit")] [SetUICulture("nl-NL")] public void TestThrowsExceptionWhenOutputIsNull() { var kernelWrapper = new DamMacroStabilityInwardsKernelWrapper(); List results; kernelWrapper.PostProcess(new DamKernelInput(), null, null, "", out results); } } }