using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Windows.Forms; using System.Xml; using Deltares.DeltaModel; using Deltares.Geotechnics; using Deltares.Geotechnics.IO; using Deltares.Geotechnics.IO.Importers; using Deltares.Soilbase; using Deltares.Standard; using Deltares.Standard.Maps; using Deltares.Standard.EventPublisher; using Deltares.Standard.Extensions; using Deltares.Standard.IO; using Deltares.Standard.Language; using Deltares.Standard.Logging; namespace Deltares.DSoilModel.Data { public class DSoilModelIO { /// /// Adds data from an old database (gdb or access) to the given project. All name clashes are resolved by renaming (uniquely) the /// here imported items. /// /// Name of the file. /// The project. public static void AddOldProjectDataBaseToProject(string fileName, DSoilModelProject project) { DataEventPublisher.InvokeWithoutPublishingEvents(() => { using (var geoDatabase = new GeoDatabase(fileName)) { try { ReadSoilsFromOldDataBaseAndAddToProject(ref project, geoDatabase); ReadSoilProfilesFromOldDatabaseAndAddToProject(ref project, geoDatabase); ReadSoilProfiles2DFromOldDatabaseAndAddToProject(ref project, geoDatabase); ReadCptsFromOldDatabaseAndAddToProject(ref project, geoDatabase); ReadBoringsFromOldDatabaseAndAddToProject(ref project, geoDatabase); ReadSegmentsFromOldDatabaseAndAddToProject(ref project, geoDatabase); } catch (Exception e) { var message = LocalizationManager.GetTranslatedText(typeof(DSoilModelIO), "OldProjectImportError"); var logmessage = new LogMessage(LogMessageType.Error, typeof(DSoilModelIO), message + e.Message); LogManager.Messages.Add(logmessage); } } }); } /// /// Adds the soil data from an old database (gdb or access) to the given project. All name clashes are resolved by renaming /// (uniquely) the here imported items. /// /// Name of the file. /// The project. public static void AddOldSoilDBToProject(string fileName, DSoilModelProject project) { DataEventPublisher.IsDataEventPublishStopped = true; using (var geoDatabase = new GeoDatabase(fileName)) { ReadSoilsFromOldDataBaseAndAddToProject(ref project, geoDatabase); } DataEventPublisher.IsDataEventPublishStopped = false; } /// /// Reads all data from the current database and add that to the newly created current project. /// /// Name of the file. /// the created project public static object OpenSoilDatabase(string fileName) { LogManager.Clear(); DataEventPublisher.DataListModified(LogManager.Messages); var oldStopped = DataEventPublisher.IsDataEventPublishStopped; DataEventPublisher.IsDataEventPublishStopped = true; // READ PROJECT FILE FROM NEW DATABASE FORMAT var project = new DSoilModelProject(); using (var db = new SoilModelDatabase()) { db.HandleExceptions = true; db.Open(fileName); project.StressCurves.AddRange(db.ReadStressCurves()); project.BondStressCurves.AddRange(db.ReadBondStressCurves()); project.Soils = db.ReadSoils(); project.CPTs.AddRange(db.ReadCPTs()); project.Borings.AddRange(db.ReadBorings(project.Soils)); project.SoilProfiles1D.AddRange(db.ReadSoilProfiles1D()); project.SoilProfiles2D.AddRange(db.ReadSoilProfiles2D()); project.CptLookup1Ds.AddRange(db.ReadCPTLookup1Ds()); project.CptLookup2Ds.AddRange(db.ReadCPTLookup2Ds()); project.BoringLookup1Ds.AddRange(db.ReadBoringLookup1Ds(project.Soils)); project.BoringLookup2Ds.AddRange(db.ReadBoringLookup2Ds(project.Soils)); project.Soilprofile1DLookup2Ds.AddRange(db.ReadSoilProfile1DLookup2Ds()); project.SpecificMechanismPointLocations.AddRange(db.ReadMechanismPointLocations()); project.SoilSegments.AddRange(db.ReadSoilSegments()); db.ReadSoilSegmentCPTs(); db.ReadSoilSegmentBorings(project.Soils); project.SurfaceLines.AddRange(db.ReadSurfaceLines()); db.Close(); // report errors if (db.ErrorMessages.Count > 0) { LogManager.Add(new LogMessage(LogMessageType.Error, project, LocalizationManager.GetTranslatedText(project, "ErrorOpeningProject"))); foreach (var msg in db.ErrorMessages) { LogManager.Add(msg); } DataEventPublisher.DataListModified(LogManager.Messages); MessageBox.Show(LocalizationManager.GetTranslatedText(project, "OpenDataBaseErrors")); } } DataEventPublisher.IsDataEventPublishStopped = oldStopped; return project; } /// /// Saves all data from the given project to the current database /// /// Name of the file. /// The project. public static void SaveSoilDatabase(string fileName, object project) { try { fileName = Path.ChangeExtension(fileName, "soil"); var dsProject = project as DSoilModelProject; if (dsProject == null) { return; } DataEventPublisher.IsDataEventPublishStopped = true; // SAVE PROJECT TO NEW DATABASE FORMAT using (var db = new SoilModelDatabase()) { db.New(fileName); db.WriteStressCurves(dsProject.StressCurves); db.WriteBondStressCurves(dsProject.BondStressCurves); db.WriteSoils(dsProject.Soils.Soils); db.WriteCPTs(dsProject.CPTs); db.WriteBorings(dsProject.Borings); db.WriteSoilProfile1Ds(dsProject.SoilProfiles1D); db.WriteSoilProfile2Ds(dsProject.SoilProfiles2D); db.WriteCPTLookup1Ds(dsProject.CptLookup1Ds); db.WriteCPTLookup2Ds(dsProject.CptLookup2Ds); db.WriteBoringLookup1Ds(dsProject.BoringLookup1Ds); db.WriteBoringLookup2Ds(dsProject.BoringLookup2Ds); db.WriteSoilProfile1DLookup2Ds(dsProject.Soilprofile1DLookup2Ds); db.WriteMechanismPointLocations(dsProject.SpecificMechanismPointLocations); db.WriteSurfaceLines(dsProject.SurfaceLines); db.WriteSoilSegments(dsProject.SoilSegments); db.WriteSoilSegmentCPTs(dsProject.SoilSegments); db.WriteSoilSegmentBorings(dsProject.SoilSegments); db.Close(); } } catch (Exception ex) { string msg = String.Format(LocalizationManager.GetTranslatedText(typeof(DSoilModelIO), "ErrorSavingProject"), ex.Message); MessageBox.Show(msg, "", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly); } finally { DataEventPublisher.IsDataEventPublishStopped = false; } } /// /// Reads surface line definition from CSV format (DAM Style) /// /// public static void ReadCsvSurfaceLineFromFileAndAddToProject(string fileName, DSoilModelProject project) { var importer = new SurfaceLinesImporter(); var surfaceLine2List = importer.ReadSurfacesLines(fileName); foreach (var surfaceLine2 in surfaceLine2List) { UniqueNameProvider.ProvideUniqueName(project.SurfaceLines, surfaceLine2); project.SurfaceLines.Add(surfaceLine2); } foreach (var msg in importer.ErrorMessages) { LogMessage(fileName + " : " + msg, project); } } /// /// Reads surface line characteristic points definition from CSV format (DAM Style) /// /// public static void ReadCsvCharacteristicPointsFromFileAndAddToProject(string fileName, DSoilModelProject project) { var importer = new CharacteristicPointsImporter(); importer.Read(fileName, project.SurfaceLines); foreach (var msg in importer.ErrorMessages) { LogMessage(fileName + " : " + msg, project); } } /// /// Reads soil segment definition from CSV format (DAM Style) /// /// file name of the CSV file to import /// the D-SoilModel project /// controls rejection of soil segments with incomplete soil profile data (default == true) public static void ReadCsvSegmentsFromFileAndAddToProject(string fileName, DSoilModelProject project, bool rejectIncompleteSegments = true) { var importer = new SoilSegmentsImporter(); var soilProfiles = new List(); soilProfiles.AddRange(project.SoilProfiles1D); soilProfiles.AddRange(project.SoilProfiles2D); var segments = importer.ReadSoilSegments(fileName, soilProfiles); foreach (var segment in segments.ToArray()) { // refuse segments with missing SoilProfile if (rejectIncompleteSegments && segment.StochasticSoilModel.StochasticSoilProfiles.Any(p => p.Profile == null || p.Profile.GetType() == typeof(SoilProfile))) { string msg = String.Format(LocalizationManager.GetTranslatedText(typeof(DSoilModelIO), "SoilSegmentRefused"), segment.Name); LogManager.Add(new LogMessage(LogMessageType.Warning, project, msg)); } else { UniqueNameProvider.ProvideUniqueName(project.SoilSegments, segment); project.SoilSegments.Add(segment); } } foreach (var msg in importer.ErrorMessages) { LogMessage(fileName + " : " + msg, project); } } /// /// Reads Dam soil segment & surfaceline data from the given file (defx or damx) and adds it to the project ensuring unique names for the imported items /// /// name of the file to import (*.defx; *.damx) /// project to add the imported data to public static void ReadDamDefinitionsFromFileAndAddToProject(string fileName, DSoilModelProject project) { string dummy = ""; ReadDamDefinitionsFromFileAndAddToProject(fileName, project, ref dummy); } /// /// Reads Dam soil segment & surfaceline data from the given file (defx or damx) and adds it to the project ensuring unique names for the imported items /// /// name of the file to import (*.defx; *.damx) /// project to add the imported data to /// returns the path of the locations shapefile, if defined public static void ReadDamDefinitionsFromFileAndAddToProject(string fileName, DSoilModelProject project, ref string locationsShpFile) { var stopped = DataEventPublisher.IsDataEventPublishStopped; DataEventPublisher.IsDataEventPublishStopped = true; try { // convert file to lower case before parsing it using xpath string xml; using (StreamReader sr = new StreamReader(fileName)) { xml = sr.ReadToEnd(); } var xmlDoc = new XmlDocument(); xmlDoc.LoadXml(xml.ToLower()); var root = "//" + xmlDoc.DocumentElement.Name; var xmlNode = xmlDoc.SelectSingleNode(root); string geometryDir = GetNodeAttribute(xmlNode, "mapsoilprofile2d"); xmlNode = xmlDoc.SelectSingleNode(root + "/datasourcelist/datasource[@datasourcetype='csvfiles']"); string csvDir = GetNodeAttribute(xmlNode, "datalocation"); xmlNode = xmlDoc.SelectSingleNode(root + "/datasourcelist/datasource[@datasourcetype='datashapefiles']"); string shapeDir = (xmlNode != null) ? GetNodeAttribute(xmlNode, "datalocation") : ""; xmlNode = xmlDoc.SelectSingleNode(root + "/datasourcelist/datasource[@datasourcetype='msoilbase']"); string soilMdb = (xmlNode != null) ? GetNodeAttribute(xmlNode, "datalocation") : ""; xmlNode = xmlDoc.SelectSingleNode(root + "/dataattributes/attribute[@id='segment_id']"); string segmentShp = (xmlNode != null) ? GetNodeAttribute(xmlNode, "datasource") : ""; string segmentField = (xmlNode != null) ? GetNodeAttribute(xmlNode, "name") : ""; xmlNode = xmlDoc.SelectSingleNode(root + "/dataattributes/attribute[@id='location_id']"); locationsShpFile = (xmlNode != null) ? Path.Combine(shapeDir, GetNodeAttribute(xmlNode, "datasource")) : ""; string basePath = Path.GetDirectoryName(fileName) + Path.DirectorySeparatorChar; // soils if (soilMdb != null) { LogManager.Add(new LogMessage(LogMessageType.Info, typeof(DSoilModelProject), "..." + basePath + soilMdb)); using (var soilBase = new GeoDatabase(basePath + soilMdb)) { ReadSoilsFromOldDataBaseAndAddToProject(ref project, soilBase); soilBase.Close(); } } // soilprofiles (1D only) string csvFile = Path.Combine(basePath, csvDir, "soilprofiles.csv"); if (File.Exists(csvFile)) { LogManager.Add(new LogMessage(LogMessageType.Info, typeof(DSoilModelProject), "..." + csvFile)); project.ReadSoilProfiles1DFromFile(csvFile); } // segments csvFile = Path.Combine(basePath, csvDir, "segments.csv"); if (File.Exists(csvFile)) { LogManager.Add(new LogMessage(LogMessageType.Info, typeof(DSoilModelProject), "..." + csvFile)); ReadCsvSegmentsFromFileAndAddToProject(csvFile, project, false); // read 2D profiles referenced by these segments ? if (geometryDir != null) { foreach (var segment in project.SoilSegments) { foreach (var profile in segment.StochasticSoilModel.StochasticSoilProfiles) { if (profile.Profile.GetType() == typeof(SoilProfile)) { var name = profile.Profile.Name; if (name.ToLower().EndsWith(".sti")) { var stiFile = Path.Combine(basePath, geometryDir, name); var existing = project.SoilProfiles2D.FirstOrDefault(p => p.Name == name); if (existing != null) { profile.Profile = existing; } else if (File.Exists(stiFile)) { try { // de-serialize LogManager.Add(new LogMessage(LogMessageType.Info, typeof(DSoilModelProject), "..." + stiFile)); var sp2D = project.ReadGeometryFromFile(stiFile, true); if (sp2D != null) { // assign to stochastic profile profile.Profile = sp2D; // clear log message(s) now that the geometry is loaded foreach (var msg in LogManager.Messages.Where(m => m.Message.EndsWith(sp2D.Name)).ToArray()) { LogManager.Messages.Remove(msg); } } } catch (Exception ex) { LogMessage(String.Format("Error reading Geometry from file: {0} ({1})", stiFile, ex.Message), project); } } else { LogMessage("file not found :" + stiFile, project); } } } } } } // reject incomplete segments (profiles not imported as SoilProfile1D or SoilProfile2D) foreach (var segment in project.SoilSegments.ToArray()) { if (segment.StochasticSoilModel.StochasticSoilProfiles.Any( p => p.Profile.GetType() == typeof(SoilProfile))) { project.SoilSegments.Remove(segment); string msg = String.Format(LocalizationManager.GetTranslatedText(typeof(DSoilModelIO), "SoilSegmentRefused"), segment.Name); LogMessage(msg, project); } } } // segments shape file ? var shpFile = Path.Combine(basePath, shapeDir, segmentShp); if (!string.IsNullOrEmpty(segmentShp)) { if (File.Exists(shpFile)) { LogManager.Add(new LogMessage(LogMessageType.Info, typeof(DSoilModelProject), "..." + segmentShp)); ReadSegmentShapefileAndAddToProject(shpFile, project, segmentField); } else { string msg = String.Format(LocalizationManager.GetTranslatedText(typeof(DSoilModelIO), "FileNotFound"), segmentShp); LogMessage(msg, project); } } // surfacelines csvFile = Path.Combine(basePath, csvDir, "surfacelines.csv"); if (File.Exists(csvFile)) { LogManager.Add(new LogMessage(LogMessageType.Info, typeof(DSoilModelProject), "..." + csvFile)); ReadCsvSurfaceLineFromFileAndAddToProject(csvFile, project); } csvFile = Path.Combine(basePath, csvDir, "characteristicpoints.csv"); if (File.Exists(csvFile)) { LogManager.Add(new LogMessage(LogMessageType.Info, typeof(DSoilModelProject), "..." + csvFile)); ReadCsvCharacteristicPointsFromFileAndAddToProject(csvFile, project); } } catch (Exception ex) { string msg = String.Format(LocalizationManager.GetTranslatedText(typeof(DSoilModelIO), "DamimportError"), ex.Message); LogMessage(msg, project); } finally { DataEventPublisher.IsDataEventPublishStopped = stopped; DataEventPublisher.DataListModified(project.Soils.Soils); DataEventPublisher.DataListModified(project.SoilProfiles1D); DataEventPublisher.DataListModified(project.SoilProfiles2D); DataEventPublisher.DataListModified(project.SoilSegments); DataEventPublisher.DataListModified(project.SurfaceLines); } } public static void ReadSegmentShapefileAndAddToProject(string fileName, DSoilModelProject project, string fieldName = "SegmentId") { // import segments shapefile to empty deltamodel var importer = new ShapeFileImporter(); var deltaModel = new DeltaModel.DeltaModel(); var fieldMap = new FieldPropertyMap(); fieldMap.Definitions.Add(new FieldDefinition(fieldName, "SegmentId", true)); importer.FieldDefinition = fieldMap; importer.Type = typeof(SoilSegment); importer.FileName = fileName; importer.Factory = new DeltaModelFactory(deltaModel); importer.Import(); // link geography to existing segments (imported from CSV) foreach (var shapeSegment in deltaModel.SoilSegments) { string name = shapeSegment.Name; foreach (var segment in project.SoilSegments.Where(s => s.Name == name || s.Name.StartsWith(name + "_"))) { segment.Points.Clear(); segment.Points.AddRange(shapeSegment.Points); } } } private static void ReadSoilsFromOldDataBaseAndAddToProject(ref DSoilModelProject project, GeoDatabase geoDatabase) { SoilList newSoils = geoDatabase.ReadSoils(new List()); project.AddSoilDataToProject(newSoils, false); // backward compatibility, isAquifer dictionary foreach (var newSoil in newSoils.Soils) { // Set Aquifer dictionary too if (newSoils.AquiferDictionary.ContainsKey(newSoil)) { if (project.Soils.AquiferDictionary.ContainsKey(newSoil)) { project.Soils.AquiferDictionary[newSoil] = newSoils.AquiferDictionary[newSoil]; } else { project.Soils.AquiferDictionary.Add(newSoil, newSoils.AquiferDictionary[newSoil]); } } } } private static void ReadSoilProfilesFromOldDatabaseAndAddToProject(ref DSoilModelProject project, GeoDatabase geoDatabase) { var soilProfiles = geoDatabase.ReadSoilProfiles(project.Soils.Soils); foreach (var soilProfile1D in soilProfiles) { // Make sure of unique name UniqueNameProvider.ProvideUniqueName(project.SoilProfiles1D, soilProfile1D); project.SoilProfiles1D.Add(soilProfile1D); } } private static void ReadSoilProfiles2DFromOldDatabaseAndAddToProject(ref DSoilModelProject project, GeoDatabase geoDatabase) { var soilProfiles2D = geoDatabase.ReadSoilProfiles2D(project.Soils.Soils); foreach (var soilProfile2D in soilProfiles2D) { // Make sure of unique name UniqueNameProvider.ProvideUniqueName(project.SoilProfiles2D, soilProfile2D); project.SoilProfiles2D.Add(soilProfile2D); } } private static void ReadCptsFromOldDatabaseAndAddToProject(ref DSoilModelProject project, GeoDatabase geoDatabase) { var cpts = geoDatabase.ReadCPTs(); foreach (var cpt in cpts) { // Make sure of unique name UniqueNameProvider.ProvideUniqueName(project.CPTs, cpt); project.CPTs.Add(cpt); } } private static void ReadBoringsFromOldDatabaseAndAddToProject(ref DSoilModelProject project, GeoDatabase geoDatabase) { var borings = geoDatabase.ReadBorings(project.Soils); foreach (var boring in borings) { // Make sure of unique name UniqueNameProvider.ProvideUniqueName(project.Borings, boring); project.Borings.Add(boring); } } private static void ReadSegmentsFromOldDatabaseAndAddToProject(ref DSoilModelProject project, GeoDatabase geoDatabase) { var segments = geoDatabase.ReadSegments(); foreach (var segment in segments) { // Make sure of unique name UniqueNameProvider.ProvideUniqueName(project.SoilSegments, segment); project.SoilSegments.Add(segment); } } private static string GetNodeAttribute(XmlNode node, string attribute) { // reading xml attribute, null safe if (node != null) { var att = node.Attributes[attribute]; return (att != null) ? att.Value : null; } return null; } private static void LogMessage(string message, object source) { var stopped = DataEventPublisher.IsDataEventPublishStopped; DataEventPublisher.IsDataEventPublishStopped = false; LogManager.Add(new LogMessage(LogMessageType.Warning, source, message)); DataEventPublisher.IsDataEventPublishStopped = stopped; } } }