using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using Deltares.DamMacroStability.Calculator.Properties;
using Deltares.DamMacroStability.Calculator.Geo;
namespace Deltares.DamMacroStability.Calculator
{
///
/// Read results from DGeoStability output file
///
public static class DGeoStabilityResultReader
{
internal enum StabilityZone { StabilityZone1a = 1, StabilityZone1b = 2, StabilityZone2a = 3, StabilityZone2b = 4, StabilityZone3a = 5, StabilityZone3b = 6 };
#region structs
public struct DGeoStabilityResults
{
public DGeoStabilityResultsSingleZone Zone1;
public DGeoStabilityResultsSingleZone? Zone2;
public string CalculationName;
public string CalculationSubDir;
public int IterationNumber;
public void Init()
{
Zone1 = new DGeoStabilityResultsSingleZone();
Zone1.Init();
Zone2 = new DGeoStabilityResultsSingleZone();
Zone2.Value.Init();
}
}
public struct DGeoStabilityResultsSingleZone
{
public double SafetyFactor;
public double CircleSurfacePointLeftXCoordinate;
public double CircleSurfacePointRightXCoordinate;
public double EntryPointXCoordinate;
public double ExitPointXCoordinate;
public void Init()
{
SafetyFactor = 0.0;
CircleSurfacePointLeftXCoordinate = 0.0;
CircleSurfacePointRightXCoordinate = 0.0;
EntryPointXCoordinate = 0.0;
ExitPointXCoordinate = 0.0;
}
}
#endregion
///
/// Extracts the relevant calculation results from the outputfile of DGeoStability
///
/// The project file to process
/// The DGeoStability calculation results
public static DGeoStabilityResults ExtractStabilityResults(string projectFileName)
{
if (string.IsNullOrEmpty(projectFileName) || projectFileName.Trim() == "")
{
throw new ArgumentException(string.Format(
Resources.DGeoStabilityResultReader_ExtractStabilityResults_ProjectFileNameNullOrEmpty, projectFileName));
}
if (!File.Exists(projectFileName))
{
throw new FileNotFoundException(string.Format(
Resources.DGeoStabilityResultReader_ExtractStabilityResults_ProjectFileNotExist, projectFileName));
}
try
{
string outputFile = Path.Combine(Path.GetDirectoryName(projectFileName), GetOutputFileName(projectFileName));
return ParseResultsFromOutputFile(outputFile);
}
catch (ArgumentNullException argumentNullException)
{
string message = Resources.DGeoStabilityResultReader_ExtractStabilityResults_CouldNotExtractSafetyFactor;
throw new DGeoStabilityResultReaderException(message, argumentNullException);
}
catch (FileNotFoundException outputFileNotFoundException)
{
string message = Resources.DGeoStabilityResultReader_ExtractStabilityResults_CouldNotExtractSafetyFactor;
string outputFile = Path.Combine(Path.GetDirectoryName(projectFileName), GetOutputFileName(projectFileName));
string[] errorMessages = ParseDGeoStabilityErrorFile(outputFile);
if (errorMessages.Length > 0)
{
message = errorMessages[0];
}
throw new DGeoStabilityResultReaderException(message, outputFileNotFoundException);
}
}
///
/// Gets the stripped file name with the correct extension extracted from the input file name
///
/// The file name with path
/// The project file name without path and correct extension
private static string GetOutputFileName(string projectFileName)
{
string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(projectFileName);
return fileNameWithoutExtension + ".std";
}
///
/// Parses the safety factor from the output file
///
/// The file to parse
/// The safety factor
internal static DGeoStabilityResults ParseResultsFromOutputFile(string outputFile)
{
if (!File.Exists(outputFile))
{
throw new FileNotFoundException(
Resources.DGeoStabilityResultReader_ParseResultsFromOutputFile_No_valid_calculation_performed);
}
var fileContent = GetFileContents(outputFile);
return GetDGeoStabilityResults(fileContent);
}
///
/// Gets the file content (text) from a file
///
/// The name of the file
/// The content string
internal static string GetFileContents(string fileName)
{
if (string.IsNullOrEmpty(fileName) || fileName.Trim() == "")
{
throw new ArgumentException(string.Format(
Resources.DGeoStabilityResultReader_GetFileContents_OutputFileIsNotValid, fileName));
}
if (!File.Exists(fileName))
{
throw new FileNotFoundException(string.Format(
Resources.DGeoStabilityResultReader_GetFileContents_OutputFileDoesNotExist, fileName));
}
string fileContents;
using (var sr = new StreamReader(fileName))
{
fileContents = sr.ReadToEnd();
}
return fileContents;
}
///
/// Read all relevant DGeoStability results from file
///
///
///
internal static DGeoStabilityResults GetDGeoStabilityResults(string fileContent)
{
DGeoStabilityResults results = new DGeoStabilityResults();
if (string.IsNullOrEmpty(fileContent) || fileContent.Trim() == "")
{
throw new ArgumentException(string.Format(
Resources.DGeoStabilityResultReader_GetDGeoStabilityResults_OutputFileHasNoContent, fileContent));
}
if (ParseHasZonePlotEnabled(fileContent))
{
DGeoStabilityResultsSingleZone? zoneResults1 = GetDGeoStabilityResultsSingleZoneFrom(fileContent, StabilityZone.StabilityZone1a, StabilityZone.StabilityZone1b);
if (zoneResults1 != null)
{
results.Zone1 = zoneResults1.Value;
}
else
{
throw new DGeoStabilityResultReaderException(Resources.DGeoStabilityResultReader_GetDGeoStabilityResults_StabilityZone1aOr1bShouldExist);
}
results.Zone2 = GetDGeoStabilityResultsSingleZoneFrom(fileContent, StabilityZone.StabilityZone2a, StabilityZone.StabilityZone2b);
}
else
{
DGeoStabilityResultsSingleZone? noZoneResults = GetDGeoStabilityResultsNoZones(fileContent);
results.Zone1 = noZoneResults.Value;
}
return results;
}
///
/// Parses the fileContent if zone plot is enabled.
///
/// Content of the file.
/// True when zone plot option is on
internal static bool ParseHasZonePlotEnabled(string fileContent)
{
StringReader stringReader = new StringReader(fileContent);
string line = "";
while ((line = stringReader.ReadLine()) != null)
{
if (line.EndsWith(": Zone plot on"))
{
return int.Parse(line.Substring(0, 3)).Equals(1) ? true : false;
}
}
return false;
}
///
/// Get the results from a zone (A or if not exists then B)
///
///
///
///
///
private static DGeoStabilityResultsSingleZone? GetDGeoStabilityResultsSingleZoneFrom(string fileContent, StabilityZone zoneA, StabilityZone zoneB)
{
DGeoStabilityResultsSingleZone? resultsSingleZone = null;
DGeoStabilityResultsSingleZone? zoneAResults = ParseZoneResults(fileContent, (int)zoneA);
if (zoneAResults != null)
{
resultsSingleZone = zoneAResults.Value;
}
else
{
var zoneBResults = ParseZoneResults(fileContent, (int)zoneB);
if (zoneBResults != null)
{
resultsSingleZone = zoneBResults.Value;
}
}
return resultsSingleZone;
}
internal static DGeoStabilityResultsSingleZone? ParseZoneResults(string fileContent, int stabilityZone)
{
StringReader stringReader = new StringReader(fileContent);
string line = "";
int stabilityFactorIndex;
int xCoordinateLeftSurfaceIndex;
int xCoordinateRightSurfaceIndex;
int zoneNumberIndex;
DGeoStabilityResultsSingleZone resultsStruct = new DGeoStabilityResultsSingleZone();
while ((line = stringReader.ReadLine()) != null)
{
if (line.Equals("[Dump]"))
{
if (!ReadParameterColumnIndices(stringReader, out stabilityFactorIndex,
out xCoordinateLeftSurfaceIndex, out xCoordinateRightSurfaceIndex, out zoneNumberIndex))
throw new DGeoStabilityResultReaderException(Resources.DGeoStabilityResultReader_ParseZoneResults_CouldNotReadColumnIndication);
while ((line = stringReader.ReadLine()) != null)
{
if (line.Equals("[Data]"))
{
var zoneStabilityResults = stringReader.ReadLine();
var zoneStabilityResultsElements = zoneStabilityResults.Split(' ').ToList().Where(x => x.Length > 0).ToArray();
if (zoneStabilityResultsElements != null)
{
if ((zoneStabilityResultsElements.Count() > stabilityFactorIndex) && (zoneStabilityResultsElements.Count() > zoneNumberIndex))
{
try
{
if (int.Parse(zoneStabilityResultsElements[zoneNumberIndex]).Equals(stabilityZone))
{
resultsStruct.SafetyFactor = zoneStabilityResultsElements[stabilityFactorIndex].ToType();
if (IsUpliftResults(fileContent))
resultsStruct.SafetyFactor = resultsStruct.SafetyFactor / 1.05;
resultsStruct.CircleSurfacePointLeftXCoordinate = zoneStabilityResultsElements[xCoordinateLeftSurfaceIndex].ToType();
resultsStruct.CircleSurfacePointRightXCoordinate = zoneStabilityResultsElements[xCoordinateRightSurfaceIndex].ToType();
return resultsStruct;
}
}
catch (Exception e)
{
throw new DGeoStabilityResultReaderException(Resources.DGeoStabilityResultReader_ParseZoneResults_CouldNotParseStabilityZone + e);
}
}
else
throw new DGeoStabilityResultReaderException(Resources.DGeoStabilityResultReader_ParseZoneResults_StabilityZoneOrStabilityFactorIndexNotFound);
}
break;
}
}
}
}
return null;
}
private static bool ReadParameterColumnIndices(StringReader stringReader, out int stabilityFactorIndex,
out int xCoordinateLeftSurfaceIndex, out int xCoordinateRightSurfaceIndex, out int zoneNumberIndex)
{
string line = "";
const string startCondition = "[Column Indication]";
const string endCondition = "[End of Column Indication]";
const string headerSafetyFactor = "Stability factor";
const string headerXCoordinateLeftSurface = "X coordinate left surface";
const string headerXCoordinateRightSurface = "X coordinate right surface";
const string headerZoneNumber = "Zone number";
bool isEndCondition = false;
stabilityFactorIndex = -1;
xCoordinateLeftSurfaceIndex = -1;
xCoordinateRightSurfaceIndex = -1;
zoneNumberIndex = -1;
while ((line = stringReader.ReadLine()) != null)
{
if (line.Equals(startCondition))
{
int columnIndex = 0;
while ((line = stringReader.ReadLine()) != null)
{
if (line.Equals(headerSafetyFactor))
stabilityFactorIndex = columnIndex;
if (line.Equals(headerXCoordinateLeftSurface))
xCoordinateLeftSurfaceIndex = columnIndex;
if (line.Equals(headerXCoordinateRightSurface))
xCoordinateRightSurfaceIndex = columnIndex;
if (line.Equals(headerZoneNumber))
zoneNumberIndex = columnIndex;
columnIndex++;
if (line.Equals(endCondition))
{
isEndCondition = true;
break;
}
}
}
if (isEndCondition)
break;
}
return (stabilityFactorIndex >= 0) && (zoneNumberIndex >= 0) && (xCoordinateLeftSurfaceIndex >= 0) && (xCoordinateRightSurfaceIndex >= 0);
}
private static bool IsUpliftResults(string fileContent)
{
fileContent = ReadContentAfterIdentifier(fileContent, "[MODEL]");
if (fileContent.Contains(" 4 : Uplift Van"))
{
return true;
}
else
{
return false;
}
}
private static string ReadContentAfterIdentifier(string fileContent, string identifier)
{
if (!fileContent.Contains(identifier))
throw new DGeoStabilityResultReaderException(
Resources.DGeoStabilityResultReader_ReadContentAfterIdentifier_StabilityFileDoesNotContainIdentifier + identifier);
fileContent = fileContent.Substring(fileContent.IndexOf(identifier));
return fileContent.Replace(identifier + Environment.NewLine, "");
}
private static DGeoStabilityResultsSingleZone GetDGeoStabilityResultsNoZones(string fileContent)
{
DGeoStabilityResultsSingleZone resultsStruct = new DGeoStabilityResultsSingleZone();
resultsStruct.SafetyFactor = GetColumnValueNoZones(fileContent, "Stability factor");
if (IsUpliftResults(fileContent))
resultsStruct.SafetyFactor = resultsStruct.SafetyFactor / 1.05;
resultsStruct.CircleSurfacePointLeftXCoordinate = GetColumnValueNoZones(fileContent, "X coordinate left surface");
resultsStruct.CircleSurfacePointRightXCoordinate = GetColumnValueNoZones(fileContent, "X coordinate right surface");
return resultsStruct;
}
///
/// Parses the content to get the safety factory
///
/// The text to parse
/// Name of the column.
///
/// The safety factor
///
private static double GetColumnValueNoZones(string fileContent, string columnName)
{
fileContent = ReadContentAfterIdentifier(fileContent, "[Dumps]");
fileContent = ReadContentAfterIdentifier(fileContent, "[Dump]");
fileContent = ReadContentAfterIdentifier(fileContent, "[Dump Header]");
fileContent = ReadContentAfterIdentifier(fileContent, "[Column Indication]");
int columnIndex = GetDataColumnIndex(fileContent, columnName, "[End of Column Indication]");
fileContent = ReadContentAfterIdentifier(fileContent, "[Data]");
double columnValue = GetNumberFromLine(fileContent, columnIndex);
return columnValue;
}
///
/// Gets the index of the data column.
///
/// The content to search in
/// The identifier to look for
/// The end tag.
///
/// The index of the column
///
///
///
///
/// Returns -1 if identifier is not found
///
private static int GetDataColumnIndex(string fileContent, string identifier, string endTag)
{
if (!fileContent.Contains(identifier))
throw new DGeoStabilityResultReaderException();
var items = fileContent
.Substring(0, fileContent.IndexOf(endTag) - Environment.NewLine.Length)
.Replace(Environment.NewLine, ";")
.Split(';');
var foundMatch = false;
var i = -1;
if (items.Length > 0)
{
foreach (var word in items)
{
++i;
if (StringsAreEqual(word, identifier))
{
foundMatch = true;
break;
}
}
}
if (i == -1 || !foundMatch)
throw new DGeoStabilityResultReaderException();
return i;
}
private static bool StringsAreEqual(string left, string right)
{
return ((!string.IsNullOrEmpty(left) || left.Trim() == "") &&
left.Equals(right, StringComparison.InvariantCulture));
}
private static double GetNumberFromLine(string fileContent, int idPos)
{
var doublesPattern = new Regex(@"-?\d+(?:\.\d+)?");
var matches = doublesPattern.Matches(fileContent);
return double.Parse(matches[idPos].Value, NumberStyles.Any, CultureInfo.InvariantCulture);
}
///
/// Parses the error messages from the error file
///
/// The file to parse
/// The error messages
private static string[] ParseDGeoStabilityErrorFile(string outputFile)
{
string errorFile = outputFile.Replace(".std", ".err");
if (File.Exists(errorFile))
{
List messages = new List();
bool content = false;
foreach (string line in File.ReadAllLines(errorFile))
{
if (line.StartsWith("**********"))
{
content = !content;
}
else if (content)
{
messages.Add(line);
}
}
return messages.ToArray();
}
else
{
return new string[0];
}
}
}
}