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, out double testSpeed, int pass = 0, double nearCofe = 0.65, double farCofe = 0.35) { var result = new ErrorRatioResult { CWOL = new List(), OWOL = new List(), ErrorRatios = new List() }; result.COModel = RepositoryInstance.Instance.COModelRepository?.GetCOModel(modelID); if (lockSpeed) { List cWOL; List oWOL; (cWOL, oWOL) = GetOilWaterLine(modelID); result.CWOL = cWOL; result.OWOL = oWOL; var firstErrorPassM = GetFirstErrorRatio(modelID, porosity, sw, speed, depth, yieldCounting, nearCofe, farCofe); 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) }); } } } else { var firstTargetErrorRatio = targetErrorRatio * Math.Sqrt(pass); List cWOL; List oWOL; (cWOL, oWOL) = GetOilWaterLine(modelID); result.CWOL = cWOL; result.OWOL = oWOL; var nearCROR = COMergeCalcService.GetNearCOORResult(modelID, porosity, sw); var farCROR = COMergeCalcService.GetFarCOORResult(modelID, porosity, sw); var mDelta = GetMDelta(porosity); speed = Math.Pow(firstTargetErrorRatio / (Math.Sqrt(160 / (0.0762 * depth * 36d * yieldCounting)) * 1d / mDelta) / Math.Sqrt((Math.Pow(nearCofe, 2) * (Math.Pow(nearCROR.Item1 / nearCROR.Item2, 2)) * (1 / nearCROR.Item1 + 1 / nearCROR.Item2)) + (Math.Pow(farCofe, 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) { if (porosity > 40) throw new InvalidDataException("Porosity value out of range!"); try { var mDelta = GetMDelta(porosity); //var mergePDEVOld = PDEVCalcService.GetMergePDEV(modelID, porosity, sw, speed, depth, yieldCounting, nearCofe, farCofe); var nearCROR = COMergeCalcService.GetNearCOORResult(modelID, porosity, sw); var farCROR = COMergeCalcService.GetFarCOORResult(modelID, porosity, sw); var mergePDEV = Math.Sqrt(160 * speed / (0.0762 * 36 * depth * yieldCounting)) * Math.Sqrt((Math.Pow(nearCofe, 2) * (Math.Pow(nearCROR.Item1 / nearCROR.Item2, 2)) * (1 / nearCROR.Item1 + 1 / nearCROR.Item2)) + (Math.Pow(farCofe, 2) * (Math.Pow(farCROR.Item1 / farCROR.Item2, 2)) * (1 / farCROR.Item1 + 1 / farCROR.Item2))); var errorRatio = mergePDEV / mDelta; return new ErrorRatio { Pass = 1, ErrorRatioValue = errorRatio }; } catch { return new ErrorRatio { Pass = 0, ErrorRatioValue = 0 }; } } private static double GetMDelta(double porosity) { var oilRes = Utility.GetParabolaValue(porosity, _parabolaCoef.a, _parabolaCoef.b, _parabolaCoef.c); var waterRes = 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 oilRes - waterRes; } private static (List, List) GetOilWaterLine(string modelID) { var cWOL = new List(); var oWOL = new List(); var fitModel = 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) 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()); 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); if (porosity == 0) { initDiff = oilVal - waterVal; } wolProperty.SetValue(waterWol, waterVal + initDiff); wolProperty.SetValue(oilWol, oilVal); } } return (oilWol, waterWol); } } }