// Copyright (C) Stichting Deltares 2025. 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.Globalization; using System.IO; using System.Linq; using System.Threading; using Deltares.DamEngine.Data.General; using Deltares.DamEngine.Data.Standard.Calculation; using Deltares.DamEngine.Interface; using Deltares.DamEngine.Io; using Deltares.DamEngine.Io.XmlInput; using Deltares.DamEngine.Io.XmlOutput; using Deltares.DamEngine.TestHelpers; using NUnit.Framework; using ConversionHelper = Deltares.DamEngine.Interface.ConversionHelper; namespace Deltares.DamEngine.IntegrationTests.IntegrationTests; [TestFixture] public class MultiCoreMacroStabilityInwardsTests { private const string tutorialStability2D = @"TestFiles\InputTutorialStability2D.xml"; [Test, Category(Categories.MultiCore)] [TestCase(4, InputStabilityModelType.Bishop, "SlopeAdaptionBeforeShoulderAdaption", 21, 6)] [TestCase(8, InputStabilityModelType.Bishop, "SlopeAdaptionBeforeShoulderAdaption", 21, 6)] [TestCase(4, InputStabilityModelType.UpliftVan, "SlopeAdaptionBeforeShoulderAdaption", 9, 17)] [TestCase(8, InputStabilityModelType.UpliftVan, "SlopeAdaptionBeforeShoulderAdaption", 9, 17)] [TestCase(4, InputStabilityModelType.Bishop, "OptimizedSlopeAndShoulderAdaption", 9, 18)] [TestCase(8, InputStabilityModelType.Bishop, "OptimizedSlopeAndShoulderAdaption", 9, 18)] [TestCase(4, InputStabilityModelType.UpliftVan, "OptimizedSlopeAndShoulderAdaption", 7, 19)] [TestCase(8, InputStabilityModelType.UpliftVan, "OptimizedSlopeAndShoulderAdaption", 7, 19)] public void GivenTutorialDesign_WhenCalculateAllWithGeometryAdaption_ThenGivesExpectedResults(int maxCores, InputStabilityModelType stabilityModelType, string designMethod, int expectedSucceeded = 21, int expectedFailed = 6) { int processorCount = Environment.ProcessorCount; if (maxCores > processorCount) { Assert.Ignore($"The number of cores requested ({maxCores}) is higher than the number of available cores ({processorCount})."); } // Use XML of general Tutorial Design project var calcDir = $"TestMultiCoreStabInwards{stabilityModelType.ToString()}_AdaptGeometry_{designMethod}_{maxCores.ToString()}-core"; if (Directory.Exists(calcDir)) { Directory.Delete(calcDir, true); // delete previous results } string inputString = File.ReadAllText(tutorialStability2D); inputString = XmlAdapter.ChangeStabilityInputModel(inputString, stabilityModelType); inputString = XmlAdapter.ChangeValueInXml(inputString, "FailureMechanismSystemType", ConversionHelper.ConvertToInputFailureMechanismSystemType( FailureMechanismSystemType.StabilityInside).ToString()); inputString = XmlAdapter.ChangeValueInXml(inputString, "SearchMethod", "CalculationGrid"); inputString = XmlAdapter.ChangeValueInXml(inputString, "ProjectPath", ""); // Current directory will be used inputString = XmlAdapter.ChangeValueInXml(inputString, "CalculationMap", calcDir); // Current directory will be used inputString = XmlAdapter.ChangeValueInXml(inputString, "SegmentFailureMechanismType", SegmentSoilGeometryProbabilitySegmentFailureMechanismType.Stability.ToString()); inputString = XmlAdapter.ChangeValueInXml(inputString, "AnalysisType", "AdaptGeometry"); inputString = XmlAdapter.ChangeValueInXml(inputString, "StabilityDesignMethod", designMethod); inputString = XmlAdapter.ChangeValueInXml(inputString, "MaxCalculationCores", maxCores.ToString()); File.WriteAllText(calcDir + "_InputFile.xml", inputString); Output output = GeneralHelper.RunAfterInputValidation(inputString); DamXmlSerialization.SaveOutputAsXmlFile(calcDir + "_OutputFile.xml", output); Assert.Multiple(() => { Assert.That(output.Results.CalculationResults, Has.Length.EqualTo(expectedSucceeded + expectedFailed)); int actualSucceeded = output.Results.CalculationResults.Count(result => ConversionHelper.ConvertToCalculationResult(result.CalculationResult) == CalculationResult.Succeeded); Assert.That(actualSucceeded, Is.EqualTo(expectedSucceeded), "Succeeded calculations"); int actualFailed = output.Results.CalculationResults.Count(result => ConversionHelper.ConvertToCalculationResult(result.CalculationResult) == CalculationResult.RunFailed); Assert.That(actualFailed, Is.EqualTo(expectedFailed), "Failed calculations"); }); } [Test, Category(Categories.MultiCore)] [TestCase(3)] [TestCase(7)] [TestCase(23)] public void DesignBishopOptimizedSlopeAndShoulderAdaptionWithScenariosForHeadPL3CalculatesCorrect(int cores) { int availableCores = Environment.ProcessorCount - 1; if (cores > availableCores) { Assert.Ignore($"The number of cores requested ({cores}) is higher than the number of available cores ({availableCores})."); } const string mapTestFiles = @"TestFiles\"; const string inputFilename = "InputFileMultiCoreTestForScenarioAdaption.xml"; string fullInputFilename = Path.Combine(mapTestFiles, inputFilename); Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; string inputString = File.ReadAllText(fullInputFilename); var engineInterface = new EngineInterface(inputString) { DamProjectData = { MaxCalculationCores = cores } }; string calcDir = engineInterface.DamProjectData.CalculationMap + "_" + cores + "_Cores"; engineInterface.DamProjectData.CalculationMap = calcDir; Assert.That(engineInterface.DamProjectData, Is.Not.Null); calcDir = Directory.GetCurrentDirectory() + "\\" + calcDir; if (Directory.Exists(calcDir)) { Directory.Delete(calcDir, true); // delete previous results } Output output = GeneralHelper.RunAfterInputValidation(engineInterface, true, "Results_" + cores + "_Cores" + ".xml"); Assert.Multiple(() => { Assert.That(output.Results.CalculationResults, Has.Length.EqualTo(18)); int resultsFound = CheckLargeResultsSets.CheckResultsDesignBishopAdaptionWithScenariosForHeadPl3CalculatesCorrect( output.Results.CalculationResults); Assert.That(resultsFound, Is.EqualTo(11)); }); } }