lx
2025-08-07 9827a8864ba0df0a4e148b4a7ac3225df7b80728
upload
已修改6个文件
384 ■■■■ 文件已修改
ErrorAnalysis.Service/COMergeCalcService.cs 181 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ErrorAnalysis.Service/ErrorRatioCalc.cs 116 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ErrorAnalysis.Service/PDEVCalcService.cs 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ErrorAnalysis.UI/FrmMain.Designer.cs 35 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ErrorAnalysis.UI/FrmMain.cs 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ErrorAnalysis.UI/Utility/UnitConvert.cs 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ErrorAnalysis.Service/COMergeCalcService.cs
@@ -1,4 +1,5 @@
using ErrorAnalysis.Repository;
using Microsoft.VisualBasic;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -22,9 +23,9 @@
        const int _oWinStartIndex = (int)(4.88 / _gg + _offset); // org
        const int _oWinEndIndex = (int)(6.36 / _gg + _offset); // width = 6.36-4.88=1.48
        const double _coef = 1e8 * 2.54 * 2.54 * 4 * 6 * 2 * 11 * 77 * 0.2 / 0.6;
        //const double _coef = 1e8 * 2.54 * 2.54 * 4 * 6 * 2 * 11 * 77 * 0.2 / 0.6;
        private static (double, double) GetFarInterplolateResult(string modelId, double porosity, double sw, double speed, double depth)
        private static (double, double) GetFarInterplolateResult(string modelId, double porosity, double sw, double speed, double depth, double yieldCounting)
        {
            var cWinLength = _cWinEndIndex - _cWinStartIndex + 1;
            var oWinLength = _oWinEndIndex - _oWinStartIndex + 1;
@@ -32,20 +33,25 @@
            var waterLine = RepositoryInstance.Instance.COFarResultRepository?.GetCOFarResult(modelId, (int)porosity, 100);
            if (oilLine == null || waterLine == null)
                throw new InvalidDataException("COFarResult Line is null");
            var oilLineValArr = oilLine.InelasticSpec.Split(',').Select(v => Convert.ToDouble(v)).ToArray();
            var waterLineValArr = waterLine.InelasticSpec.Split(',').Select(v => Convert.ToDouble(v)).ToArray();
            var oilLineValArr = oilLine.CInelasticSpec.Split(',').Select(v => Convert.ToDouble(v)).ToArray();
            var waterLineValArr = waterLine.CInelasticSpec.Split(',').Select(v => Convert.ToDouble(v)).ToArray();
            var oilLineC = oilLineValArr.Skip(_cWinStartIndex).Take(cWinLength).Sum() * _coef / speed * depth * 0.07;
            var oilLineO = oilLineValArr.Skip(_oWinStartIndex).Take(oWinLength).Sum() * _coef / speed * depth * 0.07;
            var oilLineCR = oilLineValArr.Skip(_cWinStartIndex).Take(cWinLength).Sum() / oilLineValArr.Sum();
            var oilLineOR = oilLineValArr.Skip(_oWinStartIndex).Take(oWinLength).Sum() / oilLineValArr.Sum();
            var waterLineC = waterLineValArr.Skip(_cWinStartIndex).Take(cWinLength).Sum() * _coef / speed * depth * 0.07;
            var waterLineO = waterLineValArr.Skip(_oWinStartIndex).Take(oWinLength).Sum() * _coef / speed * depth * 0.07;
            var oilLineC = 36d / 160 * oilLineCR * yieldCounting / speed * depth * 0.0762;
            var oilLineO = 36d / 160 * oilLineOR * yieldCounting / speed * depth * 0.0762;
            var waterLineCR = waterLineValArr.Skip(_cWinStartIndex).Take(cWinLength).Sum() / waterLineValArr.Sum();
            var waterLineOR = waterLineValArr.Skip(_oWinStartIndex).Take(oWinLength).Sum() / waterLineValArr.Sum();
            var waterLineC = 36d / 160 * waterLineCR * yieldCounting / speed * depth * 0.0762;
            var waterLineO = 36d / 160 * waterLineOR * yieldCounting / speed * depth * 0.0762;
            double cRes = 0, oRes = 0;
            if (sw == 0)
            {
                cRes = waterLineC;
                oRes = waterLineO;
                cRes = oilLineC;
                oRes = oilLineO;
            }
            else if (sw == 100)
            {
@@ -60,7 +66,7 @@
            return (cRes, oRes);
        }
        private static (double, double) GetNearInterplolateResult(string modelId, double porosity, double sw, double speed, double depth)
        private static (double, double) GetNearInterplolateResult(string modelId, double porosity, double sw, double speed, double depth, double yieldCounting)
        {
            var cWinLength = _cWinEndIndex - _cWinStartIndex + 1;
            var oWinLength = _oWinEndIndex - _oWinStartIndex + 1;
@@ -68,14 +74,18 @@
            var waterLine = RepositoryInstance.Instance.CONearResultRepository?.GetCONearResult(modelId, (int)porosity, 100);
            if (oilLine == null || waterLine == null)
                throw new InvalidDataException("COFarResult Line is null");
            var oilLineValArr = oilLine.InelasticSpec.Split(',').Select(v => Convert.ToDouble(v)).ToArray();
            var waterLineValArr = waterLine.InelasticSpec.Split(',').Select(v => Convert.ToDouble(v)).ToArray();
            var oilLineValArr = oilLine.CInelasticSpec.Split(',').Select(v => Convert.ToDouble(v)).ToArray();
            var waterLineValArr = waterLine.CInelasticSpec.Split(',').Select(v => Convert.ToDouble(v)).ToArray();
            var oilLineC = oilLineValArr.Skip(_cWinStartIndex).Take(cWinLength).Sum() * _coef / speed * depth * 0.07;
            var oilLineO = oilLineValArr.Skip(_oWinStartIndex).Take(oWinLength).Sum() * _coef / speed * depth * 0.07;
            var oilLineCR = oilLineValArr.Skip(_cWinStartIndex).Take(cWinLength).Sum() / oilLineValArr.Sum();
            var oilLineOR = oilLineValArr.Skip(_oWinStartIndex).Take(oWinLength).Sum() / oilLineValArr.Sum();
            var oilLineC = (36d / 160) * oilLineCR * yieldCounting / speed * depth * 0.0762;
            var oilLineO = (36d / 160) * oilLineOR * yieldCounting / speed * depth * 0.0762;
            var waterLineC = waterLineValArr.Skip(_cWinStartIndex).Take(cWinLength).Sum() * _coef / speed * depth * 0.07;
            var waterLineO = waterLineValArr.Skip(_oWinStartIndex).Take(oWinLength).Sum() * _coef / speed * depth * 0.07;
            var waterLineCR = waterLineValArr.Skip(_cWinStartIndex).Take(cWinLength).Sum() / waterLineValArr.Sum();
            var waterLineOR = waterLineValArr.Skip(_oWinStartIndex).Take(oWinLength).Sum() / waterLineValArr.Sum();
            var waterLineC = (36d / 160) * waterLineCR * yieldCounting / speed * depth * 0.0762;
            var waterLineO = (36d / 160) * waterLineOR * yieldCounting / speed * depth * 0.0762;
            double cRes = 0, oRes = 0;
            if (sw == 0)
@@ -108,7 +118,7 @@
        /// <param name="depth">深度</param>
        /// <returns>碳和氧值</returns>
        /// <exception cref="InvalidDataException">孔隙度超过范围</exception>
        public static (double, double) GetFarMergeCOResult(string modelId, double porosity, double sw, double speed, double depth)
        public static (double, double) GetFarMergeCOResult(string modelId, double porosity, double sw, double speed, double depth, double yieldCounting)
        {
            if (porosity > 40)
                throw new InvalidDataException("Porosity value out of range!");
@@ -116,15 +126,15 @@
            (double, double) result = (0, 0);
            if (porosity % 5 == 0)
            {
                result = GetFarInterplolateResult(modelId, porosity, sw, speed, depth);
                result = GetFarInterplolateResult(modelId, porosity, sw, speed, depth, yieldCounting);
            }
            else
            {
                var ceilingPorosity = Math.Ceiling(porosity / 5) * 5;
                var ceilingResult = GetFarInterplolateResult(modelId, ceilingPorosity, sw, speed, depth);
                var ceilingResult = GetFarInterplolateResult(modelId, ceilingPorosity, sw, speed, depth, yieldCounting);
                var floorPorosity = Math.Floor(porosity / 5) * 5;
                var floorResult = GetFarInterplolateResult(modelId, floorPorosity, sw, speed, depth);
                var floorResult = GetFarInterplolateResult(modelId, floorPorosity, sw, speed, depth, yieldCounting);
                result.Item1 = Utility.Interpolate(porosity, floorPorosity, floorResult.Item1, ceilingPorosity, ceilingResult.Item1);
                result.Item2 = Utility.Interpolate(porosity, floorPorosity, floorResult.Item2, ceilingPorosity, ceilingResult.Item2);
@@ -144,7 +154,7 @@
        /// <param name="depth">深度</param>
        /// <returns>碳或氧值</returns>
        /// <exception cref="InvalidDataException">孔隙度超过范围</exception>
        public static (double, double) GetNearMergeCOResult(string modelId, double porosity, double sw, double speed, double depth)
        public static (double, double) GetNearMergeCOResult(string modelId, double porosity, double sw, double speed, double depth, double yieldCounting)
        {
            if (porosity > 40)
                throw new InvalidDataException("Porosity value out of range!");
@@ -152,20 +162,141 @@
            (double, double) result = (0, 0);
            if (porosity % 5 == 0)
            {
                result = GetNearInterplolateResult(modelId, porosity, sw, speed, depth);
                result = GetNearInterplolateResult(modelId, porosity, sw, speed, depth, yieldCounting);
            }
            else
            {
                var ceilingPorosity = Math.Ceiling(porosity / 5) * 5;
                var ceilingResult = GetNearInterplolateResult(modelId, ceilingPorosity, sw, speed, depth);
                var ceilingResult = GetNearInterplolateResult(modelId, ceilingPorosity, sw, speed, depth, yieldCounting);
                var floorPorosity = Math.Floor(porosity / 5) * 5;
                var floorResult = GetNearInterplolateResult(modelId, floorPorosity, sw, speed, depth);
                var floorResult = GetNearInterplolateResult(modelId, floorPorosity, sw, speed, depth, yieldCounting);
                result.Item1 = Utility.Interpolate(porosity, floorPorosity, floorResult.Item1, ceilingPorosity, ceilingResult.Item1);
                result.Item2 = Utility.Interpolate(porosity, floorPorosity, floorResult.Item2, ceilingPorosity, ceilingResult.Item2);
            }
            return result;
        }
        public static (double, double) GetFarCROR(string modelId, double porosity, double sw)
        {
            var cWinLength = _cWinEndIndex - _cWinStartIndex + 1;
            var oWinLength = _oWinEndIndex - _oWinStartIndex + 1;
            var oilLine = RepositoryInstance.Instance.COFarResultRepository?.GetCOFarResult(modelId, (int)porosity, 0);
            var waterLine = RepositoryInstance.Instance.COFarResultRepository?.GetCOFarResult(modelId, (int)porosity, 100);
            if (oilLine == null || waterLine == null)
                throw new InvalidDataException("COFarResult Line is null");
            var oilLineValArr = oilLine.CInelasticSpec.Split(',').Select(v => Convert.ToDouble(v)).ToArray();
            var waterLineValArr = waterLine.CInelasticSpec.Split(',').Select(v => Convert.ToDouble(v)).ToArray();
            var oilLineCR = oilLineValArr.Skip(_cWinStartIndex).Take(cWinLength).Sum() / oilLineValArr.Sum();
            var oilLineOR = oilLineValArr.Skip(_oWinStartIndex).Take(oWinLength).Sum() / oilLineValArr.Sum();
            var waterLineCR = waterLineValArr.Skip(_cWinStartIndex).Take(cWinLength).Sum() / waterLineValArr.Sum();
            var waterLineOR = waterLineValArr.Skip(_oWinStartIndex).Take(oWinLength).Sum() / waterLineValArr.Sum();
            double cRes = 0, oRes = 0;
            if (sw == 0)
            {
                cRes = oilLineCR;
                oRes = oilLineOR;
            }
            else if (sw == 100)
            {
                cRes = waterLineCR;
                oRes = waterLineOR;
            }
            else if (sw > 0 && sw < 100)
            {
                cRes = Utility.Interpolate(sw, 100, waterLineCR, 0, oilLineCR);
                oRes = Utility.Interpolate(sw, 0, oilLineOR, 100, waterLineOR);
            }
            return (cRes, oRes);
        }
        public static (double, double) GetNearCROR(string modelId, double porosity, double sw)
        {
            var cWinLength = _cWinEndIndex - _cWinStartIndex + 1;
            var oWinLength = _oWinEndIndex - _oWinStartIndex + 1;
            var oilLine = RepositoryInstance.Instance.CONearResultRepository?.GetCONearResult(modelId, (int)porosity, 0);
            var waterLine = RepositoryInstance.Instance.CONearResultRepository?.GetCONearResult(modelId, (int)porosity, 100);
            if (oilLine == null || waterLine == null)
                throw new InvalidDataException("COFarResult Line is null");
            var oilLineValArr = oilLine.CInelasticSpec.Split(',').Select(v => Convert.ToDouble(v)).ToArray();
            var waterLineValArr = waterLine.CInelasticSpec.Split(',').Select(v => Convert.ToDouble(v)).ToArray();
            var oilLineCR = oilLineValArr.Skip(_cWinStartIndex).Take(cWinLength).Sum() / oilLineValArr.Sum();
            var oilLineOR = oilLineValArr.Skip(_oWinStartIndex).Take(oWinLength).Sum() / oilLineValArr.Sum();
            var waterLineCR = waterLineValArr.Skip(_cWinStartIndex).Take(cWinLength).Sum() / waterLineValArr.Sum();
            var waterLineOR = waterLineValArr.Skip(_oWinStartIndex).Take(oWinLength).Sum() / waterLineValArr.Sum();
            double crRes = 0, orRes = 0;
            if (sw == 0)
            {
                crRes = oilLineCR;
                orRes = oilLineOR;
            }
            else if (sw == 100)
            {
                crRes = waterLineCR;
                orRes = waterLineOR;
            }
            else if (sw > 0 && sw < 100)
            {
                crRes = Utility.Interpolate(sw, 100, waterLineCR, 0, oilLineCR);
                orRes = Utility.Interpolate(sw, 0, oilLineOR, 100, waterLineOR);
            }
            return (crRes, orRes);
        }
        public static (double, double) GetFarCOORResult(string modelId, double porosity, double sw)
        {
            if (porosity > 40)
                throw new InvalidDataException("Porosity value out of range!");
            (double, double) result = (0, 0);
            if (porosity % 5 == 0)
            {
                result = GetFarCROR(modelId, porosity, sw);
            }
            else
            {
                var ceilingPorosity = Math.Ceiling(porosity / 5) * 5;
                var ceilingResult = GetFarCROR(modelId, ceilingPorosity, sw);
                var floorPorosity = Math.Floor(porosity / 5) * 5;
                var floorResult = GetFarCROR(modelId, floorPorosity, sw);
                result.Item1 = Utility.Interpolate(porosity, floorPorosity, floorResult.Item1, ceilingPorosity, ceilingResult.Item1);
                result.Item2 = Utility.Interpolate(porosity, floorPorosity, floorResult.Item2, ceilingPorosity, ceilingResult.Item2);
            }
            return result;
        }
        public static (double, double) GetNearCOORResult(string modelId, double porosity, double sw)
        {
            if (porosity > 40)
                throw new InvalidDataException("Porosity value out of range!");
            (double, double) result = (0, 0);
            if (porosity % 5 == 0)
            {
                result = GetNearCROR(modelId, porosity, sw);
            }
            else
            {
                var ceilingPorosity = Math.Ceiling(porosity / 5) * 5;
                var ceilingResult = GetNearCROR(modelId, ceilingPorosity, sw);
                var floorPorosity = Math.Floor(porosity / 5) * 5;
                var floorResult = GetNearCROR(modelId, floorPorosity, sw);
                result.Item1 = Utility.Interpolate(porosity, floorPorosity, floorResult.Item1, ceilingPorosity, ceilingResult.Item1);
                result.Item2 = Utility.Interpolate(porosity, floorPorosity, floorResult.Item2, ceilingPorosity, ceilingResult.Item2);
            }
            return result;
        }
    }
}
ErrorAnalysis.Service/ErrorRatioCalc.cs
@@ -1,4 +1,5 @@
using ErrorAnalysis.Repository;
using ErrorAnalysis.Service;
using ErrorAnalysis.Service.Model;
using System;
using System.Collections.Generic;
@@ -10,7 +11,7 @@
{
    public class ErrorRatioCalc
    {
        public static ErrorRatioResult GetErrorRatioResult(string modelID, double porosity, double sw, double depth, bool lockSpeed, double speed, double targetErrorRatio, out double testSpeed, int pass = 0)
        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
            {
@@ -24,7 +25,8 @@
            {
                List<double[]> cWOL;
                List<double[]> oWOL;
                var firstErrorPassM = GetFirstErrorRatio(modelID, porosity, sw, speed, depth, out cWOL, out oWOL);
                var firstErrorPassM = GetFirstErrorRatio(modelID, porosity, sw, speed, depth, yieldCounting, nearCofe, farCofe);
                (cWOL, oWOL) = GetOilWaterLine(modelID);
                result.CWOL = cWOL;
                result.OWOL = oWOL;
                result.ErrorRatios.Add(firstErrorPassM);
@@ -42,15 +44,32 @@
                var firstTargetErrorRatio = targetErrorRatio * Math.Sqrt(pass);
                List<double[]> cWOL;
                List<double[]> oWOL;
                var firstErrorPass = new ErrorRatio();
                speed = 2;
                do
                {
                    firstErrorPass = GetFirstErrorRatio(modelID, porosity, sw, speed, depth, out cWOL, out oWOL);
                (cWOL, oWOL) = GetOilWaterLine(modelID);
                    result.CWOL = cWOL;
                    result.OWOL = oWOL;
                    speed -= 0.01;
                } while (firstErrorPass.ErrorRatioValue != 0 && firstErrorPass.ErrorRatioValue > firstTargetErrorRatio);
                var nearCROR = COMergeCalcService.GetNearCOORResult(modelID, porosity, sw);
                var farCROR = COMergeCalcService.GetFarCOORResult(modelID, porosity, sw);
                var mDelta = GetMDelta(modelID, porosity);
                speed = Math.Pow(firstTargetErrorRatio /
                    Math.Sqrt(1 / (0.0762 * depth * (36d / 160))) *
                    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) * (Math.Pow(farCROR.Item1 / farCROR.Item2, 2)) * (1 / farCROR.Item1 + 1 / farCROR.Item2))
                    , 2);
                var firstErrorPass = new ErrorRatio { Pass = 1, ErrorRatioValue = firstTargetErrorRatio };
                var firstErrorPassM = GetFirstErrorRatio(modelID, porosity, sw, speed, depth, yieldCounting, nearCofe, farCofe);
                //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++)
@@ -64,56 +83,31 @@
        }
        private static ErrorRatio GetFirstErrorRatio(string modelID, double porosity, double sw, double speed, double depth, out List<double[]> cWOL, out List<double[]> oWOL)
        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!");
            cWOL = new List<double[]>();
            oWOL = new List<double[]>();
            var cWolRes = RepositoryInstance.Instance.COWOLRepository?.GetWOL(modelID, 0);
            var oWolRes = RepositoryInstance.Instance.COWOLRepository?.GetWOL(modelID, 100);
            var mergePDEV = PDEVCalcService.GetMergePDEV(modelID, porosity, sw, speed, depth);
            var wolResType = cWolRes?.GetType();
            try
            {
                //if (sw > 0 && sw < 100)
                //{
                //    foreach (var wolProperty in wolResType.GetProperties())
                //    {
                //        if (wolProperty.Name.Contains("WLPu"))
                //        {
                //            //if (wolProperty.Name != "WLPu0")
                //            //{
                //            var interC = Utility.Interpolate(sw, 100, 0, 0, (double)wolProperty.GetValue(cWolRes));
                //            var interO = Utility.Interpolate(sw, 0, 0, 100, (double)wolProperty.GetValue(oWolRes));
                //            wolProperty.SetValue(cWolRes, interC);
                //            wolProperty.SetValue(oWolRes, interO);
                //            //}
                //            //else
                //            //{
                //            //    var interC = Utility.Interpolate(sw, 100, 0, 0, (double)wolProperty.GetValue(cWolRes));
                //            //    var interO = Utility.Interpolate(sw, 0, 0, 100, (double)wolProperty.GetValue(oWolRes));
                //            //    var interVal = Utility.Interpolate(sw, 0, interC, 100, interO);
                //            //    wolProperty.SetValue(cWolRes, interVal);
                //            //    wolProperty.SetValue(oWolRes, interVal);
                //            //}
                //        }
                //    }
                //}
                var mergePDEV = PDEVCalcService.GetMergePDEV(modelID, porosity, sw, speed, depth, yieldCounting, nearCofe, farCofe);
                foreach (var wolProperty in wolResType.GetProperties())
                var errorRatio = mergePDEV / GetMDelta(modelID, porosity);
                return new ErrorRatio { Pass = 1, ErrorRatioValue = errorRatio };
            }
            catch
                {
                    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 new ErrorRatio { Pass = 0, ErrorRatioValue = 0 };
                    }
                }
        private static double GetMDelta(string modelID, double porosity)
        {
            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;
@@ -142,17 +136,27 @@
                    cRes = Utility.Interpolate(porosity, floorPorosity, floorC, ceilingPorosity, ceilingC);
                    oRes = Utility.Interpolate(porosity, floorPorosity, floorO, ceilingPorosity, ceilingO);
                }
                var errorRatio = mergePDEV /( cRes > oRes ? (cRes - oRes) : (oRes - cRes));
                return new ErrorRatio { Pass = 1, ErrorRatioValue = errorRatio };
            return cRes - oRes;
            }
            catch
        private static (List<double[]>, List<double[]>) GetOilWaterLine(string modelID)
            {
                cWOL = null;
                oWOL = null;
                return new ErrorRatio { Pass = 0, ErrorRatioValue = 0 };
            var cWOL = new List<double[]>();
            var oWOL = new List<double[]>();
            var cWolRes = RepositoryInstance.Instance.COWOLRepository?.GetWOL(modelID, 0);
            var oWolRes = RepositoryInstance.Instance.COWOLRepository?.GetWOL(modelID, 100);
            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);
        }
    }
}
ErrorAnalysis.Service/PDEVCalcService.cs
@@ -8,15 +8,15 @@
{
    public class PDEVCalcService
    {
        public static double GetMergePDEV(string modelId, double porosity, double sw, double speed, double depth)
        public static double GetMergePDEV(string modelId, double porosity, double sw, double speed, double depth, double yieldCounting, double nearCofe, double farCofe)
        {
            var farResult = COMergeCalcService.GetFarMergeCOResult(modelId, porosity, sw, speed, depth);
            var farResult = COMergeCalcService.GetFarMergeCOResult(modelId, porosity, sw, speed, depth, yieldCounting);
            var farPDEV = CalcPDEV(farResult.Item1, farResult.Item2);
            var nearResult = COMergeCalcService.GetNearMergeCOResult(modelId, porosity, sw, speed, depth);
            var nearResult = COMergeCalcService.GetNearMergeCOResult(modelId, porosity, sw, speed, depth, yieldCounting);
            var nearPDEV = CalcPDEV(nearResult.Item1, nearResult.Item2);
            return nearPDEV * 0.65 + farPDEV * 0.35;
            return Math.Sqrt(Math.Pow(nearPDEV * nearCofe, 2) + Math.Pow(farPDEV * farCofe, 2));
        }
        private static double CalcPDEV(double c, double o) => Math.Sqrt(Math.Pow(c / o, 2) * (1 / c + 1 / o));
ErrorAnalysis.UI/FrmMain.Designer.cs
@@ -120,9 +120,11 @@
            cmbLithology = new ComboBox();
            label16 = new Label();
            tpPlan = new TabPage();
            label7 = new Label();
            cmbTargetLoggingIntervalUnit = new ComboBox();
            label5 = new Label();
            chkAlphaProcessing = new CheckBox();
            nudYieldCounting = new NumericUpDown();
            nudAlphaProcessingWin = new NumericUpDown();
            nudDepth = new NumericUpDown();
            nudTargetLoggingInterval = new NumericUpDown();
@@ -157,6 +159,7 @@
            ((System.ComponentModel.ISupportInitialize)nudSw).BeginInit();
            ((System.ComponentModel.ISupportInitialize)nudPorosity).BeginInit();
            tpPlan.SuspendLayout();
            ((System.ComponentModel.ISupportInitialize)nudYieldCounting).BeginInit();
            ((System.ComponentModel.ISupportInitialize)nudAlphaProcessingWin).BeginInit();
            ((System.ComponentModel.ISupportInitialize)nudDepth).BeginInit();
            ((System.ComponentModel.ISupportInitialize)nudTargetLoggingInterval).BeginInit();
@@ -293,7 +296,7 @@
            // 
            // nudSpeed
            // 
            nudSpeed.DecimalPlaces = 1;
            nudSpeed.DecimalPlaces = 2;
            nudSpeed.Increment = new decimal(new int[] { 1, 0, 0, 65536 });
            nudSpeed.Location = new Point(54, 16);
            nudSpeed.Maximum = new decimal(new int[] { 9999999, 0, 0, 0 });
@@ -1095,10 +1098,12 @@
            // 
            // tpPlan
            // 
            tpPlan.Controls.Add(label7);
            tpPlan.Controls.Add(cmbTargetLoggingIntervalUnit);
            tpPlan.Controls.Add(label5);
            tpPlan.Controls.Add(chkAlphaProcessing);
            tpPlan.Controls.Add(label22);
            tpPlan.Controls.Add(nudYieldCounting);
            tpPlan.Controls.Add(nudAlphaProcessingWin);
            tpPlan.Controls.Add(pnlLockPass);
            tpPlan.Controls.Add(nudDepth);
@@ -1117,6 +1122,15 @@
            tpPlan.TabIndex = 3;
            tpPlan.Text = "Plan";
            tpPlan.UseVisualStyleBackColor = true;
            //
            // label7
            //
            label7.AutoSize = true;
            label7.Location = new Point(457, 102);
            label7.Name = "label7";
            label7.Size = new Size(90, 17);
            label7.TabIndex = 17;
            label7.Text = "Yield counting";
            // 
            // cmbTargetLoggingIntervalUnit
            // 
@@ -1140,16 +1154,26 @@
            // chkAlphaProcessing
            // 
            chkAlphaProcessing.AutoSize = true;
            chkAlphaProcessing.Location = new Point(421, 69);
            chkAlphaProcessing.Location = new Point(419, 43);
            chkAlphaProcessing.Name = "chkAlphaProcessing";
            chkAlphaProcessing.Size = new Size(128, 21);
            chkAlphaProcessing.TabIndex = 15;
            chkAlphaProcessing.Text = "Alpha processing";
            chkAlphaProcessing.UseVisualStyleBackColor = true;
            // 
            // nudYieldCounting
            //
            nudYieldCounting.DecimalPlaces = 2;
            nudYieldCounting.Increment = new decimal(new int[] { 100, 0, 0, 0 });
            nudYieldCounting.Location = new Point(565, 100);
            nudYieldCounting.Maximum = new decimal(new int[] { 99999999, 0, 0, 0 });
            nudYieldCounting.Name = "nudYieldCounting";
            nudYieldCounting.Size = new Size(82, 23);
            nudYieldCounting.TabIndex = 13;
            //
            // nudAlphaProcessingWin
            // 
            nudAlphaProcessingWin.Location = new Point(555, 98);
            nudAlphaProcessingWin.Location = new Point(565, 70);
            nudAlphaProcessingWin.Maximum = new decimal(new int[] { 99999999, 0, 0, 0 });
            nudAlphaProcessingWin.Name = "nudAlphaProcessingWin";
            nudAlphaProcessingWin.Size = new Size(47, 23);
@@ -1175,7 +1199,7 @@
            // label54
            // 
            label54.AutoSize = true;
            label54.Location = new Point(391, 100);
            label54.Location = new Point(389, 72);
            label54.Name = "label54";
            label54.Size = new Size(158, 17);
            label54.TabIndex = 12;
@@ -1267,6 +1291,7 @@
            ((System.ComponentModel.ISupportInitialize)nudPorosity).EndInit();
            tpPlan.ResumeLayout(false);
            tpPlan.PerformLayout();
            ((System.ComponentModel.ISupportInitialize)nudYieldCounting).EndInit();
            ((System.ComponentModel.ISupportInitialize)nudAlphaProcessingWin).EndInit();
            ((System.ComponentModel.ISupportInitialize)nudDepth).EndInit();
            ((System.ComponentModel.ISupportInitialize)nudTargetLoggingInterval).EndInit();
@@ -1378,5 +1403,7 @@
        private TableLayoutPanel tableLayoutPanel1;
        private ProgressBar pbLoadDB;
        private RichTextBox txtAnalysisResult;
        private Label label7;
        private NumericUpDown nudYieldCounting;
    }
}
ErrorAnalysis.UI/FrmMain.cs
@@ -138,7 +138,13 @@
            if (!decimal.TryParse(nudOilDensity.Value.ToString(), out decimal oilDensity) || nudOilDensity.Value <= 0)
            {
                MessageBox.Show("Please enter a oil density");
                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;
            }
