Skip to content

Commit

Permalink
Merge pull request #22 from jonnymaserati/feature/connector
Browse files Browse the repository at this point in the history
Feature/connector
  • Loading branch information
jonnymaserati authored Dec 14, 2020
2 parents 2648d8d + 67c1333 commit 769374a
Show file tree
Hide file tree
Showing 38 changed files with 1,902 additions and 73 deletions.
57 changes: 33 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
- standard [ISCWSA] method
- new mesh based method using the [Flexible Collision Library]
## New Features!
- **Well Path Creation:** the addition of the `connector` module enables drilling well paths to be created simply by providing start and end locations (with some vector data like inclination and azimuth). No need to indicate *how* to connect the points, the module will figure that out itself.
- **Fast visualization of well trajectory meshes:** addition of the `visual` module for quick and simple viewing and QAQC of well meshes.
- **Mesh Based Collision Detection:** the current method for determining the Separation Factor between wells is constrained by the frequency and location of survey stations or necessitates interpolation of survey stations in order to determine if Anti-Collision Rules have been violated. Meshing the well bore interpolates between survey stations and as such is a more reliable method for identifying potential well bore collisions, especially wth more sparse data sets.
- More coming soon!
Expand All @@ -36,7 +37,7 @@ pip install -e .
```
Make sure you include that `.` in the final line (it's not a typo) as this ensures that any changes to your development version are immediately implemented on save.
## Quick Start
Here's an example using `welleng` to construct a couple of simple well trajectories with `numpy`, creating survey listings for the wells with well bore uncertainty data, using these surveys to create well bore meshes and finally printing the results and plotting the meshes with the closest lines and SF data.
Here's an example using `welleng` to construct a couple of simple well trajectories with the `connector` module, creating survey listings for the wells with well bore uncertainty data, using these surveys to create well bore meshes and finally printing the results and plotting the meshes with the closest lines and SF data.

```
import welleng as we
Expand All @@ -45,29 +46,37 @@ from tabulate import tabulate
# construct simple well paths
print("Constructing wells...")
md = np.linspace(0,3000,100) # 30 meter intervals to 3000 mTD
inc = np.concatenate((
np.zeros(30), # vertical section
np.linspace(0,90,60), # build section to 60 degrees
np.full(10,90) # hold section at 60 degrees
))
azi1 = np.full(100,60) # constant azimuth at 60 degrees
azi2 = np.full(100,225) # constant azimuth at 225 degrees
# make a survey object and calculate the uncertainty covariances
connector_reference = we.connector.Connector(
pos1=[0,0,0],
inc1=0,
azi1=0,
pos2=[-100,0,2000.],
inc2=90,
azi2=60,
).survey(step=50)
connector_offset = we.connector.Connector(
pos1=[0,0,0],
inc1=0,
azi1=225,
pos2=[-280,-600,2000],
inc2=90,
azi2=270,
).survey(step=50)
# make a survey objects and calculate the uncertainty covariances
print("Making surveys...")
survey_reference = we.survey.Survey(
md,
inc,
azi1,
md=connector_reference.md,
inc=connector_reference.inc_deg,
azi=connector_reference.azi_deg,
error_model='ISCWSA_MWD'
)
# make another survey with offset surface location and along another azimuth
survey_offset = we.survey.Survey(
md,
inc,
azi2,
md=connector_offset.md,
inc=connector_offset.inc_deg,
azi=connector_offset.azi_deg,
start_nev=[100,200,0],
error_model='ISCWSA_MWD'
)
Expand Down Expand Up @@ -117,21 +126,21 @@ we.visual.plot(
print("Done!")
```
This results in a quick, interactive visualization of the well meshes that's great for QAQC.
This results in a quick, interactive visualization of the well meshes that's great for QAQC. What's interesting about these results is that the ISCWSA method does not explicitly detect a collision in this scenario wheras the mesh method does.

![image](https://user-images.githubusercontent.com/41046859/100718537-c3b12700-33bb-11eb-856e-cf1bd77d3cbf.png)
![image](https://user-images.githubusercontent.com/41046859/102106351-c0dd1a00-3e30-11eb-82f0-a0454dfce1c6.png)

For more examples, check out the [examples].

## Todos
- Add a Target class to see what you're aiming for!
- Export to Landmark's .wbp format so survey listings can be modified in COMPASS
- Add a Target class to see what you're aiming for - **in progress**
- Export to Landmark's .wbp format so survey listings can be modified in COMPASS - **in progress**
- Documentation
- Generate a scene of offset wells to enable fast screening of collision risks (e.g. hundreds of wells in seconds)
- Well trajectory planning - construct your own trajectories using a range of methods (and of course, including some novel ones)
- Well trajectory planning - construct your own trajectories using a range of methods (and of course, including some novel ones) **- DONE!**
- More error models
- WebApp for those that just want answers
- Viewer - a 3D viewer to quickly visualize the data and calculated results - **DONE!**
- Viewer - a 3D viewer to quickly visualize the data and calculated results **- DONE!**

It's possible to generate data for visualizing well trajectories with [welleng], as can be seen with the rendered scenes below.
![image](https://user-images.githubusercontent.com/41046859/97724026-b78c2e00-1acc-11eb-845d-1220219843a5.png)
Expand Down
152 changes: 152 additions & 0 deletions examples/connect_two_random_points.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
import welleng as we
import numpy as np
from vedo import Arrows, Lines
import random

# Some code for testing the connector module.

# Generate some random pairs of points
pos1 = [0,0,0]
md1 = 0

pos2 = np.random.random(3) * 1000

vec1 = np.random.random(3)
vec1 /= np.linalg.norm(vec1)
inc1, azi1 = np.degrees(we.utils.get_angles(vec1, nev=True)).reshape(2).T

vec2 = np.random.random(3)
vec2 /= np.linalg.norm(vec2)

inc2, azi2 = np.degrees(we.utils.get_angles(vec2, nev=True)).reshape(2).T

md2 = 100 + random.random() * 1000

# Define some random input permutations

number = 7
rand = random.random()

# 1: test only md2 (hold)
if rand < 1 * 1 / number:
option = 1
expected_method = 'hold'
vec2, pos2, inc2, azi2 = None, None, None, None

# 2: test md2 and an inc2
elif rand < 1 * 2 / number:
option = 2
expected_method = 'min_curve'
pos2, vec2, azi2 = None, None, None

# 3: test md2 and azi2
elif rand < 1 * 3 / number:
option = 3
expected_method = 'min_curve'
pos2, vec2, inc2 = None, None, None

# 4: test md2, inc2 and azi2
elif rand < 1 * 4 / number:
option = 4
expected_method = 'min_curve'
pos2, vec2 = None, None

# 5 test pos2
elif rand < 1 * 5 / number:
option = 5
expected_method = 'min_dist_to_target'
vec2, inc2, azi2, md2 = None, None, None, None

# 6 test pos2 vec2
elif rand < 1 * 6 / number:
option = 6
expected_method = 'curve_hold_curve'
md2, inc2, azi2, = None, None, None

# 7 test pos2, inc2 and azi2
else:
option = 7
expected_method = 'curve_hold_curve'
md2, vec2 = None, None

# Print the input parameters

print(
f"Option: {option}\tExpected Method: {expected_method}\n"
f"md1: {md1}\tpos1: {pos1}\tvec1: {vec1}\tinc1: {inc1}\tazi1: {azi1}\n"
f"md2: {md2}\tpos2: {pos2}\tvec2: {vec2}\tinc2: {inc2}\tazi2: {azi2}\n"
)

# Initialize a connector object and connect the inputs
section = we.connector.Connector(
pos1=[0.,0.,0],
vec1=vec1,
md2=md2,
pos2=pos2,
vec2=vec2,
inc2=inc2,
azi2=azi2,
degrees=True
)

# Print some pertinent calculation data

print(
f"Method: {section.method}\n",
f"radius_design: {section.radius_design}\t",
f"radius_critical: {section.radius_critical}\n"
f"radius_design2: {section.radius_design2}\t",
f"radius_critical2: {section.radius_critical2}\n"
f"iterations: {section.iterations}"
)

# Create a survey object of the section with interpolated points and coords
survey = section.survey(radius=5, step=30)

# As a QAQC step, check that the wellpath hits the defined turn points
start_points = np.array([section.pos1])
end_points = np.array([section.pos_target])
if section.pos2 is not None:
start_points = np.concatenate((start_points, [section.pos2]))
end_points = np.concatenate(([section.pos2], [section.pos_target]))
if section.pos3 is not None:
start_points = np.concatenate((start_points, [section.pos3]))
end_points = np.concatenate(([section.pos2], [section.pos3], [section.pos_target]))
lines = Lines(
startPoints=start_points,
endPoints=end_points,
c='green',
lw=5
)

# Add some arrows to represent the vectors at the start and end positions
scalar=150
arrows = Arrows(
startPoints=np.array([
section.pos1,
section.pos_target
]),
endPoints=np.array([
section.pos1 + scalar * section.vec1,
section.pos_target + scalar * section.vec_target
]),
s=0.5,
res=24
)

# generate a mesh of the generated section from the survey
# use the 'circle' method to construct a cylinder with constant radius
mesh = we.mesh.WellMesh(
survey=survey,
method='circle',
n_verts=24,
)

# plot the results
we.visual.plot(
[mesh.mesh],
lines=lines,
arrows=arrows,
)

print("Done")
40 changes: 24 additions & 16 deletions examples/simple_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,37 @@

# construct simple well paths
print("Constructing wells...")
md = np.linspace(0,3000,100) # 30 meter intervals to 3000 mTD
inc = np.concatenate((
np.zeros(30), # vertical section
np.linspace(0,90,60), # build section to 60 degrees
np.full(10,90) # hold section at 60 degrees
))
azi1 = np.full(100,60) # constant azimuth at 60 degrees
azi2 = np.full(100,225) # constant azimuth at 225 degrees
connector_reference = we.connector.Connector(
pos1=[0,0,0],
inc1=0,
azi1=0,
pos2=[-100,0,2000.],
inc2=90,
azi2=60,
).survey(step=50)

# make a survey object and calculate the uncertainty covariances
connector_offset = we.connector.Connector(
pos1=[0,0,0],
inc1=0,
azi1=225,
pos2=[-280,-600,2000],
inc2=90,
azi2=270,
).survey(step=50)

# make a survey objects and calculate the uncertainty covariances
print("Making surveys...")
survey_reference = we.survey.Survey(
md,
inc,
azi1,
md=connector_reference.md,
inc=connector_reference.inc_deg,
azi=connector_reference.azi_deg,
error_model='ISCWSA_MWD'
)

# make another survey with offset surface location and along another azimuth
survey_offset = we.survey.Survey(
md,
inc,
azi2,
md=connector_offset.md,
inc=connector_offset.inc_deg,
azi=connector_offset.azi_deg,
start_nev=[100,200,0],
error_model='ISCWSA_MWD'
)
Expand Down
24 changes: 20 additions & 4 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,20 @@
numpy
scipy
trimesh
vedo
cycler==0.10.0
Cython==0.29.21
decorator==4.4.2
et-xmlfile==1.0.1
jdcal==1.4.1
kiwisolver==1.3.1
matplotlib==3.3.3
networkx==2.5
numpy==1.19.4
openpyxl==3.0.5
Pillow==8.0.1
pyparsing==2.4.7
python-dateutil==2.8.1
python-fcl==0.0.12
scipy==1.5.4
six==1.15.0
tabulate==0.8.7
trimesh==3.8.18
vedo==2020.4.2
vtk==9.0.1
5 changes: 4 additions & 1 deletion welleng/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,7 @@
import welleng.mesh
import welleng.visual
import welleng.version
import welleng.errors.iscwsa_mwd
import welleng.errors.iscwsa_mwd
import welleng.exchange.wbp
import welleng.target
import welleng.connector
Binary file modified welleng/__pycache__/__init__.cpython-37.pyc
Binary file not shown.
Binary file modified welleng/__pycache__/__init__.cpython-38.pyc
Binary file not shown.
Binary file modified welleng/__pycache__/clearance.cpython-38.pyc
Binary file not shown.
Binary file added welleng/__pycache__/connector.cpython-37.pyc
Binary file not shown.
Binary file added welleng/__pycache__/connector.cpython-38.pyc
Binary file not shown.
Binary file modified welleng/__pycache__/error.cpython-38.pyc
Binary file not shown.
Binary file modified welleng/__pycache__/mesh.cpython-37.pyc
Binary file not shown.
Binary file modified welleng/__pycache__/mesh.cpython-38.pyc
Binary file not shown.
Binary file modified welleng/__pycache__/survey.cpython-37.pyc
Binary file not shown.
Binary file modified welleng/__pycache__/survey.cpython-38.pyc
Binary file not shown.
Binary file added welleng/__pycache__/target.cpython-37.pyc
Binary file not shown.
Binary file added welleng/__pycache__/target.cpython-38.pyc
Binary file not shown.
Binary file modified welleng/__pycache__/utils.cpython-37.pyc
Binary file not shown.
Binary file modified welleng/__pycache__/utils.cpython-38.pyc
Binary file not shown.
Binary file modified welleng/__pycache__/version.cpython-37.pyc
Binary file not shown.
Binary file added welleng/__pycache__/version.cpython-38.pyc
Binary file not shown.
Binary file modified welleng/__pycache__/visual.cpython-37.pyc
Binary file not shown.
Binary file added welleng/__pycache__/visual.cpython-38.pyc
Binary file not shown.
Loading

0 comments on commit 769374a

Please sign in to comment.