// Copyright (C) Stichting Deltares 2019. All rights reserved.
//
// This file is part of the application DAM - Clients Library.
//
// DAM - UI is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
//
// All names, logos, and references to "Deltares" are registered trademarks of
// Stichting Deltares and remain full property of Stichting Deltares at all times.
// All rights reserved.
using System;
using System.Collections;
using System.ComponentModel;
using System.Linq;
using System.Xml.Serialization;
using System.Collections.Generic;
using Deltares.Dam.Data.Sensors;
using Deltares.Standard;
using Deltares.Standard.Attributes;
using Deltares.Standard.EventPublisher;
using Deltares.Standard.Language;
using Deltares.Standard.Logging;
using Deltares.Standard.Project;
using Deltares.Standard.Validation;
using LogMessage = Deltares.DamEngine.Data.Standard.Logging.LogMessage;
namespace Deltares.Dam.Data
{
public class DamProjectData : Project, IDomain, IDisposable
{
public readonly double MissValStabilitySafetyFactor = -1.0;
private WaterBoard waterBoard;
private DamProjectCalculationSpecification damProjectCalculationSpecification;
private WaterBoardJob waterBoardJob = null;
private DamProjectType damProjectType = DamProjectType.Calamity;
private string damDataSourceFileName = "";
private List jobs = new List();
private SchematizationFactorData schematizationFactorData = new SchematizationFactorData();
private List designCalculations = null;
private List dataSources = new List();
private string dataSourceEsriProjection = null;
private SensorData sensorData;
private int maxCalculationCores = 1;
private TimeSerieCollection inputTimeSerieCollection = null;
private TimeSerieCollection outputTimeSerieCollection = null;
///
/// Constructor
///
public DamProjectData()
{
this.waterBoard = new WaterBoard();
this.waterBoardJob = null;
this.damProjectCalculationSpecification = new DamProjectCalculationSpecification();
}
///
/// Gets or sets the project working path.
///
///
/// The project working path.
///
public string ProjectPath
{
get
{
return DamProject.ProjectMap;
}
}
///
/// Gets or sets the calculation map.
///
///
/// The calculation map.
///
public string CalculationMap
{
get
{
return DamProject.CalculationMap;
}
}
///
/// Gets or sets the maximum calculation cores.
///
///
/// The maximum calculation cores.
///
public int MaxCalculationCores
{
get
{
return maxCalculationCores;
}
set
{
maxCalculationCores = value;
}
}
///
/// Toplevel object to hold waterboard data
///
public virtual WaterBoard WaterBoard
{
get { return this.waterBoard; }
set
{
this.waterBoard = value;
if (this.waterBoardJob != null && this.waterBoardJob.Subject != value)
{
this.waterBoardJob = null;
}
}
}
///
/// calculation specification for the project
///
/// Composite relationship
[Validate]
public DamProjectCalculationSpecification DamProjectCalculationSpecification
{
get { return damProjectCalculationSpecification; }
set { damProjectCalculationSpecification = value; }
}
[Child]
public virtual DamJob WaterBoardJob
{
get
{
if (waterBoardJob == null)
{
waterBoardJob = new WaterBoardJob(this.waterBoard);
waterBoardJob.Subject = this.waterBoard;
foreach (Dike dike in waterBoard.Dikes)
{
CompositeJob dikeJob = new DikeJob(dike);
waterBoardJob.Jobs.Add(dikeJob);
foreach (Location location in dike.Locations)
{
LocationJob locationJob = new LocationJob(location);
dikeJob.Jobs.Add(locationJob);
}
}
}
return waterBoardJob;
}
set { waterBoardJob = value as WaterBoardJob; }
}
[ReadOnly(true)]
[Label("Calculation type")]
[Description("Indicates the purpose of the calculations")]
public virtual DamProjectType DamProjectType
{
get { return damProjectType; }
set
{
DataEventPublisher.BeforeChange(this, "DamProjectType");
bool modified = damProjectType != value;
damProjectType = value;
Location.DamProjectType = value;
DamFailureMechanismeCalculationSpecification.DamProjectType = value;
if (modified)
{
LocationJob.DamProjectType = damProjectType;
DataEventPublisher.DataListModified(this.LocationJobs);
}
DataEventPublisher.AfterChange(this, "DamProjectType");
}
}
[Label("DAM datasource file")]
[Description("Indicates which \".defx\" import definition file to use")]
public virtual string DamDataSourceFileName
{
get { return damDataSourceFileName; }
set
{
DataEventPublisher.BeforeChange(this, "DamDataSourceFileName");
damDataSourceFileName = value;
DataEventPublisher.AfterChange(this, "DamDataSourceFileName");
}
}
///
/// Clear all results
///
public void ClearResults()
{
if (designCalculations != null)
{
designCalculations.Clear();
}
foreach (LocationJob locationJob in this.LocationJobs)
{
locationJob.LocationResult = new LocationResult();
foreach (Scenario scenario in locationJob.Location.Scenarios)
{
scenario.CalculationResults.Clear();
}
}
}
private List CreateScenarioListForDeletion()
{
List scenarios = new List(); ;
List locations = this.LocationJobs.Select(x => x.Location).ToList();
foreach (Location location in locations)
{
if (location.Scenarios != null)
{
scenarios.AddRange(location.Scenarios);
}
}
return scenarios;
}
private List CreateScenarioListForCalculation()
{
List scenarios = new List(); ;
List locations = this.SelectedLocationJobs.Select(x => x.Location).ToList();
foreach (Location location in locations)
{
if (location.Scenarios != null)
{
scenarios.AddRange(location.Scenarios);
}
}
return scenarios;
}
///
/// Updates the design calculations.
///
public void UpdateDesignCalculations()
{
if (designCalculations == null)
{
designCalculations = new List();
}
else
{
designCalculations.Clear();
}
var scenarios = CreateScenarioListForCalculation();
foreach (Scenario scenario in scenarios)
{
if (scenario.CalculationResults != null && scenario.CalculationResults.Count > 0)
{
designCalculations.AddRange(scenario.CalculationResults);
}
}
DataEventPublisher.DataListModified(designCalculations);
}
[XmlIgnore]
public List CalculationMessages { get; set; }
[XmlIgnore]
[ReadOnly(true)]
public List DesignCalculations
{
get
{
if (designCalculations == null)
{
this.UpdateDesignCalculations();
}
return designCalculations;
}
set
{
designCalculations = value;
}
}
public SchematizationFactorData SchematizationFactorData
{
get { return schematizationFactorData; }
set
{
DataEventPublisher.BeforeChange(this, "SchematizationFactorData");
schematizationFactorData = value;
DataEventPublisher.AfterChange(this, "SchematizationFactorData");
}
}
public CalculationResult Validate()
{
try
{
//Todo validation has to extended, handling the actual messages instead of just CalculationResult too.
foreach (Dike dike in this.WaterBoard.Dikes)
{
dike.Validate();
}
return CalculationResult.Succeeded;
}
catch
{
return CalculationResult.InvalidInputData;
}
}
public LocationJob GetLocationJob(Location location)
{
foreach (LocationJob locationJob in this.LocationJobs)
{
if (locationJob.Location == location)
{
return locationJob;
}
}
return null;
}
[XmlIgnore]
[ReadOnly(true)]
[Browsable(false)]
public List LocationJobs
{
get
{
if (jobs.Count == 0)
{
CompositeJob waterboardJob = this.WaterBoardJob as CompositeJob;
foreach (CompositeJob dijkJob in waterboardJob.Jobs)
{
foreach (LocationJob locationJob in dijkJob.Jobs)
{
jobs.Add(locationJob);
}
}
}
return jobs;
}
}
public LocationJob GetFirstLocationJobWithDesignResults()
{
foreach (LocationJob locationJob in this.LocationJobs)
{
if (locationJob.HasDesignScenarioResults)
{
return locationJob;
}
}
return null;
}
public LocationJob GetFirstLocationJobWithCalamityResults()
{
foreach (LocationJob locationJob in this.LocationJobs)
{
if (locationJob.HasLocationResults)
{
return locationJob;
}
}
return null;
}
[XmlIgnore]
[ReadOnly(true)]
[Browsable(false)]
[Validate]
public List SelectedLocationJobs
{
get
{
List selectedLocationJobs = new List();
foreach (LocationJob locationJob in this.LocationJobs)
{
if (locationJob.Run.HasValue && locationJob.Run.Value)
{
selectedLocationJobs.Add(locationJob);
}
}
return selectedLocationJobs;
}
}
[Validate]
public ValidationResult[] ValidateEnoughLocationJobs()
{
if (this.SelectedLocationJobs.Count == 0)
{
return new ValidationResult[]
{
new ValidationResult(ValidationResultType.Error,
LocalizationManager.GetTranslatedText(this, "NoLocationsSelected"),
this)
};
}
else
{
return new ValidationResult[0];
}
}
[XmlIgnore]
[Browsable(false)]
[ReadOnly(true)]
[Label("Locations")]
public List Locations
{
get { return this.WaterBoard.Locations; }
}
[Browsable(false)]
public List DataSources
{
get { return dataSources; }
set { dataSources = value; }
}
[Browsable(false)]
public string DataSourceEsriProjection
{
get { return this.dataSourceEsriProjection; }
set { this.dataSourceEsriProjection = value; }
}
///
/// Gets or sets the sensor data.
///
///
/// The sensor data.
///
public SensorData SensorData
{
get { return sensorData; }
set { sensorData = value; }
}
///
/// Gets or sets the input time serie collection.
///
///
/// The input time serie collection.
///
public TimeSerieCollection InputTimeSerieCollection
{
get
{
return inputTimeSerieCollection;
}
set
{
inputTimeSerieCollection = value;
}
}
///
/// Gets or sets the output time serie collection.
///
///
/// The output time serie collection.
///
public TimeSerieCollection OutputTimeSerieCollection
{
get
{
return outputTimeSerieCollection;
}
set
{
outputTimeSerieCollection = value;
}
}
public void DeleteResults()
{
LogManager.Messages.Clear();
if (waterBoardJob != null && waterBoardJob.Jobs != null)
{
waterBoardJob.Jobs.Clear();
}
waterBoardJob = null;
if (jobs != null)
{
jobs.Clear();
}
// Delete calculationresults in scenarios
var scenarios = CreateScenarioListForDeletion();
foreach (Scenario scenario in scenarios)
{
scenario.ClearResults();
scenario.ClearErrors();
}
if (designCalculations != null)
{
designCalculations.Clear();
}
}
private int GetNumberOfCalculatedJobs()
{
var numberOfCalculatedJobs = 0;
foreach (LocationJob locationJob in this.LocationJobs)
{
if ((locationJob.Result != JobResult.NoRun) && locationJob.Run != null && locationJob.Run.Value)
{
foreach (Dike dike in this.WaterBoard.Dikes)
{
if (dike.Locations.Contains(locationJob.Location))
{
dike.UpdateLocation(locationJob.Location);
break;
}
}
numberOfCalculatedJobs++;
}
}
return numberOfCalculatedJobs;
}
public bool HasResults()
{
bool hasResults = waterBoard.Dikes.Count > 0 && waterBoardJob != null && waterBoardJob.Jobs.Count > 0;
if (hasResults)
{
hasResults = GetNumberOfCalculatedJobs() > 0;
}
return hasResults;
}
///
/// Check if design with geometry adaption is allowed
///
///
private bool IsDesignWithGeometryAdaptionAllowed()
{
bool isAdoption = this.DamProjectType == DamProjectType.Design && DamProjectCalculationSpecification.SelectedAnalysisType != AnalysisType.NoAdaption;
bool isStabilityOutside = this.DamProjectCalculationSpecification.DamCalculationSpecifications.Any(specification => specification.FailureMechanismSystemType == FailureMechanismSystemType.StabilityOutside);
return (!isAdoption || !isStabilityOutside);
}
///
/// Validates the geometry adaption setting.
///
///
[Validate]
public ValidationResult[] ValidateGeometryAdaptionSetting()
{
if (!IsDesignWithGeometryAdaptionAllowed())
{
return new[]{ new ValidationResult(ValidationResultType.Error, LocalizationManager.GetTranslatedText(this, "DesignAndAdaptionNotAllowedForStabilityOutside"),
this, "DamCalculationSpecifications", "DamCalculationSpecifications", null)};
}
else
{
return new ValidationResult[0];
}
}
public override bool IsVisible(string property)
{
switch (property)
{
case "SensorData": return damProjectType == DamProjectType.DamLiveConfiguration;
case "SchematizationFactors": return false;
//Bka: for now (release 1.4.1), do not show SchematizationFactors return this.HasResults() && this.DamProjectType == Data.DamProjectType.Assessment;
case "DesignCalculations": return this.HasResults() && this.DamProjectType == Data.DamProjectType.Design;
case "DamProjectCalculationSpecification":
return damProjectCalculationSpecification.DamCalculationSpecifications.Count > 0;
default: return true;
}
}
public ICollection GetDomain(string property)
{
switch (property)
{
default: return null;
}
}
public override string ToString()
{
return this.WaterBoard != null ? this.WaterBoard.Name : "";
}
public void Dispose()
{
WaterBoard.Dispose();
DamProjectCalculationSpecification.Dispose();
}
public void FillOverallSensorData()
{
if (sensorData != null)
{
sensorData.Sensors.Clear();
sensorData.SensorGroups.Clear();
sensorData.SensorLocations.Clear();
}
else
{
sensorData = new SensorData();
}
foreach (var location in Locations)
{
var sd = location.SensorLocation;
foreach (var sensor in sd.Sensors )
{
if (sensorData.GetSensorById(sensor.ID) == null)
{
sensorData.Sensors.Add(sensor);
}
}
if (sensorData.GetGroupById(sd.Group.ID) == null && sd.Group.ID != 0)
{
sd.Group.PickSensors = sensorData.Sensors;
sensorData.SensorGroups.Add(sd.Group);
}
if (sensorData.GetSensorLocationByLocationName(sd.LocationName) == null)
{
sensorData.SensorLocations.Add(sd);
}
}
}
}
}