//-----------------------------------------------------------------------
//
// Copyright (c) 2011 Deltares. All rights reserved.
//
// B.S.T.I.M. The
// tom.the@deltares.nl
// 12-05-2011
// Contains class to create PL-Lines with method Dupuit
//-----------------------------------------------------------------------
using System;
using System.IO;
using Deltares.Geotechnics;
using Deltares.Geotechnics.Soils;
using Deltares.Geotechnics.SurfaceLines;
namespace Deltares.Dam.Data
{
///
/// Exception class
///
public class PLLinesCreatorDupuitException : ApplicationException
{
public PLLinesCreatorDupuitException(string message) : base(message)
{
}
}
///
/// Create PLLines with Dupuit
///
public class PLLinesCreatorDupuit
{
const string dupuitPath = "\\Dupuit\\DikeFlow.exe";
private Geometry2DData geometry2DData = null;
private SurfaceLine2 surfaceLine = null;
private TimeSerie waterLevelTimeserie = null;
private TimeSerie safetyFactorTimeserie = null;
private SoilList soilList;
private string dupuitFilename;
private double? polderLevel = null;
private bool isReverseLayerOrder = false;
private string errorMessage = null;
private DupuitCalculationType dupuitCalculationType = DupuitCalculationType.ViaDllAndFiles;
public PLLinesCreatorDupuit()
{
DupuitFilename = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + "\\Dupuit\\DikeFlow.exe";
}
///
/// Gets or sets the geometry2 d data.
///
///
/// The geometry2 d data.
///
public Geometry2DData Geometry2DData
{
get { return geometry2DData; }
set { geometry2DData = value; }
}
///
/// Gets or sets the water level timeserie.
///
///
/// The water level timeserie.
///
public TimeSerie WaterLevelTimeserie
{
get { return waterLevelTimeserie; }
set { waterLevelTimeserie = value; }
}
///
/// Gets or sets the polder level.
///
///
/// The polder level.
///
public double? PolderLevel
{
get { return polderLevel; }
set { polderLevel = value; }
}
///
/// Gets or sets the soil list.
///
///
/// The soil list.
///
public SoilList SoilList
{
get { return soilList; }
set { soilList = value; }
}
///
/// Gets or sets the surface line.
///
///
/// The surface line.
///
public SurfaceLine2 SurfaceLine
{
get { return surfaceLine; }
set { surfaceLine = value; }
}
///
/// Gets or sets a value indicating whether this instance is reverse layer order.
///
///
/// true if this instance is reverse layer order; otherwise, false.
///
public bool IsReverseLayerOrder
{
get { return isReverseLayerOrder; }
set { isReverseLayerOrder = value; }
}
///
/// Gets or sets the safety factor timeserie.
///
///
/// The safety factor timeserie.
///
public TimeSerie SafetyFactorTimeserie
{
get { return safetyFactorTimeserie; }
set { safetyFactorTimeserie = value; }
}
///
/// Gets or sets the error message.
///
///
/// The error message.
///
public string ErrorMessage
{
get { return errorMessage; }
set { errorMessage = value; }
}
///
/// Gets or sets the dupuit filename.
///
///
/// The dupuit filename.
///
public string DupuitFilename
{
get { return dupuitFilename; }
set { dupuitFilename = value; }
}
public DupuitCalculationType DupuitCalculationType
{
get { return dupuitCalculationType; }
set { dupuitCalculationType = value; }
}
///
/// Determine limits of grid
///
///
private void ComputeGrid(ref DupuitCalculatorFileIO dupuitCalculatorFileIO)
{
double deltaX = 1.0;
double deltaY = 1.0;
double deltaRadius = 1.0;
DupuitCalculationOptions dupuitCalculationOptions = dupuitCalculatorFileIO.DupuitCalculationOptions;
dupuitCalculationOptions.GridX0 = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder).X;
double gridWidth = 1.0 * (surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder).X -
surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder).X);
dupuitCalculationOptions.GridCountX = (int) Math.Round(gridWidth/deltaX) + 1;
dupuitCalculationOptions.GridX1 = dupuitCalculationOptions.GridX0 + (dupuitCalculationOptions.GridCountX - 1) * deltaX;
dupuitCalculationOptions.GridY0 = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder).Z;
double gridHeight = 2.0 * (surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeTopAtPolder).Z -
surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder).Z);
dupuitCalculationOptions.GridCountY = (int)Math.Round(gridHeight / deltaY) + 1;
dupuitCalculationOptions.GridY1 = dupuitCalculationOptions.GridY0 + (dupuitCalculationOptions.GridCountY - 1) * deltaY;
dupuitCalculationOptions.GridTangentLineLevel1 = surfaceLine.CharacteristicPoints.GetGeometryPoint(CharacteristicPointType.DikeToeAtPolder).Z;
double maxRadius = gridHeight;
dupuitCalculationOptions.GridCircleCount = (int)Math.Round(maxRadius / deltaRadius) + 1;
dupuitCalculationOptions.GridTangentLineLevel0 = dupuitCalculationOptions.GridTangentLineLevel1 - (dupuitCalculationOptions.GridCircleCount - 1) * deltaRadius;
}
///
/// Creates all pl lines.
///
/// The full filename.
///
public DupuitPLLinesTimeSerie CreateAllPlLines(string fullFilename)
{
ThrowIfArgumentNull(Geometry2DData, "Geometry2DData");
ThrowIfArgumentNull(SurfaceLine, "SurfaceLine");
ThrowIfArgumentNull(WaterLevelTimeserie, "WaterLevelTimeserie");
ThrowIfArgumentNull(PolderLevel, "PolderLevel");
ThrowIfArgumentNull(SoilList, "SoilList");
ThrowIfArgumentNull(PolderLevel, "PolderLevel");
// Add polderlevel as a timeserie
TimeSerie polderLevelTimeserie = WaterLevelTimeserie.GetShallowCopy();
polderLevelTimeserie.Entries.Add(new TimeSerieEntry(WaterLevelTimeserie.Entries[0].DateTime, polderLevel.Value));
polderLevelTimeserie.Entries.Add(new TimeSerieEntry(WaterLevelTimeserie.Entries[WaterLevelTimeserie.Entries.Count - 1].DateTime, polderLevel.Value));
// Cleanup files if present
DeleteWorkfiles(fullFilename);
var dupuitCalculatorFileIO = new DupuitCalculatorFileIO();
dupuitCalculatorFileIO.Geometry2DData = geometry2DData;
dupuitCalculatorFileIO.SurfaceLine = surfaceLine;
dupuitCalculatorFileIO.WaterLevelTimeserie = waterLevelTimeserie;
dupuitCalculatorFileIO.PolderLevelTimeserie = polderLevelTimeserie;
dupuitCalculatorFileIO.SoilList = soilList;
dupuitCalculatorFileIO.DupuitCalculationOptions = new DupuitCalculationOptions();
ComputeGrid(ref dupuitCalculatorFileIO);
dupuitCalculatorFileIO.DupuitCalculationOptions.PolderS = polderLevel.Value;
if (waterLevelTimeserie.Entries.Count == 1)
{
// This indicates a steady state calculation
// Only with more than 1 timestep a dynamic calculation is possible
dupuitCalculatorFileIO.DupuitCalculationOptions.DupuitCountT = 0;
dupuitCalculatorFileIO.DupuitCalculationOptions.StabilityCountT = 1;
}
else
{
dupuitCalculatorFileIO.DupuitCalculationOptions.DupuitCountT = waterLevelTimeserie.Entries.Count - 1;
dupuitCalculatorFileIO.DupuitCalculationOptions.StabilityCountT = waterLevelTimeserie.Entries.Count - 1;
}
dupuitCalculatorFileIO.DupuitCalculationOptions.StabMethod = StabMethodDupuit.Bishop;
dupuitCalculatorFileIO.DupuitCalculationOptions.TimeStart = 0.0;
dupuitCalculatorFileIO.DupuitCalculationOptions.TimeEnd =
(waterLevelTimeserie.Entries[waterLevelTimeserie.Entries.Count - 1].DateTime -
waterLevelTimeserie.Entries[0].DateTime).TotalDays;
dupuitCalculatorFileIO.IsReverseLayerOrder = IsReverseLayerOrder;
Validate();
dupuitCalculatorFileIO.WriteInputFiles(fullFilename);
var dupuitCalculator = new DupuitCalculator(DupuitFilename);
try
{
dupuitCalculator.DupuitCalculationType = DupuitCalculationType;
dupuitCalculator.Calculate(fullFilename);
}
catch (DupuitCalculatorException e)
{
// Even after calculation error try to read the calculation results that are available
ErrorMessage = String.Format("Dupuit calculation error: {0}", e.Message);
}
dupuitCalculatorFileIO.ReadOutputFiles(fullFilename);
// Cleanup files if present
//DeleteWorkfiles(path, fullFilename);
// First remove all pl lines for the toplayer, because that pl-line is not relevant
dupuitCalculatorFileIO.DupuitPlLinesTimeSerie.RemoveLastPLLineForAllEntries();
if (dupuitCalculatorFileIO.SafetyFactorTimeserie != null)
{
safetyFactorTimeserie = dupuitCalculatorFileIO.SafetyFactorTimeserie;
}
else
{
CreateSafetyFactorTimeSerieWithMissingValues();
}
return dupuitCalculatorFileIO.DupuitPlLinesTimeSerie;
}
///
/// Creates the safety factor time serie with missing values.
///
private void CreateSafetyFactorTimeSerieWithMissingValues()
{
safetyFactorTimeserie = waterLevelTimeserie.GetShallowCopy();
foreach (var entry in waterLevelTimeserie.Entries)
{
var copyOfEntry = entry.GetShallowCopy();
copyOfEntry.Value = safetyFactorTimeserie.MissVal;
safetyFactorTimeserie.Entries.Add(copyOfEntry);
}
}
///
/// Validation
///
private void Validate()
{
ValidateSoils();
ValidateGeometry2DData();
}
///
/// Validate Soillist
///
private void ValidateSoils()
{
for (int layerIndex = 0; layerIndex < geometry2DData.LayerCount; layerIndex++)
{
// In DGeoStability the bottom boundary does not have a soil assigned
Soil soil;
if (layerIndex > 0)
{
Geometry2DLayer layerForSoil = geometry2DData.GetLayer(layerIndex);
int soilIndex = soilList.GetSoilIndexByName(layerForSoil.soilName);
soil = (soilIndex >= 0) ? soilList.Soils[soilIndex] : new Soil();
if (soil.PermeabKx <= 0)
{
throw new PLLinesCreatorDupuitException(String.Format("Soil '{0}' has invalid Kx ({1})", soil.Name, soil.PermeabKx));
}
}
}
}
///
/// Validate geometry before calculating
///
private void ValidateGeometry2DData()
{
// TODO: implement validation for geometry
}
///
/// Delete working files
///
///
private void DeleteWorkfiles(string fullFilename)
{
string path = Path.GetDirectoryName(fullFilename);
string filename = Path.GetFileName(fullFilename);
string[] fileEntries = Directory.GetFiles(path, filename + ".*");
foreach (string fileEntry in fileEntries)
{
File.Delete(fileEntry);
}
}
///
/// Creates all pl lines.
///
///
public DupuitPLLinesTimeSerie CreateAllPlLines()
{
string tempFilename = Path.GetTempFileName();
return CreateAllPlLines(Path.Combine(Path.GetDirectoryName(tempFilename), Path.GetFileNameWithoutExtension(tempFilename)));
}
///
/// Throws if argument null.
///
/// The argument.
/// Name of the object.
///
private void ThrowIfArgumentNull(Object argument, string objectName)
{
if (argument == null)
{
throw new PLLinesCreatorDupuitException(String.Format("Missing input: '{0}' not defined", objectName));
}
}
}
}