// 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 Deltares.DamEngine.Calculators.KernelWrappers.Common;
using Deltares.DamEngine.Calculators.KernelWrappers.Interfaces;
using Deltares.DamEngine.Data.General.Results;
using Deltares.DamEngine.Data.Standard.Logging;
using Deltares.DamEngine.Data.General;
using Deltares.DamEngine.Calculators.Uplift;
using Deltares.DamEngine.Data.Geotechnics;
using Deltares.DamPiping.SellmeijerVNKCalculator;
using System.Data;
using Deltares.DamEngine.Calculators.DikesDesign;
using Deltares.DamEngine.Calculators.Properties;
using Deltares.DamEngine.Data.Design;
using Deltares.DamEngine.Data.Geometry;
using Deltares.DamEngine.Data.Standard.Calculation;
namespace Deltares.DamEngine.Calculators.KernelWrappers.DamPipingSellmeijerVnk
{
class DamPipingSellmeijerVnkKernelWrapper : IKernelWrapper
{
private const double defaultMaxReturnValue = 90.0;
private const double defaultFluidisationGradient = 0.3;
///
/// Prepares the failure mechanism input based on general 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 damOutput = new DamPipingSellmeijerVnkOutput()
{
FoSp = defaultMaxReturnValue
};
kernelDataOutput = damOutput;
if (damKernelInput.SubSoilScenario.SegmentFailureMechanismType == FailureMechanismSystemType.Piping)
{
var soilProfile1D = damKernelInput.SubSoilScenario.SoilProfile1D;
var surfaceLine = damKernelInput.Location.SurfaceLine;
var location = damKernelInput.Location;
double riverLevel = damKernelInput.RiverLevelHigh;
UpliftSituation upliftSituation;
var plLines = PlLinesHelper.CreatePlLinesForPiping(location, soilProfile1D, riverLevel, out upliftSituation);
var upliftLocationDeterminator = new UpliftLocationDeterminator
{
PlLines = plLines,
SoilProfile = soilProfile1D,
SurfaceLine = surfaceLine,
DikeEmbankmentMaterial = location.GetDikeEmbankmentSoil(),
XSoilGeometry2DOrigin = location.XSoilGeometry2DOrigin
};
var upliftLocationAndResult = upliftLocationDeterminator.GetLocationAndResult(location.ModelFactors.UpliftCriterionPiping.Value);
upliftSituation.IsUplift = (upliftLocationAndResult != null);
var xEntry = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtRiver).X;
var xExit = 0.0;
var surfaceLevel = 0.0;
var dCoverLayer = 0.0;
var permeabilityKx = 0.0;
double? upliftFactor = null;
if (upliftLocationAndResult != null)
{
xExit = upliftLocationAndResult.X;
surfaceLevel = surfaceLine.Geometry.GetZatX(upliftLocationAndResult.X);
var topLevelAquifer = soilProfile1D.GetLayerWithName(upliftLocationAndResult.LayerWhereUpliftOccuresId).TopLevel;
dCoverLayer = DamPipingHelper.DetermineHeightCoverLayer(topLevelAquifer, surfaceLevel);
var aquiferLayer = SoilProfile1DAquiferLayerCombiner.CombineLayers(soilProfile1D, upliftLocationAndResult.LayerWhereUpliftOccuresId);
permeabilityKx = aquiferLayer.PermeabilityKx;
upliftFactor = upliftLocationAndResult.UpliftFactor;
}
var seepageLength = xExit - xEntry;
// Reference level is highest value of surfaceLevel or PolderLevel
// Uit TR Zandmeevoerende wellen (1999): "Het verval dH is gelijk aan het verschil tussen buitenwaterstand (het ontwerppeil(OP))
// bij zeedijken en de maatgevende hoogwaterstand (MHW bij rivierdijken) en de waterstand binnendijks ter plaatse van het uittredepunt,
// rekening houdend met zeespiegelrijzing etc.(zie paragraaf 3.7.2). In dien ter plaatse van het uittreepunt of de opbarstlocatie
// geen vrije waterstand heerst kan gerekend worden met het maaiveldniveau, rekening houdend met eventuele maaiveld daling (zie paragraaf 3.7.2)."
var referenceLevel = Math.Max(location.PolderLevel, surfaceLevel);
Soil inBetweenAquiferlayerSoil = soilProfile1D.BottomAquiferLayer.Soil;
double inBetweenAquiferlayerHeight;
var bottomAquiferlayerHeight = soilProfile1D.GetLayerHeight(soilProfile1D.BottomAquiferLayer);
if (soilProfile1D.InBetweenAquiferLayer != null)
{
inBetweenAquiferlayerSoil = soilProfile1D.InBetweenAquiferLayer.Soil;
inBetweenAquiferlayerHeight = soilProfile1D.GetLayerHeight(soilProfile1D.InBetweenAquiferLayer);
}
else
{
bottomAquiferlayerHeight = bottomAquiferlayerHeight / 2;
inBetweenAquiferlayerHeight = bottomAquiferlayerHeight;
}
kernelDataInput = new DamPipingSellmeijerVnkInput()
{
HRiver = riverLevel,
HExit = referenceLevel,
PolderLevel = location.PolderLevel,
Rc = defaultFluidisationGradient,
DTotal = dCoverLayer,
SeepageLength = seepageLength,
D70 = inBetweenAquiferlayerSoil.DiameterD70 * Physics.FactorMeterToMicroMeter,
WhitesConstant = inBetweenAquiferlayerSoil.WhitesConstant,
BeddingAngle = inBetweenAquiferlayerSoil.BeddingAngle,
PermeabilityKx = permeabilityKx,
WaterViscosity = Physics.WaterViscosity,
SurfaceLevel = surfaceLevel,
DInBetweenAquiferlayer = inBetweenAquiferlayerHeight,
DBottomAquiferlayer = bottomAquiferlayerHeight,
PermeabilityInBetweenAquiferlayer = inBetweenAquiferlayerSoil.PermeabKx,
PermeabilityBottomAquiferlayer = soilProfile1D.BottomAquiferLayer.Soil.PermeabKx,
};
damOutput.ExitPointX = xExit;
damOutput.UpliftFactor = upliftFactor;
damOutput.UpliftSituation = upliftSituation;
return PrepareResult.Successful;
}
kernelDataInput = null;
return PrepareResult.NotRelevant;
}
///
/// Validates the kernel data input.
///
/// The kernel data input.
/// The kernel data output.
/// The messages.
///
/// Number of errors that prevent a calculation
///
public int Validate(IKernelDataInput kernelDataInput, IKernelDataOutput kernelDataOutput, out List messages)
{
DamPipingSellmeijerVnkOutput damPipingOutput = (DamPipingSellmeijerVnkOutput)kernelDataOutput;
var calculator = CreatePipingCalculatorSellmeijerVnk(kernelDataInput);
List kernelMessages = calculator.Validate();
messages = new List();
foreach (string stringMessage in kernelMessages)
{
messages.Add(new LogMessage() { Message = stringMessage, MessageType = LogMessageType.Error });
}
if (messages.Count > 0)
{
damPipingOutput.CalculationResult = CalculationResult.InvalidInputData;
}
return messages.Count;
}
///
/// Performs a failure mechanism calculation based on the input.
///
/// The kernel data input.
/// The kernel data output.
/// The messages.
///
///
public void Execute(IKernelDataInput kernelDataInput, IKernelDataOutput kernelDataOutput, out List messages)
{
DamPipingSellmeijerVnkInput damPipingInput = kernelDataInput as DamPipingSellmeijerVnkInput;
if (damPipingInput == null)
{
throw new NoNullAllowedException(Resources.DamPipingSellmeijerVnkKernelWrapper_Execute_NoInputObjectDefinedForSellmeijerVNK);
}
DamPipingSellmeijerVnkOutput damPipingOutput = (DamPipingSellmeijerVnkOutput)kernelDataOutput;
if (damPipingOutput == null)
{
throw new NoNullAllowedException(Resources.DamPipingSellmeijerVnkKernelWrapper_NoOutputObjectDefinedForSellmeijerVNK);
}
damPipingOutput.FoSp = defaultMaxReturnValue;
messages = new List();
if (damPipingOutput.UpliftSituation.IsUplift)
{
var calculator = CreatePipingCalculatorSellmeijerVnk(kernelDataInput);
calculator.Calculate();
damPipingOutput.FoSp = calculator.FoSp;
damPipingOutput.Hc = calculator.Hc;
damPipingOutput.CalculationResult = CalculationResult.Succeeded;
}
}
///
/// Fills the dam result based on 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)
{
DamPipingSellmeijerVnkOutput damPipingOutput = kernelDataOutput as DamPipingSellmeijerVnkOutput;
if (damPipingOutput == null)
{
throw new NoNullAllowedException(Resources.DamPipingSellmeijerVnkKernelWrapper_NoOutputObjectDefinedForSellmeijerVNK);
}
if (damKernelInput == null)
{
throw new NoNullAllowedException(Resources.DamPipingSellmeijerVnkKernelWrapper_NoInputObjectDefinedForSellmeijerVNK);
}
designResults = new List();
var designResult = new DesignResult(damKernelInput.DamFailureMechanismeCalculationSpecification,
designScenario, damKernelInput.SubSoilScenario.SoilProfile1D, null)
{
CalculationResult = damPipingOutput.CalculationResult
};
var pipingDesignResults = new PipingDesignResults(PipingModelType.SellmeijerVnk);
designResult.PipingDesignResults = pipingDesignResults;
pipingDesignResults.ResultMessage = resultMessage;
// TODO: for now this only works for NoAdaption of geometry; if adaption is enabled, the real redesigned surfaceline has to be assigned
pipingDesignResults.RedesignedSurfaceLine = damKernelInput.Location.SurfaceLine;
pipingDesignResults.SellmeijerVnkFactor = damPipingOutput.FoSp;
pipingDesignResults.SellmeijerVnkHcritical = damPipingOutput.Hc;
pipingDesignResults.LocalExitPointX = damPipingOutput.ExitPointX;
pipingDesignResults.UpliftFactor = damPipingOutput.UpliftFactor;
pipingDesignResults.UpliftSituation = damPipingOutput.UpliftSituation;
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()
{
return DesignStrategy.ShoulderPerPoint;
}
private static PipingCalculatorSellmeijerVNK CreatePipingCalculatorSellmeijerVnk(IKernelDataInput kernelDataInput)
{
DamPipingSellmeijerVnkInput damPipingInput = kernelDataInput as DamPipingSellmeijerVnkInput;
if (damPipingInput == null)
{
throw new NoNullAllowedException(Resources.DamPipingSellmeijerVnkKernelWrapper_NoInputObjectDefinedForSellmeijerVNK);
}
var calculator = new PipingCalculatorSellmeijerVNK()
{
HRiver = damPipingInput.HRiver,
HExit = damPipingInput.HExit,
PolderLevel = damPipingInput.PolderLevel,
SurfaceLevel = damPipingInput.SurfaceLevel,
Rc = damPipingInput.Rc,
DTotal = damPipingInput.DTotal,
DInBetweenAquiferlayer = damPipingInput.DInBetweenAquiferlayer,
DBottomAquiferlayer = damPipingInput.DBottomAquiferlayer,
PermeabilityInBetweenAquiferlayer = damPipingInput.PermeabilityInBetweenAquiferlayer,
PermeabilityBottomAquiferlayer = damPipingInput.PermeabilityBottomAquiferlayer,
SeepageLength = damPipingInput.SeepageLength,
D70 = damPipingInput.D70,
WhitesConstant = damPipingInput.WhitesConstant,
BeddingAngle = damPipingInput.BeddingAngle,
WaterViscosity = damPipingInput.WaterViscosity,
};
return calculator;
}
}
}