// 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.Data; using System.Xml.Linq; using Deltares.DamEngine.Calculators.KernelWrappers.Common; using Deltares.DamEngine.Calculators.KernelWrappers.DamMacroStabilityCommon; using Deltares.DamEngine.Calculators.KernelWrappers.Interfaces; using Deltares.DamEngine.Calculators.Properties; using Deltares.DamEngine.Data.General; using Deltares.DamEngine.Data.General.Results; using Deltares.DamEngine.Data.Standard.Calculation; using Deltares.DamEngine.Data.Standard.Logging; using Deltares.DamMacroStability.Calculator; using System.IO; using Deltares.DamEngine.Calculators.DikesDesign; using Deltares.DamEngine.Data.Design; using Deltares.DamEngine.Data.Geometry; namespace Deltares.DamEngine.Calculators.KernelWrappers.DamMacroStabilityOutwards { /// /// Class for the wrapper around the Stability Outwards calculator /// /// public class DamMacroStabilityOutwardsKernelWrapper : IKernelWrapper { /// /// Gets or sets the failure mechanisme paramaters for mstab. /// /// /// The failure mechanisme paramaters mstab. /// public FailureMechanismParametersMStab FailureMechanismParametersMStab { get; set; } /// /// Gets or sets the index of the iteration. /// /// /// The index of the iteration. /// public int IterationIndex { get; set; } /// /// Prepares the specified dam kernel input. /// /// The dam kernel input. /// /// The kernel data input. /// The kernel data output /// /// Result of the prepare /// public PrepareResult Prepare(DamKernelInput damKernelInput, int iterationIndex, out IKernelDataInput kernelDataInput, out IKernelDataOutput kernelDataOutput) { try { var damMacroStabilityOutput = new DamMacroStabilityOutput() { StabilityOutputItems = new List(), CalculationResult = CalculationResult.NoRun }; kernelDataOutput = damMacroStabilityOutput; // Note: as segments and thus SubSoilScenario are generally divided into Piping versus Stability, // the actual SegmentFailureMechanismType would be set to StabilityInside rather than StabilityOutside // So check for both types. if (damKernelInput.SubSoilScenario.SegmentFailureMechanismType == FailureMechanismSystemType.StabilityOutside || damKernelInput.SubSoilScenario.SegmentFailureMechanismType == FailureMechanismSystemType.StabilityInside) { // Make sure the gridposition is Left. FailureMechanismParametersMStab.MStabParameters.GridPosition = MStabGridPosition.Left; FailureMechanismParametersMStab.ProjectWorkingPath = damKernelInput.CalculationDir; if (damKernelInput.SubSoilScenario.SoilProfileType == SoilProfileType.ProfileTypeStiFile) { damKernelInput.SubSoilScenario.FullStiFileName = Path.Combine(damKernelInput.ProjectDir, Path.Combine(damKernelInput.Location.StabilityOptions.SoilGeometries2DPath, damKernelInput.SubSoilScenario.StiFileName)); } // Determine whether there is uplift var upliftSituation = UpliftHelper.DetermineStabilityUplift(damKernelInput, true); damMacroStabilityOutput.UpliftSituation = upliftSituation; kernelDataOutput = damMacroStabilityOutput; var damMacroStabilityInput = new DamMacroStabilityInput() { DGeoStabilityExePath = FailureMechanismParametersMStab.DGeoStabilityExePath, DGeoStabilityInputFileName = DamMacroStabilityUtils.GetStabilityInputFileName(damKernelInput, iterationIndex, FailureMechanismParametersMStab.MStabParameters.Model, FailureMechanismParametersMStab.ProjectWorkingPath), FailureMechanismParametersMStab = FailureMechanismParametersMStab }; kernelDataInput = damMacroStabilityInput; // Write xml file XDocument xmlDocument = CreateMstabDamXmlDocument(damKernelInput, damMacroStabilityInput); // Use xml file to create sti file CreateStiFile(xmlDocument); return PrepareResult.Successful; } kernelDataInput = null; return PrepareResult.NotRelevant; } catch (Exception) { kernelDataInput = null; kernelDataOutput = null; return PrepareResult.Failed; } } /// /// Validates the specified kernel data input. /// /// The kernel data input. /// The kernel data output. /// The return messages. /// /// Number of errors that prevent a calculation /// public int Validate(IKernelDataInput kernelDataInput, IKernelDataOutput kernelDataOutput, out List messages) { var input = (DamMacroStabilityInput) kernelDataInput; messages = new List(); if (input.FailureMechanismParametersMStab.MStabParameters.ZonesType == MStabZonesType.ZoneAreas) { var message = new LogMessage(LogMessageType.Error, null, Resources.DamMacroStabilityKernelWrapper_OutsideWithZoneAreasNotAllowed); messages.Add(message); } return messages.Count; } /// /// Executes the kernel. /// /// The kernel data input. /// The kernel data output. /// The return messages. public void Execute(IKernelDataInput kernelDataInput, IKernelDataOutput kernelDataOutput, out List messages) { DamMacroStabilityOutput damMacroStabilityOutput = (DamMacroStabilityOutput) kernelDataOutput; messages = new List(); // start calculation var calculator = StabilityCalculator(kernelDataInput); calculator.Calculate(); // get results var results = calculator.GetResults(); if (results.Count > 0) { var damMacroStabilityOutputItem = new DamMacroStabilityOutputItem(); var input = (DamMacroStabilityInput)kernelDataInput; damMacroStabilityOutputItem.ProjectFileName = input.DGeoStabilityInputFileName; var zone1 = new DamMacroStabilityOutputItem.ResultsSingleZone { SafetyFactor = results[0].Zone1.SafetyFactor, CircleSurfacePointLeftXCoordinate = results[0].Zone1.CircleSurfacePointLeftXCoordinate, CircleSurfacePointRightXCoordinate = results[0].Zone1.CircleSurfacePointRightXCoordinate, }; damMacroStabilityOutputItem.Zone1Results = zone1; if (results[0].Zone2 != null) { var zone2 = new DamMacroStabilityOutputItem.ResultsSingleZone { SafetyFactor = results[0].Zone1.SafetyFactor, CircleSurfacePointLeftXCoordinate = results[0].Zone1.CircleSurfacePointLeftXCoordinate, CircleSurfacePointRightXCoordinate = results[0].Zone1.CircleSurfacePointRightXCoordinate, }; damMacroStabilityOutputItem.Zone2Results = zone2; } damMacroStabilityOutput.StabilityOutputItems.Add(damMacroStabilityOutputItem); } } internal XDocument CreateMstabDamXmlDocument(DamKernelInput damKernelInput, DamMacroStabilityInput kernelDataInput) { var stabilityProjectFilename = kernelDataInput.DGeoStabilityInputFileName; var modelFactors = damKernelInput.Location.ModelFactors; var subSoilScenario = damKernelInput.SubSoilScenario; var requiredSafetyFactor = modelFactors.RequiredSafetyFactorStabilityOuterSlope; if (requiredSafetyFactor == null) { throw new MacroStabilityException(Resources.DamMacroStabilityOutwardsKernelWrapper_Prepare_NoRequiredSafetyFactor); } List errorMessages; XDocument mstabXml = MStabXmlDoc.CreateMStabXmlDoc( stabilityProjectFilename, damKernelInput.Location, damKernelInput.RiverLevelHigh, damKernelInput.RiverLevelLow, subSoilScenario, null, requiredSafetyFactor.Value, kernelDataInput.FailureMechanismParametersMStab, damKernelInput.DamFailureMechanismeCalculationSpecification.AssessmentScenarioJobSettings, out errorMessages); mstabXml.Save(stabilityProjectFilename + ".xml"); return mstabXml; } internal void CreateStiFile(XDocument xmlDocument) { DGSMStabDAMInterface mstabDamDll = new DGSMStabDAMInterface(); var result = mstabDamDll.CreateProjectFile(xmlDocument.ToString()); if (result > 0) { string errorMessage = mstabDamDll.ErrorMessage(); throw new MacroStabilityException(errorMessage); } } internal static StabilityCalculator StabilityCalculator(IKernelDataInput kernelDataInput) { DamMacroStabilityInput damMacroStabilityInput = kernelDataInput as DamMacroStabilityInput; if (damMacroStabilityInput == null) { throw new NoNullAllowedException(Resources.DamMacroStabilityKernelWrapper_StabilityCalculator_NoInputObjectDefinedForMacroStability); } var calculator = new StabilityCalculator { ProjectName = damMacroStabilityInput.DGeoStabilityInputFileName, DGeoStabilityExePath = damMacroStabilityInput.DGeoStabilityExePath }; return calculator; } /// /// Fills the design results with the kernel output. /// /// The dam kernel input. /// The kernel data output. /// The result message. /// The design results. /// public void PostProcess(DamKernelInput damKernelInput, IKernelDataOutput kernelDataOutput, DesignScenario designScenario, string resultMessage, out List designResults) { DamMacroStabilityOutput damMacroStabilityOutput = kernelDataOutput as DamMacroStabilityOutput; if (damKernelInput == null) { throw new NoNullAllowedException(Resources.DamMacroStabilityKernelWrapper_StabilityCalculator_NoInputObjectDefinedForMacroStability); } if (damMacroStabilityOutput == null) { throw new NoNullAllowedException(Resources.DamMacroStabilityKernelWrapper_PostProcess_NoOutputObjectDefinedForMacroStability); } string soilProfile2DName = damKernelInput.SubSoilScenario.ToString(); designResults = new List(); var designResult = new DesignResult(damKernelInput.DamFailureMechanismeCalculationSpecification, designScenario, damKernelInput.SubSoilScenario.SoilProfile1D, soilProfile2DName) { // initialize as failed CalculationResult = CalculationResult.RunFailed }; // Outwards can have only one result as BishopUpliftVan as model is not allowed if (damMacroStabilityOutput.StabilityOutputItems.Count == 1) { var damMacroStabilityOutputItem = damMacroStabilityOutput.StabilityOutputItems[0]; designResult.BaseFileName = Path.GetFileNameWithoutExtension(damMacroStabilityOutputItem.ProjectFileName); var stabilityDesignResults = new StabilityDesignResults { Zone1SafetyFactor = damMacroStabilityOutputItem.Zone1Results.SafetyFactor, LocalZone1EntryPointX = damMacroStabilityOutputItem.Zone1Results.CircleSurfacePointRightXCoordinate, LocalZone1ExitPointX = damMacroStabilityOutputItem.Zone1Results.CircleSurfacePointLeftXCoordinate, ResultMessage = resultMessage, UpliftSituation = damMacroStabilityOutput.UpliftSituation }; // Overall safety factor is always the one as determined for Zone 1. The zone 2 factor is only informative. stabilityDesignResults.SafetyFactor = stabilityDesignResults.Zone1SafetyFactor; if (damMacroStabilityOutputItem.Zone2Results != null) { var zone2 = (DamMacroStabilityOutputItem.ResultsSingleZone)damMacroStabilityOutputItem.Zone2Results; stabilityDesignResults.Zone2SafetyFactor = zone2.SafetyFactor; stabilityDesignResults.LocalZone2EntryPointX = zone2.CircleSurfacePointRightXCoordinate; stabilityDesignResults.LocalZone2ExitPointX = zone2.CircleSurfacePointLeftXCoordinate; } stabilityDesignResults.RedesignedSurfaceLine = damKernelInput.Location.SurfaceLine; // In the actual sti file, the start of the surface line is always reset to 0. In order to keep all // the results that are based on the RedesignedSurfaceLine in sync, reset the surface line to 0 too. if (Math.Abs(stabilityDesignResults.RedesignedSurfaceLine.CharacteristicPoints[0].X) > 0) { var offset = stabilityDesignResults.RedesignedSurfaceLine.CharacteristicPoints[0].X; foreach (var characteristicPoint in stabilityDesignResults.RedesignedSurfaceLine.CharacteristicPoints) { characteristicPoint.X = characteristicPoint.X - offset; } } designResult.StabilityDesignResults = stabilityDesignResults; designResult.CalculationResult = damMacroStabilityOutputItem.CalculationResult; designResult.CalculationSubDir = DamMacroStabilityUtils.GetCalculationSubDir(damKernelInput.DamFailureMechanismeCalculationSpecification.StabilityModelType); } designResults.Add(designResult); } /// /// Calculates the design at point. /// /// The dam kernel input. /// The kernel data input. /// The kernel data output. /// The point. /// The messages. /// /// public ShoulderDesign CalculateDesignAtPoint(DamKernelInput damKernelInput, IKernelDataInput kernelDataInput, IKernelDataOutput kernelDataOutput, GeometryPoint point, out List messages) { throw new NotImplementedException(); } /// /// Evaluates the design (current factor greater than desired factor) /// /// The dam kernel input. /// The kernel data input. /// The kernel data output. /// The design advise. /// The evaluation message. /// /// if the design was succesful /// /// public bool EvaluateDesign(DamKernelInput damKernelInput, IKernelDataInput kernelDataInput, IKernelDataOutput kernelDataOutput, out DesignAdvise designAdvise, out string evaluationMessage) { throw new NotImplementedException(); } public void PrepareDesign(IKernelDataInput kernelDataInput, IKernelDataOutput kernelDataOutput, DamKernelInput damKernelInput, int iterationIndex, out EmbankmentDesignParameters embankmentDesignParameters) { throw new NotImplementedException(); } /// /// Gets the design strategy /// /// /// public DesignStrategy GetDesignStrategy(DamKernelInput damKernelInput) { return DesignStrategy.NoDesignPossible; } } }