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