Source code for pwptemp.main

from .inputs import inputs_dict
from .well_system import set_well
from .linearsystem import calc_temperature_distribution
from .plot import plot_behavior
from scipy.interpolate import make_interp_spline
import numpy as np
import scipy.signal
import well_profile as wp


[docs]def calc_temp(trajectory, casings=None, set_inputs=None, operation='drilling', time_steps=210, smooth=True, cells_no=None): """ Function to calculate the well temperature distribution during a specific operation at a certain time. Arguments: trajectory: wellbore trajectory excel|csv|dataframe|list casings: list of dictionaries with casings characteristics (od, id and depth) set_inputs: dictionary with parameters to set. operation: define operation type. ('drilling', 'circulating') time_steps: number of time steps to run calculations. smooth: smooth the temperature profiles. cells_no: (int) number of cells. If None -> keep same number of cells than trajectory Returns: Well temperature distribution object """ tdata = inputs_dict(casings) if set_inputs is not None: for x in set_inputs: # changing default values if x in tdata: tdata[x] = set_inputs[x] else: raise TypeError('%s is not a parameter' % x) if cells_no is not None: survey = wp.load(trajectory, points=cells_no).trajectory else: survey = wp.load(trajectory, equidistant=False).trajectory md_initial = tdata['water_depth'] md_final = survey[-1]['md'] well = set_well(tdata, survey, operation) time = [] rop_steps = [] depths = sorted([x[2] for x in well.casings]) if operation == 'drilling': prev_point = md_initial cummulative_time = [] for x in range(len(depths)): distance = depths[x] - prev_point time_section = distance / well.rop_list[x] time.append(time_section) cummulative_time.append(sum(time)) prev_point = depths[x] time.append((md_final - prev_point) / well.rop_list[-1]) cummulative_time.append(sum(time)) depths = list(depths) + [md_final] if depths[0] == 0: depths = depths[1:] time = time[1:] cummulative_time = cummulative_time[1:] tcirc = sum(time) * 3600 # drilling time, s for x in cummulative_time: rop_steps.append(round(x * 3600 / tcirc / time_steps)) else: tcirc = tdata['time'] * 3600 # circulating time, s time_step = tcirc / time_steps # seconds per time step log_temp_values(well, initial=True) # log initial temperature distribution well.delta_time = time_step time_n = time_step well.op = operation td = len(well.trajectory)-1 for x in range(time_steps): if well.op == 'drilling': d = depths[0] rop = well.rop_list[0] t = time[0] * 3600 for y in range(len(time)): if time_n < sum(time[:y+1])*3600: d = depths[y] if len(well.rop_list) > 1: rop = well.rop_list[y] t = sum(time[:y+1])*3600 break bit_depth = d - rop/3600 * (t - time_n) bit_position = [cell for cell, point in enumerate(well.trajectory) if point['md'] <= bit_depth][-1] td = bit_position if time_steps > 1: if td > 0: well = calc_temperature_distribution(well, time_step, td) well = define_temperatures(well, td) log_temp_values(well, time_n) if well.op == 'drilling': if x in range(len(rop_steps)): well.temperatures['in_pipe'] = well.temp_fm well.temperatures['pipe'] = well.temp_fm well.temperatures['annulus'] = well.temp_fm well.temperatures['casing'] = well.temp_fm well.temperatures['riser'] = well.temp_fm well.temperatures['sr'] = well.temp_fm for i in well.sections: for j in range(len(well.trajectory)): i[j]['temp'] = well.temp_fm[j] i[j]['temp_fm'] = well.temp_fm[j] well.time = time_n / 3600 time_n += time_step if smooth: smooth_results(well) additional_points(well) return well
def define_temperatures(well, bit_position): """ Make the temperature values more reachable since they are is a dictionary along the entire well. Once this function takes place, the temperatures will be available as lists. :return: a dictionary with lists of temperature values and also a list with respective depth points. """ temp_in_pipe = [x['temp'] for x in well.sections[0][:bit_position+1]] + \ [None] * (len(well.trajectory) - (bit_position + 1)) temp_pipe = [x['temp'] for x in well.sections[1][:bit_position+1]] + \ [None] * (len(well.trajectory) - (bit_position + 1)) temp_annulus = [x['temp'] for x in well.sections[2][:bit_position+1]] + \ [None] * (len(well.trajectory) - (bit_position + 1)) temp_casing = [] temp_riser = [] temp_sr = [x['temp'] for x in well.sections[4]] for y, x in enumerate(well.md): if well.riser_cells > 0 and x < well.water_depth: temp_casing.append(None) temp_riser.append(well.sections[3][y]['temp']) else: temp_riser.append(None) if x <= well.casings[0, 2]: temp_casing.append(well.sections[3][y]['temp']) else: temp_casing.append(None) well.temperatures = {'md': list(well.md), 'formation': well.temp_fm, 'in_pipe': temp_in_pipe, 'pipe': temp_pipe, 'annulus': temp_annulus, 'casing': temp_casing, 'riser': temp_riser, 'sr': temp_sr} return well def log_temp_values(well, time=0.0, initial=False): time = round(time/3600, 2) if initial: well.temp_log = [{'time': time, 'in_pipe': well.temp_fm, 'pipe': well.temp_fm, 'annulus': well.temp_fm, 'casing': well.temp_fm, 'riser': well.temp_fm, 'sr': well.temp_fm}] else: well.temp_log.append( {'time': time, 'in_pipe': [x['temp'] for x in well.sections[0]], 'pipe': [x['temp'] for x in well.sections[1]], 'annulus': well.temperatures['annulus'], 'casing': well.temperatures['casing'], 'riser': well.temperatures['riser'], 'sr': well.temperatures['sr']} )
[docs]def temperature_behavior(well): """ Function to simulate the temperature behavior. Arguments: well (obj): well temperature distribution object Returns: temperature behavior object """ time = [] temp_bottom = [] temp_outlet = [] temp_max = [] temp_fm = [] for x in well.temp_log[1:]: cells = len(well.md) - x['annulus'].count(None) time.append(x['time']) temp_bottom.append(x['in_pipe'][cells-1]) temp_outlet.append(x['annulus'][0]) temp_max.append(max(x['annulus'][:cells-1])) temp_fm.append(well.temp_fm[cells-1]) temp_bottom = list(scipy.signal.savgol_filter(temp_bottom, 59, 3)) temp_max = list(scipy.signal.savgol_filter(temp_max, 59, 3)) temp_outlet = list(scipy.signal.savgol_filter(temp_outlet, 59, 3)) temp_fm = list(scipy.signal.savgol_filter(temp_fm, 59, 3)) class TempBehavior(object): def __init__(self): self.time = time self.bottom = temp_bottom self.outlet = temp_outlet self.max = temp_max self.formation_td = temp_fm def plot(self, title=True): fig = plot_behavior(self, title) return fig return TempBehavior()
def smooth_results(well): well.temperatures['in_pipe'] = list(scipy.signal.savgol_filter(well.temperatures['in_pipe'], 15, 3)) well.temperatures['annulus'] = list(scipy.signal.savgol_filter(well.temperatures['annulus'], 15, 2)) cells = len(well.md) - np.count_nonzero(np.isnan(well.temperatures['annulus'])) ref = int(0.9 * cells - well.time*0.2) t_bottom = np.mean(well.temperatures['annulus'][ref:]) x_new = well.md[ref:] # Smooth annulus interp_ann = make_interp_spline([well.md[ref - 1], well.md[ref], well.md[-1]], [well.temperatures['annulus'][ref - 1], well.temperatures['annulus'][ref], t_bottom], k=2) temp_annulus = interp_ann(x_new) # Smooth in_pipe interp_in_pipe = make_interp_spline(well.md[:ref-2] + [well.md[-1]], well.temperatures['in_pipe'][:ref-2] + [t_bottom], k=2) temp_in_pipe = interp_in_pipe(x_new) well.temperatures['in_pipe'] = well.temperatures['in_pipe'][:ref] + list(temp_in_pipe) well.temperatures['annulus'] = well.temperatures['annulus'][:ref] + list(temp_annulus) def additional_points(well): if well.water_depth > 0: depths = [point['md'] for point in well.trajectory] seabed_point = False for idx, md in enumerate(depths): if idx > 0: if md > well.water_depth and not seabed_point: well.temperatures['md'].insert(idx, well.water_depth) well.temperatures['formation'].insert(idx, np.interp(well.water_depth, [depths[idx - 1], md], [well.temperatures['formation'][idx - 1], well.temperatures['formation'][idx]])) well.temperatures['in_pipe'].insert(idx, np.interp(well.water_depth, [depths[idx - 1], md], [well.temperatures['in_pipe'][idx - 1], well.temperatures['in_pipe'][idx]])) well.temperatures['pipe'].insert(idx, np.interp(well.water_depth, [depths[idx - 1], md], [well.temperatures['pipe'][idx - 1], well.temperatures['pipe'][idx]])) well.temperatures['annulus'].insert(idx, np.interp(well.water_depth, [depths[idx - 1], md], [well.temperatures['annulus'][idx - 1], well.temperatures['annulus'][idx]])) well.temperatures['riser'].insert(idx, well.temperatures['riser'][idx - 1]) well.temperatures['casing'].insert(idx, well.temperatures['casing'][idx]) well.temperatures['sr'].insert(idx, np.interp(well.water_depth, [depths[idx - 1], md], [well.temperatures['sr'][idx - 1], well.temperatures['sr'][idx]])) seabed_point = True reference = well.casings[0][2] if md > reference != 0: well.temperatures['md'].insert(idx + 1, reference) well.temperatures['formation'].insert(idx + 1, np.interp(reference, [depths[idx - 1], md], [well.temperatures['formation'][idx], well.temperatures['formation'][idx + 1]])) well.temperatures['in_pipe'].insert(idx + 1, np.interp(reference, [depths[idx - 1], md], [well.temperatures['in_pipe'][idx], well.temperatures['in_pipe'][idx + 1]])) well.temperatures['pipe'].insert(idx + 1, np.interp(reference, [depths[idx - 1], md], [well.temperatures['pipe'][idx], well.temperatures['pipe'][idx + 1]])) well.temperatures['annulus'].insert(idx + 1, np.interp(reference, [depths[idx - 1], md], [well.temperatures['annulus'][idx], well.temperatures['annulus'][idx + 1]])) well.temperatures['riser'].insert(idx + 1, None) well.temperatures['casing'].insert(idx + 1, well.temperatures['casing'][idx]) well.temperatures['sr'].insert(idx, np.interp(reference, [depths[idx - 1], md], [well.temperatures['sr'][idx], well.temperatures['sr'][idx + 1]])) break