// 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.Collections.Generic; using System.Linq; using Deltares.DamEngine.Calculators.KernelWrappers.MacroStabilityCommon.MacroStabilityIo; using Deltares.DamEngine.Calculators.KernelWrappers.MacroStabilityInwards; using Deltares.DamEngine.Data.General; using Deltares.DamEngine.Data.General.Results; using Deltares.DamEngine.Data.Standard.Calculation; using Deltares.DamEngine.Data.Standard.Logging; using Deltares.MacroStability.Io.XmlOutput; using NUnit.Framework; namespace Deltares.DamEngine.Calculators.Tests.KernelWrappers.MacroStabilityCommon.MacroStabilityIo; [TestFixture] public class MacroStabilityKernelOutputToEngineTests { private readonly double tolerance = 0.0005; [Test] [TestCase(StabilityModelOption.Bishop, false)] [TestCase(StabilityModelOption.Bishop, true)] [TestCase(StabilityModelOption.UpliftVan, true)] public void GivenKernelOutputWhenTransferToDamEngineThenDataIsEqual(StabilityModelOption modelOption, bool isSucceeded) { // Given FullOutputModelType kernelOutput = CreateFullOutputModel(modelOption, isSucceeded); // When var damEngineOutput = new MacroStabilityOutput { StabilityOutputItems = [] }; FillEngineFromMacroStabilityKernelOutput.FillDamProjectDataFromKernelModel(kernelOutput, damEngineOutput, out List logMessages); // Then Assert.That(logMessages, Is.Not.Null); Assert.That(logMessages, Has.Count.EqualTo(0)); CompareOutput(kernelOutput, damEngineOutput); } private void CompareOutput(FullOutputModelType kernelOutput, MacroStabilityOutput damEngineOutput) { Assert.Multiple(() => { Assert.That(damEngineOutput.StabilityOutputItems[0].CalculationResult, Is.EqualTo(kernelOutput.StabilityOutput.Succeeded ? CalculationResult.Succeeded : CalculationResult.RunFailed)); Assert.That(damEngineOutput.StabilityOutputItems[0].SafetyFactor, Is.EqualTo(kernelOutput.StabilityOutput.SafetyFactor)); Assert.That(damEngineOutput.StabilityOutputItems[0].StabilityModelType, Is.EqualTo(OutputConversionHelper.ConvertToStabilityModelType(kernelOutput.StabilityOutput.ModelOption))); Assert.That(damEngineOutput.StabilityOutputItems[0].CircleSurfacePointRightXCoordinate , Is.EqualTo(kernelOutput.StabilityOutput.MinimumSafetyCurve.Slices.Last().TopRightPoint.X)); }); switch (damEngineOutput.StabilityOutputItems[0].StabilityModelType) { case StabilityModelType.Bishop: CompareBishopSlipPlane((SlidingCircleMinimumSafetyCurveType) kernelOutput.StabilityOutput.MinimumSafetyCurve, damEngineOutput.StabilityOutputItems[0]); break; case StabilityModelType.UpliftVan: CompareUpliftVanSlipPlane((DualSlidingCircleMinimumSafetyCurveType) kernelOutput.StabilityOutput.MinimumSafetyCurve, damEngineOutput.StabilityOutputItems[0]); break; } CompareSlices(kernelOutput.StabilityOutput.MinimumSafetyCurve, damEngineOutput.StabilityOutputItems[0]); } private void CompareBishopSlipPlane(SlidingCircleMinimumSafetyCurveType stabilityOutputMinimumSafetyCurve, MacroStabilityOutputItem stabilityOutputItem) { Assert.Multiple(() => { Assert.That(stabilityOutputMinimumSafetyCurve.Center.X, Is.EqualTo(stabilityOutputItem.ActiveCenterPoint.X).Within(tolerance)); Assert.That(stabilityOutputMinimumSafetyCurve.Center.Z, Is.EqualTo(stabilityOutputItem.ActiveCenterPoint.Z).Within(tolerance)); Assert.That(stabilityOutputMinimumSafetyCurve.Radius, Is.EqualTo(stabilityOutputItem.ActiveCenterPointRadius).Within(tolerance)); }); } private void CompareUpliftVanSlipPlane(DualSlidingCircleMinimumSafetyCurveType stabilityOutputMinimumSafetyCurve, MacroStabilityOutputItem stabilityOutputItem) { Assert.Multiple(() => { Assert.That(stabilityOutputMinimumSafetyCurve.ActiveCircleCenter.X, Is.EqualTo(stabilityOutputItem.ActiveCenterPoint.X).Within(tolerance)); Assert.That(stabilityOutputMinimumSafetyCurve.ActiveCircleCenter.Z, Is.EqualTo(stabilityOutputItem.ActiveCenterPoint.Z).Within(tolerance)); Assert.That(stabilityOutputMinimumSafetyCurve.ActiveCircleRadius, Is.EqualTo(stabilityOutputItem.ActiveCenterPointRadius).Within(tolerance)); Assert.That(stabilityOutputMinimumSafetyCurve.PassiveCircleCenter.X, Is.EqualTo(stabilityOutputItem.PassiveCenterPoint.X).Within(tolerance)); Assert.That(stabilityOutputMinimumSafetyCurve.PassiveCircleCenter.Z, Is.EqualTo(stabilityOutputItem.PassiveCenterPoint.Z).Within(tolerance)); Assert.That(stabilityOutputMinimumSafetyCurve.PassiveCircleRadius, Is.EqualTo(stabilityOutputItem.PassiveCenterPointRadius).Within(tolerance)); }); } private void CompareSlices(MinimumSafetyCurveBaseType stabilityOutputMinimumSafetyCurve, MacroStabilityOutputItem stabilityOutputItem) { Assert.That(stabilityOutputItem.ResultSlices, Has.Count.EqualTo(stabilityOutputMinimumSafetyCurve.Slices.Length), "Number of slices is not equal"); for (var sliceIndex = 0; sliceIndex < stabilityOutputMinimumSafetyCurve.Slices.Length; sliceIndex++) { MinimumSafetyCurveBaseTypeSlice kernelSlice = stabilityOutputMinimumSafetyCurve.Slices[sliceIndex]; StabilityResultSlice engineSlice = stabilityOutputItem.ResultSlices[sliceIndex]; Assert.Multiple(() => { Assert.That(kernelSlice.Name, Is.EqualTo(engineSlice.Name), "Slice names are not equal"); Assert.That(kernelSlice.TopLeftPoint.X, Is.EqualTo(engineSlice.TopLeftPoint.X).Within(tolerance)); Assert.That(kernelSlice.TopLeftPoint.Z, Is.EqualTo(engineSlice.TopLeftPoint.Z).Within(tolerance)); Assert.That(kernelSlice.TopRightPoint.X, Is.EqualTo(engineSlice.TopRightPoint.X).Within(tolerance)); Assert.That(kernelSlice.TopRightPoint.Z, Is.EqualTo(engineSlice.TopRightPoint.Z).Within(tolerance)); Assert.That(kernelSlice.BottomLeftPoint.X, Is.EqualTo(engineSlice.BottomLeftPoint.X).Within(tolerance)); Assert.That(kernelSlice.BottomLeftPoint.Z, Is.EqualTo(engineSlice.BottomLeftPoint.Z).Within(tolerance)); Assert.That(kernelSlice.BottomRightPoint.X, Is.EqualTo(engineSlice.BottomRightPoint.X).Within(tolerance)); Assert.That(kernelSlice.BottomRightPoint.Z, Is.EqualTo(engineSlice.BottomRightPoint.Z).Within(tolerance)); Assert.That(kernelSlice.Width, Is.EqualTo(engineSlice.Width).Within(tolerance)); Assert.That(kernelSlice.ArcLength, Is.EqualTo(engineSlice.ArcLength).Within(tolerance)); Assert.That(kernelSlice.TopAngle, Is.EqualTo(engineSlice.TopAngle).Within(tolerance)); Assert.That(kernelSlice.BottomAngle, Is.EqualTo(engineSlice.BottomAngle).Within(tolerance)); Assert.That(kernelSlice.CohesionInput, Is.EqualTo(engineSlice.CohesionInput).Within(tolerance)); Assert.That(kernelSlice.CohesionOutput, Is.EqualTo(engineSlice.CohesionOutput).Within(tolerance)); Assert.That(kernelSlice.FrictionAngleInput, Is.EqualTo(engineSlice.FrictionAngleInput).Within(tolerance)); Assert.That(kernelSlice.FrictionAngleOutput, Is.EqualTo(engineSlice.FrictionAngleOutput).Within(tolerance)); Assert.That(kernelSlice.YieldStress, Is.EqualTo(engineSlice.YieldStress).Within(tolerance)); Assert.That(kernelSlice.OCR, Is.EqualTo(engineSlice.OCR).Within(tolerance)); Assert.That(kernelSlice.DegreeOfConsolidationPorePressure, Is.EqualTo(engineSlice.DegreeOfConsolidationPorePressure).Within(tolerance)); Assert.That(kernelSlice.PorePressureDueToDegreeOfConsolidationLoad, Is.EqualTo(engineSlice.PorePressureDueToDegreeOfConsolidationLoad).Within(tolerance)); Assert.That(kernelSlice.HydrostaticPorePressure, Is.EqualTo(engineSlice.HydrostaticPorePressure).Within(tolerance)); }); } } private static FullOutputModelType CreateFullOutputModel(StabilityModelOption modelOption, bool isSucceeded) { var fullOutputModel = new FullOutputModelType { StabilityOutput = new StabilityOutputType(), PreprocessingOutput = new PreprocessingOutputType() }; fullOutputModel.StabilityOutput.SafetyFactor = 2.34; fullOutputModel.StabilityOutput.Succeeded = isSucceeded; fullOutputModel.StabilityOutput.ModelOption = modelOption; switch (fullOutputModel.StabilityOutput.ModelOption) { case StabilityModelOption.Bishop: fullOutputModel.StabilityOutput.MinimumSafetyCurve = CreateSlidingCircleMinimumSafetyCurve(); break; case StabilityModelOption.UpliftVan: fullOutputModel.StabilityOutput.MinimumSafetyCurve = CreateDualSlidingCircleMinimumSafetyCurve(); break; } fullOutputModel.StabilityOutput.MinimumSafetyCurve.Slices = CreateSlices(); return fullOutputModel; } private static SlidingCircleMinimumSafetyCurveType CreateSlidingCircleMinimumSafetyCurve() { var slidingCircleMinimumSafetyCurve = new SlidingCircleMinimumSafetyCurveType { Center = new Point2DType { X = 1.0, Z = 2.0 }, Radius = 3.0 }; return slidingCircleMinimumSafetyCurve; } private static DualSlidingCircleMinimumSafetyCurveType CreateDualSlidingCircleMinimumSafetyCurve() { var dualSlidingCircleMinimumSafetyCurve = new DualSlidingCircleMinimumSafetyCurveType { ActiveCircleCenter = new Point2DType { X = 1.0, Z = 2.0 }, PassiveCircleCenter = new Point2DType { X = 3.0, Z = 4.0 }, ActiveCircleRadius = 5.0, PassiveCircleRadius = 6.0 }; return dualSlidingCircleMinimumSafetyCurve; } private static MinimumSafetyCurveBaseTypeSlice[] CreateSlices() { var slices = new List { new() { TopLeftPoint = new Point2DType { X = 1.0, Z = 2.0 }, TopRightPoint = new Point2DType { X = 3.0, Z = 4.0 }, BottomLeftPoint = new Point2DType { X = 5.0, Z = 6.0 }, BottomRightPoint = new Point2DType { X = 7.0, Z = 8.0 }, Name = "TestSlice", Width = 9.0, ArcLength = 10.0, TopAngle = 11.0, BottomAngle = 12.0, CohesionInput = 13.0, CohesionOutput = 14.0, FrictionAngleInput = 15.0, FrictionAngleOutput = 16.0, YieldStress = 17.0, OCR = 18.0, POP = 19.0, DegreeOfConsolidationPorePressure = 20.0, PorePressureDueToDegreeOfConsolidationLoad = 21.0, DilatancyInput = 22.0, ExternalLoad = 23.0, HydrostaticPorePressure = 24.0 }, new() { TopLeftPoint = new Point2DType { X = 10.0, Z = 20.0 }, TopRightPoint = new Point2DType { X = 30.0, Z = 40.0 }, BottomLeftPoint = new Point2DType { X = 50.0, Z = 60.0 }, BottomRightPoint = new Point2DType { X = 70.0, Z = 80.0 }, Name = "UpdatedTestSlice", Width = 90.0, ArcLength = 100.0, TopAngle = 110.0, BottomAngle = 120.0, CohesionInput = 130.0, CohesionOutput = 140.0, FrictionAngleInput = 150.0, FrictionAngleOutput = 160.0, YieldStress = 170.0, OCR = 180.0, POP = 190.0, DegreeOfConsolidationPorePressure = 200.0, PorePressureDueToDegreeOfConsolidationLoad = 210.0, DilatancyInput = 220.0, ExternalLoad = 230.0, HydrostaticPorePressure = 240.0 } }; return slices.ToArray(); } }