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