// 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); } } } }