using ErrorAnalysis.Repository; using ErrorAnalysis.Repository.Entity; using ErrorAnalysis.Service; using ErrorAnalysis.Service.Model; using ErrorAnalysis.UI.Utility; using OxyPlot; using OxyPlot.Axes; using OxyPlot.Legends; using OxyPlot.Series; using OxyPlot.WindowsForms; using System.ComponentModel.DataAnnotations; using System.Security.Cryptography; using System.Windows.Forms; using static System.Windows.Forms.VisualStyles.VisualStyleElement.Menu; namespace ErrorAnalysis.UI { public partial class FrmMain : Form { private string? _connectionString; private List _models; private Dictionary _filters; private COModelTable _model; private ReportModel _reportModel; public FrmMain() { InitializeComponent(); } private void FrmMain_Load(object sender, EventArgs e) { cmbSpeedUnit.SelectedIndex = 0; cmbTargetLoggingIntervalUnit.SelectedIndex = 0; } private void InitInputControl() { foreach (var item in gpBorehole.Controls) if (item is ComboBox cmb) cmb.Items.Clear(); if (_models != null) { cmbBit.Items.AddRange(_models.Select(m => m.BIT).Distinct().ToArray()); } } #region button event private void btnSelectDataSource_Click(object sender, EventArgs e) { var fileDlg = new OpenFileDialog(); fileDlg.Filter = "Data source|*.db"; fileDlg.InitialDirectory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Projects"); fileDlg.FilterIndex = 0; var result = fileDlg.ShowDialog(); if (result == DialogResult.OK) { pbLoadDB.Show(); pbLoadDB.Value = 0; txtDataPath.Text = fileDlg.FileName; txtToolType.Text = fileDlg.SafeFileName.Substring(0, fileDlg.SafeFileName.IndexOf("Mcnp")); _connectionString = $"Data Source={fileDlg.FileName};"; RepositoryInstance.Instance.ReLoad(_connectionString); pbLoadDB.Value = 50; _filters = new Dictionary(); Task.Run(() => { _models = RepositoryInstance.Instance.COModelRepository.GetCOModels(); BeginInvoke(new System.Action(() => { pbLoadDB.Value = 80; InitInputControl(); })); BeginInvoke(new System.Action(() => { pbLoadDB.Value = 100; })); Thread.Sleep(1000); BeginInvoke(new System.Action(() => { pbLoadDB.Hide(); })); }); } } private void btnAnalysis_Click(object sender, EventArgs e) { var curModels = GetFilterResult(); if (curModels == null || curModels.Count == 0) { MessageBox.Show("Please enter info!"); return; } if (!double.TryParse(nudPorosity.Value.ToString(), out double porosity) || nudPorosity.Value < 5) { MessageBox.Show("Please enter a reasonable porosity"); return; } if (!double.TryParse(nudSw.Value.ToString(), out double sw)) { MessageBox.Show("Please enter a reasonable water saturation!"); return; } if (!double.TryParse(nudDepth.Value.ToString(), out double depth) || nudDepth.Value <= 0) { MessageBox.Show("Please enter a reasonable depth"); return; } if (!double.TryParse(nudSoPrecisionRequired.Value.ToString(), out double targetErrorRatio) || nudSoPrecisionRequired.Value <= 0) { MessageBox.Show("Please enter a reasonable so precision required"); return; } if (!double.TryParse(nudTargetLoggingInterval.Value.ToString(), out double targetLoggingInterval) || nudTargetLoggingInterval.Value <= 0) { MessageBox.Show("Please select a target logging interval"); return; } if (cmbLithology.SelectedIndex == -1) { MessageBox.Show("Please select a lithology"); return; } if (curModels.Count == 0) { MessageBox.Show("Parameters error!"); return; } if (!decimal.TryParse(nudOilDensity.Value.ToString(), out decimal oilDensity) || nudOilDensity.Value <= 0) { MessageBox.Show("Please enter a reasonable oil density"); return; } if (!double.TryParse(nudYieldCounting.Value.ToString(), out double yieldCounting) || nudYieldCounting.Value <= 0) { MessageBox.Show("Please enter a reasonable yield counting"); return; } if (curModels.Count == 1) _model = curModels[0]; _model = curModels.FirstOrDefault(m => m.GravelFillPercent == nudGravelFIllPercent.Value.ToString() && m.OilDensity == oilDensity); if (_model == null) _model = curModels.First(); nudOilDensity.Value = _model.OilDensity.Value; nudGravelFIllPercent.Value = Convert.ToDecimal(_model.GravelFillPercent); if (cmbTargetLoggingIntervalUnit.Text == "ft") targetLoggingInterval = UnitConvert.Ft2M(targetLoggingInterval); txtAnalysisResult.Clear(); if (rdoLockSpeed.Checked) { if (!double.TryParse(nudSpeed.Value.ToString(), out double speed) || nudSpeed.Value <= 0) { MessageBox.Show("Please enter a reasonable speed"); return; } var calcSpeed = cmbSpeedUnit.Text == "ft/hr" ? UnitConvert.FtHr2MS(speed) : UnitConvert.MHR2MS(speed); var result = ErrorRatioCalc.GetErrorRatioResult(_model.ModelID, porosity, sw, depth, true, calcSpeed, yieldCounting, targetErrorRatio / 100, out _); Plot(result); double totalTime = Math.Round((targetLoggingInterval / calcSpeed / 60 / 60), 2); var errorRate = Math.Round(result.ErrorRatios.Min(r => r.ErrorRatioValue) * 100, 2); txtAnalysisResult.AppendText("A total of "); AppendText(txtAnalysisResult, result.ErrorRatios.Count.ToString(), ColorTranslator.FromHtml("#8B0000")); txtAnalysisResult.AppendText(" passes are recommended to maintain a "); AppendText(txtAnalysisResult, $"{errorRate}%", ColorTranslator.FromHtml("#8B0000")); txtAnalysisResult.AppendText(" error rate. With the tool operating at "); AppendText(txtAnalysisResult, $"{speed} {cmbSpeedUnit.Text}", ColorTranslator.FromHtml("#8B0000")); txtAnalysisResult.AppendText(" the estimated total job duration is "); AppendText(txtAnalysisResult, $"{totalTime} hours.", ColorTranslator.FromHtml("#8B0000")); _reportModel = CreateReportModel(totalTime.ToString(), result.ErrorRatios.Count.ToString(), Math.Round(UnitConvert.MS2FtHr(calcSpeed), 2).ToString(), errorRate.ToString()); } else { if (!int.TryParse(nudPass.Value.ToString(), out int pass) || nudPass.Value <= 1) { MessageBox.Show("Please enter a reasonable pass"); return; } double speed; var result = ErrorRatioCalc.GetErrorRatioResult(_model.ModelID, porosity, sw, depth, false, 0, yieldCounting, targetErrorRatio / 100, out speed, pass); Plot(result); double totalTime = Math.Round((targetLoggingInterval / speed / 60 / 60), 2); var errorRate = Math.Round(result.ErrorRatios.Min(r => r.ErrorRatioValue) * 100, 2); var speedFr = Math.Round(UnitConvert.MS2FtHr(speed), 2); txtAnalysisResult.AppendText("A total of "); AppendText(txtAnalysisResult, result.ErrorRatios.Count.ToString(), ColorTranslator.FromHtml("#8B0000")); txtAnalysisResult.AppendText(" passes are recommended to maintain a "); AppendText(txtAnalysisResult, $"{errorRate}%", ColorTranslator.FromHtml("#8B0000")); txtAnalysisResult.AppendText(" error rate. With the tool operating at "); AppendText(txtAnalysisResult, $"{speedFr} ft/hr", ColorTranslator.FromHtml("#8B0000")); txtAnalysisResult.AppendText(" the estimated total job duration is "); AppendText(txtAnalysisResult, $"{totalTime} hours.", ColorTranslator.FromHtml("#8B0000")); _reportModel = CreateReportModel(totalTime.ToString(), result.ErrorRatios.Count.ToString(), speedFr.ToString(), errorRate.ToString()); } } private void btnReport_Click(object sender, EventArgs e) { new Report(_reportModel).ShowDialog(); } #endregion #region Input event private void borehole_cmb_SelectedIndexChanged(object sender, EventArgs e) { var control = (sender as ComboBox); var property = control.Tag.ToString(); var filterVal = control.Text == "none" ? "0" : control.Text; if (_filters.ContainsKey(property)) _filters[property] = filterVal; else _filters.Add(property, filterVal); var parentControl = control.Parent; var allCmb = parentControl.Controls.OfType().Where(c => c is ComboBox).Select(c => c as ComboBox).ToList(); switch (control.Name) { case "cmbBit": cmbCasingOD.Items.Clear(); _filters.Remove("CasingOD"); goto case "cmbCasingOD"; case "cmbCasingOD": cmbCasingID.Items.Clear(); _filters.Remove("CasingID"); goto case "cmbCasingID"; case "cmbCasingID": cmbScreenOD.Items.Clear(); _filters.Remove("ScreenOD"); goto case "cmbScreenOD"; case "cmbScreenOD": cmbScreenID.Items.Clear(); _filters.Remove("ScreenID"); goto case "cmbScreenID"; case "cmbScreenID": cmbTubeOD.Items.Clear(); _filters.Remove("TubeOD"); goto case "cmbTubeOD"; case "cmbTubeOD": cmbTubeID.Items.Clear(); _filters.Remove("TubeID"); break; case "cmbTubeID": break; default: break; } cmbCasingHoldUp.Items.Clear(); _filters.Remove("CasingFluid"); cmbScreenHoldUp.Items.Clear(); _filters.Remove("ScreenFluid"); cmbTubeHoldUp.Items.Clear(); _filters.Remove("TubeFluid"); cmbLithology.Items.Clear(); _filters.Remove("Lithology"); var unSelectedCmbs = allCmb.Where(c => c.SelectedIndex == -1).ToList(); var curModels = GetFilterResult(); var modelType = typeof(COModelTable); foreach (var cmb in unSelectedCmbs) { cmb.Items.Clear(); cmb.Enabled = true; var currentItems = curModels.Select(c => modelType.GetProperty(cmb.Tag.ToString()).GetValue(c).ToString() == "0" ? "none" : modelType.GetProperty(cmb.Tag.ToString()).GetValue(c).ToString()).Distinct().ToArray(); if (currentItems.Length == 0) cmb.Enabled = false; cmb.Items.AddRange(currentItems); if (currentItems.Length == 1) cmb.Text = currentItems[0]; } holdCmbInit(); LinkageModelProperty(); } private void holdCmbInit() { cmbCasingHoldUp.Items.Clear(); _filters.Remove("CasingFluid"); cmbScreenHoldUp.Items.Clear(); _filters.Remove("ScreenFluid"); cmbTubeHoldUp.Items.Clear(); _filters.Remove("TubeFluid"); cmbLithology.Items.Clear(); _filters.Remove("Lithology"); var curModels = GetFilterResult(); if (curModels.Count == 0) return; var casingFulids = curModels.Select(x => x.CasingFluid == "999" ? "none" : x.CasingFluid == "100" ? "oil" : x.CasingFluid == "200" ? "gas" : "water").Distinct().ToArray(); if (casingFulids.Length == 1 && casingFulids[0] == "none") { cmbCasingHoldUp.Enabled = false; nudCasingHoldUp.Enabled = false; } else { cmbCasingHoldUp.Enabled = true; nudCasingHoldUp.Enabled = true; cmbCasingHoldUp.Items.AddRange(casingFulids); } var screenFulids = curModels.Select(x => x.ScreenFluid == "999" ? "none" : x.ScreenFluid == "100" ? "oil" : x.ScreenFluid == "200" ? "gas" : "water").Distinct().ToArray(); if (screenFulids.Length == 1 && screenFulids[0] == "none") { cmbScreenHoldUp.Enabled = false; nudScreenHoldUp.Enabled = false; } else { cmbScreenHoldUp.Enabled = true; nudScreenHoldUp.Enabled = true; cmbScreenHoldUp.Items.AddRange(screenFulids); } var tubeFluids = curModels.Select(x => x.TubeFluid == "999" ? "none" : x.TubeFluid == "100" ? "oil" : x.TubeFluid == "200" ? "gas" : "water").Distinct().ToArray(); if (tubeFluids.Length == 1 && tubeFluids[0] == "none") { cmbTubeHoldUp.Enabled = false; nudTubeHoldUp.Enabled = false; } else { cmbTubeHoldUp.Enabled = true; nudTubeHoldUp.Enabled = true; cmbTubeHoldUp.Items.AddRange(tubeFluids); } } private void LinkageModelProperty() { var curLithology = cmbLithology.Text; cmbLithology.Items.Clear(); _filters.Remove("Lithology"); var curModels = GetFilterResult(); if (curModels.Count == 0) return; var gravelFills = curModels.Select(x => x.GravelFillPercent).Distinct().ToArray(); if (gravelFills.Length == 1) nudGravelFIllPercent.Value = Convert.ToDecimal(gravelFills[0]); var cementBonds = curModels.Select(x => x.CementBond).Distinct().ToArray(); if (cementBonds.Length == 1) nudCementBond.Value = Convert.ToDecimal(cementBonds[0]); var bhSalinities = curModels.Select(x => x.BHSalinity).Distinct().ToArray(); if (bhSalinities.Length == 1) nudBHSalinity.Value = Convert.ToDecimal(bhSalinities[0]); var oilDensities = curModels.Select(x => x.OilDensity).Distinct().ToArray(); if (oilDensities.Length == 1) nudOilDensity.Value = Convert.ToDecimal(oilDensities[0]); var reservoirSalinities = curModels.Select(x => x.ReservoirSalinity).Distinct().ToArray(); if (reservoirSalinities.Length == 1) nudReservoirSalinity.Value = Convert.ToDecimal(reservoirSalinities[0]); var vshs = curModels.Select(x => x.VSH).Distinct().ToArray(); if (vshs.Length == 1) nudVSH.Value = Convert.ToDecimal(vshs[0]); var lithology = curModels.Select(x => x.Lithology).Distinct().ToArray(); cmbLithology.Items.AddRange(lithology); if (cmbLithology.Items.Contains(curLithology)) cmbLithology.Text = curLithology; if (lithology.Length == 1) cmbLithology.SelectedIndex = 0; } private void holdUp_cmb_SelectedIndexChanged(object sender, EventArgs e) { var control = (sender as ComboBox); var parentControl = control.Parent; var property = control.Tag.ToString(); var filterVal = control.Text == "water" ? "0" : control.Text == "oil" ? "100" : control.Text == "gas" ? "200" : "999"; if (_filters==null) return; if (_filters.ContainsKey(property)) _filters[property] = filterVal; else _filters.Add(property, filterVal); var allCmb = parentControl.Controls.OfType().Where(c => c is ComboBox).Select(c => c as ComboBox).ToList(); switch (control.Name) { case "cmbCasingHoldUp": cmbScreenHoldUp.Items.Clear(); _filters.Remove("ScreenFluid"); goto case "cmbScreenHoldUp"; case "cmbScreenHoldUp": cmbTubeHoldUp.Items.Clear(); _filters.Remove("TubeFluid"); break; default: break; } var unSelectedCmbs = allCmb.Where(c => c.SelectedIndex == -1).ToList(); var curModels = GetFilterResult(); var modelType = typeof(COModelTable); foreach (var cmb in unSelectedCmbs) { cmb.Items.Clear(); cmb.Enabled = true; var cmbProperty = modelType.GetProperty(cmb.Tag.ToString()); var currentItems = curModels.Select(c => cmbProperty.GetValue(c).ToString() == "0" ? "water" : cmbProperty.GetValue(c).ToString() == "100" ? "oil" : cmbProperty.GetValue(c).ToString() == "200" ? "gas" : "none").Distinct().ToArray(); if (currentItems.Length == 0 || (currentItems.Length == 1 && currentItems[0] == "none")) { cmb.Enabled = false; continue; } cmb.Items.AddRange(currentItems); if (_filters.ContainsKey(cmb.Tag.ToString()) && currentItems.Contains(_filters[cmb.Tag.ToString()])) cmb.Text = _filters[cmb.Tag.ToString()]; else { _filters.Remove(cmb.Tag.ToString()); if (currentItems.Length == 1) cmb.SelectedIndex = 0; } } LinkageModelProperty(); //foreach (var cmb in allCmb) //{ // if (cmb.Name != control.Name) // { // var curItems = cmb.Items.OfType().ToList(); // var cmbProperty = modelType.GetProperty(cmb.Tag.ToString()); // var curFluids = curModels.Select(x => cmbProperty.GetValue(x).ToString() == "0" ? "water" : cmbProperty.GetValue(x).ToString() == "100" ? "oil" : cmbProperty.GetValue(x).ToString() == "200" ? "gas" : "none").Distinct().ToArray(); // var minusFluids = curItems.Where(i => !curFluids.Contains(i)).ToArray(); // foreach (var item in minusFluids) // cmb.Items.Remove(item); // var addFluids = curFluids.Where(i => !curItems.Contains(i)).ToArray(); // cmb.Items.AddRange(addFluids); // } //} } private void cmbLithology_SelectedIndexChanged(object sender, EventArgs e) { var control = (sender as ComboBox); var property = control.Tag.ToString(); var filterVal = control.Text == "none" ? "0" : control.Text; if (_filters.ContainsKey(property)) _filters[property] = filterVal; else _filters.Add(property, filterVal); } private void rdoMode_CheckedChanged(object sender, EventArgs e) { if (rdoLockSpeed.Checked) { pnlLockPass.Visible = false; pnlLockSpeed.Visible = true; } else { pnlLockPass.Visible = true; pnlLockSpeed.Visible = false; } } #endregion private List GetFilterResult() { var type = typeof(COModelTable); var result = _models; foreach (var filter in _filters) result = result.Where(c => type.GetProperty(filter.Key).GetValue(c).ToString() == filter.Value).ToList(); return result; } private void Plot(ErrorRatioResult errorResult) { pnlCOPic.Controls.Clear(); var plotModel = new PlotModel(); var xAxis = new LinearAxis { Position = AxisPosition.Bottom, Title = "Porosity(%)" }; var yAxis = new LinearAxis { Position = AxisPosition.Left, Title = "C/O" }; xAxis.MajorGridlineStyle = LineStyle.DashDashDotDot; yAxis.MajorGridlineStyle = LineStyle.DashDot; plotModel.Axes.Add(xAxis); plotModel.Axes.Add(yAxis); // ´´½¨ÇúÏßϵÁÐ var oSeries = new LineSeries { Title = "Water Line", Color = OxyColors.MediumBlue }; var cSeries = new LineSeries { Title = "Oil Line", Color = OxyColors.DarkRed }; foreach (var o in errorResult.OWOL) oSeries.Points.Add(new DataPoint(o[0], o[1])); foreach (var c in errorResult.CWOL) cSeries.Points.Add(new DataPoint(c[0], c[1])); plotModel.Legends.Add(new Legend { LegendPosition = LegendPosition.TopLeft }); // Ìí¼ÓÇúÏßµ½Í¼±íÄ£ÐÍ plotModel.Series.Add(oSeries); plotModel.Series.Add(cSeries); // ¿ÉÊÓ»¯´úÂë // ´´½¨ Windows ´°ÌåÒÔÏÔʾͼ±í var plotView = new PlotView { Model = plotModel }; plotView.Width = 600; plotView.Height = 450; var bitmap = new Bitmap(plotView.Width, plotView.Height); plotView.DrawToBitmap(bitmap, new Rectangle(0, 0, bitmap.Width, bitmap.Height)); bitmap.Save(AppDomain.CurrentDomain.BaseDirectory + "co.png", System.Drawing.Imaging.ImageFormat.Png); plotView.Dock = DockStyle.Fill; pnlCOPic.Controls.Add(plotView); pnlErrorRatioPic.Controls.Clear(); plotModel = new PlotModel(); xAxis = new LinearAxis { Position = AxisPosition.Bottom, Title = "Pass" }; xAxis.MajorGridlineStyle = LineStyle.Dash; yAxis = new LinearAxis { Position = AxisPosition.Left, Title = "Error Ratio(%)" }; yAxis.MajorGridlineStyle = LineStyle.Dash; plotModel.Axes.Add(xAxis); plotModel.Axes.Add(yAxis); var series = new LineSeries { Title = "Error Ratio", Color = OxyColors.DarkRed, MarkerType = MarkerType.Diamond }; foreach (var item in errorResult.ErrorRatios) series.Points.Add(new DataPoint(item.Pass, item.ErrorRatioValue * 100)); plotModel.Series.Add(series); plotView = new PlotView { Model = plotModel }; plotView.Width = 600; plotView.Height = 450; bitmap = new Bitmap(plotView.Width, plotView.Height); plotView.DrawToBitmap(bitmap, new Rectangle(0, 0, bitmap.Width, bitmap.Height)); bitmap.Save(AppDomain.CurrentDomain.BaseDirectory + "er.png", System.Drawing.Imaging.ImageFormat.Png); plotView.Dock = DockStyle.Fill; pnlErrorRatioPic.Controls.Add(plotView); } private ReportModel CreateReportModel(string duration, string pass, string speed, string soPrecision) { return new ReportModel { BHSalinity = nudBHSalinity.Value.ToString(), BIT = cmbBit.Text, CasingFluid = cmbCasingHoldUp.Text, CasingHoldUp = nudCasingHoldUp.Value.ToString(), CasingID = cmbCasingID.Text, CasingOD = cmbCasingOD.Text, CementBond = nudCementBond.Text, DepthAveraging = nudDepth.Value.ToString(), Duration = duration, GasSalinity = nudGasDensity.Value.ToString(), GravelFillPercent = nudGravelFIllPercent.Value.ToString(), Lithology = cmbLithology.Text, OilSalinity = nudOilDensity.Value.ToString(), Pass = pass, Porosity = nudPorosity.Value.ToString(), ReserviorSalinity = nudReservoirSalinity.Value.ToString(), ScreenFluid = cmbScreenHoldUp.Text, ScreenHoldUp = nudScreenHoldUp.Value.ToString(), ScreenID = cmbScreenID.Text, ScreenOD = cmbScreenOD.Text, SoPrecisionRequired = soPrecision, Speed = speed, TargetLoggingInterval = nudTargetLoggingInterval.Value.ToString(), TubeFluid = cmbTubeHoldUp.Text, TubeHoldUp = nudTubeHoldUp.Value.ToString(), TubeID = cmbTubeID.Text, TubeOD = cmbTubeOD.Text, VSH = nudVSH.Value.ToString(), WaterSaturation = nudSw.Value.ToString() }; } private void AppendText(RichTextBox rtb, string text, Color color, Font font = null, bool isNewLine = false) { rtb.SuspendLayout(); rtb.SelectionStart = rtb.TextLength; rtb.SelectionLength = 0; rtb.SelectionColor = color; if (font != null) rtb.SelectionFont = font; rtb.AppendText(isNewLine ? $"{text}{Environment.NewLine}" : text); rtb.SelectionColor = rtb.ForeColor; rtb.ScrollToCaret(); rtb.ResumeLayout(); } } }