// Copyright (C) Stichting Deltares 2025. All rights reserved.
//
// This file is part of the application DAM - UI.
//
// DAM - UI is free software: you can redistribute it and/or modify
// it under the terms of the GNU 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 General Public License for more details.
//
// You should have received a copy of the GNU 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.IO;
using System.Linq;
using Deltares.Dam.Data;
using Deltares.Dam.Data.DataPlugins;
using Deltares.Dam.Data.DataPlugins.Configuration;
using Deltares.DamEngine.Data.Standard;
using Deltares.Geometry;
using Deltares.Geotechnics.Soils;
using Deltares.Geotechnics.SurfaceLines;
using Deltares.Standard.Language;
using Deltares.Standard.Logging;
using NUnit.Framework;
namespace Deltares.Dam.Tests;
[TestFixture]
public class DikeImporterTests
{
private DataSourceContainer dataSourceContainer;
[Test]
[TestCase(DamProjectType.Design)]
[TestCase(DamProjectType.DamLiveConfiguration)]
public void ImportDikeOnlyCsvFiles1D(DamProjectType damProjectType)
{
const double cTolerance = 0.0001;
const string definitionFilename = @".\TestData\CSVData\Full1DProject\Import.defx";
dataSourceContainer = DataSourceContainer.Deserialize(definitionFilename);
string damImportFolder = Path.GetDirectoryName(definitionFilename);
using Dike dike = DikeImporter.ImportDataForDike("", damImportFolder,
dataSourceContainer,
damProjectType, null,
out List _);
// Check Dike
Assert.That(dike, Is.Not.Null);
Assert.Multiple(() =>
{
//Check locations
Assert.That(dike.Locations, Has.Count.EqualTo(2));
// Check Soilprofiles
Assert.That(dike.SoilProfiles, Has.Count.EqualTo(23));
});
SoilProfile1D soilProfile = dike.SoilProfiles.First(x => x.Name.Equals("25_2_1_bz_4"));
Assert.Multiple(() =>
{
Assert.That(soilProfile.Layers[0].Soil.Name, Is.EqualTo("kade"));
//Check Soils
Assert.That(dike.SoilList.Soils, Has.Count.EqualTo(51));
});
Soil soil = dike.SoilList.Soils[dike.SoilList.GetSoilIndexByName("kade")];
Assert.That(soil.AbovePhreaticLevel, Is.EqualTo(17.0).Within(cTolerance));
//Check Soil of shear strength model SigmaTauTable with sigma-tau table
soil = dike.SoilList.Soils[dike.SoilList.GetSoilIndexByName("CCC")];
Assert.Multiple(() =>
{
Assert.That(soil.ShearStrengthModel, Is.EqualTo(ShearStrengthModel.StressTable));
Assert.That(soil.StressTable.Name, Is.EqualTo("CurveKlei"));
Assert.That(soil.StressTable.SigmaTaus, Has.Count.EqualTo(5));
});
Assert.Multiple(() =>
{
Assert.That(soil.StressTable.SigmaTaus[0].Sigma, Is.EqualTo(0.0).Within(cTolerance));
Assert.That(soil.StressTable.SigmaTaus[0].Tau, Is.EqualTo(2.05).Within(cTolerance));
Assert.That(soil.StressTable.SigmaTaus[4].Sigma, Is.EqualTo(110.5).Within(cTolerance));
Assert.That(soil.StressTable.SigmaTaus[4].Tau, Is.EqualTo(44.6).Within(cTolerance));
});
//Check Soil of shear strength model MohrCoulomb with sigma-tau table
soil = dike.SoilList.Soils[dike.SoilList.GetSoilIndexByName("BSS")];
Assert.Multiple(() =>
{
Assert.That(soil.ShearStrengthModel, Is.EqualTo(ShearStrengthModel.CPhi));
Assert.That(soil.StressTable.Name, Is.EqualTo("CurveZand"));
Assert.That(soil.StressTable.SigmaTaus, Has.Count.EqualTo(2));
});
Assert.Multiple(() =>
{
Assert.That(soil.StressTable.SigmaTaus[0].Sigma, Is.EqualTo(0.0).Within(cTolerance));
Assert.That(soil.StressTable.SigmaTaus[0].Tau, Is.EqualTo(0.0).Within(cTolerance));
Assert.That(soil.StressTable.SigmaTaus[1].Sigma, Is.EqualTo(200.0).Within(cTolerance));
Assert.That(soil.StressTable.SigmaTaus[1].Tau, Is.EqualTo(129.88).Within(cTolerance));
});
//Check Soil of shear strength model SuTable with su table
soil = dike.SoilList.Soils[dike.SoilList.GetSoilIndexByName("FFO")];
Assert.Multiple(() =>
{
Assert.That(soil.ShearStrengthModel, Is.EqualTo(ShearStrengthModel.SuTable));
Assert.That(soil.SuTable.Name, Is.EqualTo("SuKlei"));
Assert.That(soil.SuTable.SigmaSus, Has.Count.EqualTo(5));
});
Assert.Multiple(() =>
{
Assert.That(soil.SuTable.SigmaSus[0].Sigma, Is.EqualTo(0.0).Within(cTolerance));
Assert.That(soil.SuTable.SigmaSus[0].Su, Is.EqualTo(2.15).Within(cTolerance));
Assert.That(soil.SuTable.SigmaSus[4].Sigma, Is.EqualTo(111.5).Within(cTolerance));
Assert.That(soil.SuTable.SigmaSus[4].Su, Is.EqualTo(44.7).Within(cTolerance));
});
//Check Soil of shear strength model MohrCoulomb with su table
soil = dike.SoilList.Soils[dike.SoilList.GetSoilIndexByName("FCC")];
Assert.Multiple(() =>
{
Assert.That(soil.ShearStrengthModel, Is.EqualTo(ShearStrengthModel.CPhi));
Assert.That(soil.SuTable.Name, Is.EqualTo("CurveZand"));
Assert.That(soil.SuTable.SigmaSus, Has.Count.EqualTo(2));
});
Assert.Multiple(() =>
{
Assert.That(soil.SuTable.SigmaSus[0].Sigma, Is.EqualTo(0.0).Within(cTolerance));
Assert.That(soil.SuTable.SigmaSus[0].Su, Is.EqualTo(0.0).Within(cTolerance));
Assert.That(soil.SuTable.SigmaSus[1].Sigma, Is.EqualTo(201.0).Within(cTolerance));
Assert.That(soil.SuTable.SigmaSus[1].Su, Is.EqualTo(129.98).Within(cTolerance));
});
// Check Segments
Assert.That(dike.Segments, Has.Count.EqualTo(2));
Segment segment = dike.Segments.First(x => x.Name.Equals("106"));
Assert.Multiple(() =>
{
Assert.That(segment.SoilProfileProbabilities[0].SoilGeometryName, Is.EqualTo("25_2_1_bz_1"));
Assert.That(segment.SoilProfileProbabilities[0].Probability, Is.EqualTo(35.0).Within(cTolerance));
Assert.That(segment.SoilProfileProbabilities[0].SegmentFailureMechanismType,
Is.EqualTo(FailureMechanismSystemType.StabilityInside));
});
}
[Test]
public void ImportDikeCsvFiles1DMissingSigmaTauCurve()
{
const string definitionFilename = @".\TestData\CSVData\Full1DProjectMissingSigmaTauTable\Import.defx";
dataSourceContainer = DataSourceContainer.Deserialize(definitionFilename);
string damImportFolder = Path.GetDirectoryName(definitionFilename);
List logMessages;
using Dike dike = DikeImporter.ImportDataForDike("", damImportFolder,
dataSourceContainer,
DamProjectType.Design, null,
out logMessages);
Assert.That(logMessages, Has.Count.GreaterThan(0));
Assert.Multiple(() =>
{
Assert.That(logMessages[0].Message, Contains.Substring("Sigma-Tau curve table Missing not found in CSV file for soil CCC (or sigmataucurves.csv missing)."));
Assert.That(logMessages[1].Message, Contains.Substring("Sigma-Tau curve table MissingNotUsed not found in CSV file for soil ETL (or sigmataucurves.csv missing)."));
});
// Check Dike
Assert.That(dike, Is.Not.Null);
//Check locations
Assert.That(dike.Locations, Has.Count.EqualTo(0));
}
[Test]
public void ImportDikeCsvFiles1DMissingSigmaTauCurveCsvFile()
{
const string definitionFilename = @".\TestData\CSVData\Full1DProjectMissingSigmaTauCsvFile\Import.defx";
dataSourceContainer = DataSourceContainer.Deserialize(definitionFilename);
string damImportFolder = Path.GetDirectoryName(definitionFilename);
List logMessages;
using Dike dike = DikeImporter.ImportDataForDike("", damImportFolder,
dataSourceContainer,
DamProjectType.Design, null,
out logMessages);
Assert.That(logMessages, Has.Count.GreaterThan(0));
Assert.Multiple(() =>
{
Assert.That(logMessages[0].Message, Contains.Substring("Sigma-Tau curve table Missing not found in CSV file for soil CCC (or sigmataucurves.csv missing)."));
// Check Dike
Assert.That(dike, Is.Not.Null);
//Check locations
Assert.That(dike.Locations, Has.Count.EqualTo(0));
});
}
[Test]
public void ImportDikeCsvFiles1DMissingSuTable()
{
const string definitionFilename = @".\TestData\CSVData\Full1DProjectMissingSuTable\Import.defx";
dataSourceContainer = DataSourceContainer.Deserialize(definitionFilename);
string damImportFolder = Path.GetDirectoryName(definitionFilename);
List logMessages;
using Dike dike = DikeImporter.ImportDataForDike("", damImportFolder,
dataSourceContainer,
DamProjectType.Design, null,
out logMessages);
Assert.That(logMessages, Has.Count.GreaterThan(0));
Assert.Multiple(() =>
{
Assert.That(logMessages[0].Message, Contains.Substring("Su table Missing not found in CSV file for soil CCC (or sutables.csv missing)."));
Assert.That(logMessages[1].Message, Contains.Substring("Su table MissingNotUsed not found in CSV file for soil ETL (or sutables.csv missing)."));
});
// Check Dike
Assert.That(dike, Is.Not.Null);
//Check locations
Assert.That(dike.Locations, Has.Count.EqualTo(0));
}
[Test]
public void ImportDikeCsvFiles1DMissingSuTableCsvFile()
{
const string definitionFilename = @".\TestData\CSVData\Full1DProjectMissingSuTableCsvFile\Import.defx";
dataSourceContainer = DataSourceContainer.Deserialize(definitionFilename);
string damImportFolder = Path.GetDirectoryName(definitionFilename);
List logMessages;
using Dike dike = DikeImporter.ImportDataForDike("", damImportFolder,
dataSourceContainer,
DamProjectType.Design, null,
out logMessages);
Assert.That(logMessages, Has.Count.GreaterThan(0));
Assert.Multiple(() =>
{
Assert.That(logMessages[0].Message, Contains.Substring("Su table Missing not found in CSV file for soil CCC (or sutables.csv missing)."));
// Check Dike
Assert.That(dike, Is.Not.Null);
//Check locations
Assert.That(dike.Locations, Has.Count.EqualTo(0));
});
}
[Test]
[TestCase(DamProjectType.Design)]
[TestCase(DamProjectType.DamLiveConfiguration)]
public void ImportDikeOnlyCsvFiles2D(DamProjectType damProjectType)
{
const string definitionFilename = @".\TestData\CSVData\Full2DProject\Import.defx";
const string projectFilename = @".\TestData\TestWithGeometries2D.damx";
using (var damProject = new DamProject())
{
dataSourceContainer = DataSourceContainer.Deserialize(definitionFilename);
string damImportFolder = Path.GetDirectoryName(definitionFilename);
damProject.DamProjectData.Dike = DikeImporter.ImportDataForDike("", damImportFolder,
dataSourceContainer,
damProjectType, null, out List _);
damProject.AssignGeometry2DMapnameIfNotAssigned(Path.Combine(damImportFolder, dataSourceContainer.MapSoilProfile2D));
// Save the data
damProject.SaveXMLProject(projectFilename, damProject);
// Check Dike
Assert.That(damProject.DamProjectData.Dike, Is.Not.Null);
Dike dike = damProject.DamProjectData.Dike;
Assert.Multiple(() =>
{
//Check locations
Assert.That(dike.Locations, Has.Count.EqualTo(17));
// Check aquifers
Assert.That(dike.Aquifers, Has.Count.EqualTo(2));
// Surface lines of imported dike have same instance
Location location = dike.Locations.First(l => l.Name.Equals("location_dijkring10_dwp28_6"));
SurfaceLine2 surfaceLine = dike.SurfaceLines2.First(s => s.Name.Equals(location.SurfaceLine2.Name));
Assert.That(surfaceLine, Is.SameAs(location.SurfaceLine2));
});
}
}
[Test]
public void ImportDikeOnlyWithoutPl3AndPl4CsvFiles()
{
const string definitionFilename = @".\TestData\CSVData\DataWithoutPl3AndPl4\Import.defx";
dataSourceContainer = DataSourceContainer.Deserialize(definitionFilename);
string damImportFolder = Path.GetDirectoryName(definitionFilename);
using Dike dike = DikeImporter.ImportDataForDike("", damImportFolder,
dataSourceContainer,
DamProjectType.Design, null, out List _);
// Check Dike
Assert.That(dike, Is.Not.Null);
//Check locations
Assert.That(dike.Locations, Has.Count.EqualTo(2));
}
[Test]
public void ImportDikeOnlyCsvFiles1DRelativeSoilProfiles()
{
const double cTolerance = 0.0001;
const string definitionFilename = @".\TestData\CSVData\Full1DProject\Import relative soilprofiles.defx";
dataSourceContainer = DataSourceContainer.Deserialize(definitionFilename);
string damImportFolder = Path.GetDirectoryName(definitionFilename);
using (Dike dike = DikeImporter.ImportDataForDike("", damImportFolder, dataSourceContainer,
DamProjectType.Design, null, out List _))
using (Dike referenceDike = DikeImporter.ImportDataForDike("", damImportFolder,
dataSourceContainer,
DamProjectType.Design, null, out List _))
{
// If profiles are defined as relative profiles, new absolute profiles will be generated for each location
if (dataSourceContainer.IsImportAsRelativeProfiles)
{
DikePostProcessRelativeProfiles.CreateAbsoluteProfiles(dike,
dataSourceContainer.SoilProfileCharacteristicPointReference);
}
// Check Dike
Assert.That(dike, Is.Not.Null);
Assert.Multiple(() =>
{
//Check locations
Assert.That(dike.Locations, Has.Count.EqualTo(2));
// Check Soilprofiles
// Count is 43: 23 (imported) + 7 (generated for first location) + 13 (generated for second location)
Assert.That(dike.SoilProfiles, Has.Count.EqualTo(43));
});
SoilProfile1D soilProfile = dike.SoilProfiles.First(x => x.Name.Equals("25_2_1_bz_4"));
Assert.Multiple(() =>
{
Assert.That(soilProfile.Layers[0].Soil.Name, Is.EqualTo("kade"));
Assert.That(soilProfile.TopLevel, Is.EqualTo(60.0));
});
// Check if all profiles are made absolute from relative
foreach (Location location in dike.Locations)
foreach (SoilGeometryProbability soilProfileProbability in location.Segment.SoilProfileProbabilities)
{
GeometryPoint dikeToeAtPolder = location.SurfaceLine2.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType
.DikeToeAtPolder);
Assert.That(dikeToeAtPolder.Z, Is.EqualTo(soilProfileProbability.SoilProfile.Layers[1].TopLevel).Within(cTolerance));
}
// Compare reference dike to converted dike
foreach (Location location in dike.Locations)
{
Location referenceLocation = referenceDike.Locations.Find(l => l.Name.Equals(location.Name));
var soilProbabilityIndex = 0;
foreach (SoilGeometryProbability referenceSoilProfileProbability in referenceLocation.Segment.SoilProfileProbabilities)
{
soilProbabilityIndex++;
SoilGeometryProbability soilProfileProbability =
location.Segment.SoilProfileProbabilities.Find(
s => s.SoilProfile.Name.Equals(string.Format("{0}-{1}-{2}",
referenceSoilProfileProbability.SoilProfile.Name, location.Name, soilProbabilityIndex)));
for (var layerIndex = 0;
layerIndex < soilProfileProbability.SoilProfile.LayerCount;
layerIndex++)
{
// As the moved profile has a new top layer, make sure to compare the proper layers
if (layerIndex > 0)
{
Assert.That(
soilProfileProbability.SoilProfile.Layers[layerIndex].Height,
Is.EqualTo(referenceSoilProfileProbability.SoilProfile.Layers[layerIndex - 1].Height).Within(cTolerance),
string.Format(
"Location {0} Segment {1} soilProfile {2} Layer {3} ({4}/{5}), Org ({6}/{7})",
location.Name, location.Segment.Name, soilProfileProbability.SoilProfile.Name,
soilProfileProbability.SoilProfile.Layers[layerIndex],
soilProfileProbability.SoilProfile.Layers[layerIndex].TopLevel,
soilProfileProbability.SoilProfile.Layers[layerIndex].BottomLevel,
referenceSoilProfileProbability.SoilProfile.Layers[layerIndex - 1].TopLevel,
referenceSoilProfileProbability.SoilProfile.Layers[layerIndex - 1].BottomLevel));
}
}
}
}
}
}
[Test]
public void IsZoneDataReadCorrectlyFromCsvFiles()
{
const double cTolerance = 0.0001;
const string definitionFilename = @".\TestData\CSVData\ProjectZoneType\Import.defx";
dataSourceContainer = DataSourceContainer.Deserialize(definitionFilename);
string damImportFolder = Path.GetDirectoryName(definitionFilename);
using (Dike dike = DikeImporter.ImportDataForDike("", damImportFolder, dataSourceContainer,
DamProjectType.Design, null, out List _))
{
// Check Dike
Assert.That(dike, Is.Not.Null);
//Check locations
Assert.That(dike.Locations, Has.Count.EqualTo(2));
Assert.Multiple(() =>
{
Assert.That(dike.Locations[0].StabilityZoneType, Is.EqualTo(StabilityZoneType.NoZones));
Assert.That(dike.Locations[0].ForbiddenZoneFactor, Is.EqualTo(0.5).Within(cTolerance));
Assert.That(dike.Locations[1].StabilityZoneType, Is.EqualTo(StabilityZoneType.ForbiddenZone));
Assert.That(dike.Locations[1].ForbiddenZoneFactor, Is.EqualTo(0.9).Within(cTolerance));
});
}
}
}