using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Xml.Linq; using Deltares.Dam.Data.Assemblers; using Deltares.Geotechnics; using Deltares.Standard; using Deltares.Standard.IO.Xml; using Deltares.Standard.Logging; namespace Deltares.Dam.Data { public class StabilityCalculation : ICalculation { private static int counter = 0; private SendMessageDelegate sendMessageDelegate = null; private string mStabExePath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + "\\DGeoStability.exe"; private string inputFile = null; private RWResult stabilityResult = new RWResult(); public DamFailureMechanismeCalculationSpecification GetSpecification(string dikeName, string soilDatabaseName, Location location, SoilGeometry soilGeometry, MStabModelType model, LoadSituation loadSituation, DikeDrySensitivity dikeDrySensitivity, HydraulicShortcutType hydraulicShortcutType, MStabParameters myMStabParameters) { string soilprofileName = ""; switch (soilGeometry.SoilGeometryType) { case SoilGeometryType.SoilGeometry1D: soilprofileName = soilGeometry.SoilProfile.Name; break; case SoilGeometryType.SoilGeometry2D: soilprofileName = soilGeometry.SoilGeometry2DName; break; } string calculationName = String.Format("Dik({0})_Loc({1})_Prof({2})_Stp({3})_Mdl({4})", dikeName, location.Name, soilprofileName, ++counter, model); calculationName = Regex.Replace(calculationName, @"[\\\/:\*\?""'<>|.]", "_"); string projectWorkingDirectory = Path.GetFullPath(DamProject.ProjectWorkingPath); string failureMechanismWorkingDirectory = String.Format(@"{0}\FM{1}\", projectWorkingDirectory, model); // assemble the target project file name string projectFileName = failureMechanismWorkingDirectory + calculationName + ".sti"; location.SoildatabaseName = soilDatabaseName; //Todo #Bka eigenlijk hier geen nieuwe failureParameters maar (clone van) de current gebruiken FailureMechanismeParamatersMStab failureParameters = new FailureMechanismeParamatersMStab(); failureParameters.Location = location; failureParameters.SurfaceLine = location.LocalXZSurfaceLine2; //Todo #Bka Wat is hiervan het nut? even verderop wordt geheel nieuw MStabParameters gemaakt.. failureParameters.MStabParameters.GeometryCreationOptions.SoilGeometryType = soilGeometry.SoilGeometryType; double waterLevel = loadSituation == LoadSituation.Dry ? location.BoezemLevelHbp : location.BoezemLevelTp; failureParameters.PLLines = CreateAllPLLines(location, soilGeometry, waterLevel, dikeDrySensitivity, loadSituation, hydraulicShortcutType); failureParameters.SoilProfile = soilGeometry.SoilProfile; //Todo #Bka Nieuwe maken zou eigenlijk niet meer mogen. Gewoon aanpassen geclonede waarden. failureParameters.MStabParameters = new MStabParameters(); failureParameters.MStabParameters.SoilDatabaseName = location.SoildatabaseName; failureParameters.MStabParameters.Model = model; failureParameters.MStabParameters.ProjectFileName = projectFileName; failureParameters.MStabParameters.GeometryCreationOptions.SoilGeometry2DFilename = location.GetMostProbableGeometry2DName(FailureMechanismSystemType.StabilityInside); failureParameters.MStabParameters.GeometryCreationOptions.MaterialForDike = location.DikeEmbankmentMaterial; failureParameters.MStabParameters.GeometryCreationOptions.MaterialForShoulder = location.ShoulderEmbankmentMaterial; failureParameters.MStabParameters.GeometryCreationOptions.XOffsetSoilGeometry2DOrigin = -location.XSoilGeometry2DOrigin; failureParameters.MStabParameters.GeometryCreationOptions.IsUseOriginalPLLineAssignments = location.IsUseOriginalPLLineAssignments; failureParameters.MStabParameters.GeometryCreationOptions.IsDrySituation = (dikeDrySensitivity == DikeDrySensitivity.Dry) && (loadSituation == LoadSituation.Dry); // Todo: check minimal circle depth MStabParameters mstabParameters = failureParameters.MStabParameters; mstabParameters.CalculationOptions.MinimalCircleDepth = location.MinimalCircleDepth; mstabParameters.CalculationOptions.ZonesType = location.StabilityZoneType; failureParameters.MStabParameters.ShearStrength = mstabParameters.ShearStrength; failureParameters.TrafficLoad = location.TrafficLoad; // Horizontal balance; TODO: Combine with code in StabilityCalculator and CalculationHelper.BuildDamCalculation if (mstabParameters.Model == MStabModelType.HorizontalBalance) { if (soilGeometry.SoilGeometryType == SoilGeometryType.SoilGeometry2D) { throw new DamFailureMechanismeCalculatorException("Model horizontal balance does not support 2d-geometries"); } mstabParameters.CalculationOptions.ZonesType = MStabZonesType.NoZones; mstabParameters.HorizontalBalanceArea = new HorizontalBalanceArea(); mstabParameters.HorizontalBalanceArea.XLeft = location.LocalXZSurfaceLine2.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtRiver).X; mstabParameters.HorizontalBalanceArea.XRight = location.LocalXZSurfaceLine2.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder).X; mstabParameters.HorizontalBalanceArea.YTop = waterLevel; mstabParameters.HorizontalBalanceArea.YBottom = soilGeometry.SoilProfile.InBetweenAquiferLayer != null ? soilGeometry.SoilProfile.InBetweenAquiferLayer.TopLevel : soilGeometry.SoilProfile.BottomAquiferLayer.TopLevel; int planeCount = (int)(Math.Round((mstabParameters.HorizontalBalanceArea.YTop - mstabParameters.HorizontalBalanceArea.YBottom) / 0.25)); mstabParameters.HorizontalBalanceArea.PlaneCount = Math.Min(planeCount, 50); } // If Dike table height is not known then use highest point of dike double? dth = location.DikeTableHeight; // Slip circle definition for Uplift Van; TODO: Combine with code in StabilityCalculator and CalculationHelper.BuildDamCalculation if (mstabParameters.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 = CalculationHelper.GetLocationWithLowestUpliftFactor(surfaceLine, location.GetMostProbableProfile(FailureMechanismSystemType.StabilityInside), soilprofileName, failureParameters.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; var nonWaterRetaining2 = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.NonWaterRetainingObjectPoint2); if (nonWaterRetaining2 != null) { xCoordinateLastUpliftPoint = nonWaterRetaining2.X; } } // Zonestype is ZoneAreas; TODO: Combine with code in StabilityCalculator and CalculationHelper.BuildDamCalculation if (mstabParameters.CalculationOptions.ZonesType.Equals(MStabZonesType.ZoneAreas)) { var dikeTopAtRiver = location.LocalXZSurfaceLine2.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtRiver); failureParameters.MStabParameters.ZoneAreas = new MStabZoneAreas { DikeTableHeight = dth.Value, DikeTableWidth = location.ZoneAreaRestSlopeCrestWidth, SafetyFactorZone1A = location.ModelFactors.RequiredSafetyFactorStabilityInnerSlope.Value, SafetyFactorZone1B = location.ModelFactors.RequiredSafetyFactorStabilityInnerSlope.Value, XCoordinateDikeTopAtPolder = location.LocalXZSurfaceLine2.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder).X, XCoordinateDikeTopAtRiver = dikeTopAtRiver.X, XCoordinateStartRestProfile = dikeTopAtRiver.X }; failureParameters.MStabParameters.ZoneAreas.XCoordinateStartRestProfile = dikeTopAtRiver.X; } // Zonestype is ForbiddenZone; TODO: Combine with code in StabilityCalculator and CalculationHelper.BuildDamCalculation if (mstabParameters.CalculationOptions.ZonesType.Equals(MStabZonesType.ForbiddenZone)) { var surfaceLine = location.LocalXZSurfaceLine2; var dikeTopAtPolder = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder); double maxZoneX = dikeTopAtPolder.X + location.ForbiddenZoneFactor * (surfaceLine.GetDikeToeInward().X - dikeTopAtPolder.X); failureParameters.MStabParameters.ForbiddenZone = new MStabForbiddenZone { IsXEntryMinUsed = false, XEntryMin = 0.0, IsXEntryMaxUsed = true, XEntryMax = maxZoneX }; } // GetSpecification is used in the Assesment calculations (RWScenarioCalculation) only so specifying a new specification // here is correct and does not interfere with specifications for Design. var damCalculation = new DamFailureMechanismeCalculationSpecification(); damCalculation.FailureMechanismeParamatersMStab = failureParameters; // Make sure to set the user defined values for search method and slip circle definition. damCalculation.FailureMechanismeParamatersMStab.MStabParameters.SearchMethod = myMStabParameters.SearchMethod; damCalculation.FailureMechanismeParamatersMStab.MStabParameters.SlipCircleDefinition = myMStabParameters.SlipCircleDefinition; return damCalculation; } public void SaveToFile(FailureMechanismeParamatersMStab failureMechanismeParamatersMStab) { var assembler = new DamMStabAssembler(); XDocument mstabXML = assembler.CreateDataTransferObject(failureMechanismeParamatersMStab); // call the stability agent to create a MStab specific (dto) file var agent = new StabilityServiceAgent(); agent.MStabExePath = MStabExePath; FileInfo file = new FileInfo(failureMechanismeParamatersMStab.MStabParameters.ProjectFileName); lock (file.DirectoryName) { if (!Directory.Exists(file.DirectoryName)) { Directory.CreateDirectory(file.DirectoryName); } } mstabXML.Save(failureMechanismeParamatersMStab.MStabParameters.ProjectFileName + ".xml"); agent.CreateProjectFile(mstabXML.ToString()); } /// /// Constructor /// private PLLines CreateAllPLLines(Location location, SoilGeometry soilGeometry, double waterLevel, DikeDrySensitivity dikeDrySensitivity, LoadSituation loadSituation, HydraulicShortcutType hydraulicShortcutType) { PLLinesCreator plLinesCreator = new PLLinesCreator(); plLinesCreator.WaterLevelRiverHigh = waterLevel; plLinesCreator.HeadInPLLine2 = location.HeadPL2; plLinesCreator.HeadInPLLine3 = location.HeadPl3; plLinesCreator.HeadInPLLine4 = location.HeadPl4; plLinesCreator.SurfaceLine = location.LocalXZSurfaceLine2; plLinesCreator.ModelParametersForPLLines = location.CreateModelParametersForPLLines(); plLinesCreator.SoilProfile = soilGeometry.SoilProfile; plLinesCreator.SoilGeometry2DName = soilGeometry.SoilGeometry2DName; plLinesCreator.SoilGeometryType = soilGeometry.SoilGeometryType; plLinesCreator.GaugePLLines = location.GaugePLLines; plLinesCreator.Gauges = location.Gauges; plLinesCreator.GaugeMissVal = location.GaugeMissVal; plLinesCreator.IsAdjustPL3AndPL4SoNoUpliftWillOccurEnabled = true; // for stability this must set to true if ((dikeDrySensitivity == DikeDrySensitivity.Dry) && (loadSituation == LoadSituation.Dry)) { // For dry situation other offsets have to be used as in normal situation plLinesCreator.PlLineOffsetBelowDikeTopAtRiver = location.PLLineOffsetDryBelowDikeTopAtRiver; plLinesCreator.PlLineOffsetBelowDikeTopAtPolder = location.PLLineOffsetDryBelowDikeTopAtPolder; plLinesCreator.PlLineOffsetBelowShoulderBaseInside = location.PLLineOffsetDryBelowShoulderBaseInside; plLinesCreator.PlLineOffsetBelowDikeToeAtPolder = location.PLLineOffsetDryBelowDikeToeAtPolder; plLinesCreator.PlLineOffsetBelowDikeCrestMiddle = location.PlLineOffsetDryBelowDikeCrestMiddle; plLinesCreator.PlLineOffsetFactorBelowShoulderCrest = location.PlLineOffsetDryFactorBelowShoulderCrest; plLinesCreator.UsePlLineOffsetBelowDikeCrestMiddle = location.UsePlLineOffsetDryBelowDikeCrestMiddle; plLinesCreator.UsePlLineOffsetFactorBelowShoulderCrest = location.UsePlLineOffsetDryFactorBelowShoulderCrest; plLinesCreator.WaterLevelPolder = location.PolderLevelLow; } else { plLinesCreator.PlLineOffsetBelowDikeTopAtRiver = location.PlLineOffsetBelowDikeTopAtRiver; plLinesCreator.PlLineOffsetBelowDikeTopAtPolder = location.PlLineOffsetBelowDikeTopAtPolder; plLinesCreator.PlLineOffsetBelowShoulderBaseInside = location.PlLineOffsetBelowShoulderBaseInside; plLinesCreator.PlLineOffsetBelowDikeToeAtPolder = location.PlLineOffsetBelowDikeToeAtPolder; plLinesCreator.PlLineOffsetBelowDikeCrestMiddle = location.PlLineOffsetBelowDikeCrestMiddle; plLinesCreator.PlLineOffsetFactorBelowShoulderCrest = location.PlLineOffsetFactorBelowShoulderCrest; plLinesCreator.UsePlLineOffsetBelowDikeCrestMiddle = location.UsePlLineOffsetBelowDikeCrestMiddle; plLinesCreator.UsePlLineOffsetFactorBelowShoulderCrest = location.UsePlLineOffsetFactorBelowShoulderCrest; plLinesCreator.WaterLevelPolder = location.PolderLevel; } plLinesCreator.SoilBaseDB = location.SoilbaseDB; plLinesCreator.SoilList = location.SoilList; if (!String.IsNullOrEmpty(location.DikeEmbankmentMaterial)) { plLinesCreator.DikeEmbankmentMaterial = location.SoilList.GetSoilByName(location.DikeEmbankmentMaterial); } plLinesCreator.IsUseOvenDryUnitWeight = (dikeDrySensitivity == DikeDrySensitivity.Dry); plLinesCreator.IsHydraulicShortcut = (hydraulicShortcutType == HydraulicShortcutType.HydraulicShortcut); plLinesCreator.XSoilGeometry2DOrigin = location.XSoilGeometry2DOrigin; PLLines plLines = plLinesCreator.CreateAllPLLines(location); // We used to have the following code her: // If no HeadPl4 is assigned and no hydraulic shortcut (scenarios 2, 4, 6, 8) then no PL4 should be assigned to the inbetween sandlayer // But by fixing issue MWDAM-156 this code was not necessary anymore and was removed return plLines; } #region ICalculation Members public CalculationResult GetResults(ref string results) { XmlSerializer serializer = new XmlSerializer(); results = serializer.SerializeToString(stabilityResult); return CalculationResult.Succeeded; } public CalculationResult Load(string input) { this.inputFile = input; return CalculationResult.Succeeded; } public CalculationResult RegisterGetValues(GetValuesDelegate getValuesDelegate) { return CalculationResult.UnexpectedError; } public CalculationResult RegisterProgress(ProgressDelegate progressDelegate) { return CalculationResult.UnexpectedError; } public CalculationResult RegisterSendDebugInfo(SendDebugInfodelegate sendDebugInfoDelegate) { return CalculationResult.UnexpectedError; } public CalculationResult RegisterSendMessage(SendMessageDelegate sendMessageDelegate) { this.sendMessageDelegate = sendMessageDelegate; return CalculationResult.Succeeded; } public CalculationResult RegisterSetValues(SetValuesDelegate setValuesDelegate) { return CalculationResult.UnexpectedError; } public CalculationResult RegisterUserAbort(UserAbortDelegate userAbortDelegate) { return CalculationResult.UnexpectedError; } public CalculationResult Run() { stabilityResult = new RWResult(); stabilityResult.CalculationResult = CalculationResult.UnexpectedError; StabilityServiceAgent agent = new StabilityServiceAgent(); try { agent.MStabExePath = MStabExePath; agent.CalculateMStabProject(inputFile); MStabResults result = agent.ExtractStabilityResults(inputFile); stabilityResult.SafetyFactor = result.zone1.safetyFactor; stabilityResult.RwResultType = RWResultType.SafetyFactor; stabilityResult.CalculationResult = CalculationResult.Succeeded; return CalculationResult.Succeeded; } catch (Exception exception) { if (sendMessageDelegate != null) { sendMessageDelegate.Invoke(new LogMessage(LogMessageType.Error, this, exception.Message)); } return CalculationResult.UnexpectedError; } } public CalculationResult Validate() { return CalculationResult.UnexpectedError; } #endregion public string Version { get { return System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(); } } public string MStabExePath { get { return mStabExePath; } set { mStabExePath = value; } } } }