Skip to content

Commit

Permalink
Merge pull request #34 from jonnymaserati/dev
Browse files Browse the repository at this point in the history
Change license and implement CI/CD
  • Loading branch information
jonnymaserati authored Dec 22, 2020
2 parents d0669b9 + d47d22d commit bda2289
Show file tree
Hide file tree
Showing 11 changed files with 236 additions and 64 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,4 @@ jobs:
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
- name: Test with pytest
run: |
pytest
pytest test
31 changes: 23 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# welleng

[![Open Source Love svg2](https://badges.frapsoft.com/os/v2/open-source.svg?v=103)](https://github.com/pro-well-plan/pwptemp/blob/master/LICENSE.md)
[![PyPI version](https://badge.fury.io/py/welleng.svg)](https://badge.fury.io/py/welleng)
[![Downloads](https://static.pepy.tech/personalized-badge/welleng?period=total&units=international_system&left_color=grey&right_color=orange&left_text=Downloads)](https://pepy.tech/project/welleng)
Expand All @@ -11,52 +12,65 @@
- Calculate well bore clearance and Separation Factors (SF)
- standard [ISCWSA] method
- new mesh based method using the [Flexible Collision Library]

## New Features!

- **Import from Landmark .wbp files:** using the `exchange.wbp` module it's now possible to import .wbp files exported from Landmark's COMPASS or DecisionSpace software.
```
```python
import welleng as we

wp = we.exchange.wbp.load(demo.wbp) # import file
survey = we.exchange.wbp.wbp_to_survey(wp, step=30) # convert to survey
mesh = we.mesh.WellMesh(survey, method='circle') # convert to mesh
we.visual.plot(m.mesh) # plot the mesh
```

- **Export to .wbp files *(experiemental)*:** using the `exchange.wbp` module, it's possible to convert a planned survey file into a list of turn points that can be exported to a .wbp file.
```
```python
import welleng as we

wp = we.exchange.wbp.WellPlan(survey) # convert Survey to WellPlan object
doc = we.exchange.wbp.export(wp) # create a .wbp document
we.exchange.wbp.save_to_file(doc, f"demo.wbp") # save the document to file
```

- **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!

## Tech

[welleng] uses a number of open source projects to work properly:

* [trimesh] - awesome library for loading and using triangular meshes
* [numpy] - the fundamental package for scientific computing with Python
* [scipy] - a Python-based ecosystem of open-source software for mathematics, science, and engineering
* [vedo] - a python module for scientific visualization, analysis of 3D objects and point clouds based on VTK.

## Installation

[welleng] requires [trimesh], [numpy] and [scipy] to run. Other libraries are optional depending on usage and to get [python-fcl] running on which [trimesh] is built may require some additional installations. Other than that, it should be an easy pip install to get up and running with welleng and the minimum dependencies.

```
```python
pip install welleng
```

For developers, the repository can be cloned and locally installed in your GitHub directory via your preferred Python env.
```

```python
git clone https://github.com/jonnymaserati/welleng.git
cd welleng
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 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.

```
```python
import welleng as we
import numpy as np
from tabulate import tabulate
Expand Down Expand Up @@ -143,6 +157,7 @@ we.visual.plot(

print("Done!")
```

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/102106351-c0dd1a00-3e30-11eb-82f0-a0454dfce1c6.png)
Expand All @@ -154,6 +169,7 @@ For more examples, including how to build a well trajectory by joining up a seri
Well trajectory generated by [build_a_well_from_sections.py]

## Todos

- 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
Expand All @@ -172,10 +188,9 @@ Equinor's Volve Wells

The ISCWSA standard set of well paths for evaluating clearance scenarios and Equinor's [volve] wells have been rendered in [blender] above. See the [examples] for the code used to generate the [volve] scene, extracting the data from the [volve] EDM.xml file.

License
----
## License

LGPL v3
[Apache 2.0](LICENSE)

Please note the terms of the license. Although this software endeavors to be accurate, it should not be used as is for real wells. If you want a production version or wish to develop this software for a particular application, then please get in touch with [jonnycorcutt], but the intent of this library is to assist development.

Expand Down
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ six==1.15.0
tabulate==0.8.7
trimesh==3.8.18
vedo==2020.4.2
vtk==9.0.1
vtk==9.0.1
PyYAML==5.3.1
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
],
author='Jonathan Corcutt',
author_email='jonnycorcutt@gmail.com',
license='LGPL v3',
license='Apache 2.0',
packages=find_packages(exclude=["tests"]),
install_requires=[
'python-fcl',
Expand Down
Empty file added test/__init__.py
Empty file.
121 changes: 121 additions & 0 deletions test/test_connector.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
from welleng.connector import Connector
from welleng.survey import Survey
import numpy as np


def test_md_hold():
# test hold with only md provided
c = Connector(
vec1=[0, 0, 1],
md2=500,
)
assert (
c.inc_target == c.inc1
and c.azi_target == c.azi1
and c.pos_target[2] == c.md_target
), "Failed c1"
assert c.method == 'hold', "Unexpected method"

c.survey()


def test_md_and_vec():
# test with md2 and vec2 provided (minimum curvature)
c = Connector(
vec1=[0, 0, 1],
md2=1000,
vec2=[0, 1, 0]
)
assert c.method == 'min_curve'


def test_pos():
# test with pos2 provided (minimum distance)
c = Connector(
vec1=[0, 0, 1],
pos2=[100, 100, 1000],
)
assert c.md_target > c.pos1[2], "Failed c3"


def test_pos_and_dls():
# test with pos2 needing more aggressive dls (minimum curvature)
c = Connector(
vec1=[0, 0, 1],
pos2=[200, 400, 200]
)
assert c.method == 'min_curve_to_target'


def test_pos_and_vec():
# test with pos2 and vec2 provided
vec1 = [-1, -1, 1]
vec2 = [1, -1, 0]
c = Connector(
pos1=[0., 0., 0],
vec1=vec1 / np.linalg.norm(vec1),
pos2=[0., 1000., 500.],
vec2=vec2 / np.linalg.norm(vec2),
)
assert c.method == 'curve_hold_curve'

# test if interpolator and survey functions are working
assert isinstance(c.survey(), Survey)


def test_pos_inc_azi():
# test with pos2, inc1 and azi1 provided
c = Connector(
pos1=[0., 0., 0],
inc1=0.,
azi1=90,
pos2=[1000., 1000., 1000.],
vec2=[0., 0., 1.],
)
assert c.method == 'curve_hold_curve'


def test_dls2():
# test with different dls for second curve section
c = Connector(
pos1=[0., 0., 0],
vec1=[0., 0., 1.],
pos2=[0., 100., 1000.],
vec2=[0., 0., 1.],
dls_design2=5
)
assert c.radius_design2 < c.radius_design


def test_radius_critical():
# test with dls_critical requirement (actual dls < dls_design)
c = Connector(
pos1=[0., 0., 0],
vec1=[0., 0., 1.],
pos2=[0., 100., 100.],
vec2=[0., 0., 1.],
)
assert c.radius_critical < c.radius_design


def test_min_curve():
# test min_curve (inc2 provided)
c = Connector(
pos1=[0., 0., 0],
vec1=[0., 0., 1.],
inc2=30,
)
assert c.method == 'min_curve'


def test_radius_critical_with_min_curve():
# test min_curve with md less than required radius
c = Connector(
pos1=[0., 0., 0],
inc1=0,
azi1=0,
md2=500,
inc2=90,
azi2=0,
)
assert c.radius_critical < c.radius_design
Loading

0 comments on commit bda2289

Please sign in to comment.