// Copyright (C) Stichting Deltares 2017. All rights reserved. // // This file is part of Ringtoets. // // Ringtoets 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; using System.Collections.Generic; using System.Linq; using Core.Common.Base.Data; using Ringtoets.Common.Service; using Ringtoets.Common.Service.ValidationRules; using Ringtoets.MacroStabilityInwards.Data; using Ringtoets.MacroStabilityInwards.KernelWrapper; using Ringtoets.MacroStabilityInwards.KernelWrapper.SubCalculator; using Ringtoets.MacroStabilityInwards.Primitives; using Ringtoets.MacroStabilityInwards.Service.Properties; using RingtoetsCommonServiceResources = Ringtoets.Common.Service.Properties.Resources; using RingtoetsCommonFormsResources = Ringtoets.Common.Forms.Properties.Resources; namespace Ringtoets.MacroStabilityInwards.Service { /// /// This class is responsible for invoking operations on the . Error and status information is /// logged during the execution of the operation. /// public static class MacroStabilityInwardsCalculationService { /// /// Performs validation over the values on the given . Error and status information is logged during /// the execution of the operation. /// /// The for which to validate the values. /// False if contains validation errors; True otherwise. /// Thrown when is null. public static bool Validate(MacroStabilityInwardsCalculation calculation) { if (calculation == null) { throw new ArgumentNullException(nameof(calculation)); } CalculationServiceHelper.LogValidationBeginTime(calculation.Name); CalculationServiceHelper.LogMessagesAsWarning(GetInputWarnings(calculation.InputParameters).ToArray()); string[] inputValidationResults = ValidateInput(calculation.InputParameters).ToArray(); if (inputValidationResults.Length > 0) { CalculationServiceHelper.LogMessagesAsError(RingtoetsCommonServiceResources.Error_in_validation_0, inputValidationResults); CalculationServiceHelper.LogValidationEndTime(calculation.Name); return false; } List validationResults = new MacroStabilityInwardsCalculator(CreateInputFromData(calculation.InputParameters), MacroStabilityInwardsSubCalculatorFactory.Instance).Validate(); CalculationServiceHelper.LogMessagesAsError(RingtoetsCommonServiceResources.Error_in_validation_0, validationResults.ToArray()); CalculationServiceHelper.LogValidationEndTime(calculation.Name); return validationResults.Count == 0; } /// /// Performs a macro stability inwards calculation based on the supplied and sets /// based on the result if the calculation was successful. Error and status information is logged during /// the execution of the operation. /// /// The to base the input for the calculation upon. /// Thrown when is null. /// Consider calling first to see if calculation is possible. public static void Calculate(MacroStabilityInwardsCalculation calculation) { if (calculation == null) { throw new ArgumentNullException(nameof(calculation)); } CalculationServiceHelper.LogCalculationBeginTime(calculation.Name); try { MacroStabilityInwardsCalculatorResult macroStabilityInwardsResult = new MacroStabilityInwardsCalculator(CreateInputFromData(calculation.InputParameters), MacroStabilityInwardsSubCalculatorFactory.Instance).Calculate(); calculation.Output = new MacroStabilityInwardsOutput(new MacroStabilityInwardsOutput.ConstructionProperties { UpliftZValue = macroStabilityInwardsResult.UpliftZValue, UpliftFactorOfSafety = macroStabilityInwardsResult.UpliftFactorOfSafety, HeaveZValue = macroStabilityInwardsResult.HeaveZValue, HeaveFactorOfSafety = macroStabilityInwardsResult.HeaveFactorOfSafety, SellmeijerZValue = macroStabilityInwardsResult.SellmeijerZValue, SellmeijerFactorOfSafety = macroStabilityInwardsResult.SellmeijerFactorOfSafety, UpliftEffectiveStress = macroStabilityInwardsResult.UpliftEffectiveStress, HeaveGradient = macroStabilityInwardsResult.HeaveGradient, SellmeijerCreepCoefficient = macroStabilityInwardsResult.SellmeijerCreepCoefficient, SellmeijerCriticalFall = macroStabilityInwardsResult.SellmeijerCriticalFall, SellmeijerReducedFall = macroStabilityInwardsResult.SellmeijerReducedFall }); } catch (MacroStabilityInwardsCalculatorException e) { CalculationServiceHelper.LogMessagesAsError(Resources.Error_in_piping_calculation_0, e.Message); } finally { CalculationServiceHelper.LogCalculationEndTime(calculation.Name); } } private static List ValidateInput(MacroStabilityInwardsInput inputParameters) { var validationResults = new List(); validationResults.AddRange(ValidateHydraulics(inputParameters)); IEnumerable coreValidationError = ValidateCoreSurfaceLineAndSoilProfileProperties(inputParameters); validationResults.AddRange(coreValidationError); if (double.IsNaN(inputParameters.EntryPointL)) { validationResults.Add(Resources.PipingCalculationService_ValidateInput_No_value_for_EntryPointL); } if (!coreValidationError.Any()) { validationResults.AddRange(ValidateSoilLayers(inputParameters)); } return validationResults; } private static IEnumerable ValidateHydraulics(MacroStabilityInwardsInput inputParameters) { var validationResults = new List(); if (!inputParameters.UseAssessmentLevelManualInput && inputParameters.HydraulicBoundaryLocation == null) { validationResults.Add(Resources.PipingCalculationService_ValidateInput_No_HydraulicBoundaryLocation_selected); } else { validationResults.AddRange(ValidateAssessmentLevel(inputParameters)); if (double.IsNaN(inputParameters.PiezometricHeadExit) || double.IsInfinity(inputParameters.PiezometricHeadExit)) { validationResults.Add(Resources.PipingCalculationService_ValidateInput_Cannot_determine_PiezometricHeadExit); } } return validationResults; } private static IEnumerable ValidateAssessmentLevel(MacroStabilityInwardsInput inputParameters) { var validationResult = new List(); if (inputParameters.UseAssessmentLevelManualInput) { validationResult.AddRange(new NumericInputRule(inputParameters.AssessmentLevel, ParameterNameExtractor.GetFromDisplayName(RingtoetsCommonFormsResources.AssessmentLevel_DisplayName)).Validate()); } else { if (double.IsNaN(inputParameters.AssessmentLevel)) { validationResult.Add(Resources.PipingCalculationService_ValidateInput_Cannot_determine_AssessmentLevel); } } return validationResult; } private static IEnumerable ValidateCoreSurfaceLineAndSoilProfileProperties(MacroStabilityInwardsInput inputParameters) { var validationResults = new List(); if (inputParameters.SurfaceLine == null) { validationResults.Add(Resources.PipingCalculationService_ValidateInput_No_SurfaceLine_selected); } if (inputParameters.StochasticSoilProfile == null) { validationResults.Add(Resources.PipingCalculationService_ValidateInput_No_StochasticSoilProfile_selected); } if (double.IsNaN(inputParameters.ExitPointL)) { validationResults.Add(Resources.PipingCalculationService_ValidateInput_No_value_for_ExitPointL); } return validationResults; } private static IEnumerable ValidateSoilLayers(MacroStabilityInwardsInput inputParameters) { var validationResults = new List(); if (double.IsNaN(inputParameters.ThicknessAquiferLayer.Mean)) { validationResults.Add(Resources.PipingCalculationService_ValidateInput_Cannot_determine_thickness_aquifer_layer); } MacroStabilityInwardsSoilProfile macroStabilityInwardsSoilProfile = inputParameters.StochasticSoilProfile.SoilProfile; double surfaceLevel = inputParameters.SurfaceLine.GetZAtL(inputParameters.ExitPointL); validationResults.AddRange(ValidateAquiferLayers(inputParameters, macroStabilityInwardsSoilProfile, surfaceLevel)); validationResults.AddRange(ValidateCoverageLayers(inputParameters, macroStabilityInwardsSoilProfile, surfaceLevel)); return validationResults; } private static IEnumerable ValidateAquiferLayers(MacroStabilityInwardsInput inputParameters, MacroStabilityInwardsSoilProfile macroStabilityInwardsSoilProfile, double surfaceLevel) { var validationResult = new List(); bool hasConsecutiveAquiferLayers = macroStabilityInwardsSoilProfile.GetConsecutiveAquiferLayersBelowLevel(surfaceLevel).Any(); if (!hasConsecutiveAquiferLayers) { validationResult.Add(Resources.PipingCalculationService_ValidateInput_No_aquifer_layer_at_ExitPointL_under_SurfaceLine); } else { if (double.IsNaN(MacroStabilityInwardsSemiProbabilisticDesignValueFactory.GetDarcyPermeability(inputParameters).GetDesignValue())) { validationResult.Add(Resources.PipingCalculationService_ValidateInput_Cannot_derive_DarcyPermeability); } if (double.IsNaN(MacroStabilityInwardsSemiProbabilisticDesignValueFactory.GetDiameter70(inputParameters).GetDesignValue())) { validationResult.Add(Resources.PipingCalculationService_ValidateInput_Cannot_derive_Diameter70); } } return validationResult; } private static IEnumerable ValidateCoverageLayers(MacroStabilityInwardsInput inputParameters, MacroStabilityInwardsSoilProfile macroStabilityInwardsSoilProfile, double surfaceLevel) { var validationResult = new List(); bool hasConsecutiveCoverageLayers = macroStabilityInwardsSoilProfile.GetConsecutiveCoverageLayersBelowLevel(surfaceLevel).Any(); if (hasConsecutiveCoverageLayers) { RoundedDouble saturatedVolumicWeightOfCoverageLayer = MacroStabilityInwardsSemiProbabilisticDesignValueFactory.GetSaturatedVolumicWeightOfCoverageLayer(inputParameters).GetDesignValue(); if (double.IsNaN(saturatedVolumicWeightOfCoverageLayer)) { validationResult.Add(Resources.PipingCalculationService_ValidateInput_Cannot_derive_SaturatedVolumicWeight); } else if (saturatedVolumicWeightOfCoverageLayer < inputParameters.WaterVolumetricWeight) { validationResult.Add(Resources.PipingCalculationService_ValidateInput_SaturatedVolumicWeightCoverageLayer_must_be_larger_than_WaterVolumetricWeight); } } return validationResult; } private static List GetInputWarnings(MacroStabilityInwardsInput inputParameters) { var warnings = new List(); if (IsSurfaceLineProfileDefinitionComplete(inputParameters)) { double surfaceLineLevel = inputParameters.SurfaceLine.GetZAtL(inputParameters.ExitPointL); warnings.AddRange(GetMultipleAquiferLayersWarning(inputParameters, surfaceLineLevel)); warnings.AddRange(GetMultipleCoverageLayersWarning(inputParameters, surfaceLineLevel)); warnings.AddRange(GetDiameter70Warnings(inputParameters)); warnings.AddRange(GetThicknessCoverageLayerWarnings(inputParameters)); } return warnings; } private static IEnumerable GetThicknessCoverageLayerWarnings(MacroStabilityInwardsInput inputParameters) { var warnings = new List(); MacroStabilityInwardsSoilProfile macroStabilityInwardsSoilProfile = inputParameters.StochasticSoilProfile.SoilProfile; double surfaceLevel = inputParameters.SurfaceLine.GetZAtL(inputParameters.ExitPointL); bool hasConsecutiveCoverageLayers = macroStabilityInwardsSoilProfile.GetConsecutiveCoverageLayersBelowLevel(surfaceLevel).Any(); if (!hasConsecutiveCoverageLayers) { warnings.Add(Resources.PipingCalculationService_ValidateInput_No_coverage_layer_at_ExitPointL_under_SurfaceLine); } if (double.IsNaN(inputParameters.ThicknessCoverageLayer.Mean)) { warnings.Add(Resources.PipingCalculationService_ValidateInput_Cannot_determine_thickness_coverage_layer); } return warnings; } private static IEnumerable GetDiameter70Warnings(MacroStabilityInwardsInput inputParameters) { var warnings = new List(); RoundedDouble diameter70Value = MacroStabilityInwardsSemiProbabilisticDesignValueFactory.GetDiameter70(inputParameters).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(MacroStabilityInwardsInput inputParameters, double surfaceLineLevel) { var warnings = new List(); bool hasMoreThanOneCoverageLayer = inputParameters.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(MacroStabilityInwardsInput inputParameters, double surfaceLineLevel) { var warnings = new List(); bool hasMoreThanOneAquiferLayer = inputParameters.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(MacroStabilityInwardsInput surfaceLineMissing) { return surfaceLineMissing.SurfaceLine != null && surfaceLineMissing.StochasticSoilProfile != null && !double.IsNaN(surfaceLineMissing.ExitPointL); } private static MacroStabilityInwardsCalculatorInput CreateInputFromData(MacroStabilityInwardsInput inputParameters) { return new MacroStabilityInwardsCalculatorInput( new MacroStabilityInwardsCalculatorInput.ConstructionProperties { WaterVolumetricWeight = inputParameters.WaterVolumetricWeight, SaturatedVolumicWeightOfCoverageLayer = MacroStabilityInwardsSemiProbabilisticDesignValueFactory.GetSaturatedVolumicWeightOfCoverageLayer(inputParameters).GetDesignValue(), UpliftModelFactor = inputParameters.UpliftModelFactor, AssessmentLevel = inputParameters.AssessmentLevel, PiezometricHeadExit = inputParameters.PiezometricHeadExit, DampingFactorExit = MacroStabilityInwardsSemiProbabilisticDesignValueFactory.GetDampingFactorExit(inputParameters).GetDesignValue(), PhreaticLevelExit = MacroStabilityInwardsSemiProbabilisticDesignValueFactory.GetPhreaticLevelExit(inputParameters).GetDesignValue(), CriticalHeaveGradient = inputParameters.CriticalHeaveGradient, ThicknessCoverageLayer = MacroStabilityInwardsSemiProbabilisticDesignValueFactory.GetThicknessCoverageLayer(inputParameters).GetDesignValue(), EffectiveThicknessCoverageLayer = MacroStabilityInwardsSemiProbabilisticDesignValueFactory.GetEffectiveThicknessCoverageLayer(inputParameters).GetDesignValue(), SellmeijerModelFactor = inputParameters.SellmeijerModelFactor, SellmeijerReductionFactor = inputParameters.SellmeijerReductionFactor, SeepageLength = MacroStabilityInwardsSemiProbabilisticDesignValueFactory.GetSeepageLength(inputParameters).GetDesignValue(), SandParticlesVolumicWeight = inputParameters.SandParticlesVolumicWeight, WhitesDragCoefficient = inputParameters.WhitesDragCoefficient, Diameter70 = MacroStabilityInwardsSemiProbabilisticDesignValueFactory.GetDiameter70(inputParameters).GetDesignValue(), DarcyPermeability = MacroStabilityInwardsSemiProbabilisticDesignValueFactory.GetDarcyPermeability(inputParameters).GetDesignValue(), WaterKinematicViscosity = inputParameters.WaterKinematicViscosity, Gravity = inputParameters.Gravity, ThicknessAquiferLayer = MacroStabilityInwardsSemiProbabilisticDesignValueFactory.GetThicknessAquiferLayer(inputParameters).GetDesignValue(), MeanDiameter70 = inputParameters.MeanDiameter70, BeddingAngle = inputParameters.BeddingAngle, ExitPointXCoordinate = inputParameters.ExitPointL, SurfaceLine = inputParameters.SurfaceLine, SoilProfile = inputParameters.StochasticSoilProfile?.SoilProfile }); } } }