// Copyright (C) Stichting Deltares 2017. 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.Globalization;
using System.IO;
using System.Text.RegularExpressions;
using System.Xml.Linq;
using Deltares.DamEngine.Calculators.Dikes_Operational;
using Deltares.DamEngine.Calculators.PlLinesCreator;
using Deltares.DamEngine.Calculators.Stability;
using Deltares.DamEngine.Calculators.Uplift;
using Deltares.DamEngine.Data.General;
using Deltares.DamEngine.Data.General.PlLines;
using Deltares.DamEngine.Data.General.Results;
using Deltares.DamEngine.Data.Geotechnics;
namespace Deltares.DamEngine.Calculators.General
{
public class StabilityProjectFileCreationArguments
{
public string DikeName { get; set; }
public Location Location { get; set; }
public int EntryCount { get; set; }
public DateTime EntryDateTime { get; set; }
public MStabModelType Model { get; set; }
public string StabilityWorkingPath { get; set; }
public string SoilGeometry2DName { get; set; }
public SoilGeometryType SoilGeometryType { get; set; }
public PLLines PLLines { get; set; }
public FailureMechanismSystemType FailureMechanismType { get; set; }
public MStabParameters StabilityParameters { get; set; }
public string StabilityExePath { get; set; }
}
internal class CalculationHelper
{
internal static string CreateStabilityProjectFile(StabilityProjectFileCreationArguments arg)
{
var location = arg.Location;
var model = arg.Model;
var fileName = GetProjectFileName(arg.DikeName, location, null, model, arg.StabilityWorkingPath, arg.EntryDateTime);
// get all the parameters needed for the calculation
var damCalculation = GetCalculationSpecification(arg, fileName);
// Create the project file
CreateMStabProjectFile(damCalculation.FailureMechanismeParamatersMStab, arg.StabilityExePath);
return fileName;
}
internal static IEnumerable GetStabilityModels(bool isCombinedBishopUpliftVan, Location location, PLLines plLines, string soilGeometry2DName, MStabModelType defaultModel)
{
double? upliftFactor = GetLowestUpliftFactor(location.LocalXZSurfaceLine2,
location.GetMostProbableProfile(FailureMechanismSystemType.StabilityInside), soilGeometry2DName, plLines, location);
return !isCombinedBishopUpliftVan ? new List { defaultModel } : GetMStabModelsToCalculate(upliftFactor);
}
internal static DamFailureMechanismeCalculationSpecification GetCalculationSpecification(StabilityProjectFileCreationArguments arguments, string projectFileName)
{
return GetCalculationSpecification(arguments.FailureMechanismType, arguments.Location,
arguments.SoilGeometry2DName, arguments.SoilGeometryType,
arguments.PLLines, arguments.StabilityParameters, arguments.Model,
arguments.Location.SoildatabaseName, projectFileName);
}
internal static DamFailureMechanismeCalculationSpecification GetCalculationSpecification(
FailureMechanismSystemType failureMechanismType,
Location location, string soilGeometry2DName,
SoilGeometryType soilGeometryType,
PLLines plLines,
MStabParameters mstabParameters, MStabModelType model,
string soilDatabasePath, string projectFileName)
{
// Note: local use of new calculationSpecification for now ok but might be unwanted in future when you want to use multiple specifications
var calculationSpecification = new DamFailureMechanismeCalculationSpecification();
BuildDamCalculation(failureMechanismType, location, soilGeometry2DName, soilGeometryType, plLines, mstabParameters, model, calculationSpecification, soilDatabasePath, projectFileName);
return calculationSpecification;
}
///
/// Fill damCalculation with the appropriate values
///
internal static void BuildDamCalculation(FailureMechanismSystemType failureMechanismType, Location location, string soilGeometry2DName, SoilGeometryType soilGeometryType,
PLLines plLines, MStabParameters mstabParameters, MStabModelType model,
DamFailureMechanismeCalculationSpecification damCalculation, string soilDatabasePath, string projectFileName)
{
damCalculation.FailureMechanismeParamatersMStab =
new FailureMechanismeParamatersMStab
{
Location = location,
SurfaceLine = location.LocalXZSurfaceLine2,
PLLines = plLines,
SoilProfile = location.GetMostProbableProfile(FailureMechanismSystemType.StabilityInside),
TrafficLoad = location.TrafficLoad,
MStabParameters =
new MStabParameters
{
SoilDatabaseName = soilDatabasePath,
Model = model,
ProjectFileName = projectFileName,
GeometryCreationOptions =
{
SoilGeometryType = soilGeometryType,
SoilGeometry2DFilename = soilGeometry2DName,
MaterialForDike = location.DikeEmbankmentMaterial,
MaterialForShoulder = location.ShoulderEmbankmentMaterial,
XOffsetSoilGeometry2DOrigin = -location.XSoilGeometry2DOrigin,
IsUseOriginalPLLineAssignments = location.IsUseOriginalPLLineAssignments
}
}
};
damCalculation.FailureMechanismeParamatersMStab.MStabParameters.GridPosition =
failureMechanismType == FailureMechanismSystemType.StabilityOutside ? MStabGridPosition.Left : MStabGridPosition.Right;
MStabParameters parameters = damCalculation.FailureMechanismeParamatersMStab.MStabParameters;
parameters.GeometryCreationOptions.PLLineAssignment = PLLineCreationMethod2PLLineAssignment(location.ModelParametersForPLLines.PLLineCreationMethod);
if (location.IsUseOriginalPLLineAssignments)
parameters.GeometryCreationOptions.PLLineAssignment = PLLineAssignment.OrginalPLLines;
parameters.GeometryCreationOptions.IntrusionVerticalWaterPressureType = location.IntrusionVerticalWaterPressure.Value;
parameters.GeometryCreationOptions.PenetrationLength = location.ModelParametersForPLLines.PenetrationLength;
switch (failureMechanismType)
{
case FailureMechanismSystemType.StabilityOutside:
parameters.GridPosition = MStabGridPosition.Left;
break;
default:
parameters.GridPosition = MStabGridPosition.Right;
break;
}
parameters.ShearStrength = mstabParameters.ShearStrength;
parameters.IsProbabilistic = mstabParameters.IsProbabilistic;
parameters.SearchMethod = mstabParameters.SearchMethod;
parameters.CalculationOptions = mstabParameters.CalculationOptions;
parameters.CalculationOptions.MinimalCircleDepth = location.MinimalCircleDepth;
parameters.ZoneAreas = new MStabZoneAreas
{
SafetyFactorZone1A = location.ModelFactors.RequiredSafetyFactorStabilityInnerSlope.Value,
SafetyFactorZone1B = location.ModelFactors.RequiredSafetyFactorStabilityInnerSlope.Value,
DikeTableHeight = location.SurfaceLine2.GetDefaultDikeTableHeight().Value,
DikeTableWidth = location.ZoneAreaRestSlopeCrestWidth,
XCoordinateDikeTopAtPolder = location.SurfaceLine2.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder).X,
XCoordinateDikeTopAtRiver = location.SurfaceLine2.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver).X,
XCoordinateStartRestProfile = location.SurfaceLine2.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver).X
};
// Slip circle definition for Uplift Van; TODO: Combine with code in StabilityCalculation
parameters.SlipCircleDefinition.Assign(mstabParameters.SlipCircleDefinition);
if (parameters.Model == MStabModelType.UpliftVan)
{
// Determine right side of slip plane grid (right grid)
// This is the location with the lowest uplift factor or, if present, the second NWO point
SurfaceLine2 surfaceLine = location.LocalXZSurfaceLine2;
var upliftLocationAndResult = GetLocationWithLowestUpliftFactor(surfaceLine, location.GetMostProbableProfile(FailureMechanismSystemType.StabilityInside), soilGeometry2DName, plLines, location);
double upliftCriterion = location.UpliftCriterionStability.Value;
bool isUplift = !(upliftLocationAndResult == null) && (upliftLocationAndResult.UpliftFactor < upliftCriterion);
double xCoordinateLastUpliftPoint = isUplift ? upliftLocationAndResult.X : surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder).X;
if (surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.NonWaterRetainingObjectPoint2) != null)
{
xCoordinateLastUpliftPoint = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.NonWaterRetainingObjectPoint2).X;
}
parameters.SlipCircleDefinition.XCoordinateLastUpliftPoint = xCoordinateLastUpliftPoint;
}
if (parameters.CalculationOptions.ZonesType.Equals(MStabZonesType.ForbiddenZone))
{
var surfaceLine = damCalculation.FailureMechanismeParamatersMStab.SurfaceLine;
double maxZoneX = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder).X +
location.ForbiddenZoneFactor * (surfaceLine.GetDikeToeInward().X - surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder).X);
parameters.ForbiddenZone = new MStabForbiddenZone
{
IsXEntryMinUsed = false,
XEntryMin = 0.0,
IsXEntryMaxUsed = true,
XEntryMax = maxZoneX
};
}
}
///
/// Converts PLLineCreationMethod (from location) to PLLineAssignment
///
/// The pl line creation method.
/// the pl line assignment method
public static PLLineAssignment PLLineCreationMethod2PLLineAssignment(PLLineCreationMethod plLineCreationMethod)
{
PLLineAssignment plLineAssignment = PLLineAssignment.ExpertKnowledge;
switch (plLineCreationMethod)
{
case PLLineCreationMethod.ExpertKnowledgeRRD:
case PLLineCreationMethod.ExpertKnowledgeLinearInDike:
case PLLineCreationMethod.GaugesWithFallbackToExpertKnowledgeRRD:
plLineAssignment = PLLineAssignment.ExpertKnowledge;
break;
}
return plLineAssignment;
}
///
/// Gets the location with lowest uplift factor.
///
/// The surface line.
/// The soil profile.
/// Name of the soil geometry2 D.
/// The pl lines.
/// The location.
///
static public UpliftLocationAndResult GetLocationWithLowestUpliftFactor(SurfaceLine2 surfaceLine, SoilProfile1D soilProfile, string soilGeometry2DName, PLLines plLines, Location location)
{
UpliftLocationDeterminator upliftLocationDeterminator = new UpliftLocationDeterminator()
{
SurfaceLine = surfaceLine,
SoilProfile = soilProfile,
SoilGeometry2DName = soilGeometry2DName,
SoilList = location.SoilList,
DikeEmbankmentMaterial = location.GetDikeEmbankmentSoil(),
PLLines = plLines,
XSoilGeometry2DOrigin = location.XSoilGeometry2DOrigin
};
return upliftLocationDeterminator.GetLocationAtWithLowestUpliftFactor();
}
///
/// Calculate all generated MStab files
///
///
///
internal static void CalculateMStabProjects(string directory, string mstabExePath)
{
var agent = new StabilityServiceAgent { MStabExePath = mstabExePath };
agent.CalculateMStabDirectory(directory);
}
///
/// Calculate all generated MStab files
///
internal static void CalculateMStabProjects(IEnumerable projectFilenames, string stabilityExePath)
{
var agent = new StabilityServiceAgent { MStabExePath = stabilityExePath };
foreach (string mstabProjectFilename in projectFilenames)
{
string mstabProjectFullFilename = Path.GetFullPath(mstabProjectFilename);
agent.CalculateMStabProject(mstabProjectFullFilename);
}
}
///
/// Determine name of Stability project file
///
internal static string GetProjectFileName(string dikeName, Location location, int? jobCount, MStabModelType? model, string stabilityWorkingPath, DateTime? dateTime)
{
string calculationName = String.Format("Dik({0})_Loc({1})", dikeName, location.Name);
if (jobCount != null)
{
calculationName = calculationName + String.Format("_Stp({0})", jobCount);
}
if (model != null)
{
calculationName = calculationName + String.Format("_Mdl({0})", model);
}
if (dateTime != null)
{
calculationName = calculationName + "_" + DateToTimeStamp(dateTime.Value);
}
calculationName = Regex.Replace(calculationName, @"[\\\/:\*\?""'<>|.]", "_");
// assemble the target project file name
return Path.Combine(stabilityWorkingPath, calculationName + ".sti");
}
///
/// Convert Date to time stamp as needed by TNO AnySense.
///
/// The date time.
///
public static string DateToTimeStamp(DateTime dateTime)
{
// Following 2 lines is an example how to handle customization of this format.
// TNO at the last moment decided they did not need this change so we change it back to
// the default format
// string customFormat = "yyyy-MM-dd_HH-mm-ss";
// return dateTime.ToString(customFormat);
return dateTime.ToString("s", DateTimeFormatInfo.InvariantInfo);
}
///
/// Select which models to calculate dependent on uplift factor
///
internal static IList GetMStabModelsToCalculate(double? upliftFactor)
{
const double CBishopMinimum = 1.0;
const double CLiftVanMaximum = 1.2;
var models = new List();
if (!upliftFactor.HasValue || upliftFactor >= CBishopMinimum)
models.Add(MStabModelType.Bishop);
if (!upliftFactor.HasValue || upliftFactor <= CLiftVanMaximum)
models.Add(MStabModelType.UpliftVan);
return models;
}
///
/// Determine where lowest uplift factor occurs and the value of that factor
///
internal static double? GetLowestUpliftFactor(SurfaceLine2 surfaceLine, SoilProfile1D soilProfile, string soilGeometry2DName, PLLines plLines, Location location)
{
var upliftLocationDeterminator = new UpliftLocationDeterminator()
{
SurfaceLine = surfaceLine,
SoilProfile = soilProfile,
SoilGeometry2DName = soilGeometry2DName,
SoilList = location.SoilList,
DikeEmbankmentMaterial = location.GetDikeEmbankmentSoil(),
PLLines = plLines,
XSoilGeometry2DOrigin = location.XSoilGeometry2DOrigin
};
UpliftLocationAndResult upliftLocationAndResult = upliftLocationDeterminator.GetLocationAtWithLowestUpliftFactor();
if (upliftLocationAndResult != null)
return upliftLocationAndResult.UpliftFactor;
return null;
}
///
/// Creates all PL lines.
///
/// The water level.
/// The location.
/// Name of the soil geometry2 D.
/// Type of the soil geometry.
///
internal static PLLines CreateAllPLLines(double waterLevel, Location location, string soilGeometry2DName, SoilGeometryType soilGeometryType)
{
// When calculating with timeseries, we want PL3 and PL4 to derive the head from the waterlevel.
// We can force that by overruling the location HeadPl3 and HeadPl4 with null,
// because then in PLLinesCreator the waterlevel is used as head for Pl3 and Pl4
// for stability this must set to true
var plLinesCreator = new PLLinesCreator
{
WaterLevelRiverHigh = waterLevel,
SurfaceLine = location.LocalXZSurfaceLine2,
WaterLevelPolder = location.PolderLevel,
HeadInPLLine2 = location.HeadPl2,
HeadInPLLine3 = null,
HeadInPLLine4 = null,
ModelParametersForPLLines = location.ModelParametersForPLLines,
SoilProfile = location.GetMostProbableProfile(FailureMechanismSystemType.StabilityInside),
SoilGeometry2DName = soilGeometry2DName,
SoilGeometryType = soilGeometryType,
GaugePLLines = location.GaugePLLines,
Gauges = location.Gauges,
GaugeMissVal = location.GaugeMissVal,
IsAdjustPL3AndPL4SoNoUpliftWillOccurEnabled = true,
PlLineOffsetBelowDikeTopAtRiver = location.PlLineOffsetBelowDikeTopAtRiver,
PlLineOffsetBelowDikeTopAtPolder = location.PlLineOffsetBelowDikeTopAtPolder,
PlLineOffsetBelowDikeCrestMiddle = location.PlLineOffsetBelowDikeCrestMiddle,
PlLineOffsetFactorBelowShoulderCrest = location.PlLineOffsetFactorBelowShoulderCrest,
UsePlLineOffsetBelowDikeCrestMiddle = location.UsePlLineOffsetBelowDikeCrestMiddle,
UsePlLineOffsetFactorBelowShoulderCrest = location.UsePlLineOffsetFactorBelowShoulderCrest,
SoilList = location.SoilList,
DikeEmbankmentMaterial = location.SoilList.GetSoilByName(location.DikeEmbankmentMaterial),
XSoilGeometry2DOrigin = location.XSoilGeometry2DOrigin
};
PLLines plLines = plLinesCreator.CreateAllPLLines(location);
return plLines;
}
///
/// Create and write the XML definiton file for the MStab project
/// Call the stability agent to create the stability project file
///
internal static void CreateMStabProjectFile(FailureMechanismeParamatersMStab failureMechanismeParamatersMStab, string stabilityExePath)
{
// var assembler = new DamMStabAssembler();
// XDocument xDocument = assembler.CreateDataTransferObject(failureMechanismeParamatersMStab);
// var fileName = failureMechanismeParamatersMStab.MStabParameters.ProjectFileName + ".xml";
// xDocument.Save(fileName);
//
// // call the stability agent to create a MStab specific (xml) file
// var agent = new StabilityServiceAgent { MStabExePath = stabilityExePath };
// agent.CreateProjectFile(xDocument.ToString()); ##Bka: to be rplaced by interface call to kernel.
}
///
/// Determine the minimal safety factor for a set of MStab projects
///
internal static double DetermineSafetyFactor(IEnumerable mstabProjectPaths, ref string basisFileName, string stabilityExePath)
{
var agent = new StabilityServiceAgent { MStabExePath = stabilityExePath };
double? minimumSafetyFactor = null;
foreach (string path in mstabProjectPaths)
{
MStabResults mStabResults = agent.ExtractStabilityResults(path);
if (!minimumSafetyFactor.HasValue || mStabResults.zone1.safetyFactor < minimumSafetyFactor)
{
minimumSafetyFactor = mStabResults.zone1.safetyFactor;
basisFileName = path;
}
}
return minimumSafetyFactor ?? 0;
}
public static SoilGeometryBase GetSoilGeometryType(Location location, string workingPath)
{
var geom = GetSoilGeometryType(location);
if (!geom.SoilGeometryName.Contains(workingPath))
geom.SoilGeometryName = Path.Combine(workingPath, geom.SoilGeometryName);
return geom;
}
private static SoilGeometryBase GetSoilGeometryType(Location location)
{
SoilGeometryType soilGeometryType;
string soilGeometry2DName;
DetermineSoilGeometryType(location, out soilGeometryType, out soilGeometry2DName);
return new SoilGeometryBase { SoilGeometryType = soilGeometryType, SoilGeometryName = soilGeometry2DName };
}
///
/// Determines the type of the soil geometry (1D or 2D).
///
/// The location.
/// Type of the soil geometry.
/// Name of the soil geometry2 D.
internal static void DetermineSoilGeometryType(Location location, out SoilGeometryType soilGeometryType, out string soilGeometry2DName)
{
SoilProfile1D soilProfile = location.GetMostProbableProfile(FailureMechanismSystemType.StabilityInside);
soilGeometry2DName = location.GetMostProbableGeometry2DName(FailureMechanismSystemType.StabilityInside);
string mapForSoilGeometries2D = location.MapForSoilGeometries2D;
if ((soilGeometry2DName != null) && (mapForSoilGeometries2D != null))
{
soilGeometry2DName = Path.Combine(mapForSoilGeometries2D, soilGeometry2DName);
}
if (soilProfile != null)
{
soilGeometryType = SoilGeometryType.SoilGeometry1D;
}
else
{
if (soilGeometry2DName == null)
{
throw new TimeSerieStabilityCalculatorException(String.Format("Location {0} does not have a soilprofile assigned", location.Name));
}
soilGeometryType = SoilGeometryType.SoilGeometry2D;
}
}
}
}