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]; } } } }