Index: Ringtoets/Common/src/Ringtoets.Common.IO/Properties/Resources.Designer.cs =================================================================== diff -u -rbe4427a66ef77dfa213048b0a823824ea679bce3 -rd06750a4979861471df64a5f49dca99c33d34ce6 --- Ringtoets/Common/src/Ringtoets.Common.IO/Properties/Resources.Designer.cs (.../Resources.Designer.cs) (revision be4427a66ef77dfa213048b0a823824ea679bce3) +++ Ringtoets/Common/src/Ringtoets.Common.IO/Properties/Resources.Designer.cs (.../Resources.Designer.cs) (revision d06750a4979861471df64a5f49dca99c33d34ce6) @@ -1729,6 +1729,55 @@ } /// + /// Looks up a localized string similar to {0} + ///Het bestand wordt overgeslagen.. + /// + public static string StochasticSoilModelImporter_CriticalErrorMessage_0_File_Skipped { + get { + return ResourceManager.GetString("StochasticSoilModelImporter_CriticalErrorMessage_0_File_Skipped", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Inlezen van de stochastische ondergrondmodellen.. + /// + public static string StochasticSoilModelImporter_GetStochasticSoilModelReadResult_Reading_stochastic_soil_models_from_database { + get { + return ResourceManager.GetString("StochasticSoilModelImporter_GetStochasticSoilModelReadResult_Reading_stochastic_s" + + "oil_models_from_database", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Inlezen van de D-Soil Model database.. + /// + public static string StochasticSoilModelImporter_Reading_database { + get { + return ResourceManager.GetString("StochasticSoilModelImporter_Reading_database", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Er zijn geen ondergrondschematisaties gevonden in het stochastische ondergrondmodel '{0}'.. + /// + public static string StochasticSoilModelImporter_ValidateStochasticSoilModel_No_profiles_found_in_stochastic_soil_model_0 { + get { + return ResourceManager.GetString("StochasticSoilModelImporter_ValidateStochasticSoilModel_No_profiles_found_in_stoc" + + "hastic_soil_model_0", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to De som van de kansen van voorkomen in het stochastich ondergrondmodel '{0}' is niet gelijk aan 100%.. + /// + public static string StochasticSoilModelImporter_ValidateStochasticSoilModel_Sum_of_probabilities_of_stochastic_soil_model_0_is_not_correct { + get { + return ResourceManager.GetString("StochasticSoilModelImporter_ValidateStochasticSoilModel_Sum_of_probabilities_of_s" + + "tochastic_soil_model_0_is_not_correct", resourceCulture); + } + } + + /// /// Looks up a localized string similar to Het faalmechanisme '{0}' wordt niet ondersteund.. /// public static string StochasticSoilModelReader_ReadFailureMechanismType_Failure_mechanism_0_not_supported { Index: Ringtoets/Common/src/Ringtoets.Common.IO/Properties/Resources.resx =================================================================== diff -u -rbe4427a66ef77dfa213048b0a823824ea679bce3 -rd06750a4979861471df64a5f49dca99c33d34ce6 --- Ringtoets/Common/src/Ringtoets.Common.IO/Properties/Resources.resx (.../Resources.resx) (revision be4427a66ef77dfa213048b0a823824ea679bce3) +++ Ringtoets/Common/src/Ringtoets.Common.IO/Properties/Resources.resx (.../Resources.resx) (revision d06750a4979861471df64a5f49dca99c33d34ce6) @@ -858,4 +858,20 @@ Het faalmechanisme '{0}' wordt niet ondersteund. + + Inlezen van de D-Soil Model database. + + + {0} +Het bestand wordt overgeslagen. + + + Inlezen van de stochastische ondergrondmodellen. + + + Er zijn geen ondergrondschematisaties gevonden in het stochastische ondergrondmodel '{0}'. + + + De som van de kansen van voorkomen in het stochastich ondergrondmodel '{0}' is niet gelijk aan 100%. + \ No newline at end of file Index: Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/StochasticSoilModelImporter.cs =================================================================== diff -u -r513400f1ec7b01dd0e4d3ce2681af3c1e8bf2e0e -rd06750a4979861471df64a5f49dca99c33d34ce6 --- Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/StochasticSoilModelImporter.cs (.../StochasticSoilModelImporter.cs) (revision 513400f1ec7b01dd0e4d3ce2681af3c1e8bf2e0e) +++ Ringtoets/Common/src/Ringtoets.Common.IO/SoilProfile/StochasticSoilModelImporter.cs (.../StochasticSoilModelImporter.cs) (revision d06750a4979861471df64a5f49dca99c33d34ce6) @@ -20,10 +20,17 @@ // All rights reserved. using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; using Core.Common.Base; using Core.Common.Base.IO; +using Core.Common.IO.Readers; using Ringtoets.Common.Data; +using Ringtoets.Common.Data.Exceptions; +using Ringtoets.Common.IO.Exceptions; using Ringtoets.Common.IO.FileImporters.MessageProviders; +using Ringtoets.Common.IO.Properties; using RingtoetsCommonDataResources = Ringtoets.Common.Data.Properties.Resources; namespace Ringtoets.Common.IO.SoilProfile @@ -37,9 +44,12 @@ : class, IMechanismStochasticSoilModel { private readonly IImporterMessageProvider messageProvider; - private readonly IStochasticSoilModelUpdateModelStrategy stochasticSoilModelupdateStrategy; - private readonly IStochasticSoilModelTransformer stochasticSoilModeltransformer; + private readonly IStochasticSoilModelUpdateModelStrategy updateStrategy; + private readonly IStochasticSoilModelTransformer transformer; + private readonly IStochasticSoilModelMechanismFilter filter; + private IEnumerable updatedInstances; + /// /// Creates a new instance of the class. /// @@ -67,8 +77,11 @@ } this.messageProvider = messageProvider; - stochasticSoilModelupdateStrategy = configuration.UpdateStrategy; - stochasticSoilModeltransformer = configuration.Transformer; + updateStrategy = configuration.UpdateStrategy; + transformer = configuration.Transformer; + filter = configuration.MechanismFilter; + + updatedInstances = Enumerable.Empty(); } protected override void LogImportCanceledMessage() @@ -79,7 +92,184 @@ protected override bool OnImport() { - return false; + ReadResult importStochasticSoilModelResult = ReadStochasticSoilModels(); + if (importStochasticSoilModelResult.CriticalErrorOccurred || Canceled) + { + return false; + } + + ReadResult transformedStochasticSoilModels; + + try + { + transformedStochasticSoilModels = GetTransformedStochasticSoilModels(importStochasticSoilModelResult.Items); + } + catch (ImportedDataTransformException e) + { + Log.ErrorFormat(Resources.StochasticSoilModelImporter_CriticalErrorMessage_0_File_Skipped, + e.Message); + return false; + } + + if (transformedStochasticSoilModels.CriticalErrorOccurred || Canceled) + { + return false; + } + + if (!transformedStochasticSoilModels.Items.Any()) + { + return true; + } + + NotifyProgress(messageProvider.GetAddDataToModelProgressText(), 1, 1); + + try + { + updatedInstances = updateStrategy.UpdateModelWithImportedData(transformedStochasticSoilModels.Items, FilePath); + } + catch (UpdateDataException e) + { + string message = string.Format(messageProvider.GetUpdateDataFailedLogMessageText( + RingtoetsCommonDataResources.StochasticSoilModelCollection_TypeDescriptor), + e.Message); + Log.Error(message, e); + return false; + } + return true; } + + private void HandleException(Exception e) + { + string message = string.Format(Resources.StochasticSoilModelImporter_CriticalErrorMessage_0_File_Skipped, + e.Message); + Log.Error(message, e); + } + + #region Read stochastic soil models + + private ReadResult ReadStochasticSoilModels() + { + NotifyProgress(Resources.StochasticSoilModelImporter_Reading_database, 1, 1); + try + { + using (var stochasticSoilModelReader = new StochasticSoilModelReader(FilePath)) + { + stochasticSoilModelReader.Validate(); + return GetStochasticSoilModelReadResult(stochasticSoilModelReader); + } + } + catch (CriticalFileReadException e) + { + HandleException(e); + } + return new ReadResult(true); + } + + private ReadResult GetStochasticSoilModelReadResult(StochasticSoilModelReader stochasticSoilModelReader) + { + int totalNumberOfSteps = stochasticSoilModelReader.StochasticSoilModelCount; + var currentStep = 1; + + var soilModels = new Collection(); + while (stochasticSoilModelReader.HasNext) + { + if (Canceled) + { + return new ReadResult(false); + } + try + { + NotifyProgress(Resources.StochasticSoilModelImporter_GetStochasticSoilModelReadResult_Reading_stochastic_soil_models_from_database, + currentStep++, + totalNumberOfSteps); + soilModels.Add(stochasticSoilModelReader.ReadStochasticSoilModel()); + } + catch (StochasticSoilModelException e) + { + HandleException(e); + return new ReadResult(true); + } + } + + return new ReadResult(false) + { + Items = soilModels + }; + } + + #endregion + + #region Validate stochastic soil models + + /// + /// Transforms the stochastic soil models into mechanism specific stochastic soil models. + /// + /// The stochastic soil models to transform. + /// Returns a collection of mechanism specific stochastic + /// soil models, or an empty when any of the + /// is not valid to be transformed. + /// Thrown when transforming a stochastic + /// soil model failed. + private ReadResult GetTransformedStochasticSoilModels(ICollection stochasticSoilModels) + { + var transformedStochasticSoilModels = new List(); + var stochasticSoilModelNumber = 1; + StochasticSoilModel[] importedModels = stochasticSoilModels.Where(ssm => filter.IsValidForFailureMechanism(ssm)) + .ToArray(); + + foreach (StochasticSoilModel stochasticSoilModel in importedModels) + { + NotifyProgress(Resources.Importer_ProgressText_Validating_imported_data, stochasticSoilModelNumber++, importedModels.Length); + if (Canceled) + { + return new ReadResult(false); + } + + if (!ValidateStochasticSoilModel(stochasticSoilModel)) + { + return new ReadResult(true); + } + + transformedStochasticSoilModels.Add(transformer.Transform(stochasticSoilModel)); + } + + return new ReadResult(false) + { + Items = transformedStochasticSoilModels + }; + } + + /// + /// Validate the definition of a . + /// + /// The to validate. + /// false when the stochastic soil model does not contain any stochastic soil profiles + /// or when a stochastic soil profile does not have a definition for a soil profile; true + /// otherwise. + private bool ValidateStochasticSoilModel(StochasticSoilModel stochasticSoilModel) + { + if (!stochasticSoilModel.StochasticSoilProfiles.Any()) + { + Log.ErrorFormat(Resources.StochasticSoilModelImporter_ValidateStochasticSoilModel_No_profiles_found_in_stochastic_soil_model_0, + stochasticSoilModel.Name); + return false; + } + if (!IsSumOfAllProbabilitiesEqualToOne(stochasticSoilModel)) + { + Log.ErrorFormat(Resources.StochasticSoilModelImporter_ValidateStochasticSoilModel_Sum_of_probabilities_of_stochastic_soil_model_0_is_not_correct, + stochasticSoilModel.Name); + return false; + } + return true; + } + + private static bool IsSumOfAllProbabilitiesEqualToOne(StochasticSoilModel stochasticSoilModel) + { + double sumOfAllScenarioProbabilities = stochasticSoilModel.StochasticSoilProfiles + .Sum(s => s.Probability); + return Math.Abs(sumOfAllScenarioProbabilities - 1.0) < 1e-6; + } + + #endregion } } \ No newline at end of file Index: Ringtoets/Common/test/Ringtoets.Common.IO.Test/SoilProfile/StochasticSoilModelImporterTest.cs =================================================================== diff -u -ra5f97617cc03e3535d369676ae09179c82947b17 -rd06750a4979861471df64a5f49dca99c33d34ce6 --- Ringtoets/Common/test/Ringtoets.Common.IO.Test/SoilProfile/StochasticSoilModelImporterTest.cs (.../StochasticSoilModelImporterTest.cs) (revision a5f97617cc03e3535d369676ae09179c82947b17) +++ Ringtoets/Common/test/Ringtoets.Common.IO.Test/SoilProfile/StochasticSoilModelImporterTest.cs (.../StochasticSoilModelImporterTest.cs) (revision d06750a4979861471df64a5f49dca99c33d34ce6) @@ -20,19 +20,26 @@ // All rights reserved. using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; using Core.Common.Base; using Core.Common.Base.IO; +using Core.Common.TestUtil; +using log4net.Core; using NUnit.Framework; using Rhino.Mocks; using Ringtoets.Common.Data; using Ringtoets.Common.IO.FileImporters.MessageProviders; using Ringtoets.Common.IO.SoilProfile; +using Ringtoets.Common.IO.SoilProfile.Schema; namespace Ringtoets.Common.IO.Test.SoilProfile { [TestFixture] public class StochasticSoilModelImporterTest { + private readonly string testDataPath = TestHelper.GetTestDataPath(TestDataPath.Ringtoets.Common.IO, "StochasticSoilModelReader"); private MockRepository mocks; private IStochasticSoilModelTransformer transformer; @@ -167,6 +174,202 @@ Assert.IsInstanceOf>>(importer); } + [Test] + public void Import_NonExistingFile_LogErrorReturnFalse() + { + // Setup + var messageProvider = mocks.Stub(); + var filter = mocks.Stub(); + var updateStrategy = mocks.Stub>(); + mocks.ReplayAll(); + + const string file = "nonexisting.soil"; + var collection = new TestStochasticSoilModelCollection(); + string validFilePath = Path.Combine(testDataPath, file); + var configuration = new StochasticSoilModelImporterConfiguration(transformer, filter, updateStrategy); + + var importer = new StochasticSoilModelImporter( + collection, + validFilePath, + messageProvider, + configuration); + + var progress = 0; + importer.SetProgressChanged((description, step, steps) => { progress++; }); + + var importResult = true; + + // Call + Action call = () => importResult = importer.Import(); + + // Assert + TestHelper.AssertLogMessagesWithLevelAndLoggedExceptions(call, messages => + { + Assert.AreEqual(1, messages.Count()); + Tuple expectedLog = messages.ElementAt(0); + + StringAssert.EndsWith($"{string.Empty} {Environment.NewLine}Het bestand wordt overgeslagen.", + expectedLog.Item1); + Assert.AreEqual(Level.Error, expectedLog.Item2); + Assert.IsInstanceOf(expectedLog.Item3); + }); + + Assert.AreEqual(1, progress); + Assert.IsFalse(importResult); + } + + [Test] + [TestCaseSource(typeof(InvalidPathHelper), nameof(InvalidPathHelper.InvalidPaths))] + public void Import_InvalidPath_LogErrorReturnFalse(string fileName) + { + // Setup + var messageProvider = mocks.Stub(); + var filter = mocks.Stub(); + var updateStrategy = mocks.Stub>(); + mocks.ReplayAll(); + + var collection = new TestStochasticSoilModelCollection(); + var configuration = new StochasticSoilModelImporterConfiguration(transformer, filter, updateStrategy); + + var importer = new StochasticSoilModelImporter( + collection, + fileName, + messageProvider, + configuration); + + var progress = 0; + importer.SetProgressChanged((description, step, steps) => { progress++; }); + + var importResult = true; + + // Call + Action call = () => importResult = importer.Import(); + + // Assert + TestHelper.AssertLogMessagesWithLevelAndLoggedExceptions(call, messages => + { + Assert.AreEqual(1, messages.Count()); + Tuple expectedLog = messages.ElementAt(0); + + StringAssert.EndsWith($"{string.Empty} {Environment.NewLine}Het bestand wordt overgeslagen.", + expectedLog.Item1); + Assert.AreEqual(Level.Error, expectedLog.Item2); + Assert.IsInstanceOf(expectedLog.Item3); + }); + + Assert.AreEqual(1, progress); + Assert.IsFalse(importResult); + } + + [Test] + [TestCase(FailureMechanismType.Piping, 3)] + [TestCase(FailureMechanismType.Stability, 3)] + [TestCase(FailureMechanismType.None, 0)] + public void Import_ImportingToValidTargetWithValidFile_ImportSoilModelToCollection( + FailureMechanismType failureMechanismType, + int nrOfFailureMechanismSpecificModelsInDatabase) + { + // Setup + string validFilePath = Path.Combine(testDataPath, "complete.soil"); + const int totalNrOfStochasticSoilModelInDatabase = 6; + + const string expectedAddDataText = "Adding Data"; + + var filter = mocks.StrictMock(); + filter.Expect(f => f.IsValidForFailureMechanism(null)) + .IgnoreArguments() + .Return(false) + .WhenCalled(invocation => { FilterFailureMechanismSpecificModel(invocation, failureMechanismType); }) + .Repeat + .Times(totalNrOfStochasticSoilModelInDatabase); + var messageProvider = mocks.StrictMock(); + var updateStrategy = mocks.StrictMock>(); + + if (nrOfFailureMechanismSpecificModelsInDatabase > 0) + { + messageProvider.Expect(mp => mp.GetAddDataToModelProgressText()) + .Return(expectedAddDataText); + + updateStrategy.Expect(u => u.UpdateModelWithImportedData(null, null)).IgnoreArguments().WhenCalled(invocation => + { + var soilModels = (IEnumerable) invocation.Arguments[0]; + var filePath = (string) invocation.Arguments[1]; + + Assert.AreEqual(nrOfFailureMechanismSpecificModelsInDatabase, soilModels.Count()); + Assert.AreEqual(validFilePath, filePath); + }); + } + + mocks.ReplayAll(); + + var progressChangeNotifications = new List(); + var importer = new StochasticSoilModelImporter( + new TestStochasticSoilModelCollection(), + validFilePath, + messageProvider, + new StochasticSoilModelImporterConfiguration( + transformer, + filter, + updateStrategy)); + + importer.SetProgressChanged((description, step, steps) => + progressChangeNotifications.Add(new ProgressNotification(description, step, steps))); + + // Call + bool importResult = importer.Import(); + + // Assert + Assert.IsTrue(importResult); + + var expectedProgressMessages = new List + { + new ProgressNotification("Inlezen van de D-Soil Model database.", 1, 1) + }; + for (var i = 1; i <= totalNrOfStochasticSoilModelInDatabase; i++) + { + expectedProgressMessages.Add(new ProgressNotification( + "Inlezen van de stochastische ondergrondmodellen.", i, totalNrOfStochasticSoilModelInDatabase)); + } + for (var i = 1; i <= nrOfFailureMechanismSpecificModelsInDatabase; i++) + { + expectedProgressMessages.Add(new ProgressNotification( + "Valideren van ingelezen data.", i, nrOfFailureMechanismSpecificModelsInDatabase)); + } + + if (nrOfFailureMechanismSpecificModelsInDatabase > 0) + { + expectedProgressMessages.Add(new ProgressNotification(expectedAddDataText, 1, 1)); + } + Assert.AreEqual(expectedProgressMessages.Count, progressChangeNotifications.Count); + for (var i = 0; i < expectedProgressMessages.Count; i++) + { + ProgressNotification notification = expectedProgressMessages[i]; + ProgressNotification actualNotification = progressChangeNotifications[i]; + Assert.AreEqual(notification.Text, actualNotification.Text); + Assert.AreEqual(notification.CurrentStep, actualNotification.CurrentStep); + Assert.AreEqual(notification.TotalSteps, actualNotification.TotalSteps); + } + } + + private static void FilterFailureMechanismSpecificModel(MethodInvocation invocation, FailureMechanismType failureMechanismType) + { + invocation.ReturnValue = failureMechanismType == ((StochasticSoilModel) invocation.Arguments[0]).FailureMechanismType; + } + + private class ProgressNotification + { + public ProgressNotification(string description, int currentStep, int totalSteps) + { + Text = description; + CurrentStep = currentStep; + TotalSteps = totalSteps; + } + + public string Text { get; } + public int CurrentStep { get; } + public int TotalSteps { get; } + } + private class TestStochasticSoilModelCollection : ObservableUniqueItemCollectionWithSourcePath { public TestStochasticSoilModelCollection() Index: Ringtoets/Common/test/Ringtoets.Common.IO.Test/SoilProfile/StochasticSoilModelReaderTest.cs =================================================================== diff -u -r133fb73ed33467075fa1317ab736902755ff6e4f -rd06750a4979861471df64a5f49dca99c33d34ce6 --- Ringtoets/Common/test/Ringtoets.Common.IO.Test/SoilProfile/StochasticSoilModelReaderTest.cs (.../StochasticSoilModelReaderTest.cs) (revision 133fb73ed33467075fa1317ab736902755ff6e4f) +++ Ringtoets/Common/test/Ringtoets.Common.IO.Test/SoilProfile/StochasticSoilModelReaderTest.cs (.../StochasticSoilModelReaderTest.cs) (revision d06750a4979861471df64a5f49dca99c33d34ce6) @@ -1,4 +1,5 @@ -// Copyright (C) Stichting Deltares 2017. All rights reserved. + +// Copyright (C) Stichting Deltares 2017. All rights reserved. // // This file is part of Ringtoets. //