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