using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Xml.Serialization; using Deltares.Geometry; using Deltares.Geotechnics; using Deltares.Geotechnics.Soils; using Deltares.Mathematics; using Deltares.Standard; using Deltares.Standard.Attributes; using Deltares.Standard.EventPublisher; using Deltares.Standard.Units; using Deltares.Standard.Validation; namespace Deltares.Stability { public class StressesInGeometry : GeometryObject, IDisposable { private const double allowedDiff = 0.0002; private bool dirty = false; private SoilProfile1D soilProfile1D; private SoilProfile2D soilProfile2D; private List stresses = new List(); private Waternet waternetModel; private double x = Double.NaN; public StressesInGeometry() { DataEventPublisher.OnAfterChange += DataEventPublisher_OnAfterChange; } [Unit(UnitType.Length)] [Minimum(-1000000)] [Maximum(1000000)] [PropertyOrder(0)] [Translation("L")] [Description("Location for which the stresses are calculated")] [Category("ConstantXCoordiateCategory")] [Format("F3")] [Impact(Impact.Descriptive)] public double X { get { if (Double.IsNaN(x)) { x = (soilProfile2D.Geometry.Left + soilProfile2D.Geometry.Right) / 2; } else if (x < soilProfile2D.Geometry.Left) { x = soilProfile2D.Geometry.Left; } else if (x > soilProfile2D.Geometry.Right) { x = soilProfile2D.Geometry.Right; } return x; } set { DataEventPublisher.BeforeChange(this, "X"); x = value; dirty = true; DataEventPublisher.AfterChange(this, "X"); } } [XmlIgnore] public bool Dirty { get { return dirty; } set { dirty = value; } } public SoilProfile2D SoilProfile2D { get { return soilProfile2D; } set { soilProfile2D = value; } } public Waternet WaternetModel { get { return waternetModel; } set { waternetModel = value; } } [XmlIgnore] public List Stresses { get { if (dirty) { dirty = false; RefreshStresses(); } return stresses; } } public void Dispose() { DataEventPublisher.OnAfterChange -= DataEventPublisher_OnAfterChange; } private void DataEventPublisher_OnAfterChange(object sender, PublishEventArgs e) { if (sender is GeometryPoint) { // respond only if point is part of geometry if (soilProfile2D != null && soilProfile2D.Geometry != null) { var srcPoint = (GeometryPoint)sender; if (soilProfile2D.Geometry.Points.Contains(srcPoint)) { Dirty = true; DataEventPublisher.AfterChange(this); return; } } } else if (sender is Soil) { var srcSoil = (Soil)sender; if ((soilProfile2D != null && soilProfile2D.Surfaces != null && soilProfile2D.Surfaces.Any(s => s.Soil == srcSoil)) || (soilProfile1D != null && soilProfile1D.Layers != null && soilProfile1D.Layers.Any(l => l.Soil == srcSoil))) { Dirty = true; DataEventPublisher.AfterChange(this); return; } } else if (sender is PhreaticLine) { // TODO: this does not work as intended ? dirty = true; DataEventPublisher.AfterChange(this); } } private void RefreshStresses() { if (soilProfile2D != null) { soilProfile1D = soilProfile2D.GetSoilProfile1D(X); } stresses.Clear(); double phreaticLevel = Double.MinValue; double surfaceLevel = soilProfile1D.Layers.Max(p => p.TopLevel); // Add phreatic level if (waternetModel.PhreaticLine != null) { phreaticLevel = waternetModel.PhreaticLine.GetZAtX(X); if (!double.IsNaN(phreaticLevel)) { AddStress(phreaticLevel); } } // Add all waternet levels foreach (var waternetIntersection in waternetModel.IntersectListWaterlines(X)) { dirty = false; AddStress(waternetIntersection.Z); } // Add level just above the surface level // This level is necessary if the head is not equal to the phreatic level at the surface AddStress(surfaceLevel + 0.0001); // Add all soil surface levels foreach (var layer in soilProfile1D.Layers) { AddStress(layer.TopLevel); } // Add the bottom of the soil profile AddStress(soilProfile2D.Geometry.Bottom); stresses.Sort(); foreach (var stress in stresses) { stress.WaterPressure = waternetModel.GetPorePressure(X, stress.Z, surfaceLevel, false); stress.TotalPressure = soilProfile1D.GetTotalPressure(stress.Z, phreaticLevel, waternetModel.UnitWeight); } // Remove almost equal stresses for (int i = stresses.Count - 1; i > 0; i--) { GeometryLevelStress stress = stresses[i]; GeometryLevelStress nextStress = stresses[i - 1]; if (Routines2D.AreEqual(stress.Z, nextStress.Z, allowedDiff) && Routines2D.AreEqual(stress.TotalPressure, nextStress.TotalPressure, allowedDiff * waternetModel.UnitWeight) && Routines2D.AreEqual(stress.WaterPressure, nextStress.WaterPressure, allowedDiff * waternetModel.UnitWeight)) { stresses.Remove(nextStress); } } DataEventPublisher.DataListModified(Stresses); } private void AddStress(double z) { foreach (var existingStress in Stresses) { if (Math.Abs(existingStress.Z - z) < 0.00001) { return; } } var stress = new GeometryLevelStress(); stress.Z = z; stresses.Add(stress); } } public class GeometryLevelStress : IVisibleEnabled, IComparable { private double totalPressure = Double.NaN; private double waterPressure = Double.NaN; public GeometryLevelStress() { } [Label("Z")] [Description("Z Coordinate of the stress")] [Format("F3")] [Unit(UnitType.Length)] [ReadOnly(true)] [PropertyOrder(0, 1)] public double Z { get; set; } [Label("Water")] [Description("Water stress")] [Format("F3")] [Unit(UnitType.Pressure)] [ReadOnly(true)] [PropertyOrder(1, 1)] public double WaterPressure { get { return waterPressure; } set { waterPressure = value; } } [Label("Total")] [Description("Total stress")] [Unit(UnitType.Pressure)] [Format("F3")] [ReadOnly(true)] [PropertyOrder(1, 2)] public double TotalPressure { get { return totalPressure; } set { totalPressure = value; } } [Label("Effective")] [Description("Effective stress")] [Unit(UnitType.Pressure)] [Format("F3")] [PropertyOrder(1, 3)] public double EffectivePressure { get { return TotalPressure - WaterPressure; } } #region IVisibleEnabled Members public bool IsVisible(string property) { switch (property) { case "WaterPressure": return !Double.IsNaN(WaterPressure); case "TotalPressure": return !Double.IsNaN(TotalPressure); default: return true; } } public bool IsEnabled(string property) { return false; } #endregion public override string ToString() { return Z.ToString("F3"); } public int CompareTo(GeometryLevelStress other) { return -Z.CompareTo(other.Z); } } }