// 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 Deltares.DamEngine.Calculators.DikesDesign;
using Deltares.DamEngine.Calculators.KernelWrappers.Common;
using Deltares.DamEngine.Calculators.KernelWrappers.Interfaces;
using Deltares.DamEngine.Calculators.Properties;
using Deltares.DamEngine.Calculators.Uplift;
using Deltares.DamEngine.Data.Design;
using Deltares.DamEngine.Data.General;
using Deltares.DamEngine.Data.General.PlLines;
using Deltares.DamEngine.Data.General.Results;
using Deltares.DamEngine.Data.Geometry;
using Deltares.DamEngine.Data.Geotechnics;
using Deltares.DamEngine.Data.Standard.Calculation;
using Deltares.DamEngine.Data.Standard.Logging;
using Deltares.WTIPiping;
namespace Deltares.DamEngine.Calculators.KernelWrappers.WbiPipingSellmeijerRevised
{
///
/// Wrapper for Wbi Piping SellmeijerRevised kernel
///
public class WbiPipingSellmeijerRevisedKernelWrapper: 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 damPipingOutput = new WbiPipingSellmeijerRevisedOutput()
{
FoSp = defaultMaxReturnValue
};
kernelDataOutput = damPipingOutput;
if (damKernelInput.SubSoilScenario.SegmentFailureMechanismType == FailureMechanismSystemType.Piping)
{
var soilProfile1D = damKernelInput.SubSoilScenario.SoilProfile1D;
var location = damKernelInput.Location;
double waterLevel = damKernelInput.RiverLevelHigh;
UpliftSituation upliftSituation;
var plLines = PlLinesHelper.CreatePlLinesForPiping(location, soilProfile1D, waterLevel,
damKernelInput.DamFailureMechanismeCalculationSpecification.AssessmentScenarioJobSettings.HydraulicShortcutType,
out upliftSituation);
EvaluateUpliftSituation(damKernelInput, out kernelDataInput, plLines, waterLevel, damPipingOutput);
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)
{
var wbiPipingSellmeijerRevisedOutput = (WbiPipingSellmeijerRevisedOutput)kernelDataOutput;
var calculator = CreatePipingCalculatorWbiSellmeijerRevised(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)
{
wbiPipingSellmeijerRevisedOutput.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)
{
var wbiPipingSellmeijerRevisedInput = kernelDataInput as WbiPipingSellmeijerRevisedInput;
var wbiPipingSellmeijerRevisedOutput = (WbiPipingSellmeijerRevisedOutput)kernelDataOutput;
ThrowWhenKernelInputNull(wbiPipingSellmeijerRevisedInput);
ThrowWhenKernelOutputNull(wbiPipingSellmeijerRevisedOutput);
PerformSingleCalculationWbiSellmeijerRevised(out messages, wbiPipingSellmeijerRevisedOutput, wbiPipingSellmeijerRevisedInput);
}
public void PostProcess(DamKernelInput damKernelInput, IKernelDataOutput kernelDataOutput, DesignScenario designScenario, string resultMessage, out List designResults)
{
var damPipingOutput = kernelDataOutput as WbiPipingSellmeijerRevisedOutput;
ThrowWhenDamKernelInputNull(damKernelInput);
ThrowWhenKernelOutputNull(damPipingOutput);
designResults = new List();
var designResult = new DesignResult(damKernelInput.DamFailureMechanismeCalculationSpecification,
designScenario, damKernelInput.SubSoilScenario.SoilProfile1D, null)
{
CalculationResult = damPipingOutput.CalculationResult
};
var pipingDesignResults = new PipingDesignResults(PipingModelType.Wti2017);
designResult.PipingDesignResults = pipingDesignResults;
pipingDesignResults.ResultMessage = resultMessage;
pipingDesignResults.RedesignedSurfaceLine = damKernelInput.Location.SurfaceLine;
// Make sure defaultMaxReturnValue is limit.
pipingDesignResults.Wti2017Factor = Math.Min(damPipingOutput.FoSp, defaultMaxReturnValue);
pipingDesignResults.Wti2017Hcritical = damPipingOutput.Hc;
pipingDesignResults.LocalExitPointX = damPipingOutput.ExitPointX;
pipingDesignResults.UpliftFactor = damPipingOutput.UpliftFactor;
pipingDesignResults.UpliftSituation = damPipingOutput.UpliftSituation;
designResults.Add(designResult);
}
public ShoulderDesign CalculateDesignAtPoint(DamKernelInput damKernelInput, IKernelDataInput kernelDataInput, IKernelDataOutput kernelDataOutput, GeometryPoint point, out List messages)
{
throw new NotImplementedException();
}
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();
}
public DesignStrategy GetDesignStrategy(DamKernelInput damKernelInput)
{
throw new NotImplementedException();
}
private static void EvaluateUpliftSituation(DamKernelInput damKernelInput, out IKernelDataInput kernelDataInput,
PlLines plLines, double waterLevel,
WbiPipingSellmeijerRevisedOutput damPipingOutput)
{
const double upliftCriterionTolerance = 0.000000001;
var soilProfile1D = damKernelInput.SubSoilScenario.SoilProfile1D;
var surfaceLine = damKernelInput.Location.SurfaceLine;
var location = damKernelInput.Location;
var upliftSituation = new UpliftSituation();
var upliftLocationDeterminator = new UpliftLocationDeterminator
{
PlLines = plLines,
SoilProfile = soilProfile1D,
SurfaceLine = surfaceLine,
DikeEmbankmentMaterial = location.GetDikeEmbankmentSoil(),
XSoilGeometry2DOrigin = location.XSoilGeometry2DOrigin
};
// The tolerance is built in because after design it could be that the value that is designed to, is not reached by this margin
var upliftCriterion = location.UpliftCriterionPiping.Value - upliftCriterionTolerance;
var upliftLocationAndResult = upliftLocationDeterminator.GetLocationAndResult(upliftCriterion);
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 d70 = 0.0;
var aquiferHeight = 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);
d70 = aquiferLayer.D70 * Physics.FactorMeterToMicroMeter;
aquiferHeight = aquiferLayer.Height;
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;
if (soilProfile1D.InBetweenAquiferLayer != null)
{
inBetweenAquiferlayerSoil = soilProfile1D.InBetweenAquiferLayer.Soil;
}
kernelDataInput = new WbiPipingSellmeijerRevisedInput()
{
HRiver = waterLevel,
HExit = referenceLevel,
Rc = defaultFluidisationGradient,
DTotal = dCoverLayer,
SeepageLength = seepageLength,
// specific Sellmeijer 4 Forces
KinematicViscosityWater = Physics.WaterViscosity,
WhitesDragCoefficient = inBetweenAquiferlayerSoil.WhitesConstant,
BeddingAngle = inBetweenAquiferlayerSoil.BeddingAngle,
D70 = d70,
DAquifer = aquiferHeight,
DarcyPermeability = permeabilityKx,
};
damPipingOutput.ExitPointX = xExit;
damPipingOutput.UpliftFactor = upliftFactor;
damPipingOutput.UpliftSituation = upliftSituation;
}
private static Sellmeijer2011Calculator CreatePipingCalculatorWbiSellmeijerRevised(IKernelDataInput kernelDataInput)
{
var wbiPipingSellmeijerRevisedInput = kernelDataInput as WbiPipingSellmeijerRevisedInput;
ThrowWhenKernelInputNull(wbiPipingSellmeijerRevisedInput);
var calculator = new Sellmeijer2011Calculator
{
HRiver = wbiPipingSellmeijerRevisedInput.HRiver,
HExit = wbiPipingSellmeijerRevisedInput.HExit,
Rc = wbiPipingSellmeijerRevisedInput.Rc,
DTotal = wbiPipingSellmeijerRevisedInput.DTotal,
DAquifer = wbiPipingSellmeijerRevisedInput.DAquifer,
SeepageLength = wbiPipingSellmeijerRevisedInput.SeepageLength,
D70 = wbiPipingSellmeijerRevisedInput.D70,
D70Mean = wbiPipingSellmeijerRevisedInput.D70Mean,
WhitesDragCoefficient = wbiPipingSellmeijerRevisedInput.WhitesDragCoefficient,
BeddingAngle = wbiPipingSellmeijerRevisedInput.BeddingAngle,
DarcyPermeability = wbiPipingSellmeijerRevisedInput.DarcyPermeability,
KinematicViscosityWater = wbiPipingSellmeijerRevisedInput.KinematicViscosityWater,
VolumetricWeightOfWater = wbiPipingSellmeijerRevisedInput.VolumetricWeightOfWater,
GammaSubParticles = wbiPipingSellmeijerRevisedInput.GammaSubParticles,
Gravity = wbiPipingSellmeijerRevisedInput.Gravity,
BottomLevelAquitardAboveExitPointZ = wbiPipingSellmeijerRevisedInput.BottomLevelAquitardAboveExitPointZ,
ModelFactorPiping = wbiPipingSellmeijerRevisedInput.ModelFactorPiping
};
return calculator;
}
private static void PerformSingleCalculationWbiSellmeijerRevised(out List messages, WbiPipingSellmeijerRevisedOutput wbiPipingOutput,
WbiPipingSellmeijerRevisedInput wbiPipingInput)
{
wbiPipingOutput.CalculationResult = CalculationResult.NoRun;
wbiPipingOutput.FoSp = defaultMaxReturnValue;
messages = new List();
try
{
if (wbiPipingOutput.UpliftSituation.IsUplift)
{
var calculator = CreatePipingCalculatorWbiSellmeijerRevised(wbiPipingInput);
calculator.Calculate();
wbiPipingOutput.FoSp = calculator.FoSp;
wbiPipingOutput.Hc = calculator.Hc;
wbiPipingOutput.CalculationResult = CalculationResult.Succeeded;
}
}
catch (Exception e)
{
wbiPipingOutput.CalculationResult = CalculationResult.UnexpectedError;
messages.Add(new LogMessage(LogMessageType.Error, null, e.Message));
}
}
private static void ThrowWhenKernelInputNull(WbiPipingSellmeijerRevisedInput wbiPipingInput)
{
if (wbiPipingInput == null)
{
throw new NoNullAllowedException(Resources.WbiPipingSellmeijerRevisedKernelWrapper_NoInputObjectDefined);
}
}
private static void ThrowWhenKernelOutputNull(WbiPipingSellmeijerRevisedOutput wbiPipingOutput)
{
if (wbiPipingOutput == null)
{
throw new NoNullAllowedException(Resources.WbiPipingSellmeijerRevisedKernelWrapper_NoOutputObjectDefined);
}
}
private static void ThrowWhenDamKernelInputNull(DamKernelInput damKernelInput)
{
if (damKernelInput == null)
{
throw new NoNullAllowedException(Resources.WbiPipingSellmeijerRevisedKernelWrapper_NoInputObjectDefined);
}
}
}
}