From 0adef36b267df125096d205c7a651053eee9d6b8 Mon Sep 17 00:00:00 2001 From: Patrick McDonagh Date: Fri, 27 May 2016 17:38:12 -0500 Subject: [PATCH] Adds files --- algorithm.py | 726 ++++++++++++++++++++++++++++++++++ algorithm_velocity.py | 713 +++++++++++++++++++++++++++++++++ setupTapers.py | 183 +++++++++ surface_card.json | 1 + valveCheck.py | 49 +++ wellconfigs/BeanRanch341.p | 82 ++++ wellconfigs/Casselman16-8.p | 75 ++++ wellconfigs/UnivTaylor192UW.p | 82 ++++ 8 files changed, 1911 insertions(+) create mode 100644 algorithm.py create mode 100644 algorithm_velocity.py create mode 100644 setupTapers.py create mode 100644 surface_card.json create mode 100644 valveCheck.py create mode 100644 wellconfigs/BeanRanch341.p create mode 100644 wellconfigs/Casselman16-8.p create mode 100644 wellconfigs/UnivTaylor192UW.p diff --git a/algorithm.py b/algorithm.py new file mode 100644 index 0000000..b3585c5 --- /dev/null +++ b/algorithm.py @@ -0,0 +1,726 @@ +import math +import matplotlib +matplotlib.use("TkAgg") +import matplotlib.pyplot as plt +from collections import deque +import datetime +import time +import csv +import json +import setupTapers + + +print("Be sure that this folder includes setupTapers.py and that you've put a surface card in surface_card.json.") +ready = str(raw_input("Are you ready to start? (y/n): ")).lower() +if not (ready == 'y'): + raise Exception("Not ready to start!") + +well_setup = setupTapers.get_setup() + +surface = [] +with open('surface_card.json') as sc: + surface = json.loads(sc.read()) + +load_before = 0.0 +load_after = 0.0 +load_before_3 = 0.0 +load_after_3 = 0.0 + +blank_array = [0.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, 0.0] +pr_p = [0.0, 0.0] +pmp_p = [0.0, 0.0] +pmp_l = [0.0, 0.0] + +count = [0] * (well_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.well_setup = 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") + self.riemann_slices = 100 + + def set_strokes_per_minute(self, strokes_per_minute): + self.strokes_per_minute = strokes_per_minute + + 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 distance_to_line(self, x0, y0): + """ Finds the perpendicular distance from a point to the line between max and min points""" + x1 = self.downhole_min_position[0] + x2 = self.downhole_max_position[0] + y1 = self.downhole_min_load[1] + y2 = self.downhole_max_load[1] + + d = abs((y2-y1)*x0 - (x2-x1)*y0 + x2*y1 - y2*x1) / math.sqrt(math.pow(y2-y1, 2) + math.pow(x2-x1, 2)) + return d + + def find_corners(self, sl=100): + self.find_limits() + + def lineresolve(x1, x2, y1, y2, targ): + m = ((y2 - y1) / (x2 - x1)) + b = y1 - m * x1 + return(m * targ + b) + + slices = int(sl) + num_points = len(self.downhole_pos) + dh_pos = self.downhole_pos + dh_lod = self.downhole_load + delta_p = (self.downhole_max_position[0] - self.downhole_min_position[0]) / float(slices) + position_targets = [] + for i in range(0, slices): + position_targets.append(self.downhole_min_position[0] + i * delta_p) + + self.top_slices = [] + last_pos_index = 0 + for i in range(0, slices): + targ = position_targets[i] + for j in range(last_pos_index, num_points - 1): + if (dh_pos[j] <= targ and dh_pos[j+1] > targ): + found_i = j + next_i = j+1 + fake_load = lineresolve(dh_pos[found_i], dh_pos[next_i], dh_lod[found_i], dh_lod[next_i], targ) + self.top_slices.append((targ, fake_load)) + last_pos_index = found_i + break + + self.bot_slices = [] + last_pos_index = 0 + for i in range(0, slices): + targ = position_targets[i] + for j in range(0, num_points - 1): + if (dh_pos[j] > targ and dh_pos[j+1] <= targ): + found_i = j + next_i = j+1 + fake_load = lineresolve(dh_pos[found_i], dh_pos[next_i], dh_lod[found_i], dh_lod[next_i], targ) + self.bot_slices.append((targ, fake_load)) + break + + top_d = [] + bot_d = [] + + # Here's where we get the distance from each point to the line + for i in range(1, slices): + try: + top_d.append(self.distance_to_line(self.top_slices[i][0], self.top_slices[i][1])) + except Exception as e: + print e + print("Error - top_d, index: {0}".format(i)) + + try: + bot_d.append(self.distance_to_line(self.bot_slices[i][0], self.bot_slices[i][1])) + except Exception: + print("Error - bot_d, index: {0}".format(i)) + + top_cor_i = top_d.index(max(top_d)) + bot_cor_i = bot_d.index(max(bot_d)) + self.corner_top_left = self.top_slices[top_cor_i] + self.corner_fillage = self.bot_slices[bot_cor_i] + self.corner_top_right = self.downhole_max_position + self.corner_bottom_left = self.downhole_min_position + + def print_corners(self): + if self.corner_fillage: + self.find_corners(100) + print("Bottom Left:", self.corner_bottom_left) + print("Top Left:", self.corner_top_left) + print("Top Right:", self.corner_top_right) + print("Fill Point:", self.corner_fillage) + + def calc_fillage(self): + if not ('self.corner_fillage' in locals()): + self.find_corners(100) + self.downhole_gross_stroke = self.downhole_max_position[0] - self.downhole_min_position[0] + + self.tubing_movement = 12 * (tapers.rod_depth_total - self.well_setup['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_and_analyze(self): + self.polished_rod_horsepower = 0 + self.pump_horsepower = 0 + if not self.surface_stroke_length: + self.find_limits() + if not self.downhole_net_stroke: + self.calc_fillage() + + dx_surface = self.surface_stroke_length / (self.riemann_slices + 1) + dx_downhole = self.downhole_net_stroke / (self.riemann_slices + 1) + + for i in range(1, self.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) + + top_slices.push(slice_downhole[1]) + bottom_slices.push(slice_downhole[2]) + + self.polished_rod_horsepower += (dx_surface / 12) * slice_surface[0] * self.strokes_per_minute / 33000 + self.pump_horsepower += (dx_downhole / 12) * slice_downhole[0] * self.strokes_per_minute / 33000 + + # CARD ANALYSIS / $$$ MAKER + + def prepare_points(analysis_slices): + if (analysis_slices > (self.riemann_slices * 0.50)): + return 911 + + top_left_average = 0 + top_right_average = 0 + top_mid_average = 0 + bot_left_average = 0 + bot_right_average = 0 + bot_mid_average = 0 + pct_slices = (analysis_slices / self.riemann_slices) * 100 + + first_x_pct_end = math.floor(self.riemann_slices*pct_slices) + x_pct_ct = math.floor(self.riemann_slices*pct_slices) + last_x_pct_start = self.riemann_slices - math.floor(self.riemann_slices * pct_slices) + num_btw_slices = self.riemann_slices - (3 * x_pct_ct) # number of slices between the measurements used for top/bottom average and the mid point average + + # Find average of leftmost Points + for la_i in range(0, first_x_pct_end): + top_left_average += self.top_slices[la_i] * (1/x_pct_ct) + bot_left_average += self.bottom_slices[la_i] * (1/x_pct_ct) + # Find average of rightmost points + for ra_i in range(last_x_pct_start, self.riemann_slices): + top_right_average += self.top_slices[ra_i] * (1/x_pct_ct) + bot_right_average += self.bottom_slices[ra_i] * (1/x_pct_ct) + # Find average of middle points + for ma_i in range(math.floor((self.riemann_slices/2) - self.riemann_slices * (pct_corners / 2)), math.floor((self.riemann_slices / 2) + self.riemann_slices * (pct_corners / 2))): + top_mid_average += self.top_slices[ma_i] * (1/x_pct_ct) + bot_mid_average += self.bottom_slices[ma_i] * (1/x_pct_ct) + + 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.well_setup['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_and_analyze(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.well_setup['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') + + 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.0 + self.rod_weight_in_fluid_total = 0.0 + self.rod_weight_in_air_total = 0.0 + self.weight_data_total = 0.0 + self.rod_depth_total = 0.0 + self.annular_force_data_total = 0.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.0) + self.pressure.append(0.0) + self.buoyant_force.append(0.0) + self.rod_weight_in_air.append(0.0) + self.rod_depth.append(0.0) + self.rod_weight_in_fluid.append(0.0) + self.weight_data.append(0.0) + self.annular_force_data.append(0.0) + self.a.append(0.0) + self.stretch.append(0.0) + self.force.append(0.0) + self.alpha.append(0.0) + self.x_over_a.append(0.0) + self.factor_array.append(0.0) + self.lag_index_array.append(0.0) + self.center_point.append(0.0) + self.sum_center_point.append(0.0) + self.length_required.append(0.0) + + for area_i in range(1, self.params['num_tapers']+1): + self.area[area_i] = (math.pi / 4.0) * (self.params['rod_diameter_data'][area_i] ** 2.0) + + for i in range(1, self.params['num_tapers']+1): + self.a[i] = 1000.0 * (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.0 + load_after = 0.0 + load_before_3 = 0.0 + load_after_3 = 0.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.0 + pump_pos = math.exp((cd * rod_length) / (2.0 * 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.0 * 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.0 + q = 1 + while(q < 2 * lag_index - 1): + inside_integral = inside_integral + dt * (1.0 / (Y1 * A1)) * (math.exp(-(cd * (lag_index - q) * dt) / 2.0) * top_load_array[p][i_before + q]) + q += 1 + inside_integral = inside_integral + (0.5) * dt * (1.0 / (Y1 * A1)) * (math.exp(-(cd * lag_index * dt) / 2.0) * top_load_array[p][i_before] + math.exp(- (cd * (-lag_index) * dt) / 2.0) * top_load_array[p][i_after]) + + load_before = math.exp(-(cd * lag_index * dt) / 2.0) * top_load_array[p][i_before] + factor * (math.exp(-(cd * (lag_index + 1.0) * dt) / 2.0) * top_load_array[p][i_before - 1] - math.exp(-(cd * (lag_index) * dt) / 2.0) * top_load_array[p][i_before]) + load_after = math.exp(-(cd * (-lag_index) * dt) / 2.0) * top_load_array[p][i_after] + factor * (math.exp(-(cd * (-lag_index - 1.0) * dt) / 2.0) * top_load_array[p][i_after + 1] - math.exp(-(cd * (-lag_index) * dt) / 2.0) * top_load_array[p][i_after]) + inside_integral = inside_integral + 0.5 * factor * dt * (1.0 / (Y1 * A1)) * (load_before + math.exp(-(cd * (lag_index) * dt) / 2.0) * top_load_array[p][i_before]) + inside_integral = inside_integral + 0.5 * factor * dt * (1.0 / (Y1 * A1)) * (load_after + math.exp(-(cd * (-lag_index) * dt) / 2.0) * top_load_array[p][i_after]) + inside_integral = (0.5) * a1 * inside_integral + pump_pos = pump_pos + inside_integral + inside_integral = 0.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 + (0.5) * dt * (math.exp(-(cd * lag_index * dt) / 2.0) * top_pos_array[p][i_before] + math.exp(-(cd * (-lag_index) * dt)/2.0) * top_pos_array[p][i_after]) + + load_before_3 = math.exp(-(cd * (lag_index) * dt) / 2.0) * top_pos_array[p][i_before] + factor * (math.exp(-(cd * (lag_index + 1) * dt) / 2.0) * top_pos_array[p][i_before - 1] - math.exp(-(cd * (lag_index) * dt) / 2.0) * top_pos_array[p][i_before]) + + load_after_3 = math.exp(-(cd * (-lag_index) * dt) / 2.0) * top_pos_array[p][i_after] + factor * (math.exp(-(cd * (-lag_index - 1.0) * dt) / 2.0) * top_pos_array[p][i_after + 1] - math.exp(-(cd * (-lag_index) * dt) / 2.0) * top_pos_array[p][i_after]) + inside_integral = inside_integral + (0.5) * factor * dt * (load_before_3 + math.exp(-(cd * (lag_index) * dt) / 2.0) * top_pos_array[p][i_before]) + inside_integral = inside_integral + (0.5) * factor * dt * (load_after_3 + math.exp(-(cd * (-lag_index) * dt) / 2.0) * top_pos_array[p][i_after]) + inside_integral = -((cd * rod_length) / 4.0) * ((0.5) * (cd / (2.0 * 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] + 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.0**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.0 + pump_load = (0.5) * (a1 / (Y1*A1)) * (1.0 / a1) * (load_before + load_after) + pump_load = pump_load - ((cd * rod_length) / 4.0) * ((0.5) * (cd / (2.0 * a1))) * (1.0 / a1) * (load_before_3 + load_after_3) + + first_part = 0.0 + + point_after = (top_pos_array[s][i_after+1] - top_pos_array[s][i_after - 1]) / (2.0 * dt) + point_before = (top_pos_array[s][i_before+1] - top_pos_array[s][i_before - 1]) / (2.0 * dt) + first_part = (math.exp((cd*rod_length)/(2.0*a1)) * point_after - math.exp(-(cd*rod_length)/(2*a1)) * point_before) / (2.0 * a1) + first_part = first_part + (cd * math.exp((cd*rod_length)/(2.0*a1))*top_pos_array[s][i_after] - cd * math.exp((-cd*rod_length)/(2*a1))*top_pos_array[s][i_before]) / (4.0 * 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.0) + + 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(well_setup) + + +if __name__ == '__main__': + + 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) + print(current) + 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, well_setup) + last_card.set_strokes_per_minute((1 / stroke_time_delta) * 60.0) + last_card.calc_fillage() + last_card.print_corners() + # last_card.calc_hp_and_analyze(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(2) + +# pprint(vars(last_card)) diff --git a/algorithm_velocity.py b/algorithm_velocity.py new file mode 100644 index 0000000..4810a66 --- /dev/null +++ b/algorithm_velocity.py @@ -0,0 +1,713 @@ +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)) diff --git a/setupTapers.py b/setupTapers.py new file mode 100644 index 0000000..49e0af1 --- /dev/null +++ b/setupTapers.py @@ -0,0 +1,183 @@ +import pickle +import math +import traceback +from os import listdir +from os.path import isfile, join +import Tkinter + + +wt_per_foot = { + 'steel': { + # diameter: lbs/ft + 2.000: 10.70, + 1.750: 8.200, + 1.650: 7.000, + 1.500: 6.000, + 1.375: 5.000, + 1.250: 4.172, + 1.125: 3.676, + 1.000: 2.904, + 0.875: 2.224, + 0.750: 1.634, + 0.625: 1.130, + 0.500: 0.720 + }, + 'fiberglass': { + # diameter: lbs/ft + 1.250: 1.2879, + 1.125: 1.0900, + 1.000: 0.8188, + 0.875: 0.6108, + 0.750: 0.4840 + } +} + +youngs_modulus = { + 'steel': 30.5, + 'fiberglass': 7.2 +} + +configfile = "" + + +def get_setup(): + global youngs_modulus, wt_per_ft, configfile + well_setup = {} + create_new = True + pickled_configs = filter(lambda x: x[-2:] == ".p", [f for f in listdir('wellconfigs') if isfile(join('wellconfigs', f))]) + if len(pickled_configs) > 0: + pickled_configs.append("...New file") + + master = Tkinter.Tk() + var = Tkinter.StringVar(master) + var.set(pickled_configs[0]) # initial value + + w = apply(Tkinter.OptionMenu, (master, var) + tuple(pickled_configs)) + w.pack() + + def ok(): + global configfile + configfile = var.get() + master.quit() + master.destroy() + + button = Tkinter.Button(master, text="OK", command=ok) + button.pack() + Tkinter.mainloop() + fpath = 'wellconfigs/' + configfile + print(fpath) + if isfile(fpath): + with open(fpath, 'rb') as well_config_file: + well_setup = pickle.load(well_config_file) + reuse = str(raw_input("Do you want to use the last settings for {}? (y/n): ".format(well_setup['well_name']))).lower() + create_new = (reuse == 'n') + try: + if create_new: + well_setup = {} + well_setup['c'] = [0.0] + well_setup['rod_length_data'] = [0.0] + well_setup['rod_diameter_data'] = [0.0] + well_setup['rod_material'] = [''] + well_setup['rod_youngs_modulus_data'] = [0.0] + well_setup['rod_weight_data'] = [0.0] + + ask_num_tapers = int(raw_input("How many tapers to configure (1-10): ")) + if (ask_num_tapers > 0) and (ask_num_tapers <= 10): + well_setup['num_tapers'] = ask_num_tapers + for i in range(1, ask_num_tapers + 1): + print("================") + print("== TAPER {} ==".format(i)) + print("================") + ask_length = float(raw_input("Enter Taper Length in feet: ")) + if ask_length > 0.0: + well_setup['rod_length_data'].append(ask_length) + else: + raise Exception("Invalid length {} for taper {}".format(ask_length, i)) + + ask_diameter = float(raw_input("Enter Rod Diameter in inches: ")) + if ask_diameter > 0.0: + well_setup['rod_diameter_data'].append(ask_diameter) + else: + raise Exception("Invalid diameter {} for taper {}".format(ask_diameter, i)) + + ask_material = str(raw_input("Enter material type (steel or fiberglass): ")).lower() + if (ask_material == 'fiberglass') or (ask_material == 'steel'): + well_setup['rod_material'].append(ask_material) + else: + raise Exception("Invalid material {} for taper {}".format(ask_material, i)) + + ask_c = float(raw_input("Enter Damping Factor(0.0 - 1.0): ")) + if (ask_c >= 0.0) and (ask_c <= 1.0): + well_setup['c'].append(ask_c) + else: + raise Exception("Invalid Daming Factor {} for taper {}".format(ask_c, i)) + + for j in range(1, ask_num_tapers + 1): + well_setup['rod_youngs_modulus_data'].append(youngs_modulus[well_setup['rod_material'][j]]) + well_setup['rod_weight_data'].append(wt_per_foot[well_setup['rod_material'][i]][well_setup['rod_diameter_data'][j]]) + + ask_thp = float(raw_input("Enter Tubing Head Pressure in PSI: ")) + if ask_length > 0.0: + well_setup['tubing_head_pressure'] = ask_thp + else: + raise Exception("Invalid Tubing Head Pressure: {} PSI".format(ask_length)) + + ask_fluid_gradient = float(raw_input("Enter Fluid Gradient in PSI/ft: ")) + if ask_fluid_gradient > 0.0: + well_setup['fluid_gradient'] = ask_fluid_gradient + else: + raise Exception("Invalid Fluid Gradient: {} PSI/ft".format(ask_fluid_gradient)) + + ask_sbf = float(raw_input("Enter Stuffing Box Friction in lbs: ")) + if ask_sbf > 0.0: + well_setup['stuffing_box_friction'] = ask_sbf + else: + raise Exception("Invalid Stuffing Box Friction: {} PSI/ft".format(ask_sbf)) + + ask_dt = float(raw_input("Enter delta t in seconds: ")) + if ask_dt > 0.0: + well_setup['dt'] = ask_dt + else: + raise Exception("Invalid delta t: {} sec".format(ask_dt)) + + ask_tubingID = float(raw_input("Enter Tubing ID in inches: ")) + if ask_tubingID > 0.0: + well_setup['tubing_id'] = ask_tubingID + else: + raise Exception("Invalid Tubing ID: {} in".format(ask_tubingID)) + + ask_tubingOD = float(raw_input("Enter Tubing OD in inches: ")) + if ask_tubingOD > 0.0: + well_setup['tubing_od'] = ask_tubingOD + else: + raise Exception("Invalid Tubing OD: {} in".format(ask_tubingOD)) + + ask_TAC = float(raw_input("Enter Tubing Anchor Depth in feet: ")) + if ask_TAC > 0.0: + well_setup['anchor_depth'] = ask_TAC + else: + raise Exception("Invalid Tubing Anchor Depth: {} ft".format(ask_TAC)) + + ask_pump_diameter = float(raw_input("Enter Pump Diameter in inches: ")) + if ask_pump_diameter > 0.0: + well_setup['pump_diameter'] = ask_pump_diameter + well_setup['pump_area'] = (well_setup['pump_diameter']**2) * math.pi + else: + raise Exception("Invalid Pump Diameter: {} in".format(ask_pump_diameter)) + + well_setup['well_name'] = str(raw_input("Enter Well Name: ")) + + else: + raise Exception("Invalid taper count") + + with open('wellconfigs/' + well_setup['well_name'].replace(" ", "") + '.p', 'wb') as well_config_file: + pickle.dump(well_setup, well_config_file) + return well_setup + + except Exception as e: + traceback.print_exc() + print e + return False + +if __name__ == '__main__': + get_setup() diff --git a/surface_card.json b/surface_card.json new file mode 100644 index 0000000..e12dc2f --- /dev/null +++ b/surface_card.json @@ -0,0 +1 @@ +[[96.237, 20163.0], [94.954, 20122.0], [94.215, 20086.0], [93.467, 20040.0], [92.578, 19987.0], [91.832, 19929.0], [90.908, 19868.0], [90.09, 19805.0], [89.145, 19740.0], [88.213, 19672.0], [87.382, 19601.0], [86.51, 19529.0], [85.792, 19456.0], [84.804, 19397.0], [83.954, 19319.0], [83.058, 19257.0], [82.07, 19195.0], [81.111, 19131.0], [79.967, 19060.0], [79.024, 18980.0], [77.832, 18890.0], [76.766, 18794.0], [75.661, 18694.0], [74.537, 18591.0], [73.411, 18486.0], [72.068, 18378.0], [71.038, 18264.0], [69.634, 18165.0], [68.349, 18017.0], [67.026, 17881.0], [65.708, 17739.0], [64.413, 17595.0], [62.947, 17451.0], [61.692, 17311.0], [60.056, 17175.0], [58.662, 17042.0], [57.076, 16913.0], [55.551, 16786.0], [54.007, 16659.0], [52.492, 16532.0], [51.015, 16403.0], [49.304, 16272.0], [47.644, 16136.0], [45.928, 15992.0], [44.357, 15837.0], [42.736, 15673.0], [41.048, 15504.0], [39.504, 15334.001], [37.731, 15169.999], [36.265, 15014.001], [34.355, 14872.0], [32.688, 14751.0], [30.962, 14671.0], [29.251, 14598.001], [27.666, 14571.0], [25.791, 14574.001], [24.382, 14599.0], [22.643, 14640.0], [21.078, 14691.0], [19.57, 14749.0], [18.089, 14811.0], [16.729, 14865.0], [15.135, 14945.999], [13.937, 15019.0], [12.542, 15097.999], [11.404, 15183.0], [10.212, 15277.0], [9.119, 15380.0], [8.12, 15489.999], [7.121, 15607.0], [6.288, 15728.0], [5.4, 15849.999], [4.654, 15971.0], [3.961, 16068.0], [3.343, 16192.0], [2.838, 16284.0], [2.415, 16347.0], [2.09, 16413.0], [1.846, 16450.0], [1.672, 16469.0], [1.537, 16481.0], [1.441, 16483.0], [1.381, 16481.0], [1.488, 16476.0], [1.612, 16473.0], [1.835, 16469.0], [2.102, 16467.0], [2.512, 16462.0], [2.883, 16458.0], [3.315, 16453.0], [3.808, 16446.0], [4.316, 16438.0], [4.973, 16433.0], [5.54, 16433.0], [6.391, 16440.0], [7.156, 16468.0], [8.009, 16503.0], [8.931, 16575.0], [9.897, 16639.0], [11.031, 16738.0], [11.944, 16811.0], [13.171, 16908.0], [14.28, 16972.0], [15.421, 17044.0], [16.721, 17125.0], [17.889, 17192.0], [19.22, 17248.0], [20.432, 17315.0], [21.853, 17392.0], [23.192, 17446.0], [24.544, 17521.0], [26.013, 17585.0], [27.328, 17650.0], [28.995, 17718.0], [30.292, 17778.0], [31.928, 17857.0], [33.342, 17944.0], [34.936, 18059.0], [36.643, 18171.0], [38.108, 18273.0], [39.958, 18430.0], [41.311, 18553.0], [43.084, 18707.0], [44.599, 18892.0], [46.3, 19047.0], [47.912, 19169.0], [49.415, 19304.0], [51.044, 19447.0], [52.523, 19559.0], [54.304, 19647.0], [55.622, 19766.0], [57.414, 19850.0], [58.858, 19949.0], [60.449, 20047.0], [62.086, 20160.0], [63.562, 20241.0], [65.164, 20356.0], [66.461, 20456.0], [68.089, 20540.0], [69.502, 20645.0], [71.015, 20769.0], [72.48, 20875.0], [73.887, 20977.0], [75.417, 21053.0], [76.705, 21138.0], [78.147, 21178.0], [79.382, 21201.0], [80.704, 21200.0], [81.955, 21178.0], [83.116, 21142.0], [84.558, 21099.0], [85.614, 21052.0], [86.767, 20994.0], [87.773, 20953.0], [88.818, 20903.0], [89.783, 20846.0], [90.683, 20804.0], [91.642, 20745.0], [92.435, 20701.0], [93.347, 20646.0], [94.051, 20589.0], [94.778, 20530.0], [95.418, 20468.0], [96.068, 20394.0], [96.684, 20339.0], [97.189, 20274.0], [97.729, 20215.0], [98.187, 20165.0], [98.624, 20131.0], [98.97, 20114.0], [99.232, 20116.0], [99.499, 20128.0], [99.718, 20150.0], [99.816, 20177.0], [99.889, 20205.0], [99.907, 20234.0], [99.856, 20250.0], [99.682, 20260.0], [99.481, 20260.0], [99.27, 20250.0], [98.926, 20234.0], [98.616, 20216.0], [98.117, 20200.0], [97.676, 20189.0], [97.143, 20184.0], [96.531, 20181.0], [95.914, 20178.0], [96.237, 20163.0], [96.237, 20163.0]] diff --git a/valveCheck.py b/valveCheck.py new file mode 100644 index 0000000..8efa2d2 --- /dev/null +++ b/valveCheck.py @@ -0,0 +1,49 @@ +#!/usr/bin/python + +from pycomm.ab_comm.clx import Driver as ClxDriver +c = ClxDriver(True, 'ClxDriver.log') +PLC_IP_ADDRESS = "192.168.1.10" + +class PLCException(Exception): + pass + +upstroke_target_percent = [20.0, 50.0, 75.0] +downstroke_target_percent = [50.0] + +if c.open(PLC_IP_ADDRESS): + # check that well is stopped + pump_run_status = c.read_tag(['Pump.Run'])[0][1] + if pump_run_status == 1: + raise PLCException("Cannot run the valve check while the pump is running. Stop the pump and try again.") + + # Set up position targets + stroke_length = float(c.read_tag(['UnitConfig.Total_Stroke_Length'])[0][1]) + upstroke_target = map(lamba x: (x/100.0) * stroke_length, upstroke_target_percent) + downstroke_target = map(lamba x: (x/100.0) * stroke_length, downstroke_target_percent) + + # Store motor parameters + prev_motor_mode = map(lambda x: {'value':x[1], 'type':x[2]},c.read_tag(['UnitConfig.Speed_Torque_Mode'])[0])[0] + + # Ensure drive in speed mode + if prev_motor_mode['value'] != 1: + c.write_tag('Card_Past[1].Data_Read', 1, 'REAL') + + # Loop through upstroke position targets + + + # jog past 0 to within 3 inches of the target position + + # let pid take over to hold at target + + # once at target, start timer and store surface and downhole load and position + + # For downstroke position target + # jog past 0 to within 3 inches of the target position + + # let pid take over to hold at target + + # once at target, start timer and store surface and downhole load and position + + # re-write motor parameters + + # do calculations diff --git a/wellconfigs/BeanRanch341.p b/wellconfigs/BeanRanch341.p new file mode 100644 index 0000000..6dc2d98 --- /dev/null +++ b/wellconfigs/BeanRanch341.p @@ -0,0 +1,82 @@ +(dp0 +S'tubing_id' +p1 +F2.441 +sS'c' +p2 +(lp3 +F0.0 +aF0.08 +aF0.08 +aF0.08 +asS'rod_diameter_data' +p4 +(lp5 +F0.0 +aF1.25 +aF1.0 +aF1.5 +asS'num_tapers' +p6 +I3 +sS'rod_material' +p7 +(lp8 +S'' +p9 +aS'fiberglass' +p10 +aS'steel' +p11 +aS'steel' +p12 +asS'rod_youngs_modulus_data' +p13 +(lp14 +F0.0 +aF7.2 +aF30.5 +aF30.5 +asS'anchor_depth' +p15 +F4598.0 +sS'tubing_od' +p16 +F2.875 +sS'dt' +p17 +F0.1 +sS'rod_weight_data' +p18 +(lp19 +F0.0 +aF4.172 +aF2.904 +aF6.0 +asS'pump_area' +p20 +F12.566370614359172 +sS'stuffing_box_friction' +p21 +F100.0 +sS'fluid_gradient' +p22 +F0.45 +sS'rod_length_data' +p23 +(lp24 +F0.0 +aF2700.0 +aF1575.0 +aF250.0 +asS'well_name' +p25 +S'Bean Ranch 341' +p26 +sS'tubing_head_pressure' +p27 +F50.0 +sS'pump_diameter' +p28 +F2.0 +s. \ No newline at end of file diff --git a/wellconfigs/Casselman16-8.p b/wellconfigs/Casselman16-8.p new file mode 100644 index 0000000..63ef08e --- /dev/null +++ b/wellconfigs/Casselman16-8.p @@ -0,0 +1,75 @@ +(dp0 +S'tubing_id' +p1 +F1.995 +sS'c' +p2 +(lp3 +F0.0 +aF0.08 +aF0.08 +asS'rod_diameter_data' +p4 +(lp5 +F0.0 +aF0.75 +aF1.5 +asS'num_tapers' +p6 +I2 +sS'rod_material' +p7 +(lp8 +S'' +p9 +aS'steel' +p10 +aS'steel' +p11 +asS'rod_youngs_modulus_data' +p12 +(lp13 +F0.0 +aF30.5 +aF30.5 +asS'anchor_depth' +p14 +F8923.0 +sS'tubing_od' +p15 +F2.375 +sS'dt' +p16 +F0.06 +sS'rod_weight_data' +p17 +(lp18 +F0.0 +aF1.634 +aF6.0 +asS'pump_area' +p19 +F4.908738521234052 +sS'stuffing_box_friction' +p20 +F100.0 +sS'fluid_gradient' +p21 +F0.45 +sS'rod_length_data' +p22 +(lp23 +F0.0 +aF10095.0 +aF300.0 +asS'well_name' +p24 +S'Casselman 16-8' +p25 +sS'tubing_head_pressure' +p26 +F150.0 +sS'pump_diameter' +p27 +F1.25 +s. \ No newline at end of file diff --git a/wellconfigs/UnivTaylor192UW.p b/wellconfigs/UnivTaylor192UW.p new file mode 100644 index 0000000..a271258 --- /dev/null +++ b/wellconfigs/UnivTaylor192UW.p @@ -0,0 +1,82 @@ +(dp0 +S'tubing_id' +p1 +F2.441 +sS'c' +p2 +(lp3 +F0.0 +aF0.08 +aF0.08 +aF0.08 +asS'rod_diameter_data' +p4 +(lp5 +F0.0 +aF1.0 +aF0.75 +aF1.5 +asS'num_tapers' +p6 +I3 +sS'rod_material' +p7 +(lp8 +S'' +p9 +aS'fiberglass' +p10 +aS'steel' +p11 +aS'steel' +p12 +asS'rod_youngs_modulus_data' +p13 +(lp14 +F0.0 +aF7.2 +aF30.5 +aF30.5 +asS'anchor_depth' +p15 +F4598.0 +sS'tubing_od' +p16 +F2.875 +sS'dt' +p17 +F0.06 +sS'rod_weight_data' +p18 +(lp19 +F0.0 +aF2.904 +aF1.634 +aF6.0 +asS'pump_area' +p20 +F12.566370614359172 +sS'stuffing_box_friction' +p21 +F100.0 +sS'fluid_gradient' +p22 +F0.45 +sS'rod_length_data' +p23 +(lp24 +F0.0 +aF4435.0 +aF2950.0 +aF250.0 +asS'well_name' +p25 +S'UnivTaylor192UW' +p26 +sS'tubing_head_pressure' +p27 +F50.0 +sS'pump_diameter' +p28 +F2.0 +s. \ No newline at end of file