Index: DamEngine/trunk/src/Deltares.DamEngine.Calculators/DikesDesign/DesignCalculatorTask.cs =================================================================== diff -u --- DamEngine/trunk/src/Deltares.DamEngine.Calculators/DikesDesign/DesignCalculatorTask.cs (revision 0) +++ DamEngine/trunk/src/Deltares.DamEngine.Calculators/DikesDesign/DesignCalculatorTask.cs (revision 1468) @@ -0,0 +1,44 @@ +// 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 Deltares.DamEngine.Data.Design; +using Deltares.DamEngine.Data.General; +using Deltares.DamEngine.Data.General.Results; +using Deltares.DamEngine.Data.Standard.Logging; + +namespace Deltares.DamEngine.Calculators.DikesDesign +{ + /// + /// Task to be used in multi-core design calculation + /// + public class DesignCalculatorTask + { + public Location Location { get; set; } + public SoilGeometryProbability SoiProfileProbability { get; set; } + public DesignScenario DesignScenario { get; set; } + public string ProjectPath { get; set; } + public string CalculationMap { get; set; } + public DamFailureMechanismeCalculationSpecification FailureMechanismeCalculationSpecification { get; set; } + public List DesignResults { get; set; } + public List CalculationMessages { get; set; } + } +} Index: DamEngine/trunk/src/Deltares.DamEngine.Calculators/DikesDesign/DesignCalculator.cs =================================================================== diff -u -r1466 -r1468 --- DamEngine/trunk/src/Deltares.DamEngine.Calculators/DikesDesign/DesignCalculator.cs (.../DesignCalculator.cs) (revision 1466) +++ DamEngine/trunk/src/Deltares.DamEngine.Calculators/DikesDesign/DesignCalculator.cs (.../DesignCalculator.cs) (revision 1468) @@ -22,6 +22,7 @@ using System; using System.Collections.Generic; using System.IO; +using Deltares.DamEngine.Calculators.General; using Deltares.DamEngine.Calculators.KernelWrappers.Common; using Deltares.DamEngine.Calculators.KernelWrappers.Interfaces; using Deltares.DamEngine.Calculators.Properties; @@ -59,8 +60,7 @@ { damProjectData.CalculationMessages.Clear(); } - var totalCalculationSteps = DetermineTotalCalculationSteps(damProjectData.Dike.Locations); - var currentStep = 0; + var designCalculatorTasks = new List(); for (int locationIndex = 0; locationIndex < damProjectData.Dike.Locations.Count; locationIndex++) { var location = damProjectData.Dike.Locations[locationIndex]; @@ -73,18 +73,36 @@ var projectPath = damProjectData.ProjectPath != "" ? damProjectData.ProjectPath : Directory.GetCurrentDirectory(); var designResults = new List(); var calculationMessages = new List(); - CalculateOneScenario(location, soiProfileProbability, designScenario, projectPath, damProjectData.CalculationMap, - damProjectData.DamProjectCalculationSpecification.CurrentSpecification, - designResults, calculationMessages); - damProjectData.CalculationMessages.AddRange(calculationMessages); - damProjectData.DesignCalculations.AddRange(designResults); + designCalculatorTasks.Add(new DesignCalculatorTask() + { + Location = location, + SoiProfileProbability = soiProfileProbability, + DesignScenario = designScenario, + ProjectPath = projectPath, + CalculationMap = damProjectData.CalculationMap, + FailureMechanismeCalculationSpecification = damProjectData.DamProjectCalculationSpecification.CurrentSpecification, + DesignResults = designResults, + CalculationMessages = calculationMessages + }); } - currentStep++; - progressDelegate?.Invoke(Convert.ToDouble(currentStep) / Convert.ToDouble(totalCalculationSteps)); } } + + // Perform the calculation + Parallel.Run(designCalculatorTasks, RunDesignCalculatorTask, progressDelegate, damProjectData.MaxCalculationCores); + foreach (var desigCalculatorTask in designCalculatorTasks) + { + damProjectData.CalculationMessages.AddRange(desigCalculatorTask.CalculationMessages); + damProjectData.DesignCalculations.AddRange(desigCalculatorTask.DesignResults); + } } + private void RunDesignCalculatorTask(object designCalculatorTask) + { + DesignCalculatorTask task = (DesignCalculatorTask)designCalculatorTask; + CalculateOneScenario(task.Location, task.SoiProfileProbability, task.DesignScenario, task.ProjectPath, + task.CalculationMap, task.FailureMechanismeCalculationSpecification, task.DesignResults, task.CalculationMessages); + } private void CalculateOneScenario(Location location, SoilGeometryProbability soiProfileProbability, DesignScenario designScenario, string projectPath, string calculationMap, DamFailureMechanismeCalculationSpecification damFailureMechanismeCalculationSpecification, List designResults, List calculationMessages) @@ -323,14 +341,17 @@ return CalculationResult.Succeeded; } - private int DetermineTotalCalculationSteps(IList locations) + private int DetermineMainNumberOfCalculations(IList locations) { - var totalCalculationSteps = 0; + var total = 0; foreach (var location in locations) { - totalCalculationSteps += location.Segment.SoilProfileProbabilities.Count; + for (int subSoilScenarioIndex = 0; subSoilScenarioIndex < location.Segment.SoilProfileProbabilities.Count; subSoilScenarioIndex++) + { + total++; + } } - return totalCalculationSteps; + return total; } } } Index: DamEngine/trunk/src/Deltares.DamEngine.Calculators/Deltares.DamEngine.Calculators.csproj =================================================================== diff -u -r1447 -r1468 --- DamEngine/trunk/src/Deltares.DamEngine.Calculators/Deltares.DamEngine.Calculators.csproj (.../Deltares.DamEngine.Calculators.csproj) (revision 1447) +++ DamEngine/trunk/src/Deltares.DamEngine.Calculators/Deltares.DamEngine.Calculators.csproj (.../Deltares.DamEngine.Calculators.csproj) (revision 1468) @@ -63,6 +63,7 @@ + Index: DamEngine/trunk/src/Deltares.DamEngine.Interface.Tests/PipingBlighTests.cs =================================================================== diff -u -r1406 -r1468 --- DamEngine/trunk/src/Deltares.DamEngine.Interface.Tests/PipingBlighTests.cs (.../PipingBlighTests.cs) (revision 1406) +++ DamEngine/trunk/src/Deltares.DamEngine.Interface.Tests/PipingBlighTests.cs (.../PipingBlighTests.cs) (revision 1468) @@ -19,11 +19,17 @@ // Stichting Deltares and remain full property of Stichting Deltares at all times. // All rights reserved. +using System; +using System.Collections.Generic; using System.IO; +using System.Linq; +using System.Text; using System.Threading; using Deltares.DamEngine.Data.General; using Deltares.DamEngine.Data.Geotechnics; using Deltares.DamEngine.Io; +using Deltares.DamEngine.Io.XmlOutput; +using Deltares.DamEngine.TestHelpers; using NUnit.Framework; namespace Deltares.DamEngine.Interface.Tests @@ -216,5 +222,47 @@ Assert.AreEqual(1.311, output.Results.CalculationResults.DesignResults[locationIndex * 2 + 1].PipingDesignResults.BlighFactor, tolerance); Assert.AreEqual((locationIndex + 1) * 2, output.Results.CalculationResults.DesignResults.Length); } + [Test] + public void CanPerformBlighDesignWithAdaptionRechterDiezedijkMultiCore() + { + // Based on CanPerformBlighDesignWithAdaptionRechterDiezedijk + const string fileName = @"TestFiles\Rechter Diezedijk_BlighDesignInputFile.xml"; + const string fileNameOutputOneCore = @"TestFiles\Rechter Diezedijk_BlighDesignInputFileOneCoreOut.xml"; + const string fileNameOutputMultiCore = @"TestFiles\Rechter Diezedijk_BlighDesignInputFileMultiCoreOut.xml"; + string inputString = File.ReadAllText(fileName); + + // Calculate one core + EngineInterface engineInterface = new EngineInterface(inputString); + Assert.IsNotNull(engineInterface.DamProjectData); + string outputString = engineInterface.Run(); + Assert.IsNotNull(outputString); + var outputOneCore = DamXmlSerialization.LoadOutputFromXmlString(outputString); + File.WriteAllText(fileNameOutputOneCore, outputString, Encoding.Unicode); + + // Calculate multicore + inputString = XmlAdapter.ChangeValueInXml(inputString, "MaxCalculationCores", @"6"); + engineInterface = new EngineInterface(inputString); + Assert.IsNotNull(engineInterface.DamProjectData); + outputString = engineInterface.Run(); + Assert.IsNotNull(outputString); + var outputMultiCore = DamXmlSerialization.LoadOutputFromXmlString(outputString); + File.WriteAllText(fileNameOutputMultiCore, outputString, Encoding.Unicode); + + // Compare the results + var differences = new List(); + StringBuilder sb = new StringBuilder(); + foreach (DesignResult oneCoreResult in outputOneCore.Results.CalculationResults.DesignResults) + { + DesignResult multiCoreResult = outputMultiCore.Results.CalculationResults.DesignResults.Where(x => x.LocationName.Equals(oneCoreResult.LocationName) && x.ProfileName.Equals(oneCoreResult.ProfileName)).FirstOrDefault(); + if (Math.Abs(oneCoreResult.PipingDesignResults.BlighFactor - multiCoreResult.PipingDesignResults.BlighFactor) > tolerance) + { + var diffString = String.Format("Different result in {0}, {1}: 1 core = {2}, multicore = {3}", oneCoreResult.LocationName, oneCoreResult.ProfileName, oneCoreResult.PipingDesignResults.BlighFactor, multiCoreResult.PipingDesignResults.BlighFactor); + sb.AppendLine(diffString); + differences.Add(diffString); + } + } + + Assert.IsTrue(differences.Count == 0, "Differences found" + Environment.NewLine + sb.ToString()); + } } }