@@ -163,12 +169,12 @@
                    MessageBox.Show("Please enter a reasonable speed");
                    return;
                }
                var calcSpeed = cmbSpeedUnit.Text == "ft/hr" ? UnitConvert.FtHr2MMin(speed) : UnitConvert.MHR2MMin(speed);
                var calcSpeed = cmbSpeedUnit.Text == "ft/hr" ? UnitConvert.FtHr2MS(speed) : UnitConvert.MHR2MS(speed);
                var result = ErrorRatioCalc.GetErrorRatioResult(_model.ModelID, porosity, sw, depth, true, calcSpeed, targetErrorRatio / 100, out _);
                var result = ErrorRatioCalc.GetErrorRatioResult(_model.ModelID, porosity, sw, depth, true, calcSpeed, yieldCounting, targetErrorRatio / 100, out _);
                Plot(result);
                double totalTime = Math.Round((targetLoggingInterval / calcSpeed / 60), 2);
                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"));
@@ -179,7 +185,7 @@
                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.MMin2FtHr(calcSpeed), 2).ToString(), errorRate.ToString());
                _reportModel = CreateReportModel(totalTime.ToString(), result.ErrorRatios.Count.ToString(), Math.Round(UnitConvert.MS2FtHr(calcSpeed), 2).ToString(), errorRate.ToString());
            }
            else
            {
@@ -189,12 +195,12 @@
                    return;
                }
                double speed;
                var result = ErrorRatioCalc.GetErrorRatioResult(_model.ModelID, porosity, sw, depth, false, 0, targetErrorRatio / 100, out speed, pass);
                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), 2);
                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.MMin2FtHr(speed), 2);
                var speedFr = Math.Round(UnitConvert.MS2FtHr(speed), 2);
                txtAnalysisResult.AppendText("A total of ");
                AppendText(txtAnalysisResult, result.ErrorRatios.Count.ToString(), ColorTranslator.FromHtml("#8B0000"));
