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
}
}