// 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.IO; using System.Xml.Linq; using Deltares.DamEngine.Calculators.KernelWrappers.Common; using Deltares.DamEngine.Calculators.KernelWrappers.DamMacroStabilityCommon.Assemblers; using Deltares.DamEngine.Calculators.Properties; using Deltares.DamEngine.Data.Design; using Deltares.DamEngine.Data.General; using Deltares.DamEngine.Data.Geotechnics; using Deltares.DamEngine.Data.Standard.Logging; namespace Deltares.DamEngine.Calculators.KernelWrappers.DamMacroStabilityCommon { /// /// Class for raising specified exceptions for MStabXmlDoc objects /// /// public class MStabXmlDocException : Exception { /// /// Initializes a new instance of the class. /// /// The message that describes the error. public MStabXmlDocException(string message) : base(message) { } } /// /// Class for creating the xml-file for stability calculations using DGeoStability Delphi. /// public static class MStabXmlDoc { /// /// Create XML definition for Stability calculation /// /// /// /// /// /// /// /// /// public static XDocument CreateMStabXmlDoc(string mstabProjectFilename, Location location, double riverLevelHigh, double? riverLevelLow, SoilGeometryProbability subSoilScenario, MStabDesignEmbankment mstabDesignEmbankment, double requiredSafetyFactor, FailureMechanismParametersMStab inputFailureMechanismParametersMStab, out List errorMessages) { errorMessages = new List(); var profile1D = subSoilScenario.SoilProfile1D; var soilGeometry2DName = subSoilScenario.FullStiFileName; ConsistencyCheck(profile1D); var failureMechanismParametersMStab = inputFailureMechanismParametersMStab.Clone(); failureMechanismParametersMStab.Location = location; if (profile1D != null) { failureMechanismParametersMStab.SoilProfile = profile1D; // 1d-geometry failureMechanismParametersMStab.MStabParameters.GeometryCreationOptions.SoilProfileType = SoilProfileType.ProfileType1D; } else { // 2d-geometry failureMechanismParametersMStab.MStabParameters.GeometryCreationOptions.SoilProfileType = SoilProfileType.ProfileTypeStiFile; } // Geometry Creation Options failureMechanismParametersMStab.MStabParameters.GeometryCreationOptions.SoilGeometry2DFilename = soilGeometry2DName; failureMechanismParametersMStab.MStabParameters.GeometryCreationOptions.MaterialForDike = location.DikeEmbankmentMaterial; failureMechanismParametersMStab.MStabParameters.GeometryCreationOptions.MaterialForShoulder = location.ShoulderEmbankmentMaterial; failureMechanismParametersMStab.MStabParameters.GeometryCreationOptions.IsUseOriginalPlLineAssignments = location.IsUseOriginalPlLineAssignments; failureMechanismParametersMStab.MStabParameters.GeometryCreationOptions.IsDesign = (mstabDesignEmbankment != null); failureMechanismParametersMStab.MStabParameters.GeometryCreationOptions.XOffsetSoilGeometry2DOrigin = -location.XSoilGeometry2DOrigin; failureMechanismParametersMStab.MStabParameters.GeometryCreationOptions.PlLineAssignment = CalculationHelper.PlLineCreationMethod2PlLineAssignment(location.ModelParametersForPlLines.PlLineCreationMethod); if (location.IntrusionVerticalWaterPressure != null) failureMechanismParametersMStab.MStabParameters.GeometryCreationOptions.IntrusionVerticalWaterPressureType = location.IntrusionVerticalWaterPressure.Value; failureMechanismParametersMStab.MStabParameters.GeometryCreationOptions.PenetrationLength = location.ModelParametersForPlLines.PenetrationLength; // End of Geometry Creation Options // Design options failureMechanismParametersMStab.Design = mstabDesignEmbankment; failureMechanismParametersMStab.SurfaceLine = location.SurfaceLine; failureMechanismParametersMStab.RiverLevel = riverLevelHigh; failureMechanismParametersMStab.DikeTableHeight = location.SurfaceLine.GetDefaultDikeTableHeight() ?? 0; failureMechanismParametersMStab.TrafficLoad = location.StabilityOptions.TrafficLoad ?? 0; // Horizontal balance; TODO: Combine with code in StabilityCalculation if (failureMechanismParametersMStab.MStabParameters.Model == MStabModelType.HorizontalBalance) { if (profile1D == null) { throw new MStabXmlDocException( Resources.DamMacroStabilityKernelWrapper_HorBal2DProfNotAllowed); } failureMechanismParametersMStab.MStabParameters.HorizontalBalanceArea = new HorizontalBalanceArea { XLeft = location.SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtRiver).X, XRight = location.SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder).X, YTop = riverLevelHigh, YBottom = profile1D.InBetweenAquiferLayer?.TopLevel ?? profile1D.BottomAquiferLayer.TopLevel }; int planeCount = (int)(Math.Round((failureMechanismParametersMStab.MStabParameters.HorizontalBalanceArea.YTop - failureMechanismParametersMStab.MStabParameters.HorizontalBalanceArea.YBottom) / 0.25)); failureMechanismParametersMStab.MStabParameters.HorizontalBalanceArea.PlaneCount = Math.Min(planeCount, 50); } failureMechanismParametersMStab.MStabParameters.CalculationOptions.MinimalCircleDepth = location.StabilityOptions.MinimalCircleDepth ?? 0.0; failureMechanismParametersMStab.MStabParameters.CalculationOptions.ZonesType = location.StabilityOptions.StabilityZoneType; // Zonestype is ZoneAreas; TODO: Combine with code in StabilityCalculation if (failureMechanismParametersMStab.MStabParameters.CalculationOptions.ZonesType.Equals(MStabZonesType.ZoneAreas)) { var dikeTopAtPolder = location.SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder); double? dikeTableHeight = location.SurfaceLine.GetDefaultDikeTableHeight(); if (!dikeTableHeight.HasValue) throw new MStabXmlDocException("Surface line has no dike table height."); failureMechanismParametersMStab.MStabParameters.ZoneAreas = new MStabZoneAreas { DikeTableHeight = dikeTableHeight.Value, SafetyFactorZone1A = requiredSafetyFactor, SafetyFactorZone1B = requiredSafetyFactor, XCoordinateDikeTopAtPolder = dikeTopAtPolder.X, XCoordinateDikeTopAtRiver = location.SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver).X, XCoordinateStartRestProfile = location.SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver).X }; if (location.StabilityOptions?.ZoneAreaRestSlopeCrestWidth != null) { failureMechanismParametersMStab.MStabParameters.ZoneAreas.DikeTableWidth = location.StabilityOptions.ZoneAreaRestSlopeCrestWidth.Value; } } if (failureMechanismParametersMStab.MStabParameters.CalculationOptions.ZonesType.Equals(MStabZonesType.ForbiddenZone)) { failureMechanismParametersMStab.MStabParameters.ForbiddenZone = CreateForbiddenZone(location, location.SurfaceLine); } // Make sure riverlevel is correct with respect to surfaceline // double? riverLevelLow = null; // if (failureMechanismParametersMStab.MStabParameters.GridPosition == MStabGridPosition.Left && riverLevelLow.HasValue) // { // riverLevelLow = scenario.RiverLevelLow.Value; // } // double? riverLevelHigh = scenario.RiverLevel; var surfaceLevelOutside = location.SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.SurfaceLevelOutside); if (riverLevelHigh < surfaceLevelOutside.Z) { var riverLevelHighIsBelowSurfaceLevelOutside = Path.GetFileName(mstabProjectFilename) + ": " + Resources.MStabXmlDoc_CreateMStabXmlDoc_RiverLevelHighIsBelowSurfaceLevelOutside; LogMessage logMessage = new LogMessage(LogMessageType.Warning, null, string.Format(riverLevelHighIsBelowSurfaceLevelOutside, riverLevelHigh, surfaceLevelOutside.Z)); errorMessages.Add(logMessage); } // TODO #The folloing line shoukld be resolved for design // var currentSurfaceLine = scenario.GetMostRecentSurfaceLine(subSoilScenario.SoilProfile1D, Path.GetFileName(soilGeometry2DName)); SurfaceLine2 currentSurfaceLine = null; if (currentSurfaceLine == null) { currentSurfaceLine = location.SurfaceLine; } var waterLevel = riverLevelHigh; UpliftSituation upliftSituation; failureMechanismParametersMStab.PlLines = PlLinesHelper.CreatePlLinesForStability( location, subSoilScenario, waterLevel, soilGeometry2DName, riverLevelLow, out upliftSituation); // Slip circle definition for Uplift Van; TODO: Combine with code in StabilityCalculation if (failureMechanismParametersMStab.MStabParameters.Model == MStabModelType.UpliftVan) { // Determine right side of slip plane grid (right grid) // This is the location with the lowest uplift factor var upliftLocationAndResult = CalculationHelper.GetLocationWithLowestUpliftFactor(currentSurfaceLine, subSoilScenario.SoilProfile1D, soilGeometry2DName, failureMechanismParametersMStab.PlLines, location); double upliftCriterion = location.ModelFactors.UpliftCriterionStability.Value; bool isUplift = !(upliftLocationAndResult == null) && (upliftLocationAndResult.UpliftFactor < upliftCriterion); double xCoordinateLastUpliftPoint = isUplift ? upliftLocationAndResult.X : currentSurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder).X; failureMechanismParametersMStab.MStabParameters.SlipCircleDefinition.XCoordinateLastUpliftPoint = xCoordinateLastUpliftPoint; } failureMechanismParametersMStab.MStabParameters.ProjectFileName = mstabProjectFilename; failureMechanismParametersMStab.MStabParameters.SoilDatabaseName = location.StabilityOptions.SoilDatabaseName; if (!failureMechanismParametersMStab.IsComplete) { throw new Exception("Not all required data is available"); } DamMStabAssembler assembler = new DamMStabAssembler(); XDocument mstabXml = assembler.CreateDataTransferObject(failureMechanismParametersMStab); return mstabXml; } private static MStabForbiddenZone CreateForbiddenZone(Location location, SurfaceLine2 surfaceLine) { var dikeTopAtPolder = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder); // Zonestype is ForbiddenZone; TODO: Combine with code in StabilityCalculator? var zoneFactor = 1.0; if (location.StabilityOptions?.ForbiddenZoneFactor != null) { zoneFactor = location.StabilityOptions.ForbiddenZoneFactor.Value; } double maxZoneX = dikeTopAtPolder.X + zoneFactor * (surfaceLine.GetDikeToeInward().X - dikeTopAtPolder.X); return new MStabForbiddenZone { IsXEntryMinUsed = false, XEntryMin = 0.0, IsXEntryMaxUsed = true, XEntryMax = maxZoneX }; } private static void ConsistencyCheck(SoilProfile1D soilProfile) { if (soilProfile != null) { if (soilProfile.BottomAquiferLayer == null) { throw new MStabXmlDocException(String.Format( "Soilprofile '{0}' does not contain aquifer layers.", soilProfile.Name)); } } } } }