// 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.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;
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; }
///
/// 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;
// 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 model = FailureMechanismParametersMStab.MStabParameters.Model;
if (model == MStabModelType.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 calculted and how many calculations are required
switch (FailureMechanismParametersMStab.MStabParameters.Model)
{
case MStabModelType.Bishop:
case MStabModelType.UpliftVan:
{
// prepare the requested calc
break;
}
case MStabModelType.BishopUpliftVan:
{
// see if uplift is required
// if so, both upliftvan and bishop are to be prepared, calculated and worst case is to be determined
damMacroStabilityInput.DGeoStabilityInputFileNameSecondModel =
DamMacroStabilityUtils.GetStabilityInputFileName(damKernelInput, iterationIndex,
MStabModelType.UpliftVan, FailureMechanismParametersMStab.ProjectWorkingPath);
// if not, only Bishop calculation so leave SecondModel empty.
break;
}
default:
{
//model not implemented error
break;
}
}
kernelDataInput = damMacroStabilityInput;
// When BishopUpliftVan is performed, make sure the first one is Bishop
var bishopUpliftVan = damMacroStabilityInput.FailureMechanismParametersMStab.MStabParameters.Model ==
MStabModelType.BishopUpliftVan;
if (bishopUpliftVan)
{
damMacroStabilityInput.FailureMechanismParametersMStab.MStabParameters.Model = MStabModelType.Bishop;
}
// 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 and model
damMacroStabilityInput.DGeoStabilityInputFileName = inputFileName;
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;
}
// 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)
{
// reset model
input.FailureMechanismParametersMStab.MStabParameters.Model = MStabModelType.BishopUpliftVan;
if (damMacroStabilityOutput.UpliftSituation.IsUplift)
{
var inputFileName = input.DGeoStabilityInputFileName;
// set proper name and model
input.DGeoStabilityInputFileName = input.DGeoStabilityInputFileNameSecondModel;
input.FailureMechanismParametersMStab.MStabParameters.Model = MStabModelType.UpliftVan;
try
{
var stabilityOutputItemSecondModel = ExcecuteCalculation(kernelDataInput, messages);
if (stabilityOutputItemSecondModel != null)
{
damMacroStabilityOutput.StabilityOutputItems.Add(stabilityOutputItemSecondModel);
}
}
finally
{
// reset name and model
input.DGeoStabilityInputFileName = inputFileName;
input.FailureMechanismParametersMStab.MStabParameters.Model = MStabModelType.BishopUpliftVan;
}
}
}
}
private static DamMacroStabilityOutputItem ExcecuteCalculation(IKernelDataInput kernelDataInput, List messages)
{
var calculator = StabilityCalculator(kernelDataInput);
try
{
calculator.Calculate();
// get (first) results
var results = calculator.GetResults();
if (results.Count > 0)
{
var stabilityOutputItem = new DamMacroStabilityOutputItem();
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.Info, Message = e.Message };
messages.Add(message);
var stabilityOutputItem =
new DamMacroStabilityOutputItem {CalculationResult = CalculationResult.UnexpectedError};
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("Required safety factor must be specified");
}
List errorMessages;
XDocument mstabXml = MStabXmlDoc.CreateMStabXmlDoc(
stabilityProjectFilename,
damKernelInput.Location,
damKernelInput.RiverLevelHigh,
damKernelInput.RiverLevelLow,
subSoilScenario,
null, requiredSafetyFactor.Value,
kernelDataInput.FailureMechanismParametersMStab, 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)
{
if (damKernelInput == null)
{
throw new NoNullAllowedException(Resources.DamMacroStabilityKernelWrapper_StabilityCalculator_NoInputObjectDefinedForMacroStability);
}
DamMacroStabilityOutput damMacroStabilityOutput = kernelDataOutput as DamMacroStabilityOutput;
if (damMacroStabilityOutput == null)
{
throw new NoNullAllowedException(Resources.DamMacroStabilityKernelWrapper_PostProcess_NoOutputObjectDefinedForMacroStability);
}
designResults = new List();
if (damMacroStabilityOutput.StabilityOutputItems.Count > 0)
{
var damMacroStabilityOutputItem = damMacroStabilityOutput.StabilityOutputItems[0];
if (damMacroStabilityOutputItem != null)
{
var designResult = NewDesignResult(damKernelInput, designScenario);
FillDesignResult(damMacroStabilityOutputItem, designResult);
designResult.StabilityDesignResults.UpliftSituation = damMacroStabilityOutput.UpliftSituation;
designResults.Add(designResult);
}
}
var bishopUpliftVan = FailureMechanismParametersMStab.MStabParameters.Model == MStabModelType.BishopUpliftVan;
if (bishopUpliftVan)
{
if (damMacroStabilityOutput.StabilityOutputItems.Count > 1) // UpliftVan was calculated
{
var damMacroStabilityOutputItem = damMacroStabilityOutput.StabilityOutputItems[1];
if (damMacroStabilityOutputItem != null)
{
var designResult = NewDesignResult(damKernelInput, designScenario);
FillDesignResult(damMacroStabilityOutputItem, designResult);
designResult.StabilityDesignResults.UpliftSituation = damMacroStabilityOutput.UpliftSituation;
designResults.Add(designResult);
}
}
else
{
// add empty result for UpliftVan
var designResult = NewDesignResult(damKernelInput, designScenario);
designResult.DamFailureMechanismeCalculation.FailureMechanismParametersMStab.MStabParameters.Model =
MStabModelType.UpliftVan;
designResult.CalculationResult = CalculationResult.NoRun;
designResult.StabilityDesignResults.UpliftSituation = damMacroStabilityOutput.UpliftSituation;
designResults.Add(designResult);
}
// 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)
{
designResults.Add(designResults[0]);
}
else
{
designResults.Add(designResults[1]);
}
}
else
{
if (designResults[1].CalculationResult == CalculationResult.Succeeded)
{
designResults.Add(designResults[1]); // only Uplift Van succeeded
}
else
{
designResults.Add(designResults[0]); // only Bishop succeeded or both did not succeed
}
}
}
}
///
/// 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 evaluation message.
///
/// if the design was succesful
///
///
public bool EvaluateDesign(DamKernelInput damKernelInput, IKernelDataInput kernelDataInput, IKernelDataOutput kernelDataOutput, out string evaluationMessage)
{
throw new NotImplementedException();
}
private DesignResult NewDesignResult(DamKernelInput damKernelInput, DesignScenario designScenario)
{
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.ProfileName = soilProfile2DName;
designResult.StabilityDesignResults = stabilityDesignResults;
designResult.CalculationSubDir = DamMacroStabilityUtils.GetCalculationSubDir(FailureMechanismParametersMStab.MStabParameters.Model);
return designResult;
}
private static void FillDesignResult(DamMacroStabilityOutputItem damMacroStabilityOutputItem, DesignResult designResult)
{
designResult.CalculationResult = damMacroStabilityOutputItem.CalculationResult;
if (designResult.CalculationResult != CalculationResult.UnexpectedError)
{
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;
}
}
}
}
}