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