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, 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)
|
{
|
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, 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);
|
|
//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<double[]>, List<double[]>) GetOilWaterLine(string modelID, bool original = false)
|
{
|
var cWOL = new List<double[]>();
|
var oWOL = new List<double[]>();
|
|
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<PointF> oilPoints = [];
|
List<PointF> 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);
|
}
|
}
|
}
|