Wellpathpy tutorial¶
This document aims to provide a sample workthrough using wellpathpy showing:
- Abbreviations
- Imports
- Loading a deviation
- Loading the well header
- Converting deviation surveys to positional logs
- Well location and tvdss
- Exporting results
Abbreviations¶
m | metres |
ft | feet |
md | measured depth |
inc | inclination |
azi | azimuth |
tvd | true vertical depth |
east_offset | horizontal distance away from wellhead towards the east |
north_offset | horizontal distance away from wellhead towards the north |
tvdss | true vertical depth subsea |
mE | horizontal distance in meters away from surface location towards the east |
mN | horizontal distance in meters away from surface location towards the north |
Loading a deviation¶
Wellpathpy provides a fairly simple loading function for reading a deviation survey from CSV.
Loading a deviation from CSV¶
A valid input file must be a CSV file containing the columns: md, inc, azi in that order, as shown in this example:
md,inc,azi
0,0,244
10,11,220
50,43,254
150,78.5,254
252.5,90,359.9
- column headers are generally expected but will be skipped when the file is read
- if no headers are provided, the
skiprows
argument can be set to0
- md must increase monotonically
- as inc and azi cannot be distinguished numerically it is the user’s responsibility to ensure the data are passed in this order
- inc must be in range 0 <= inc < 180 (to allow for horizontal wells to climb)
- azi must be in range 0 <= azi < 360
You can then load them into wellpathpy using:
md, inc, azi = wp.read_csv(fname)
wp.read_csv
simply calls np.loadtxt
with delimiter=','
and skiprows=1
.
These can be changed if required; for example the delimiter
and skiprows
can be changed with:
md, inc, azi = wp.read_csv(fname, delimiter='\t', skiprows=0)
Additional kwargs
accepted by np.loadtxt
can also be passed in, for example:
md, inc, azi = wp.read_csv(fname, comments='$')
Notes:
Some simple sanity checks are performed to reject bad CSVs. wp.read_csv
supports all options np.loadtxt
supports. Only those columns named md, inc, azi will be read.
If the deviation survey is not in CSV, is generated in a different place in your
program, or is from some other source, wellpathpy is still useful. If you
provide three np.ndarray
md, inc, and azi, the rest of wellpathpy works fine.
Observe that the same basic requirements still apply:
- md, inc and azi have the same shape
- md increases monotonically
- inc is in range 0-180
- azi is in range 0-360
Once md
, inc
and azi
have been returned from wp.read_csv()
, an instance of
the wp.deviation()
class is created with:
dev = wp.deviation(
md = md,
inc = inc,
azi = azi
)
- With this, it is then possible to resample the depths using the
minimum_curvature()
method - and go back to a deviation survey in
md
,inc
andazi
:
step = 30
depths = list(range(0, int(dev.md[-1]) + 1, step))
pos = dev.minimum_curvature().resample(depths = depths)
dev2 = pos.deviation()
Notes:
With increasing step size, float uncertainty can introduce some noise as shown in the figures below. First we see an overview of the well in 3D, followed by plots of inclination and azimuth versus depth.
Loading the well header¶
To make sense of the deviation position, wellpathpy supports reading a survey header from json file. The header requires the following keys:
{
"datum": "kb",
"elevation_units": "m",
"elevation": 100.0,
"surface_coordinates_units": "m",
"surface_easting": 1000.0,
"surface_northing": 2000.0
}
header = wp.read_header_json(fname)
Notes:
This function is provided for convenience - wellpathpy does not care about the
source of this data. It will simply use json.load()
to read the JSON file and save it as a python dict
.
Converting deviation surveys to positional logs¶
All these methods can be accessed from the deviation object created with:
dev = wp.deviation(
md = md,
inc = inc,
azi = azi,
)
Standard method¶
The standard method for converting a deviation surveys [md, inc, azi] into a positional logs [tvd, northing, easting] is the minimum curvature method. This method is provided by wellpathpy and is recommended for most use cases.
- minimum curvature method :
dev.minimum_curvature()
This method uses angles from upper and lower end of survey interval to calculate a curve that passes through both survey points. This curve is smoothed by use of the ratio factor defined by the tortuosity or dogleg of the wellpath. This method returns a dogleg severity calculated for a given course_length.
- minimum curvature method :
Comparison methods¶
Other methods are provided should the need arise to compare mininum curvature to older surveys that may have been calculated with one of these methods. In general these other methods are not recommended.
- radius of curvature method :
dev.radius_curvature()
Calculate TVD using radius or curvature method. Caution: this will yield unreliable results when data are closely spaced or when the borehole is straight but deviated. This method uses angles from upper and lower end of survey interval to calculate a curve that passes through both survey points.
- radius of curvature method :
- average tan method :
dev.tan_method()
Calculate TVD using average tangential method. This method averages the inclination and azimuth at the top and bottom of the survey interval before taking their sine and cosine, this average angle is used to estimate tvd.
- average tan method :
- balanced tan method :
dev.tan_method(choice='bal')
Calculate TVD using balanced tangential method. This method takes the sines and cosines of the inclination and azimuth at the top and bottom of the survey interval before averaging them, this average angle is used to estimate tvd. This will provide a smoother curve than the average tan method but requires closely spaced survey stations to avoid errors.
- balanced tan method :
- high tan method :
dev.tan_method(choice='high')
Calculate TVD using high tangential method. This method takes the sines and cosines of the inclination and azimuth at the bottom of the survey interval to estimate tvd. This method is not recommended as it can make gross tvd and offset errors in typical deviated wells.
- high tan method :
- low tan method :
dev.tan_method(choice='low')
Calculate TVD using low tangential method. This method takes the sines and cosines of the inclination and azimuth at the top of the survey interval to estimate tvd. This method is not recommended as it can make gross tvd and offset errors in typical deviated wells.
- low tan method :
Usage¶
In order to use these functions, you first need a deviation object as described in Loading a deviation. You can then run the following methods once you’ve imported your deviation and header and done any unit conversion required as described above.
# The recommended method for most use-cases
pos = dev.mininum_curvature(course_length=30)
tvd = pos.depth
northing = pos.northing
easting = pos.easting
# Comparison methods to contrast with older deviation surveys
tvd, northing, easting = dev.radius_curvature()
tvd, northing, easting = dev.tan_method() # for the default 'avg' method
tvd, northing, easting = dev.tan_method(choice='bal')
tvd, northing, easting = dev.tan_method(choice='high')
tvd, northing, easting = dev.tan_method(choice='low')
We can compare the outputs of all these methods in the figure below:
Well location and tvdss¶
The methods above are not aware of surface location or datum elevation.
If you want to move the positional log to a given surface location, to 0,0 coordinates, or shift the tvd to tvdss,
you can use the following functions which return a copy of the positional log by default (inplace=False
).
- to shift a positional log to a wellhead location
pos_wellhead = pos.to_wellhead(surface_northing=surface_northing,
surface_easting=surface_easting)
- to shift a positional log to a 0,0 coordinate location
pos_zero = pos_wellhead.to_zero(surface_northing=surface_northing,
surface_easting=surface_easting)
- to shift a positional log to tvdss
pos_tvdss = pos.to_tvdss(datum_elevation=header['elevation'])
If you have a header loaded as shown in the Loading the well header section, you can use that object to access the required properties with:
surface_northing = header['surface_northing']
surface_easting = header['surface_easting']
datum_elevation = header['datum_elevation']
Notes:
Wellpathpy is oblivious to units, and assumes the input units are consistent.
Exporting results¶
The two main wellpathpy
objects; deviation
and position
logs can be written to CSV via
object methods as shown below. These both call np.savetxt
with fmt='%.3f'
and delimiter=','
.
The deviation
also has header='md,inc,azi'
and the postition
has header='easting,northing,depth'
.
Other kwargs
accepted by np.savetxt
are also accepted.
- for a deviation survey:
dev.to_csv('./deviation.csv')
- for a positional log:
pos.to_csv('./position.csv')
Additional kwargs
can be passed like:
dev.to_csv('./deviation.csv', fmt='%.2e')
pos.to_csv('./position.csv', header='X,Y,Z', comments='$')
This is a pretty straight-forward function convenient CSV writing. If you need more control, or more sophisticated output, you must implement your own writer.