lx
2025-09-05 0b108f56b2d0c35d01ee361dc593119ac52a14e1
ErrorAnalysis.Service/ErrorRatioCalc.cs
@@ -16,26 +16,41 @@
        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)
        public static ErrorRatioResult GetErrorRatioResult(string modelID, double porosity, double sw, double depth, bool lockSpeed, double speed, double yieldCounting, double targetErrorRatio, out double testSpeed, out ProcessingDataModel processingData, int pass = 0, double nearCofe = 0.65, double farCofe = 0.35)
        {
            processingData = new ProcessingDataModel { Depth = depth, NearPDEVCoef = nearCofe, FarPDEVCoef = farCofe, NearTO = yieldCounting };
            var result = new ErrorRatioResult
            {
                CWOL = new List<double[]>(),
                OWOL = new List<double[]>(),
                ErrorRatios = new List<ErrorRatio>()
            };
            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);
            var farCROR = COMergeCalcService.GetFarCOORResult(modelID, porosity, sw);
            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)
            {
                List<double[]> cWOL;
                List<double[]> oWOL;
                (cWOL, oWOL) = GetOilWaterLine(modelID);
                result.CWOL = cWOL;
                result.OWOL = oWOL;
                var firstErrorPassM = GetFirstErrorRatio(modelID, porosity, sw, speed, depth, yieldCounting, nearCofe, farCofe);
                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)));
@@ -44,25 +59,17 @@
                        result.ErrorRatios.Add(new ErrorRatio { Pass = i, ErrorRatioValue = firstErrorPassM.ErrorRatioValue / Math.Sqrt(i) });
                    }
                }
                processingData.Speed = speed;
            }
            else
            {
                var firstTargetErrorRatio = targetErrorRatio * Math.Sqrt(pass);
                List<double[]> cWOL;
                List<double[]> 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);
                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 };
@@ -88,36 +95,38 @@
        }
        private static ErrorRatio GetFirstErrorRatio(string modelID, double porosity, double sw, double speed, double depth, double yieldCounting, double nearCofe, double farCofe)
        private static ErrorRatio GetFirstErrorRatio(string modelID, double porosity, double sw, double speed, double depth, double yieldCounting, double nearCofe, double farCofe, out double oilPoint, out double waterPoint)
        {
            if (porosity > 40)
                throw new InvalidDataException("Porosity value out of range!");
            try
            {
                var mDelta = GetMDelta(porosity);
                var mDelta = GetMDelta(porosity, out oilPoint, out waterPoint);
                //var mergePDEVOld = PDEVCalcService.GetMergePDEV(modelID, porosity, sw, speed, depth, yieldCounting, nearCofe, farCofe);
                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 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 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 = mergePDEV / mDelta;
                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)
        private static double GetMDelta(double porosity, out double oilPoint, out double waterPoint)
        {
            var oilRes = Utility.GetParabolaValue(porosity, _parabolaCoef.a, _parabolaCoef.b, _parabolaCoef.c);
            var waterRes = Utility.GetLineValue(porosity, _lineCoef.slope, _lineCoef.intercept);
            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);
@@ -150,15 +159,15 @@
            //    cRes = Utility.Interpolate(porosity, floorPorosity, floorC, ceilingPorosity, ceilingC);
            //    oRes = Utility.Interpolate(porosity, floorPorosity, floorO, ceilingPorosity, ceilingO);
            //}
            return oilRes - waterRes;
            return oilPoint - waterPoint;
        }
        private static (List<double[]>, List<double[]>) GetOilWaterLine(string modelID)
        private static (List<double[]>, List<double[]>) GetOilWaterLine(string modelID, bool original = false)
        {
            var cWOL = new List<double[]>();
            var oWOL = new List<double[]>();
            var fitModel = GetFitModel(modelID);
            var fitModel = original ? GetModel(modelID) : GetFitModel(modelID);
            var cWolRes = fitModel.Item1;
            var oWolRes = fitModel.Item2;
@@ -173,6 +182,13 @@
                }
            }
            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)
@@ -198,6 +214,7 @@
            _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;
@@ -208,6 +225,7 @@
                    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;