// Copyright (C) Stichting Deltares 2016. 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.Calculation.Properties;
using Ringtoets.Piping.Calculation.SubCalculator;
using EffectiveThicknessCalculator = Ringtoets.Piping.Calculation.SubCalculator.EffectiveThicknessCalculator;
using HeaveCalculator = Ringtoets.Piping.Calculation.SubCalculator.HeaveCalculator;
namespace Ringtoets.Piping.Calculation
{
///
/// 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.
///
/// or is null.
public PipingCalculator(PipingCalculatorInput input, IPipingSubCalculatorFactory factory)
{
if (input == null)
{
throw new ArgumentNullException("input", "PipingCalculatorInput required for creating a PipingCalculator.");
}
if (factory == null)
{
throw new ArgumentNullException("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()
{
var upliftResult = CalculateUplift();
var heaveResult = CalculateHeave();
var sellmeijerResult = CalculateSellmeijer();
return new PipingCalculatorResult(
upliftResult.Zu,
upliftResult.FoSu,
heaveResult.Zh,
heaveResult.FoSh,
sellmeijerResult.Zp,
sellmeijerResult.FoSp
);
}
///
/// 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 soilProfileValidationResults = ValidateSoilProfile();
List surfaceLineValidationResults = ValidateSurfaceLine();
List upliftCalculatorValidationResults = new List();
if (soilProfileValidationResults.Count == 0 && surfaceLineValidationResults.Count == 0)
{
upliftCalculatorValidationResults = ValidateUpliftCalculator();
}
List heaveCalculatorValidationResults = CreateHeaveCalculator().Validate();
List sellmeijerCalculatorValidationResults = CreateSellmeijerCalculator().Validate();
return upliftCalculatorValidationResults
.Concat(surfaceLineValidationResults)
.Concat(soilProfileValidationResults)
.Concat(heaveCalculatorValidationResults)
.Concat(sellmeijerCalculatorValidationResults)
.ToList();
}
///
/// Calculates the 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
///
public double CalculateThicknessCoverageLayer()
{
try
{
var calculator = factory.CreateEffectiveThicknessCalculator();
calculator.ExitPointXCoordinate = input.ExitPointXCoordinate;
calculator.PhreaticLevel = input.PhreaticLevelExit;
calculator.SoilProfile = PipingProfileCreator.Create(input.SoilProfile);
calculator.SurfaceLine = PipingSurfaceLineCreator.Create(input.SurfaceLine);
calculator.VolumicWeightOfWater = input.WaterVolumetricWeight;
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()
{
var calculator = factory.CreatePiezometricHeadAtExitCalculator();
calculator.PhiPolder = input.PhreaticLevelExit;
calculator.HRiver = input.AssessmentLevel;
calculator.RExit = input.DampingFactorExit;
calculator.Calculate();
return calculator.PhiExit;
}
private List ValidateSurfaceLine()
{
var validationResults = new List();
if (input.SurfaceLine == null)
{
validationResults.Add(Resources.PipingCalculation_Validate_Lacks_surfaceline_uplift);
}
else
{
try
{
PipingSurfaceLineCreator.Create(input.SurfaceLine).Validate();
}
catch (PipingSurfaceLineException e)
{
validationResults.Add(e.Message);
}
}
return validationResults;
}
private List ValidateSoilProfile()
{
var validationResults = new List();
if (input.SoilProfile == null)
{
validationResults.Add(Resources.PipingCalculation_Validate_Lacks_SoilProfile_uplift);
}
else
{
try
{
PipingProfileCreator.Create(input.SoilProfile).Validate();
}
catch (PipingProfileException e)
{
validationResults.Add(e.Message);
}
}
return validationResults;
}
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()
{
var 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 IHeaveCalculator CreateHeaveCalculator()
{
var 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()
{
var effectiveStress = DetermineEffectiveStressForOneLayerProfile(input.ThicknessCoverageLayer, input.SaturatedVolumicWeightOfCoverageLayer, input.WaterVolumetricWeight);
var 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()
{
var 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;
return calculator;
}
///
/// Determines the effective stress for a one layer profile.
///
/// The thickness of aquitard layer.
/// The saturated volumic weight of aquitard layer.
///
///
private static double DetermineEffectiveStressForOneLayerProfile(double thicknessOfCoverageLayer, double volumicWeightOfCoverageLayer, double waterVolumetricWeight)
{
return thicknessOfCoverageLayer * (volumicWeightOfCoverageLayer - waterVolumetricWeight);
}
}
}