// 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.IO; using Deltares.DamEngine.Calculators.KernelWrappers.Common; using Deltares.DamEngine.Calculators.KernelWrappers.Interfaces; using Deltares.DamEngine.Calculators.KernelWrappers.MacroStabilityInwards; using Deltares.DamEngine.Calculators.Tests.KernelWrappers.TestHelpers; 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.Interface; using Deltares.DamEngine.Io; using Deltares.DamEngine.TestHelpers; using Deltares.DamEngine.TestHelpers.Factories; using NUnit.Framework; using CharacteristicPointType = Deltares.DamEngine.Data.Geotechnics.CharacteristicPointType; using LogMessage = Deltares.DamEngine.Data.Standard.Logging.LogMessage; using MacroStabilityOutput = Deltares.DamEngine.Calculators.KernelWrappers.MacroStabilityInwards.MacroStabilityOutput; namespace Deltares.DamEngine.Calculators.Tests.KernelWrappers.MacroStabilityInwards { [TestFixture] public class MacroStabilityInwardsKernelWrapperTests { private const string TestFolder = @"..\..\Deltares.DamEngine.IntegrationTests\TestFiles"; private string inputXmlForDamEngine = Path.Combine(TestFolder, "StabilityDesign1Dbased.xml"); [Test] public void TestPrepare() { var kernelWrapper = new MacroStabilityInwardsKernelWrapper { FailureMechanismParametersMStab = new FailureMechanismParametersMStab() }; IKernelDataInput kernelDataInput; IKernelDataOutput kernelDataOutput; var kernelInput = CreateDamKernelInputForTest(); // Situation 1: no uplift. Expected PrepareResult.NotRelevant kernelInput.Location.ModelFactors.UpliftCriterionStability = 0.8; var prepareResult = kernelWrapper.Prepare(kernelInput, 0, out kernelDataInput, out kernelDataOutput); Assert.AreEqual(PrepareResult.NotRelevant, prepareResult); MacroStabilityOutput damMacroStabilityOutput = (MacroStabilityOutput)kernelDataOutput; Assert.AreEqual(CalculationResult.NoRun, damMacroStabilityOutput.CalculationResult); Assert.AreEqual(false, damMacroStabilityOutput.UpliftSituation.IsUplift); // Situation 2: there is uplift and prepare succeeds. Expected PrepareResult.Successful kernelInput.Location.ModelFactors.UpliftCriterionStability = 1.4; prepareResult = kernelWrapper.Prepare(kernelInput, 0, out kernelDataInput, out kernelDataOutput); Assert.AreEqual(PrepareResult.Successful, prepareResult); damMacroStabilityOutput = (MacroStabilityOutput)kernelDataOutput; Assert.AreEqual(CalculationResult.NoRun, damMacroStabilityOutput.CalculationResult); Assert.AreEqual(true, damMacroStabilityOutput.UpliftSituation.IsUplift); // Situation 3: prepare fails. Expected PrepareResult.Failed kernelInput.Location.ModelFactors.UpliftCriterionStability = 1.2; kernelInput.Location.SurfaceLine.CharacteristicPoints.Clear(); prepareResult = kernelWrapper.Prepare(kernelInput, 0, out kernelDataInput, out kernelDataOutput); Assert.AreEqual(PrepareResult.Failed, prepareResult); damMacroStabilityOutput = (MacroStabilityOutput)kernelDataOutput; Assert.AreEqual(CalculationResult.NoRun, damMacroStabilityOutput.CalculationResult); } [Test, ] public void TestValidate() { var kernelWrapper = new MacroStabilityInwardsKernelWrapper(); kernelWrapper.FailureMechanismParametersMStab = new FailureMechanismParametersMStab(); // Validate without setting values. Expected error messages. var macroStabilityInput1 = new MacroStabilityKernelDataInput(); var macroStabilityOutput1 = new MacroStabilityOutput(); macroStabilityOutput1.CalculationResult = CalculationResult.NoRun; List messages; var errorCount = kernelWrapper.Validate(macroStabilityInput1, macroStabilityOutput1, out messages); Assert.IsTrue(errorCount > 0); Assert.AreEqual(CalculationResult.InvalidInputData, macroStabilityOutput1.CalculationResult); // Validate the input when valid input is provided. Expected no messages. var kernelInput = CreateDamKernelInputForTest(); kernelInput.Location.ModelFactors.UpliftCriterionStability = 1.4; var prepareResult = kernelWrapper.Prepare(kernelInput, 0, out IKernelDataInput kernelDataInput, out IKernelDataOutput kernelDataOutput); Assert.IsTrue(prepareResult == PrepareResult.Successful); messages.Clear(); errorCount = kernelWrapper.Validate(kernelDataInput, kernelDataOutput, out messages); Assert.IsTrue(errorCount == 0); Assert.AreEqual(CalculationResult.NoRun, (kernelDataOutput as MacroStabilityOutput).CalculationResult); } [Test] public void TestPostProcess() { const double diff = 0.0001; var kernelWrapper = new MacroStabilityInwardsKernelWrapper(); var kernelInput = CreateDamKernelInputForTest(); MacroStabilityOutput macroStabilityOutput = new MacroStabilityOutput(); DesignScenario designScenario = new DesignScenario { Location = kernelInput.Location }; List results; macroStabilityOutput.CalculationResult = CalculationResult.Succeeded; var macroStabilityOutputItem = new MacroStabilityOutputItem(); macroStabilityOutputItem.CalculationResult = CalculationResult.Succeeded; macroStabilityOutput.UpliftSituation = new UpliftSituation { IsUplift = true }; macroStabilityOutputItem.SafetyFactor = 2.34; macroStabilityOutput.StabilityOutputItems = new List(); macroStabilityOutput.StabilityOutputItems.Add(macroStabilityOutputItem); kernelWrapper.PostProcess(kernelInput, macroStabilityOutput, designScenario, "", out results); Assert.IsTrue(results.Count > 0); foreach (var result in results) { Assert.AreEqual(CalculationResult.Succeeded, result.CalculationResult); Assert.AreEqual(true, ((UpliftSituation)result.StabilityDesignResults.UpliftSituation).IsUplift); Assert.AreEqual(0, result.StabilityDesignResults.NumberOfIterations); //NumberOfIterations can not be set for this test, so always zero here Assert.AreEqual(2.34, result.StabilityDesignResults.SafetyFactor, diff); Assert.AreEqual(kernelInput.Location.SurfaceLine, result.StabilityDesignResults.RedesignedSurfaceLine); Assert.AreEqual(kernelInput.SubSoilScenario.ToString(), result.ProfileName); } } [Test] public void TestFullCalculationFails() { var kernelWrapper = new MacroStabilityInwardsKernelWrapper(); IKernelDataInput kernelDataInput = new MacroStabilityKernelDataInput(); IKernelDataOutput kernelDataOutput = new MacroStabilityOutput(); // Run the dll List messages; MacroStabilityKernelDataInput macroStabilityKernelDataInput = (MacroStabilityKernelDataInput)kernelDataInput; kernelWrapper.Execute(kernelDataInput, kernelDataOutput, out messages); MacroStabilityOutput macroStabilityOutput = (MacroStabilityOutput)kernelDataOutput; Assert.IsTrue(messages.Count > 0); // as there is no data at all, expect unexpected error Assert.AreEqual(CalculationResult.UnexpectedError, macroStabilityOutput.CalculationResult); } [Test] public void TestFullCalculationFailsWithBadTangentLines() { var kernelWrapper = new MacroStabilityInwardsKernelWrapper(); kernelWrapper.FailureMechanismParametersMStab = new FailureMechanismParametersMStab(); // Prepare the wrapper. Result is input for the calculation dll var kernelInput = CreateDamKernelInputForTest(); kernelInput.Location.ModelFactors.UpliftCriterionStability = 1.4; var sd = kernelInput.DamFailureMechanismeCalculationSpecification.FailureMechanismParametersMStab .MStabParameters.SlipCircleDefinition; sd.UpliftVanTangentLinesDefinition = TangentLinesDefinition.Specified; PrepareResult prepareResult = kernelWrapper.Prepare(kernelInput, 0, out IKernelDataInput kernelDataInput, out IKernelDataOutput kernelDataOutput); Assert.AreEqual(PrepareResult.Successful, prepareResult); // Validate the input List messages; var errorCount = kernelWrapper.Validate(kernelDataInput, kernelDataOutput, out messages); Assert.IsTrue(errorCount == 0); // Run the dl; the tangent line position is defined in such a way that a circle segment can not be matched to a soil this should fail. kernelWrapper.Execute(kernelDataInput, kernelDataOutput, out messages); MacroStabilityOutput macroStabilityOutput = (MacroStabilityOutput)kernelDataOutput; Assert.AreEqual(1, messages.Count); Assert.AreEqual(CalculationResult.UnexpectedError, macroStabilityOutput.CalculationResult); Assert.IsTrue(messages[0].Message.Contains("A slice is beyond the geometry at x")); } [Test] public void TestFullCalculationSucceeds() { const double diff = 0.0001; var kernelWrapper = new MacroStabilityInwardsKernelWrapper(); kernelWrapper.FailureMechanismParametersMStab = new FailureMechanismParametersMStab(); // Prepare the wrapper. Result is input for the calculation dll IKernelDataInput kernelDataInput; IKernelDataOutput kernelDataOutput; var kernelInput = CreateDamKernelInputForTest(); // To ensure uplift occurs, set criterion to 1.4 kernelInput.Location.ModelFactors.UpliftCriterionStability = 1.4; PrepareResult prepareResult = kernelWrapper.Prepare(kernelInput, 0, out kernelDataInput, out kernelDataOutput); Assert.AreEqual(PrepareResult.Successful, prepareResult); // Validate the input List messages; var errorCount = kernelWrapper.Validate(kernelDataInput, kernelDataOutput, out messages); Assert.IsTrue(errorCount == 0); // Run the dll kernelWrapper.Execute(kernelDataInput, kernelDataOutput, out messages); MacroStabilityOutput macroStabilityOutput = (MacroStabilityOutput)kernelDataOutput; Assert.AreEqual(2, messages.Count); Assert.AreEqual(CalculationResult.Succeeded, macroStabilityOutput.CalculationResult); Assert.AreEqual(1, macroStabilityOutput.StabilityOutputItems.Count); Assert.AreEqual(1.5211, macroStabilityOutput.StabilityOutputItems[0].SafetyFactor, diff); // ToDo replace by actual value when calculation is done and output is parsed // Fill the design results DesignScenario designScenario = new DesignScenario { Location = kernelInput.Location }; List results; kernelWrapper.PostProcess(kernelInput, macroStabilityOutput, designScenario, "", out results); Assert.IsTrue(results.Count > 0); foreach (var result in results) { Assert.AreEqual(CalculationResult.Succeeded, result.CalculationResult); Assert.AreEqual(1.5211, result.StabilityDesignResults.SafetyFactor, diff); } } [Test] public void CalculationBishopBasedOnDamEngineXmlFailsForWrongType() { const string calcDir = "TestStabInwardsBishop"; if (Directory.Exists(calcDir)) { Directory.Delete(calcDir, true); // delete previous results } Directory.CreateDirectory(calcDir); string inputString = File.ReadAllText(inputXmlForDamEngine); inputString = XmlAdapter.ChangeValueInXml(inputString, "ProjectPath", ""); // Current directory will be used inputString = XmlAdapter.ChangeValueInXml(inputString, "CalculationMap", calcDir); // Current directory will be used EngineInterface engineInterface = new EngineInterface(inputString); Assert.IsNotNull(engineInterface.DamProjectData); string outputString = engineInterface.Run(); Assert.IsNotNull(outputString); var output = DamXmlSerialization.LoadOutputFromXmlString(outputString); Assert.AreEqual(3,output.Results.CalculationMessages.Length, "No results available"); Assert.IsTrue(output.Results.CalculationMessages[0].Message1.Contains("Requested kernel not implemented")); } [Test] public void CalculationUpliftBasedOnDamEngineXmlWorks() { const string calcDir = "TestStabInwardsBishop"; if (Directory.Exists(calcDir)) { Directory.Delete(calcDir, true); // delete previous results } Directory.CreateDirectory(calcDir); string inputString = File.ReadAllText(inputXmlForDamEngine); inputString = XmlAdapter.ChangeValueInXml(inputString, "ProjectPath", ""); // Current directory will be used inputString = XmlAdapter.ChangeValueInXml(inputString, "CalculationMap", calcDir); // Current directory will be used EngineInterface engineInterface = new EngineInterface(inputString); Assert.IsNotNull(engineInterface.DamProjectData); engineInterface.DamProjectData.DamProjectCalculationSpecification.CurrentSpecification.StabilityModelType = MStabModelType.UpliftVan; string outputString = engineInterface.Run(); Assert.IsNotNull(outputString); var output = DamXmlSerialization.LoadOutputFromXmlString(outputString); Assert.IsNotNull(output.Results.CalculationResults, "No results available"); Assert.AreEqual(1.575, output.Results.CalculationResults[0].StabilityDesignResults.SafetyFactor, 0.001); } [Test] [ExpectedException(typeof(NoNullAllowedException), ExpectedMessage = "Geen invoer object gedefinieerd voor Macrostabiliteit")] [SetUICulture("nl-NL")] public void TestLanguageNLThrowsExceptionWhenInputIsNull() { List messages; var kernelWrapper = new MacroStabilityInwardsKernelWrapper(); kernelWrapper.Execute(null, null, out messages); ; } [Test] [ExpectedException(typeof(NoNullAllowedException), ExpectedMessage = "No input object defined for Macro Stability")] [SetUICulture("en-US")] public void TestLanguageENThrowsExceptionWhenStabilityInputIsNull() { List messages; var kernelWrapper = new MacroStabilityInwardsKernelWrapper(); kernelWrapper.Execute(null, null, out messages); } [Test] [ExpectedException(typeof(NoNullAllowedException), ExpectedMessage = "Geen uitvoer object gedefinieerd voor Macrostabiliteit")] [SetUICulture("nl-NL")] public void TestThrowsExceptionWhenStabilityOutputIsNull() { var kernelWrapper = new MacroStabilityInwardsKernelWrapper(); List results; kernelWrapper.PostProcess(new DamKernelInput(), null, null, "", out results); } [Test] [ExpectedException(typeof(NoNullAllowedException), ExpectedMessage = "Geen Dam invoer object gedefinieerd voor Macrostabiliteit")] [SetUICulture("nl-NL")] public void TestThrowsExceptionWhenDamKernelInputIsNull() { var kernelWrapper = new MacroStabilityInwardsKernelWrapper(); List results; kernelWrapper.PostProcess(null, null, null, "", out results); } private static DamKernelInput CreateDamKernelInputForTest() { var location = DamEngineDataTestFactory.CreateLocation(FactoryForSurfaceLines.CreateSurfaceLineTutorial1()); // Correction needed in order to make surface line as lengthy as needed to perform a proper calculation. location.SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.SurfaceLevelInside).X = 100; // Correction needed in order to make surface line points strictly increasing increasing (ditch was vertical at polderside, // now this not allowed by the kernel validator!) So that needs to be fixed in the kernel). location.SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DitchPolderSide).X = 62.5; location.SurfaceLine.Geometry.SyncCalcPoints(); // This test is based on a 1D profile, to be combined with the surface line. var subSoilScenario = new SoilGeometryProbability(); subSoilScenario.SoilProfileType = SoilProfileType.ProfileType1D; subSoilScenario.StiFileName = ""; subSoilScenario.FullStiFileName = ""; subSoilScenario.SoilProfile2D = null; subSoilScenario.SegmentFailureMechanismType = SegmentFailureMechanismType.Stability; subSoilScenario.SoilProfile1D = DamEngineDataTestFactory.CreateSoilProfile1D(location.SoilList); var damKernelInput = new DamKernelInput { Location = location, SubSoilScenario = subSoilScenario, RiverLevelLow = null, DamFailureMechanismeCalculationSpecification = new DamFailureMechanismeCalculationSpecification() }; var sd = damKernelInput.DamFailureMechanismeCalculationSpecification.FailureMechanismParametersMStab .MStabParameters.SlipCircleDefinition; sd.UpliftVanLeftGridHorizontalPointCount = 3; sd.UpliftVanLeftGridVerticalPointCount = 3; sd.UpliftVanLeftGridHorizontalPointDistance = 1; sd.UpliftVanLeftGridVerticalPointDistance = 1; sd.UpliftVanRightGridHorizontalPointCount = 3; sd.UpliftVanRightGridVerticalPointCount = 3; sd.UpliftVanRightGridHorizontalPointDistance = 1; sd.UpliftVanRightGridVerticalPointDistance = 1; sd.UpliftVanTangentLinesDefinition = TangentLinesDefinition.OnBoundaryLines; sd.UpliftVanTangentLinesDistance = 1; sd.GridSizeDetermination = GridSizeDetermination.Specified; damKernelInput.DamFailureMechanismeCalculationSpecification.FailureMechanismParametersMStab.MStabParameters.Model = MStabModelType.UpliftVan; return damKernelInput; } } }