714 lines
31 KiB
Python
714 lines
31 KiB
Python
import math
|
|
import matplotlib as mpl
|
|
import numpy as np
|
|
import matplotlib.pyplot as plt
|
|
import matplotlib.animation as animation
|
|
from collections import deque
|
|
import datetime
|
|
import time
|
|
from pprint import pprint
|
|
import csv
|
|
|
|
|
|
|
|
### Create Surface & Load Files ###
|
|
import tkinter as tk
|
|
import tkinter.filedialog as fd
|
|
from time import sleep
|
|
|
|
root = tk.Tk()
|
|
root.withdraw()
|
|
|
|
surface = []
|
|
|
|
|
|
taper_setup = {}
|
|
taper_setup['tubing_head_pressure'] = 50
|
|
taper_setup['fluid_gradient'] = .45
|
|
taper_setup['stuffing_box_friction']= 100
|
|
taper_setup['c'] = [0, .08 , .08]
|
|
taper_setup['rod_length_data'] = [0, 10095, 300 ]
|
|
taper_setup['num_tapers'] = len(taper_setup['rod_length_data'])-1
|
|
taper_setup['rod_diameter_data'] = [0, .750 , 1.5 ]
|
|
taper_setup['rod_youngs_modulus_data'] = [0, 30.5, 30.5 ]
|
|
taper_setup['rod_weight_data'] = [0, 1.634 , 6]
|
|
taper_setup['dt'] = 0.0500
|
|
taper_setup['tubing_id'] = 1.995
|
|
taper_setup['tubing_od'] = 2.375
|
|
|
|
unit_config = {}
|
|
unit_config['anchor_depth'] = 8923.0
|
|
unit_config['well_name'] = "Python Demo Well"
|
|
unit_config['pump_diameter'] = 1.25
|
|
unit_config['pump_area'] = (unit_config['pump_diameter']**2) * math.pi
|
|
|
|
load_before = 0
|
|
load_after = 0
|
|
load_before_3 = 0
|
|
load_after_3 = 0
|
|
|
|
blank_array = [0]*100
|
|
top_pos_array = deque()
|
|
top_load_array = deque()
|
|
|
|
for i in range(0,10):
|
|
top_pos_array.append(blank_array[:])
|
|
top_load_array.append(blank_array[:])
|
|
|
|
pump_pos_array = []
|
|
pump_load_array = []
|
|
|
|
pr_l = [0,0]
|
|
pr_p = [0,0]
|
|
pmp_p = [0,0]
|
|
pmp_l = [0,0]
|
|
|
|
count = [0]* (taper_setup['num_tapers']+1)
|
|
|
|
position_load_counter = 0
|
|
surface_pos_array = []
|
|
surface_load_array = []
|
|
|
|
|
|
|
|
class Card:
|
|
def __init__(self, id, s_p_array, s_l_array, d_p_array, d_l_array, t, u_c):
|
|
self.card_id = id
|
|
self.date_time = datetime.datetime.now()
|
|
self.tapers = t
|
|
self.unit_config = u_c
|
|
self.surface_pos = s_p_array[:]
|
|
self.surface_load = s_l_array[:]
|
|
self.downhole_pos = d_p_array[:]
|
|
self.downhole_load = d_l_array[:]
|
|
self.downhole_fluid_load_adjustment = 223.907
|
|
print("downhole_fluid_load_adjustment not configured")
|
|
self.card_type = "NotConfigured"
|
|
print("card_type not configured")
|
|
|
|
def set_strokes_per_minute(self, strokes_per_minute):
|
|
self.strokes_per_minute = strokes_per_minute
|
|
|
|
def __find_nearest_point_to_load(self, direction, card_half ,target_load, pos_array, load_array):
|
|
left_ignore = min(pos_array) + (min(pos_array)+ max(pos_array))*(.75)
|
|
right_ignore = min(pos_array) + (min(pos_array)+ max(pos_array))*(.25)
|
|
|
|
if (direction=="up"):
|
|
for i in range(1, len(pos_array)):
|
|
if (card_half=="right" and pos_array[i] >= right_ignore):
|
|
if ((load_array[i] <= target_load) & (load_array[i-1] > target_load)):
|
|
return [pos_array[i], load_array[i]]
|
|
elif( card_half =="left" and pos_array[i] <= left_ignore):
|
|
if ((load_array[i] >= target_load) & (load_array[i-1] < target_load)):
|
|
return [pos_array[i], load_array[i]]
|
|
else:
|
|
for j in range(len(pos_array)-1, 1, -1):
|
|
if (card_half=="right" and pos_array[i] >= right_ignore):
|
|
if ((load_array[i] >= target_load) & (load_array[i-1] < target_load)):
|
|
return [pos_array[i], load_array[i]]
|
|
elif( card_half =="left" and pos_array[i] <= left_ignore):
|
|
if ((load_array[i] <= target_load) & (load_array[i-1] > target_load)):
|
|
return [pos_array[i], load_array[i]]
|
|
|
|
def __find_incremental_load(self, target_position, pos_array, load_array):
|
|
for i in range(1, len(pos_array)):
|
|
if ((pos_array[i] > target_position) and (pos_array[i-1] < target_position)):
|
|
up_point_greater = [pos_array[i], load_array[i]]
|
|
up_point_lesser = [pos_array[i-1], load_array[i-1]]
|
|
if ((pos_array[i] < target_position) and (pos_array[i-1] > target_position)):
|
|
down_point_greater = [pos_array[i], load_array[i]]
|
|
down_point_lesser = [pos_array[i-1], load_array[i-1]]
|
|
m_up = (up_point_greater[1] - up_point_lesser[1]) / (up_point_greater[0] - up_point_lesser[0])
|
|
b_up = up_point_greater[1] - (m_up * up_point_greater[0])
|
|
up_middle = (m_up*target_position) + b_up
|
|
|
|
m_down = (down_point_greater[1] - down_point_lesser[1]) / (down_point_greater[0] - down_point_lesser[0])
|
|
b_down = down_point_greater[1] - (m_down * down_point_greater[0])
|
|
down_middle = (m_down*target_position) + b_down
|
|
|
|
return up_middle - down_middle
|
|
|
|
|
|
def find_limits(self):
|
|
surface_max_position_position = max(self.surface_pos)
|
|
surface_max_position_load = self.surface_load[self.surface_pos.index(surface_max_position_position)]
|
|
self.surface_max_position = [surface_max_position_position, surface_max_position_load]
|
|
|
|
surface_min_position_position = min(self.surface_pos)
|
|
surface_min_position_load = self.surface_load[self.surface_pos.index(surface_min_position_position)]
|
|
self.surface_min_position = [surface_min_position_position, surface_min_position_load]
|
|
|
|
surface_max_load_load = max(self.surface_load)
|
|
surface_max_load_position = self.surface_pos[self.surface_load.index(surface_max_load_load)]
|
|
self.surface_max_load = [surface_max_load_position, surface_max_load_load]
|
|
|
|
surface_min_load_load = min(self.surface_load)
|
|
surface_min_load_position = self.surface_pos[self.surface_load.index(surface_min_load_load)]
|
|
self.surface_min_load = [surface_min_load_position, surface_min_load_load]
|
|
|
|
downhole_max_load_load = max(self.downhole_load)
|
|
downhole_max_load_position = self.downhole_pos[self.downhole_load.index(downhole_max_load_load)]
|
|
self.downhole_max_load = [downhole_max_load_position, downhole_max_load_load]
|
|
|
|
downhole_min_load_load = min(self.downhole_load)
|
|
downhole_min_load_position = self.downhole_pos[self.downhole_load.index(downhole_min_load_load)]
|
|
self.downhole_min_load = [downhole_min_load_position, downhole_min_load_load]
|
|
|
|
downhole_min_position_position = min(self.downhole_pos)
|
|
downhole_min_position_load = self.downhole_load[self.downhole_pos.index(downhole_min_position_position)]
|
|
self.downhole_min_position = [downhole_min_position_position, downhole_min_position_load]
|
|
|
|
downhole_max_position_position = max(self.downhole_pos)
|
|
downhole_max_position_load = self.downhole_load[self.downhole_pos.index(downhole_max_position_position)]
|
|
self.downhole_max_position = [downhole_max_position_position, downhole_max_position_load]
|
|
|
|
self.downhole_fluid_load = (self.downhole_max_load[1] - self.downhole_min_load[1]) - self.downhole_fluid_load_adjustment
|
|
self.surface_stroke_length = self.surface_max_position[0] - self.surface_min_position[0]
|
|
|
|
def print_limits(self):
|
|
if not ('self.surface_stroke_length' in locals()):
|
|
self.find_limits()
|
|
print("Surface Max Position:", self.surface_max_position)
|
|
print("Surface Min Position:", self.surface_min_position)
|
|
print("Surface Max Load:", self.surface_max_load)
|
|
print("Surface Min Load:", self.surface_min_load)
|
|
print("Downhole Max Load:", self.downhole_max_load)
|
|
print("Downhole Min Load:", self.downhole_min_load)
|
|
print("Downhole Min Position:", self.downhole_min_position)
|
|
print("Downhole Max Position:", self.downhole_max_position)
|
|
|
|
|
|
def find_corners(self, pct_top, pct_bottom):
|
|
if not ('self.surface_stroke_length' in locals()):
|
|
self.find_limits()
|
|
|
|
downhole_load_span = self.downhole_max_load[1] - self.downhole_min_load[1]
|
|
half_load_load = self.downhole_min_load[1] + downhole_load_span / 2
|
|
half_load = self.__find_nearest_point_to_load("up", "left", half_load_load , self.downhole_pos, self.downhole_load)
|
|
|
|
if(self.downhole_min_position[0] < half_load[0]):
|
|
self.corner_bottom_left = self.downhole_min_position
|
|
self.corner_top_left = self.__find_nearest_point_to_load("up", "left", self.downhole_max_load[1]-downhole_load_span*(pct_top/100), self.downhole_pos, self.downhole_load)
|
|
else:
|
|
self.corner_bottom_left = self.__find_nearest_point_to_load("up", "left", self.downhole_min_load[1]+downhole_load_span*(pct_bottom/100), self.downhole_pos, self.downhole_load)
|
|
self.corner_top_left = self.downhole_min_position
|
|
|
|
self.corner_top_right = self.downhole_max_position
|
|
self.corner_fillage = self.__find_nearest_point_to_load("up", "right", self.downhole_min_load[1]+downhole_load_span*(pct_bottom/100), self.downhole_pos, self.downhole_load)
|
|
self.corner_full_fillage_point = [self.corner_bottom_left[0]+ self.corner_top_right[0] - self.corner_top_left[0], self.corner_bottom_left[1]]
|
|
|
|
def print_corners(self):
|
|
if not ('self.corner_fillage' in locals()):
|
|
self.find_corners(25, 25)
|
|
print("Bottom Left:", self.corner_bottom_left)
|
|
print("Bottom Left:", self.corner_top_left)
|
|
print("Bottom Left:", self.corner_top_right)
|
|
print("Bottom Left:", self.corner_fillage)
|
|
print("Bottom Left:", self.corner_full_fillage_point)
|
|
|
|
def calc_fillage(self, pct_top, pct_bottom):
|
|
if not ('self.corner_fillage' in locals()):
|
|
self.find_corners(pct_top, pct_bottom)
|
|
self.downhole_gross_stroke = self.downhole_max_position[0] - self.downhole_min_position[0]
|
|
|
|
self.tubing_movement = 12 * (tapers.rod_depth_total - self.unit_config['anchor_depth'])*self.downhole_fluid_load / (30500000* self.tapers.tubing_cross_sectional_area)
|
|
self.downhole_adjusted_gross_stroke = self.downhole_gross_stroke - self.tubing_movement
|
|
self.downhole_net_stroke = self.corner_fillage[0] - self.corner_bottom_left[0]
|
|
self.fillage_estimated = ((self.corner_fillage[0] - self.corner_bottom_left[0])/(self.corner_full_fillage_point[0] - self.corner_bottom_left[0])) * 100
|
|
self.fillage_calculated = ((self.downhole_net_stroke + self.tubing_movement) / self.downhole_gross_stroke) * 100
|
|
|
|
def listSurface(self):
|
|
for i in range(0,len(self.surface_pos)):
|
|
print([self.surface_pos[i], self.surface_load[i]])
|
|
|
|
def listDownhole(self):
|
|
for i in range(0,len(self.downhole_pos)):
|
|
print([self.downhole_pos[i], self.downhole_load[i]])
|
|
|
|
def calc_hp(self, riemann_slices):
|
|
self.polished_rod_horsepower = 0
|
|
self.pump_horsepower = 0
|
|
downSlices = []
|
|
if not ('self.surface_stroke_length' in locals()):
|
|
self.find_limits()
|
|
if not ('self.downhole_net_stroke' in locals()):
|
|
self.calc_fillage(25,25)
|
|
|
|
dx_surface = self.surface_stroke_length / (riemann_slices + 1)
|
|
dx_downhole = self.downhole_net_stroke / (riemann_slices + 1)
|
|
|
|
for i in range(1, riemann_slices):
|
|
target_surface = dx_surface * i + self.surface_min_position[0]
|
|
target_downhole = dx_downhole*i + self.downhole_min_position[0]
|
|
|
|
slice_surface = self.__find_incremental_load(target_surface, self.surface_pos, self.surface_load)
|
|
slice_downhole = self.__find_incremental_load(target_downhole, self.downhole_pos, self.downhole_load)
|
|
|
|
self.polished_rod_horsepower += (dx_surface / 12) * slice_surface * self.strokes_per_minute / 33000
|
|
self.pump_horsepower += (dx_downhole / 12) * slice_downhole * self.strokes_per_minute / 33000
|
|
|
|
def calc_fluid_level(self):
|
|
if not ('self.downhole_fluid_load' in locals()):
|
|
self.find_limits()
|
|
self.pump_intake_pressure = self.tapers.params['fluid_gradient'] * self.tapers.rod_depth_total - (self.downhole_fluid_load / self.unit_config['pump_area'])
|
|
self.fluid_above_pump = self.pump_intake_pressure / self.tapers.params['fluid_gradient']
|
|
|
|
def write_csv(self):
|
|
if not ('self.fluid_above_pump' in locals()):
|
|
self.calc_fluid_level()
|
|
if not ('self.polished_rod_horsepower' in locals()):
|
|
self.calc_hp(100)
|
|
if not ('self.fillage_calculated' in locals()):
|
|
self.calc_fillage(25,25)
|
|
|
|
csvData = {}
|
|
csvData['card_id'] = self.card_id
|
|
csvData['num_tapers'] = self.tapers.params['num_tapers']
|
|
csvData['num_points'] = len(self.surface_pos)
|
|
csvData['card_type'] = self.card_type
|
|
csvData['_year'] = self.date_time.year
|
|
csvData['_month'] = self.date_time.month
|
|
csvData['_day'] = self.date_time.day
|
|
csvData['_hour'] = self.date_time.hour
|
|
csvData['_minute'] = self.date_time.minute
|
|
csvData['_second'] = self.date_time.second
|
|
csvData['well_name'] = self.unit_config['well_name']
|
|
csvData['tubing_head_pressure'] = self.tapers.params['tubing_head_pressure']
|
|
csvData['fluid_gradient'] = self.tapers.params['fluid_gradient']
|
|
csvData['stuffing_box_friction'] = self.tapers.params['stuffing_box_friction']
|
|
csvData['dt'] = self.tapers.dt
|
|
csvData['downhole_max_load'] = self.downhole_max_load[1]
|
|
csvData['downhole_min_load'] = self.downhole_min_load[1]
|
|
csvData['downhole_max_position'] = self.downhole_max_position[0]
|
|
csvData['downhole_min_position'] = self.downhole_min_position[0]
|
|
csvData['downhole_gross_stroke'] = self.downhole_gross_stroke
|
|
csvData['downhole_adjusted_gross_stroke'] = self.downhole_adjusted_gross_stroke
|
|
csvData['downhole_net_stroke'] = self.downhole_net_stroke
|
|
csvData['downhole_fluid_load'] = self.downhole_fluid_load
|
|
csvData['surface_max_load'] = self.surface_max_load[1]
|
|
csvData['surface_min_load'] = self.surface_min_load[1]
|
|
csvData['surface_max_position'] = self.surface_max_position[0]
|
|
csvData['surface_min_position'] = self.surface_min_position[0]
|
|
csvData['tubing_movement'] = self.tubing_movement
|
|
csvData['surface_stroke_length'] = self.surface_stroke_length
|
|
csvData['fillage_percent'] = self.fillage_calculated
|
|
csvData['polished_rod_horsepower'] = self.polished_rod_horsepower
|
|
csvData['pump_horsepower'] = self.pump_horsepower
|
|
csvData['strokes_per_minute'] = self.strokes_per_minute
|
|
csvData['fluid_above_pump'] = self.fluid_above_pump
|
|
|
|
file_date = str(self.date_time.year) + str(self.date_time.month) + str(self.date_time.day)
|
|
file_time = str(self.date_time.hour) + str(self.date_time.minute) + str(self.date_time.second)
|
|
file_fillage = str(round(self.fillage_calculated,3))
|
|
filename = file_date + '_' + file_time + '_' + str(self.card_id) + '_' + self.card_type + '_' + str(self.fillage_calculated).replace(".", "-") + ".csv"
|
|
|
|
with open(filename, 'wt', newline='') as card_file:
|
|
writer = csv.writer(card_file)
|
|
for data_point in csvData:
|
|
writer.writerow([data_point, csvData[data_point]])
|
|
writer.writerow(["s_pos", "s_load"])
|
|
for i in range(0, len(self.surface_pos)):
|
|
writer.writerow([self.surface_pos[i], self.surface_load[i]])
|
|
writer.writerow(["d_pos", "d_load"])
|
|
for j in range(0, len(self.downhole_pos)):
|
|
writer.writerow([self.downhole_pos[j], self.downhole_load[j]])
|
|
|
|
def plot(self):
|
|
fig = plt.figure(figsize=(12, 9))
|
|
fig.canvas.set_window_title('Well Load & Position Cards')
|
|
ax1 = fig.add_subplot(2,1,1)
|
|
ax2 = fig.add_subplot(2,1,2)
|
|
ax1.set_title("Surface Card")
|
|
ax2.set_title("Downhole Card")
|
|
ax1.set_xlabel('Position')
|
|
ax2.set_xlabel('Position')
|
|
ax1.set_ylabel('Load')
|
|
ax2.set_ylabel('Load')
|
|
|
|
ax1.fill(self.surface_pos, self.surface_load, 'g')
|
|
ax2.fill(self.downhole_pos, self.downhole_load, 'b')
|
|
|
|
leg1 = ax1.legend()
|
|
leg2 = ax2.legend()
|
|
|
|
fig.subplots_adjust(hspace=.4)
|
|
ax1.grid(True)
|
|
ax2.grid(True)
|
|
plt.ion()
|
|
plt.show()
|
|
|
|
class Taper:
|
|
def __init__(self,params):
|
|
self.params = params
|
|
self.buoyant_force_total = 0
|
|
self.rod_weight_in_fluid_total = 0
|
|
self.rod_weight_in_air_total = 0
|
|
self.weight_data_total = 0
|
|
self.rod_depth_total = 0
|
|
self.annular_force_data_total = 0
|
|
|
|
self.a = []
|
|
self.area = []
|
|
self.pressure = [self.params['tubing_head_pressure']]
|
|
self.buoyant_force = []
|
|
self.stretch = []
|
|
self.weight_data = []
|
|
self.annular_force_data = []
|
|
self.force = []
|
|
self.alpha = []
|
|
self.x_over_a = []
|
|
self.factor_array = []
|
|
self.lag_index_array = []
|
|
self.center_point = []
|
|
self.sum_center_point = []
|
|
self.length_required =[]
|
|
|
|
self.dt = params['dt']
|
|
|
|
self.rod_depth = []
|
|
self.rod_weight_in_air = []
|
|
self.rod_weight_in_fluid = []
|
|
|
|
for x in range(0, self.params['num_tapers'] + 2):
|
|
self.area.append(0)
|
|
self.pressure.append(0)
|
|
self.buoyant_force.append(0)
|
|
self.rod_weight_in_air.append(0)
|
|
self.rod_depth.append(0)
|
|
self.rod_weight_in_fluid.append(0)
|
|
self.weight_data.append(0)
|
|
self.annular_force_data.append(0)
|
|
self.a.append(0)
|
|
self.stretch.append(0)
|
|
self.force.append(0)
|
|
self.alpha.append(0)
|
|
self.x_over_a.append(0)
|
|
self.factor_array.append(0)
|
|
self.lag_index_array.append(0)
|
|
self.center_point.append(0)
|
|
self.sum_center_point.append(0)
|
|
self.length_required.append(0)
|
|
|
|
for area_i in range(1, self.params['num_tapers']+1):
|
|
self.area[area_i] = (math.pi / 4) * (self.params['rod_diameter_data'][area_i] ** 2)
|
|
|
|
for i in range(1, self.params['num_tapers']+1):
|
|
self.a[i] = 1000 * (32.2 * self.params['rod_youngs_modulus_data'][i] * self.area[i] / self.params['rod_weight_data'][i])**(0.5)
|
|
self.rod_depth[i] = self.rod_depth[i-1] + self.params['rod_length_data'][i]
|
|
self.pressure[i] = self.pressure[i-1] + self.params['fluid_gradient'] * self.params['rod_length_data'][i]
|
|
self.buoyant_force[i] = self.pressure[i] * (self.area[i+1] - self.area[i])
|
|
self.rod_weight_in_air[i] = self.params['rod_weight_data'][i] * self.params['rod_length_data'][i]
|
|
self.rod_weight_in_fluid[i] = self.rod_weight_in_air[i] + self.buoyant_force[i]
|
|
|
|
for j in range(1, self.params['num_tapers']+1):
|
|
for k in range(j+1, self.params['num_tapers']+1):
|
|
self.weight_data[j] = self.weight_data[j] + self.params['rod_weight_data'][k] * self.params['rod_length_data'][k]
|
|
for l in range(j, self.params['num_tapers']):
|
|
self.annular_force_data[j] = self.annular_force_data[j] + self.pressure[l] * (self.area[l] - self.area[l+1])
|
|
self.force[j] = (-self.area[self.params['num_tapers']] * self.pressure[self.params['num_tapers']]) + self.weight_data[j] - self.annular_force_data[j]
|
|
self.alpha[j] = (self.force[j] + self.params['rod_weight_data'][j] * self.params['rod_length_data'][j]) / (self.params['rod_youngs_modulus_data'][j] * 10**6 * self.area[j])
|
|
self.stretch[j] = self.stretch[j-1] + self.alpha[j] * self.params['rod_length_data'][j] - (self.params['rod_weight_data'][j] * self.params['rod_length_data'][j]**2) / (2 * self.params['rod_youngs_modulus_data'][j] * 10**6 * self.area[j])
|
|
|
|
for m in range(1, self.params['num_tapers']+1):
|
|
self.x_over_a[m] = self.params['rod_length_data'][m] / self.a[m]
|
|
self.lag_index_array[m] = math.trunc(self.params['rod_length_data'][m] / (self.a[m] * self.dt))
|
|
self.factor_array[m] = (self.x_over_a[m] - self.lag_index_array[m] * self.dt) / self.dt
|
|
self.center_point[m] = self.lag_index_array[m] + 2
|
|
self.length_required[m] = 2 * (self.lag_index_array[m] + 1) + 1
|
|
|
|
self.sum_center_point[1] = self.center_point[1]
|
|
for n in range(2, self.params['num_tapers']):
|
|
self.sum_center_point[n] = self.sum_center_point[n-1] + self.center_point[n] - 1
|
|
|
|
for b in self.buoyant_force:
|
|
self.buoyant_force_total = self.buoyant_force_total + b
|
|
|
|
for r in self.rod_weight_in_air:
|
|
self.rod_weight_in_air_total = self.rod_weight_in_air_total + r
|
|
|
|
for r1 in self.rod_weight_in_fluid:
|
|
self.rod_weight_in_fluid_total = self.rod_weight_in_fluid_total + r1
|
|
|
|
for r2 in self.params['rod_length_data']:
|
|
self.rod_depth_total = self.rod_depth_total + r2
|
|
|
|
for a1 in self.annular_force_data:
|
|
self.annular_force_data_total = self.annular_force_data_total + a1
|
|
|
|
for w in self.weight_data:
|
|
self.weight_data_total = self.weight_data_total + w
|
|
|
|
self.tubing_cross_sectional_area = (math.pi / 4) * (self.params['tubing_od']**2 - self.params['tubing_id']**2)
|
|
|
|
def set_real_dt(self, dt):
|
|
self.dt = dt
|
|
for m in range(1, self.params['num_tapers']+1):
|
|
self.lag_index_array[m] = math.trunc(self.params['rod_length_data'][m] / (self.a[m] * self.dt))
|
|
self.factor_array[m] = (self.x_over_a[m] - self.lag_index_array[m] * self.dt) / self.dt
|
|
|
|
def printSetup(self):
|
|
print("------------ Well Params ---------------------")
|
|
print("Tubing Head pressure: ", self.params['tubing_head_pressure'])
|
|
print("Fluid Gradient: ", self.params['fluid_gradient'])
|
|
print("Stuffing Box Friction: ", self.params['stuffing_box_friction'])
|
|
print("Number of Tapers: ", self.params['num_tapers'])
|
|
print("Damping Factor: " , self.params['c'] )
|
|
print("Rod Length Data: " , self.params['rod_length_data'])
|
|
print("Rod Diameter Data: ", self.params['rod_diameter_data'])
|
|
print("Rod Young's Modulus Data: ", self.params['rod_youngs_modulus_data'])
|
|
print("Rod Weight Data: ", self.params['rod_weight_data'])
|
|
print("dt: ", self.dt)
|
|
print("tubing_id:", self.params['tubing_id'])
|
|
print("tubing_od:", self.params['tubing_od'])
|
|
print("----------------------------------------------")
|
|
|
|
def printTaper(self):
|
|
print("------------ Taper Params --------------------")
|
|
print("area:", self.area)
|
|
print("Speed of Sound in Rod(a):", self.a)
|
|
print("Rod Depth:", self.rod_depth)
|
|
print("pressure:", self.pressure)
|
|
print("Buoyant force:", self.buoyant_force)
|
|
print("Rod Weight in Air:", self.rod_weight_in_air)
|
|
print("Weight Data:", self.weight_data)
|
|
print("Annulus pressure Data:", self.annular_force_data)
|
|
print("force Data:", self.force)
|
|
print("alpha Data:", self.alpha)
|
|
print("stretch Data:", self.stretch)
|
|
print("X over A:", self.x_over_a)
|
|
print("Factor Array:", self.factor_array)
|
|
print("Lag Index Array:", self.lag_index_array)
|
|
print("center_point:", self.center_point)
|
|
print("sum_center_point:", self.sum_center_point)
|
|
print("Length Required:", self.length_required)
|
|
print("TubingCSA:", self.tubing_cross_sectional_area)
|
|
print("------------ Taper Totals --------------------")
|
|
print("buoyant_force_total:", self.buoyant_force_total)
|
|
print("rod_weight_in_air_total:", self.rod_weight_in_air_total)
|
|
print("rod_weight_in_fluid_total:", self.rod_weight_in_fluid_total)
|
|
print("rod_depth_total:", self.rod_depth_total)
|
|
print("annular_force_data_total:", self.annular_force_data_total)
|
|
print("weight_data_total:", self.weight_data_total)
|
|
print("----------------------------------------------")
|
|
|
|
|
|
def position_function(p,tap): #CHECKED LOGIC ON 1/21/2015
|
|
|
|
global top_load_array
|
|
global top_pos_array
|
|
global load_before
|
|
global load_after
|
|
global load_before_3
|
|
global load_after_3
|
|
|
|
load_before = 0
|
|
load_after = 0
|
|
load_before_3 = 0
|
|
load_after_3 = 0
|
|
|
|
dt = tap.dt
|
|
a1= tap.a[p]
|
|
cd = tap.params['c'][p]
|
|
factor = tap.factor_array[p]
|
|
rod_length = tap.params['rod_length_data'][p]
|
|
lag_index = tap.lag_index_array[p]
|
|
Y1 = tap.params['rod_youngs_modulus_data'][p]
|
|
Y1 = Y1 * 10**6
|
|
A1 = tap.area[p]
|
|
center_of_array = tap.center_point[p]
|
|
|
|
#print("p:", p, "a1:", a1, "| cd:", cd, "| factor:", factor, "| rod_length:", rod_length, "| lag_index:", lag_index, "| Y1:", Y1, "| A1:", A1, "| center_of_array:", center_of_array)
|
|
i_before = center_of_array - lag_index
|
|
i_after = center_of_array + lag_index
|
|
#print("------")
|
|
pump_pos = 0
|
|
pump_pos = math.exp((cd * rod_length) / (2 * a1)) * (top_pos_array[p][i_after] + factor * (top_pos_array[p][i_after + 1] - top_pos_array[p][i_after]))
|
|
pump_pos = pump_pos + math.exp(-(cd * rod_length) / (2 * a1)) * (top_pos_array[p][i_before] + factor * (top_pos_array[p][i_before - 1] - top_pos_array[p][i_before]))
|
|
pump_pos = 0.5 * pump_pos
|
|
inside_integral = 0
|
|
q = 1
|
|
while(q < 2* lag_index - 1):
|
|
inside_integral = inside_integral + dt * (1 / (Y1 * A1)) * (math.exp(-(cd * (lag_index - q ) * dt) / 2 ) * top_load_array[p][i_before +q])
|
|
q+=1
|
|
inside_integral = inside_integral + (1/2) * dt * (1 / (Y1 * A1)) * (math.exp(-(cd *lag_index * dt)/ 2) * top_load_array[p][i_before] + math.exp(- (cd* (-lag_index ) * dt) / 2) * top_load_array[p][i_after])
|
|
|
|
load_before = math.exp(-(cd * lag_index * dt) / 2) * top_load_array[p][i_before] + factor * (math.exp(-(cd * (lag_index + 1) * dt) / 2) * top_load_array[p][i_before - 1] - math.exp(-(cd* (lag_index) * dt ) / 2 ) * top_load_array[p][i_before])
|
|
load_after = math.exp(-(cd * (-lag_index) * dt) / 2) * top_load_array[p][i_after] + factor * (math.exp(-(cd * (-lag_index - 1) * dt) / 2) * top_load_array[p][i_after + 1] - math.exp(-(cd* (-lag_index) * dt ) / 2 ) * top_load_array[p][i_after])
|
|
inside_integral = inside_integral + 0.5 * factor * dt * (1 / (Y1 * A1)) * (load_before + math.exp(-(cd * (lag_index) * dt ) / 2) * top_load_array[p][i_before])
|
|
inside_integral = inside_integral + 0.5 * factor * dt * (1 / (Y1 * A1)) * (load_after + math.exp(-(cd * (-lag_index) * dt ) / 2) * top_load_array[p][i_after])
|
|
inside_integral = (1/2) * a1 * inside_integral
|
|
pump_pos = pump_pos + inside_integral
|
|
inside_integral = 0
|
|
|
|
r = 1
|
|
while(r < 2 * lag_index - 1):
|
|
inside_integral = inside_integral + dt * (math.exp(-(cd *(lag_index - r) * dt)/2) * (top_pos_array[p][i_before + r]))
|
|
r = r+1
|
|
|
|
inside_integral = inside_integral + (1/2) * dt * (math.exp(-(cd * lag_index * dt) / 2) * top_pos_array[p][i_before] + math.exp(-(cd * (-lag_index) * dt)/2) * top_pos_array[p][i_after])
|
|
|
|
load_before_3 = math.exp(-(cd * (lag_index) *dt) / 2) * top_pos_array[p][i_before] + factor * (math.exp(-(cd * (lag_index + 1) *dt) / 2) * top_pos_array[p][i_before - 1] - math.exp(-(cd * (lag_index) * dt)/2) * top_pos_array[p][i_before])
|
|
|
|
load_after_3 = math.exp(-(cd * (-lag_index) *dt) / 2) * top_pos_array[p][i_after] + factor * (math.exp(-(cd * (-lag_index - 1) *dt) / 2) * top_pos_array[p][i_after + 1] - math.exp(-(cd * (-lag_index) * dt)/2) * top_pos_array[p][i_after])
|
|
inside_integral = inside_integral + (1/2) * factor * dt * (load_before_3 + math.exp(-(cd * (lag_index) * dt)/2) * top_pos_array[p][i_before])
|
|
inside_integral = inside_integral + (1/2) * factor * dt * (load_after_3 + math.exp(-(cd * (-lag_index) * dt)/2) * top_pos_array[p][i_after])
|
|
inside_integral = -((cd * rod_length) / 4 ) * ((1/2) * (cd / (2*a1))) * inside_integral
|
|
pump_pos = pump_pos + inside_integral
|
|
return(pump_pos)
|
|
|
|
def load_function(s, tap):
|
|
|
|
global top_load_array
|
|
global top_pos_array
|
|
global load_before
|
|
global load_after
|
|
global load_before_3
|
|
global load_after_3
|
|
|
|
dt = tap.dt
|
|
a1= tap.a[s]
|
|
cd = tap.params['c'][s]
|
|
factor = tap.factor_array[s]
|
|
rod_length = tap.params['rod_length_data'][s]
|
|
lag_index = tap.lag_index_array[s]
|
|
Y1 = tap.params['rod_youngs_modulus_data'][s]
|
|
Y1 = Y1 * 10**6
|
|
A1 = tap.area[s]
|
|
center_of_array = tap.center_point[s]
|
|
i_before = center_of_array - lag_index
|
|
i_after = center_of_array + lag_index
|
|
|
|
pump_load = 0
|
|
pump_load = (1/2) * (a1 / (Y1*A1)) * (1 / a1) * (load_before + load_after)
|
|
temp_result = Y1 * A1 * pump_load
|
|
pump_load = pump_load -((cd * rod_length) / 4 ) * ((1/2) * (cd / (2*a1))) * (1/a1) * (load_before_3 + load_after_3)
|
|
|
|
first_part = 0
|
|
|
|
point_after = (top_pos_array[s][i_after+1] - top_pos_array[s][i_after -1]) / (2 * dt)
|
|
point_before = (top_pos_array[s][i_before+1] - top_pos_array[s][i_before -1]) / (2 * dt)
|
|
first_part = (math.exp((cd*rod_length)/(2*a1)) * point_after - math.exp(-(cd*rod_length)/(2*a1)) * point_before) / (2 *a1)
|
|
first_part = first_part +(cd * math.exp((cd*rod_length)/(2*a1))*top_pos_array[s][i_after] - cd * math.exp((-cd*rod_length)/(2*a1))*top_pos_array[s][i_before]) / (4 * a1)
|
|
pump_load = Y1 * A1 * (first_part + pump_load)
|
|
return(pump_load)
|
|
|
|
def calc(pos, load, t):
|
|
global pr_p
|
|
global pr_l
|
|
global pmp_p
|
|
global pmp_l
|
|
global top_pos_array
|
|
global top_load_array
|
|
global position_load_counter
|
|
global surface_pos_array
|
|
global surface_load_array
|
|
USE_SHIFT = False
|
|
surface_pos_array.append(pos)
|
|
surface_load_array.append(load)
|
|
|
|
load_mult = 1
|
|
tapers_allowed = 1
|
|
pr_l[0] = pr_l[1]
|
|
pmp_l[0] = pmp_l[1]
|
|
pr_p[0] = pr_p[1]
|
|
pmp_p[0] = pmp_p[1]
|
|
pr_p[1] = pos
|
|
pr_l[1] = load
|
|
for ii in range(1, t.length_required[1]+1):
|
|
top_pos_array[1][ii-1] = top_pos_array[1][ii]
|
|
top_load_array[1][ii-1] = top_load_array[1][ii]
|
|
top_pos_array[1][t.length_required[1]] = -(pr_p[1] / 12)
|
|
|
|
if(pr_p[1] > pr_p[0]):
|
|
top_load_array[1][t.length_required[1]] = load_mult * (pr_l[1] - t.rod_weight_in_fluid_total) - t.params['stuffing_box_friction']
|
|
elif (pr_p[1] < pr_p[0]):
|
|
top_load_array[1][t.length_required[1]] = load_mult * (pr_l[1] - t.rod_weight_in_fluid_total) + t.params['stuffing_box_friction']
|
|
else:
|
|
top_load_array[1][t.length_required[1]] = load_mult * (pr_l[1] - t.rod_weight_in_fluid_total)
|
|
j=1
|
|
while j <= tapers_allowed:
|
|
count[j] = count[j] + 1
|
|
if (count[j] >= t.length_required[j]):
|
|
if((j+1) <= t.params['num_tapers']):
|
|
for ii in range(2, t.length_required[j+1]+1):
|
|
top_pos_array[j+1][ii-1] = top_pos_array[j+1][ii]
|
|
top_load_array[j+1][ii-1] = top_load_array[j+1][ii]
|
|
top_pos_array[j+1][t.length_required[j+1]] = position_function(j,t)
|
|
top_load_array[j+1][t.length_required[j+1]] = load_function(j,t)
|
|
else:
|
|
if USE_SHIFT:
|
|
pmp_p[1] = -12 * (position_function(j,t) + t.stretch[t.params['num_tapers']])
|
|
else:
|
|
pmp_p[1] = -12 * position_function(j,t)
|
|
pmp_l[1] = load_function(j,t) + t.force[t.params['num_tapers']]
|
|
pump_pos_array.append(pmp_p[1])
|
|
pump_load_array.append(pmp_l[1])
|
|
position_load_counter += 1
|
|
count[j] = count[j] - 1
|
|
tapers_allowed = tapers_allowed + 1
|
|
if(tapers_allowed > t.params['num_tapers']):
|
|
tapers_allowed = t.params['num_tapers']
|
|
j = j+1
|
|
|
|
return [[pr_p[1], pr_l[1]], [pmp_p[1], pmp_l[1]]]
|
|
|
|
|
|
tapers = Taper(taper_setup)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
file_path = fd.askopenfilename()
|
|
store_points = False
|
|
import csv
|
|
with open(file_path, 'r') as csvfile:
|
|
data_reader = csv.reader(csvfile)
|
|
for row in data_reader:
|
|
if (row[0]=="s_pos"):
|
|
store_points = False
|
|
if store_points:
|
|
surface.append([float(row[0]),float(row[1])])
|
|
if (row[0]=="d_pos"):
|
|
store_points = True
|
|
|
|
def loop(iterations):
|
|
stroke_start_time = time.time()
|
|
point_times = [0,0]
|
|
for point in range(0,len(surface)):
|
|
#print ("calc for", surface[point][0], surface[point][1] )
|
|
point_time_delta = point_times[1] - point_times[0]
|
|
#print("pt took:", point_time_delta)
|
|
point_times[0] = point_times[1]
|
|
point_times[1] = time.time()
|
|
current = calc(surface[point][0], surface[point][1], tapers)
|
|
if ((point_time_delta > 0) and (point_time_delta < 2)):
|
|
tapers.set_real_dt(point_time_delta)
|
|
time.sleep(tapers.params['dt'])
|
|
stroke_end_time = time.time()
|
|
stroke_time_delta = stroke_end_time - stroke_start_time
|
|
|
|
|
|
pump_pos_array.append(pump_pos_array[0])
|
|
pump_load_array.append(pump_load_array[0])
|
|
surface_pos_array.append(surface_pos_array[0])
|
|
surface_load_array.append(surface_load_array[0])
|
|
|
|
last_card = Card(1,surface_pos_array, surface_load_array, pump_pos_array, pump_load_array, tapers, unit_config)
|
|
last_card.set_strokes_per_minute((1 / stroke_time_delta) * 60)
|
|
last_card.calc_fillage(25,25)
|
|
last_card.calc_hp(100)
|
|
print("polished_rod_horsepower:", last_card.polished_rod_horsepower)
|
|
print("pump_horsepower:", last_card.pump_horsepower)
|
|
print("strokes_per_minute:", last_card.strokes_per_minute)
|
|
iterations -= 1
|
|
if (iterations > 0):
|
|
loop(iterations)
|
|
if (iterations == 0):
|
|
last_card.print_corners()
|
|
last_card.write_csv()
|
|
last_card.plot()
|
|
|
|
|
|
loop(1)
|
|
|
|
#pprint(vars(last_card))
|