using ErrorAnalysis.Repository; using ErrorAnalysis.Repository.Entity; using ErrorAnalysis.Service; using ErrorAnalysis.Service.Model; using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ErrorAnalysis.Service { public class ErrorRatioCalc { private static (double slope, double intercept) _lineCoef; private static (double a, double b, double c) _parabolaCoef; public static ErrorRatioResult GetErrorRatioResult(string modelID, double porosity, double sw, double depth, bool lockSpeed, double speed, double yieldCounting, double targetErrorRatio, string type, out double testSpeed, out ProcessingDataModel processingData, int pass = 0, double nearCofe = 0.65, double farCofe = 0.35) { int countStart = 9; int countEnd = 179; if (type == "SMRT") { countStart = 24; } processingData = new ProcessingDataModel { Depth = depth, NearPDEVCoef = nearCofe, FarPDEVCoef = farCofe, NearTO = yieldCounting }; var result = new ErrorRatioResult { CWOL = new List(), OWOL = new List(), ErrorRatios = new List() }; result.COModel = RepositoryInstance.Instance.COModelRepository?.GetCOModel(modelID); (result.CWOL, result.OWOL) = GetOilWaterLine(modelID); processingData.OilLine = result.CWOL; processingData.WaterLine = result.OWOL; (processingData.OilLineOrigin, processingData.WaterLineOrgin) = GetOilWaterLine(modelID, true); processingData.FarSpecData = COMergeCalcService.GetFarSpectrum(modelID, porosity, sw); processingData.NearSpecData = COMergeCalcService.GetNearSpectrum(modelID, porosity, sw); var nearCROR = COMergeCalcService.GetNearCOORResult(modelID, porosity, sw, countStart, countEnd); var farCROR = COMergeCalcService.GetFarCOORResult(modelID, porosity, sw, countStart, countEnd); processingData.NearCR = nearCROR.Item1; processingData.NearOR = nearCROR.Item2; processingData.FarCR = farCROR.Item1; processingData.FarOR = farCROR.Item2; var mDelta = GetMDelta(porosity, out double oilPoint, out double waterPoint); processingData.OilPoint = oilPoint; processingData.WaterPoint = waterPoint; if (lockSpeed) { var mergePDEV = Math.Sqrt(160 * speed / (0.0762 * 36 * depth)) * Math.Sqrt((Math.Pow(nearCofe, 2) / yieldCounting * (Math.Pow(nearCROR.Item1 / nearCROR.Item2, 2)) * (1 / nearCROR.Item1 + 1 / nearCROR.Item2)) + (Math.Pow(farCofe, 2) / yieldCounting / 2.2 * (Math.Pow(farCROR.Item1 / farCROR.Item2, 2)) * (1 / farCROR.Item1 + 1 / farCROR.Item2))); var firstErrorPassM = new ErrorRatio { Pass = 1, ErrorRatioValue = mergePDEV / mDelta }; result.ErrorRatios.Clear(); result.ErrorRatios.Add(firstErrorPassM); if (firstErrorPassM.ErrorRatioValue > targetErrorRatio) { var targetPass = Convert.ToInt32(Math.Ceiling(Math.Pow(firstErrorPassM.ErrorRatioValue / targetErrorRatio, 2))); for (int i = 2; i <= targetPass; i++) { result.ErrorRatios.Add(new ErrorRatio { Pass = i, ErrorRatioValue = firstErrorPassM.ErrorRatioValue / Math.Sqrt(i) }); } } processingData.Speed = speed; } else { var firstTargetErrorRatio = targetErrorRatio * Math.Sqrt(pass); processingData.Speed = speed = Math.Pow(firstTargetErrorRatio / (Math.Sqrt(160 / (0.0762 * depth * 36d)) * 1d / mDelta) / Math.Sqrt((Math.Pow(nearCofe, 2) / yieldCounting * (Math.Pow(nearCROR.Item1 / nearCROR.Item2, 2)) * (1 / nearCROR.Item1 + 1 / nearCROR.Item2)) + (Math.Pow(farCofe, 2) / yieldCounting / 2.2 * (Math.Pow(farCROR.Item1 / farCROR.Item2, 2)) * (1 / farCROR.Item1 + 1 / farCROR.Item2))) , 2); var firstErrorPass = new ErrorRatio { Pass = 1, ErrorRatioValue = firstTargetErrorRatio }; //var firstErrorPass = new ErrorRatio(); //speed = 0.05; //do //{ // firstErrorPass = GetFirstErrorRatio(modelID, porosity, sw, speed, depth, yieldCounting, nearCofe, farCofe); // result.CWOL = cWOL; // result.OWOL = oWOL; // speed -= 0.0001; //} while (firstErrorPass.ErrorRatioValue != 0 && firstErrorPass.ErrorRatioValue > firstTargetErrorRatio); result.ErrorRatios.Clear(); result.ErrorRatios.Add(firstErrorPass); for (int i = 2; i <= pass; i++) { result.ErrorRatios.Add(new ErrorRatio { Pass = i, ErrorRatioValue = firstErrorPass.ErrorRatioValue / Math.Sqrt(i) }); } } testSpeed = speed; return result; } //废弃 private static ErrorRatio GetFirstErrorRatio(string modelID, double porosity, double sw, double speed, double depth, double yieldCounting, double nearCofe, double farCofe,int countStart,int countEnd, out double oilPoint, out double waterPoint) { if (porosity > 40) throw new InvalidDataException("Porosity value out of range!"); try { var mDelta = GetMDelta(porosity, out oilPoint, out waterPoint); var mergePDEVOld = PDEVCalcService.GetMergePDEV(modelID, porosity, sw, speed, depth, yieldCounting, nearCofe, farCofe,countStart,countEnd); //var nearCROR = COMergeCalcService.GetNearCOORResult(modelID, porosity, sw); //var farCROR = COMergeCalcService.GetFarCOORResult(modelID, porosity, sw); //var mergePDEV = Math.Sqrt(160 * speed / (0.0762 * 36 * depth)) * Math.Sqrt((Math.Pow(nearCofe, 2) / yieldCounting * (Math.Pow(nearCROR.Item1 / nearCROR.Item2, 2)) * (1 / nearCROR.Item1 + 1 / nearCROR.Item2)) + (Math.Pow(farCofe, 2) / yieldCounting / 2.2 * (Math.Pow(farCROR.Item1 / farCROR.Item2, 2)) * (1 / farCROR.Item1 + 1 / farCROR.Item2))); var errorRatio = mergePDEVOld / mDelta; return new ErrorRatio { Pass = 1, ErrorRatioValue = errorRatio }; } catch { oilPoint = 0; waterPoint = 0; return new ErrorRatio { Pass = 0, ErrorRatioValue = 0 }; } } private static double GetMDelta(double porosity, out double oilPoint, out double waterPoint) { oilPoint = Utility.GetParabolaValue(porosity, _parabolaCoef.a, _parabolaCoef.b, _parabolaCoef.c); waterPoint = Utility.GetLineValue(porosity, _lineCoef.slope, _lineCoef.intercept); //var cWolRes = RepositoryInstance.Instance.COWOLRepository?.GetWOL(modelID, 0); //var oWolRes = RepositoryInstance.Instance.COWOLRepository?.GetWOL(modelID, 100); //var wolResType = cWolRes?.GetType(); //double cRes = 0; //double oRes = 0; //if (porosity % 5 == 0) //{ // var poroFiledName = $"WLPu" + porosity; // var property = wolResType.GetProperty(poroFiledName); // cRes = Convert.ToDouble(property.GetValue(cWolRes)); // oRes = Convert.ToDouble(property.GetValue(oWolRes)); //} //else //{ // var ceilingPorosity = Math.Ceiling(porosity / 5) * 5; // var ceilingProperty = wolResType.GetProperty($"WLPu" + ceilingPorosity); // var ceilingC = Convert.ToDouble(ceilingProperty.GetValue(cWolRes)); // var ceilingO = Convert.ToDouble(ceilingProperty.GetValue(oWolRes)); // var floorPorosity = Math.Floor(porosity / 5) * 5; // var floorProperty = wolResType.GetProperty($"WLPu" + floorPorosity); // var floorC = Convert.ToDouble(floorProperty.GetValue(cWolRes)); // var floorO = Convert.ToDouble(floorProperty.GetValue(oWolRes)); // cRes = Utility.Interpolate(porosity, floorPorosity, floorC, ceilingPorosity, ceilingC); // oRes = Utility.Interpolate(porosity, floorPorosity, floorO, ceilingPorosity, ceilingO); //} return oilPoint - waterPoint; } private static (List, List) GetOilWaterLine(string modelID, bool original = false) { var cWOL = new List(); var oWOL = new List(); var fitModel = original ? GetModel(modelID) : GetFitModel(modelID); var cWolRes = fitModel.Item1; var oWolRes = fitModel.Item2; var wolResType = cWolRes?.GetType(); foreach (var wolProperty in wolResType.GetProperties()) { if (wolProperty.Name.Contains("WLPu")) { cWOL.Add([Convert.ToDouble(wolProperty.Name.Replace("WLPu", "")), Convert.ToDouble(wolProperty.GetValue(cWolRes))]); oWOL.Add([Convert.ToDouble(wolProperty.Name.Replace("WLPu", "")), Convert.ToDouble(wolProperty.GetValue(oWolRes))]); } } return (cWOL, oWOL); } private static (COWOLTable, COWOLTable) GetModel(string modelID) { var oilWol = RepositoryInstance.Instance.COWOLRepository?.GetWOL(modelID, 0); var waterWol = RepositoryInstance.Instance.COWOLRepository?.GetWOL(modelID, 100); return (oilWol, waterWol); } private static (COWOLTable, COWOLTable) GetFitModel(string modelID) { var oilWol = RepositoryInstance.Instance.COWOLRepository?.GetWOL(modelID, 0); var waterWol = RepositoryInstance.Instance.COWOLRepository?.GetWOL(modelID, 100); var wolResType = oilWol?.GetType(); List oilPoints = []; List waterPoints = []; foreach (var wolProperty in wolResType.GetProperties()) { if (wolProperty.Name.Contains("WLPu")) { var porosity = float.Parse(wolProperty.Name.Replace("WLPu", "")); var oilVal = (double)wolProperty.GetValue(oilWol); var waterVal = (double)wolProperty.GetValue(waterWol); oilPoints.Add(new PointF(porosity, (float)oilVal)); waterPoints.Add(new PointF(porosity, (float)waterVal)); } } _lineCoef = Utility.FitLine(waterPoints.ToArray()); _parabolaCoef = Utility.FitParabola(oilPoints.ToArray()); //var texCoef = Utility.quadraticLine(oilPoints.Select(o => Convert.ToDouble(o.X)).ToArray(), oilPoints.Select(o => Convert.ToDouble(o.Y)).ToArray()); double initDiff = 0; foreach (var wolProperty in wolResType.GetProperties()) { if (wolProperty.Name.Contains("WLPu")) { var porosity = double.Parse(wolProperty.Name.Replace("WLPu", "")); var waterVal = Utility.GetLineValue(porosity, _lineCoef.slope, _lineCoef.intercept); var oilVal = Utility.GetParabolaValue(porosity, _parabolaCoef.a, _parabolaCoef.b, _parabolaCoef.c); //var testoilVal = Utility.GetParabolaValue(porosity, texCoef.a, texCoef.b, texCoef.c); if (porosity == 0) { initDiff = oilVal - waterVal; } wolProperty.SetValue(waterWol, waterVal + initDiff); wolProperty.SetValue(oilWol, oilVal); } } return (oilWol, waterWol); } } }