// Copyright (C) Stichting Deltares 2023. 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 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); var inputData = CreateExampleDamProjectData(); DamProjectData actualDamProjectData = FillDamFromXmlOutput.CreateDamProjectData(inputData, output); CompareDamProjectData(actualDamProjectData, expectedDamProjectData); } [Test] public void CanWriteAndReadDamProjectDataToXmlString() { DamProjectData expectedDamProjectData = CreateExampleDamProjectData(); Output output = FillXmlOutputFromDam.CreateOutput(expectedDamProjectData); var xmlString = DamXmlSerialization.SaveOutputAsXmlString(output); output = DamXmlSerialization.LoadOutputFromXmlString(xmlString); var 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 var calculationResults = output.Results.CalculationResults; int expectedNrOfCalculationResults = project.DesignCalculations.Count; Assert.AreEqual(expectedNrOfCalculationResults, calculationResults.Length); 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 (int 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, GeometryPoint = new GeometryPoint(), X = 0, Z = 0 }; surfaceline.CharacteristicPoints.Add(p1); var p2 = new CharacteristicPoint { CharacteristicPointType = CharacteristicPointType.DikeToeAtRiver, GeometryPoint = new GeometryPoint(), X = 10, Z = 0 }; surfaceline.CharacteristicPoints.Add(p2); var p3 = new CharacteristicPoint { CharacteristicPointType = CharacteristicPointType.DikeTopAtRiver, GeometryPoint = new GeometryPoint(), X = 15, Z = 2 }; surfaceline.CharacteristicPoints.Add(p3); var p4 = new CharacteristicPoint { CharacteristicPointType = CharacteristicPointType.DikeTopAtPolder, GeometryPoint = new GeometryPoint(), X = 18, Z = 2 }; surfaceline.CharacteristicPoints.Add(p4); var p5 = new CharacteristicPoint { CharacteristicPointType = CharacteristicPointType.DikeToeAtPolder, GeometryPoint = new GeometryPoint(), X = 23, Z = 0 }; surfaceline.CharacteristicPoints.Add(p5); var p6 = new CharacteristicPoint { CharacteristicPointType = CharacteristicPointType.SurfaceLevelInside, GeometryPoint = new GeometryPoint(), X = 100, Z = 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 (int 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: 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 == MStabModelType.Bishop || stabilityDesignResults.StabilityModelType == MStabModelType.UpliftVan) { stabilityDesignResults.ResultSlices = new List(); for (int 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 (int i = 0; i < timeSeriesCount; i++) { string locationId = String.Format("location{0}", i); var 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 = String.Format("station{0}", i); timeSerie.Units = "m"; timeSerie.SourceOrganisation = String.Format("organisation{0}", i); timeSerie.SourceSystem = String.Format("system{0}", i); timeSerie.FileDescription = String.Format("filedescription{0}", i); timeSerie.Region = String.Format("region{0}", i); timeSerie.TimeStep.Multiplier = 3600; timeSerie.TimeStep.Unit = TimeStepUnit.Second; for (int 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, Flag = 1, BasisFileName = String.Format("BasisFileName{0}", 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() : (double?) null, NumberOfIterations = random.Next(0, 2) == 1 ? random.Next() : (int?) null, UpliftSituation = random.Next(0, 2) == 1 ? CreateUpliftSituation(seed) : (UpliftSituation?) null, StabilityModelType = random.Next(0, 2) == 1 ? supportedModelTypeValues[random.Next(supportedModelTypeValues.Length - 1)] : (MStabModelType?) 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, GeometryPoint = new GeometryPoint(), X = random.NextDouble(), Z = random.NextDouble() }); surfaceLine.CharacteristicPoints.Add(new CharacteristicPoint { CharacteristicPointType = CharacteristicPointType.DikeToeAtRiver, GeometryPoint = new GeometryPoint(), X = random.NextDouble(), Z = random.NextDouble() }); surfaceLine.CharacteristicPoints.Add(new CharacteristicPoint { CharacteristicPointType = CharacteristicPointType.DikeTopAtRiver, GeometryPoint = new GeometryPoint(), X = random.NextDouble(), Z = random.NextDouble() }); surfaceLine.CharacteristicPoints.Add(new CharacteristicPoint { CharacteristicPointType = CharacteristicPointType.DikeTopAtPolder, GeometryPoint = new GeometryPoint(), X = random.NextDouble(), Z = random.NextDouble() }); surfaceLine.CharacteristicPoints.Add(new CharacteristicPoint { CharacteristicPointType = CharacteristicPointType.DikeToeAtPolder, GeometryPoint = new GeometryPoint(), X = random.NextDouble(), Z = random.NextDouble() }); surfaceLine.CharacteristicPoints.Add(new CharacteristicPoint { CharacteristicPointType = CharacteristicPointType.SurfaceLevelInside, GeometryPoint = new GeometryPoint(), X = random.NextDouble(), Z = 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.AreEqual(expected.ResultMessage, actual.ResultMessage); AssertUpliftSituation(expected.UpliftSituation, actual.UpliftSituation); bool safetyFactorHasValue = expected.SafetyFactor.HasValue; Assert.AreEqual(safetyFactorHasValue, actual.SafetyFactorSpecified); Assert.AreEqual(safetyFactorHasValue ? expected.SafetyFactor : 0, actual.SafetyFactor); bool numberOfIterationsHasValue = expected.NumberOfIterations.HasValue; Assert.AreEqual(numberOfIterationsHasValue, actual.NumberOfIterationsSpecified); Assert.AreEqual(numberOfIterationsHasValue ? expected.NumberOfIterations : 0, actual.NumberOfIterations); bool mStabModelTypeHasValue = expected.StabilityModelType.HasValue; Assert.AreEqual(mStabModelTypeHasValue, actual.StabilityModelTypeSpecified); var expectedModelType = mStabModelTypeHasValue ? Convert(expected.StabilityModelType) : DesignResultStabilityDesignResultsStabilityModelType.Bishop; Assert.AreEqual(expectedModelType, actual.StabilityModelType); AssertSurfaceLine(expected.RedesignedSurfaceLine, actual.RedesignedSurfaceLine); } private static void AssertUpliftSituation(UpliftSituation? expected, Io.XmlOutput.UpliftSituation actual) { if (!expected.HasValue) { Assert.IsNull(actual); return; } Assert.AreEqual(expected.Value.IsUplift, actual.IsUplift); Assert.AreEqual(expected.Value.Pl3MinUplift, actual.Pl3MinUplift); Assert.AreEqual(expected.Value.Pl3HeadAdjusted, actual.Pl3HeadAdjusted); Assert.AreEqual(expected.Value.Pl3LocationXMinUplift, actual.Pl3LocationXMinUplift); Assert.AreEqual(expected.Value.Pl4MinUplift, actual.Pl4MinUplift); Assert.AreEqual(expected.Value.Pl4HeadAdjusted, actual.Pl4HeadAdjusted); Assert.AreEqual(expected.Value.Pl4LocationXMinUplift, actual.Pl4LocationXMinUplift); } private static void AssertSurfaceLine(SurfaceLine2 expected, SurfaceLine actual) { if (expected == null) { Assert.IsNull(actual); return; } Assert.AreEqual(expected.Name, actual.Name); int expectedNrOfCharacteristicPoints = expected.CharacteristicPoints.Count; Assert.AreEqual(expectedNrOfCharacteristicPoints, actual.Points.Length); 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.AreEqual(expected.X, actual.X); Assert.AreEqual(expected.Z, actual.Z); Assert.AreEqual(ConversionHelper.ConvertToInputPointType(expected.CharacteristicPointType), actual.PointType); } private void CompareDamProjectData(DamProjectData actual, DamProjectData expected) { var compare = new CompareLogic { Config = { MaxDifferences = 100 } }; var result = compare.Compare(expected, actual); var fakeDiffCount = 0; foreach (var resultDifference in result.Differences) { if (resultDifference.PropertyName.Contains("ForecastDateTime")) { fakeDiffCount++; } } Assert.AreEqual(fakeDiffCount, result.Differences.Count, "Differences found read/write Input object"); } } }