//-----------------------------------------------------------------------
//
// Copyright (c) 2009 Deltares. All rights reserved.
//
// B.S.T. The
// tom.the@deltares.nl
// 25-8-2009
// Base class for piping calculators Bligh and Sellmeijer
//-----------------------------------------------------------------------
using Deltares.Geometry;
using Deltares.Geotechnics.Soils;
using Deltares.Geotechnics.SurfaceLines;
using Deltares.Probabilistic;
using Deltares.Uplift;
namespace Deltares.Dam.Data
{
using System;
using System.Collections.Generic;
using Deltares.Piping.Data;
using Deltares.Standard;
using Deltares.Geotechnics;
public struct PipingCalculatorInput
{
public double Length;
public double WhitesConstant;
public double WaterViscosity;
public double DInBetweenAquiferlayer;
public double DBottomAquiferlayer;
public double PermeabilityInBetweenAquiferlayer;
public double PermeabilityBottomAquiferlayer;
public double BeddingAngle;
public double D70;
public ProbabilisticStruct ProbPermeabilityInBetweenAquiferlayer;
public ProbabilisticStruct ProbPermeabilityBottomAquiferlayer;
public ProbabilisticStruct ProbWhitesConstant;
public ProbabilisticStruct ProbBeddingAngle;
public ProbabilisticStruct ProbD70;
}
public struct PipingProbabilisticParameters
{
public PipingProbabilisticParameters(DistributionType layerHeightDistribution, double layerHeightDeviation)
{
LayerHeightDistribution = layerHeightDistribution;
LayerHeightDeviation = layerHeightDeviation;
}
public DistributionType LayerHeightDistribution;
public double LayerHeightDeviation;
}
public class PipingCalculator
{
public const string PipingFilenameExtension = ".txt";
public const string DamParametersSectionId = "[DamParameters]";
public const string ResultsSectionId = "[Results]";
public const double D50DividedByD70 = 0.81;
protected const double CDefaultFluidisationGradient = 0.3;
protected static double CGammaPDividedByGammaW = 16.5 / Physics.UnitWeightOfwater; // Gamma korrel is now assumed 16.5 kN/m3
protected double CDefaultWaterViscosity = Physics.WaterViscosity;
protected const double cDegreeToRadian = Math.PI / 180.0;
protected ModelParametersForPLLines modelParametersForPLLines;
protected double requiredSafetyFactor;
protected const double cToleranceHead = 0.00000001;
private IList gaugePLLines;
private IList gauges;
public double HCritical { get; set; }
public double? HeaveFactor { get; set; }
public PipingProbabilisticParameters? PipingProbabilisticParameters { get; set; }
protected double upliftCriterion;
protected bool hasProbabilisticParameters = false;
public string CalculationModelIdentifier = "Piping";
private bool isHydraulicShortcut = false;
public string PipingCalculationDirectory { get; set; }
public PipingCalculator(ModelParametersForPLLines modelParametersForPLLines, double requiredSafetyFactor,
IList gaugePLLines, IList gauges, PipingProbabilisticParameters? pipingProbabilisticParameters,
double upliftCriterion)
{
this.modelParametersForPLLines = modelParametersForPLLines;
this.requiredSafetyFactor = requiredSafetyFactor;
this.gaugePLLines = gaugePLLines;
this.gauges = gauges;
this.HCritical = 0.0;
this.PipingProbabilisticParameters = pipingProbabilisticParameters;
this.FilenameCalculation = "";
this.PipingCalculationDirectory = "";
this.upliftCriterion = upliftCriterion;
hasProbabilisticParameters = (pipingProbabilisticParameters != null);
}
public const double cDefaultMaxReturnValue = 90.0;
public const double cDefaultMinReturnValue = 0.0;
protected PLLines PLLines { get; set; }
protected SoilProfile1D SoilProfile { get; set; }
public UpliftLocationAndResult UpliftLocationAndResult { get; set; }
public string FilenameCalculation { get; set; }
protected GeometryPoint entryPoint { get; set; }
///
/// Determines the height of the cover layer (distance between surfacelevel and top of aquifer where uplift occurs).
///
/// The surface level.
///
protected double DetermineHeightCoverLayer(double surfaceLevel)
{
var topLevelAquifer = SoilProfile.GetLayerWithId(UpliftLocationAndResult.LayerWhereUpliftOccuresId).TopLevel;
topLevelAquifer = Math.Min(topLevelAquifer, surfaceLevel);
var d = surfaceLevel - topLevelAquifer;
// if d negative is negative then top of aquifer is higher then surface layer.
// This means that the aquifer is exposed on the surface.
// In this case d = 0
d = Math.Max(0, d);
return d;
}
///
/// Determines the piping factor based on h actual and hCritical, setting upperlimit of cDefaultMaxReturnValue.
///
/// The h actual.
/// The h critical.
///
protected double DeterminePipingFactorWithUpperLimit(double hActual, double hCritical)
{
var pipingFactor = cDefaultMaxReturnValue;
if (hActual > cToleranceHead)
{
var hc = hCritical;
pipingFactor = hc / hActual;
}
return (pipingFactor > cDefaultMaxReturnValue) ? cDefaultMaxReturnValue : pipingFactor;
}
///
/// Chek whether there is hydraulic shortcut.
///
///
/// true if [is hydraulic shortcut]; otherwise, false.
///
public bool IsHydraulicShortcut
{
get { return isHydraulicShortcut; }
set { isHydraulicShortcut = value; }
}
///
/// Calculate desigh values for piping channel length and shoulderheight at a given point
///
///
///
///
///
///
///
public virtual PipingDesign CalculateDesignAtPoint(Location location, SurfaceLine2 surfaceLine, SoilProfile1D soilProfile, double waterLevel, GeometryPoint point)
{
SetupCalculationAtGivenPoint(location, surfaceLine, soilProfile, waterLevel, point);
return new PipingDesign(0.0, 0.0);
}
///
/// Base for Calculate piping factor. This always return null as the overriding method(s) must provide the real value.
///
///
///
///
///
/// Piping factor.
public virtual double? CalculatePipingFactor(Location location, SurfaceLine2 surfaceLine, SoilProfile1D soilProfile, double waterLevel)
{
this.HCritical = 0.0;
SetupCalculation(location, surfaceLine, soilProfile, waterLevel);
return (null);
}
///
/// Base for Calculate reliability index. This always return null as the overriding method(s) must provide the real value.
///
///
///
///
///
///
/// Reliability index.
public virtual double? CalculateReliabilityIndex(Location location, SurfaceLine2 surfaceLine, SoilProfile1D soilProfile,
ProbabilisticStruct waterLevel)
{
SetupCalculation(location, surfaceLine, soilProfile, waterLevel.Mean);
return (null);
}
///
/// Base for Calculate probability of failure. This always return null as the overriding method(s) must provide the real value.
///
///
///
///
///
///
/// Probability of failure.
public virtual double? CalculatePipingFailureProbability(Location location, SurfaceLine2 surfaceLine, SoilProfile1D soilProfile,
ProbabilisticStruct waterLevel)
{
return (null);
}
///
/// Base for Calculates the new shoulder height when possible. This always return null as the overriding method(s) must provide the real value.
///
///
///
///
///
///
public virtual double? CalculateDesignShoulderHeight(Location location, SurfaceLine2 surfaceLine, SoilProfile1D soilProfile,
double waterLevel)
{
SetupCalculation(location, surfaceLine, soilProfile, waterLevel);
if (UpliftLocationAndResult != null)
{
return CalculateExtraShoulderHeight();
}
else
{
return null;
}
}
///
/// Prepare for calculation
///
protected virtual void SetupCalculation(Location location, SurfaceLine2 surfaceLine, SoilProfile1D soilProfile,
double waterLevel)
{
this.SoilProfile = soilProfile;
ThrowHelper.ThrowWhenConditionIsTrue
(
string.Format(ThrowHelper.GetResourceString(StringResourceNames.NoSoilProfileDefinedForLocation), ""),
() => (this.SoilProfile == null || this.SoilProfile.Layers.Count < 1)
);
ThrowHelper.ThrowWhenParameterIsMissing(this, "SurfaceLine", surfaceLine);
entryPoint = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtRiver);
ThrowHelper.ThrowWhenParameterIsMissing(surfaceLine, "DikeToeAtRiver", entryPoint);
ThrowHelper.ThrowIfArgumentNull(this.SoilProfile.BottomAquiferLayer, StringResourceNames.TwoSandlayersRequiredInSoilProfile);
this.PLLines = CreatePLLines(location, surfaceLine, soilProfile, waterLevel);
UpliftLocationDeterminator upliftLocationDeterminator = new UpliftLocationDeterminator
{
PLLines = this.PLLines,
SoilProfile = this.SoilProfile,
SurfaceLine = surfaceLine,
DikeEmbankmentMaterial = location.GetDikeEmbankmentSoil(),
XSoilGeometry2DOrigin = location.XSoilGeometry2DOrigin
};
UpliftLocationAndResult = upliftLocationDeterminator.GetLocationAndResult(upliftCriterion);
// next lines are outcommented because they are not in the Release 15.1
// but they are needed to get the same results as in the new 18.1 version
// start block for debugging
// const double upliftCriterionTolerance = 0.000000001;
// double upliftCriterionTmp = upliftCriterion - upliftCriterionTolerance;
// UpliftLocationAndResult = upliftLocationDeterminator.GetLocationAndResult(upliftCriterionTmp);
// end block for debugging
}
///
/// Prepare for calculation
///
protected virtual void SetupCalculationAtGivenPoint(Location location, SurfaceLine2 surfaceLine, SoilProfile1D soilProfile,
double waterLevel, GeometryPoint givenPoint)
{
this.SoilProfile = soilProfile;
ThrowHelper.ThrowWhenConditionIsTrue
(
string.Format(ThrowHelper.GetResourceString(StringResourceNames.NoSoilProfileDefinedForLocation), ""),
() => (this.SoilProfile == null || this.SoilProfile.Layers.Count < 1)
);
ThrowHelper.ThrowWhenParameterIsMissing(this, "SurfaceLine", surfaceLine);
entryPoint = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtRiver);
ThrowHelper.ThrowWhenParameterIsMissing(surfaceLine, "DikeToeAtRiver", entryPoint);
ThrowHelper.ThrowIfArgumentNull(this.SoilProfile.BottomAquiferLayer, StringResourceNames.TwoSandlayersRequiredInSoilProfile);
this.PLLines = CreatePLLines(location, surfaceLine, soilProfile, waterLevel);
UpliftLocationDeterminator upliftLocationDeterminator = new UpliftLocationDeterminator
{
PLLines = this.PLLines,
SoilProfile = this.SoilProfile,
SurfaceLine = surfaceLine,
DikeEmbankmentMaterial = location.GetDikeEmbankmentSoil(),
XSoilGeometry2DOrigin = location.XSoilGeometry2DOrigin
};
UpliftLocationAndResult = upliftLocationDeterminator.GetUpliftFactorAtPoint(givenPoint);
}
///
/// Create PLLines with waterlevel as input
///
///
/// created pllines
protected PLLines CreatePLLines(Location location, SurfaceLine2 surfaceLine, SoilProfile1D soilProfile, double waterLevel)
{
var plLineCreator = new PLLinesCreator
{
WaterLevelRiverHigh = waterLevel,
SurfaceLine = surfaceLine,
WaterLevelPolder = location.PolderLevel,
HeadInPLLine2 = location.HeadPL2,
HeadInPLLine3 = location.HeadPl3,
HeadInPLLine4 = location.HeadPl4,
ModelParametersForPLLines = modelParametersForPLLines,
SoilProfile = soilProfile,
GaugePLLines = this.gaugePLLines,
Gauges = this.gauges,
IsAdjustPL3AndPL4SoNoUpliftWillOccurEnabled = false, // for piping this must be set to false
PlLineOffsetBelowDikeTopAtRiver = location.PlLineOffsetBelowDikeTopAtRiver,
PlLineOffsetBelowDikeTopAtPolder = location.PlLineOffsetBelowDikeTopAtPolder,
DikeEmbankmentMaterial = location.GetDikeEmbankmentSoil(),
IsHydraulicShortcut = this.IsHydraulicShortcut,
XSoilGeometry2DOrigin = location.XSoilGeometry2DOrigin
};
return plLineCreator.CreateAllPLLines(location);
}
///
/// Throws exception D70 not in correct ranfe.
///
/// The D70.
protected void ThrowIfInvalidD70(double d70)
{
const double dMinValue = 1e-8;
const double dMaxValue = 0.1;
if ((d70 < dMinValue) || (d70 > dMaxValue))
{
throw new PipingCalculationException(String.Format("D70 must be between {0} and {1}, but is {2}", dMinValue, dMaxValue, d70));
}
}
///
/// Defines the piping input from the location parameters.
///
///
protected PipingCalculatorInput DefinePipingInputFromModel()
{
PipingCalculatorInput pipingCalculatorInput = new PipingCalculatorInput();
Soil inBetweenAquiferlayerSoil = this.SoilProfile.BottomAquiferLayer.Soil;
Soil bottomAquiferlayerSoil = this.SoilProfile.BottomAquiferLayer.Soil;
double heightInBetweenAquiferlayer = 0.0;
double heightBottomAquiferlayer = this.SoilProfile.GetLayerHeight(this.SoilProfile.BottomAquiferLayer);
if (this.SoilProfile.InBetweenAquiferLayer != null)
{
inBetweenAquiferlayerSoil = this.SoilProfile.InBetweenAquiferLayer.Soil;
heightInBetweenAquiferlayer = this.SoilProfile.GetLayerHeight(this.SoilProfile.InBetweenAquiferLayer);
}
else
{
heightBottomAquiferlayer = heightBottomAquiferlayer / 2;
heightInBetweenAquiferlayer = heightBottomAquiferlayer;
}
ThrowIfInvalidD70(inBetweenAquiferlayerSoil.DiameterD70);
pipingCalculatorInput.Length = UpliftLocationAndResult.X - entryPoint.X;
double topLevel = SoilProfile.GetLayerWithId(UpliftLocationAndResult.LayerWhereUpliftOccuresId).TopLevel;
pipingCalculatorInput.DInBetweenAquiferlayer = heightInBetweenAquiferlayer;
pipingCalculatorInput.DBottomAquiferlayer = heightBottomAquiferlayer;
pipingCalculatorInput.WhitesConstant = inBetweenAquiferlayerSoil.WhitesConstant;
pipingCalculatorInput.WaterViscosity = CDefaultWaterViscosity;
pipingCalculatorInput.BeddingAngle = inBetweenAquiferlayerSoil.BeddingAngle;
pipingCalculatorInput.D70 = Physics.FactorMeterToMicroMeter * inBetweenAquiferlayerSoil.DiameterD70;
pipingCalculatorInput.PermeabilityInBetweenAquiferlayer = inBetweenAquiferlayerSoil.PermeabKx;
pipingCalculatorInput.PermeabilityBottomAquiferlayer = bottomAquiferlayerSoil.PermeabKx;
if (hasProbabilisticParameters)
{
ThrowIfInvalidD70(inBetweenAquiferlayerSoil.DiameterD70Stochast.Deviation);
pipingCalculatorInput.ProbPermeabilityInBetweenAquiferlayer = new ProbabilisticStruct(inBetweenAquiferlayerSoil.PermeabKx, inBetweenAquiferlayerSoil.PermeabKxStochast.Deviation, (int)inBetweenAquiferlayerSoil.PermeabKxStochast.DistributionType, true);
pipingCalculatorInput.ProbPermeabilityBottomAquiferlayer = new ProbabilisticStruct(bottomAquiferlayerSoil.PermeabKx, bottomAquiferlayerSoil.PermeabKxStochast.Deviation, (int)bottomAquiferlayerSoil.PermeabKxStochast.DistributionType, true);
pipingCalculatorInput.ProbWhitesConstant = new ProbabilisticStruct(inBetweenAquiferlayerSoil.WhitesConstant, inBetweenAquiferlayerSoil.WhitesConstantStochast.Deviation, (int)inBetweenAquiferlayerSoil.WhitesConstantStochast.DistributionType, true);
pipingCalculatorInput.ProbBeddingAngle = new ProbabilisticStruct(inBetweenAquiferlayerSoil.BeddingAngle, inBetweenAquiferlayerSoil.BeddingAngleStochast.Deviation, (int)inBetweenAquiferlayerSoil.BeddingAngleStochast.DistributionType, true);
pipingCalculatorInput.ProbD70 = new ProbabilisticStruct(
Physics.FactorMeterToMicroMeter * inBetweenAquiferlayerSoil.DiameterD70,
Physics.FactorMeterToMicroMeter * inBetweenAquiferlayerSoil.DiameterD70Stochast.Deviation,
(int) inBetweenAquiferlayerSoil.DiameterD70Stochast.DistributionType, true);
}
return pipingCalculatorInput;
}
///
///
///
///
///
static protected double KIntrinisc(double permeabilityPipingLayer, double waterViscosity)
{
double result = permeabilityPipingLayer * waterViscosity / Physics.GravityConstant;
return result;
}
///
/// Check on precondition
///
protected void ThrowIfNoPLLinesDefined()
{
if (PLLines == null)
throw new UpliftLocationDeterminatorException("Required pllines not found");
}
///
/// Calculates the height of the extra shoulder.
///
///
protected double CalculateExtraShoulderHeight()
{
var calculator = new UpliftCalculator();
calculator.SoilProfile = this.SoilProfile;
calculator.SurfaceLevel = UpliftLocationAndResult.Z;
calculator.PhreaticLevel = this.PLLines.Lines[PLLineType.PL1].ZFromX(UpliftLocationAndResult.X);
calculator.TopOfLayerToBeEvaluated = SoilProfile.GetLayerWithId(UpliftLocationAndResult.LayerWhereUpliftOccuresId).TopLevel;
PLLine plLine;
if (UpliftLocationAndResult.LayerWhereUpliftOccuresId == SoilProfile.BottomAquiferLayer.Id)
{
plLine = this.PLLines.Lines[PLLineType.PL3];
}
else
{
plLine = this.PLLines.Lines[PLLineType.PL4];
}
return calculator.CalculateExtraHeight(plLine.ZFromX(UpliftLocationAndResult.X), upliftCriterion);
}
}
}