// Copyright (C) Stichting Deltares 2018. All rights reserved.
//
// This file is part of the Dam Engine.
//
// The Dam Engine is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero 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.Generic;
using System.ComponentModel;
using System.Linq;
using Deltares.DamEngine.Data.Design;
using Deltares.DamEngine.Data.General.Gauges;
using Deltares.DamEngine.Data.General.PlLines;
using Deltares.DamEngine.Data.Geotechnics;
using Deltares.DamEngine.Data.Standard;
using Deltares.DamEngine.Data.Standard.Language;
using Deltares.DamEngine.Data.Standard.Logging;
namespace Deltares.DamEngine.Data.General
{
///
/// Exception class for the Dike class
///
///
public class DikeException : Exception
{
///
/// Initializes a new instance of the class.
///
/// The message that describes the error.
public DikeException(string message)
: base(message)
{
}
}
///
/// Class for the dike parameter names
///
public class DikeParameterNames
{
///
/// The map for soilgeometries2d
///
public const string MapForSoilGeometries2D = "MapForSoilGeometries2D";
}
///
/// Class holding all info for a Dike.
///
public class Dike
{
private string description = "";
public virtual string MapForSoilGeometries2D { get; set; }
private IList locations;
private IList pl1Lines;
private bool removeStiFiles;
private MStabShearStrength shearmodel;
private SoilList soilList;
private IList gauges = new List();
private IList gaugePLLines = new List();
private IList soilProfiles;
private IList soilProfiles2D;
private List databaseSoils = new List();
///
/// Initializes a new instance of the class.
///
public Dike()
{
Name = "Dijkring";
MapForSoilGeometries2D = "";
locations = new List();
soilProfiles = new List();
soilProfiles2D = new List();
// this.surfaceLines = new DelegatedList { AddMethod = ConvertAddedOldSurfaceLineToNewFormat };
SurfaceLines2 = new List();
pl1Lines = new List();
soilList = new SoilList();
removeStiFiles = true;
}
public bool IsRemoveStiFiles { get { return removeStiFiles; } set { removeStiFiles = value; } }
public MStabShearStrength ShearStrengthModel { get { return shearmodel; } set { shearmodel = value; } }
public virtual string Name { get; set; }
///
/// Updates the locations for scenarios.
///
public void UpdateLocationsForScenarios()
{
foreach (Location location in this.Locations)
{
foreach (DesignScenario scenario in location.Scenarios)
{
scenario.Location = location;
}
}
}
///
/// Gets the locations.
///
///
/// The locations.
///
public virtual IList Locations
{
get { return this.locations; }
private set { this.locations = value; }
}
///
/// Sorts the locations.
///
public void SortLocations()
{
this.locations = this.Locations.OrderBy(o => o.Name).ToList();
}
public IList SurfaceLines2 { get; set; }
public virtual IList PL1Lines
{
get { return this.pl1Lines; }
set { this.pl1Lines = value; }
}
public virtual IList SoilProfiles
{
get { return this.soilProfiles; }
set { this.soilProfiles = value; }
}
///
/// Gets or sets the soilprofiles2d.
///
///
/// The soilprofiles2d.
///
public virtual IList SoilProfiles2D
{
get { return soilProfiles2D; }
set { soilProfiles2D = value; }
}
public virtual SoilList SoilList
{
get { return this.soilList; }
set { this.soilList = value; }
}
[Browsable(false)]
public virtual IList Gauges
{
get { return this.gauges; }
set { this.gauges = value; }
}
[Browsable(false)]
public virtual IList GaugePLLines
{
get { return this.gaugePLLines; }
set { this.gaugePLLines = value; }
}
public bool UsesGauges { get { return this.GaugePLLines != null && this.GaugePLLines.Count > 0 && this.Gauges != null; } }
public virtual List Scenarios
{
get
{
var scenarios = new List();
foreach (Location location in Locations)
{
scenarios.AddRange(location.Scenarios);
}
return scenarios;
}
}
public string Description
{
get { return description; }
set { description = value; }
}
public void Validate()
{
if (Locations == null || Locations.Count < 1)
{
throw new DikeException("The dike ring has no locations defined");
}
foreach (Location location in Locations)
{
if (location.SurfaceLine != null)
{
var validator = new SurfaceLine2Validator();
var validationResults = validator.ValidateCharacteristicPointsAreOrdered(location.SurfaceLine)
.Concat(validator.ValidateGeometryPointsAreOrdered(location.SurfaceLine)).ToArray();
if (validationResults.Length > 0)
{
throw new SurfaceLineException(validationResults[0].Text);
}
}
}
}
///
/// Adapt data so it is consistent
///
public List MakeDataConsistent()
{
var errorSoils = TryToMakeSoilDataConsistent();
var logMessages = new List();
// Delete all locations without surfaceline
logMessages.AddRange(DeleteLocationsWithoutSurfaceLines());
// Delete all locations that have profiles (in their segment) which hold soils
// that are not in the soil database and so have no parameters.
logMessages.AddRange(DeleteLocationsWithProfilesWithUnknownSoils(errorSoils));
return logMessages;
}
///
/// Tries to make the soil data as read for 1D profiles consistent with the data in the soil database.
/// In the end we have a neat soil list with parameters for every soil as read from the database.
/// We might have a list with errors (soils that were not to be found in the database so soils for which
/// no parameters could be found).
///
///
private List TryToMakeSoilDataConsistent()
{
var errorSoils = new List();
// Fill the list of errorSoils with soils that are in the current soillist (as result of importing
// 1D profiles) but that are not found in the soil database because that are errors
foreach (var soil in soilList.Soils)
{
var fs = databaseSoils.Find(t => String.Equals(t.Name, soil.Name, StringComparison.CurrentCultureIgnoreCase));
if (fs == null)
{
errorSoils.Add(soil);
}
}
// Remove the error soils form the list
foreach (var errorSoil in errorSoils)
{
soilList.Soils.Remove(errorSoil);
}
// Get the parameters for every soil in the now proper soil list from the database. Add soils
// that are in the database but not yet in the soil list.
foreach (Soil soil in databaseSoils)
{
Soil existingSoil = this.soilList.GetSoilByName(soil.Name);
if (existingSoil == null)
{
this.soilList.Soils.Add(soil);
}
else
{
existingSoil.Assign(soil);
}
}
return errorSoils;
}
///
/// Removes all locations which have profiles that have invalid soils
///
private List DeleteLocationsWithProfilesWithUnknownSoils(List invalidSoils)
{
var logMessages = new List();
var invalidLocations = new List();
string soilProf;
string invSoil;
foreach (var location in locations)
{
bool isInValid;
string message = "";
if (location.Segment == null)
{
isInValid = true;
message = String.Format(LocalizationManager.GetTranslatedText(this.GetType(), "LocationWitNameHasNoSegment"), location.Name);
}
else
{
isInValid = DoesLocationHaveInvalidSoils(invalidSoils, location, out soilProf, out invSoil);
if (isInValid)
{
message = String.Format(LocalizationManager.GetTranslatedText(this.GetType(), "locationHasProfileWithInvalidSoils"), location.Name, soilProf, invSoil);
}
}
if (isInValid)
{
invalidLocations.Add(location);
logMessages.Add(new LogMessage(LogMessageType.Warning, this, message));
}
}
foreach (var invalidLocation in invalidLocations)
{
locations.Remove(invalidLocation);
}
return logMessages;
}
///
/// Checks wether a location (or rather the soilprofiles in the segement of the location) contains invalid soils.
/// A soil is hereby considered invalid if it is not found in the database.
///
///
///
///
///
///
private bool DoesLocationHaveInvalidSoils(List invalidSoils, Location location, out string soilProf, out string invSoil)
{
soilProf = " ";
invSoil = " ";
foreach (var spp in location.Segment.SoilProfileProbabilities)
{
foreach (var invalidSoil in invalidSoils)
{
var fl = spp.SoilProfile1D.Layers.Find(l => String.Equals(l.Soil.Name, invalidSoil.Name, StringComparison.CurrentCultureIgnoreCase));
if (fl != null)
{
soilProf = spp.SoilProfile1D.Name;
invSoil = invalidSoil.Name;
return true;
}
}
}
return false;
}
///
/// Delete all locations without surfacelines
///
private List DeleteLocationsWithoutSurfaceLines()
{
var logMessages = new List();
//Add all locations with valid surfaceline
var newLocations = new List();
newLocations.AddRange(this.Locations.Where(loc => loc.SurfaceLine != null));
// Report which locations are not added because no valid surfaceline is found
var deletedLocations = new List();
deletedLocations.AddRange(this.Locations.Where(loc => loc.SurfaceLine == null));
foreach (var deletedLocation in deletedLocations)
{
var locationHasNoSurfaceLine = LocalizationManager.GetTranslatedText(this.GetType(), "LocationHasNoSurfaceLine");
logMessages.Add(new LogMessage(LogMessageType.Warning, this,
String.Format(locationHasNoSurfaceLine, deletedLocation.Name)));
}
this.Locations = newLocations;
return logMessages;
}
public override string ToString()
{
return this.Name;
}
public Dictionary GetParametersAsNameValuePairs()
{
var nameValuePairs = new Dictionary();
nameValuePairs.Add(DikeParameterNames.MapForSoilGeometries2D, MapForSoilGeometries2D);
return nameValuePairs;
}
public void SetParameterFromNameValuePair(string parameterName, string parameterValue)
{
if (parameterName.Equals(DikeParameterNames.MapForSoilGeometries2D))
this.MapForSoilGeometries2D = parameterValue;
}
public void UpdateLocation(Location location)
{
location.SoilList = this.SoilList;
if (location.StabilityOptions != null)
{
location.StabilityOptions.MapForSoilGeometries2D = this.MapForSoilGeometries2D;
}
location.Gauges.Clear();
location.Gauges.AddRange(Gauges);
location.GaugePLLines.Clear();
location.GaugePLLines.AddRange(GaugePLLines);
}
}
}