// 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, DesignScenario scenario, SoilGeometryProbability subSoilScenario, MStabDesignEmbankment mstabDesignEmbankment, double requiredSafetyFactor, FailureMechanismParametersMStab inputFailureMechanismParametersMStab, out List errorMessages) { errorMessages = new List(); var profile1D = subSoilScenario.SoilProfile1D; var soilGeometry2DName = subSoilScenario.FullStiFileName; ConsistencyCheck(scenario, profile1D); var failureMechanismParametersMStab = inputFailureMechanismParametersMStab.Clone(); failureMechanismParametersMStab.Location = scenario.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 = scenario.Location.DikeEmbankmentMaterial; failureMechanismParametersMStab.MStabParameters.GeometryCreationOptions.MaterialForShoulder = scenario.Location.ShoulderEmbankmentMaterial; failureMechanismParametersMStab.MStabParameters.GeometryCreationOptions.IsUseOriginalPLLineAssignments = scenario.Location.IsUseOriginalPLLineAssignments; failureMechanismParametersMStab.MStabParameters.GeometryCreationOptions.IsDesign = (mstabDesignEmbankment != null); failureMechanismParametersMStab.MStabParameters.GeometryCreationOptions.XOffsetSoilGeometry2DOrigin = -scenario.Location.XSoilGeometry2DOrigin; failureMechanismParametersMStab.MStabParameters.GeometryCreationOptions.PLLineAssignment = CalculationHelper.PlLineCreationMethod2PlLineAssignment(scenario.Location.ModelParametersForPLLines.PlLineCreationMethod); if (scenario.Location.IntrusionVerticalWaterPressure != null) failureMechanismParametersMStab.MStabParameters.GeometryCreationOptions.IntrusionVerticalWaterPressureType = scenario.Location.IntrusionVerticalWaterPressure.Value; failureMechanismParametersMStab.MStabParameters.GeometryCreationOptions.PenetrationLength = scenario.Location.ModelParametersForPLLines.PenetrationLength; // End of Geometry Creation Options // Design options failureMechanismParametersMStab.Design = mstabDesignEmbankment; failureMechanismParametersMStab.SurfaceLine = scenario.Location.SurfaceLine; failureMechanismParametersMStab.RiverLevel = scenario.RiverLevel; failureMechanismParametersMStab.DikeTableHeight = scenario.DikeTableHeight ?? scenario.Location.SurfaceLine.GetDefaultDikeTableHeight() ?? 0; failureMechanismParametersMStab.TrafficLoad = scenario.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 = scenario.Location.SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtRiver).X, XRight = scenario.Location.SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder).X, YTop = scenario.RiverLevel, 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 = scenario.Location.StabilityOptions.MinimalCircleDepth ?? 0.0; failureMechanismParametersMStab.MStabParameters.CalculationOptions.ZonesType = scenario.Location.StabilityOptions.StabilityZoneType; // Zonestype is ZoneAreas; TODO: Combine with code in StabilityCalculation if (failureMechanismParametersMStab.MStabParameters.CalculationOptions.ZonesType.Equals(MStabZonesType.ZoneAreas)) { var dikeTopAtPolder = scenario.Location.SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder); double? dikeTableHeight = scenario.DikeTableHeight ?? scenario.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 = scenario.Location.SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver).X, XCoordinateStartRestProfile = scenario.Location.SurfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver).X }; if (scenario.Location.StabilityOptions?.ZoneAreaRestSlopeCrestWidth != null) { failureMechanismParametersMStab.MStabParameters.ZoneAreas.DikeTableWidth = scenario.Location.StabilityOptions.ZoneAreaRestSlopeCrestWidth.Value; } } if (failureMechanismParametersMStab.MStabParameters.CalculationOptions.ZonesType.Equals(MStabZonesType.ForbiddenZone)) { failureMechanismParametersMStab.MStabParameters.ForbiddenZone = CreateForbiddenZone(scenario, scenario.Location.SurfaceLine); } // Make sure riverlevel is correct with respect to surfaceline double? riverLevelLow = null; if (failureMechanismParametersMStab.MStabParameters.GridPosition == MStabGridPosition.Left && scenario.RiverLevelLow.HasValue) { riverLevelLow = scenario.RiverLevelLow.Value; } double? riverLevelHigh = scenario.RiverLevel; var surfaceLevelOutside = scenario.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); } var currentSurfaceLine = scenario.GetMostRecentSurfaceLine(subSoilScenario.SoilProfile1D, Path.GetFileName(soilGeometry2DName)); if (currentSurfaceLine == null) { currentSurfaceLine = scenario.Location.SurfaceLine; } var waterLevel = riverLevelHigh.Value; UpliftSituation upliftSituation; failureMechanismParametersMStab.PLLines = PlLinesHelper.CreatePlLinesForStability( scenario.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, scenario.Location); double upliftCriterion = scenario.GetUpliftCriterionStability(scenario.Location.ModelFactors.UpliftCriterionStability); 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 = scenario.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(DesignScenario scenario, SurfaceLine2 surfaceLine) { var dikeTopAtPolder = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder); // Zonestype is ForbiddenZone; TODO: Combine with code in StabilityCalculator? var zoneFactor = 1.0; if (scenario.Location.StabilityOptions?.ForbiddenZoneFactor != null) { zoneFactor = scenario.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(DesignScenario scenario, SoilProfile1D soilProfile) { if (soilProfile != null) { if (soilProfile.BottomAquiferLayer == null) { throw new MStabXmlDocException(String.Format( "Scenario {0}: Soilprofile '{1}' does not contain aquifer layers.", scenario.LocationScenarioID, soilProfile.Name)); } } } } }