// 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;
}
}
}