Files
POC-Matlab/Card.m
2017-09-07 17:38:29 -05:00

307 lines
13 KiB
Matlab

classdef Card < handle
properties
numPointsUsed = 0;
strokeNumber;
strokeStartTime;
surfacePosition=zeros(1, 1500, 'double');
surfaceLoad=zeros(1, 1500, 'double');
downholePosition=zeros(1, 1500, 'double');
downholeLoad=zeros(1, 1500, 'double');
numRepSlices=200;
repDownholePosition=zeros(1, 199, 'double');
repDownholeLoadTop=zeros(1, 199, 'double');
repDownholeLoadBottom=zeros(1, 199, 'double');
repSurfacePosition=zeros(1, 199, 'double');
repSurfaceLoadTop=zeros(1, 199, 'double');
repSurfaceLoadBottom=zeros(1, 199, 'double');
surfacePositionMax=LPPair(0,0);
surfacePositionMin=LPPair(0,0);
surfaceLoadMax=LPPair(0,0);
surfaceLoadMin=LPPair(0,0);
downholePositionMax=LPPair(0,0);
downholePositionMin=LPPair(0,0);
downholeLoadMax=LPPair(0,0);
downholeLoadMin=LPPair(0,0);
topCorner=LPPair(0,0);
bottomCorner=LPPair(0,0);
surfaceStrokeLength;
downholeNetStrokeLength;
downholeGrossStrokeLength;
downholeAdjustedGrossStrokeLength;
downholeLoadSpan;
fluidLoad;
pumpIntakePressure;
fluidLevel;
fillageEstimated;
fillageCalculated;
tubingMovement;
strokeSpeed;
structuralLoading;
polishedRodHorsepower;
pumpHorsepower;
fluidBblMoved;
fluidBblMovedAdjusted;
waterBblMoved;
oilBblMoved;
gasMcfMoved;
end
methods
function obj=Card(strokeNumber)
% Initialization Function
obj.strokeNumber = strokeNumber;
% obj.strokeStartTime = now;
obj.strokeStartTime = 0;
obj.topCorner = LPPair(0, 0);
obj.bottomCorner = LPPair(0, 0);
end
function push(obj, s_pos, s_load, d_pos, d_load)
obj.numPointsUsed = obj.numPointsUsed + 1;
obj.surfacePosition(obj.numPointsUsed) = s_pos;
obj.surfaceLoad(obj.numPointsUsed) = s_load;
obj.downholePosition(obj.numPointsUsed) = d_pos;
obj.downholeLoad(obj.numPointsUsed) = d_load;
end
function calcStrokeData(obj, fluidGradient, rodDepth, ...
anchorDepth, tubingCSA, pumpArea, frictionEstimate, ...
structuralRating, kFactor, waterBBLRatio, oilBBLRatio, ...
gasMCFRatio)
obj.calculateSPM();
numSlices = obj.numRepSlices;
obj.surfacePositionMax = obj.positionMax(obj.surfacePosition, obj.surfaceLoad, obj.numPointsUsed);
obj.surfaceLoadMax = obj.loadMax(obj.surfacePosition, obj.surfaceLoad, obj.numPointsUsed);
obj.surfacePositionMin = obj.positionMin(obj.surfacePosition, obj.surfaceLoad, obj.numPointsUsed);
obj.surfaceLoadMin = obj.loadMin(obj.surfacePosition, obj.surfaceLoad, obj.numPointsUsed);
obj.downholePositionMax = obj.positionMax(obj.downholePosition, obj.downholeLoad, obj.numPointsUsed);
obj.downholeLoadMax = obj.loadMax(obj.downholePosition, obj.downholeLoad, obj.numPointsUsed);
obj.downholePositionMin = obj.positionMin(obj.downholePosition, obj.downholeLoad, obj.numPointsUsed);
obj.downholeLoadMin = obj.loadMin(obj.downholePosition, obj.downholeLoad, obj.numPointsUsed);
obj.surfaceStrokeLength = obj.surfacePositionMax.position - obj.surfacePositionMin.position;
obj.downholeGrossStrokeLength = obj.downholePositionMax.position - obj.downholePositionMin.position;
obj.downholeLoadSpan = obj.downholeLoadMax.load - obj.downholeLoadMin.load;
dxSurf = (obj.surfacePositionMax.position - obj.surfacePositionMin.position) / double(numSlices);
dxDown = (obj.downholePositionMax.position - obj.downholePositionMin.position) / double(numSlices);
obj.pumpHorsepower = 0.0;
obj.polishedRodHorsepower = 0.0;
dhDistanceTop = 0.0;
dhDistanceBottom = 0.0;
for i = 1:numSlices-1
suPosTarget = obj.surfacePositionMin.position + (double(i) * dxSurf);
dhPosTarget = obj.downholePositionMin.position + (double(i) * dxDown);
suLoadAtTargetTop = 0.0;
suLoadAtTargetBottom = 0.0;
dhLoadAtTargetTop = 0.0;
dhLoadAtTargetBottom = 0.0;
for j = 1:obj.numPointsUsed-1
if (obj.downholePosition(j) <= dhPosTarget && obj.downholePosition(j+1) > dhPosTarget)
dhLoadAtTargetTop = obj.lineResolve(obj.downholePosition(j), obj.downholePosition(j+1), obj.downholeLoad(j), obj.downholeLoad(j+1), dhPosTarget);
end
if (obj.downholePosition(j) >= dhPosTarget && obj.downholePosition(j+1) < dhPosTarget)
dhLoadAtTargetBottom = obj.lineResolve(obj.downholePosition(j), obj.downholePosition(j+1), obj.downholeLoad(j), obj.downholeLoad(j+1), dhPosTarget);
end
if (obj.surfacePosition(j) <= suPosTarget && obj.surfacePosition(j+1) > suPosTarget)
suLoadAtTargetTop = obj.lineResolve(obj.surfacePosition(j), obj.surfacePosition(j+1), obj.surfaceLoad(j), obj.surfaceLoad(j+1), suPosTarget);
end
if (obj.surfacePosition(j) >= suPosTarget && obj.surfacePosition(j+1) < suPosTarget)
suLoadAtTargetBottom = obj.lineResolve(obj.surfacePosition(j), obj.surfacePosition(j+1), obj.surfaceLoad(j), obj.surfaceLoad(j+1), suPosTarget);
end
end
obj.repDownholePosition(i) = dhPosTarget;
if (dhLoadAtTargetTop == 0.0) && (i > 1)
obj.repDownholeLoadTop(i) = obj.repDownholeLoadTop(i-1);
elseif (dhLoadAtTargetTop == 0.0) && (i == 1)
obj.repDownholeLoadTop(i) = obj.downholePositionMin.load;
else
obj.repDownholeLoadTop(i) = dhLoadAtTargetTop;
end
if dhLoadAtTargetBottom == 0.0 && (i > 1)
obj.repDownholeLoadBottom(i) = obj.repDownholeLoadBottom(i-1);
elseif dhLoadAtTargetBottom == 0.0 && (i == 1)
obj.repDownholeLoadBottom(i) = obj.downholePositionMin.load;
else
obj.repDownholeLoadBottom(i) = dhLoadAtTargetBottom;
end
obj.repSurfacePosition(i) = suPosTarget;
if suLoadAtTargetTop == 0.0 && (i > 1)
obj.repSurfaceLoadTop(i) = obj.repSurfaceLoadTop(i-1);
elseif suLoadAtTargetTop == 0.0 && (i == 1)
obj.repSurfaceLoadTop(i) = obj.surfacePositionMin.load;
else
obj.repSurfaceLoadTop(i) = suLoadAtTargetTop;
end
if suLoadAtTargetBottom == 0.0 && (i > 1)
obj.repSurfaceLoadBottom(i) = obj.repSurfaceLoadBottom(i-1);
elseif suLoadAtTargetBottom == 0.0 && (i == 1)
obj.repSurfaceLoadBottom(i) = obj.surfacePositionMin.load;
else
obj.repSurfaceLoadBottom(i) = suLoadAtTargetBottom;
end
obj.polishedRodHorsepower = obj.polishedRodHorsepower + (dxSurf / 12.0) * (suLoadAtTargetTop - suLoadAtTargetBottom) * (obj.strokeSpeed / 33000.0);
obj.pumpHorsepower = obj.pumpHorsepower + (dxDown / 12.0) * (dhLoadAtTargetTop - dhLoadAtTargetBottom) * (obj.strokeSpeed / 33000.0);
tDistance = obj.distanceToLine(dhPosTarget, dhLoadAtTargetTop);
bDistance = obj.distanceToLine(dhPosTarget, dhLoadAtTargetBottom);
if (tDistance > dhDistanceTop) && (dhLoadAtTargetTop ~= 0.0)
dhDistanceTop = tDistance;
obj.topCorner = LPPair(dhPosTarget, dhLoadAtTargetTop);
end
if (bDistance > dhDistanceBottom) && (dhLoadAtTargetBottom ~= 0.0)
dhDistanceBottom = bDistance;
obj.bottomCorner = LPPair(dhPosTarget, dhLoadAtTargetBottom);
end
end
obj.downholeAdjustedGrossStrokeLength = obj.downholePositionMax.position - obj.topCorner.position;
obj.downholeNetStrokeLength = obj.bottomCorner.position - obj.downholePositionMin.position;
obj.fillageCalculated = (obj.downholeNetStrokeLength / obj.downholeAdjustedGrossStrokeLength) * 100.0;
obj.fillageEstimated =(obj.downholeNetStrokeLength / obj.downholeGrossStrokeLength) * 100.0;
obj.fluidBblMoved = obj.downholeNetStrokeLength * pumpArea * 0.00010307;
obj.fluidBblMovedAdjusted = obj.fluidBblMoved * kFactor;
obj.oilBblMoved = obj.fluidBblMoved * oilBBLRatio;
obj.waterBblMoved = obj.fluidBblMoved * waterBBLRatio;
obj.gasMcfMoved = obj.fluidBblMoved * gasMCFRatio;
if (obj.fillageEstimated > 100)
obj.fillageEstimated = 100.0;
end
if (obj.fillageEstimated < 0.0)
obj.fillageEstimated = 0.0;
end
if (obj.fillageCalculated > 100)
obj.fillageCalculated = 100.0;
end
if (obj.fillageCalculated < 0.0)
obj.fillageCalculated = 0.0;
end
obj.fluidLoad = obj.downholeLoadSpan - frictionEstimate;
obj.pumpIntakePressure = fluidGradient * rodDepth - (obj.fluidLoad / pumpArea);
obj.fluidLevel = obj.pumpIntakePressure / fluidGradient;
obj.tubingMovement = 12 * (rodDepth - anchorDepth) * obj.fluidLoad / (30500000 * tubingCSA);
obj.structuralLoading = (obj.surfaceLoadMax.load / (structuralRating * 100)) * 100;
end
function calculateSPM(obj)
obj.strokeSpeed = 60000.0 / (5000 - obj.strokeStartTime);
end
function dist = distanceToLine(obj, pos, load)
% Finds the distance between a point and a line between the
% Max Position at Max Load and Min Position at Min Load
x1 = obj.downholePositionMin.position;
x2 = obj.downholePositionMax.position;
y1 = obj.downholeLoadMin.load;
y2 = obj.downholeLoadMax.load;
dist = abs((y2-y1)* pos - (x2-x1)* load + x2*y1 - y2*x1) / sqrt(power(y2-y1, 2) + power(x2-x1,2));
end
function plot(obj)
ax1 = subplot(2,1,1);
plot(obj.surfacePosition(1:obj.numPointsUsed), obj.surfaceLoad(1:obj.numPointsUsed))
title('Surface Card')
ax2 = subplot(2,1,2);
plot(obj.downholePosition(1:obj.numPointsUsed),obj.downholeLoad(1:obj.numPointsUsed), 'r')
title('Downhole Card')
linkaxes([ax1, ax2], 'x')
end
end
methods(Static)
function yTest = lineResolve(x1, x2, y1, y2, xTest)
% Uses the standard line equation to find the y value given x
line_m = (y2 - y1) / (x2 - x1);
line_b = y1 - line_m * x1;
yTest = line_m * xTest + line_b;
end
function foundPoint = positionMax(positionArr, loadArr, arrSize)
maxPos = positionArr(1);
loadAtMaxP = -inf;
for i = 1:arrSize
maxPos = max(maxPos, positionArr(i));
if (maxPos == positionArr(i))
loadAtMaxP = loadArr(i);
end
end
foundPoint = LPPair(maxPos, loadAtMaxP);
end
function foundPoint = positionMin(positionArr, loadArr, arrSize)
minPosition = positionArr(1);
loadAtMinP = inf;
for i = 1:arrSize
minPosition = min(minPosition, positionArr(i));
if (minPosition == positionArr(i))
loadAtMinP = loadArr(i);
end
end
foundPoint = LPPair(minPosition, loadAtMinP);
end
function foundPoint = loadMax(positionArr, loadArr, arrSize)
maxLoad = loadArr(1);
posAtMaxL = -inf;
for i = 1:arrSize
maxLoad = max(maxLoad, loadArr(i));
if (maxLoad == positionArr(i))
posAtMaxL = positionArr(i);
end
end
foundPoint = LPPair(posAtMaxL, maxLoad);
end
function foundPoint = loadMin(positionArr, loadArr, arrSize)
minLoad = loadArr(1);
posAtMinL = inf;
for i = 1:arrSize
minLoad = min(minLoad, loadArr(i));
if (minLoad == positionArr(i))
posAtMinL = positionArr(i);
end
end
foundPoint = LPPair(posAtMinL, minLoad);
end
end
end