AnalogIn, DigitalIn, DigitalOut, Simulation, and Card classes all working correctly so far

This commit is contained in:
Patrick McDonagh
2017-02-01 14:24:35 -06:00
commit a7073aae9c
46 changed files with 2240 additions and 0 deletions

View File

@@ -0,0 +1,595 @@
package com.henrypump.poc;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import static java.lang.Math.exp;
import static java.lang.Math.pow;
import static java.lang.Math.sqrt;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
/**
* Created by patrickjmcd on 1/31/17.
*/
public class Well {
private double[][] topPosArray = new double[10][100];
private double[][] topLoadArray = new double[10][100];
// CONSTANTS
private static double YM_STEEL = 30.5;
private static double YM_FIBERGLASS = 7.2;
private static final int BAD_STATUS = 0;
private static final int GOOD_STATUS = 0;
// USER INPUTS
private double dt;
private double tubingHeadPressure;
private double fluidGradient;
private double sbfriction;
private int numTapers;
private double tubingAnchorDepth;
private double pumpDiameter;
private double tubingID, tubingOD;
private double structuralRating;
private double[] c = new double[11];
private double[] rodLength = new double[11];
private double[] rodDiameter = new double[11];
private double[] rodYM = new double[11];
private double[] rodWeightPerFoot = new double[11];
// CALCULATED TAPER PARAMETERS
private int nT1; // should always be equal to number of tapers + 1
private double frictionEstimate;
private double theoreticalMaxFluidLoad;
private double[] a = new double[11];
private double[] area = new double[11];
private double[] pressure = new double[11];
private double[] buoyantForce = new double[11];
private double buoyantForceTotal;
private double[] stretch = new double[11];
private double[] weightData = new double[11];
private double weightDataTotal;
private double[] annularForceData = new double[11];
private double annularForceDataTotal;
private double[] force = new double[11];
private double[] alpha = new double[11];
private double[] xOverA = new double[11];
private double[] factor = new double[11];
private int[] lagIndex = new int[11];
private int[] lengthRequired = new int[11];
private int[] centerPoint = new int[11];
private double[] rodDepth = new double[11];
private double rodDepthTotal;
private double[] rodWeightAir = new double[11];
private double rodWeightAirTotal;
private double[] rodWeightFluid = new double[11];
private double rodWeightFluidTotal;
private double pumpArea;
private double tubingCrossSectionalArea;
// Intermediate Variables
private double loadBefore = 0.0;
private double loadAfter = 0.0;
private double loadBefore3 = 0.0;
private double loadAfter3 = 0.0;
private int[] count = new int[11];
private double sPositionPrevious;
public double getDt() {
return dt;
}
public void setDt(double dt) {
this.dt = dt;
}
public double getTubingHeadPressure() {
return tubingHeadPressure;
}
public void setTubingHeadPressure(double tubingHeadPressure) {
this.tubingHeadPressure = tubingHeadPressure;
}
public double getFluidGradient() {
return fluidGradient;
}
public void setFluidGradient(double fluidGradient) {
this.fluidGradient = fluidGradient;
}
public double getSbfriction() {
return sbfriction;
}
public void setSbfriction(double sbfriction) {
this.sbfriction = sbfriction;
}
public int getNumTapers() {
return numTapers;
}
public void setNumTapers(int numTapers) {
this.numTapers = numTapers;
}
public double getTubingAnchorDepth() {
return tubingAnchorDepth;
}
public void setTubingAnchorDepth(double tubingAnchorDepth) {
this.tubingAnchorDepth = tubingAnchorDepth;
}
public double getPumpDiameter() {
return pumpDiameter;
}
public void setPumpDiameter(double pumpDiameter) {
this.pumpDiameter = pumpDiameter;
this.pumpArea = pow(pumpDiameter, 2) * Math.PI;
}
public double getTubingID() {
return tubingID;
}
public void setTubingID(double tubingID) {
this.tubingID = tubingID;
this.tubingCrossSectionalArea = (Math.PI / 4) * (pow(this.tubingOD, 2) - pow(this.tubingID,2));
}
public double getTubingOD() {
return tubingOD;
}
public void setTubingOD(double tubingOD) {
this.tubingOD = tubingOD;
this.tubingCrossSectionalArea = (Math.PI / 4) * (pow(this.tubingOD, 2) - pow(tubingID,2));
}
public void setDampingFactor(int i, double c) {
this.c[i] = c;
}
public double getDampingFactor(int i){ return c[i]; }
public void setRodLength(int i, double rodLength) {
this.rodLength[i] = rodLength;
}
public double getRodLength(int i){ return rodLength[i]; }
public void setRodDiameter(int i, double rodDiameter) {
this.rodDiameter[i] = rodDiameter;
}
public double getRodDiameter(int i){ return rodDiameter[i]; }
public void setRodYM(int i, String material) {
if (material.toLowerCase().equals("steel")) rodYM[i] = YM_STEEL;
else if (material.toLowerCase().equals("fiberglass")) rodYM[i] = YM_FIBERGLASS;
}
public double getRodYM(int i){ return rodYM[i]; }
public String getRodMaterial(int i){
if(rodYM[i] == YM_STEEL)
return "steel";
if(rodYM[i] == YM_FIBERGLASS)
return "fiberglass";
return "unknown";
}
public double getStructuralRating() {
return structuralRating;
}
public void setStructuralRating(double structuralRating) {
this.structuralRating = structuralRating;
}
public static double lookupRodWeightPerFoot(double i_ym, double i_diam) {
double wtPerFt;
if (i_ym == YM_STEEL) {
if (i_diam <= 2 && i_diam > 1.75) {
wtPerFt = 10.7;
} else if (i_diam <= 1.75 && i_diam > 1.65) {
wtPerFt = 8.2;
} else if (i_diam <= 1.65 && i_diam > 1.5) {
wtPerFt = 7;
} else if (i_diam <= 1.5 && i_diam > 1.375) {
wtPerFt = 6;
} else if (i_diam <= 1.375 && i_diam > 1.125) {
wtPerFt = 5;
} else if (i_diam <= 1.125 && i_diam > 1) {
wtPerFt = 3.676;
} else if (i_diam <= 1 && i_diam > 0.875) {
wtPerFt = 2.904;
} else if (i_diam <= 0.875 && i_diam > 0.75) {
wtPerFt = 2.224;
} else if (i_diam <= 0.75 && i_diam > 0.625) {
wtPerFt = 1.634;
} else if (i_diam <= 0.625 && i_diam > 0.5) {
wtPerFt = 1.13;
} else if (i_diam <= 0.5) {
wtPerFt = 0.72;
} else {
wtPerFt = 0;
}
} else if (i_ym == YM_FIBERGLASS) {
if (i_diam <= 1.25 && i_diam > 1.125) {
wtPerFt = 1.2879;
} else if (i_diam <= 1.125 && i_diam > 1) {
wtPerFt = 1.09;
} else if (i_diam <= 1 && i_diam > 0.875) {
wtPerFt = 0.8188;
} else if (i_diam <= 0.875 && i_diam > 0.75) {
wtPerFt = 0.6108;
} else if (i_diam <= 0.75) {
wtPerFt = 0.484;
} else {
wtPerFt = 0;
}
} else {
wtPerFt = 0;
}
return wtPerFt;
};
public void parseJSONFile(String jsonFilename){
JSONParser parser = new JSONParser();
try {
Object obj = parser.parse(new FileReader(jsonFilename));
JSONObject well = (JSONObject) obj;
Object newDeltaT = well.get("deltaT");
if (newDeltaT != null) dt = (Double) newDeltaT;
Object newPumpDiameter = well.get("pumpDiameter");
if (newPumpDiameter != null) setPumpDiameter((Double) newPumpDiameter);
Object newFluidGradient = well.get("fluidGradient");
if (newFluidGradient != null) fluidGradient = (Double) newFluidGradient;
Object newTubingID = well.get("tubingID");
if (newTubingID != null) setTubingID((Double) newTubingID);
Object newTubingOD = well.get("tubingOD");
if (newTubingOD != null) setTubingOD((Double) newTubingOD);
Object newTubingAnchorDepth = well.get("tubingAnchorDepth");
if (newTubingAnchorDepth != null) tubingAnchorDepth = (Double) newTubingAnchorDepth;
Object newStructuralRating = well.get("structuralRating");
if (newStructuralRating != null) structuralRating = (Double) newStructuralRating;
Object newStuffingBoxFriction = well.get("stuffingBoxFriction");
if (newStuffingBoxFriction != null) setSbfriction((Double) newStuffingBoxFriction);
Object newTubingHeadPressure = well.get("tubingOD");
if (newTubingHeadPressure != null) setTubingOD((Double) newTubingHeadPressure);
JSONArray tapers = (JSONArray) well.get("tapers");
numTapers = tapers.size();
for (int i = 0; i < numTapers; i++){
int currentTaperNum = i + 1;
JSONObject taperObj = (JSONObject) tapers.get(i);
Object newLength = taperObj.get("length");
if (newLength != null) setRodLength(currentTaperNum, (Double) newLength);
Object newDiameter = taperObj.get("diameter");
if (newDiameter != null) setRodDiameter(currentTaperNum, (Double) newDiameter);
Object newMaterial = taperObj.get("material");
System.out.println("found material " + (String) newMaterial);
if (newMaterial != null) setRodYM(currentTaperNum, (String) newMaterial);
Object newDampingFactor = taperObj.get("dampingFactor");
if (newDampingFactor != null) setDampingFactor(currentTaperNum, (Double) newDampingFactor);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
}
public void printTapers(){
System.out.println("=== INPUT PARAMETERS ===");
System.out.println("DeltaT: " + getDt());
System.out.println("Fluid Gradient: " + getFluidGradient());
System.out.println("Pump Diameter: " + getPumpDiameter());
System.out.println("Stuffing Box Friction: " + getSbfriction());
System.out.println("Structural Rating: " + getStructuralRating());
System.out.println("Tubing Anchor Depth: " + getTubingAnchorDepth());
System.out.println("Tubing Head Pressure: " + getTubingHeadPressure());
System.out.println("Tubing ID: " + getTubingID());
System.out.println("Tubing OD: " + getTubingOD());
System.out.println("Number of Tapers: " + getNumTapers());
System.out.println("");
for(int i = 1; i <= numTapers; i++){
System.out.printf("=== Taper %d === \n", i);
System.out.println("Rod Length: " + getRodLength(i));
System.out.println("Rod Diameter: " + getRodDiameter(i));
System.out.println("Rod Damping Factor: " + getDampingFactor(i));
System.out.println("Rod Material: " + getRodMaterial(i));
System.out.println("Rod Young's Modulus: " + getRodYM(i));
System.out.println("");
}
};
public void updateTapers(){
nT1 = numTapers + 1;
// start by setting everything to 0
a[0] = 0.0;
area[0] = 0.0;
area[numTapers + 1] = 0.0;
pressure[0] = tubingHeadPressure;
buoyantForce[0] = 0.0;
stretch[0] = 0.0;
weightData[0] = 0.0;
annularForceData[0] = 0.0;
force[0] = 0.0;
alpha[0] = 0.0;
xOverA[0] = 0.0;
factor[0] = 0.0;
lagIndex[0] = 0;
lengthRequired[0] = 0;
centerPoint[0] = 0;
rodDepth[0] = 0.0;
rodWeightAir[0] = 0.0;
rodWeightFluid[0] = 0.0;
buoyantForceTotal = 0.0;
weightDataTotal = 0.0;
annularForceDataTotal = 0.0;
rodDepthTotal = 0.0;
rodWeightAirTotal = 0.0;
rodWeightFluidTotal = 0.0;
for(int i = 1; i < nT1; i++){
rodWeightPerFoot[i] = lookupRodWeightPerFoot(rodYM[i], rodDiameter[i]);
}
for (int area_i = 1; area_i < nT1; area_i++)
{
area[area_i] = (Math.PI / 4) * pow(rodDiameter[area_i], 2);
}
for (int i = 1; i < nT1; i++)
{
a[i] = 1000 * sqrt(32.2 * rodYM[i] * area[i] / rodWeightPerFoot[i]);
rodDepth[i] = rodDepth[i - 1] + rodLength[i];
pressure[i] = pressure[i - 1] + fluidGradient * rodLength[i];
buoyantForce[i] = pressure[i] * (area[i + 1] - area[i]);
rodWeightAir[i] = rodWeightPerFoot[i] * rodLength[i];
rodWeightFluid[i] = rodWeightAir[i] + buoyantForce[i];
}
for (int j = 1; j < nT1; j++)
{
for (int k = j + 1; k < nT1; k++)
{
weightData[j] += rodWeightAir[k]; // how much weight is felt on each taper
}
for (int l = j; l < numTapers; l++)
{
annularForceData[j] += -buoyantForce[l]; //buoyant force exerted on each taper
}
force[j] = (-area[numTapers] * pressure[numTapers]) + weightData[j] - annularForceData[j];
alpha[j] = (force[j] + rodWeightAir[j]) / (rodYM[j] * pow(10, 6) * area[j]);
stretch[j] = (stretch[j - 1] + (alpha[j] * rodLength[j])) - ((rodWeightPerFoot[j] * pow(rodLength[j], 2)) / (2 * rodYM[j] * pow(10, 6) * area[j]));
}
for (int m = 1; m < nT1; m++)
{
xOverA[m] = rodLength[m] / a[m];
lagIndex[m] = (int)(rodLength[m] / (a[m] * dt));
factor[m] = (xOverA[m] - lagIndex[m] * dt) / dt;
centerPoint[m] = lagIndex[m] + 2;
lengthRequired[m] = 2 * (lagIndex[m] + 1) + 1;
}
for (int t = 0; t < nT1; t++)
{
buoyantForceTotal += buoyantForce[t];
rodWeightAirTotal += rodWeightAir[t];
rodWeightFluidTotal += rodWeightFluid[t];
rodDepthTotal += rodLength[t];
annularForceDataTotal += annularForceData[t];
weightDataTotal += weightData[t];
}
theoreticalMaxFluidLoad = fluidGradient* rodDepthTotal* pumpArea;
frictionEstimate = 0.10 * rodDepthTotal;
}
private double position(int p)
//generate the downhole position of the given rod part
{
loadBefore = 0;
loadAfter = 0;
loadBefore3 = 0;
loadAfter3 = 0;
//Temporary Variables
double a1 = a[p];
double cd = c[p];
double fact = factor[p];
double rodLengthp = rodLength[p];
int lagInd = lagIndex[p];
double Y1 = rodYM[p] * pow(10, 6);
double A1 = area[p];
int centerOfArray = centerPoint[p];
int iBefore = centerOfArray - lagInd;
int iAfter = centerOfArray + lagInd;
double pumpPOS = 0;
//Do work
pumpPOS = exp((cd * rodLengthp) / (2 * a1)) * (topPosArray[p][iAfter] + fact * (topPosArray[p][ iAfter + 1] - topPosArray[p][iAfter]));
pumpPOS += exp(-(cd * rodLengthp) / (2 * a1)) * (topPosArray[p][iBefore] + fact * (topPosArray[p][iBefore - 1] - topPosArray[p][iBefore]));
pumpPOS = pumpPOS / 2;
double insideIntegral = 0;
int q = 1;
while (q < 2 * lagInd - 1)
{
insideIntegral += dt * (1 / (Y1 * A1)) * (exp(-(cd * (lagInd - q) * dt) / 2) * topLoadArray[p][iBefore + q]);
q++;
}
insideIntegral += 0.5 * dt * (1 / (Y1 * A1)) * (exp(-(cd * lagInd * dt) / 2) * topLoadArray[p][iBefore] + exp(-(cd * (-lagInd) * dt) / 2) * topLoadArray[p][iAfter]);
loadBefore = exp(-(cd * lagInd * dt) / 2) * topLoadArray[p][iBefore] + fact * (exp(-(cd * (lagInd + 1) * dt) / 2) * topLoadArray[p][iBefore - 1] - exp(-(cd * lagInd * dt) / 2) * topLoadArray[p][iBefore]);
loadAfter = exp(-(cd * (-lagInd) * dt) / 2) * topLoadArray[p][iAfter] + fact * (exp(-(cd * (-lagInd - 1) * dt) / 2) * topLoadArray[p][iAfter + 1] - exp(-(cd * (-lagInd) * dt) / 2) * topLoadArray[p][iAfter]);
insideIntegral += 0.5 * fact * dt * (1 / (Y1 * A1)) * (loadBefore + exp(-(cd * (lagInd) * dt) / 2) * topLoadArray[p][iBefore]);
insideIntegral += 0.5 * fact * dt * (1 / (Y1 * A1)) * (loadAfter + exp(-(cd * (-lagInd) * dt) / 2) * topLoadArray[p][iAfter]);
insideIntegral = 0.5 * a1 * insideIntegral;
pumpPOS += insideIntegral;
insideIntegral = 0;
int r = 1;
while (r < 2 * lagInd - 1)
{
insideIntegral += dt * (exp(-(cd * lagInd - r) * dt) / 2) * (topPosArray[p][iBefore + r]);
r++;
}
insideIntegral += 0.5 * dt * (exp(-(cd * lagInd * dt) / 2) * topPosArray[p][iBefore] + exp(-(cd * (-lagInd) * dt) / 2) * topPosArray[p][iAfter]);
loadBefore3 = exp(-(cd * (lagInd) * dt) / 2) * topPosArray[p][iBefore] + fact * (exp(-(cd * (lagInd + 1) * dt) / 2) * topPosArray[p][iBefore] - exp(-(cd * (lagInd) * dt) / 2) * topPosArray[p][iBefore]);
loadAfter3 = exp(-(cd * (-lagInd) * dt) / 2) * topPosArray[p][iAfter] + fact * (exp(-(cd * (-lagInd - 1) * dt) / 2) * topPosArray[p][iAfter] - exp(-(cd * (-lagInd) * dt) / 2) * topPosArray[p][iAfter]);
insideIntegral += 0.5 * fact * dt * (loadBefore3 + exp(-(cd * (lagInd) * dt) / 2) * topPosArray[p][iBefore]);
insideIntegral += 0.5 * fact * dt * (loadAfter3 + exp(-(cd * (-lagInd) * dt) / 2) * topPosArray[p][iAfter]);
insideIntegral = -((cd * rodLengthp) / 4) * (0.5 * (cd / (2 * a1))) * insideIntegral;
pumpPOS += insideIntegral;
//printf("Position: %f\n", pumpPOS);
return pumpPOS;
};
private double load(int s)
//calculate the downhole load of the given rod part
{
//temporary variables
double a1 = a[s];
double cd = c[s];
double rodLengths = rodLength[s];
int lagInd = lagIndex[s];
double Y1 = rodYM[s] * pow(10, 6);
double A1 = area[s];
int centerOfArray = centerPoint[s];
int iBefore = centerOfArray - lagInd;
int iAfter = centerOfArray + lagInd;
double pumpLOAD = 0;
pumpLOAD = 0.5 * (a1 / (Y1 * A1)) * (1 / a1) * (loadBefore + loadAfter);
pumpLOAD += -((cd * rodLengths) / 4) * (0.5 * (cd / (2 * a1))) * (1 / a1) * (loadBefore3 + loadAfter3);
double firstPart = 0;
double pointAfter = (topPosArray[s][iAfter + 1] - topPosArray[s][iAfter - 1]) / (2 * dt);
double pointBefore = (topPosArray[s][iBefore + 1] - topPosArray[s][iBefore - 1]) / (2 * dt);
firstPart = (exp((cd * rodLengths) / (2 * a1)) * pointAfter - exp(-(cd * rodLengths) / (2 * a1)) * pointBefore) / (2 * a1);
firstPart += (cd * exp((cd * rodLengths) / (2 * a1)) * topPosArray[s][iAfter] - cd * exp((-cd * rodLengths) / (2 * a1)) * topPosArray[s][iBefore]) / (4 * a1);
pumpLOAD = Y1 * A1 * (firstPart + pumpLOAD);
//printf("Load: %f\n", pumpLOAD);
return pumpLOAD;
};
public LPStatus calc(double sPosition, double sLoad){
boolean useShift = false;
int loadMult = 1;
int tapersAllowed = 1;
double dPosition = 0;
double dLoad = 0;
int status = BAD_STATUS;
for (int ii = 1; ii < lengthRequired[1] + 1; ii++)
{
topPosArray[1][ii - 1] = topPosArray[1][ii];
topLoadArray[1][ii - 1] = topLoadArray[1][ii];
}
topPosArray[1][lengthRequired[1]] = -(sPosition / 12); //stores current position in feet
if (sPosition > sPositionPrevious)
{
topLoadArray[1][lengthRequired[1]] = loadMult * (sLoad - rodWeightFluidTotal) - sbfriction;
}
else
{
topLoadArray[1][lengthRequired[1]] = loadMult * (sLoad - rodWeightFluidTotal) + sbfriction;
}
int j = 1;
while (j <= tapersAllowed)
{
count[j]++;
if (count[j] >= lengthRequired[j])
{
if ((j + 1) <= numTapers)
{
for (int jj = 2; jj < lengthRequired[j + 1] + 1; jj++)
{
topPosArray[j + 1][jj - 1] = topPosArray[j + 1][jj];
topLoadArray[j + 1][jj - 1] = topLoadArray[j + 1][jj];
}
topPosArray[j + 1][lengthRequired[j + 1]] = position(j);
topLoadArray[j + 1][lengthRequired[j + 1]] = load(j);
}
else
{
if (useShift)
{
dPosition = -12 * (position(j) + stretch[numTapers]);
}
else
{
dPosition = -12 * position(j);
}
dLoad = load(j) + force[numTapers];
status = GOOD_STATUS;
}
count[j]--;
tapersAllowed += 1;
if (tapersAllowed > numTapers)
{
tapersAllowed = numTapers;
}
}
j++;
}
LPStatus downholeValues = new LPStatus(dPosition, dLoad, status);
return downholeValues;
};
public static void main( String[] args ){
Well thisWell = new Well();
thisWell.parseJSONFile(args[0]);
// thisWell.parseJSONFile("/Users/patrickjmcd/Henry_Pump/poc-java/wellSetup.json");
thisWell.printTapers();
}
}