Index: DamClients/DamUI/trunk/src/Dam/Tests/Deltares.Dam.Tests.csproj =================================================================== diff -u -r3008 -r3015 --- DamClients/DamUI/trunk/src/Dam/Tests/Deltares.Dam.Tests.csproj (.../Deltares.Dam.Tests.csproj) (revision 3008) +++ DamClients/DamUI/trunk/src/Dam/Tests/Deltares.Dam.Tests.csproj (.../Deltares.Dam.Tests.csproj) (revision 3015) @@ -149,6 +149,7 @@ + Index: DamClients/DamUI/trunk/src/DamClientsLibrary/Deltares.Dam.Data/StiImporter/SoilProfile2DImporter.cs =================================================================== diff -u --- DamClients/DamUI/trunk/src/DamClientsLibrary/Deltares.Dam.Data/StiImporter/SoilProfile2DImporter.cs (revision 0) +++ DamClients/DamUI/trunk/src/DamClientsLibrary/Deltares.Dam.Data/StiImporter/SoilProfile2DImporter.cs (revision 3015) @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Deltares.Geotechnics.Soils; +using Deltares.Standard.Logging; + +namespace Deltares.Dam.Data.StiImporter +{ + /// + /// Importer to import . + /// + public class SoilProfile2DImporter + { + /// + /// Imports the that are contained within . + /// + /// The directory to retrieve the soil profiles from. + /// The to import the soil profiles for. + /// The that contains all the valid soil materials. + /// A collection of . + /// + /// Thrown when or is null. + /// + /// Thrown when + /// is null, empty or consist of only whitespaces. + /// + /// Thrown when no soil profiles could be read from . + /// + public IEnumerable Import(string soilProfileDirectory, Segment segment, SoilList availableSoils) + { + if (segment == null) + { + throw new ArgumentNullException(nameof(segment)); + } + + if (availableSoils == null) + { + throw new ArgumentNullException(nameof(availableSoils)); + } + + if (string.IsNullOrWhiteSpace(soilProfileDirectory)) + { + throw new ArgumentException($"'{nameof(soilProfileDirectory)}' cannot be null or consist of whitespaces only."); + } + + // Extract all soil profile 2D from a segment + var soilProfiles = segment.SoilProfileProbabilities + .Where(sp => sp.SoilProfileType == SoilProfileType.SoilGeometryStiFile); + + var importedSoilProfiles = new List(); + foreach (SoilGeometryProbability profile in soilProfiles) + { + string soilProfileFile = profile.SoilGeometry2DName; + SoilProfile2D readSoilProfile = ReadSoilProfile(soilProfileDirectory, soilProfileFile); + if (readSoilProfile != null) + { + if (IsValidSoilProfile(availableSoils, readSoilProfile)) + { + importedSoilProfiles.Add(readSoilProfile); + } + else + { + LogManager.Messages.Add(new LogMessage(LogMessageType.Error, this, $"'{soilProfileFile}' contains undefined soil materials.")); + } + } + } + + return importedSoilProfiles; + } + + private SoilProfile2D ReadSoilProfile(string soilProfileDirectory, string soilProfileFile) + { + string filePath = Path.Combine(soilProfileDirectory, soilProfileFile); + + try + { + var reader = new StiFileReader(); + SoilProfile2D readSoilProfile = reader.ReadSoilProfile(filePath); + return readSoilProfile; + } + catch (StiFileReadException e) + { + LogManager.Messages.Add(new LogMessage(LogMessageType.Error, this, e.Message)); + } + + return null; + } + + private static bool IsValidSoilProfile(SoilList availableSoils, SoilProfile2D profile) + { + var soilNames = new HashSet(availableSoils.Soils.Select(s => s.Name)); + return profile.Surfaces.All(soilLayer => soilNames.Contains(soilLayer.Name)); + } + } +} \ No newline at end of file Index: DamClients/DamUI/trunk/src/DamClientsLibrary/Deltares.Dam.Data/Deltares.Dam.Data.csproj =================================================================== diff -u -r3007 -r3015 --- DamClients/DamUI/trunk/src/DamClientsLibrary/Deltares.Dam.Data/Deltares.Dam.Data.csproj (.../Deltares.Dam.Data.csproj) (revision 3007) +++ DamClients/DamUI/trunk/src/DamClientsLibrary/Deltares.Dam.Data/Deltares.Dam.Data.csproj (.../Deltares.Dam.Data.csproj) (revision 3015) @@ -200,6 +200,7 @@ + Index: DamClients/DamUI/trunk/src/Dam/Tests/StiImporter/SoilProfile2DImporterTest.cs =================================================================== diff -u --- DamClients/DamUI/trunk/src/Dam/Tests/StiImporter/SoilProfile2DImporterTest.cs (revision 0) +++ DamClients/DamUI/trunk/src/Dam/Tests/StiImporter/SoilProfile2DImporterTest.cs (revision 3015) @@ -0,0 +1,219 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Deltares.Dam.Data; +using Deltares.Dam.Data.StiImporter; +using Deltares.Standard.Logging; +using NUnit.Framework; +using Soil = Deltares.Geotechnics.Soils.Soil; +using SoilList = Deltares.Geotechnics.Soils.SoilList; +using SoilProfile2D = Deltares.Geotechnics.Soils.SoilProfile2D; + +namespace Deltares.Dam.Tests.StiImporter +{ + [TestFixture] + public class SoilProfile2DImporterTest + { + private const string TestDataFolder = @"TestData\StiImporter\"; + + [Test] + [TestCase(null)] + [TestCase(" ")] + [TestCase("")] + public void Import_InvalidSoilProfileDirectory_ThrowsArgumentException(string invalidSoilProfileDirectory) + { + // Setup + var importer = new SoilProfile2DImporter(); + + // Call + TestDelegate call = () => importer.Import(invalidSoilProfileDirectory, new Segment(), new SoilList()); + + // Assert + Assert.That(call, Throws.ArgumentException + .With.Message.EqualTo("'soilProfileDirectory' cannot be null or consist of whitespaces only.")); + } + + [Test] + public void Import_SegmentNull_ThrowsArgumentNullException() + { + // Setup + var importer = new SoilProfile2DImporter(); + + // Call + TestDelegate call = () => importer.Import(string.Empty, null, new SoilList()); + + // Assert + Assert.That(call, Throws.TypeOf() + .With.Property(nameof(ArgumentNullException.ParamName)) + .EqualTo("segment")); + } + + [Test] + public void Import_AvailableSoilsNull_ThrowsArgumentNullException() + { + // Setup + var importer = new SoilProfile2DImporter(); + + // Call + TestDelegate call = () => importer.Import(string.Empty, new Segment(), null); + + // Assert + Assert.That(call, Throws.TypeOf() + .With.Property(nameof(ArgumentNullException.ParamName)) + .EqualTo("availableSoils")); + } + + [Test] + public void Import_WithValidArguments_ReturnsExpectedSoilProfiles() + { + // Setup + Segment segment = CreateSegmentWithProfiles(new[] + { + "SimpleProfile.sti", + "Tutorial-1a 10.1.4.3.sti" + }); + SoilList availableSoils = CreateSoilList(new[] + { + "Soft Clay", + "Sand", + "Peat", + "Muck" + }); + + var importer = new SoilProfile2DImporter(); + + // Call + IEnumerable soilProfiles = importer.Import(TestDataFolder, segment, availableSoils); + + // Assert + Assert.That(soilProfiles, Has.Count.EqualTo(2)); + SoilProfile2D soilProfileOne = soilProfiles.ElementAt(0); + CollectionAssert.AreEqual(new[] + { + "Soft Clay", + "Muck" + }, soilProfileOne.Surfaces.Select(s => s.Name)); + + SoilProfile2D soilProfileTwo = soilProfiles.ElementAt(1); + CollectionAssert.AreEqual(new[] + { + "Soft Clay", + "Sand", + "Peat", + "Soft Clay" + }, soilProfileTwo.Surfaces.Select(s => s.Name)); + } + + [Test] + public void Import_WithIncompleteSoilList_ReturnsOnlyCompleteSoilProfilesAndLogsMessage() + { + // Setup + LogManager.Messages.Clear(); // Clear all messages as it is a singleton + + const string invalidSoilProfile = "Tutorial-1a 10.1.4.3.sti"; // Soil profile also contains peat and sand for its layers + Segment segment = CreateSegmentWithProfiles(new[] + { + "SimpleProfile.sti", + invalidSoilProfile + }); + SoilList availableSoils = CreateSoilList(new[] + { + "Soft Clay", + "Muck" + }); + + var importer = new SoilProfile2DImporter(); + + // Call + IEnumerable soilProfiles = importer.Import(TestDataFolder, segment, availableSoils); + + // Assert + Assert.That(soilProfiles, Has.Count.EqualTo(1)); + SoilProfile2D soilProfileOne = soilProfiles.ElementAt(0); + CollectionAssert.AreEqual(new[] + { + "Soft Clay", + "Muck" + }, soilProfileOne.Surfaces.Select(s => s.Name)); + + string expectedMessage = $"'{invalidSoilProfile}' contains undefined soil materials."; + CollectionAssert.AreEqual(new[] + { + expectedMessage + }, LogManager.Messages.Select(m => m.Message)); + CollectionAssert.AreEqual(new[] + { + LogMessageType.Error + }, LogManager.Messages.Select(m => m.MessageType)); + CollectionAssert.AreEqual(new[] + { + importer + }, LogManager.Messages.Select(m => m.Subject)); + } + + [Test] + public void Import_WithSoilProfileCausingReadException_ReturnsOnlyCompleteSoilProfilesAndLogsMessage() + { + // Setup + LogManager.Messages.Clear(); // Clear all messages as it is a singleton + + const string invalidSoilProfile = "NonExistentSoilProfile"; + Segment segment = CreateSegmentWithProfiles(new[] + { + "SimpleProfile.sti", + invalidSoilProfile + }); + SoilList availableSoils = CreateSoilList(new[] + { + "Soft Clay", + "Muck" + }); + + var importer = new SoilProfile2DImporter(); + + // Call + IEnumerable soilProfiles = importer.Import(TestDataFolder, segment, availableSoils); + + // Assert + Assert.That(soilProfiles, Has.Count.EqualTo(1)); + SoilProfile2D soilProfileOne = soilProfiles.ElementAt(0); + CollectionAssert.AreEqual(new[] + { + "Soft Clay", + "Muck" + }, soilProfileOne.Surfaces.Select(s => s.Name)); + + LogMessage logMessage = LogManager.Messages.Single(); + Assert.That(logMessage.Message, Is.Not.Empty); + Assert.That(logMessage.MessageType, Is.EqualTo(LogMessageType.Error)); + Assert.That(logMessage.Subject, Is.SameAs(importer)); + } + + private static Segment CreateSegmentWithProfiles(IEnumerable soilProfileNames) + { + var random = new Random(21); + + var segment = new Segment(); + foreach (string soilProfileName in soilProfileNames) + { + segment.AddSoilGeometry2DProbability(soilProfileName, random.NextDouble(), null); + } + + return segment; + } + + private static SoilList CreateSoilList(IEnumerable soilNames) + { + var soilList = new SoilList(); + foreach (string soilName in soilNames) + { + soilList.Add(new Soil + { + Name = soilName + }); + } + + return soilList; + } + } +} \ No newline at end of file