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