//----------------------------------------------------------------------- // // Copyright (c) 2009 Deltares. All rights reserved. // // B. Faassen // barry.faassen@deltares.nl // 19-5-2008 // n.a. //----------------------------------------------------------------------- using System.Collections.Generic; using System.Threading; using Deltares.Geometry; using Deltares.Geotechnics; using Deltares.Geotechnics.IO.Importers; using Deltares.Geotechnics.SurfaceLines; using Deltares.Standard; using Deltares.Standard.Language; namespace Deltares.Dam.Data { using System; using System.Diagnostics; using System.IO; using System.Text; public struct MStabResults { public MStabResultsSingleZone zone1; public MStabResultsSingleZone? zone2; public string CalculationName; public string CalculationSubDir; public int IterationNumber; public void Init() { zone1 = new MStabResultsSingleZone(); zone1.Init(); zone2 = new MStabResultsSingleZone(); zone2.Value.Init(); } } public struct MStabResultsSingleZone { public double safetyFactor; public double circleSurfacePointLeftXCoordinate; public double circleSurfacePointRightXCoordinate; public double entryPointXCoordinate; public double exitPointXCoordinate; public double beta; public void Init() { safetyFactor = 0.0; circleSurfacePointLeftXCoordinate = 0.0; circleSurfacePointRightXCoordinate = 0.0; entryPointXCoordinate = 0.0; exitPointXCoordinate = 0.0; beta = 0.0; } } public struct NonWaterRetainingObjectResults { public string NwoId; public double LocationXrdStart; public double LocationYrdStart; public double LocationZrdStart; public double LocationXrdEnd; public double LocationYrdEnd; public double LocationZrdEnd; public MStabResults MStabResults; public SurfaceLine2 AdaptedSurfaceLine; public SoilGeometryProbability SoilProfileProbability; public void Init() { NwoId = ""; MStabResults = new MStabResults(); MStabResults.Init(); LocationXrdStart = 0.0; LocationYrdStart = 0.0; LocationZrdStart = 0.0; LocationXrdEnd = 0.0; LocationYrdEnd = 0.0; LocationZrdEnd = 0.0; AdaptedSurfaceLine = null; } } /// /// Defines the service agent which is responsible for delegating calls /// to the MStab calculation kernel or services /// public class StabilityServiceAgent : IDisposable { private DGSMStabDAMInterface mstabDamDll; private DGSDAMSlopeWInterface slopeWDamDll; public StabilityServiceAgent() { mstabDamDll = new DGSMStabDAMInterface(); slopeWDamDll = new DGSDAMSlopeWInterface(); MStabExePath = Properties.Settings.Default.MStabExePath; SlopeWExePath = Properties.Settings.Default.SlopeWExePath; } #region Native Members /// /// Constant to the dll file can only be a constant! /// #endregion #region Wrapper Methods public string MStabExePath { get; set; } public string SlopeWExePath { get; set; } public ProgramType ProgramType { get; set; } /// /// Get DLL version /// /// public string GetDllVersion() { if (ProgramType == ProgramType.SlopeW) { return slopeWDamDll.GetDllVersion(); } else { return mstabDamDll.GetDllVersion(); } } /// /// Create MStab project file /// /// public void CreateProjectFile(string inputXmlString) { lock (typeof (StabilityServiceAgent)) { var result = 0; if (ProgramType == ProgramType.SlopeW) { result = slopeWDamDll.CreateProjectFile(inputXmlString); if (result > 0) { string errorMessage = slopeWDamDll.ErrorMessage(); throw new StabilityServiceAgentException(errorMessage); } } else { result = mstabDamDll.CreateProjectFile(inputXmlString); if (result > 0) { string errorMessage = mstabDamDll.ErrorMessage(); throw new StabilityServiceAgentException(errorMessage); } } } } /// /// Create Soilprofile for location X in geometry-2d /// /// /// public void ConvertGeometry2DTo1D(string inputXML, ref StringBuilder outputXML) { const int defaultBufferSize = 10000; int bufferSize = defaultBufferSize; outputXML = new StringBuilder(bufferSize); int returnCode = mstabDamDll.Geometry2DTo1DConversion(inputXML, outputXML, ref bufferSize); if (returnCode == DgsStandardDllInterface.DllErrorOutputBufferTooSmall) { outputXML = new StringBuilder(bufferSize); returnCode = mstabDamDll.Geometry2DTo1DConversion(inputXML, outputXML, ref bufferSize); } if (returnCode != DgsStandardDllInterface.DllErrorNone) throw new StabilityServiceAgentException(mstabDamDll.ErrorMessage()); } /// /// Create Geometry2DData object from geometry2D file /// /// /// public void CreateGeometry2DDataFromGeometry2D(string inputXML, ref StringBuilder outputXML) { const int defaultBufferSize = 10000; int bufferSize = defaultBufferSize; outputXML = new StringBuilder(bufferSize); int returnCode = mstabDamDll.CreateGeometry2DDataFromGeometry2D(inputXML, outputXML, ref bufferSize); if (returnCode == DgsStandardDllInterface.DllErrorOutputBufferTooSmall) { outputXML = new StringBuilder(bufferSize); returnCode = mstabDamDll.CreateGeometry2DDataFromGeometry2D(inputXML, outputXML, ref bufferSize); } if (returnCode != DgsStandardDllInterface.DllErrorNone) throw new StabilityServiceAgentException(mstabDamDll.ErrorMessage()); } /// /// Calculate piping length /// /// /// public double CalculatePipingLength(PolyLine headLine) { int pointCount = headLine.Points.Count; var headLinePoints = new DGSMStabDAMInterface.LegacyCoordinate[pointCount]; double[] pointCoordinates = new double[pointCount * 2]; for (int pointIndex = 0; pointIndex < pointCount; pointIndex++) { headLinePoints[pointIndex].x = headLine.Points[pointIndex].X; headLinePoints[pointIndex].z = headLine.Points[pointIndex].Z; pointCoordinates[pointIndex * 2] = headLine.Points[pointIndex].X; pointCoordinates[pointIndex * 2 + 1] = headLine.Points[pointIndex].Z; } return mstabDamDll.PipingLengthCalculation(pointCount, ref headLinePoints); } /// /// Calculate MStab projects in specified directory /// /// public void CalculateMStabDirectory(string directoryPath) { ThrowHelper.ThrowIfStringArgumentNullOrEmpty(directoryPath, StringResourceNames.ProjectFileNameNullOrEmpty); ThrowHelper.ThrowIfDirectoryNotExist(directoryPath, StringResourceNames.ProjectFileNotExist); ThrowHelper.ThrowIfFileNotExist(MStabExePath, StringResourceNames.MStabExecutableFileNameNotFound); try { // Compute the project files ProcessInputfFile(directoryPath); } catch (ArgumentNullException argumentNullException) { throw new StabilityServiceAgentException(argumentNullException.Message, argumentNullException); } catch (FileNotFoundException outputFileNotFoundException) { throw new StabilityServiceAgentException(outputFileNotFoundException.Message, outputFileNotFoundException); } } /// /// Calculate MStab project /// /// public void CalculateMStabProject(string projectFilePath) { ThrowHelper.ThrowIfStringArgumentNullOrEmpty(projectFilePath, StringResourceNames.ProjectFileNameNullOrEmpty); ThrowHelper.ThrowIfFileNotExist(projectFilePath, StringResourceNames.ProjectFileNotExist); ThrowHelper.ThrowIfFileNotExist(MStabExePath, StringResourceNames.MStabExecutableFileNameNotFound); try { // Compute the project files ProcessInputfFile(projectFilePath); } catch (ArgumentNullException argumentNullException) { throw new StabilityServiceAgentException(argumentNullException.Message, argumentNullException); } catch (FileNotFoundException outputFileNotFoundException) { throw new StabilityServiceAgentException(outputFileNotFoundException.Message, outputFileNotFoundException); } } /// /// Calculate SlopeW project /// /// public void CalculateSlopeWProject(string projectFilePath) { ThrowHelper.ThrowIfStringArgumentNullOrEmpty(projectFilePath, StringResourceNames.ProjectFileNameNullOrEmpty); ThrowHelper.ThrowIfFileNotExist(projectFilePath, StringResourceNames.ProjectFileNotExist); ThrowHelper.ThrowIfFileNotExist(SlopeWExePath, StringResourceNames.SlopeWExecutableFileNameNotFound); try { // Compute the project files ProcessInputfFile(projectFilePath); } catch (ArgumentNullException argumentNullException) { throw new StabilityServiceAgentException(argumentNullException.Message, argumentNullException); } catch (FileNotFoundException outputFileNotFoundException) { throw new StabilityServiceAgentException(outputFileNotFoundException.Message, outputFileNotFoundException); } } /// /// Extracts the relevant calculation results from the outputfile of MStab /// /// The project file to process /// The MStab calculation results public MStabResults ExtractStabilityResults(string projectFileName) { ThrowHelper.ThrowIfStringArgumentNullOrEmpty(projectFileName, StringResourceNames.ProjectFileNameNullOrEmpty); ThrowHelper.ThrowIfFileNotExist(projectFileName, StringResourceNames.ProjectFileNotExist); try { if (ProgramType == ProgramType.SlopeW) { string outputFile = GetSlopeWOutputFileName(projectFileName); return ParseSlopeWResultsFromOutputFile(outputFile); } else { string outputFile = Path.Combine(Path.GetDirectoryName(projectFileName), GetOutputFileName(projectFileName)); return ParseMStabResultsFromOutputFile(outputFile); } } catch (ArgumentNullException argumentNullException) { string message = LocalizationManager.GetTranslatedText(this.GetType(), "CouldNotExtractSafetyFactor"); throw new StabilityServiceAgentException(message, argumentNullException); } catch (FileNotFoundException outputFileNotFoundException) { string message = LocalizationManager.GetTranslatedText(this.GetType(), "CouldNotExtractSafetyFactor"); string outputFile = Path.Combine(Path.GetDirectoryName(projectFileName), GetOutputFileName(projectFileName)); string[] errorMessages = ParseMStabErrorFile(outputFile); if (errorMessages.Length > 0) { message = errorMessages[0]; } throw new StabilityServiceAgentException(message, outputFileNotFoundException); } } /// /// Extract the beta-value from dumpfile of MStab /// /// /// public double ExtractBeta(string projectFileName) { ThrowHelper.ThrowIfStringArgumentNullOrEmpty(projectFileName, StringResourceNames.ProjectFileNameNullOrEmpty); ThrowHelper.ThrowIfFileNotExist(projectFileName, StringResourceNames.ProjectFileNotExist); string outputFile = Path.Combine(Path.GetDirectoryName(projectFileName), GetOutputFileName(projectFileName)); try { return ParseBetaFromOutputFile(outputFile); } catch (ArgumentNullException argumentNullException) { throw new StabilityServiceAgentException(argumentNullException.Message, argumentNullException); } catch (FileNotFoundException outputFileNotFoundException) { throw new StabilityServiceAgentException(outputFileNotFoundException.Message, outputFileNotFoundException); } } #endregion #region Helper Methods private string CreateMStabIniFile(string inputFileName) { string filename = Path.GetTempFileName(); filename = Path.ChangeExtension(filename, "ini"); string defaultIniFilename = Path.Combine(Path.GetDirectoryName(MStabExePath), "DGeoStability.ini"); string newIniContent = "[D-Geo Stability batch processing]"; var isDirectoryBatchCalculation = Directory.Exists(inputFileName); if (isDirectoryBatchCalculation) { newIniContent += System.Environment.NewLine + "Path=" + inputFileName; newIniContent += System.Environment.NewLine + "Filespec=*.sti"; } else { newIniContent += System.Environment.NewLine + "InputFileName=" + inputFileName; } newIniContent += System.Environment.NewLine + "Plot Critical Circle=1"; newIniContent += System.Environment.NewLine + "PlotWMF=1"; newIniContent += System.Environment.NewLine + "PlotJPeg=1"; if (File.Exists(defaultIniFilename)) { string iniContent = File.ReadAllText(defaultIniFilename); newIniContent += System.Environment.NewLine + System.Environment.NewLine + iniContent; }; File.WriteAllText(filename, newIniContent); return filename; } /// /// Processes the input file using the working folder /// /// The folder or file name; for MStab: if a filename is specified then the file will be calculated; if a foldername is specified, all the stability files in the folder will be calculated. For SlopeW only filename is allowed private void ProcessInputfFile(string folderOrFileName) { const string quote = "\""; var argument = ""; var programpath = ""; string mStabIniFilename = ""; if (ProgramType == ProgramType.SlopeW) { programpath = SlopeWExePath; argument = " /s /x " + quote + folderOrFileName + quote + " " + quote + Path.GetFileNameWithoutExtension(folderOrFileName) + quote; } else { programpath = MStabExePath; mStabIniFilename = CreateMStabIniFile(folderOrFileName); argument = string.Format("/b \"{0}\"", mStabIniFilename); // For debugging and calling with commandline options i.s.o. inifile //string filename = Path.GetTempFileName(); //File.WriteAllText(filename, programpath); //File.WriteAllText(filename, argument); //File.AppendAllText(filename, mStabIniFilename); //argument = string.Format("/B /PlotJPeg /Plot \"{0}\"", folderOrFileName); // note: use the folder name only for running MStab in batch mode //File.AppendAllText(filename, argument); } var process = new Process { StartInfo = { FileName = programpath, Arguments = argument, UseShellExecute = false } }; Parallel.KillOnAbort(process); process.Start(); try { process.WaitForExit(); } catch (ThreadInterruptedException) { // thread was killed by user action to stop calculation } finally { if (File.Exists(mStabIniFilename)) { File.Delete(mStabIniFilename); } } } /// /// Creates a random working folder by using a GUID /// /// The generated folder name private static string CreateTempDirName() { return string.Format("{0}\\{1}", Path.GetTempPath(), Guid.NewGuid().ToString().Replace('-', '0')); } /// /// 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) { return GetStrippedFileNameWithoutExtension(projectFileName) + ".std"; } /// /// Gets the filename with the correct extension and the proper path for the outputfile for SlopeW /// /// The file name with path /// The project file name with extended path and correct extension private static string GetSlopeWOutputFileName(string projectFileName) { string outputFile = Path.GetDirectoryName(projectFileName); outputFile = Path.Combine(outputFile, Path.GetFileNameWithoutExtension(projectFileName)); outputFile = Path.Combine(outputFile, "001"); outputFile = Path.Combine(outputFile, Path.GetFileNameWithoutExtension(projectFileName)); string outputFileTest = outputFile + ".optfrc"; if (!File.Exists(outputFileTest)) { outputFileTest = outputFile + ".frc01"; } if (!File.Exists(outputFileTest)) { outputFileTest = ""; } return outputFileTest; } /// /// Gets the stripped file name without a path /// /// The file name /// The project file name without path and correct extension private static string GetInputFileName(string projectFileName) { return GetStrippedFileNameWithoutExtension(projectFileName) + ".sti"; } /// /// Gets the stripped file name without path and extension /// /// The file name to strip /// The file name private static string GetStrippedFileNameWithoutExtension(string fileName) { return fileName.Substring(fileName.LastIndexOf("\\") + 1).Split('.')[0]; } /// /// Gets the constructed file name with folder /// /// The name of the file /// The name of the folder /// The full file path private static string GetFileName(string fileName, string folderName) { return string.Format("{0}\\{1}", folderName, fileName); } /// /// Parses the safety factor from the output file /// /// The file to parse /// The safety factor private static MStabResults ParseMStabResultsFromOutputFile(string outputFile) { if (!File.Exists(outputFile)) throw new FileNotFoundException("No valid calculation performed"); var fileContent = StabilityServiceFileParser.GetFileContents(outputFile); return StabilityServiceFileParser.GetMStabResults(fileContent); } /// /// Parses the error messages from the error file /// /// The file to parse /// The error messages private string[] ParseMStabErrorFile(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(outputFile)) { if (line.StartsWith("**********")) { content = !content; } else if (content) { messages.Add(line); } } return messages.ToArray(); } else { return new string[0]; } } /// /// Parses the safety factor from the output file /// /// The file to parse /// The safety factor private static MStabResults ParseSlopeWResultsFromOutputFile(string outputFile) { if (!File.Exists(outputFile)) throw new FileNotFoundException("No valid calculation performed"); var fileContent = StabilityServiceFileParser.GetFileContents(outputFile); return StabilityServiceFileParser.GetSlopeWResults(fileContent); } private static double ParseBetaFromOutputFile(string outputFile) { if (!File.Exists(outputFile)) throw new FileNotFoundException("No valid calculation performed"); var fileContent = StabilityServiceFileParser.GetFileContents(outputFile); return StabilityServiceFileParser.GetBeta(fileContent); } #endregion #region IDispose Members public void Dispose() { Dispose(true); } protected virtual void Dispose(bool disposing) { if (disposing) { // No need to call the finalizer since we've now cleaned // up the unmanaged memory GC.SuppressFinalize(this); } } // This finalizer is called when Garbage collection occurs, but only if // the IDisposable.Dispose method wasn't already called. ~StabilityServiceAgent() { Dispose(false); } #endregion } }