//----------------------------------------------------------------------- // // Copyright (c) 2009 Deltares. All rights reserved. // // Rob Brinkman // rob.brinkman@deltares.nl // 16-2-2011 // n.a. //----------------------------------------------------------------------- using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Linq; using Deltares.Geographic; using Deltares.Standard.Attributes; using Deltares.Standard.EventPublisher; using Deltares.Standard.Validation; namespace Deltares.Dam.Data { using System; using System.Xml.Serialization; using Deltares.Standard; public interface ILocationJob { Location Location { get; } IEnumerable RWScenarioResults { get; } bool HasRWScenarioResults { get; } } public class LocationJob : DamJob, ILocationJob, IGeographicPoint, IVisibleEnabled { private TimeSerie waterLevelTimeSerie = new TimeSerie(); private LocationResult locationResult = new LocationResult(); private static ScenarioType currentScenarioType = ScenarioType.Scenario01; private static string currentProfileName = ""; private static string currentScenarioName = ""; private static string currentCalculation = ""; private static DateTime currentTime = DateTime.Today; private static DamProjectType damProjectType = DamProjectType.Calamity; private static ProbabilisticType probabilisticType = ProbabilisticType.Deterministic; private double designRequiredFactor = 0.0; public LocationJob() { } public LocationJob(object subject) : base(subject) { } /// /// TODO: what todo when location is null? /// public double XRd { get { return this.Location == null ? 0 : this.Location.XRd; } } public double YRd { get { return this.Location == null ? 0 : this.Location.YRd; } } [XmlIgnore] [Validate] public Location Location { get { return this.Subject as Location; } set { this.Subject = value; } } public TimeSerie WaterLevelTimeSerie { get { return waterLevelTimeSerie; } set { DataEventPublisher.BeforeChange(this, "WaterLevelTimeSerie"); waterLevelTimeSerie = value; DataEventPublisher.AfterChange(this, "WaterLevelTimeSerie"); } } [XmlOldName("ScenarioResults")] public virtual IEnumerable RWScenarioResults { get { return !this.HasRWScenarioResults ? new List() : this.locationResult.RWScenariosResult.RWScenarioResults; } } public virtual IEnumerable SchematizationFactorResults { get { return !this.HasSchematizationFactorResults ? new List() : this.locationResult.SchematizationFactorsResult.SchematizationFactorResults; } } public bool HasRWScenarioResults { get { return this.locationResult != null && this.locationResult.RWScenariosResult != null && this.locationResult.RWScenariosResult.RWScenarioResults.Any(); } } public bool HasSchematizationFactorResults { get { return this.locationResult != null && this.locationResult.SchematizationFactorsResult != null; } } public virtual LocationResult LocationResult { get { return locationResult; } set { DataEventPublisher.BeforeChange(this, "LocationResult"); locationResult = value; DataEventPublisher.AfterChange(this, "LocationResult"); } } private bool HasUsableStabilityTimeSerieEntries() { var res = false; foreach (var timeSerieEntry in locationResult.StabilityTimeSerie.Entries) { if (timeSerieEntry.Value != Double.NaN) { res = true; break; } } return res; } public bool HasLocationResults { get { if (locationResult == null) return false; return ((locationResult.PipingTimeSerie != null && locationResult.PipingTimeSerie.Entries.Count > 0) || (locationResult.StabilityTimeSerie != null && locationResult.StabilityTimeSerie.Entries.Count > 0 && HasUsableStabilityTimeSerieEntries())); } } public LocationResult GetLocationResultWithStabilityTimeSerie(string locationName) { LocationResult result = null; if (locationResult != null && locationResult.StabilityTimeSerie != null && locationResult.StabilityTimeSerie.LocationId == locationName && locationResult.StabilityTimeSerie.Entries != null && locationResult.StabilityTimeSerie.Entries.Count > 1) { result = locationResult; } return result; } public LocationResult GetFirstLocationResultWithStabilityTimeSerie() { LocationResult result = null; if (locationResult != null && locationResult.StabilityTimeSerie != null && locationResult.StabilityTimeSerie.Entries != null && locationResult.StabilityTimeSerie.Entries.Count > 1) { result = locationResult; } return result; } public RWScenarioProfileResult GetAssesmentResultByProfile(ScenarioType scenarioType, string profileName) { if (this.HasRWScenarioResults) { RWScenarioResult scenarioResult = this.LocationResult.RWScenariosResult.GetScenarioResult(scenarioType); if (scenarioResult != null) { foreach (var res in scenarioResult.RWScenarioProfileResults) { if (res.SoilProfileName == profileName) return res; } } } return null; } public CsvExportData GetFirstDesignResult() { if (this.HasScenarioResults) { Scenario scenario = Location.Scenarios[0]; if (scenario != null && scenario.CalculationResults.Count > 0) { return scenario.CalculationResults[0]; } } return null; } public CsvExportData GetDesignResultByProfileScenarioAndCalculationName(string profileName, string scenarioName, string calculationName) { if (this.HasScenarioResults) { foreach (var scenario in Location.Scenarios) { foreach (var calculationResult in scenario.CalculationResults) { if (calculationResult.ProfileName == profileName && calculationResult.ScenarioName == scenarioName && calculationResult.Calculation == calculationName) return calculationResult; } } } return null; } /// /// Return the result of the profile with highest probability of occurrence /// /// /// public RWScenarioProfileResult GetRWScenarioResultOfProfileWithHighestProbablilityOfOccurrence(ScenarioType scenarioType) { if (this.HasRWScenarioResults) { RWScenarioResult scenarioResult = this.LocationResult.RWScenariosResult.GetScenarioResult(scenarioType); if (scenarioResult != null && scenarioResult.RWScenarioProfileResults.Count > 0) { RWScenarioProfileResult rwScenarioProfileResult = scenarioResult.RWScenarioProfileResults[0]; for (int i = 1; i < scenarioResult.RWScenarioProfileResults.Count; i++) { if (scenarioResult.RWScenarioProfileResults[i].SoilProfileProbability > rwScenarioProfileResult.SoilProfileProbability) { rwScenarioProfileResult = scenarioResult.RWScenarioProfileResults[i]; } } return rwScenarioProfileResult; } } return null; } /// /// Return result with the lowest safetyfactor /// /// /// public RWScenarioProfileResult GetRWScenarioResultWithLowestSafetyFactor(ScenarioType scenarioType) { if (this.HasRWScenarioResults) { RWScenarioResult scenarioResult = this.LocationResult.RWScenariosResult.GetScenarioResult(scenarioType); if (scenarioResult != null && scenarioResult.RWScenarioProfileResults.Count > 0) { RWScenarioProfileResult rwScenarioProfileResult = scenarioResult.RWScenarioProfileResults[0]; for (int i = 1; i < scenarioResult.RWScenarioProfileResults.Count; i++) { if (scenarioResult.RWScenarioProfileResults[i].SafetyFactor < rwScenarioProfileResult.SafetyFactor) { rwScenarioProfileResult = scenarioResult.RWScenarioProfileResults[i]; } } return rwScenarioProfileResult; } } return null; } public bool HasScenarioResults { get { List scenarios = Location.Scenarios; foreach (var scenario in scenarios) { foreach (var calculationResult in scenario.CalculationResults) { if (ProbabilisticType == ProbabilisticType.Deterministic) { if ((calculationResult.SafetyFactor != null) || (calculationResult.CalculationResult == CalculationResult.UnexpectedError) ) { return true; } } else { if (calculationResult.FailureProbability != null) { return true; } } } } return false; } } /// /// Get lowest safetyfactor of all scenarios /// /// private double GetLowestRealSafetyFactorFromScenarios() { var res = double.MaxValue; List scenarios = Location.Scenarios; foreach (var scenario in scenarios) { foreach (var calculationResult in scenario.CalculationResults) { if (calculationResult.CalculationResult == CalculationResult.UnexpectedError) { res = -1; } if (calculationResult.SafetyFactor != null) { if (calculationResult.SafetyFactor.Value < res) { res = calculationResult.SafetyFactor.Value; if (calculationResult.RequiredSafetyFactor != null) { designRequiredFactor = calculationResult.RequiredSafetyFactor.Value; } } } } } if (res == double.MaxValue) res = DamGlobalConstants.NoRunValue; return res; } /// /// Get highest porbability of failure of all scenarios /// /// private double GetHighestRealPropbabilityFromScenarios() { var res = double.MinValue; List scenarios = Location.Scenarios; foreach (var scenario in scenarios) { foreach (var calculationResult in scenario.CalculationResults) { if (calculationResult.Calculation.Equals("FlowSlide")) { designRequiredFactor = 1.0; // This is a hack to make FlowSlide color display correct; // TODO: make a good generic method to display colored results } else { if (calculationResult.PipingFailureProbability != null) { if (calculationResult.PipingFailureProbability.Value > res && calculationResult.PipingFailureProbability.Value < DamGlobalConstants.NoRunValue) { res = calculationResult.PipingFailureProbability.Value; if (calculationResult.RequiredFailureProbability != null) { designRequiredFactor = calculationResult.RequiredFailureProbability.Value; } } } } } } if (res == double.MinValue) res = DamGlobalConstants.NoRunValue; return res; } [Data] [Label("Safety factor")] [XmlIgnore] [Format("F3")] public double SafetyFactor { get { if (DamProjectType == DamProjectType.Calamity) { if (this.HasLocationResults) { TimeSerie timeSerie = this.LocationResult.StabilityTimeSerie; return timeSerie.GetValue(CurrentTime); } else { return DamGlobalConstants.NoRunValue; } } else if (DamProjectType == DamProjectType.Assessment) { if (this.HasRWScenarioResults && GetRWScenarioResultWithLowestSafetyFactor(currentScenarioType) != null) { return GetRWScenarioResultWithLowestSafetyFactor(currentScenarioType).SafetyFactor; } else { if (this.locationResult.RWScenariosResult != null && this.locationResult.RWScenariosResult.CalculationResult == CalculationResult.RunFailed) { // DamGlobalConstants.NoRunValue is the default result resulting in NoRun whereas the // status must be failed. So when failed set to -1. return -1; } else { return DamGlobalConstants.NoRunValue; } } } else if (DamProjectType == DamProjectType.Design) { return GetLowestRealSafetyFactorFromScenarios(); } else { return DamGlobalConstants.NoRunValue; } } } [Data] [Label("Detriment factor")] [Format("F3")] public double DetrimentFactor { get { if (DamProjectType == DamProjectType.Design) { return designRequiredFactor; } else { // For Piping in Assesment projects, ignore the given detriment factor and use the required safety for Piping if (DamProjectType == DamProjectType.Assessment && (currentScenarioType == ScenarioType.Scenario10 || currentScenarioType == ScenarioType.Scenario11)) { return DamGlobalConstants.RequiredSafetyPipingForAssessment; } return this.Location.DetrimentFactor; } } } [Data] [Label("Failure probability")] [XmlIgnore] [Format("F3")] public double FailureProbability { get { if (DamProjectType == DamProjectType.Calamity) { return DamGlobalConstants.NoRunValue; } else if (DamProjectType == DamProjectType.Assessment) { return DamGlobalConstants.NoRunValue; } else if (DamProjectType == DamProjectType.Design) { return GetHighestRealPropbabilityFromScenarios(); } else { return DamGlobalConstants.NoRunValue; } } } [Data] [Label("Required probability")] [Format("F3")] [XmlIgnore] public double RequiredProbability { get { if (DamProjectType == DamProjectType.Design) { return designRequiredFactor; // only for piping at the moment } else { return 1; //#Bka: for now return 1 if not piping probabilistic. } } } public bool AreRWScenarioResultsMixed(ScenarioType scenarioType) { if (this.HasRWScenarioResults) { RWScenarioResult scenarioResult = this.LocationResult.RWScenariosResult.GetScenarioResult(scenarioType); if (scenarioResult != null && scenarioResult.RWScenarioProfileResults.Count > 0) { var aboveRequiredSafety = false; var belowRequiredSafety = false; for (int i = 0; i < scenarioResult.RWScenarioProfileResults.Count; i++) { if (!aboveRequiredSafety) { aboveRequiredSafety = scenarioResult.RWScenarioProfileResults[i].SafetyFactor >= DetrimentFactor; } if (!belowRequiredSafety) { belowRequiredSafety = scenarioResult.RWScenarioProfileResults[i].SafetyFactor < DetrimentFactor; } } return aboveRequiredSafety && belowRequiredSafety; } } return false; } [Data] [XmlIgnore] [Label("Result")] public JobResult Result { get { if (ProbabilisticType == ProbabilisticType.Deterministic) { if (DamProjectType == DamProjectType.Assessment && AreRWScenarioResultsMixed(currentScenarioType)) { return JobResult.Mixed; } return JobResultInterpreter.GetJobResult(SafetyFactor, DetrimentFactor, true); } else { return JobResultInterpreter.GetJobResult(FailureProbability, RequiredProbability, false); } } } [XmlIgnore] [Browsable(false)] public double X { get { return this.Location.XRd; } set { this.Location.XRd = value; } } [XmlIgnore] [Browsable(false)] public double Y { get { return this.Location.YRd; } set { this.Location.YRd = value; } } [XmlIgnore] [Browsable(false)] public static ScenarioType CurrentScenarioType { get { return currentScenarioType; } set { currentScenarioType = value; } } [XmlIgnore] [Browsable(false)] public static string CurrentProfileName { get { return currentProfileName; } set { currentProfileName = value; } } [XmlIgnore] [Browsable(false)] public static string CurrentScenarioName { get { return currentScenarioName; } set { currentScenarioName = value; } } [XmlIgnore] [Browsable(false)] public static string CurrentCalculation { get { return currentCalculation; } set { currentCalculation = value; } } [XmlIgnore] [Browsable(false)] public static DateTime CurrentTime { get { return currentTime; } set { currentTime = value; } } [XmlIgnore] [Browsable(false)] public static DamProjectType DamProjectType { get { return damProjectType; } set { damProjectType = value; } } [XmlIgnore] [Browsable(false)] public static ProbabilisticType ProbabilisticType { get { return probabilisticType; } set { probabilisticType = value; } } public bool IsEnabled(string property) { return true; } public bool IsVisible(string property) { switch (property) { case "SafetyFactor": return this.Result != JobResult.NoRun && this.Result != JobResult.Failed && ProbabilisticType == ProbabilisticType.Deterministic; case "DetrimentFactor": return this.Result != JobResult.NoRun && this.Result != JobResult.Failed && ProbabilisticType == ProbabilisticType.Deterministic; case "RequiredProbability": return this.Result != JobResult.NoRun && this.Result != JobResult.Failed && ProbabilisticType != ProbabilisticType.Deterministic; case "FailureProbability": return this.Result != JobResult.NoRun && this.Result != JobResult.Failed && ProbabilisticType != ProbabilisticType.Deterministic; case "WaterLevelTimeSerie": return HasLocationResults; case "RWScenarioResults": return HasRWScenarioResults; default: return true; } } public override string ToString() { return this.Location != null ? this.Location.ToString() : ""; } } }