// Copyright (C) Stichting Deltares 2021. 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;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using Deltares.DamEngine.Data.General;
using Deltares.DamEngine.Interface;
using Deltares.DamEngine.Io;
using Deltares.DamEngine.Io.XmlOutput;
using Deltares.DamEngine.TestHelpers;
using NUnit.Framework;
namespace Deltares.DamEngine.IntegrationTests.IntegrationTests
{
[TestFixture]
[Ignore("Test disabled due to removal of the old MacroStability kernel wrapper implementation")]
public class MultiCoreMacroStabilityTests
{
private const double tolerance = 0.0005;
[Test, Category("MultiCore")]
[TestCase(MStabModelType.Bishop, AnalysisType.NoAdaption)]
[TestCase(MStabModelType.UpliftVan, AnalysisType.NoAdaption)]
[TestCase(MStabModelType.BishopUpliftVan, AnalysisType.NoAdaption)]
[TestCase(MStabModelType.Bishop, AnalysisType.AdaptGeometry)]
[TestCase(MStabModelType.UpliftVan, AnalysisType.AdaptGeometry)]
public void CanPerformRunMacroStabilityTutorialDesignMultiCore(MStabModelType mStabModelType, AnalysisType analysisType)
{
// Based on ".data\DamEngineTestProjects\DAM Tutorial Design\DAM Tutorial Design.damx"
// with Dam Classic rev.1059
// Select locations DWP_1 to DWP_12
const int multiCoreCount = 4;
const string fileName = @"TestFiles\MacroStabilityTutorialDesignInputFileMultipleLocations.xml";
const string fileNameOutputPrefix = @"TestFiles\MacroStabilityTutorialDesignMultipleLocations";
string inputString = File.ReadAllText(fileName);
inputString = XmlAdapter.ChangeValueInXml(inputString, "ProjectPath", ""); // Current directory will be used
inputString = XmlAdapter.ChangeValueInXml(inputString, "MapForSoilgeometries2D", @"TestFiles\DAM Tutorial Design.geometries2D.0\");
inputString = XmlAdapter.ChangeValueInXml(inputString, "SoilDatabaseName", @"TestFiles\DAM Tutorial Design0.soilmaterials.mdb");
inputString = XmlAdapter.ChangeValueInXml(inputString, "StabilityModelType", mStabModelType.ToString());
inputString = XmlAdapter.ChangeValueInXml(inputString, "AnalysisType", analysisType.ToString());
// Calculate one core
string calcDir = String.Format("TestStabInwards_{0}_{1}_{2}Core", mStabModelType.ToString(), analysisType.ToString(), 1);
string outputFilename = DetermineOutputFilename(fileNameOutputPrefix, mStabModelType.ToString(), analysisType.ToString(), 1);
string outputString;
EngineInterface engineInterface;
// Following line to force 1-core calculation to be performed always.
// Outcomment it to prevent 1-core calculation to be performed if it as already done in a previous run, to speed up the test.
if (File.Exists(outputFilename)) File.Delete(outputFilename);
if (File.Exists(outputFilename))
{
// This is to speed up local testing; after the first run the file will be read from disk.
// If something in the calculation results changes, the file has to be deleted (see line above)
// It will then be generated again in the else block of this statement
outputString = File.ReadAllText(outputFilename);
Debug.WriteLine("Skipping single core calculation Macrostability; results are read from file");
}
else
{
inputString = XmlAdapter.ChangeValueInXml(inputString, "CalculationMap", calcDir); // Current directory will be used
if (Directory.Exists(calcDir))
{
Directory.Delete(calcDir, true); // delete previous results
}
Directory.CreateDirectory(calcDir);
Debug.WriteLine("Perform single core calculation Macrostability");
engineInterface = new EngineInterface(inputString);
Assert.IsNotNull(engineInterface.DamProjectData);
outputString = engineInterface.Run();
Assert.IsNotNull(outputString);
File.WriteAllText(outputFilename, outputString, Encoding.Unicode);
}
var outputOneCore = DamXmlSerialization.LoadOutputFromXmlString(outputString);
// Calculate multicore
calcDir = String.Format("TestStabInwards_{0}_{1}_{2}Core", mStabModelType.ToString(), analysisType.ToString(), multiCoreCount);
outputFilename = DetermineOutputFilename(fileNameOutputPrefix, mStabModelType.ToString(), analysisType.ToString(), multiCoreCount);
// Following line to force multicore calculation to be performed always.
// Outcomment it to prevent multicore calculation to be performed if it as already done in a previous run, to speed up the test.
if (File.Exists(outputFilename)) File.Delete(outputFilename);
if (File.Exists(outputFilename))
{
// This is to speed up local testing; after the first run the file will be read from disk.
// If something in the calculation results changes, the file has to be deleted (see line above)
// It will then be generated again in the else block of this statement
outputString = File.ReadAllText(outputFilename);
Debug.WriteLine("Skipping multicore calculation Macrostability; results are read from file");
}
else
{
inputString = XmlAdapter.ChangeValueInXml(inputString, "CalculationMap", calcDir); // Current directory will be used
inputString = XmlAdapter.ChangeValueInXml(inputString, "MaxCalculationCores", multiCoreCount.ToString());
if (Directory.Exists(calcDir))
{
Directory.Delete(calcDir, true); // delete previous results
}
Directory.CreateDirectory(calcDir);
Debug.WriteLine("Perform multicore calculation with {0} cores Macrostability", multiCoreCount);
engineInterface = new EngineInterface(inputString);
Assert.IsNotNull(engineInterface.DamProjectData);
outputString = engineInterface.Run();
Assert.IsNotNull(outputString);
File.WriteAllText(outputFilename, outputString, Encoding.Unicode);
}
var outputMultiCore = DamXmlSerialization.LoadOutputFromXmlString(outputString);
// Compare the results
var differences = new List();
StringBuilder differencesStringBuilder = new StringBuilder();
foreach (DesignResult oneCoreResult in outputOneCore.Results.CalculationResults)
{
DesignResult multiCoreResult = outputMultiCore.Results.CalculationResults.FirstOrDefault(x =>
x.LocationName.Equals(oneCoreResult.LocationName) &&
x.ProfileName.Equals(oneCoreResult.ProfileName) &&
x.StabilityDesignResults.StabilityModelType == oneCoreResult.StabilityDesignResults.StabilityModelType);
if (multiCoreResult == null)
{
var diffString = String.Format("No multicore result in location '{0}', soilprofile '{1}'", oneCoreResult.LocationName, oneCoreResult.ProfileName);
differencesStringBuilder.AppendLine(diffString);
differences.Add(diffString);
}
else
{
if (Math.Abs(oneCoreResult.StabilityDesignResults.SafetyFactor - multiCoreResult.StabilityDesignResults.SafetyFactor) > tolerance)
{
var diffString = String.Format("Different result in location '{0}', soilprofile '{1}': 1 core = {2}, multicore = {3}", oneCoreResult.LocationName, oneCoreResult.ProfileName, oneCoreResult.StabilityDesignResults.SafetyFactor, multiCoreResult.StabilityDesignResults.SafetyFactor);
differencesStringBuilder.AppendLine(diffString);
differences.Add(diffString);
}
}
}
Assert.IsTrue(differences.Count == 0, "Differences found" + Environment.NewLine + differencesStringBuilder);
}
private string DetermineOutputFilename(string prefix, string modelType, string analysisType, int coreCount, string extension = ".xml")
{
return String.Format("{0}_{1}_{2}_{3}core_OutputFile{4}", prefix, modelType, analysisType, coreCount, extension);
}
}
}