437 lines
16 KiB
Java
437 lines
16 KiB
Java
package com.henrypump.poc;
|
|
|
|
import de.vandermeer.asciitable.v2.RenderedTable;
|
|
import de.vandermeer.asciitable.v2.V2_AsciiTable;
|
|
import de.vandermeer.asciitable.v2.render.V2_AsciiTableRenderer;
|
|
import de.vandermeer.asciitable.v2.render.WidthAbsoluteEven;
|
|
import de.vandermeer.asciitable.v2.themes.V2_E_TableThemes;
|
|
import static java.lang.Math.abs;
|
|
import static java.lang.Math.pow;
|
|
import static java.lang.Math.sqrt;
|
|
|
|
/**
|
|
* Created by patrickjmcd on 1/31/17.
|
|
*/
|
|
public class Card {
|
|
// Card Points
|
|
private int maxPoints = 1500;
|
|
private double[] surfacePosition = new double[maxPoints];
|
|
private double[] downholePosition = new double[maxPoints];
|
|
private double[] surfaceLoad = new double[maxPoints];
|
|
private double[] downholeLoad = new double[maxPoints];
|
|
private int numPointsUsed;
|
|
|
|
//Card
|
|
private long strokeNumber;
|
|
private LPPair surfacePositionMax;
|
|
private LPPair surfacePositionMin;
|
|
private LPPair surfaceLoadMax;
|
|
private LPPair surfaceLoadMin;
|
|
private LPPair downholePositionMax;
|
|
private LPPair downholePositionMin;
|
|
private LPPair downholeLoadMax;
|
|
private LPPair downholeLoadMin;
|
|
|
|
private LPPair topCorner;
|
|
private LPPair bottomCorner;
|
|
|
|
private double surfaceStrokeLength;
|
|
private double downholeNetStrokeLength;
|
|
private double downholeGrossStrokeLength;
|
|
private double downholeAdjustedGrossStrokeLength;
|
|
private double downholeLoadSpan;
|
|
private double fluidLoad;
|
|
private double pumpIntakePressure;
|
|
private double fluidLevel;
|
|
private double fillageEstimated;
|
|
private double fillageCalculated;
|
|
private double tubingMovement;
|
|
private double strokeSpeed;
|
|
|
|
private double structuralLoading;
|
|
|
|
private double polishedRodHorsepower;
|
|
private double pumpHorsepower;
|
|
private double fluidBBLMoved;
|
|
private double fluidBBLMovedAdjusted;
|
|
private double waterBBLMoved;
|
|
private double oilBBLMoved;
|
|
private double gasMCFMoved;
|
|
|
|
private long strokeStartTime;
|
|
|
|
Card(long strokeNumber){
|
|
this.strokeNumber = strokeNumber;
|
|
strokeStartTime = System.currentTimeMillis();
|
|
}
|
|
|
|
public void setSurfacePosition(int i, double position){
|
|
this.surfacePosition[i] = position;
|
|
};
|
|
|
|
public void setDownholePosition(int i, double position){
|
|
this.downholePosition[i] = position;
|
|
};
|
|
|
|
public void setSurfaceLoad(int i, double load){
|
|
this.surfaceLoad[i] = load;
|
|
};
|
|
|
|
public void setDownholeLoad(int i, double load){
|
|
this.downholeLoad[i] = load;
|
|
};
|
|
|
|
public double[] getSurfacePosition() {
|
|
return this.surfacePosition;
|
|
}
|
|
|
|
public double[] getDownholePosition() {
|
|
return this.downholePosition;
|
|
}
|
|
|
|
public double[] getSurfaceLoad() {
|
|
return this.surfaceLoad;
|
|
}
|
|
|
|
public double[] getDownholeLoad() {
|
|
return this.downholeLoad;
|
|
}
|
|
|
|
public LPPair getSurfacePositionMax() {
|
|
return this.surfacePositionMax;
|
|
}
|
|
|
|
public long getStrokeNumber() {
|
|
return strokeNumber;
|
|
}
|
|
|
|
public double getSurfaceStrokeLength() {
|
|
return surfaceStrokeLength;
|
|
}
|
|
|
|
public double getDownholeNetStrokeLength() {
|
|
return downholeNetStrokeLength;
|
|
}
|
|
|
|
public double getDownholeGrossStrokeLength() {
|
|
return downholeGrossStrokeLength;
|
|
}
|
|
|
|
public double getDownholeAdjustedGrossStrokeLength() {
|
|
return downholeAdjustedGrossStrokeLength;
|
|
}
|
|
|
|
public double getDownholeLoadSpan() {
|
|
return downholeLoadSpan;
|
|
}
|
|
|
|
public double getFluidLoad() {
|
|
return fluidLoad;
|
|
}
|
|
|
|
public double getFillageEstimated() {
|
|
return fillageEstimated;
|
|
}
|
|
|
|
public double getFillageCalculated() {
|
|
return fillageCalculated;
|
|
}
|
|
|
|
public double getTubingMovement() {
|
|
return tubingMovement;
|
|
}
|
|
|
|
public double getStructuralLoading() {
|
|
return structuralLoading;
|
|
}
|
|
|
|
public double getPumpIntakePressure() {
|
|
return pumpIntakePressure;
|
|
}
|
|
|
|
public double getFluidLevel() {
|
|
return fluidLevel;
|
|
}
|
|
|
|
public double getStrokeSpeed() {
|
|
return strokeSpeed;
|
|
}
|
|
|
|
public double getPolishedRodHorsepower() {
|
|
return polishedRodHorsepower;
|
|
}
|
|
|
|
public double getPumpHorsepower() {
|
|
return pumpHorsepower;
|
|
}
|
|
|
|
public LPPair getSurfaceLoadMax() {
|
|
return surfaceLoadMax;
|
|
}
|
|
|
|
public LPPair getSurfaceLoadMin() {
|
|
return surfaceLoadMin;
|
|
}
|
|
|
|
public LPPair getDownholeLoadMax() {
|
|
return downholeLoadMax;
|
|
}
|
|
|
|
public LPPair getDownholeLoadMin() {
|
|
return downholeLoadMin;
|
|
}
|
|
|
|
public double getFluidBBLMoved() {
|
|
return fluidBBLMoved;
|
|
}
|
|
|
|
|
|
public double getFluidBBLMovedAdjusted() {
|
|
return fluidBBLMovedAdjusted;
|
|
}
|
|
|
|
public double getWaterBBLMoved() {
|
|
return waterBBLMoved;
|
|
}
|
|
|
|
public double getOilBBLMoved() {
|
|
return oilBBLMoved;
|
|
}
|
|
|
|
public double getGasMCFMoved() {
|
|
return gasMCFMoved;
|
|
}
|
|
|
|
public int getNumPointsUsed() {
|
|
return numPointsUsed;
|
|
}
|
|
|
|
public void setNumPointsUsed(int numPointsUsed) {
|
|
this.numPointsUsed = numPointsUsed;
|
|
}
|
|
|
|
private void calculateSPM(){
|
|
long now = System.currentTimeMillis();
|
|
long strokeMillis = now - strokeStartTime;
|
|
strokeSpeed = 60000.0 / (double)(now - strokeStartTime);
|
|
}
|
|
|
|
private static double lineResolve(double x1, double x2, double y1, double y2, double xTest)
|
|
{
|
|
double line_m = (y2 - y1) / (x2 - x1);
|
|
double line_b = y1 - line_m * x1;
|
|
double yTest = line_m * xTest + line_b;
|
|
return yTest;
|
|
}
|
|
|
|
private static LPPair positionMax(double[] positionArr, double[] loadArr, int arrSize) {
|
|
double maxPos = positionArr[0];
|
|
double loadAtMaxP = Double.MIN_VALUE;
|
|
|
|
for(int i = 0; i < arrSize; i++) {
|
|
maxPos = Math.max(maxPos, positionArr[i]);
|
|
if (maxPos == positionArr[i]) loadAtMaxP = loadArr[i];
|
|
}
|
|
return new LPPair(maxPos, loadAtMaxP);
|
|
}
|
|
|
|
private static LPPair positionMin(double[] positionArr, double[] loadArr, int arrSize) {
|
|
double minPos = positionArr[0];
|
|
double loadAtMinP = Double.MAX_VALUE;
|
|
|
|
for(int i = 0; i < arrSize; i++) {
|
|
minPos = Math.min(minPos, positionArr[i]);
|
|
if (minPos == positionArr[i]) loadAtMinP = loadArr[i];
|
|
}
|
|
return new LPPair(minPos, loadAtMinP);
|
|
}
|
|
|
|
private static LPPair loadMax(double[] positionArr, double[] loadArr, int arrSize) {
|
|
double maxLoad = loadArr[0];
|
|
double posAtMaxL = Double.MIN_VALUE;
|
|
|
|
for(int i = 0; i < arrSize; i++) {
|
|
maxLoad = Math.max(maxLoad, loadArr[i]);
|
|
if (maxLoad == positionArr[i]) posAtMaxL = positionArr[i];
|
|
}
|
|
return new LPPair(posAtMaxL, maxLoad);
|
|
}
|
|
|
|
private static LPPair loadMin(double[] positionArr, double[] loadArr, int arrSize) {
|
|
double minLoad = loadArr[0];
|
|
double posAtMinL = Double.MAX_VALUE;
|
|
|
|
for(int i = 0; i < arrSize; i++) {
|
|
minLoad = Math.min(minLoad, loadArr[i]);
|
|
if (minLoad == positionArr[i]) posAtMinL = positionArr[i];
|
|
}
|
|
return new LPPair(posAtMinL, minLoad);
|
|
}
|
|
|
|
private double distanceToLine(double pos, double load)
|
|
{
|
|
double x1 = downholePositionMin.getPosition();
|
|
double x2 = downholePositionMax.getPosition();
|
|
double y1 = downholeLoadMin.getLoad();
|
|
double y2 = downholeLoadMax.getLoad();
|
|
|
|
return abs((y2-y1)*pos - (x2-x1)*load + x2*y1 - y2*x1) / sqrt(pow(y2-y1, 2) + pow(x2-x1,2));
|
|
};
|
|
|
|
void calcStrokeData(int numSlices, double fluidGradient, double rodDepth, double anchorDepth, double tubingCSA,
|
|
double pumpArea, double frictionEstimate, double structuralRating,
|
|
double kFactor, double waterBBLRatio, double oilBBLRatio, double gasMCFRatio)
|
|
{
|
|
calculateSPM();
|
|
surfacePositionMax = positionMax(surfacePosition, surfaceLoad, numPointsUsed);
|
|
surfaceLoadMax = loadMax(surfacePosition, surfaceLoad, numPointsUsed);
|
|
surfacePositionMin = positionMin(surfacePosition, surfaceLoad, numPointsUsed);
|
|
surfaceLoadMin = loadMin(surfacePosition, surfaceLoad, numPointsUsed);
|
|
|
|
downholePositionMax = positionMax(downholePosition, downholeLoad, numPointsUsed);
|
|
downholeLoadMax = loadMax(downholePosition, downholeLoad, numPointsUsed);
|
|
downholePositionMin = positionMin(downholePosition, downholeLoad, numPointsUsed);
|
|
downholeLoadMin = loadMin(downholePosition, downholeLoad, numPointsUsed);
|
|
|
|
surfaceStrokeLength = surfacePositionMax.getPosition() - surfacePositionMin.getPosition();
|
|
downholeGrossStrokeLength = downholePositionMax.getPosition() - downholePositionMin.getPosition();
|
|
downholeLoadSpan = downholeLoadMax.getLoad() - downholeLoadMin.getLoad();
|
|
|
|
double dxSurf = (surfacePositionMax.getPosition() - surfacePositionMin.getPosition()) / (float) numSlices;
|
|
double dxDown = (downholePositionMax.getPosition() - downholePositionMin.getPosition()) / (float) numSlices;
|
|
|
|
pumpHorsepower = 0.0;
|
|
polishedRodHorsepower = 0.0;
|
|
double dhDistanceTop = 0.0;
|
|
double dhDistanceBottom = 0.0;
|
|
|
|
for (int i = 1; i < numSlices+1; i++)
|
|
{
|
|
double suPosTarget = surfacePositionMin.getPosition() + ((double) i * dxSurf);
|
|
double dhPosTarget = downholePositionMin.getPosition() + ((double) i * dxDown);
|
|
double suLoadAtTargetTop = 0.0;
|
|
double suLoadAtTargetBottom = 0.0;
|
|
double dhLoadAtTargetTop = 0.0;
|
|
double dhLoadAtTargetBottom = 0.0;
|
|
|
|
for(int j = 0; j < numPointsUsed - 1; j++)
|
|
{
|
|
if (downholePosition[j] <= dhPosTarget && downholePosition[j+1] > dhPosTarget){
|
|
dhLoadAtTargetTop = lineResolve(downholePosition[j], downholePosition[j+1], downholeLoad[j], downholeLoad[j+1], dhPosTarget);
|
|
}
|
|
|
|
if (downholePosition[j] > dhPosTarget && downholePosition[j+1] >= dhPosTarget){
|
|
dhLoadAtTargetBottom = lineResolve(downholePosition[j], downholePosition[j+1], downholeLoad[j], downholeLoad[j+1], dhPosTarget);
|
|
}
|
|
|
|
if (surfacePosition[j] <= suPosTarget && surfacePosition[j+1] > suPosTarget){
|
|
suLoadAtTargetTop = lineResolve(surfacePosition[j], surfacePosition[j+1], surfaceLoad[j], surfaceLoad[j+1], suPosTarget);
|
|
}
|
|
|
|
if (surfacePosition[j] > suPosTarget && surfacePosition[j+1] >= suPosTarget){
|
|
suLoadAtTargetBottom = lineResolve(surfacePosition[j], surfacePosition[j+1], surfaceLoad[j], surfaceLoad[j+1], suPosTarget);
|
|
}
|
|
}
|
|
|
|
polishedRodHorsepower += (dxSurf / 12.0) * (suLoadAtTargetTop - suLoadAtTargetBottom) * (strokeSpeed / 33000.0);
|
|
pumpHorsepower += (dxDown / 12.0) * (dhLoadAtTargetTop - dhLoadAtTargetBottom) * (strokeSpeed / 33000.0);
|
|
|
|
double tDistance = distanceToLine(dhPosTarget, dhLoadAtTargetTop);
|
|
double bDistance = distanceToLine(dhPosTarget, dhLoadAtTargetBottom);
|
|
|
|
if (tDistance > dhDistanceTop)
|
|
{
|
|
dhDistanceTop = tDistance;
|
|
topCorner = new LPPair(dhPosTarget, dhLoadAtTargetTop);
|
|
}
|
|
|
|
if (bDistance > dhDistanceBottom)
|
|
{
|
|
dhDistanceBottom = bDistance;
|
|
bottomCorner = new LPPair(dhPosTarget, dhLoadAtTargetBottom);
|
|
}
|
|
}
|
|
|
|
downholeAdjustedGrossStrokeLength = downholePositionMax.getPosition() - topCorner.getPosition();
|
|
downholeNetStrokeLength = bottomCorner.getPosition() - downholePositionMin.getPosition();
|
|
fillageCalculated = (downholeNetStrokeLength / downholeAdjustedGrossStrokeLength) * 100.0;
|
|
fillageEstimated =(downholeNetStrokeLength / downholeGrossStrokeLength) * 100.0;
|
|
fluidBBLMoved = downholeNetStrokeLength * pumpArea * 0.00010307;
|
|
fluidBBLMovedAdjusted = fluidBBLMoved * kFactor;
|
|
oilBBLMoved = fluidBBLMoved * oilBBLRatio;
|
|
waterBBLMoved = fluidBBLMoved * waterBBLRatio;
|
|
gasMCFMoved = fluidBBLMoved * gasMCFRatio;
|
|
|
|
|
|
if (fillageEstimated > 100)
|
|
fillageEstimated = 100.0;
|
|
|
|
if (fillageCalculated > 100)
|
|
fillageCalculated = 100.0;
|
|
|
|
fluidLoad = downholeLoadSpan - frictionEstimate;
|
|
pumpIntakePressure = fluidGradient * rodDepth - (fluidLoad / pumpArea);
|
|
//printf("PIP = %f * %f - (%f / %f) = %f\n", fluidGradient, rodDepth, fluidLoad, pumpArea, pumpIntakePressure);
|
|
fluidLevel = pumpIntakePressure / fluidGradient;
|
|
tubingMovement = 12 * (rodDepth - anchorDepth) * fluidLoad / (30500000 * tubingCSA);
|
|
structuralLoading = (surfaceLoadMax.getLoad() / (structuralRating * 100)) * 100;
|
|
};
|
|
|
|
public void printCard(String printType, boolean printDataTableToo){
|
|
if(printType.toLowerCase().equals("table")) {
|
|
V2_AsciiTable pointsTable = new V2_AsciiTable();
|
|
pointsTable.addRule();
|
|
pointsTable.addRow("Surface Position", "Surface Load", "Downhole Position", "Downhole Load");
|
|
pointsTable.addRule();
|
|
for (int i = 0; i < numPointsUsed; i++) {
|
|
pointsTable.addRow(surfacePosition[i], surfaceLoad[i], downholePosition[i], downholeLoad[i]);
|
|
}
|
|
pointsTable.addRule();
|
|
V2_AsciiTableRenderer rend = new V2_AsciiTableRenderer();
|
|
rend.setTheme(V2_E_TableThemes.UTF_LIGHT.get());
|
|
rend.setWidth(new WidthAbsoluteEven(100));
|
|
RenderedTable rt = rend.render(pointsTable);
|
|
System.out.println(rt);
|
|
System.out.println();
|
|
} else if (printType.toLowerCase().equals("csv")){
|
|
System.out.println("surf_pos,surf_load,down_pos,down_load");
|
|
for (int i = 0; i < numPointsUsed; i++) {
|
|
System.out.printf("%f,%f,%f,%f\n", surfacePosition[i], surfaceLoad[i], downholePosition[i], downholeLoad[i]);
|
|
}
|
|
System.out.println();
|
|
}
|
|
|
|
if(printDataTableToo){
|
|
V2_AsciiTable dataTable = new V2_AsciiTable();
|
|
dataTable.addRule();
|
|
dataTable.addRow("Card " + strokeNumber, "Value");
|
|
dataTable.addStrongRule();
|
|
dataTable.addRow("Fill % (Est.)", fillageEstimated);
|
|
dataTable.addRow("Fill % (Calc.)", fillageCalculated);
|
|
dataTable.addRule();
|
|
dataTable.addRow("Surf. Stroke Length", surfaceStrokeLength);
|
|
dataTable.addRow("Down. Gross Stroke", downholeGrossStrokeLength);
|
|
dataTable.addRow("Down. Net Stroke", downholeNetStrokeLength);
|
|
dataTable.addRow("Tubing Movement", tubingMovement);
|
|
dataTable.addRule();
|
|
dataTable.addRow("Polished Rod HP", polishedRodHorsepower);
|
|
dataTable.addRow("Pump HP", pumpHorsepower);
|
|
dataTable.addRule();
|
|
dataTable.addRow("Stroke Speed", strokeSpeed);
|
|
dataTable.addRule();
|
|
dataTable.addRow("Fluid Load", fluidLoad);
|
|
dataTable.addRow("Pump Intake Pressure", pumpIntakePressure);
|
|
dataTable.addRow("Fluid Level", fluidLevel);
|
|
dataTable.addRule();
|
|
dataTable.addRow("Structural Loading", structuralLoading);
|
|
dataTable.addRule();
|
|
V2_AsciiTableRenderer rend = new V2_AsciiTableRenderer();
|
|
rend.setTheme(V2_E_TableThemes.UTF_LIGHT.get());
|
|
rend.setWidth(new WidthAbsoluteEven(50));
|
|
RenderedTable rt = rend.render(dataTable);
|
|
System.out.println(rt);
|
|
System.out.println();
|
|
}
|
|
}
|
|
}
|