using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Xml;
using Deltares.Geotechnics;
using Deltares.Geotechnics.IO.Importers;
using Deltares.Probabilistic;
using Deltares.Standard.EventPublisher;
using Deltares.Standard.Language;
using Deltares.Standard.Logging;
using Deltares.Standard.TestUtils;
using NUnit.Framework;
namespace Deltares.DSoilModel.Data.Tests
{
[TestFixture]
public class DSoilModelIOTest
{
private bool oldIsDataEventPublishStopped;
private LanguageType oldLanguageType;
[TestFixtureSetUp]
public void FixtureSetup()
{
oldIsDataEventPublishStopped = DataEventPublisher.IsDataEventPublishStopped;
DataEventPublisher.IsDataEventPublishStopped = true;
oldLanguageType = LocalizationManager.CurrentLanguage;
LocalizationManager.CurrentLanguage = LanguageType.English;
Directory.CreateDirectory("TempFiles");
}
[TestFixtureTearDown]
public void FixtureTearDown()
{
DataEventPublisher.IsDataEventPublishStopped = oldIsDataEventPublishStopped;
LocalizationManager.CurrentLanguage = oldLanguageType;
Directory.Delete("TempFiles", true);
}
[TestCase("Groot Salland.mdb", 66, 5, 1, 3, 2)]
[TestCase("Groot Salland.gdb", 66, 5, 1, 3, 2)]
[TestCase("FileNotFound", 0, 0, 0, 0, 0)]
public void TestAddOldProjectDataBaseToProject(string fileName, int soils, int profiles1D, int profiles2D, int cpts, int borings)
{
var project = new DSoilModelProject();
string filePath = Path.Combine(GetTestFilesPath(), fileName);
LogManager.Clear();
DSoilModelIO.AddOldProjectDataBaseToProject(filePath, project);
if (File.Exists(filePath))
{
// Number of soils is original 65, but after reading borings the number will be 66 because a material "Onbepaald" is added
Assert.AreEqual(soils, project.Soils.Soils.Count);
Assert.AreEqual(profiles1D, project.SoilProfiles1D.Count);
Assert.AreEqual(profiles2D, project.SoilProfiles2D.Count);
Assert.AreEqual(cpts, project.CPTs.Count);
Assert.AreEqual(borings, project.Borings.Count);
}
else
{
LogManager.Messages.Any(m => m.MessageType == LogMessageType.Error);
}
}
[Test]
public void ImportOfEmptyCsvFilesResultsInWarninLogMessage()
{
// empty soilprofiles Csv
var testFile = Path.Combine("TempFiles","empty_soilprofiles.csv");
File.WriteAllText(testFile, @"soilprofile_id;top_level;soil_name;soiltype", Encoding.ASCII);
var project = new DSoilModelProject();
LogManager.Clear();
project.ReadSoilProfiles1DFromFile(testFile);
CheckForEmptyWarningInLog();
File.Delete(testFile);
// empty segments.csv
testFile = Path.Combine("TempFiles","empty_segments.csv");
File.WriteAllText(testFile, @"segment_id;soilprofile_id;probability;calculation_type", Encoding.ASCII);
LogManager.Clear();
DSoilModelIO.ReadCsvSegmentsFromFileAndAddToProject(testFile, project);
CheckForEmptyWarningInLog();
File.Delete(testFile);
// empty surfacelines.csv
testFile = Path.Combine("TempFiles","empty_surfacelines.csv");
File.WriteAllText(testFile, @"LocationID;Geologischprofiel;X_GridPoint;Y_GridPoint;ScenarioClusterID;X1;Y1;Z1;.....;Xn;Yn;Zn;(Profiel)", Encoding.ASCII);
LogManager.Clear();
DSoilModelIO.ReadCsvSurfaceLineFromFileAndAddToProject(testFile, project);
CheckForEmptyWarningInLog();
File.Delete(testFile);
// empty characteristicpoints.csv
testFile = Path.Combine("TempFiles","empty_characteristicpoints.csv");
File.WriteAllText(testFile, @"LocationID;X_Maaiveld binnenwaarts;Y_Maaiveld binnenwaarts;Z_Maaiveld binnenwaarts;X_Insteek sloot polderzijde;Y_Insteek sloot polderzijde;Z_Insteek sloot polderzijde;X_Slootbodem polderzijde;Y_Slootbodem polderzijde;Z_Slootbodem polderzijde;X_Slootbodem dijkzijde;Y_Slootbodem dijkzijde;Z_Slootbodem dijkzijde;X_Insteek sloot dijkzijde;Y_Insteek_sloot dijkzijde;Z_Insteek sloot dijkzijde;X_Teen dijk binnenwaarts;Y_Teen dijk binnenwaarts;Z_Teen dijk binnenwaarts;X_Kruin binnenberm;Y_Kruin binnenberm;Z_Kruin binnenberm;X_Insteek binnenberm;Y_Insteek binnenberm;Z_Insteek binnenberm;X_Kruin binnentalud;Y_Kruin binnentalud;Z_Kruin binnentalud;X_Verkeersbelasting kant binnenwaarts;Y_Verkeersbelasting kant binnenwaarts;Z_Verkeersbelasting kant binnenwaarts;X_Verkeersbelasting kant buitenwaarts;Y_Verkeersbelasting kant buitenwaarts;Z_Verkeersbelasting kant buitenwaarts;X_Kruin buitentalud;Y_Kruin buitentalud;Z_Kruin buitentalud;X_Insteek buitenberm;Y_Insteek buitenberm;Z_Insteek buitenberm;X_Kruin buitenberm;Y_Kruin buitenberm;Z_Kruin buitenberm;X_Teen dijk buitenwaarts;Y_Teen dijk buitenwaarts;Z_Teen dijk buitenwaarts;X_Maaiveld buitenwaarts;Y_Maaiveld buitenwaarts;Z_Maaiveld buitenwaarts;X_Dijktafelhoogte;Y_Dijktafelhoogte;Z_Dijktafelhoogte;Volgnummer", Encoding.ASCII);
LogManager.Clear();
DSoilModelIO.ReadCsvCharacteristicPointsFromFileAndAddToProject(testFile, project);
CheckForEmptyWarningInLog();
File.Delete(testFile);
}
private static void CheckForEmptyWarningInLog()
{
Assert.Greater(LogManager.Messages.Count, 0);
var logMessage = LogManager.Messages.FirstOrDefault(m => m.Message.Contains("empty"));
Assert.NotNull(logMessage);
Assert.AreEqual(logMessage.MessageType, LogMessageType.Warning);
}
[Test]
public void DamDefxImporterMustRefuseIncompleteSegments()
{
// setup, using a copy of DAM tutorial Design with the Geometries folder deleted.
string tutorial = Path.Combine(GetTestFilesPath(), "DAM Incomplete.defx");
Assert.IsTrue(File.Exists(tutorial));
// call
using (var project = new DSoilModelProject())
{
LogManager.Messages.Clear();
DSoilModelIO.ReadDamDefinitionsFromFileAndAddToProject(tutorial, project);
// assert
Assert.AreEqual(0, project.SoilSegments.Count);
Assert.AreEqual(0, project.SoilProfiles2D.Count);
Assert.AreEqual(200, project.Soils.Soils.Count);
Assert.GreaterOrEqual(LogManager.Messages.Count(m => m.MessageType == LogMessageType.Warning && m.Message.Contains("is refused as one or more profiles are missing")), 23);
}
}
///
/// Test import of defx file from Dam Tutorial design
///
[Test]
public void ImportDamSegmentsFromTutorialDefxFile()
{
// setup
string tutorial = Path.Combine(GetTestFilesPath(), "Dam Tutorial Design", "DAM Tutorial Design.defx");
Assert.IsTrue(File.Exists(tutorial));
// call
using (var project = new DSoilModelProject())
{
LogManager.Messages.Clear();
DSoilModelIO.ReadDamDefinitionsFromFileAndAddToProject(tutorial, project);
// assert
Assert.AreEqual(23, project.SoilSegments.Count);
Assert.AreEqual(23, project.SoilProfiles2D.Count);
Assert.AreEqual(200, project.Soils.Soils.Count);
Assert.IsFalse(LogManager.Messages.Any(m => m.MessageType == LogMessageType.Error ||m.MessageType == LogMessageType.FatalError));
foreach (var segment in project.SoilSegments)
{
foreach (var profile in segment.StochasticSoilModel.StochasticSoilProfiles)
{
Assert.IsTrue(profile.Profile is SoilProfile1D || profile.Profile is SoilProfile2D);
}
}
}
}
///
/// Test import of defx file from Delfland example
///
[Test]
public void ImportDamSegmentsFromDelflandDefxFile()
{
// setup
string defxPath = Path.Combine(GetTestFilesPath(), "Delfland.defx");
Assert.IsTrue(File.Exists(defxPath));
// call
using (var project = new DSoilModelProject())
{
LogManager.Messages.Clear();
DSoilModelIO.ReadDamDefinitionsFromFileAndAddToProject(defxPath, project);
// assert
Assert.AreEqual(10, project.SoilSegments.Count);
Assert.AreEqual(147, project.SoilProfiles1D.Count);
Assert.AreEqual(51, project.Soils.Soils.Count);
Assert.IsFalse(LogManager.Messages.Any(m => m.MessageType == LogMessageType.Error || m.MessageType == LogMessageType.FatalError));
foreach (var segment in project.SoilSegments)
{
foreach (var profile in segment.StochasticSoilModel.StochasticSoilProfiles)
{
Assert.IsTrue(profile.Profile is SoilProfile1D || profile.Profile is SoilProfile2D);
}
}
}
}
[Test]
public void ImportDuplicateMdbDoesNotCreateDuplicateSoils()
{
string mdbFile = Path.Combine(GetTestFilesPath(), "Groot Salland.mdb");
var project = new DSoilModelProject();
project.ReadSoilsFromDatabase(mdbFile);
var soilsCount = project.Soils.Soils.Count;
// importing the same file again should not add to the soil count
project.ReadSoilsFromDatabase(mdbFile);
Assert.AreEqual(soilsCount, project.Soils.Soils.Count);
}
[Test]
public void ImportMdbAquitardDoesNotOverwriteAquiferSoilWithSameName()
{
var project = new DSoilModelProject();
// file with TestSand as aquifer
project.ReadSoilsFromDatabase(Path.Combine(GetTestFilesPath(), "AquiferTest.mdb"));
// file with TestSand as aquitard
project.ReadSoilsFromDatabase(Path.Combine(GetTestFilesPath(), "AquitardTest.mdb"));
Assert.AreEqual(3, project.Soils.Soils.Count);
Assert.AreEqual(1, project.Soils.Soils.Count(s => s.Name == "TestSand"));
Assert.AreEqual(1, project.Soils.Soils.Count(s => s.Name == "TestSand (1)"));
Assert.AreEqual(1, project.Soils.Soils.Count(s => s.Name == "TestLoam"));
Assert.AreEqual(1, project.Soils.AquiferDictionary.Count(item => item.Value == true));
}
// please note that not all ShearstrengthModel options are supported by DSoilModel, so most values in the file are converted to ShearStrengthModel.None here
// the same testfile and cases are tested in Deltares.SoilBase.Test (DslGeoIo) and there the result is a bit different
[TestCase(1, "1 C-Phi", SoilType.Gravel, 11, 12, ShearStrengthModel.CPhi, 13, 14, true, 15, 16, 0.17, 111, 11, DistributionType.Normal, 11, 1, DistributionType.Deterministic)]
[TestCase(2, "2 Stress table", SoilType.Sand, 21, 22, ShearStrengthModel.None, 23, 24, true, 25, 26, 0.27, 222, 22, DistributionType.Normal, 22, 2, DistributionType.Deterministic)]
[TestCase(3, "3 Pseudo values", SoilType.Loam, 31, 32, ShearStrengthModel.None, 33, 34, true, 35, 36, 0.37, 333, 33, DistributionType.LogNormal, 33, 3, DistributionType.Normal)]
[TestCase(4, "4 Su measured", SoilType.Clay, 41, 42, ShearStrengthModel.None, 43, 44, true, 45, 46, 0.47, 444, 44, DistributionType.LogNormal, 44, 4, DistributionType.Normal)]
[TestCase(5, "5 Su calculated", SoilType.Peat, 51, 52, ShearStrengthModel.CuCalculated, 53, 54, true, 55, 56, 0.57, 555, 55, DistributionType.Deterministic, 55, 5, DistributionType.LogNormal)]
[TestCase(6, "6 Su gradient", SoilType.Gravel, 61, 62, ShearStrengthModel.None, 63, 64, true, 65, 66, 0.67, 666, 66, DistributionType.Deterministic, 66, 6, DistributionType.LogNormal)]
[TestCase(7, "7 No type", SoilType.Sand, 71, 72, ShearStrengthModel.CPhi, 73, 74, true, 75, 76, 0.77, 777, 77, DistributionType.Normal, 77, 7, DistributionType.Deterministic)]
public void ImportMaterialsFromMdbFileMadeWithMSoilBase(int nb, string name, SoilType type, double gammaUnsat, double gammaSat, ShearStrengthModel model, double coh, double phi,
bool usePop, double pop, double ratioS, double expM, double d70MeanInMicroMeter, double d70StdDevInMicroMeter, DistributionType d70Dist, double permMean, double permStdDev, DistributionType permDist)
{
var project = new DSoilModelProject();
project.ReadSoilsFromDatabase(Path.Combine(GetTestFilesPath(), "MSoilBase.mdb"));
Assert.AreEqual(7, project.Soils.Soils.Count);
project.Soils.Soils.Sort();
// General properties
Assert.AreEqual(name, project.Soils.Soils[nb-1].Name);
Assert.AreEqual(type, project.Soils.Soils[nb-1].SoilType);
// Filter BM Macrostabiliteit
Assert.AreEqual(gammaUnsat, project.Soils.Soils[nb - 1].AbovePhreaticLevel);
Assert.AreEqual(gammaSat, project.Soils.Soils[nb - 1].BelowPhreaticLevel);
Assert.AreEqual(model, project.Soils.Soils[nb - 1].ShearStrengthModel);
Assert.AreEqual(coh, project.Soils.Soils[nb - 1].Cohesion);
Assert.AreEqual(coh, project.Soils.Soils[nb - 1].CohesionStochast.Mean);
Assert.AreEqual(phi, project.Soils.Soils[nb - 1].FrictionAngle);
Assert.AreEqual(phi, project.Soils.Soils[nb - 1].FrictionAngleStochast.Mean);
Assert.AreEqual(usePop, project.Soils.Soils[nb - 1].UsePop);
Assert.AreEqual(pop, project.Soils.Soils[nb - 1].POP);
Assert.AreEqual(pop, project.Soils.Soils[nb - 1].POPStochast.Mean);
Assert.AreEqual(ratioS, project.Soils.Soils[nb - 1].RatioCuPc);
Assert.AreEqual(ratioS, project.Soils.Soils[nb - 1].RatioCuPcStochast.Mean);
Assert.AreEqual(expM, project.Soils.Soils[nb - 1].StrengthIncreaseExponent);
Assert.AreEqual(expM, project.Soils.Soils[nb - 1].StrengthIncreaseExponentStochast.Mean);
// Filter Piping - Ringtoets
Assert.AreEqual(gammaUnsat, project.Soils.Soils[nb - 1].AbovePhreaticLevelStochast.Mean);
Assert.AreEqual(double.NaN, project.Soils.Soils[nb - 1].AbovePhreaticLevelStochast.Deviation);
Assert.AreEqual(DistributionType.LogNormal, project.Soils.Soils[nb - 1].AbovePhreaticLevelStochast.DistributionType);
Assert.AreEqual(gammaSat, project.Soils.Soils[nb - 1].BelowPhreaticLevelStochast.Mean);
Assert.AreEqual(double.NaN, project.Soils.Soils[nb - 1].BelowPhreaticLevelStochast.Deviation);
Assert.AreEqual(DistributionType.LogNormal, project.Soils.Soils[nb - 1].BelowPhreaticLevelStochast.DistributionType);
Assert.AreEqual(d70MeanInMicroMeter * 1e-6, project.Soils.Soils[nb - 1].DiameterD70);
Assert.AreEqual(d70MeanInMicroMeter * 1e-6, project.Soils.Soils[nb - 1].DiameterD70Stochast.Mean);
Assert.AreEqual(d70StdDevInMicroMeter * 1e-6, project.Soils.Soils[nb - 1].DiameterD70Stochast.Deviation);
Assert.AreEqual(d70Dist, project.Soils.Soils[nb - 1].DiameterD70Stochast.DistributionType);
Assert.AreEqual(permMean, project.Soils.Soils[nb - 1].PermeabKx);
Assert.AreEqual(permMean, project.Soils.Soils[nb - 1].PermeabKxStochast.Mean);
Assert.AreEqual(permStdDev, project.Soils.Soils[nb - 1].PermeabKxStochast.Deviation);
Assert.AreEqual(permDist, project.Soils.Soils[nb - 1].PermeabKxStochast.DistributionType);
}
///
/// Test of the import of surface lines from Csv file
///
[Test]
public void ImportSurfacelinesFromCsvFile()
{
string csvFullFileName = Path.Combine(GetTestFilesPath(), "DSoilModelsurfacelines.csv");
using (var project = new DSoilModelProject())
{
DSoilModelIO.ReadCsvSurfaceLineFromFileAndAddToProject(csvFullFileName, project);
Assert.AreEqual(2, project.SurfaceLines.Count,
"The number of surface lines read from csv file is not right.");
Assert.AreEqual(202, project.SurfaceLines[0].Geometry.Count,
"The number of points in the surface lines read from csv file is not right.");
Assert.AreEqual(132, project.SurfaceLines[1].Geometry.Count,
"The number of points in the surface lines read from csv file is not right.");
}
}
[Test]
public void SegmentsImporterMustRefuseIncompleteSegments()
{
// setup using DAM files
string segmentFile = Path.Combine(GetTestFilesPath(), "Delfland", "segments.csv");
string soilprofileFile = Path.Combine(GetTestFilesPath(), "Delfland", "soilprofiles.csv");
using (var project = new DSoilModelProject())
{
// complete import
project.SoilProfiles1D.AddRange(new SoilProfilesImporter().ReadSoilProfiles(soilprofileFile, new SoilList()));
Assert.AreEqual(147, project.SoilProfiles1D.Count);
LogManager.Clear();
DSoilModelIO.ReadCsvSegmentsFromFileAndAddToProject(segmentFile, project);
Assert.AreEqual(10, project.SoilSegments.Count);
Assert.AreEqual(0, LogManager.Messages.Count);
// incomplete import of segments
project.SoilProfiles1D.Clear();
project.SoilSegments.Clear();
DSoilModelIO.ReadCsvSegmentsFromFileAndAddToProject(segmentFile, project);
Assert.AreEqual(0, project.SoilSegments.Count);
Assert.GreaterOrEqual(LogManager.Messages.Count, 10);
}
}
[Test]
public void StoreAndRestoreUnusedStressTables()
{
// even if a stresstable has no records, is not used by any soil, save and reopen project should not discard those
const string testFile = @"TempFiles\EmptyStressTables.soil";
using (var project = new DSoilModelProject())
{
project.StressCurves.Add(new StressCurve { Name = "StressCurve" } );
project.BondStressCurves.Add(new BondStressCurve { Name = "BondStressCurve" });
DSoilModelIO.SaveSoilDatabase(testFile, project);
}
using (var project = (DSoilModelProject) DSoilModelIO.OpenSoilDatabase(testFile))
{
Assert.AreEqual(1, project.StressCurves.Count);
Assert.AreEqual("StressCurve", project.StressCurves.First().Name);
Assert.AreEqual(1, project.BondStressCurves.Count);
Assert.AreEqual("BondStressCurve", project.BondStressCurves.First().Name);
}
}
[Test]
public void SegmentCsvImportWithAllSoilProfilesMissing_IncompleteSegmentsRefused()
{
// see issue DSB-389, dataset wit all profiles missing
var project = new DSoilModelProject();
LogManager.Clear();
project.ReadSoilProfiles1DFromFile(Path.Combine(GetTestFilesPath(), "Missing profiles", "1D_profiles.csv"));
Assert.AreEqual(3, project.SoilProfiles1D.Count);
Assert.AreEqual(5, LogManager.Messages.Count(m => m.Message.Contains("undefined soil")));
LogManager.Clear();
DSoilModelIO.ReadCsvSegmentsFromFileAndAddToProject(Path.Combine(GetTestFilesPath(), "Missing profiles", "Soilsegments.csv"), project, true);
Assert.AreEqual(0, project.SoilSegments.Count);
Assert.AreEqual(2, LogManager.Messages.Count(m => m.Message.Contains("profiles are missing")));
}
[Test]
public void SegmentCsvImportWithSomeProfilesMissing_IncompleteSegmentsRefused()
{
// dataset with partially missing profiles
var project = new DSoilModelProject();
LogManager.Clear();
project.ReadSoilProfiles1DFromFile(Path.Combine(GetTestFilesPath(), "Missing profiles", "1D_profiles_2segmenten.csv"));
Assert.AreEqual(5, project.SoilProfiles1D.Count);
Assert.AreEqual(7, LogManager.Messages.Count(m => m.Message.Contains("undefined soil")));
LogManager.Clear();
DSoilModelIO.ReadCsvSegmentsFromFileAndAddToProject(Path.Combine(GetTestFilesPath(), "Missing profiles", "Soilsegments_2segmenten.csv"), project, true);
Assert.AreEqual(2, project.SoilSegments.Count);
Assert.AreEqual(2, LogManager.Messages.Count(m => m.Message.Contains("profiles are missing")));
}
private string GetTestFilesPath()
{
return Path.GetFullPath(@"..\..\Deltares.DSoilModel.Data.Tests\TestFiles");
}
private string GetNodeAttribute(XmlNode node, string attribute)
{
return (string)typeof(DSoilModelIO).GetMethod("GetNodeAttribute", BindingFlags.NonPublic | BindingFlags.Static).Invoke(null, new object[] { node , attribute });
}
[Test]
public void GetNodeAttributeTest()
{
var doc = new XmlDocument();
var node = doc.CreateNode(XmlNodeType.Element, "SomeName", "SomeUrl");
var res = GetNodeAttribute(null, "SomeAttribute");
Assert.IsNull(res, "No node - no attributes");
res = GetNodeAttribute(node, "SomeAttribute");
Assert.IsNull(res, "Attribute doesn't exist");
var attr = doc.CreateAttribute("Attr1");
attr.Value = "Text1";
node.Attributes.Append(attr);
res = GetNodeAttribute(node, "Attr1");
Assert.AreEqual("Text1", res, "Attribute doesn't exist");
}
}
}