// 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.IO; using System.Xml.Linq; using Deltares.DamEngine.Calculators.DikesDesign; 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.Design; using Deltares.DamEngine.Data.General; using Deltares.DamEngine.Data.General.Results; using Deltares.DamEngine.Data.Geometry; using Deltares.DamEngine.Data.Standard.Calculation; using Deltares.DamEngine.Data.Standard.Logging; using Deltares.DamMacroStability.Calculator; using Deltares.DamEngine.Data.Geotechnics; namespace Deltares.DamEngine.Calculators.KernelWrappers.DamMacroStabilityInwards { public class DamMacroStabilityInwardsKernelWrapper : IKernelWrapper { /// /// Gets or sets the failure mechanisme paramaters for mstab. /// /// /// The failure mechanisme paramaters mstab. /// public FailureMechanismParametersMStab FailureMechanismParametersMStab { get; set; } private int lastIterationIndex = 0; /// /// Prepares the specified dam kernel input. /// /// The dam kernel input. /// The number of the current iteration. /// 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) { var damMacroStabilityOutput = new DamMacroStabilityOutput() { StabilityOutputItems = new List(), CalculationResult = CalculationResult.NoRun }; kernelDataOutput = damMacroStabilityOutput; if (damKernelInput.DamFailureMechanismeCalculationSpecification == null) { damKernelInput.DamFailureMechanismeCalculationSpecification = new DamFailureMechanismeCalculationSpecification(); } // Make sure the gridposition is Right. FailureMechanismParametersMStab.MStabParameters.GridPosition = MStabGridPosition.Right; // Make sure no riverlevellow is defined, because this will trigger Outside stability code elsewhere damKernelInput.RiverLevelLow = null; if (damKernelInput.SubSoilScenario.SegmentFailureMechanismType == FailureMechanismSystemType.StabilityInside) { var bishopUpliftVan = FailureMechanismParametersMStab.MStabParameters.Model == MStabModelType.BishopUpliftVan; var model = FailureMechanismParametersMStab.MStabParameters.Model; if (bishopUpliftVan) { // if current model is BishopUpliftVan then set to Bishop for proper name/path for inputfile model = MStabModelType.Bishop; } 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)); } var damMacroStabilityInput = new DamMacroStabilityInput() { DGeoStabilityExePath = FailureMechanismParametersMStab.DGeoStabilityExePath, DGeoStabilityInputFileName = DamMacroStabilityUtils.GetStabilityInputFileName( damKernelInput, iterationIndex, model, FailureMechanismParametersMStab.ProjectWorkingPath), FailureMechanismParametersMStab = FailureMechanismParametersMStab }; // Determine whether there is uplift var upliftSituation = UpliftHelper.DetermineStabilityUplift(damKernelInput, false); damMacroStabilityOutput.UpliftSituation = upliftSituation; kernelDataOutput = damMacroStabilityOutput; // Check the model to see what is to be calculated and how many calculations are required if (bishopUpliftVan) { // see if uplift is required // if so, both upliftvan and bishop are to be prepared, calculated and worst case is to be determined model = MStabModelType.UpliftVan; damMacroStabilityInput.DGeoStabilityInputFileNameSecondModel = DamMacroStabilityUtils.GetStabilityInputFileName(damKernelInput, iterationIndex, model, FailureMechanismParametersMStab.ProjectWorkingPath); // if not, only Bishop calculation so leave SecondModel empty. } kernelDataInput = damMacroStabilityInput; // When BishopUpliftVan is performed, make sure the first one is Bishop if (bishopUpliftVan) { damMacroStabilityInput.FailureMechanismParametersMStab.MStabParameters.Model = MStabModelType.Bishop; } try { // start prepare for (first) calculation // Write xml file XDocument xmlDocument = CreateMstabDamXmlDocument(damKernelInput, damMacroStabilityInput); // Use xml file to create sti file CreateStiFile(xmlDocument); // now check if second calculation for BishopUpliftVan is needed, if so perform prepare. if (bishopUpliftVan) { // reset model damMacroStabilityInput.FailureMechanismParametersMStab.MStabParameters.Model = MStabModelType.BishopUpliftVan; if (upliftSituation.IsUplift) { var inputFileName = damMacroStabilityInput.DGeoStabilityInputFileName; // set proper name and model damMacroStabilityInput.DGeoStabilityInputFileName = damMacroStabilityInput.DGeoStabilityInputFileNameSecondModel; damMacroStabilityInput.FailureMechanismParametersMStab.MStabParameters.Model = MStabModelType.UpliftVan; try { // Write xml file xmlDocument = CreateMstabDamXmlDocument(damKernelInput, damMacroStabilityInput); // Use xml file to create sti file CreateStiFile(xmlDocument); } finally { // reset name damMacroStabilityInput.DGeoStabilityInputFileName = inputFileName; } } } } finally { if (bishopUpliftVan) { // reset model damMacroStabilityInput.FailureMechanismParametersMStab.MStabParameters.Model = MStabModelType.BishopUpliftVan; } } return PrepareResult.Successful; } kernelDataInput = null; return PrepareResult.NotRelevant; } /// /// 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) { // calculator has no Validate. messages = new List(); 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(); var input = (DamMacroStabilityInput)kernelDataInput; // When BishopUpliftVan is performed, make sure the first one is Bishop var bishopUpliftVan = input.FailureMechanismParametersMStab.MStabParameters.Model == MStabModelType.BishopUpliftVan; if (bishopUpliftVan) { input.FailureMechanismParametersMStab.MStabParameters.Model = MStabModelType.Bishop; } try { // start (first) calculation var stabilityOutputItem = ExcecuteCalculation(kernelDataInput, messages); if (stabilityOutputItem != null) { damMacroStabilityOutput.StabilityOutputItems.Add(stabilityOutputItem); } // now check if second calculation for BishopUpliftVan is needed, if so perform it. if (bishopUpliftVan) { input.FailureMechanismParametersMStab.MStabParameters.Model = MStabModelType.UpliftVan; if (damMacroStabilityOutput.UpliftSituation.IsUplift) { var inputFileName = input.DGeoStabilityInputFileName; // set proper name and model input.DGeoStabilityInputFileName = input.DGeoStabilityInputFileNameSecondModel; try { var stabilityOutputItemSecondModel = ExcecuteCalculation(kernelDataInput, messages); if (stabilityOutputItemSecondModel != null) { damMacroStabilityOutput.StabilityOutputItems.Add(stabilityOutputItemSecondModel); } } finally { // reset name input.DGeoStabilityInputFileName = inputFileName; } } else { // add result that tells that no calculation was made stabilityOutputItem = new DamMacroStabilityOutputItem { CalculationResult = CalculationResult.NoRun }; stabilityOutputItem.StabilityModelType = input.FailureMechanismParametersMStab.MStabParameters.Model; damMacroStabilityOutput.StabilityOutputItems.Add(stabilityOutputItem); } } } finally { if (bishopUpliftVan) { // reset model input.FailureMechanismParametersMStab.MStabParameters.Model = MStabModelType.BishopUpliftVan; } } } private static DamMacroStabilityOutputItem ExcecuteCalculation(IKernelDataInput kernelDataInput, List messages) { var input = (DamMacroStabilityInput)kernelDataInput; var calculator = StabilityCalculator(kernelDataInput); try { calculator.Calculate(); // get (first) results var results = calculator.GetResults(); if (results.Count > 0) { var stabilityOutputItem = new DamMacroStabilityOutputItem(); stabilityOutputItem.StabilityModelType = input.FailureMechanismParametersMStab.MStabParameters.Model; stabilityOutputItem.ProjectFileName = input.DGeoStabilityInputFileName; var zone1 = new DamMacroStabilityOutputItem.ResultsSingleZone { SafetyFactor = results[0].Zone1.SafetyFactor, CircleSurfacePointLeftXCoordinate = results[0].Zone1.CircleSurfacePointLeftXCoordinate, CircleSurfacePointRightXCoordinate = results[0].Zone1.CircleSurfacePointRightXCoordinate, }; stabilityOutputItem.Zone1Results = zone1; if (results[0].Zone2 != null) { var zone2Result = results[0].Zone2.Value; var zone2 = new DamMacroStabilityOutputItem.ResultsSingleZone { SafetyFactor = zone2Result.SafetyFactor, CircleSurfacePointLeftXCoordinate = zone2Result.CircleSurfacePointLeftXCoordinate, CircleSurfacePointRightXCoordinate = zone2Result.CircleSurfacePointRightXCoordinate, }; stabilityOutputItem.Zone2Results = zone2; } return stabilityOutputItem; } return null; } catch (Exception e) { var message = new LogMessage { MessageType = LogMessageType.Error, Message = e.Message }; messages.Add(message); var stabilityOutputItem = new DamMacroStabilityOutputItem { CalculationResult = CalculationResult.UnexpectedError }; stabilityOutputItem.StabilityModelType = input.FailureMechanismParametersMStab.MStabParameters.Model; return stabilityOutputItem; } } internal XDocument CreateMstabDamXmlDocument(DamKernelInput damKernelInput, DamMacroStabilityInput kernelDataInput) { var stabilityProjectFilename = kernelDataInput.DGeoStabilityInputFileName; var subSoilScenario = damKernelInput.SubSoilScenario; var requiredSafetyFactor = damKernelInput.Location.ModelFactors.RequiredSafetyFactorStabilityInnerSlope; if (requiredSafetyFactor == null) { throw new MacroStabilityException(Resources.DamMacroStabilityKernelWrapper_NoRequiredSafetyFactorSpecified); } List errorMessages; XDocument mstabXml = MStabXmlDoc.CreateMStabXmlDoc( stabilityProjectFilename, damKernelInput.Location, damKernelInput.RiverLevelHigh, damKernelInput.RiverLevelLow, subSoilScenario, FailureMechanismParametersMStab.EmbankmentDesignParameters, 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; DamMacroStabilityUtils.ThrowWhenMacroStabilityKernelInputNull(damMacroStabilityInput); 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 design scenario. /// The result message. /// The design results. /// public void PostProcess(DamKernelInput damKernelInput, IKernelDataOutput kernelDataOutput, DesignScenario designScenario, string resultMessage, out List designResults) { DamMacroStabilityUtils.ThrowWhenMacroStabilityDamKernelInputNull(damKernelInput); DamMacroStabilityOutput damMacroStabilityOutput = kernelDataOutput as DamMacroStabilityOutput; DamMacroStabilityUtils.ThrowWhenMacroStabilityKernelOutputNull(damMacroStabilityOutput); designResults = new List(); if (damMacroStabilityOutput.StabilityOutputItems.Count > 0) { var damMacroStabilityOutputItem = damMacroStabilityOutput.StabilityOutputItems[0]; if (damMacroStabilityOutputItem != null) { var designResult = NewDesignResult(damKernelInput, designScenario, damMacroStabilityOutputItem); FillDesignResult(damMacroStabilityOutputItem, designResult); designResult.StabilityDesignResults.NumberOfIterations = lastIterationIndex; designResult.StabilityDesignResults.UpliftSituation = damMacroStabilityOutput.UpliftSituation; designResults.Add(designResult); } } // If designScenario indicates an unsuccesfull design then reset the designResult to an unsuccesfull calculation // The results that were put above, were from the previous run if ((designScenario != null) && (designScenario.CalculationResult == CalculationResult.RunFailed)) { var designResult = designResults[designResults.Count - 1]; designResult.CalculationResult = CalculationResult.RunFailed; designResult.StabilityDesignResults.RedesignedSurfaceLine = null; designResult.StabilityDesignResults.UpliftSituation = null; var subSoilScenario = damKernelInput.SubSoilScenario; designResult.StabilityDesignResults.ResultMessage = designScenario.GetResultMessage(subSoilScenario.SoilProfile1D, subSoilScenario.StiFileName); } var bishopUpliftVan = FailureMechanismParametersMStab.MStabParameters.Model == MStabModelType.BishopUpliftVan; if (bishopUpliftVan) { if (damMacroStabilityOutput.StabilityOutputItems.Count > 1) { var damMacroStabilityOutputItem = damMacroStabilityOutput.StabilityOutputItems[1]; if (damMacroStabilityOutputItem != null) { var designResult = NewDesignResult(damKernelInput, designScenario, damMacroStabilityOutputItem); FillDesignResult(damMacroStabilityOutputItem, designResult); designResult.StabilityDesignResults.NumberOfIterations = lastIterationIndex; designResult.StabilityDesignResults.UpliftSituation = damMacroStabilityOutput.UpliftSituation; designResults.Add(designResult); } } int index; // add worst result from Bishop/UpliftVan, but only if both succeeded. if (designResults[0].CalculationResult == CalculationResult.Succeeded && designResults[1].CalculationResult == CalculationResult.Succeeded) { if (designResults[0].StabilityDesignResults.SafetyFactor <= designResults[1].StabilityDesignResults.SafetyFactor) { index = 0; } else { index = 1; } } else if (designResults[0].CalculationResult != CalculationResult.Succeeded) { // There is no reason why Bishop should not have succeeded therefore no end results can be given index = 0; } else if (designResults[1].CalculationResult == CalculationResult.NoRun) { // No uplift therefore no UpliftVan calculation was made. Present Bishop result. index = 0; } else { // UpliftVan calculation failed. No end results can be given index = 1; } var macroStabilityOutputItem = damMacroStabilityOutput.StabilityOutputItems[index]; if (macroStabilityOutputItem != null) { var overallResult = NewDesignResult(damKernelInput, designScenario, macroStabilityOutputItem); FillDesignResult(macroStabilityOutputItem, overallResult); overallResult.StabilityDesignResults.UpliftSituation = damMacroStabilityOutput.UpliftSituation; overallResult.StabilityDesignResults.StabilityModelType = MStabModelType.BishopUpliftVan; designResults.Add(overallResult); } } } /// /// 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) { DamMacroStabilityInput damMacroStabilityInput = kernelDataInput as DamMacroStabilityInput; DamMacroStabilityOutput damMacroStabilityOutput = kernelDataOutput as DamMacroStabilityOutput; DamMacroStabilityUtils.ThrowWhenMacroStabilityKernelInputNull(damMacroStabilityInput); DamMacroStabilityUtils.ThrowWhenMacroStabilityKernelOutputNull(damMacroStabilityOutput); DamMacroStabilityUtils.ThrowWhenMacroStabilityDamKernelInputNull(damKernelInput); double fosRequired = damKernelInput.Location.ModelFactors.RequiredSafetyFactorStabilityInnerSlope.Value; var zoneResult = damMacroStabilityOutput.StabilityOutputItems[0].Zone1Results; double fosAchieved = zoneResult.SafetyFactor; double exitPointXCoordinate = zoneResult.CircleSurfacePointRightXCoordinate; GeometryPoint limitPointForShoulderDesign = damKernelInput.Location.SurfaceLine.GetLimitPointForShoulderDesign(); evaluationMessage = String.Format(Resources.FactorAchievedVsFactorRequired, fosAchieved, fosRequired); if (exitPointXCoordinate > limitPointForShoulderDesign.X) { designAdvise = DesignAdvise.ShoulderInwards; } else { designAdvise = DesignAdvise.SlopeInwards; } bool isDesignReady = fosAchieved >= fosRequired; if (isDesignReady) { designAdvise = DesignAdvise.None; } return isDesignReady; } /// /// Gets the design strategy /// /// /// public DesignStrategy GetDesignStrategy(DamKernelInput damKernelInput) { switch (damKernelInput.Location.StabilityDesignMethod) { case StabilityDesignMethod.OptimizedSlopeAndShoulderAdaption: return DesignStrategy.OptimizedSlopeAndShoulderAdaption; case StabilityDesignMethod.SlopeAdaptionBeforeShoulderAdaption: return DesignStrategy.SlopeAdaptionBeforeShoulderAdaption; default: return DesignStrategy.NoDesignPossible; } } /// /// Prepares the design. /// /// The kernel data input. /// The kernel data output. /// The dam kernel input. /// Index of the iteration. /// The embankment design parameters. /// Initial geometry file (sti) is not created. public void PrepareDesign(IKernelDataInput kernelDataInput, IKernelDataOutput kernelDataOutput, DamKernelInput damKernelInput, int iterationIndex, out EmbankmentDesignParameters embankmentDesignParameters) { DamMacroStabilityInput damMacroStabilityInput = kernelDataInput as DamMacroStabilityInput; DamMacroStabilityUtils.ThrowWhenMacroStabilityKernelInputNull(damMacroStabilityInput); lastIterationIndex = iterationIndex; string projectWorkingPath = FailureMechanismParametersMStab.ProjectWorkingPath; MStabModelType model = FailureMechanismParametersMStab.MStabParameters.Model; if (model != MStabModelType.Bishop && model != MStabModelType.UpliftVan) { throw new MacroStabilityException(string.Format(Resources.DamMacroStabilityKernelWrapper_DesignNotSupportedForModel, model)); } string mstabProjectFilename = DamMacroStabilityUtils.GetStabilityInputFileName(damKernelInput, iterationIndex, model, projectWorkingPath); var location = damKernelInput.Location; var subSoilScenario = damKernelInput.SubSoilScenario; double riverLevel = damKernelInput.RiverLevelHigh; List errorMessages; // The following parameter is used for correctly creating the MStab file // For the initial geometry, no previous geometry filenam has to be defined EmbankmentDesignParameters embankmentDesignParametersForCreatingMstabFile; if (iterationIndex < 1) { // In the first prepareDesign, the initial geometry filename is determined and should be stored in the embankmentDesignParameters embankmentDesignParameters = new EmbankmentDesignParameters() { EmbankmentMaterialname = location.ShoulderEmbankmentMaterial, PreviousGeometry2DFilename = mstabProjectFilename }; FailureMechanismParametersMStab.EmbankmentDesignParameters = embankmentDesignParameters; embankmentDesignParametersForCreatingMstabFile = null; } else { // In the following prepareDesign calls just return the stored embankmentDesignParameters embankmentDesignParameters = FailureMechanismParametersMStab.EmbankmentDesignParameters; embankmentDesignParametersForCreatingMstabFile = embankmentDesignParameters; } XDocument mstabXML = MStabXmlDoc.CreateMStabXmlDoc( mstabProjectFilename, damKernelInput.Location, riverLevel, damKernelInput.RiverLevelLow, subSoilScenario, embankmentDesignParametersForCreatingMstabFile, location.ModelFactors.RequiredSafetyFactorStabilityInnerSlope.Value, damMacroStabilityInput.FailureMechanismParametersMStab, damKernelInput.DamFailureMechanismeCalculationSpecification.AssessmentScenarioJobSettings, out errorMessages); mstabXML.Save(mstabProjectFilename + ".xml"); damMacroStabilityInput.DGeoStabilityInputFileName = mstabProjectFilename; CreateStiFile(mstabXML); if (!File.Exists(mstabProjectFilename)) { throw new MacroStabilityException(Resources.DamMacroStabilityKernelWrapper_CannotCreateInitialGeometryFile); } } private DesignResult NewDesignResult(DamKernelInput damKernelInput, DesignScenario designScenario, DamMacroStabilityOutputItem macroStabilityOutputItem) { string soilProfile2DName = damKernelInput.SubSoilScenario.ToString(); var designResult = new DesignResult(damKernelInput.DamFailureMechanismeCalculationSpecification, designScenario, damKernelInput.SubSoilScenario.SoilProfile1D, soilProfile2DName) { // initialize as failed CalculationResult = CalculationResult.RunFailed }; var stabilityDesignResults = new StabilityDesignResults(); stabilityDesignResults.RedesignedSurfaceLine = damKernelInput.Location.SurfaceLine; designResult.BaseFileName = Path.GetFileNameWithoutExtension(macroStabilityOutputItem.ProjectFileName); designResult.ProfileName = soilProfile2DName; designResult.StabilityDesignResults = stabilityDesignResults; designResult.CalculationSubDir = DamMacroStabilityUtils.GetCalculationSubDir(macroStabilityOutputItem.StabilityModelType); return designResult; } private static void FillDesignResult(DamMacroStabilityOutputItem damMacroStabilityOutputItem, DesignResult designResult) { designResult.CalculationResult = damMacroStabilityOutputItem.CalculationResult; designResult.StabilityDesignResults.StabilityModelType = damMacroStabilityOutputItem.StabilityModelType; if (designResult.CalculationResult == CalculationResult.Succeeded) { designResult.StabilityDesignResults.Zone1SafetyFactor = damMacroStabilityOutputItem.Zone1Results.SafetyFactor; designResult.StabilityDesignResults.LocalZone1EntryPointX = damMacroStabilityOutputItem.Zone1Results.CircleSurfacePointLeftXCoordinate; designResult.StabilityDesignResults.LocalZone1ExitPointX = damMacroStabilityOutputItem.Zone1Results.CircleSurfacePointRightXCoordinate; designResult.StabilityDesignResults.SafetyFactor = designResult.StabilityDesignResults.Zone1SafetyFactor; if (damMacroStabilityOutputItem.Zone2Results != null) { var zone2 = (DamMacroStabilityOutputItem.ResultsSingleZone)damMacroStabilityOutputItem.Zone2Results; designResult.StabilityDesignResults.Zone2SafetyFactor = zone2.SafetyFactor; designResult.StabilityDesignResults.LocalZone2EntryPointX = zone2.CircleSurfacePointLeftXCoordinate; designResult.StabilityDesignResults.LocalZone2ExitPointX = zone2.CircleSurfacePointRightXCoordinate; } } } } }