using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Xml.Serialization; using Deltares.DeltaModel; using Deltares.Geographic; using Deltares.Geometry; using Deltares.Geotechnics; using Deltares.Geotechnics.GeotechnicalGeometry; using Deltares.Geotechnics.Mechanisms; using Deltares.Geotechnics.Soils; using Deltares.Geotechnics.SurfaceLines; using Deltares.Probabilistic; using Deltares.Standard; using Deltares.Standard.Attributes; using Deltares.Standard.EventPublisher; using Deltares.Standard.Reflection; using Deltares.Standard.Units; using Deltares.Standard.Validation; namespace Deltares.AssessmentMechanism { /// /// This class represents all the parameters for a which may be required for a specific . The /// contains the schematizations of the imported data and allows for modifications thereupon. /// public class DikeLocationInfo : IName, IHasGeographic, IHasSurfaceLine, IHasSchematizedSurfaceLine, IComparable, IComparable, IVisibleEnabled, IDomain, IDisposable { private readonly List locations = new List(); protected readonly List scenarios = new List(); private double allowedFailureProbability = double.NaN; private AssessmentScenario currentScenario; private StochasticSoilProfile currentStochasticSoilProfile; protected Soil defaultDikeEmbankmentMaterial; private DikeLocation dikeLocation = new DikeLocation(); private SurfaceLine2 schematizedSurfaceLine = new SurfaceLine2 { CharacteristicPoints = { GeometryMustContainPoint = false } }; private SoilProfile1D soilProfile; private SoilProfile2D soilProfile2D; protected SoilSurfaceProfile soilSurfaceProfile; protected SoilSurfaceProfile2D soilSurfaceProfile2D; private StochasticSoilModel stochasticSoilModel; private LocalizedGeometryPointString surfaceLine = new LocalizedGeometryPointString(); /// /// Initializes a new instance of the class. /// public DikeLocationInfo() { schematizedSurfaceLine.Geometry = surfaceLine; // Initialize with default 1D soil profile in order to provide a default soil schematization (also when no actual soil profiles are involved) SoilProfile = new SoilProfile1D(); DataEventPublisher.OnAfterChange += DataEventPublisher_OnAfterChange; } /// /// Gets or sets the dike location that this dike location info was created for. Composite relation. /// [Browsable(false)] [Validate] public virtual DikeLocation DikeLocation { get { return dikeLocation; } set { DataEventPublisher.BeforeChange(this, "DikeLocation"); if (null != dikeLocation) { dikeLocation.Dispose(); } dikeLocation = value; DataEventPublisher.AfterChange(this, "DikeLocation"); } } /// /// Gets or sets the offset end point. /// /// /// The offset end point. /// [Unit(UnitType.Length)] [Minimum(0.0)] [Format("F1")] [PropertyOrder(2, 8)] public virtual double OffsetEndPoint { get { var dikeSection = DikeLocation as DikeSection; if (dikeSection != null) { return dikeSection.EndPoint.Offset; } return 0.0; } set { var dikeSection = DikeLocation as DikeSection; if (dikeSection != null) { DataEventPublisher.BeforeChange(this, "OffsetEndPoint"); dikeSection.OffsetEndPoint = value; UpdateDikeSection(dikeSection, value, false); DataEventPublisher.AfterChange(this, "OffsetEndPoint"); } } } /// /// Gets or sets the offset begin point. /// /// /// The offset begin point. /// [Unit(UnitType.Length)] [Minimum(0.0)] [Format("F1")] [PropertyOrder(1, 7)] public virtual double OffsetBeginPoint { get { var dikeSection = DikeLocation as DikeSection; if (dikeSection != null) { return dikeSection.BeginPoint.Offset; } return 0.0; } set { var dikeSection = DikeLocation as DikeSection; if (dikeSection != null) { DataEventPublisher.BeforeChange(this, "OffsetBeginPoint"); dikeSection.OffsetBeginPoint = value; UpdateDikeSection(dikeSection, value, true); DataEventPublisher.AfterChange(this, "OffsetBeginPoint"); } } } /// /// Gets the length. /// /// /// The length. /// [Unit(UnitType.Length)] [Description("Length of the dike section")] [Format("F1")] [PropertyOrder(2, 9)] [Label("Length")] public double Length { get { return OffsetEndPoint - OffsetBeginPoint; } } /// /// Gets or sets a list of DunesDikeLocationInfo. Used in the DunesCalculation. /// public List Locations { get { return locations; } } /// /// Gets or sets the soil profile (1D) for location /// [PropertyOrder(2, 2)] [Mechanism(Mechanism.PipingUpliftGradient, Mechanism.Piping, Mechanism.Stability)] [Validate] [XmlIgnore] public virtual SoilProfile1D SoilProfile { get { return soilProfile; } set { if (soilProfile == value) { return; } DataEventPublisher.BeforeChange(this, dli => dli.SoilProfile); soilProfile = value; SoilSurfaceProfile = soilProfile != null ? new SoilSurfaceProfile { SurfaceLine = surfaceLine, SoilProfile = soilProfile, DikeEmbankmentMaterial = DefaultDikeEmbankmentMaterial } : null; DataEventPublisher.AfterChange(this, dli => dli.SoilProfile); } } /// /// Gets or sets the soil profile (2D) for location /// [PropertyOrder(2, 3)] [Mechanism(Mechanism.Stability)] [Validate] [XmlIgnore] public virtual SoilProfile2D SoilProfile2D { get { return soilProfile2D; } set { if (soilProfile2D == value) { return; } DataEventPublisher.BeforeChange(this, "SoilProfile2D"); soilProfile2D = value; SoilSurfaceProfile2D = soilProfile2D != null ? new SoilSurfaceProfile2D { SurfaceLine = surfaceLine, SoilProfile2D = soilProfile2D, DikeEmbankmentMaterial = DefaultDikeEmbankmentMaterial } : null; DataEventPublisher.AfterChange(this, "SoilProfile2D"); } } /// /// Gets or sets the stochastic soil model for the location /// [Mechanism(Mechanism.PipingUpliftGradient, Mechanism.Piping, Mechanism.Stability)] public virtual StochasticSoilModel StochasticSoilModel { get { return stochasticSoilModel; } set { this.SetAndNotify2(out stochasticSoilModel, value, dli => dli.StochasticSoilModel); } } /// /// Gets or sets the currently active Stochastic soil profile for the location. /// [Browsable(false)] [XmlIgnore] public StochasticSoilProfile CurrentStochasticSoilProfile { get { return currentStochasticSoilProfile; } set // Don't remove: used by scenario items in derived classes { DataEventPublisher.BeforeChange(this, dli => dli.CurrentStochasticSoilProfile); currentStochasticSoilProfile = value; if (currentStochasticSoilProfile == null || currentStochasticSoilProfile.Profile == null) { SoilProfile2D = null; SoilProfile = null; } else if (currentStochasticSoilProfile.Profile is SoilProfile2D) { SoilProfile2D = (SoilProfile2D)currentStochasticSoilProfile.Profile; SoilProfile = null; } else if (currentStochasticSoilProfile.Profile is SoilProfile1D) { SoilProfile = (SoilProfile1D)currentStochasticSoilProfile.Profile; SoilProfile2D = null; } DataEventPublisher.AfterChange(this, dli => dli.CurrentStochasticSoilProfile); } } /// /// Gets or sets the active scenario for which the assessment will be performed. /// // TODO Should the current active scenario always be part of the known Scenario's property? [XmlOmit(null)] [Mechanism(Mechanism.PipingUpliftGradient, Mechanism.Piping, Mechanism.Stability)] public virtual AssessmentScenario CurrentScenario { get { if (currentScenario == null) { if (!DataEventPublisher.IsDataEventPublishStopped && scenarios.Count == 0) { InitializeScenarios(); } } return currentScenario; } set { if (currentScenario != value) { try { Delayed.BeginDelay(); DataEventPublisher.BeforeChange(this, dli => dli.CurrentScenario); if (currentScenario != null) { currentScenario.Synchronize(); if (value == null) { currentScenario.Unapply(); } else { DataEventPublisher.InvokeWithoutPublishingEvents(() => currentScenario.Unapply()); } } currentScenario = value; if (currentScenario != null) { currentScenario.Apply(); } DataEventPublisher.AfterChange(this, dli => dli.CurrentScenario); } finally { Delayed.EndDelay(); } } } } /// /// Gets the combination of soil profile (2D) and surface line. /// [Browsable(false)] public virtual SoilSurfaceProfile2D SoilSurfaceProfile2D { get { return soilSurfaceProfile2D; } protected set { DataEventPublisher.BeforeChange(this, dli => dli.SoilSurfaceProfile2D); if (soilSurfaceProfile2D != null) { soilSurfaceProfile2D.Dispose(); } soilSurfaceProfile2D = value; DataEventPublisher.AfterChange(this, dli => dli.SoilSurfaceProfile2D); } } /// /// Gets or sets the combination of soil profile (1D) and surface line. /// [Browsable(false)] public virtual SoilSurfaceProfile SoilSurfaceProfile { get { return soilSurfaceProfile; } protected set { DataEventPublisher.BeforeChange(this, dli => dli.SoilSurfaceProfile); if (soilSurfaceProfile != null) { soilSurfaceProfile.Dispose(); } soilSurfaceProfile = value; DataEventPublisher.AfterChange(this, dli => dli.SoilSurfaceProfile); } } /// /// Default embankment material to be used in and/or . /// [Browsable(false)] public virtual Soil DefaultDikeEmbankmentMaterial { get { return defaultDikeEmbankmentMaterial; } set { this.SetAndNotify2(out defaultDikeEmbankmentMaterial, value, x => x.DefaultDikeEmbankmentMaterial); if (SoilSurfaceProfile != null) { SoilSurfaceProfile.DikeEmbankmentMaterial = value; } if (SoilSurfaceProfile2D != null) { SoilSurfaceProfile2D.DikeEmbankmentMaterial = value; } } } /// /// Gets the list of . /// [Mechanism(Mechanism.PipingUpliftGradient, Mechanism.Piping, Mechanism.Stability)] public virtual IList Scenarios { get { if (!DataEventPublisher.IsDataEventPublishStopped && scenarios.Count == 0) { InitializeScenarios(); } return scenarios; } } /// /// Gets or sets the maximum allowed failure probability based on the failure probability of the which the /// is part of. /// [Unit(UnitType.ProbabilityPerYear)] [Format("F2")] [ReadOnly(true)] [PropertyOrder(1, 1)] public double AllowedFailureProbability { get { return allowedFailureProbability; } set { if (value != allowedFailureProbability) { this.SetAndNotify2(out allowedFailureProbability, value, dli => dli.AllowedFailureProbability); } } } /// /// Returns the geographic part of the dike location /// [Browsable(false)] public IGeographic Geographic { get { return DikeLocation; } } /// /// Gets or sets the schematized surface line for a specific mechanism. /// [PropertyOrder(2, 1)] [Label("Surface line")] [Description("Surface line")] [Browsable(false)] [Validate] public virtual SurfaceLine2 SchematizedSurfaceLine { get { return schematizedSurfaceLine; } set { DataEventPublisher.BeforeChange(this, "SchematizedSurfaceLine"); if (null != schematizedSurfaceLine) { schematizedSurfaceLine.Dispose(); } schematizedSurfaceLine = value; if (schematizedSurfaceLine != null) { schematizedSurfaceLine.Geometry = surfaceLine; } DataEventPublisher.AfterChange(this, "SchematizedSurfaceLine"); } } /// /// Gets or sets the adapted surface line for the failure mechanism. /// public virtual LocalizedGeometryPointString SurfaceLine { get { return surfaceLine; } set { DataEventPublisher.BeforeChange(this, "SurfaceLine"); surfaceLine = value; schematizedSurfaceLine.Geometry = surfaceLine; if (soilSurfaceProfile != null) { soilSurfaceProfile.SurfaceLine = surfaceLine; } if (soilSurfaceProfile2D != null) { soilSurfaceProfile2D.SurfaceLine = surfaceLine; } DataEventPublisher.AfterChange(this, "SurfaceLine"); } } /// /// Name visible to the end user /// [Label("Name")] [PropertyOrder(0, 1)] [XmlIgnore] public virtual string Name { get { return DikeLocation.Name; } set { DataEventPublisher.BeforeChange(this, "Name"); DikeLocation.Name = value; DataEventPublisher.AfterChange(this, "Name"); } } /// /// Initializes the for a calculation. This method is invoked from HydraRing to gain a specific /// state for this instance. Invoking this method means that /// has to be called after the calculation has been executed. /// public virtual void InitializeForCalculation() {} /// /// Finalizes the from a calculation. If parameters have changed in /// which could influence successive calculations, then this method will reset them appropriately. /// public virtual void FinalizeFromCalculation() {} /// /// Updates the dike section. /// TODO: Comment /// /// The dike section. /// The offset. /// if set to true [begin p]. TODO: Comment: what is beginP? public void UpdateDikeSection(DikeSection dikeSection, double offset, bool beginP) { var newSection = dikeSection; if (beginP) { var index = 0; var point = GeographicHelper.Instance.FindGeographicPointByOffsetOnLine(offset, newSection.DikeLine); newSection.BeginPoint.SetCoordinate(point.X, point.Y); DataEventPublisher.AfterChange(this); } if (!beginP) { var index = 0; var point = GeographicHelper.Instance.FindGeographicPointByOffsetOnLine(offset, newSection.DikeLine); newSection.EndPoint.SetCoordinate(point.X, point.Y); DataEventPublisher.AfterChange(this); } DikeLocation = newSection; } /// /// Gets the stochasts. /// /// list with stochasts public virtual List GetStochasts() { return new List(); } /// /// Initialize the scenarios for this instance. /// public virtual void InitializeScenarios() { // Clear any previous scenarios scenarios.Clear(); // Add a dummy scenario scenarios.Add(new AssessmentScenario { Probability = 1.0 }); CurrentScenario = scenarios[0]; } /// /// Reverts the surface line. /// [Label("Revert")] public virtual void RevertSurfaceLine() { // First, re-clone the SchematizedSurfaceLine according to the original SchematizedSurfaceLine DikeLocation.SchematizedSurfaceLine.FullDeepClone(SchematizedSurfaceLine, MechanismSupport.Mechanisms); InitializeScenarios(); // Second, also re-clone the SurfaceLine line when it doesn't equal OriginalDikeLocation.SurfaceLine if (!ReferenceEquals(SurfaceLine, DikeLocation.SurfaceLine)) { SurfaceLine = SchematizedSurfaceLine.Geometry; // Note: the newly cloned SchematizedSurfaceLine already holds a new clone of the original SurfaceLine, so use that one DataEventPublisher.DataListModified(SurfaceLine.Points); } DataEventPublisher.DataListModified(SchematizedSurfaceLine.CharacteristicPoints); DataEventPublisher.DataListModified(SchematizedSurfaceLine.Geometry.Points); DataEventPublisher.DataListModified(Scenarios); // Send an event which will be handled to complete the revert of the dike location DataEventPublisher.AfterChange(DikeLocation, "Revert"); } /// /// Gets the name. /// /// The property. /// null public virtual string GetName(string property) { return null; } /// /// Gets the part of the surface line which is relevant for the mechanism. /// /// All relevant surface line points. public virtual GeometryPointString GetRelevantSurfacePoints() { return SurfaceLine; } /// /// Returns a that represents this instance. /// /// /// A that represents this instance. /// public override string ToString() { if (Geographic != null) { return Geographic.ToString(); } else { return base.ToString(); } } #region IDisposable public virtual void Dispose() { DataEventPublisher.OnAfterChange -= DataEventPublisher_OnAfterChange; if (soilSurfaceProfile != null) { soilSurfaceProfile.Dispose(); } if (soilSurfaceProfile2D != null) { soilSurfaceProfile2D.Dispose(); } if (schematizedSurfaceLine != null) { schematizedSurfaceLine.Dispose(); } if (dikeLocation != null) { dikeLocation.Dispose(); } } #endregion #region IDomain Members public virtual ICollection GetDomain(string property) { if (property == this.GetMemberName(dli => dli.CurrentScenario)) { return Scenarios.ToArray(); } return null; } #endregion private void DataEventPublisher_OnAfterChange(object sender, PublishEventArgs e) { var windHydraulicBoundary = sender as WindHydraulicBoundary; if (windHydraulicBoundary != null && DikeLocation.WaveZone.Waves.Count > 0) { if (DikeLocation.HydraulicBoundary1 != null && DikeLocation.HydraulicBoundary1.WindHydraulicBoundaries.Contains(windHydraulicBoundary)) { DikeLocation.WaveZone.Waves[0].Height = Double.NaN; } else if (DikeLocation.HydraulicBoundary2 != null && DikeLocation.HydraulicBoundary2.WindHydraulicBoundaries.Contains(windHydraulicBoundary)) { DikeLocation.WaveZone.Waves[0].Height = Double.NaN; } } } #region IVisibleEnabled Members /// /// Determines whether the specified property is enabled. /// /// The property. /// true public virtual bool IsEnabled(string property) { return true; } public virtual bool IsVisible(string property) { var visible = MechanismSupport.IsMechanismVisible(typeof(DikeLocationInfo), property); if (visible && property == this.GetMemberName(dli => dli.CurrentScenario)) { // Ensure you have a scenario to choose from: visible = Scenarios.Count >= 2; } return visible; } #endregion #region IComparable Members /// /// Compares the current instance with another object of the same type /// /// An object to compare with this instance. /// /// if object is DikeLocationInfo, calls above function, otherwise returns 1 /// public int CompareTo(object obj) { if (obj is DikeLocationInfo) { return CompareTo((DikeLocationInfo) obj); } else { return 1; } } /// /// Compares the current object with another object of the same type. /// /// An object to compare with this object. /// /// value of comparing offsetBeginPoints /// public int CompareTo(DikeLocationInfo other) { return OffsetBeginPoint.CompareTo(other.OffsetBeginPoint); } #endregion } }