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