// 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.Geotechnics;
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;
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.DGeoStabilityExePath = @".\KernelWrappers\DamMacroStabilityCommon\DGeoStability.exe";
if (string.IsNullOrEmpty(damKernelInput.WorkingDir))
{
FailureMechanismParametersMStab.ProjectWorkingPath = Directory.GetCurrentDirectory();
}
else
{
FailureMechanismParametersMStab.ProjectWorkingPath = damKernelInput.WorkingDir;
}
damKernelInput.SubSoilScenario.StiFileName =
Path.Combine(damKernelInput.Location.StabilityOptions.MapForSoilGeometries2D,
damKernelInput.SubSoilScenario.StiFileName);
var damMacroStabilityInput = new DamMacroStabilityInput()
{
DGeoStabilityExePath = FailureMechanismParametersMStab.DGeoStabilityExePath,
DGeoStabilityInputFileName = DamMacroStabilityUtils.GetStabilityInputFileName(
damKernelInput, iterationIndex, model, FailureMechanismParametersMStab.ProjectWorkingPath),
FailureMechanismParametersMStab = FailureMechanismParametersMStab
};
// 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;
// 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;
}
///
/// 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 calculator = StabilityCalculator(kernelDataInput);
//ToDo zant calculator has no Validate.
// List kernelMessages = calculator.Validate();
messages = new List();
// foreach (string stringMessage in kernelMessages)
// {
// messages.Add(new LogMessage() { Message = stringMessage, MessageType = LogMessageType.Error });
// }
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 there are two calculations to be performed (BishopUpliftVan), make sure the first one is Bishop
if (!string.IsNullOrEmpty(input.DGeoStabilityInputFileNameSecondModel))
{
input.FailureMechanismParametersMStab.MStabParameters.Model = MStabModelType.Bishop;
}
// start (first) calculation
var stabilityOutputItem = ExcecuteCalculation(kernelDataInput);
if (stabilityOutputItem != null)
{
damMacroStabilityOutput.StabilityOutputItems.Add(stabilityOutputItem);
}
// now check if second calculation for BishopUpliftVan is needed, if so perform it.
if (!string.IsNullOrEmpty(input.DGeoStabilityInputFileNameSecondModel))
{
var inputFileName = input.DGeoStabilityInputFileName;
// set proper name and model
input.DGeoStabilityInputFileName = input.DGeoStabilityInputFileNameSecondModel;
input.FailureMechanismParametersMStab.MStabParameters.Model = MStabModelType.UpliftVan;
try
{
var stabilityOutputItemSecondModel = ExcecuteCalculation(kernelDataInput);
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)
{
var calculator = StabilityCalculator(kernelDataInput);
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,
EntryPointXCoordinate = results[0].Zone1.EntryPointXCoordinate,
ExitPointXCoordinate = results[0].Zone1.ExitPointXCoordinate
};
stabilityOutputItem.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,
EntryPointXCoordinate = results[0].Zone1.EntryPointXCoordinate,
ExitPointXCoordinate = results[0].Zone1.ExitPointXCoordinate
};
stabilityOutputItem.Zone2Results = zone2;
}
return stabilityOutputItem;
}
return null;
}
internal XDocument CreateMstabDamXmlDocument(DamKernelInput damKernelInput, DamMacroStabilityInput kernelDataInput)
{
var stabilityProjectFilename = kernelDataInput.DGeoStabilityInputFileName;
var scenario = damKernelInput.DesignScenario;
var subSoilScenario = damKernelInput.SubSoilScenario;
var requiredSafetyFactor = scenario.RequiredSafetyFactorStabilityInnerSlope?? scenario.Location.ModelFactors.RequiredSafetyFactorStabilityInnerSlope;
if (requiredSafetyFactor == null)
{
throw new MacroStabilityException("Required safety factor must be specified");
}
List errorMessages;
XDocument mstabXml = MStabXmlDoc.CreateMStabXmlDoc(stabilityProjectFilename, scenario, 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, string resultMessage, out List designResults)
{
DamMacroStabilityOutput damMacroStabilityOutput = kernelDataOutput as DamMacroStabilityOutput;
if (damMacroStabilityOutput == null)
{
throw new NoNullAllowedException(Resources.DamMacroStabilityKernelWrapper_PostProcess_NoOutputObjectDefinedForMacroStability);
}
// TODO: this is just fake data
string soilProfile2DName = "soilProfile2DName";
var d = new DamFailureMechanismeCalculationSpecification();
var s = new DesignScenario
{
Location = new Location()
};
var p = new SoilProfile1D();
designResults = new List();
var designResult = new DesignResult(d, s, p, soilProfile2DName, AnalysisType.NoAdaption);
if (damMacroStabilityOutput.StabilityOutputItems.Count > 0)
{
var damMacroStabilityOutputItem = damMacroStabilityOutput.StabilityOutputItems[0];
if (damMacroStabilityOutputItem != null)
{
FillDesignResult(damMacroStabilityOutputItem, designResult);
designResults.Add(designResult);
}
}
if (damMacroStabilityOutput.StabilityOutputItems.Count > 1)
{
// Todo this next line is still fake!
designResult = new DesignResult(d, s, p, soilProfile2DName, AnalysisType.NoAdaption);
var damMacroStabilityOutputItem = damMacroStabilityOutput.StabilityOutputItems[1];
if (damMacroStabilityOutputItem != null)
{
FillDesignResult(damMacroStabilityOutputItem, designResult);
}
designResults.Add(designResult);
//Todo combine results from bishop/upliftvan and add these too? check in old Dam.
// Bka: Old Dam shows both bishop, upliftvan and combined result. So this should
// add decisive result as well.
}
}
private static void FillDesignResult(DamMacroStabilityOutputItem damMacroStabilityOutputItem, DesignResult designResult)
{
var stabilityDesignResults = new StabilityDesignResults
{
Zone1SafetyFactor = damMacroStabilityOutputItem.Zone1Results.SafetyFactor,
LocalZone1EntryPointX = damMacroStabilityOutputItem.Zone1Results.EntryPointXCoordinate,
LocalZone1ExitPointX = damMacroStabilityOutputItem.Zone1Results.ExitPointXCoordinate
};
stabilityDesignResults.SafetyFactor = stabilityDesignResults.Zone1SafetyFactor;
if (damMacroStabilityOutputItem.Zone2Results != null)
{
var zone2 = (DamMacroStabilityOutputItem.ResultsSingleZone) damMacroStabilityOutputItem.Zone2Results;
stabilityDesignResults.Zone2SafetyFactor = zone2.SafetyFactor;
stabilityDesignResults.LocalZone2EntryPointX = zone2.EntryPointXCoordinate;
stabilityDesignResults.LocalZone2ExitPointX = zone2.ExitPointXCoordinate;
stabilityDesignResults.SafetyFactor = Math.Min(damMacroStabilityOutputItem.Zone1Results.SafetyFactor, zone2.SafetyFactor);
}
designResult.StabilityDesignResults = stabilityDesignResults;
}
}
}