// Copyright (C) Stichting Deltares 2017. All rights reserved. // // This file is part of Ringtoets. // // Ringtoets is free software: you can redistribute it and/or modify // it under the terms of the GNU 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 General Public License for more details. // // You should have received a copy of the GNU 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.Linq; using Deltares.WTIPiping; using Ringtoets.Piping.KernelWrapper.Creators; using Ringtoets.Piping.KernelWrapper.SubCalculator; using EffectiveThicknessCalculator = Ringtoets.Piping.KernelWrapper.SubCalculator.EffectiveThicknessCalculator; using HeaveCalculator = Ringtoets.Piping.KernelWrapper.SubCalculator.HeaveCalculator; namespace Ringtoets.Piping.KernelWrapper { /// /// This class represents a combination of piping sub calculations, which together can be used /// to assess based on piping. /// public class PipingCalculator { private readonly PipingCalculatorInput input; private readonly IPipingSubCalculatorFactory factory; /// /// Constructs a new . The is used to /// obtain the parameters used in the different sub calculations. /// /// The containing all the values required /// for performing a piping calculation. /// The factory responsible for creating the sub calculators. /// or is null. public PipingCalculator(PipingCalculatorInput input, IPipingSubCalculatorFactory factory) { if (input == null) { throw new ArgumentNullException(nameof(input), @"PipingCalculatorInput required for creating a PipingCalculator."); } if (factory == null) { throw new ArgumentNullException(nameof(factory), @"IPipingSubCalculatorFactory required for creating a PipingCalculator."); } this.input = input; this.factory = factory; } /// /// Performs the actual sub calculations and returns a , which /// contains the results of all sub calculations. /// /// A containing the results of the sub calculations. /// Thrown when any of the invocations of the sub calculations from the kernel throws an Exception. public PipingCalculatorResult Calculate() { IUpliftCalculator upliftResult = CalculateUplift(); IHeaveCalculator heaveResult = CalculateHeave(); ISellmeijerCalculator sellmeijerResult = CalculateSellmeijer(); return new PipingCalculatorResult(new PipingCalculatorResult.ConstructionProperties { UpliftZValue = upliftResult.Zu, UpliftFactorOfSafety = upliftResult.FoSu, HeaveZValue = heaveResult.Zh, HeaveFactorOfSafety = heaveResult.FoSh, SellmeijerZValue = sellmeijerResult.Zp, SellmeijerFactorOfSafety = sellmeijerResult.FoSp, UpliftEffectiveStress = upliftResult.EffectiveStress, HeaveGradient = heaveResult.Gradient, SellmeijerCreepCoefficient = sellmeijerResult.CreepCoefficient, SellmeijerCriticalFall = sellmeijerResult.CriticalFall, SellmeijerReducedFall = sellmeijerResult.ReducedFall }); } /// /// Returns a list of validation messages. The validation messages are based on the values of the /// which was provided to this and are determined by the Piping kernel. /// public List Validate() { List effectiveThicknessCalculatorValidationResults = CreateEffectiveThicknessCalculator().Validate(); List pipingProfilePropertyCalculatorValidationResults = CreatePipingProfilePropertyCalculator().Validate(); List upliftCalculatorValidationResults = ValidateUpliftCalculator(); List heaveCalculatorValidationResults = CreateHeaveCalculator().Validate(); var sellmeijerCalculatorValidationResults = new List(); if (!pipingProfilePropertyCalculatorValidationResults.Any()) { sellmeijerCalculatorValidationResults.AddRange(CreateSellmeijerCalculator().Validate()); } return upliftCalculatorValidationResults .Concat(heaveCalculatorValidationResults) .Concat(sellmeijerCalculatorValidationResults) .Concat(pipingProfilePropertyCalculatorValidationResults) .Concat(effectiveThicknessCalculatorValidationResults) .Distinct() .ToList(); } /// /// Calculates the effective thickness of the coverage layer based on the values of the . /// /// The thickness of the coverage layer. /// Thrown when: /// /// surface at exit point's x-coordinate is higher than the soil profile /// surface line is null /// soil profile is null /// soil profile's aquifer layer is not set /// public double CalculateEffectiveThicknessCoverageLayer() { try { IEffectiveThicknessCalculator calculator = CreateEffectiveThicknessCalculator(); calculator.Calculate(); return calculator.EffectiveHeight; } catch (SoilVolumicMassCalculatorException e) { throw new PipingCalculatorException(e.Message, e); } catch (NullReferenceException e) { throw new PipingCalculatorException(e.Message, e); } } /// /// Calculates the piezometric head at the exit point based on the values of the . /// /// The piezometric head at the exit point. public double CalculatePiezometricHeadAtExit() { IPiezoHeadCalculator calculator = factory.CreatePiezometricHeadAtExitCalculator(); calculator.PhiPolder = input.PhreaticLevelExit; calculator.HRiver = input.AssessmentLevel; calculator.RExit = input.DampingFactorExit; calculator.Calculate(); return calculator.PhiExit; } private List ValidateUpliftCalculator() { try { return CreateUpliftCalculator().Validate(); } catch (Exception exception) { return new List { exception.Message }; } } private ISellmeijerCalculator CalculateSellmeijer() { ISellmeijerCalculator sellmeijerCalculator = CreateSellmeijerCalculator(); try { sellmeijerCalculator.Calculate(); } catch (PipingException e) { throw new PipingCalculatorException(e.Message, e); } catch (PipingException e) { throw new PipingCalculatorException(e.Message, e); } return sellmeijerCalculator; } private IHeaveCalculator CalculateHeave() { IHeaveCalculator heaveCalculator = CreateHeaveCalculator(); try { heaveCalculator.Calculate(); } catch (PipingException e) { throw new PipingCalculatorException(e.Message, e); } return heaveCalculator; } private IUpliftCalculator CalculateUplift() { IUpliftCalculator upliftCalculator = CreateUpliftCalculator(); try { upliftCalculator.Calculate(); } catch (WTIUpliftCalculatorException e) { throw new PipingCalculatorException(e.Message, e); } catch (PipingException e) { throw new PipingCalculatorException(e.Message, e); } return upliftCalculator; } private IEffectiveThicknessCalculator CreateEffectiveThicknessCalculator() { IEffectiveThicknessCalculator calculator = factory.CreateEffectiveThicknessCalculator(); calculator.ExitPointXCoordinate = input.ExitPointXCoordinate; calculator.PhreaticLevel = input.PhreaticLevelExit; calculator.SoilProfile = CreateSoilProfile(); calculator.SurfaceLine = CreateSurfaceLine(); calculator.VolumicWeightOfWater = input.WaterVolumetricWeight; return calculator; } private IHeaveCalculator CreateHeaveCalculator() { IHeaveCalculator calculator = factory.CreateHeaveCalculator(); calculator.Ich = input.CriticalHeaveGradient; calculator.PhiExit = input.PiezometricHeadExit; calculator.DTotal = input.ThicknessCoverageLayer; calculator.PhiPolder = input.PhreaticLevelExit; calculator.RExit = input.DampingFactorExit; calculator.HExit = input.PhreaticLevelExit; return calculator; } private IUpliftCalculator CreateUpliftCalculator() { double effectiveStress = DetermineEffectiveStressForOneLayerProfile(input.EffectiveThicknessCoverageLayer, input.SaturatedVolumicWeightOfCoverageLayer, input.WaterVolumetricWeight); IUpliftCalculator calculator = factory.CreateUpliftCalculator(); calculator.VolumetricWeightOfWater = input.WaterVolumetricWeight; calculator.ModelFactorUplift = input.UpliftModelFactor; calculator.EffectiveStress = effectiveStress; calculator.HRiver = input.AssessmentLevel; calculator.PhiExit = input.PiezometricHeadExit; calculator.RExit = input.DampingFactorExit; calculator.HExit = input.PhreaticLevelExit; calculator.PhiPolder = input.PhreaticLevelExit; return calculator; } private ISellmeijerCalculator CreateSellmeijerCalculator() { ISellmeijerCalculator calculator = factory.CreateSellmeijerCalculator(); calculator.ModelFactorPiping = input.SellmeijerModelFactor; calculator.HRiver = input.AssessmentLevel; calculator.HExit = input.PhreaticLevelExit; calculator.Rc = input.SellmeijerReductionFactor; calculator.DTotal = input.ThicknessCoverageLayer; calculator.SeepageLength = input.SeepageLength; calculator.GammaSubParticles = input.SandParticlesVolumicWeight; calculator.WhitesDragCoefficient = input.WhitesDragCoefficient; calculator.D70 = input.Diameter70; calculator.VolumetricWeightOfWater = input.WaterVolumetricWeight; calculator.DarcyPermeability = input.DarcyPermeability; calculator.KinematicViscosityWater = input.WaterKinematicViscosity; calculator.Gravity = input.Gravity; calculator.DAquifer = input.ThicknessAquiferLayer; calculator.D70Mean = input.MeanDiameter70; calculator.BeddingAngle = input.BeddingAngle; calculator.BottomLevelAquitardAboveExitPointZ = GetBottomAquitardLayerAboveExitPointZ(); return calculator; } private IPipingProfilePropertyCalculator CreatePipingProfilePropertyCalculator() { IPipingProfilePropertyCalculator calculator = factory.CreatePipingProfilePropertyCalculator(); calculator.SoilProfile = CreateSoilProfile(); calculator.SurfaceLine = CreateSurfaceLine(); calculator.ExitPointX = input.ExitPointXCoordinate; return calculator; } private PipingSurfaceLine CreateSurfaceLine() { return input.SurfaceLine == null ? null : PipingSurfaceLineCreator.Create(input.SurfaceLine); } private PipingProfile CreateSoilProfile() { return input.SoilProfile == null ? null : PipingProfileCreator.Create(input.SoilProfile); } private double GetBottomAquitardLayerAboveExitPointZ() { IPipingProfilePropertyCalculator pipingProfilePropertyCalculator = CreatePipingProfilePropertyCalculator(); pipingProfilePropertyCalculator.Calculate(); return pipingProfilePropertyCalculator.BottomAquitardLayerAboveExitPointZ; } /// /// Determines the effective stress for a one layer profile. /// /// The thickness of the aquitard layer. /// The saturated volumic weight of the aquitard layer. /// The volumetric weight of water. /// The effective stress. private static double DetermineEffectiveStressForOneLayerProfile(double thicknessOfCoverageLayer, double volumicWeightOfCoverageLayer, double waterVolumetricWeight) { return thicknessOfCoverageLayer * (volumicWeightOfCoverageLayer - waterVolumetricWeight); } } }