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