// 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.IO;
using Deltares.DamEngine.Calculators.KernelWrappers.Common;
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.Logging;
namespace Deltares.DamEngine.Calculators.DikesDesign
{
///
/// The Dam Engine design calculator
///
public class DesignCalculator
{
///
/// Performs the design calculation
///
/// The dam project data.
///
public List Execute(DamProjectData damProjectData)
{
damProjectData.DesignCalculations = new List();
var calculationMessages = new List();
for (int locationIndex = 0; locationIndex < damProjectData.Dike.Locations.Count; locationIndex++)
{
var location = damProjectData.Dike.Locations[locationIndex];
for (int subSoilScenarioIndex = 0; subSoilScenarioIndex < location.Segment.SoilProfileProbabilities.Count; subSoilScenarioIndex++)
{
var soiProfileProbability = location.Segment.SoilProfileProbabilities[subSoilScenarioIndex];
for (int designScenarioIndex = 0; designScenarioIndex < location.Scenarios.Count; designScenarioIndex++)
{
DesignScenario designScenario = location.Scenarios[designScenarioIndex];
try
{
// Prepare input
var damKernelInput = new DamKernelInput();
var projectPath = damProjectData.ProjectPath != "" ? damProjectData.ProjectPath : Directory.GetCurrentDirectory();
damKernelInput.ProjectDir = projectPath;
damKernelInput.CalculationDir = Path.Combine(projectPath, damProjectData.CalculationMap);
damKernelInput.Location = location;
damKernelInput.SubSoilScenario = soiProfileProbability;
damKernelInput.DamFailureMechanismeCalculationSpecification = damProjectData.DamProjectCalculationSpecification.CurrentSpecification;
damKernelInput.RiverLevelHigh = designScenario.RiverLevel;
damKernelInput.RiverLevelLow = designScenario.RiverLevelLow;
damKernelInput.FilenamePrefix = String.Format("Loc({0})_Sce({1})", designScenario.Location.Name, designScenario.LocationScenarioID);
AnalysisType analysisType = DamProjectCalculationSpecification.SelectedAnalysisType;
SynchronizeScenarioDataWithLocationData(designScenario, location);
IKernelDataInput kernelDataInput;
IKernelDataOutput kernelDataOutput;
// Create kernelwrapper
IKernelWrapper kernelWrapper = KernelWrapperHelper.CreateKernelWrapper(damProjectData.DamProjectCalculationSpecification.CurrentSpecification);
if (kernelWrapper == null)
{
throw new NotImplementedException(Resources.DesignCalculatorKernelNotImplemented);
}
PrepareResult prepareResult = kernelWrapper.Prepare(damKernelInput, 0, out kernelDataInput, out kernelDataOutput);
// Sometimes the kernelDataInput is not created (p.e when soilprofileprobablility is meant for
// stability where Piping calc is wanted). In that case, do nothing but just skip.
if (prepareResult == PrepareResult.Successful)
{
switch (analysisType)
{
case AnalysisType.AdaptGeometry:
PerformDesignCalculation(
kernelWrapper, kernelDataInput, kernelDataOutput,
damKernelInput, designScenario, calculationMessages,
damProjectData.DesignCalculations);
break;
case AnalysisType.NoAdaption:
DesignCalculatorSingle.PerformSingleCalculation(
kernelWrapper, kernelDataInput, kernelDataOutput,
damKernelInput, designScenario, calculationMessages,
damProjectData.DesignCalculations);
break;
}
}
else
{
if (prepareResult == PrepareResult.NotRelevant)
{
// Do nothing. Calculation will be skipped.
}
if (prepareResult == PrepareResult.Failed)
{
calculationMessages.Add(new LogMessage(LogMessageType.Error, null,
string.Format(Resources.DesignCalculatorPrepareError,
location.Name,
soiProfileProbability.ToString(),
designScenario.LocationScenarioID)));
}
}
}
catch (Exception e)
{
calculationMessages.Add(new LogMessage(LogMessageType.Error, null,
string.Format(Resources.DesignCalculatorGeneralException,
location.Name,
soiProfileProbability.ToString(),
designScenario.LocationScenarioID,
e.Message)));
}
}
}
}
return calculationMessages;
}
///
/// Performs the design calculation shoulder per point.
///
/// The kernel wrapper.
/// The kernel data input.
/// The kernel data output.
/// The dam kernel input.
/// The design scenario.
/// The calculation messages.
/// The design calculations.
public static void PerformDesignCalculation(
IKernelWrapper kernelWrapper, IKernelDataInput kernelDataInput,
IKernelDataOutput kernelDataOutput, DamKernelInput damKernelInput,
DesignScenario designScenario,
List calculationMessages, List designCalculations)
{
// During the design calculation the location.SurfaceLine is adapted; so store a copy to restore it after the calculation
Location location = damKernelInput.Location;
SurfaceLine2 orgLocationSurfaceLine = location.SurfaceLine.FullDeepClone();
try
{
if (damKernelInput.Location.RedesignDikeHeight)
{
// Redesign the surfaceline to the desired Dike Tabel Height
var surfaceLineHeightAdapter = new SurfaceLineHeightAdapter(location.SurfaceLine, location);
SurfaceLine2 adaptedSurfaceLine = surfaceLineHeightAdapter.ConstructNewSurfaceLine(designScenario.DikeTableHeight ?? location.SurfaceLine.GetDefaultDikeTableHeight() ?? 0);
location.SurfaceLine = adaptedSurfaceLine;
}
if (damKernelInput.Location.RedesignDikeShoulder)
{
// Redesign the surfaceline with shoulder and or slope adaption
switch (kernelWrapper.GetDesignStrategy(damKernelInput))
{
case DesignStrategy.ShoulderPerPoint:
DesignCalculatorShoulderPerPoint.PerformDesignCalculationShoulderPerPoint(
kernelWrapper, kernelDataInput, kernelDataOutput,
damKernelInput, designScenario, calculationMessages,
designCalculations);
break;
case DesignStrategy.NoDesignPossible:
throw new NotImplementedException("No design is possible for this failure mechanism");
case DesignStrategy.SlopeAdaptionBeforeShoulderAdaption:
DesignCalculatorFirstSlopeAdaptionThenShoulderAdaption.PerformDesignCalculationFirstSlopeAdaptionThenShoulderAdaption(
kernelWrapper, kernelDataInput, kernelDataOutput, damKernelInput, designScenario,
calculationMessages, designCalculations);
break;
case DesignStrategy.OptimizedSlopeAndShoulderAdaption:
DesignCalculatorCombinedSlopeAndShoulderAdaption.PerformDesignCalculationCombinedSlopeAdaptionAndShoulderAdaption(
kernelWrapper, kernelDataInput, kernelDataOutput, damKernelInput, designScenario,
calculationMessages, designCalculations);
break;
}
}
}
finally
{
// Restore the original surfaceline
location.SurfaceLine = orgLocationSurfaceLine.FullDeepClone();
}
}
///
/// Synchronizes the scenario data with location data.
/// Note that scenario data is leading when available.
///
/// The scenario.
/// The location.
private void SynchronizeScenarioDataWithLocationData(DesignScenario designScenario, Location location)
{
// Synchronize PlLine parameters
if (designScenario.PlLineOffsetBelowDikeToeAtPolder.HasValue)
{
location.PlLineOffsetBelowDikeToeAtPolder = designScenario.PlLineOffsetBelowDikeToeAtPolder.Value;
}
if (designScenario.PlLineOffsetBelowDikeTopAtPolder.HasValue)
{
location.PlLineOffsetBelowDikeTopAtPolder = designScenario.PlLineOffsetBelowDikeTopAtPolder.Value;
}
if (designScenario.PlLineOffsetBelowDikeTopAtRiver.HasValue)
{
location.PlLineOffsetBelowDikeTopAtRiver = designScenario.PlLineOffsetBelowDikeTopAtRiver.Value;
}
if (designScenario.PlLineOffsetBelowShoulderBaseInside.HasValue)
{
location.PlLineOffsetBelowShoulderBaseInside = designScenario.PlLineOffsetBelowShoulderBaseInside.Value;
}
if (designScenario.PlLineOffsetBelowDikeCrestMiddle.HasValue)
{
location.PlLineOffsetBelowDikeCrestMiddle = designScenario.PlLineOffsetBelowDikeCrestMiddle;
}
if (designScenario.PlLineOffsetFactorBelowShoulderCrest.HasValue)
{
location.PlLineOffsetFactorBelowShoulderCrest = designScenario.PlLineOffsetFactorBelowShoulderCrest;
}
if (designScenario.UsePlLineOffsetBelowDikeCrestMiddle.HasValue)
{
location.UsePlLineOffsetBelowDikeCrestMiddle = designScenario.UsePlLineOffsetBelowDikeCrestMiddle;
}
if (designScenario.UsePlLineOffsetFactorBelowShoulderCrest.HasValue)
{
location.UsePlLineOffsetFactorBelowShoulderCrest = designScenario.UsePlLineOffsetFactorBelowShoulderCrest;
}
if (designScenario.HeadPl3.HasValue)
{
location.HeadPl3 = designScenario.HeadPl3.Value;
}
if (designScenario.HeadPl4.HasValue)
{
location.HeadPl4 = designScenario.HeadPl4.Value;
}
// Synchronize piping design parameters
if (designScenario.UpliftCriterionPiping.HasValue)
{
location.UpliftCriterionPiping = designScenario.UpliftCriterionPiping.Value;
}
if (designScenario.RequiredSafetyFactorPiping.HasValue)
{
location.ModelFactors.RequiredSafetyFactorPiping = designScenario.RequiredSafetyFactorPiping.Value;
}
// Synchronize stability design parameters
if (designScenario.UpliftCriterionStability.HasValue)
{
location.UpliftCriterionStability = designScenario.UpliftCriterionStability.Value;
}
if (designScenario.RequiredSafetyFactorStabilityInnerSlope.HasValue)
{
location.ModelFactors.RequiredSafetyFactorStabilityInnerSlope = designScenario.RequiredSafetyFactorStabilityInnerSlope.Value;
}
if (designScenario.RequiredSafetyFactorStabilityOuterSlope.HasValue)
{
location.ModelFactors.RequiredSafetyFactorStabilityOuterSlope = designScenario.RequiredSafetyFactorStabilityOuterSlope.Value;
}
if (designScenario.DikeTableHeight.HasValue)
{
location.DikeTableHeight = designScenario.DikeTableHeight ?? location.SurfaceLine.GetDefaultDikeTableHeight() ?? 0;
}
}
}
}