using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Xml.Serialization; using Deltares.Mathematics; using Deltares.Standard; using Deltares.Standard.Attributes; using Deltares.Standard.Units; using Deltares.Standard.Validation; namespace Deltares.Stability { public class Slice : IComparable, IVisibleEnabled { public static readonly Color WaterColor = Color.CornflowerBlue; public static readonly Color LoadsColor = Color.IndianRed; public static readonly Color ShearColor = Color.ForestGreen; public static readonly Color NormalColor = Color.MediumOrchid; public static readonly Color IntersliceColor = Color.Gray; public const double CMinSliceWidth = 0.001; private const double CAlmostZero = 1E-7; private const double CDegreeToRad = Math.PI/180; private Point2D bottomLeft = new Point2D(); private Point2D bottomRight = new Point2D(); private double cohesion; private double degreeofConsolidationPorePressure; private double porePressureDueToDegreeOfConsolidationLoad; private double dilatancy; private double effectiveStress; private double excessPorePressure; private double externalLoad; private double hPoreOnSurface; private double horizontalQuakeforce = 0; private double hydrostaticPorePressure; private int index = 0; private double leftForce; private double leftForceAngle; private double leftForceY = double.NaN; private double loadStress; private double normalStress; private double oCR; private double pGrens; private double pOP; private double phi; private double piezometricPorePressure; private double poreOnSurface; private double resultantAngle; private double resultantForce; private double resultantMoment; //{ Approach with adapted first and last resultant slope } private double resultantNorm = 0; private double rightForce; private double rightForceAngle; private double rightForceY = double.NaN; private double shearStress; private double sigmaSoilQuake; private SlidingCurve slidingCurve; private double soilStress; private double temploadStress; private double tmpSafety; private Point2D topLeft = new Point2D(); private Point2D topRight = new Point2D(); private double totalPorePressure; private double totalStress; private double vPoreOnSurface; private double weight; private double zwaartepunt = 0; public Slice() {} [Unit(UnitType.Pressure)] [Label("POP")] [ReadOnly(true)] [Format("F3")] public double POP { get { return pOP; } set { pOP = value; } } [Browsable(false)] [Unit(UnitType.Pressure)] [ReadOnly(true)] [Format("F3")] public double PGrens { get { return pGrens; } set { pGrens = value; } } [Unit(UnitType.Fractions)] [Label("OCR")] [ReadOnly(true)] [Format("F3")] public double OCR { get { return oCR; } set { oCR = value; } } [Browsable(false)] public double ResultantForce { get { return resultantForce; } set { resultantForce = value; } } [Browsable(false)] public double ResultantMoment { get { return resultantMoment; } set { resultantMoment = value; } } [Browsable(false)] public double TmpSafety { get { return tmpSafety; } set { tmpSafety = value; } } [Browsable(false)] public double ResultantAngle { get { return resultantAngle; } set { resultantAngle = value; } } [PropertyOrder(0, 0)] [ReadOnly(true)] public string Name { get { return "Slice " + (Index + 1).ToString(); } } [Browsable(false)] public int Index { get { return index; } set { index = value; } } [Browsable(false)] public Point2D TopLeft { get { return topLeft; } set { topLeft = value; } } [Browsable(false)] public Point2D TopRight { get { return topRight; } set { topRight = value; } } [Browsable(false)] public Point2D BottomLeft { get { return bottomLeft; } set { bottomLeft = value; } } [Browsable(false)] public Point2D BottomRight { get { return bottomRight; } set { bottomRight = value; } } [Unit(UnitType.Length)] [Label("X")] [Description("X")] [Format("F2")] [ReadOnly(true)] [PropertyOrder(1, 0)] public double XCenter { get { return (BottomLeft.X + BottomRight.X)/2.0; } } [Unit(UnitType.Depth)] [Label("Y")] [Description("Y")] [Format("F2")] [ReadOnly(true)] [Browsable(false)] [PropertyOrder(1, 1)] public double ZCenterTop { get { return (TopLeft.Y + TopRight.Y)/2.0; } } [Unit(UnitType.Depth)] [Label("Z")] [Description("Z")] [Format("F2")] [ReadOnly(true)] [PropertyOrder(1, 2)] public double ZCenterBottom { get { return (BottomLeft.Y + BottomRight.Y)/2.0; } } [Unit(UnitType.Angle, GeometryAngleUnit.rad)] [PropertyOrder(1, 6)] [Format("F2")] public double TopAngle { get { if (TopRight.X == TopLeft.X) { return Math.PI/2; } else { return Math.Atan2(TopRight.Y - TopLeft.Y, TopRight.X - TopLeft.X); } } } [PropertyOrder(1, 7)] [Unit(UnitType.Angle, GeometryAngleUnit.rad)] [Format("F2")] public double BottomAngle { get { if (BottomRight.X == BottomLeft.X) { return Math.PI/2; } else { return Math.Atan2(BottomRight.Y - BottomLeft.Y, BottomRight.X - BottomLeft.X); } } } [PropertyOrder(1, 5)] [Unit(UnitType.Length)] [Format("F2")] public double ArcLength { get { return Math.Sqrt(BottomIncrement*BottomIncrement + Width*Width); } } [PropertyOrder(1, 4)] [Unit(UnitType.Length)] [Format("F2")] public double Width { get { return Math.Abs(TopRight.X - TopLeft.X); } } [Unit(UnitType.Angle)] [Minimum(0)] [Maximum(90)] [PropertyOrder(2, 1)] [Label("Phi")] [Description("Phi")] [Format("F3")] [ReadOnly(true)] public double Phi { get { return phi; } set { phi = value; } } [Unit(UnitType.Pressure)] [Minimum(-1.000e+07)] [Maximum(1.000e+07)] [PropertyOrder(2, 2)] [Label("Cohesion")] [Description("Cohesion")] [Format("F3")] [ReadOnly(true)] public double Cohesion { get { return cohesion; } set { cohesion = value; } } [Unit(UnitType.Pressure)] [Minimum(-1.000e+07)] [Maximum(1.000e+07)] [PropertyOrder(2, 3)] [Label("Shear stress")] [Description("Shear stress")] [Format("F3")] [ReadOnly(true)] public double ShearStress { get { return shearStress; } set { shearStress = value; } } [Unit(UnitType.PressurePerLength)] [Minimum(-1.000e+07)] [Maximum(1.000e+07)] [PropertyOrder(2, 4)] [Label("Weight")] [Description("Weight")] [Format("F3")] [ReadOnly(true)] public double Weight { get { return weight; } set { weight = value; } } [Unit(UnitType.Pressure)] [Minimum(-1.000e+07)] [Maximum(1.000e+07)] [PropertyOrder(2, 5)] [Label("Total pore pressure")] [Format("F3")] [ReadOnly(true)] public double TotalPorePressure { get { return totalPorePressure; } set { totalPorePressure = value; } } [Unit(UnitType.Pressure)] [Minimum(-1.000e+07)] [Maximum(1.000e+07)] [PropertyOrder(2, 6)] [Label("Effective stress")] [Format("F3")] [ReadOnly(true)] public double EffectiveStress { get { return effectiveStress; } set { effectiveStress = value; } } [Unit(UnitType.Pressure)] [Minimum(-1.000e+07)] [Maximum(1.000e+07)] [PropertyOrder(2, 7)] [Label("Hydrostatic pore pressure")] [Format("F3")] [ReadOnly(true)] public double HydrostaticPorePressure { get { return hydrostaticPorePressure; } set { hydrostaticPorePressure = value; } } [Unit(UnitType.Pressure)] [Minimum(-1.000e+07)] [Maximum(1.000e+07)] [PropertyOrder(2, 8)] [Label("Piezometric pore pressure")] [Format("F3")] [ReadOnly(true)] public double PiezometricPorePressure { get { return piezometricPorePressure; } set { piezometricPorePressure = value; } } [Browsable(false)] [Unit(UnitType.Pressure)] [Label("Excess pore pressure")] [Format("F3")] [ReadOnly(true)] [PropertyOrder(2, 9)] public double ExcessPorePressure { get { return excessPorePressure; } set { excessPorePressure = value; } } [Unit(UnitType.Pressure)] [Minimum(-1.000e+07)] [Maximum(1.000e+07)] [PropertyOrder(2, 10)] [Label("Degree of consolidation stress")] [Description("DegreeOfConsolidationStressCaption")] [Format("F3")] [ReadOnly(true)] public double DegreeofConsolidationPorePressure { get { return degreeofConsolidationPorePressure; } set { degreeofConsolidationPorePressure = value; } } [Unit(UnitType.Pressure)] [Minimum(-1.000e+07)] [Maximum(1.000e+07)] [PropertyOrder(2, 11)] [Label("Degree of consolidation stress from load")] [Description("DegreeOfConsolidationStressLoadCaption")] [Format("F3")] [ReadOnly(true)] public double PorePressureDueToDegreeOfConsolidationLoad { get { return porePressureDueToDegreeOfConsolidationLoad; } set { porePressureDueToDegreeOfConsolidationLoad = value; } } [Unit(UnitType.Pressure)] [Format("F3")] [ReadOnly(true)] public double LoadStress { get { return loadStress; } set { loadStress = value; } } [Browsable(false)] public double TempLoadStress { get { return temploadStress; } set { temploadStress = value; } } [Browsable(false)] [Unit(UnitType.Pressure)] [Label("Soil stress")] [Description("SoilStressCaption")] [Format("F3")] [ReadOnly(true)] [PropertyOrder(2, 12)] public double SoilStress { //get { return this.effectiveStress + this.totalPorePressure; } get { return soilStress; } set { soilStress = value; } } [Browsable(false)] [Unit(UnitType.Pressure)] [Label("Total stress")] [Description("TotalStressCaption")] [Format("F3")] [ReadOnly(true)] [PropertyOrder(2, 13)] public double TotalStress { get { return totalStress; } set { totalStress = value; } } [Unit(UnitType.Pressure)] [Format("F3")] [Label("Pore pressure on surface")] [ReadOnly(true)] [PropertyOrder(2, 14)] public double PoreOnSurface { get { return poreOnSurface; } set { poreOnSurface = value; } } [Unit(UnitType.Pressure)] [Format("F3")] [Label("Vertical pore pressure")] [ReadOnly(true)] [PropertyOrder(2, 15)] public double VPoreOnSurface { get { return vPoreOnSurface; } set { vPoreOnSurface = value; } } [Unit(UnitType.Pressure)] [Label("Horizontal pore pressure")] [Format("F3")] [ReadOnly(true)] [PropertyOrder(2, 16)] public double HPoreOnSurface { get { return hPoreOnSurface; } set { hPoreOnSurface = value; } } [Unit(UnitType.PressurePerLength)] [Label("External load")] [Format("F3")] [ReadOnly(true)] [PropertyOrder(2, 17)] public double ExternalLoad { get { return externalLoad; } set { externalLoad = value; } } [Unit(UnitType.Pressure)] [Label("Soil quake")] [Format("F3")] [ReadOnly(true)] [PropertyOrder(2, 18)] public double SigmaSoilQuake { get { return sigmaSoilQuake; } set { sigmaSoilQuake = value; } } [Unit(UnitType.Pressure)] [Label("Normal stress")] [Description("NormalStressCaption")] [Format("F3")] [ReadOnly(true)] [PropertyOrder(2, 19)] public double NormalStress { get { return normalStress; } set { normalStress = value; } } [Unit(UnitType.Pressure)] [Label("Left force")] [Format("F3")] [ReadOnly(true)] [PropertyOrder(2, 20)] public double LeftForce { get { return leftForce; } set { leftForce = value; } } [Browsable(false)] [Unit(UnitType.Depth)] [Clearable] public double LeftForceY { get { return leftForceY; } set { leftForceY = value; } } /// /// Gets or sets the right force y. /// The right force y could be the height of the "aangrijpingspunt" /// /// /// The right force y. /// [ReadOnly(true)] [Unit(UnitType.Depth)] [Format("F3")] [Clearable] public double RightForceY { get { return rightForceY; } set { rightForceY = value; } } [Unit(UnitType.Pressure)] [Label("Right force")] [Format("F3")] [ReadOnly(true)] [PropertyOrder(2, 17)] public double RightForce { get { return rightForce; } set { rightForce = value; } } [Unit(UnitType.Angle)] [Label("Left force angle")] [Format("F3")] [ReadOnly(true)] [PropertyOrder(2, 18)] public double LeftForceAngle { get { return leftForceAngle; } set { leftForceAngle = value; } } [Unit(UnitType.None)] [Label("Right force angle")] [Format("F3")] [ReadOnly(true)] [PropertyOrder(2, 18)] public double RightForceAngle { get { return rightForceAngle; } set { rightForceAngle = value; } } [Unit(UnitType.None)] [Label("Dilatancy")] [Format("F3")] [ReadOnly(true)] [Browsable(false)] [PropertyOrder(2, 19)] public double Dilatancy { get { return dilatancy; } set { dilatancy = value; } } [Browsable(false)] [XmlIgnore] public SlidingCurve SlidingCurve { get { return slidingCurve; } set { slidingCurve = value; } } public override string ToString() { return string.Format("{0:F3} - {1:F3}", TopLeft.X, TopRight.X); } public void GetVectors(ref List vectors, ref List descriptions) { vectors = new List(); descriptions = new List(); // water stress var waterStressBeginPoint = new Point2D(BottomLeft.X, BottomLeft.Y); double waterforce = Math.Sqrt(VPoreOnSurface*VPoreOnSurface + HPoreOnSurface*HPoreOnSurface); var waterStressEndPoint = new Point2D(waterStressBeginPoint.X + waterforce*Math.Sin(TopAngle), waterStressBeginPoint.Y - waterforce*Math.Cos(TopAngle)); vectors.Add(new Point2D[] { waterStressBeginPoint, waterStressEndPoint }); descriptions.Add("Water force [" + UnitsManager.GetUserUnitString(UnitType.Force) + "] = " + UnitsManager.GetUserValue(UnitType.Force, waterforce).ToString("F3")); // load double fictiveWeight = Weight + ExternalLoad + SigmaSoilQuake*Width; var loadEndPoint = new Point2D(waterStressEndPoint.X, waterStressEndPoint.Y - fictiveWeight); vectors.Add(new Point2D[] { waterStressEndPoint, loadEndPoint }); descriptions.Add("Loads [" + UnitsManager.GetUserUnitString(UnitType.Force) + "] = " + UnitsManager.GetUserValue(UnitType.Force, fictiveWeight).ToString("F3")); // shear stress double shearForce = ShearStress*ArcLength; int sign = 1; // delphi: if (Number < 0) then {reversed geometry} sign := -1; var shearStressEndPoint = new Point2D(loadEndPoint.X - sign*shearForce*Math.Cos(BottomAngle), loadEndPoint.Y - sign*shearForce*Math.Sin(BottomAngle)); vectors.Add(new Point2D[] { loadEndPoint, shearStressEndPoint }); descriptions.Add("Shear force [" + UnitsManager.GetUserUnitString(UnitType.Force) + "] = " + UnitsManager.GetUserValue(UnitType.Force, shearForce).ToString("F3")); // Normal force on bottom double normalForceBottom = (TotalPorePressure + NormalStress)*ArcLength; var normalForceBottomPoint = new Point2D(shearStressEndPoint.X - normalForceBottom*Math.Sin(BottomAngle), shearStressEndPoint.Y + normalForceBottom*Math.Cos(BottomAngle)); vectors.Add(new Point2D[] { shearStressEndPoint, normalForceBottomPoint }); descriptions.Add("Normal force on bottom [" + UnitsManager.GetUserUnitString(UnitType.Pressure) + "] = " + UnitsManager.GetUserValue(UnitType.Pressure, normalForceBottom).ToString("F3")); // Left interslice forces double forceDifference = LeftForce - RightForce; var interSlicePoint = new Point2D(normalForceBottomPoint.X + sign*forceDifference*Math.Cos(-LeftForceAngle), normalForceBottomPoint.Y + sign*forceDifference*Math.Sin(-LeftForceAngle)); vectors.Add(new Point2D[] { normalForceBottomPoint, interSlicePoint }); descriptions.Add("Interslice forces [" + UnitsManager.GetUserUnitString(UnitType.Force) + "] = " + UnitsManager.GetUserValue(UnitType.Force, forceDifference).ToString("F3")); } public void DetermineInterSliceForces() { // See equation (10) } // Nte, that Spencer's theory considers the crest at the right hand side, while the MStab code applies it left. // Consequently, Right corresponds to index n-1, Left to index n. Moment and resultant force get opposite sign. } rightForce = leftForce + resultantForce; rightForceY = (resultantMoment + leftForce*Math.Cos(resultantAngle)*(leftForceY - ZCenterBottom) - (leftForce + rightForce)*Math.Sin(resultantAngle)*Width/2.0)/rightForce/Math.Cos(resultantAngle) + ZCenterBottom; rightForceAngle = resultantAngle; } /* {======================================================================================================================= Comment: The blue print of the theoretical implications is found in: https://repos.deltares.nl/repos/pvcsprojects/documents/trunk/DGeoStability/Design/BluePrintGeoStability.doc Date ID Modification 2011-08-12 Sel Created =======================================================================================================================} */ public void DetermineSliceForcesAndSlopes() { double LLeftAngle; double LRightAngle; double LPhiBottom; /* Note, Takenote that Spencer 's theory considers the crest at the right hand side, while the MStab code applies it left. Consequently, Right corresponds to index n - 1, Left to index n. Moment and resultant force get opposite sign. */ LPhiBottom = Math.Atan(Math.Tan(Phi*CDegreeToRad)/tmpSafety); // Auxiliary angles, see equation(13); in FRightForceY the ActionRatio is temporarily placed LRightAngle = rightForceY*(topRight.Y - bottomRight.Y) - Math.Tan(-BottomAngle)*Width/2; rightForceY = LRightAngle + ZCenterBottom; LRightAngle = Math.Atan(LRightAngle/Width*2.0); LLeftAngle = Math.Atan((leftForceY - ZCenterBottom)/Width*2.0); // Resultant slope, see equation(13) resultantAngle = resultantMoment/Width*2.0 - leftForce* (Math.Sin(leftForceAngle + LRightAngle)/Math.Cos(LRightAngle) + Math.Sin(leftForceAngle - LLeftAngle)/Math.Cos(LLeftAngle)); resultantAngle = resultantAngle/resultantNorm*Math.Cos(LRightAngle)/Math.Cos(-BottomAngle - LPhiBottom + LRightAngle); resultantAngle = -BottomAngle - LPhiBottom - Math.Atan(Math.Tan(-BottomAngle - LPhiBottom + LRightAngle) - resultantAngle); DetermineResultantForce(); // Right inter - slice slope rightForceAngle = leftForce*Math.Cos(leftForceAngle) + resultantForce*Math.Cos(resultantAngle); if (Math.Abs(rightForceAngle) > CAlmostZero) { rightForceAngle = Math.Atan((leftForce*Math.Sin(leftForceAngle) + resultantForce*Math.Sin(resultantAngle))/ rightForceAngle); } else { rightForceAngle = Math.PI/2 - CAlmostZero; } // Right inter - slice force rightForce = leftForce*Math.Cos(leftForceAngle - rightForceAngle) + resultantForce*Math.Cos(resultantAngle - rightForceAngle); } /* {======================================================================================================================= Comment: The blue print of the theoretical implications is found in: https://repos.deltares.nl/repos/pvcsprojects/documents/trunk/DGeoStability/Design/BluePrintGeoStability.doc Date ID Modification 2010-11-09 Sel Created =======================================================================================================================} */ public void DetermineResultantNorm() { double LFictiveWeigth; double LWaterForce; double LPhiBottom; //{ See equation (3) } LFictiveWeigth = weight + externalLoad + sigmaSoilQuake*Width; LWaterForce = poreOnSurface*Width/Math.Cos(-TopAngle); LPhiBottom = Math.Atan(Math.Tan(phi*CDegreeToRad)/tmpSafety); //{ Note, that Spencer's theory considers the crest at the right hand side, while the MStab code applies it left. // Consequently, Right corresponds to index n-1, Left to index n. Moment and resultant force get opposite sign. } resultantNorm = LWaterForce*Math.Sin(-BottomAngle + TopAngle - LPhiBottom) + LFictiveWeigth*Math.Sin(-BottomAngle - LPhiBottom) + horizontalQuakeforce*Math.Cos(-BottomAngle - LPhiBottom) - cohesion*ArcLength/tmpSafety*Math.Cos(LPhiBottom) + totalPorePressure*ArcLength*Math.Sin(LPhiBottom); } /* {======================================================================================================================= Comment: The blue print of the theoretical implications is found in: https://repos.deltares.nl/repos/pvcsprojects/documents/trunk/DGeoStability/Design/BluePrintGeoStability.doc Date ID Modification// 2010-11-09 Sel Created =======================================================================================================================} * */ public void DetermineResultantForce() { double LPhiBottom; //{ See equation (3) } LPhiBottom = Math.Atan(Math.Tan(phi*CDegreeToRad)/tmpSafety); resultantForce = resultantNorm/Math.Cos(-BottomAngle - LPhiBottom - resultantAngle); } /* {======================================================================================================================= Date ID Modification 2010-11-09 Sel Created =======================================================================================================================} */ public void DetermineResultantMoment() { // Moment of external loadings around the base midpoint } resultantMoment = horizontalQuakeforce*(zwaartepunt - ZCenterBottom) + HPoreOnSurface*(ZCenterTop - ZCenterBottom); } public int CompareTo(Slice other) { return TopLeft.X.CompareTo(other.TopLeft.X); } public bool IsVisible(string property) { switch (property) { case "LeftForce": return !double.IsNaN(leftForce); case "RightForce": return !double.IsNaN(rightForce); case "LeftForceAngle": return !double.IsNaN(leftForceAngle); case "RightForceAngle": return !double.IsNaN(rightForceAngle); case "LeftForceY": return !double.IsNaN(leftForceY); case "RightForceY": return !double.IsNaN(rightForceY); default: return true; } } public bool IsEnabled(string property) { return true; } private double BottomIncrement { get { return BottomRight.Y - BottomLeft.Y; } } } }