Index: Ringtoets/Piping/src/Ringtoets.Piping.Data/DerivedPipingInput.cs =================================================================== diff -u -r35db69dfe64b7e7deeaf9ef85d4df42ff6009b11 -r2363244674e6b7b97bead9a6855806420d368d80 --- Ringtoets/Piping/src/Ringtoets.Piping.Data/DerivedPipingInput.cs (.../DerivedPipingInput.cs) (revision 35db69dfe64b7e7deeaf9ef85d4df42ff6009b11) +++ Ringtoets/Piping/src/Ringtoets.Piping.Data/DerivedPipingInput.cs (.../DerivedPipingInput.cs) (revision 2363244674e6b7b97bead9a6855806420d368d80) @@ -20,11 +20,13 @@ // All rights reserved. using System; +using System.Linq; using Core.Common.Base.Data; using Ringtoets.Common.Data.Probabilistics; using Ringtoets.HydraRing.Data; using Ringtoets.Piping.InputParameterCalculation; using Ringtoets.Piping.Primitives; +using Ringtoets.Piping.Primitives.Exceptions; namespace Ringtoets.Piping.Data { @@ -65,7 +67,8 @@ } /// - /// Gets the piezometric head exit. + /// Gets the piezometric head at the exit point. + /// [m] /// public RoundedDouble PiezometricHeadExit { @@ -79,7 +82,8 @@ } /// - /// Gets the seepage length. + /// Gets the horizontal distance between entry and exit point. + /// [m] /// public LogNormalDistribution SeepageLength { @@ -96,99 +100,272 @@ } /// - /// Gets the thickness coverage layer. + /// Gets the total thickness of the coverage layers at the exit point. + /// [m] /// public LogNormalDistribution ThicknessCoverageLayer { get { LogNormalDistribution thicknessCoverageLayer = new LogNormalDistribution(2) { + Mean = (RoundedDouble) double.NaN, StandardDeviation = (RoundedDouble) 0.5 }; - if (input.SurfaceLine != null && input.StochasticSoilProfile != null && input.StochasticSoilProfile.SoilProfile != null & !double.IsNaN(input.ExitPointL)) - { - TrySetThicknessCoverageLayer(thicknessCoverageLayer); - } - else - { - thicknessCoverageLayer.Mean = (RoundedDouble) double.NaN; - } + UpdateThicknessCoverageLayerMean(thicknessCoverageLayer); return thicknessCoverageLayer; } } /// - /// gets the thickness aquifer layer. + /// Gets the total thickness of the aquifer layers at the exit point. + /// [m] /// public LogNormalDistribution ThicknessAquiferLayer { get { LogNormalDistribution thicknessAquiferLayer = new LogNormalDistribution(2) { + Mean = (RoundedDouble) double.NaN, StandardDeviation = (RoundedDouble) 0.5 }; + UpdateThicknessAquiferLayerMean(thicknessAquiferLayer); - StochasticSoilProfile stochasticSoilProfile = input.StochasticSoilProfile; + return thicknessAquiferLayer; + } + } - RingtoetsPipingSurfaceLine surfaceLine = input.SurfaceLine; - RoundedDouble exitPointL = input.ExitPointL; + /// + /// Gets the sieve size through which 70% fraction of the grains of the top part of the aquifer passes. + /// [m] + /// + public LogNormalDistribution DiameterD70 + { + get + { + var distribution = new LogNormalDistribution(6) + { + Mean = (RoundedDouble) double.NaN, + StandardDeviation = (RoundedDouble) double.NaN + }; + UpdateDiameterD70Parameters(distribution); - if (stochasticSoilProfile != null && stochasticSoilProfile.SoilProfile != null && surfaceLine != null && !double.IsNaN(exitPointL)) + return distribution; + } + } + + /// + /// Gets or sets the Darcy-speed with which water flows through the aquifer layer. + /// [m/s] + /// + public LogNormalDistribution DarcyPermeability + { + get + { + var distribution = new LogNormalDistribution(6) { - double thicknessTopAquiferLayer = GetThicknessTopAquiferLayer(stochasticSoilProfile.SoilProfile, surfaceLine, exitPointL); - TrySetThicknessAquiferLayerMean(thicknessAquiferLayer, thicknessTopAquiferLayer); + Mean = (RoundedDouble) double.NaN, + StandardDeviation = (RoundedDouble) double.NaN + }; + UpdateDarcyPermeabilityParameters(distribution); + + return distribution; + } + } + + /// + /// Gets or sets the volumic weight of the saturated coverage layer. + /// + public ShiftedLogNormalDistribution SaturatedVolumicWeightOfCoverageLayer + { + get + { + var distribution = new ShiftedLogNormalDistribution(2) + { + Mean = (RoundedDouble) double.NaN, + StandardDeviation = (RoundedDouble) double.NaN, + Shift = (RoundedDouble) double.NaN + }; + UpdateSaturatedVolumicWeightOfCoverageLayerParameters(distribution); + + return distribution; + } + } + + private void UpdateThicknessAquiferLayerMean(LogNormalDistribution thicknessAquiferLayer) + { + StochasticSoilProfile stochasticSoilProfile = input.StochasticSoilProfile; + RingtoetsPipingSurfaceLine surfaceLine = input.SurfaceLine; + RoundedDouble exitPointL = input.ExitPointL; + + if (stochasticSoilProfile != null && stochasticSoilProfile.SoilProfile != null && surfaceLine != null && !double.IsNaN(exitPointL)) + { + var thicknessTopAquiferLayer = new RoundedDouble(thicknessAquiferLayer.Mean.NumberOfDecimalPlaces, + GetThicknessTopAquiferLayer(stochasticSoilProfile.SoilProfile, surfaceLine, exitPointL)); + + if (thicknessTopAquiferLayer > 0) + { + thicknessAquiferLayer.Mean = thicknessTopAquiferLayer; } - else + } + } + + private void UpdateThicknessCoverageLayerMean(LogNormalDistribution thicknessCoverageLayerDistribution) + { + if (input.SurfaceLine != null && input.StochasticSoilProfile != null && input.StochasticSoilProfile.SoilProfile != null && !double.IsNaN(input.ExitPointL)) + { + var weightedMean = new RoundedDouble(thicknessCoverageLayerDistribution.Mean.NumberOfDecimalPlaces, + InputParameterCalculationService.CalculateThicknessCoverageLayer( + input.WaterVolumetricWeight, + PipingSemiProbabilisticDesignValueFactory.GetPhreaticLevelExit(input).GetDesignValue(), + input.ExitPointL, + input.SurfaceLine, + input.StochasticSoilProfile.SoilProfile)); + + if (weightedMean > 0) { - thicknessAquiferLayer.Mean = (RoundedDouble) double.NaN; + thicknessCoverageLayerDistribution.Mean = weightedMean; } + } + } - return thicknessAquiferLayer; + private void UpdateDiameterD70Parameters(LogNormalDistribution diameterD70Distribution) + { + PipingSoilLayer topMostAquiferLayer = GetConsecutiveAquiferLayers().FirstOrDefault(); + if (topMostAquiferLayer != null) + { + var diameterD70Mean = new RoundedDouble(diameterD70Distribution.Mean.NumberOfDecimalPlaces, topMostAquiferLayer.DiameterD70Mean); + + if (diameterD70Mean > 0) + { + diameterD70Distribution.Mean = diameterD70Mean; + } + diameterD70Distribution.StandardDeviation = (RoundedDouble) topMostAquiferLayer.DiameterD70Deviation; } } - private static void TrySetThicknessAquiferLayerMean(LogNormalDistribution thicknessAquiferLayer, double thicknessTopAquiferLayer) + private void UpdateDarcyPermeabilityParameters(LogNormalDistribution darcyPermeabilityDistribution) { - if (thicknessTopAquiferLayer > 0) + PipingSoilLayer topMostAquiferLayer = GetConsecutiveAquiferLayers().FirstOrDefault(); + if (topMostAquiferLayer != null) { - thicknessAquiferLayer.Mean = (RoundedDouble) thicknessTopAquiferLayer; + var darcyPermeabilityMean = new RoundedDouble(darcyPermeabilityDistribution.Mean.NumberOfDecimalPlaces, topMostAquiferLayer.PermeabilityMean); + + if (darcyPermeabilityMean > 0) + { + darcyPermeabilityDistribution.Mean = darcyPermeabilityMean; + } + darcyPermeabilityDistribution.StandardDeviation = (RoundedDouble) topMostAquiferLayer.PermeabilityDeviation; } - else + } + + + private void UpdateSaturatedVolumicWeightOfCoverageLayerParameters(ShiftedLogNormalDistribution volumicWeightDistribution) + { + PipingSoilLayer[] aquitardLayers = GetConsecutiveAquitardLayers(); + + if (HasUniqueShiftAndDeviationSaturatedWeightDefinition(aquitardLayers)) { - thicknessAquiferLayer.Mean = (RoundedDouble) double.NaN; + PipingSoilLayer topMostAquitardLayer = aquitardLayers.First(); + volumicWeightDistribution.Shift = (RoundedDouble) topMostAquitardLayer.BelowPhreaticLevelShift; + volumicWeightDistribution.StandardDeviation = (RoundedDouble) topMostAquitardLayer.BelowPhreaticLevelDeviation; + + var weightedMean = new RoundedDouble(volumicWeightDistribution.Mean.NumberOfDecimalPlaces, + GetWeightedMeanForVolumicWeightOfCoverageLayer( + aquitardLayers, + input.StochasticSoilProfile.SoilProfile, + input.SurfaceLine.GetZAtL(input.ExitPointL))); + + if (weightedMean > 0) + { + volumicWeightDistribution.Mean = weightedMean; + } } } - private static double GetThicknessTopAquiferLayer(PipingSoilProfile soilProfile, RingtoetsPipingSurfaceLine surfaceLine, RoundedDouble exitPointL) + private static double GetWeightedMeanForVolumicWeightOfCoverageLayer(PipingSoilLayer[] aquitardLayers, PipingSoilProfile profile, double surfaceLevel) { - try + double totalThickness = 0.0; + double weighedTotal = 0.0; + + foreach (var layer in aquitardLayers) { - var zAtL = surfaceLine.GetZAtL(exitPointL); - return soilProfile.GetTopmostConsecutiveAquiferLayerThicknessBelowLevel(zAtL); + double layerThickness = profile.GetLayerThickness(layer); + double bottom = layer.Top - layerThickness; + double thicknessUnderSurface = Math.Min(layer.Top, surfaceLevel) - bottom; + + totalThickness += thicknessUnderSurface; + weighedTotal += layer.BelowPhreaticLevelMean*thicknessUnderSurface; } - catch (ArgumentException) + + return weighedTotal/totalThickness; + } + + private bool HasUniqueShiftAndDeviationSaturatedWeightDefinition(PipingSoilLayer[] consecutiveAquitardLayers) + { + if (!consecutiveAquitardLayers.Any()) { - return double.NaN; + return false; } + if (consecutiveAquitardLayers.Length == 1) + { + return true; + } + + return consecutiveAquitardLayers.All(al => + AlmostEquals(al.BelowPhreaticLevelDeviation, consecutiveAquitardLayers[0].BelowPhreaticLevelDeviation) + && AlmostEquals(al.BelowPhreaticLevelShift, consecutiveAquitardLayers[0].BelowPhreaticLevelShift)); } + + private PipingSoilLayer[] GetConsecutiveAquiferLayers() + { + RingtoetsPipingSurfaceLine surfaceLine = input.SurfaceLine; + PipingSoilProfile soilProfile = input.StochasticSoilProfile != null ? input.StochasticSoilProfile.SoilProfile : null; + RoundedDouble exitPointL = input.ExitPointL; - private void TrySetThicknessCoverageLayer(LogNormalDistribution thicknessCoverageLayer) + if (surfaceLine != null && soilProfile != null && !double.IsNaN(exitPointL)) + { + return soilProfile.GetConsecutiveAquiferLayersBelowLevel(surfaceLine.GetZAtL(exitPointL)).ToArray(); + } + + return new PipingSoilLayer[0]; + } + + private PipingSoilLayer[] GetConsecutiveAquitardLayers() { + RingtoetsPipingSurfaceLine surfaceLine = input.SurfaceLine; + PipingSoilProfile soilProfile = input.StochasticSoilProfile != null ? input.StochasticSoilProfile.SoilProfile : null; + RoundedDouble exitPointL = input.ExitPointL; + + if (surfaceLine != null && soilProfile != null && !double.IsNaN(exitPointL)) + { + return soilProfile.GetConsecutiveAquitardLayersBelowLevel(surfaceLine.GetZAtL(exitPointL)).ToArray(); + } + + return new PipingSoilLayer[0]; + } + + private bool AlmostEquals(double a, double b) + { + return Math.Abs(a - b) < 1e-6; + } + + private static double GetThicknessTopAquiferLayer(PipingSoilProfile soilProfile, RingtoetsPipingSurfaceLine surfaceLine, RoundedDouble exitPointL) + { try { - thicknessCoverageLayer.Mean = (RoundedDouble) InputParameterCalculationService.CalculateThicknessCoverageLayer( - input.WaterVolumetricWeight, - PipingSemiProbabilisticDesignValueFactory.GetPhreaticLevelExit(input).GetDesignValue(), - input.ExitPointL, - input.SurfaceLine, - input.StochasticSoilProfile.SoilProfile); + double zAtL = surfaceLine.GetZAtL(exitPointL); + return soilProfile.GetTopmostConsecutiveAquiferLayerThicknessBelowLevel(zAtL); } - catch (ArgumentOutOfRangeException) + catch (Exception e) { - thicknessCoverageLayer.Mean = (RoundedDouble) double.NaN; + if (e is RingtoetsPipingSurfaceLineException || e is InvalidOperationException || e is ArgumentException) + { + return double.NaN; + } + throw; } } }