/// <summary> /// Attaches the corresponding descriptions for a measurement interval from the database to the measurement. /// </summary> /// <param name="dbContext">A DESCDatabase context</param> /// <param name="measurement">A measurement interval</param> /// <param name="columnNames">The description columns to return</param> /// <returns></returns> public static async Task <Measurement> MatchDescriptionForMeasurementAsync(DescDBContext dbContext, Measurement measurement, [Optional] ICollection <string> columnNames) { measurement.SectionInfo = measurement.SectionInfo ?? throw new Exception("Measurement does not have Section information"); SectionInfo section = await dbContext.Sections.Where(x => measurement.SectionInfo.Equals(x)) .FirstOrDefaultAsync().ConfigureAwait(true); if (section == null) { return(measurement); } var x = dbContext.LithologicDescriptions .Where(description => description.SectionInfo.Equals(measurement.SectionInfo)) .Where(description => description.StartOffset <= measurement.StartOffset && description.EndOffset >= measurement.EndOffset); if (columnNames.Any()) { x = x.Include(description => description.DescriptionColumnValues.Where(columnValuPair => columnNames.Contains(columnValuPair.ColumnName)) ); } measurement.Descriptions = x.Select(g => g).ToHashSet(); return(measurement); }
public static Dictionary <int, Measurement> Convert(IODPDataTable dataTable, SectionInfoCollection SectionCollection) { _ = SectionCollection ?? throw new ArgumentNullException(nameof(SectionCollection)); _ = dataTable ?? throw new ArgumentNullException(nameof(dataTable)); Dictionary <int, Measurement> _measurements = new Dictionary <int, Measurement>(); int measurementCount = _measurements.Count + 1; //TODO: Ignore record if error is thrown, ex: offsets with TCON foreach (DataRow record in dataTable.DataTable.Rows) { SectionInfo measurementSectionInfo = new SectionInfo(); try { measurementSectionInfo.Expedition = record[dataTable.ExpeditionColumn].ToString(); measurementSectionInfo.Site = record[dataTable.SiteColumn].ToString(); measurementSectionInfo.Hole = record[dataTable.HoleColumn].ToString(); measurementSectionInfo.Core = record[dataTable.CoreColumn].ToString(); measurementSectionInfo.Type = record[dataTable.TypeColumn].ToString(); measurementSectionInfo.Section = record[dataTable.SectionColumn].ToString(); } catch (Exception) { throw new IndexOutOfRangeException(nameof(record)); } Measurement measurement = new Measurement(measurementSectionInfo); measurement.SectionInfo = SectionCollection.GetExistingElseAddAndGetCurrentSection(measurement.SectionInfo); //CARB files throw error here because there isn't an offset field within the file. Ensure there is. try { if (!string.IsNullOrEmpty(dataTable.OffsetColumn)) { measurement.StartOffset = double.Parse(record[dataTable.OffsetColumn].ToString(), CultureInfo.CurrentCulture); measurement.EndOffset = double.Parse(record[dataTable.OffsetColumn].ToString(), CultureInfo.CurrentCulture); } if (!string.IsNullOrEmpty(dataTable.TopOffsetColumn)) { measurement.StartOffset = double.Parse(record[dataTable.TopOffsetColumn].ToString(), CultureInfo.CurrentCulture); } if (!string.IsNullOrEmpty(dataTable.BottomOffsetColumn)) { measurement.EndOffset = double.Parse(record[dataTable.BottomOffsetColumn].ToString(), CultureInfo.CurrentCulture); } measurement.DataRow = record; _measurements.Add(measurementCount, measurement); measurementCount++; } catch (Exception) { //throw; } } return(_measurements); }
public SectionInfo GetExistingElseAddAndGetCurrentSection(SectionInfo section) { var matchedSection = Sections.Where(x => section.Equals(x)).FirstOrDefault(); if (matchedSection != null) { return(matchedSection); } Sections.Add(section); return(section); }
/// <summary> /// Gets a collection of LithologicDescriptions from a corrected file. /// </summary> /// <param name="filename"></param> /// <param name="columnIdentifiers"></param> /// <returns></returns> public static async Task <ICollection <LithologicDescription> > GetDescriptionsFromFileAsync(string filename, [Optional] IntervalHierarchyNames columnIdentifiers) { columnIdentifiers = columnIdentifiers ?? new IntervalHierarchyNames() { Expedition = "Expedition_VP", Site = "Site_VP", Hole = "Hole_VP", Core = "Core_VP", Type = "Type_VP", Section = "Section_VP", Half = "SectionHalf_VP", TopOffset = "TopOffset_VP", BottomOffset = "BottomOffset_VP", ArchiveTextID = "ArchiveSectionTextID_VP", WorkingTextID = "WorkingSectionTextID_VP", ParentTextID = "ParentSectionTextID_VP" }; IODPDataTable iODPDataTable = Importer.ImportDataTableFromFile(filename, columnIdentifiers); ICollection <LithologicDescription> descriptions = new HashSet <LithologicDescription>(); using (DescDBContext dbContext = new DescDBContext()) { try { foreach (DataRow row in iODPDataTable.DataTable.Rows) { SectionInfo section = new SectionInfo(Importer.GetHierarchyValuesFromDataRow(row, columnIdentifiers)); LithologicDescription description = new LithologicDescription(); // description.SectionInfo = section; description.SectionInfo = await DatabaseWorkflowHandler.GetSectionInfoFromDatabaseForIntervalAsync(dbContext, section).ConfigureAwait(true); description.LithologicID = row["LithologicID_VP"].ToString(); description.DataRow = row; description.DescriptionReport = row["Filename_VP"].ToString();; description.StartOffset = double.TryParse(row[columnIdentifiers.TopOffset].ToString(), out double startOffset) ? startOffset : -1; description.EndOffset = double.TryParse(row[columnIdentifiers.BottomOffset].ToString(), out double endOffset) ? endOffset : -1; descriptions.Add(description); } } catch (Exception) { throw new Exception("Error creating lithologic description from data row"); } } return(descriptions); }
public void ParseSectionInfoFromDataTable(DataTable sectionsDatatable, IntervalHierarchyNames hierarchyNames) { foreach (DataRow row in sectionsDatatable.Rows) { try { IntervalHierarchyValues values = Importer.GetHierarchyValuesFromDataRow(row, hierarchyNames); SectionInfo section = new SectionInfo(values); Sections.Add(section); } catch (Exception) { throw new Exception("Error parsing SectionInfo from data row"); } } }
} //Issue with new SectionInfo Overwriting data from database public LithologicDescription(SectionInfo sectionInfo) { SectionInfo = sectionInfo; }
/// <summary> /// Instantiates a new Lithologic Description /// </summary> public LithologicDescription() { SectionInfo = new SectionInfo(); } //Issue with new SectionInfo Overwriting data from database
/// <summary> /// Instantiates a new Lithologic Description /// </summary> /// <param name="SampleID">A IODP sample ID to be parsed to fill the Lithologic Description's SectionInfo fields</param> public LithologicDescription(string SampleID) : this() { SectionInfo = new SectionInfo(SampleID); }
public static SectionInfo GetSectionInfoFromCollection(ICollection <SectionInfo> sections, SectionInfo section) { return(sections.Where(record => section.Equals(record)).FirstOrDefault()); }
/// <summary> /// Asynchronously gets a SectionInfo from the databse for a given measurement or lithologic description interval /// </summary> /// <param name="dbContext">A DESCDatabase context</param> /// <param name="interval">An interval</param> /// <returns>A single SectionInfo</returns> public static async Task <SectionInfo> GetSectionInfoFromDatabaseForIntervalAsync(DescDBContext dbContext, SectionInfo section) { return(await dbContext.Sections.Where(record => record.Expedition == section.Expedition && record.Site == section.Site && record.Hole == section.Hole && record.Core == section.Core && record.Type == section.Type && record.Section == section.Section).FirstOrDefaultAsync().ConfigureAwait(true)); }
public static async Task <bool> CheckForSectionAsync(DescDBContext dBContext, SectionInfo section) { bool recordExists; if (section.ID != 0) { recordExists = await dBContext.Sections .Where(x => x.ID == section.ID) .AnyAsync().ConfigureAwait(true); } else if (section.ParentTextID != "") { recordExists = await dBContext.Sections .Where(x => x.ParentTextID == section.ParentTextID) .AnyAsync().ConfigureAwait(true); } else if (section.ID == 0) { recordExists = await dBContext.Sections .Where(x => section.Equals(x)) .AnyAsync().ConfigureAwait(true); } else { return(false); } return(recordExists); }
public Measurement(SectionInfo sectionInfo) : this() { SectionInfo = sectionInfo; }
public static List <DrillingDisturbanceRecord> FormatDrillingDisturbanceFile(string filename, string exportFilename) { Log.Information("--------Parsing a new file--------"); DataTable sections = SectionInfoCollection.ImportAllSections(ConfigurationManager.AppSettings["AllSectionsFile"]); ICollection <DrillingDisturbanceRecord> descriptions = new HashSet <DrillingDisturbanceRecord>(); List <DrillingDisturbanceRecord> FinalDescriptionsToAdd = new List <DrillingDisturbanceRecord>(); #region ImportDrillingDisturbances var dataTableReader = new CSVReader(); dataTableReader.ReadPath = filename; DataTable drillingDisturbances = dataTableReader.Read(); //Correct Column Names: ChangeColumn(drillingDisturbances, "Drilling disturbance intensity [rank]", "Drilling disturbance intensity rank"); ChangeColumn(drillingDisturbances, "Drilling disturbance intensity rank(read only)", "Drilling disturbance intensity rank"); ChangeColumn(drillingDisturbances, "Drilling disturbance intensity rank (read only)", "Drilling disturbance intensity rank"); ChangeColumn(drillingDisturbances, "Label ID", "Sample"); ChangeColumn(drillingDisturbances, "Top depth [m]", "Top Depth [m]"); ChangeColumn(drillingDisturbances, "Bottom depth [m]", "Bottom Depth [m]"); ChangeColumn(drillingDisturbances, "Disturbance [name]", "Disturbance"); ChangeColumn(drillingDisturbances, "File data", "File Data"); //Add additional columns if (!drillingDisturbances.Columns.Contains("Drilling disturbance comment")) { drillingDisturbances.Columns.Add("Drilling disturbance comment"); } if (!drillingDisturbances.Columns.Contains("Drilling disturbance type")) { drillingDisturbances.Columns.Add("Drilling disturbance type"); } if (!drillingDisturbances.Columns.Contains("Drilling disturbance intensity")) { drillingDisturbances.Columns.Add("Drilling disturbance intensity"); } if (!drillingDisturbances.Columns.Contains("Drilling disturbance intensity rank")) { drillingDisturbances.Columns.Add("Drilling disturbance intensity rank"); } try { //Collection of all drilling disturbances foreach (DataRow row in drillingDisturbances.Rows) { DrillingDisturbanceRecord record = new DrillingDisturbanceRecord() { Column1 = row["Column1"].ToString(), SampleID = row["Sample"].ToString(), Top_cm = row["Top [cm]"].ToString(), Bottom_cm = row["Bottom [cm]"].ToString(), TopDepth_m = row["Top Depth [m]"].ToString(), BottomDepth_m = row["Bottom Depth [m]"].ToString(), DrillingDisturbanceType = row["Drilling disturbance type"].ToString(), DrillingDisturbanceIntensity = row["Drilling disturbance intensity"].ToString(), DrillingDisturbanceIntensityRank = row["Drilling disturbance intensity rank"].ToString(), DrillingDisturbanceComment = row["Drilling disturbance comment"].ToString(), // ShipFileLinks = row["Ship File Links"].ToString(), // ShoreFileLinks = row["Shore File Links"].ToString(), FileData = row["File Data"].ToString() }; descriptions.Add(record); } } catch (Exception ex) { Log.Warning(ex.Message); Log.Warning($"Could not created disturbance records from {filename}"); return(FinalDescriptionsToAdd); } #endregion #region GetTheSectionsInCoreDescription foreach (var description in descriptions) { //Find rows where sample Id doesn't end in A OR W if (description.SampleID.EndsWith("A") || description.SampleID.EndsWith("W")) { FinalDescriptionsToAdd.Add(description); continue; } Log.Information($"{description.SampleID} is a description on the Core"); Log.Information($"{description.SampleID} TOP OFFSET: {description.Top_cm} BOTTOM OFFSET: {description.Bottom_cm} TOPDEPTH: {description.TopDepth_m} BOTTOM DEPTH: {description.BottomDepth_m}"); //At this point the description should be of the entire Core; //Parse Core information from the Sample: SectionInfo coreInfo = new SectionInfo(description.SampleID); //Find all the sections within the AllSectionsTable which overlap with the Top/Bottom offsets of the Core description var constituentSections = sections.AsEnumerable() .Where(x => x.Field <string>("Exp") == coreInfo.Expedition) .Where(x => x.Field <string>("Site") == coreInfo.Site) .Where(x => x.Field <string>("Hole") == coreInfo.Hole) .Where(x => x.Field <string>("Core") == coreInfo.Core) .Where(x => x.Field <string>("Type") == coreInfo.Type) .Where(x => (x.Field <string>("Top depth CSF-A (m)").ToDouble() >= description.TopDepth_m.ToDouble() && x.Field <string>("Top depth CSF-A (m)").ToDouble() < description.BottomDepth_m.ToDouble()) || (x.Field <string>("Bottom depth CSF-A (m)").ToDouble() > description.TopDepth_m.ToDouble() && x.Field <string>("Bottom depth CSF-A (m)").ToDouble() <= description.BottomDepth_m.ToDouble()) ) .Select(x => x) .ToHashSet(); //collection of datarows... //Create new drilling disturbance records by mashing up data between original Disturbances and sections: //Need to relook at this: Use only the top and bottom offsets from the Sample //Find the sections from the allsections table which overlap those intervals //Create new drilling disturbances with section information HashSet <DrillingDisturbanceRecord> newDrillingRecords = new HashSet <DrillingDisturbanceRecord>(); foreach (var section in constituentSections) { //Create new sampleID, All of them will be on the Archive half string newSampleID = string.Format("{0}-{1}{2}-{3}{4}-{5}-A", section["Exp"], section["Site"], section["Hole"], section["Core"], section["Type"], section["Sect"]); //Create a new drilling disturbance record var record = new DrillingDisturbanceRecord { Column1 = description.Column1, SampleID = newSampleID, Top_cm = "0", //section["Top Offset (cm)"].ToString(), Bottom_cm = Math.Round((section["Curated length (m)"].ToString().ToDouble() * 100), 2).ToString(), TopDepth_m = section["Top depth CSF-A (m)"].ToString(), BottomDepth_m = section["Bottom depth CSF-A (m)"].ToString(), DrillingDisturbanceType = description.DrillingDisturbanceType, DrillingDisturbanceIntensity = description.DrillingDisturbanceIntensityRank, DrillingDisturbanceComment = description.DrillingDisturbanceComment, DrillingDisturbanceIntensityRank = description.DrillingDisturbanceIntensityRank, ShipFileLinks = description.ShipFileLinks, ShoreFileLinks = description.ShoreFileLinks, FileData = description.FileData }; newDrillingRecords.Add(record); Log.Information($"{newSampleID}: Section Added: TOP OFFSET: {record.Top_cm} BOTTOM OFFSET: {record.Bottom_cm} TOP DEPTH: {record.TopDepth_m} BOTTOM DEPTH: {record.BottomDepth_m}"); } #endregion region #region SetTheOffsetsForBorderingSections //Set the TOP/BOTTOM offsets for core description's first and last sections to be equal to the core descriptions TOP/BOTTOM Offsets var topSection = newDrillingRecords.OrderBy(x => x.TopDepth_m).First(); var topCorrection = topSection.Top_cm.ToDouble() + (description.TopDepth_m.ToDouble() - topSection.TopDepth_m.ToDouble()) * 100; topCorrection = Math.Round(topCorrection, 2); topSection.Top_cm = topCorrection.ToString(); //Need to calculate offsets based on depths topSection.TopDepth_m = description.TopDepth_m; Log.Information($"{topSection.SampleID}: Changed TopDepth to {topSection.TopDepth_m} and TopOffset to {topSection.Top_cm}"); var bottomSection = newDrillingRecords.OrderBy(x => x.BottomDepth_m).Last(); var bottomCorrection = bottomSection.Bottom_cm.ToDouble() - (bottomSection.BottomDepth_m.ToDouble() - description.BottomDepth_m.ToDouble()) * 100; bottomCorrection = Math.Round(bottomCorrection, 2); bottomSection.Bottom_cm = bottomCorrection.ToString(); bottomSection.BottomDepth_m = description.BottomDepth_m; #endregion Log.Information($"{bottomSection.SampleID}: Changed BottomDepth to {bottomSection.BottomDepth_m} and BottomOffset to {bottomSection.Bottom_cm}"); foreach (var newSectionDescription in newDrillingRecords) { //Find all descriptions the core describer's made for this SECTION. The sample ID's should be equal var describedIntervalsOnSection = descriptions.Where(x => x.SampleID == newSectionDescription.SampleID).ToHashSet(); //If they described any intervals, pass those intervals into the algo to correctly process gap intervals if (describedIntervalsOnSection.Any()) { ICollection <DrillingDisturbanceRecord> finalRecords = CoreToSectionAlgo(newSectionDescription, describedIntervalsOnSection); FinalDescriptionsToAdd.AddRange(finalRecords); foreach (var record in finalRecords) { Log.Information($"{newSectionDescription.SampleID}: Adding to final descriptions"); } } else if (!describedIntervalsOnSection.Any()) { FinalDescriptionsToAdd.Add(newSectionDescription); Log.Information($"{newSectionDescription.SampleID}: Adding to final descriptions"); } } } //These are new descriptions to add to the file foreach (var record in FinalDescriptionsToAdd) { var offsetDifference = Math.Round(record.Bottom_cm.ToDouble() - record.Top_cm.ToDouble(), 2); var depthDifference = Math.Round((record.BottomDepth_m.ToDouble() - record.TopDepth_m.ToDouble()) * 100, 2); if (offsetDifference != depthDifference) { Log.Warning($"Error in Offsets: {record.SampleID}: TOP OFFSET: {record.Top_cm} BOTTOMOFFSET: {record.Bottom_cm} TOPDEPTH: {record.TopDepth_m} BOTTOMDEPTH: {record.BottomDepth_m}"); } else { Log.Information($"{record.SampleID}: TOP OFFSET: {record.Top_cm} BOTTOMOFFSET: {record.Bottom_cm} TOPDEPTH: {record.TopDepth_m} BOTTOMDEPTH: {record.BottomDepth_m}"); } } DataTable dt = new DataTable(); // DataColumn[] columns = new DataColumn[drillingDisturbances.Columns.Count]; // drillingDisturbances.Columns.CopyTo(columns, 0); // dt.Columns.AddRange(columns); for (int i = 0; i < drillingDisturbances.Columns.Count; i++) { dt.Columns.Add(drillingDisturbances.Columns[i].ColumnName, drillingDisturbances.Columns[i].DataType); } //Add in new corrected drilling disturbances foreach (var item in FinalDescriptionsToAdd) { DataRow row = dt.NewRow(); //row.BeginEdit(); row["Column1"] = item.Column1; row["Sample"] = item.SampleID; row["Top [cm]"] = item.Top_cm; row["Bottom [cm]"] = item.Bottom_cm; row["Top Depth [m]"] = item.TopDepth_m; row["Bottom Depth [m]"] = item.BottomDepth_m; row["Drilling disturbance type"] = item.DrillingDisturbanceType; row["Drilling disturbance intensity"] = item.DrillingDisturbanceIntensity; row["Drilling disturbance intensity rank"] = item.DrillingDisturbanceIntensityRank; row["Drilling disturbance comment"] = item.DrillingDisturbanceComment; //row["Ship File Links"] = item.ShipFileLinks; //row["Shore File Links"] = item.ShoreFileLinks; row["File Data"] = item.FileData; dt.Rows.Add(row); //row.EndEdit(); } Importer.ExportDataTableAsNewFile(exportFilename, dt); return(FinalDescriptionsToAdd); }