// 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;
using System.Collections.Generic;
using Deltares.DamEngine.Data.General;
using Deltares.DamEngine.Data.General.Results;
using Deltares.DamEngine.Data.General.TimeSeries;
using Deltares.DamEngine.Data.Geometry;
using Deltares.DamEngine.Data.Geotechnics;
using Deltares.DamEngine.Data.Standard.Calculation;
using Deltares.DamEngine.Data.Standard.Logging;
using Deltares.DamEngine.Io;
using Deltares.DamEngine.Io.XmlOutput;
using KellermanSoftware.CompareNetObjects;
using NUnit.Framework;
using DesignResult = Deltares.DamEngine.Data.General.Results.DesignResult;
using TimeSerie = Deltares.DamEngine.Data.General.TimeSeries.TimeSerie;
using UpliftSituation = Deltares.DamEngine.Data.General.UpliftSituation;
namespace Deltares.DamEngine.Interface.Tests;
[TestFixture]
public class FillXmlOutputFromDamTests
{
[Test]
public void CanWriteAndReadDamProjectDataToXml()
{
const string outputFilename = "OutputFile.xml";
DamProjectData expectedDamProjectData = CreateExampleDamProjectData();
Output output = FillXmlOutputFromDam.CreateOutput(expectedDamProjectData);
DamXmlSerialization.SaveOutputAsXmlFile(outputFilename, output);
output = DamXmlSerialization.LoadOutputFromXmlFile(outputFilename);
DamProjectData inputData = CreateExampleDamProjectData();
DamProjectData actualDamProjectData = FillDamFromXmlOutput.CreateDamProjectData(inputData, output);
CompareDamProjectData(actualDamProjectData, expectedDamProjectData);
}
[Test]
public void CanWriteAndReadDamProjectDataToXmlString()
{
DamProjectData expectedDamProjectData = CreateExampleDamProjectData();
Output output = FillXmlOutputFromDam.CreateOutput(expectedDamProjectData);
string xmlString = DamXmlSerialization.SaveOutputAsXmlString(output);
output = DamXmlSerialization.LoadOutputFromXmlString(xmlString);
DamProjectData inputData = CreateExampleDamProjectData();
DamProjectData actualDamProjectData = FillDamFromXmlOutput.CreateDamProjectData(inputData, output);
CompareDamProjectData(actualDamProjectData, expectedDamProjectData);
}
[Test]
public void CreateOutput_DamProjectDataWithStabilityDesignResults_CreatesOutputWithStabilityResults()
{
// Setup
var random = new Random(21);
var project = new DamProjectData
{
CalculationMessages = new List(),
DesignCalculations = new List
{
CreateStabilityDesignResults(random.Next()),
CreateStabilityDesignResults(random.Next()),
CreateStabilityDesignResults(random.Next()),
CreateStabilityDesignResults(random.Next())
}
};
// Call
Output output = FillXmlOutputFromDam.CreateOutput(project);
// Assert
Io.XmlOutput.DesignResult[] calculationResults = output.Results.CalculationResults;
int expectedNrOfCalculationResults = project.DesignCalculations.Count;
Assert.That(calculationResults.Length, Is.EqualTo(expectedNrOfCalculationResults));
for (var i = 0; i < expectedNrOfCalculationResults; i++)
{
AssertStabilityDesignResults(project.DesignCalculations[i].StabilityDesignResults,
calculationResults[i].StabilityDesignResults);
}
}
private DamProjectData CreateExampleDamProjectData()
{
const int designResultsCount = 3;
const int locationResultsCount = 2;
var damProjectData = new DamProjectData
{
DesignCalculations = new List()
};
for (var i = 0; i < designResultsCount; i++)
{
var result = new DesignResult("location " + i, "Scenario " + (i * 2))
{
BaseFileName = "my basefilename " + i,
CalculationSubDir = "CalcSubDir",
ProfileName = "profile" + i
};
result.CalculationResult = CalculationResult.RunFailed;
// Note : as Wti2017BackwardErosionHcritical is in use in this test, the modeltype MUST be Wti2017.
result.PipingDesignResults = new PipingDesignResults(PipingModelType.Wti2017)
{
ResultMessage = "no run made",
UpliftFactor = 1.3 * i,
HeaveFactor = 1.1 * i,
BlighFactor = 1.03 * i,
BlighHcritical = 0.4,
LocalExitPointX = 34.21,
Wti2017UpliftDeltaPhiC = 1.09 * i,
EffectiveStress = 13.23 * i,
Wti2017UpliftHcritical = 1.19 * i,
Wti2017BackwardErosionHcritical = 1.29 * i,
Wti2017BackwardErosionDeltaPhiC = 1.34 * i,
Wti2017BackwardErosionDeltaPhiReduced = 1.27 * i,
Wti2017HeaveHcritical = 1.24 * i,
Wti2017BackwardErosionSafetyFactor = 1.39 * i,
Wti2017UpliftSafetyFactor = 1.49 * i,
Wti2017HeaveSafetyFactor = 1.59 * i,
Wti2017Gradient = 1.69 * i,
Wti2017HcriticalOverall = 1.79 * i,
Wti2017SafetyFactorOverall = 3.21 * i,
CCreep = 234.1 * i
};
var situation = new UpliftSituation
{
IsUplift = true,
Pl3MinUplift = 0.1,
Pl3HeadAdjusted = 0.2,
Pl3LocationXMinUplift = 0.3,
Pl4MinUplift = 0.1 * i,
Pl4HeadAdjusted = 0.2 * i,
Pl4LocationXMinUplift = 0.3 * i
};
var surfaceline = new SurfaceLine2();
surfaceline.Name = "Redesigned Surfaceline";
surfaceline.CharacteristicPoints.Geometry = surfaceline.Geometry;
var p1 = new CharacteristicPoint
{
CharacteristicPointType = CharacteristicPointType.SurfaceLevelOutside,
Point = new Point2D(0, 0)
};
surfaceline.CharacteristicPoints.Add(p1);
var p2 = new CharacteristicPoint
{
CharacteristicPointType = CharacteristicPointType.DikeToeAtRiver,
Point = new Point2D(10, 0)
};
surfaceline.CharacteristicPoints.Add(p2);
var p3 = new CharacteristicPoint
{
CharacteristicPointType = CharacteristicPointType.DikeTopAtRiver,
Point = new Point2D(15, 2)
};
surfaceline.CharacteristicPoints.Add(p3);
var p4 = new CharacteristicPoint
{
CharacteristicPointType = CharacteristicPointType.DikeTopAtPolder,
Point = new Point2D(18, 2)
};
surfaceline.CharacteristicPoints.Add(p4);
var p5 = new CharacteristicPoint
{
CharacteristicPointType = CharacteristicPointType.DikeToeAtPolder,
Point = new Point2D(23, 0)
};
surfaceline.CharacteristicPoints.Add(p5);
var p6 = new CharacteristicPoint
{
CharacteristicPointType = CharacteristicPointType.SurfaceLevelInside,
Point = new Point2D(100, 0)
};
surfaceline.CharacteristicPoints.Add(p6);
result.PipingDesignResults.RedesignedSurfaceLine = surfaceline;
result.PipingDesignResults.UpliftSituation = situation;
var stabilityMStabModelTypes = new[]
{
MStabModelType.Bishop,
MStabModelType.UpliftVan,
MStabModelType.BishopUpliftVan
};
result.StabilityDesignResults = new StabilityDesignResults
{
ResultMessage = "no problemo",
SafetyFactor = (i + 1) * 0.66,
NumberOfIterations = (i + 1) * 3,
UpliftSituation = situation,
RedesignedSurfaceLine = surfaceline,
StabilityModelType = stabilityMStabModelTypes[i]
};
CreateSlipCircleResults(result.StabilityDesignResults);
damProjectData.DesignCalculations.Add(result);
}
damProjectData.Dike = new Dike();
for (var i = 0; i < locationResultsCount; i++)
{
var location = new Location();
location.Name = "A" + (i + 1);
location.DistanceToEntryPoint = 0.2 * i + 0.56;
location.Segment = new Segment();
var soilGeometryProbability = new SoilGeometryProbability();
soilGeometryProbability.SoilProfile1D = new SoilProfile1D();
soilGeometryProbability.SoilProfile1DName = soilGeometryProbability.SoilProfile1D.Name;
location.Segment.SoilProfileProbabilities.Add(soilGeometryProbability);
damProjectData.Dike.Locations.Add(location);
}
damProjectData.CalculationMessages = new List();
damProjectData.CalculationMessages.Add(new LogMessage(LogMessageType.Error, null, "Error 1"));
damProjectData.CalculationMessages.Add(new LogMessage(LogMessageType.Error, null, "Error 2"));
damProjectData.CalculationMessages.Add(new LogMessage(LogMessageType.Warning, null, "Warning 1"));
FillOutputTimeSeries(damProjectData);
return damProjectData;
}
private void CreateSlipCircleResults(StabilityDesignResults stabilityDesignResults)
{
switch (stabilityDesignResults.StabilityModelType)
{
case MStabModelType.Bishop:
stabilityDesignResults.ActiveCenterPoint = new Point2D
{
X = 100,
Z = -10
};
stabilityDesignResults.ActiveCenterPointRadius = 50;
break;
case MStabModelType.UpliftVan:
case MStabModelType.BishopUpliftVan:
stabilityDesignResults.ActiveCenterPoint = new Point2D
{
X = 100,
Z = -10
};
stabilityDesignResults.ActiveCenterPointRadius = 50;
stabilityDesignResults.PassiveCenterPoint = new Point2D
{
X = 101,
Z = -11
};
stabilityDesignResults.PassiveCenterPointRadius = 51;
break;
}
if (stabilityDesignResults.StabilityModelType is MStabModelType.Bishop or MStabModelType.UpliftVan or MStabModelType.BishopUpliftVan)
{
stabilityDesignResults.ResultSlices = new List();
for (var i = 0; i < 9; i++)
{
var slice = new StabilityResultSlice();
slice.TopLeftPoint = new Point2D(i + 1.3, i + 2.3);
slice.TopRightPoint = new Point2D(i + 12.3, i + 22.3);
slice.BottomLeftPoint = new Point2D(i - 1.3, i - 2.3);
slice.BottomRightPoint = new Point2D(i - 12.3, i - 22.3);
stabilityDesignResults.ResultSlices.Add(slice);
}
}
}
private void FillOutputTimeSeries(DamProjectData damProjectData)
{
const int timeSeriesCount = 2;
const int timeEntriesCount = 3;
const string idPipingBligh = "PipingFactorBligh";
const string idStabilityInsideFactor = "StabilityInsideFactor";
damProjectData.OutputTimeSerieCollection = new TimeSerieCollection();
for (var i = 0; i < timeSeriesCount; i++)
{
var locationId = $"location{i}";
TimeSerie timeSerie = damProjectData.OutputTimeSerieCollection.AddNewSeries(locationId);
timeSerie.ParameterId = (i % 2 == 0) ? idPipingBligh : idStabilityInsideFactor;
timeSerie.ForecastDateTime = DateTime.Now;
timeSerie.Type = "instantaneous";
timeSerie.StartDateTime = new DateTime(2012, 12, 31);
timeSerie.EndDateTime = new DateTime(2012, 12, 31, 1, 0, 0);
timeSerie.MissVal = -9999.0;
timeSerie.LongName = timeSerie.LocationId + "long";
timeSerie.StationName = $"station{i}";
timeSerie.Units = "m";
timeSerie.SourceOrganisation = $"organisation{i}";
timeSerie.SourceSystem = $"system{i}";
timeSerie.FileDescription = $"filedescription{i}";
timeSerie.Region = $"region{i}";
timeSerie.TimeStep.Multiplier = 3600;
timeSerie.TimeStep.Unit = TimeStepUnit.Second;
for (var j = 0; j < timeEntriesCount; j++)
{
timeSerie.Entries.Add(new TimeSerieEntry
{
DateTime = new DateTime(2012, 12, 31, 1, j * 10, 0),
Value = 1 + j * 0.1,
BishopCircleX = 2 + j * 0.2,
BishopCircleZ = 3 + j * 0.3,
BishopRadius = 4 + j * 0.4
// Flag = 1,
// BasisFileName = $"BasisFileName{i}"
});
}
}
}
private static DesignResult CreateStabilityDesignResults(int seed)
{
var random = new Random(seed);
var supportedModelTypeValues = new[]
{
MStabModelType.Bishop,
MStabModelType.UpliftVan,
MStabModelType.BishopUpliftVan
};
var stabilityDesignResults = new StabilityDesignResults
{
ResultMessage = "ResultMessage",
SafetyFactor = random.Next(0, 2) == 1 ? random.NextDouble() : null,
NumberOfIterations = random.Next(0, 2) == 1 ? random.Next() : null,
UpliftSituation = random.Next(0, 2) == 1 ? CreateUpliftSituation(seed) : null,
StabilityModelType = random.Next(0, 2) == 1
? supportedModelTypeValues[random.Next(supportedModelTypeValues.Length - 1)]
: null,
RedesignedSurfaceLine = random.Next(0, 2) == 1 ? CreateSurfaceLine(seed) : null,
ActiveCenterPoint = CreatePoint2D(seed),
ActiveCenterPointRadius = random.NextDouble(),
PassiveCenterPoint = CreatePoint2D(seed),
PassiveCenterPointRadius = random.NextDouble()
};
return new DesignResult
{
StabilityDesignResults = stabilityDesignResults
};
}
private static UpliftSituation CreateUpliftSituation(int seed)
{
var random = new Random(seed);
return new UpliftSituation
{
IsUplift = true,
Pl3MinUplift = random.NextDouble(),
Pl3HeadAdjusted = random.NextDouble(),
Pl3LocationXMinUplift = random.NextDouble(),
Pl4MinUplift = random.NextDouble(),
Pl4HeadAdjusted = random.NextDouble(),
Pl4LocationXMinUplift = random.NextDouble()
};
}
private static SurfaceLine2 CreateSurfaceLine(int seed)
{
var random = new Random(seed);
var surfaceLine = new SurfaceLine2
{
Name = "Redesigned Surfaceline"
};
surfaceLine.CharacteristicPoints.Add(new CharacteristicPoint
{
CharacteristicPointType = CharacteristicPointType.SurfaceLevelOutside,
Point = new Point2D(random.NextDouble(), random.NextDouble())
});
surfaceLine.CharacteristicPoints.Add(new CharacteristicPoint
{
CharacteristicPointType = CharacteristicPointType.DikeToeAtRiver,
Point = new Point2D(random.NextDouble(), random.NextDouble())
});
surfaceLine.CharacteristicPoints.Add(new CharacteristicPoint
{
CharacteristicPointType = CharacteristicPointType.DikeTopAtRiver,
Point = new Point2D(random.NextDouble(), random.NextDouble())
});
surfaceLine.CharacteristicPoints.Add(new CharacteristicPoint
{
CharacteristicPointType = CharacteristicPointType.DikeTopAtPolder,
Point = new Point2D(random.NextDouble(), random.NextDouble()),
});
surfaceLine.CharacteristicPoints.Add(new CharacteristicPoint
{
CharacteristicPointType = CharacteristicPointType.DikeToeAtPolder,
Point = new Point2D(random.NextDouble(), random.NextDouble())
});
surfaceLine.CharacteristicPoints.Add(new CharacteristicPoint
{
CharacteristicPointType = CharacteristicPointType.SurfaceLevelInside,
Point = new Point2D(random.NextDouble(), random.NextDouble())
});
return surfaceLine;
}
private static Point2D CreatePoint2D(int seed)
{
var random = new Random(seed);
return new Point2D
{
X = random.NextDouble(),
Z = random.NextDouble()
};
}
private static DesignResultStabilityDesignResultsStabilityModelType? Convert(MStabModelType? stabilityModelType)
{
if (stabilityModelType.HasValue)
{
return ConversionHelper.ConvertToOutputStabilityModelType(stabilityModelType.Value);
}
throw new NotSupportedException();
}
private static void AssertStabilityDesignResults(StabilityDesignResults expected,
DesignResultStabilityDesignResults actual)
{
Assert.That(actual.ResultMessage, Is.EqualTo(expected.ResultMessage));
AssertUpliftSituation(expected.UpliftSituation, actual.UpliftSituation);
bool safetyFactorHasValue = expected.SafetyFactor.HasValue;
Assert.That(actual.SafetyFactorSpecified, Is.EqualTo(safetyFactorHasValue));
Assert.That(actual.SafetyFactor, Is.EqualTo(safetyFactorHasValue ? expected.SafetyFactor : 0));
bool numberOfIterationsHasValue = expected.NumberOfIterations.HasValue;
Assert.That(actual.NumberOfIterationsSpecified, Is.EqualTo(numberOfIterationsHasValue));
Assert.That(actual.NumberOfIterations, Is.EqualTo(numberOfIterationsHasValue ? expected.NumberOfIterations : 0));
bool mStabModelTypeHasValue = expected.StabilityModelType.HasValue;
Assert.That(actual.StabilityModelTypeSpecified, Is.EqualTo(mStabModelTypeHasValue));
DesignResultStabilityDesignResultsStabilityModelType? expectedModelType = mStabModelTypeHasValue
? Convert(expected.StabilityModelType)
: DesignResultStabilityDesignResultsStabilityModelType.Bishop;
Assert.That(actual.StabilityModelType, Is.EqualTo(expectedModelType));
AssertSurfaceLine(expected.RedesignedSurfaceLine, actual.RedesignedSurfaceLine);
}
private static void AssertUpliftSituation(UpliftSituation? expected, Io.XmlOutput.UpliftSituation actual)
{
if (!expected.HasValue)
{
Assert.That(actual, Is.Null);
return;
}
Assert.That(actual.IsUplift, Is.EqualTo(expected.Value.IsUplift));
Assert.That(actual.Pl3MinUplift, Is.EqualTo(expected.Value.Pl3MinUplift));
Assert.That(actual.Pl3HeadAdjusted, Is.EqualTo(expected.Value.Pl3HeadAdjusted));
Assert.That(actual.Pl3LocationXMinUplift, Is.EqualTo(expected.Value.Pl3LocationXMinUplift));
Assert.That(actual.Pl4MinUplift, Is.EqualTo(expected.Value.Pl4MinUplift));
Assert.That(actual.Pl4HeadAdjusted, Is.EqualTo(expected.Value.Pl4HeadAdjusted));
Assert.That(actual.Pl4LocationXMinUplift, Is.EqualTo(expected.Value.Pl4LocationXMinUplift));
}
private static void AssertSurfaceLine(SurfaceLine2 expected, SurfaceLine actual)
{
if (expected == null)
{
Assert.That(actual, Is.Null);
return;
}
Assert.That(actual.Name, Is.EqualTo(expected.Name));
int expectedNrOfCharacteristicPoints = expected.CharacteristicPoints.Count;
Assert.That(actual.Points.Length, Is.EqualTo(expectedNrOfCharacteristicPoints));
for (var i = 0; i < expectedNrOfCharacteristicPoints; i++)
{
CharacteristicPoint expectedCharacteristicPoint = expected.CharacteristicPoints[i];
SurfaceLinePoint actualCharacteristicPoint = actual.Points[i];
AssertCharacteristicPoint(expectedCharacteristicPoint, actualCharacteristicPoint);
}
}
private static void AssertCharacteristicPoint(CharacteristicPoint expected, SurfaceLinePoint actual)
{
Assert.That(actual.X, Is.EqualTo(expected.Point.X));
Assert.That(actual.Z, Is.EqualTo(expected.Point.Z));
Assert.That(actual.PointType,
Is.EqualTo(ConversionHelper.ConvertToInputPointType(expected.CharacteristicPointType)));
}
private void CompareDamProjectData(DamProjectData actual, DamProjectData expected)
{
var compare = new CompareLogic
{
Config =
{
MaxDifferences = 100
}
};
ComparisonResult result = compare.Compare(expected, actual);
var fakeDiffCount = 0;
foreach (Difference resultDifference in result.Differences)
{
if (resultDifference.PropertyName.Contains("ForecastDateTime"))
{
fakeDiffCount++;
}
}
Assert.That(result.Differences.Count, Is.EqualTo(fakeDiffCount), "Differences found read/write Input object");
}
}