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