Index: Riskeer/Piping/src/Riskeer.Piping.Service/PipingCalculationValidationHelper.cs =================================================================== diff -u -r8f93b96f3300a006271575369d424b8628dbc751 -r56198a842a4c892afc1ea3166d310c3daa4d271d --- Riskeer/Piping/src/Riskeer.Piping.Service/PipingCalculationValidationHelper.cs (.../PipingCalculationValidationHelper.cs) (revision 8f93b96f3300a006271575369d424b8628dbc751) +++ Riskeer/Piping/src/Riskeer.Piping.Service/PipingCalculationValidationHelper.cs (.../PipingCalculationValidationHelper.cs) (revision 56198a842a4c892afc1ea3166d310c3daa4d271d) @@ -35,8 +35,36 @@ public static class PipingCalculationValidationHelper { /// - /// Validates the given . + /// Gets validation warnings for the given . /// + /// The to get the warning for. + /// An of validation warnings. + /// Thrown when is null. + public static IEnumerable GetValidationWarnings(PipingInput input) + { + if (input == null) + { + throw new ArgumentNullException(nameof(input)); + } + + var warnings = new List(); + + if (IsSurfaceLineProfileDefinitionComplete(input)) + { + double surfaceLineLevel = input.SurfaceLine.GetZAtL(input.ExitPointL); + + warnings.AddRange(GetMultipleAquiferLayersWarning(input, surfaceLineLevel)); + warnings.AddRange(GetMultipleCoverageLayersWarning(input, surfaceLineLevel)); + warnings.AddRange(GetDiameter70Warnings(input)); + warnings.AddRange(GetThicknessCoverageLayerWarnings(input)); + } + + return warnings; + } + + /// + /// Gets validation errors for the given . + /// /// The to validate. /// The used /// in the validation. @@ -72,6 +100,74 @@ return validationResults; } + private static IEnumerable GetThicknessCoverageLayerWarnings(PipingInput input) + { + var warnings = new List(); + + PipingSoilProfile pipingSoilProfile = input.StochasticSoilProfile.SoilProfile; + double surfaceLevel = input.SurfaceLine.GetZAtL(input.ExitPointL); + + bool hasConsecutiveCoverageLayers = pipingSoilProfile.GetConsecutiveCoverageLayersBelowLevel(surfaceLevel).Any(); + if (!hasConsecutiveCoverageLayers) + { + warnings.Add(Resources.PipingCalculationService_ValidateInput_No_coverage_layer_at_ExitPointL_under_SurfaceLine); + } + + if (double.IsNaN(DerivedPipingInput.GetThicknessCoverageLayer(input).Mean)) + { + warnings.Add(Resources.PipingCalculationService_ValidateInput_Cannot_determine_thickness_coverage_layer); + } + + return warnings; + } + + private static IEnumerable GetDiameter70Warnings(PipingInput input) + { + var warnings = new List(); + + RoundedDouble diameter70Value = PipingDesignVariableFactory.GetDiameter70(input).GetDesignValue(); + + if (!double.IsNaN(diameter70Value) && (diameter70Value < 6.3e-5 || diameter70Value > 0.5e-3)) + { + warnings.Add(string.Format(Resources.PipingCalculationService_GetInputWarnings_Specified_DiameterD70_value_0_not_in_valid_range_of_model, diameter70Value)); + } + + return warnings; + } + + private static IEnumerable GetMultipleCoverageLayersWarning(PipingInput input, double surfaceLineLevel) + { + var warnings = new List(); + + bool hasMoreThanOneCoverageLayer = input.StochasticSoilProfile.SoilProfile.GetConsecutiveCoverageLayersBelowLevel(surfaceLineLevel).Count() > 1; + if (hasMoreThanOneCoverageLayer) + { + warnings.Add(Resources.PipingCalculationService_GetInputWarnings_Multiple_coverage_layers_Attempt_to_determine_value_from_combination); + } + + return warnings; + } + + private static IEnumerable GetMultipleAquiferLayersWarning(PipingInput input, double surfaceLineLevel) + { + var warnings = new List(); + + bool hasMoreThanOneAquiferLayer = input.StochasticSoilProfile.SoilProfile.GetConsecutiveAquiferLayersBelowLevel(surfaceLineLevel).Count() > 1; + if (hasMoreThanOneAquiferLayer) + { + warnings.Add(Resources.PipingCalculationService_GetInputWarnings_Multiple_aquifer_layers_Attempt_to_determine_values_for_DiameterD70_and_DarcyPermeability_from_top_layer); + } + + return warnings; + } + + private static bool IsSurfaceLineProfileDefinitionComplete(PipingInput input) + { + return input.SurfaceLine != null && + input.StochasticSoilProfile != null && + !double.IsNaN(input.ExitPointL); + } + private static IEnumerable ValidateCoreSurfaceLineAndSoilProfileProperties(PipingInput input) { var validationResults = new List(); Index: Riskeer/Piping/src/Riskeer.Piping.Service/SemiProbabilistic/SemiProbabilisticPipingCalculationService.cs =================================================================== diff -u -r8f93b96f3300a006271575369d424b8628dbc751 -r56198a842a4c892afc1ea3166d310c3daa4d271d --- Riskeer/Piping/src/Riskeer.Piping.Service/SemiProbabilistic/SemiProbabilisticPipingCalculationService.cs (.../SemiProbabilisticPipingCalculationService.cs) (revision 8f93b96f3300a006271575369d424b8628dbc751) +++ Riskeer/Piping/src/Riskeer.Piping.Service/SemiProbabilistic/SemiProbabilisticPipingCalculationService.cs (.../SemiProbabilisticPipingCalculationService.cs) (revision 56198a842a4c892afc1ea3166d310c3daa4d271d) @@ -1,4 +1,4 @@ -// Copyright (C) Stichting Deltares 2019. All rights reserved. +// Copyright (C) Stichting Deltares 2019. All rights reserved. // // This file is part of Riskeer. // @@ -67,7 +67,7 @@ CalculationServiceHelper.LogValidationBegin(); - CalculationServiceHelper.LogMessagesAsWarning(GetInputWarnings(calculation.InputParameters).ToArray()); + CalculationServiceHelper.LogMessagesAsWarning(PipingCalculationValidationHelper.GetValidationWarnings(calculation.InputParameters).ToArray()); string[] inputValidationResults = ValidateInput(calculation.InputParameters, generalInput, normativeAssessmentLevel).ToArray(); @@ -198,91 +198,6 @@ return validationResult; } - private static List GetInputWarnings(PipingInput input) - { - var warnings = new List(); - - if (IsSurfaceLineProfileDefinitionComplete(input)) - { - double surfaceLineLevel = input.SurfaceLine.GetZAtL(input.ExitPointL); - - warnings.AddRange(GetMultipleAquiferLayersWarning(input, surfaceLineLevel)); - warnings.AddRange(GetMultipleCoverageLayersWarning(input, surfaceLineLevel)); - warnings.AddRange(GetDiameter70Warnings(input)); - warnings.AddRange(GetThicknessCoverageLayerWarnings(input)); - } - - return warnings; - } - - private static IEnumerable GetThicknessCoverageLayerWarnings(PipingInput input) - { - var warnings = new List(); - - PipingSoilProfile pipingSoilProfile = input.StochasticSoilProfile.SoilProfile; - double surfaceLevel = input.SurfaceLine.GetZAtL(input.ExitPointL); - - bool hasConsecutiveCoverageLayers = pipingSoilProfile.GetConsecutiveCoverageLayersBelowLevel(surfaceLevel).Any(); - if (!hasConsecutiveCoverageLayers) - { - warnings.Add(Resources.PipingCalculationService_ValidateInput_No_coverage_layer_at_ExitPointL_under_SurfaceLine); - } - - if (double.IsNaN(DerivedPipingInput.GetThicknessCoverageLayer(input).Mean)) - { - warnings.Add(Resources.PipingCalculationService_ValidateInput_Cannot_determine_thickness_coverage_layer); - } - - return warnings; - } - - private static IEnumerable GetDiameter70Warnings(PipingInput input) - { - var warnings = new List(); - - RoundedDouble diameter70Value = PipingDesignVariableFactory.GetDiameter70(input).GetDesignValue(); - - if (!double.IsNaN(diameter70Value) && (diameter70Value < 6.3e-5 || diameter70Value > 0.5e-3)) - { - warnings.Add(string.Format(Resources.PipingCalculationService_GetInputWarnings_Specified_DiameterD70_value_0_not_in_valid_range_of_model, diameter70Value)); - } - - return warnings; - } - - private static IEnumerable GetMultipleCoverageLayersWarning(PipingInput input, double surfaceLineLevel) - { - var warnings = new List(); - - bool hasMoreThanOneCoverageLayer = input.StochasticSoilProfile.SoilProfile.GetConsecutiveCoverageLayersBelowLevel(surfaceLineLevel).Count() > 1; - if (hasMoreThanOneCoverageLayer) - { - warnings.Add(Resources.PipingCalculationService_GetInputWarnings_Multiple_coverage_layers_Attempt_to_determine_value_from_combination); - } - - return warnings; - } - - private static IEnumerable GetMultipleAquiferLayersWarning(PipingInput input, double surfaceLineLevel) - { - var warnings = new List(); - - bool hasMoreThanOneAquiferLayer = input.StochasticSoilProfile.SoilProfile.GetConsecutiveAquiferLayersBelowLevel(surfaceLineLevel).Count() > 1; - if (hasMoreThanOneAquiferLayer) - { - warnings.Add(Resources.PipingCalculationService_GetInputWarnings_Multiple_aquifer_layers_Attempt_to_determine_values_for_DiameterD70_and_DarcyPermeability_from_top_layer); - } - - return warnings; - } - - private static bool IsSurfaceLineProfileDefinitionComplete(PipingInput input) - { - return input.SurfaceLine != null && - input.StochasticSoilProfile != null && - !double.IsNaN(input.ExitPointL); - } - private static PipingCalculatorInput CreateInputFromData(SemiProbabilisticPipingInput input, GeneralPipingInput generalPipingInput, RoundedDouble normativeAssessmentLevel) Index: Riskeer/Piping/test/Riskeer.Piping.Service.Test/PipingCalculationValidationHelperTest.cs =================================================================== diff -u -r8f93b96f3300a006271575369d424b8628dbc751 -r56198a842a4c892afc1ea3166d310c3daa4d271d --- Riskeer/Piping/test/Riskeer.Piping.Service.Test/PipingCalculationValidationHelperTest.cs (.../PipingCalculationValidationHelperTest.cs) (revision 8f93b96f3300a006271575369d424b8628dbc751) +++ Riskeer/Piping/test/Riskeer.Piping.Service.Test/PipingCalculationValidationHelperTest.cs (.../PipingCalculationValidationHelperTest.cs) (revision 56198a842a4c892afc1ea3166d310c3daa4d271d) @@ -49,6 +49,247 @@ } [Test] + public void GetValidationWarnings_InputNull_ThrowsArgumentNullException() + { + // Call + void Call() => PipingCalculationValidationHelper.GetValidationWarnings(null); + + // Assert + var exception = Assert.Throws(Call); + Assert.AreEqual("input", exception.ParamName); + } + + [Test] + public void GetValidationWarnings_WithoutSurfaceLine_ReturnsNoMessages() + { + // Setup + calculation.InputParameters.SurfaceLine = null; + + // Call + IEnumerable messages = PipingCalculationValidationHelper.GetValidationWarnings(calculation.InputParameters); + + // Assert + CollectionAssert.IsEmpty(messages); + } + + [Test] + public void GetValidationWarnings_WithoutStochasticSoilProfile_ReturnsNoMessages() + { + // Setup + calculation.InputParameters.StochasticSoilProfile = null; + + // Call + IEnumerable messages = PipingCalculationValidationHelper.GetValidationWarnings(calculation.InputParameters); + + // Assert + CollectionAssert.IsEmpty(messages); + } + + [Test] + public void GetValidationWarnings_WithoutExitPointL_ReturnsNoMessages() + { + // Setup + calculation.InputParameters.ExitPointL = RoundedDouble.NaN; + + // Call + IEnumerable messages = PipingCalculationValidationHelper.GetValidationWarnings(calculation.InputParameters); + + // Assert + CollectionAssert.IsEmpty(messages); + } + + [Test] + public void GetValidationWarnings_WithoutAquitardLayer_LogsWarningsAndReturnsTrue() + { + // Setup + var aquiferLayer = new PipingSoilLayer(10.56) + { + IsAquifer = true, + DiameterD70 = new VariationCoefficientLogNormalDistribution + { + Mean = (RoundedDouble) 1e-4, + CoefficientOfVariation = (RoundedDouble) 0 + }, + Permeability = new VariationCoefficientLogNormalDistribution + { + Mean = (RoundedDouble) 1, + CoefficientOfVariation = (RoundedDouble) 0.5 + } + }; + var profile = new PipingSoilProfile(string.Empty, 0.0, + new[] + { + aquiferLayer + }, + SoilProfileType.SoilProfile1D); + + calculation.InputParameters.StochasticSoilProfile = new PipingStochasticSoilProfile(0.0, profile); + + // Call + IEnumerable messages = PipingCalculationValidationHelper.GetValidationWarnings(calculation.InputParameters); + + // Assert + Assert.AreEqual(2, messages.Count()); + Assert.AreEqual("Geen deklaag gevonden voor de ondergrondschematisatie onder de profielschematisatie bij het uittredepunt.", messages.ElementAt(0)); + Assert.AreEqual("Kan de totale deklaagdikte bij het uittredepunt niet afleiden op basis van de invoer.", messages.ElementAt(1)); + } + + [Test] + public void GetValidationWarnings_WithoutCoverageLayer_LogsWarningsAndReturnsTrue() + { + // Setup + var coverageLayerAboveSurfaceLine = new PipingSoilLayer(13.0) + { + IsAquifer = false + }; + var bottomAquiferLayer = new PipingSoilLayer(11.0) + { + IsAquifer = true, + DiameterD70 = new VariationCoefficientLogNormalDistribution + { + Mean = (RoundedDouble) 1e-4, + CoefficientOfVariation = (RoundedDouble) 0 + }, + Permeability = new VariationCoefficientLogNormalDistribution + { + Mean = (RoundedDouble) 1, + CoefficientOfVariation = (RoundedDouble) 0.5 + } + }; + var profile = new PipingSoilProfile(string.Empty, 0.0, + new[] + { + coverageLayerAboveSurfaceLine, + bottomAquiferLayer + }, + SoilProfileType.SoilProfile1D); + + calculation.InputParameters.StochasticSoilProfile = new PipingStochasticSoilProfile(0.0, profile); + + // Call + IEnumerable messages = PipingCalculationValidationHelper.GetValidationWarnings(calculation.InputParameters); + + // Assert + Assert.AreEqual(2, messages.Count()); + Assert.AreEqual("Geen deklaag gevonden voor de ondergrondschematisatie onder de profielschematisatie bij het uittredepunt.", messages.ElementAt(0)); + Assert.AreEqual("Kan de totale deklaagdikte bij het uittredepunt niet afleiden op basis van de invoer.", messages.ElementAt(1)); + } + + [Test] + public void GetValidationWarnings_MultipleCoverageLayer_LogsWarningAndReturnsTrue() + { + // Setup + var random = new Random(21); + const double belowPhreaticLevelDeviation = 0.5; + const int belowPhreaticLevelShift = 1; + const double belowPhreaticLevelMeanBase = 15.0; + + var topCoverageLayer = new PipingSoilLayer(testSurfaceLineTopLevel) + { + IsAquifer = false, + BelowPhreaticLevel = new LogNormalDistribution + { + Mean = (RoundedDouble) (belowPhreaticLevelMeanBase + belowPhreaticLevelShift + random.NextDouble()), + StandardDeviation = (RoundedDouble) belowPhreaticLevelDeviation, + Shift = (RoundedDouble) belowPhreaticLevelShift + } + }; + var middleCoverageLayer = new PipingSoilLayer(8.5) + { + IsAquifer = false, + BelowPhreaticLevel = new LogNormalDistribution + { + Mean = (RoundedDouble) (belowPhreaticLevelMeanBase + belowPhreaticLevelShift + random.NextDouble()), + StandardDeviation = (RoundedDouble) belowPhreaticLevelDeviation, + Shift = (RoundedDouble) belowPhreaticLevelShift + } + }; + var bottomAquiferLayer = new PipingSoilLayer(5.0) + { + IsAquifer = true, + Permeability = new VariationCoefficientLogNormalDistribution + { + Mean = (RoundedDouble) 1, + CoefficientOfVariation = (RoundedDouble) 0.5 + }, + DiameterD70 = new VariationCoefficientLogNormalDistribution + { + Mean = (RoundedDouble) 1e-4, + CoefficientOfVariation = (RoundedDouble) 0 + } + }; + + var profile = new PipingSoilProfile(string.Empty, 0.0, + new[] + { + topCoverageLayer, + middleCoverageLayer, + bottomAquiferLayer + }, + SoilProfileType.SoilProfile1D); + + calculation.InputParameters.StochasticSoilProfile = new PipingStochasticSoilProfile(0.0, profile); + + // Call + IEnumerable messages = PipingCalculationValidationHelper.GetValidationWarnings(calculation.InputParameters); + + // Assert + Assert.AreEqual(1, messages.Count()); + const string expectedMessage = "Meerdere aaneengesloten deklagen gevonden. De grondeigenschappen worden bepaald door het nemen van een gewogen gemiddelde, mits de standaardafwijkingen en verschuivingen voor alle lagen gelijk zijn."; + Assert.AreEqual(expectedMessage, messages.ElementAt(0)); + } + + [Test] + [TestCase(6.2e-5)] + [TestCase(5.1e-3)] + public void GetValidationWarnings_InvalidDiameterD70Value_LogsWarningAndReturnsTrue(double diameter70Value) + { + // Setup + var random = new Random(21); + var coverageLayerInvalidD70 = new PipingSoilLayer(5.0) + { + IsAquifer = true, + Permeability = new VariationCoefficientLogNormalDistribution + { + Mean = (RoundedDouble) 1, + CoefficientOfVariation = (RoundedDouble) 0.5 + }, + DiameterD70 = new VariationCoefficientLogNormalDistribution + { + Mean = (RoundedDouble) diameter70Value, + CoefficientOfVariation = (RoundedDouble) 0 + } + }; + var validLayer = new PipingSoilLayer(testSurfaceLineTopLevel) + { + IsAquifer = false, + BelowPhreaticLevel = new LogNormalDistribution + { + Mean = random.NextRoundedDouble(15.0, 999.999), + StandardDeviation = random.NextRoundedDouble(1e-6, 5.0), + Shift = random.NextRoundedDouble(1e-6, 10) + } + }; + var profile = new PipingSoilProfile(string.Empty, 0.0, + new[] + { + validLayer, + coverageLayerInvalidD70 + }, + SoilProfileType.SoilProfile1D); + + calculation.InputParameters.StochasticSoilProfile = new PipingStochasticSoilProfile(0.0, profile); + + // Call + IEnumerable messages = PipingCalculationValidationHelper.GetValidationWarnings(calculation.InputParameters); + + // Assert + Assert.AreEqual(1, messages.Count()); + var expectedMessage = $"Rekenwaarde voor d70 ({new RoundedDouble(6, diameter70Value)} m) ligt buiten het geldigheidsbereik van dit model. Geldige waarden liggen tussen 0.000063 m en 0.0005 m."; + Assert.AreEqual(expectedMessage, messages.ElementAt(0)); + } + + [Test] public void GetValidationErrors_InputNull_ThrowsArgumentNullException() { // Call