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