@@ -307,9 +313,9 @@
            if (curModels.Count == 0)
                return;
            var casingFulids = curModels.Select(x => x.CasingFluid == "0" ? "water" : x.CasingFluid == "100" ? "oil" : x.CasingFluid == "200" ? "gas" : "none").Distinct().ToArray();
            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] == "999")
            if (casingFulids.Length == 1 && casingFulids[0] == "none")
            {
                cmbCasingHoldUp.Enabled = false;
                nudCasingHoldUp.Enabled = false;
@@ -322,7 +328,7 @@
                cmbCasingHoldUp.Items.AddRange(casingFulids);
            }
            var screenFulids = curModels.Select(x => x.ScreenFluid == "0" ? "water" : x.ScreenFluid == "100" ? "oil" : x.ScreenFluid == "200" ? "gas" : "none").Distinct().ToArray();
            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")
            {
@@ -336,7 +342,7 @@
                cmbScreenHoldUp.Items.AddRange(screenFulids);
            }
            var tubeFluids = curModels.Select(x => x.TubeFluid == "0" ? "water" : x.TubeFluid == "100" ? "oil" : x.TubeFluid == "200" ? "gas" : "none").Distinct().ToArray();
            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;
@@ -487,6 +493,7 @@
            }
        }
        #endregion
        private List<COModelTable> GetFilterResult()
        {
            var type = typeof(COModelTable);
ErrorAnalysis.UI/Utility/UnitConvert.cs
@@ -12,10 +12,17 @@
        public static double M2Ft(double val) => val * 3.281;
        public static double FtHr2MMin(double val) => val / 3.281 / 60;
        public static double FtHr2MS(double val) => val / 3.281 / 60/60;
        public static double MHR2MMin(double val) => val /60;
        public static double MHR2MS(double val) => val /60/60;
        public static double MMin2FtHr(double val) => val * 3.281 * 60;
        public static double MS2FtHr(double val) => val * 3.281 * 60*60;
        /// <summary>
        /// 计算YieldCounting备用
        /// </summary>
        /// <param name="yieldCounting">产额</param>
        /// <returns>产额</returns>
        public static double CalcYieldCounting(double yieldCounting) => yieldCounting;
    }
}