// Copyright (C) Stichting Deltares 2024. 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.IO;
using Deltares.DamEngine.Data.General;
using Deltares.DamEngine.Io;
using Deltares.DamEngine.Io.XmlOutput;
using Deltares.DamEngine.TestHelpers;
using NUnit.Framework;
namespace Deltares.DamEngine.IntegrationTests.IntegrationTests;
///
/// These tests were based on DamLiveIntegrationTest.Run_UsingTestFiles_HasExpectedResultsInOutputFile()
///
public static class OperationalMultiCoreTests
{
private const string mapCompareMultiCore = @"CompareMultiCoreTo1CoreOperational\";
private const string mapTestFiles = @"TestFiles\";
private const string outputBase = "Output";
private const string calcBase = "Cores";
public class RunMultiCoreOperationalHHNKTests
{
private const string mapMultiCore = @"MultiCoreOperational\";
[OneTimeSetUp]
public void Init()
{
GeneralHelper.RemoveTestWorkingDirectory(mapMultiCore);
}
[OneTimeTearDown]
public void Cleanup()
{
GeneralHelper.RemoveTestWorkingDirectory(mapMultiCore);
}
[Test, Category(Categories.MultiCore)]
[Category(Categories.WorkInProgress)] // When running multicore without running single core first, sometimes it gives errors
[TestCase(2)]
[TestCase(4)]
[TestCase(8)] // 8 relevant combinations
public static void MultiCoreOperationalHHNKWithXmlInputFile(int maxCores)
{
const string workDir = mapMultiCore + @"HHNKTests\";
// Based on "DamLive\trunk\data\HHNK Purmer\DAMLive.damx"
const string inputFileName = @"Operational\HHNKPurmer\Input.xml";
TestMultiCoreOperational(maxCores, workDir, inputFileName, 8, 8, 4);
}
}
public class CompareMultiCoreTo1CoreOperationalHHNKTests
{
private const string workDir = mapCompareMultiCore + @"HHNKTests\";
[OneTimeSetUp]
public void Init()
{
GeneralHelper.RemoveTestWorkingDirectory(workDir);
OperationalHHNKWithXmlInputFile(1);
}
[OneTimeTearDown]
public void Cleanup()
{
GeneralHelper.RemoveTestWorkingDirectory(workDir);
}
[Test, Category(Categories.MultiCore)]
[TestCase(2)]
[TestCase(4)]
[TestCase(8)] // 8 relevant combinations
public void OperationalHHNKWithXmlInputFile(int maxCores)
{
// Based on "DamLive\trunk\data\HHNK Purmer\DAMLive.damx"
const string inputFileName = @"Operational\HHNKPurmer\Input.xml";
TestCompareMultiCoreTo1CoreOperational(maxCores, workDir, inputFileName, 8, 8, 4);
}
}
private static void TestMultiCoreOperational(int maxCores, string workDir, string inputFilename,
int expectedTimeSeries, int expectedResults, int expectedRealResults)
{
string calcDir = workDir + calcBase + maxCores;
string outputFilename = Path.Combine(calcDir, outputBase + maxCores + ".xml");
Output output = RunOperationalMultiCoreWithXmlInputFile(maxCores, calcDir, inputFilename, outputFilename);
Assert.That(output.Results.OperationalOutputTimeSeries, Has.Length.EqualTo(expectedTimeSeries));
CheckNumberOfRealResults(output, expectedResults, expectedRealResults);
}
private static void TestCompareMultiCoreTo1CoreOperational(int maxCores, string workDir, string inputFilename,
int expectedTimeSeries, int expectedResults, int expectedRealResults)
{
string calcDir = workDir + calcBase + maxCores;
string outputFilename = Path.Combine(calcDir, outputBase + maxCores + ".xml");
if (maxCores > 1)
{
Output outputMultiCore = RunOperationalMultiCoreWithXmlInputFile(maxCores, calcDir, inputFilename, outputFilename);
string calcDir1Core = workDir + calcBase + "1";
string outputFilename1Core = Path.Combine(calcDir1Core, outputBase + "1.xml");
Output output1Core;
if (File.Exists(outputFilename1Core))
{
string outputCopy1Core = Path.Combine(calcDir, outputBase + "1.xml");
File.Copy(outputFilename1Core, outputCopy1Core, true);
output1Core = DamXmlSerialization.LoadOutputFromXmlFile(outputCopy1Core);
GeneralHelper.CompareOutput(output1Core, outputMultiCore);
}
else
{
Assert.Fail("File not found: " + outputFilename1Core);
}
}
else
{
Output output1Core = RunOperationalMultiCoreWithXmlInputFile(maxCores, calcDir, inputFilename, outputFilename);
Assert.That(output1Core.Results.OperationalOutputTimeSeries, Has.Length.EqualTo(expectedTimeSeries));
CheckNumberOfRealResults(output1Core, expectedResults, expectedRealResults);
}
}
private static Output RunOperationalMultiCoreWithXmlInputFile(int maxCores, string calcDir, string inputFilename, string outputFilename)
{
return GeneralHelper.RunMultiCoreWithXmlInputFile(mapTestFiles, DamProjectType.Operational,
maxCores, calcDir, inputFilename, outputFilename);
}
private static void CheckNumberOfRealResults(Output output, int expectedNumberOfResults, int expectedNumberOfRealResults)
{
var numberOfResults = 0;
var numberOfRealResults = 0;
foreach (TimeSerie resultSerie in output.Results.OperationalOutputTimeSeries)
{
numberOfResults += resultSerie.Entries.TimeSerieEntry.Length;
foreach (TimeSerieEntriesTimeSerieEntry timeSerieEntriesTimeSerieEntry in resultSerie.Entries.TimeSerieEntry)
{
if (!double.IsNaN(timeSerieEntriesTimeSerieEntry.SafetyFactor) &&
timeSerieEntriesTimeSerieEntry.SafetyFactor is > 0 and < 100000)
{
numberOfRealResults++;
}
}
}
Assert.Multiple(() =>
{
Assert.That(numberOfResults, Is.EqualTo(expectedNumberOfResults));
Assert.That(numberOfRealResults, Is.EqualTo(expectedNumberOfRealResults));
});
}
}