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