Giter Site home page Giter Site logo

jonnymaserati / welleng Goto Github PK

View Code? Open in Web Editor NEW
108.0 9.0 31.0 32.78 MB

A collection of Wells/Drilling Engineering tools, focused on well trajectory planning for the time being.

License: Apache License 2.0

Python 100.00%
survey survey-listings wbp survey-stations wellbore drilling drilling-engineering well-design well-engineering engineering

welleng's Introduction

welleng

Open Source Love svg2 PyPI version Downloads License welleng-tests Actions Status

welleng aspires to be a collection of useful tools for Wells/Drilling Engineers, kicking off with a range of well trajectory tools.

  • Generate survey listings and interpolation with minimum curvature
  • Calculate well bore uncertainty data (utilizing either the ISCWSA MWD Rev5 models) - the coded error models are within 0.001% accuracy of the ISCWSA test data.
  • Calculate well bore clearance and Separation Factors (SF)

Support welleng

welleng is fuelled by copious amounts of coffee, so if you wish to supercharge development please donate generously:

Buy Me A Coffee

Documentation

It's still very much in beta (or maybe even alpha), but there's documentation available to help use the modules.

New Features!

  • Documentation: started to add documentation to try and make the library more accessible to starters.

  • Maximum Curvature Method: added an alternative Survey method for calculating a well trajectory from survey stations that add a more realistic (in terms of tortuosity) versus the traditional minimum curvature method. See this post for more details.

  • Modified Tortuosity Index: added a Survey method for calculating a modified tortuosity index as described here.

  • Panel Plot: added the type='panel' to the Survey.figure() method to return plan and section plots.

  • Torque and Drag: added a simple torque_drag module and an architecture module for creating scenarios (well bore and simple strings) - see this post for instructions.

  • Vertical Section: this should have been included a long time ago, but finally a vertical section will be calculated if the vertical_section_azimuth parameter is included in the SurveyHeader when initiating a Survey instance. Otherwise, to return the vertical section for a given azimuth (e.g. 45 degrees), or to set the vertical section azimuth and add the vertical section data to the Survey then:

    survey.get_vertical_section(45)
    survey.set_vertical_section(45)
  • Hello version 0.4: major version update to reflect all of the changes happening in the back end. If you have code that's built on previous versions of welleng then please lock that version in your env since likely it will require modifying to run with version 0.4 and higher.

  • Project Ahead: you can now project a survey from the last station to the bit or project to a target to see how to get back on track:

    >>> node_bit = survey.project_to_bit(delta_md=9.0)
    >>> survey_to_target = survey.project_to_target(node_target, dls_design=3.0, delta_md=9.0)
    
  • Interpolate Survey on TVD Depth: new survey function for interpolating fixed TVD intervals along a welleng Survey instance, e.g. to interpolate survey every 10mTVD and return the interpolated survey as s_interp_tvd:

    >>> s_interp_tvd = survey.interpolate_survey_tvd(step=10)
    
  • OWSG Tool Error Models: the ISCWSA curated Rev 4 and Rev 5 tool models have been coded up and continue to honor the ISCWSA diagnostic data. The OWSG tool errors are experimental with the following status:

    • Working: MWD, SRGM, _Fl, SAG, IFR1, IFR2, EMS
    • Not Currently Working Correctly: AX, GYRO

    The available error models can be listed with the following command:

    >>> welleng.errors.ERROR_MODELS
    
  • World Magnetic Model Calculator: calculates magnetic field data from the World Magnetic Model if magnetic field strength is not provided with the survey data.

  • 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.

    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(mesh.mesh)  # plot the mesh
  • Export to .wbp files (experimental): 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.

    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, "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.
  • Flexible Collision Library - for fast collision detection.
  • 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.
  • magnetic-field-calculator - a Python API for the British Geological Survey magnetic field calculator.

Simple Installation

A default, minimal welleng installation requires numpy and scipy which is sufficient for importing or generating trajectories with error models. Other libraries are optional depending on usage - most of welleng's functionality can be unlocked with the easy install tag, but if you wish to use mesh collision functionality, then an advanced install is required using the all install tag to get python-fcl, after first installing the compiled dependencies as described below.

You'll receive some ImportError messages and a suggested install tag if you try to use functions for which the required dependencies are missing.

Default install with minimal dependencies:

pip install welleng

Easy install with most of the dependencies and no compiled dependencies:

pip install welleng[easy]

Advanced Installation

If you want to use the mesh collision detection method, then the compiled dependencies are required prior to installing all of the welleng dependencies.

Ubuntu

Here's how to get the trickier dependencies manually installed on Ubuntu (further instructions can be found here):

sudo apt-get update
sudo apt-get install libeigen3-dev libccd-dev octomap-tools

On a Mac you should be able to install the above with brew and on a Windows machine you'll probably have to build these libraries following the instruction in the link, but it's not too tricky. Once the above are installed, then it should be a simple:

pip install welleng[all]

For developers, the repository can be cloned and locally installed in your GitHub directory via your preferred Python env (the dev branch is usuall a version or two ahead of the main).

git clone https://github.com/jonnymaserati/welleng.git
cd welleng
pip install -e .[all]

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.

Windows

Detailed instructions for installing welleng in a Windows OS can be found in this post.

Colaboratory

Perhaps the simplest way of getting up and running with welleng is to with a colab notebook. The required dependencies can be installed with the following cell:

!apt-get install -y xvfb x11-utils libeigen3-dev libccd-dev octomap-tools
!pip install welleng[all]

Unfortunately the visualization doesn't work with colab (or rather I've not been able to embed a VTK object) so some further work is needed to view the results. However, the welleng engine can be used to generate data in the notebook. Test it out with the following code:

!pip install plotly jupyter-dash pint
!pip install -U git+https://github.com/Kitware/ipyvtk-simple.git

import welleng as we
import plotly.graph_objects as go
from jupyter_dash import JupyterDash


# create a survey
s = we.survey.Survey(
    md=[0., 500., 2000., 5000.],
    inc=[0., 0., 30., 90],
    azi=[0., 0., 30., 90.]
)

# interpolate survey - generate points every 30 meters
s_interp = s.interpolate_survey(step=30)

# plot the results
fig = go.Figure()
fig.add_trace(
    go.Scatter3d(
        x=s_interp.x,
        y=s_interp.y,
        z=s_interp.z,
        mode='lines',
        line=dict(
            color='blue'
        ),
        name='survey_interpolated'
    ),
)

fig.add_trace(
    go.Scatter3d(
        x=s.x,
        y=s.y,
        z=s.z,
        mode='markers',
        marker=dict(
            color='red'
        ),
        name='survey'
    )
)
fig.update_scenes(zaxis_autorange="reversed")
fig.show()

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.

import welleng as we
from tabulate import tabulate

# construct simple well paths
print("Constructing wells...")
connector_reference = we.survey.from_connections(
    we.connector.Connector(
        pos1=[0., 0., 0.],
        inc1=0.,
        azi1=0.,
        pos2=[-100., 0., 2000.],
        inc2=90,
        azi2=60,
        ),
    step=50
)

connector_offset = we.survey.from_connections(
    we.connector.Connector(
        pos1=[0., 0., 0.],
        inc1=0.,
        azi1=225.,
        pos2=[-280., -600., 2000.],
        inc2=90.,
        azi2=270.,
    ),
    step=50
)

# make survey objects and calculate the uncertainty covariances
print("Making surveys...")
sh_reference = we.survey.SurveyHeader(
    name="reference",
    azi_reference="grid"
)
survey_reference = we.survey.Survey(
    md=connector_reference.md,
    inc=connector_reference.inc_deg,
    azi=connector_reference.azi_grid_deg,
    header=sh_reference,
    error_model='ISCWSA MWD Rev4'
)
sh_offset = we.survey.SurveyHeader(
    name="offset",
    azi_reference="grid"
)
survey_offset = we.survey.Survey(
    md=connector_offset.md,
    inc=connector_offset.inc_deg,
    azi=connector_offset.azi_grid_deg,
    start_nev=[100., 200., 0.],
    header=sh_offset,
    error_model='ISCWSA MWD Rev4'
)

# generate mesh objects of the well paths
print("Generating well meshes...")
mesh_reference = we.mesh.WellMesh(
    survey_reference
)
mesh_offset = we.mesh.WellMesh(
    survey_offset
)

# determine clearances
print("Setting up clearance models...")
c = we.clearance.Clearance(
    survey_reference,
    survey_offset
)

print("Calculating ISCWSA clearance...")
clearance_ISCWSA = we.clearance.ISCWSA(c)

print("Calculating mesh clearance...")
clearance_mesh = we.clearance.MeshClearance(c, sigma=2.445)

# tabulate the Separation Factor results and print them
results = [
    [md, sf0, sf1]
    for md, sf0, sf1
    in zip(c.reference.md, clearance_ISCWSA.SF, clearance_mesh.SF)
]

print("RESULTS\n-------")
print(tabulate(results, headers=['md', 'SF_ISCWSA', 'SF_MESH']))

# get closest lines between wells
lines = we.visual.get_lines(clearance_mesh)

# plot the result
we.visual.plot(
    [mesh_reference.mesh, mesh_offset.mesh],  # list of meshes
    names=['reference', 'offset'],  # list of names
    colors=['red', 'blue'],  # list of colors
    lines=lines
)

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

For more examples, including how to build a well trajectory by joining up a series of sections created with the welleng.connector module (see pic below), check out the examples and follow the jonnymaserati blog.

image

Well trajectory generated by build_a_well_from_sections.py

Todos

  • Add a Target class to see what you're aiming for - in progress
  • Documentation - in progress
  • Generate a scene of offset wells to enable fast screening of collision risks (e.g. hundreds of wells in seconds)
  • WebApp for those that just want answers
  • Add a units module to handle any units system - in progress

It's possible to generate data for visualizing well trajectories with welleng, as can be seen with the rendered scenes below. image ISCWSA Standard Set of Well Paths

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

License

Apache 2.0

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.

welleng's People

Contributors

jonnymaserati avatar kwinkunks avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

welleng's Issues

Inc, Azi to X,Y,Z

Hey can you please show me the formulas to convert the Inc, Azi to X, Y, and Z coordinates.

Project ahead feature: Bit position

From MWD -> Bit, there's still 18m (or less) , and it will be great to get the current bit position with current survey data .
FYI, there's 2 projection type according to compass:

  1. project to target
  2. curve only: user defined projection

pip installation fails when using --use-pep517 flag

The installation fails with error

error in welleng setup command: 'python_requires' must be a string containing valid version specifiers; Invalid specifier: '>=3.7.*'

When installing using poetry --use-pep517 is automatically included.

The quick fix would be to remove wildcard from version requirements

Speed up iscwsa_mwd.py

Use the lists attached survey object instead of continuously slicing lists when calculating the survey errors.

Add annulus volume function to utils

Add the following function to the utils module:

def annular_volume(od : float, id : float = None, length: float = None):
    """
    Calculate an annular volume.

    If no ``id`` is provided then circular volume is calculated. If no
    ``length`` is provided, then the unit volume is calculated (i.e. the
    area).

    Units are assumed consistent across input parameters, i.e. the
    calculation is dimensionless.

    Parameters
    ----------
    od : float
        The outer diameter.
    id : float | None, optional
        The innter diameter, default is 0.
    length : float | None, optional
        The length of the annulus.
    
    Returns
    -------
    annular_volume : float
        The (unit) volume of the annulus or cylinder.
    """
    length = 1 if length is None else length
    id = 0 if id is None else id
    annular_unit_volume = np.pi * ((od - id)**2) / 4
    annular_volume = annular_unit_volume * length

    return annular_volume

I beleive that a pure python implementation would be faster in this situation. I've re-implemented in our patckage the case where data=False in pure python and got a speedup of ~20x

welleng/welleng/survey.py

Lines 1647 to 1670 in 0afc2dd

# assume that Survey object is in meters
l_c = (
(sections[-1].md - sections[1].md) * ureg.meters
).to('ft').m
l_cs, l_xs = np.vstack([
[
l.md - u.md,
np.linalg.norm(np.array(l.location) - np.array(u.location))
]
for u, l in zip(sections_upper, sections_lower)
]).T
ti = np.hstack((
np.array([0.0]),
(
(n_sections / (n_sections + 1)) * (1 / l_c) * (
np.cumsum(
(l_cs / l_xs) - 1
)
)
) * 1e7
))

Fatal Python error: Segmentation fault

I tried to run the below code in ubuntu. but getting below error. Your help greatly appreciated.

import welleng as we
from tabulate import tabulate

construct simple well paths

print("Constructing wells...")
connector_reference = we.survey.from_connections(
we.connector.Connector(
pos1=[0., 0., 0.],
inc1=0.,
azi1=0.,
pos2=[-100., 0., 2000.],
inc2=90,
azi2=60,
),
step=50
)

connector_offset = we.survey.from_connections(
we.connector.Connector(
pos1=[0., 0., 0.],
inc1=0.,
azi1=225.,
pos2=[-280., -600., 2000.],
inc2=90.,
azi2=270.,
),
step=50
)

make survey objects and calculate the uncertainty covariances

print("Making surveys...")
sh_reference = we.survey.SurveyHeader(
name="reference",
azi_reference="grid"
)
survey_reference = we.survey.Survey(
md=connector_reference.md,
inc=connector_reference.inc_deg,
azi=connector_reference.azi_grid_deg,
header=sh_reference,
error_model='ISCWSA MWD Rev4'
)
sh_offset = we.survey.SurveyHeader(
name="offset",
azi_reference="grid"
)
survey_offset = we.survey.Survey(
md=connector_offset.md,
inc=connector_offset.inc_deg,
azi=connector_offset.azi_grid_deg,
start_nev=[100., 200., 0.],
header=sh_offset,
error_model='ISCWSA MWD Rev4'
)

generate mesh objects of the well paths

print("Generating well meshes...")
mesh_reference = we.mesh.WellMesh(
survey_reference
)
mesh_offset = we.mesh.WellMesh(
survey_offset
)

determine clearances

print("Setting up clearance models...")
c = we.clearance.Clearance(
survey_reference,
survey_offset
)

print("Calculating ISCWSA clearance...")
clearance_ISCWSA = we.clearance.ISCWSA(c)

print("Calculating mesh clearance...")
clearance_mesh = we.clearance.MeshClearance(c, sigma=2.445)

tabulate the Separation Factor results and print them

results = [
[md, sf0, sf1]
for md, sf0, sf1
in zip(c.reference.md, clearance_ISCWSA.SF, clearance_mesh.SF)
]

print("RESULTS\n-------")
print(tabulate(results, headers=['md', 'SF_ISCWSA', 'SF_MESH']))

get closest lines between wells

lines = we.visual.get_lines(clearance_mesh)

plot the result

we.visual.plot(
[mesh_reference.mesh, mesh_offset.mesh], # list of meshes
names=['reference', 'offset'], # list of names
colors=['red', 'blue'], # list of colors
lines=lines
)

print("Done!")


ERROR:

Fatal Python error: Segmentation fault

Current thread 0x00007fbd49723740 (most recent call first):
File "/usr/local/lib/python3.8/dist-packages/welleng/visual.py", line 161 in show
File "/usr/local/lib/python3.8/dist-packages/welleng/visual.py", line 268 in plot
File "testwell.py", line 96 in
Segmentation fault (core dumped)

is karma.js malware?

Is this real malware or a false detected?

docs/source/_static/js/karma.js

www.virustotal.com
https://www.virustotal.com/gui/file/d86bccdf80bcc25af3967c678ff6738bb30752371c8c874b1f46fd66db819785/detection

17 security vendors and no sandboxes flagged this file as malicious.
Security Vendors' Analysis
Ad-Aware
JS:Trojan.Cryxos.7406

ALYac
JS:Trojan.Cryxos.7406

Arcabit
JS:Trojan.Cryxos.D1CEE

Avast
Script:SNH-gen [Drp]

AVG
Script:SNH-gen [Drp]

BitDefender
JS:Trojan.Cryxos.7406

Emsisoft
JS:Trojan.Cryxos.7406 (B)

eScan
JS:Trojan.Cryxos.7406

GData
JS:Trojan.Cryxos.7406

Google
Detected

Ikarus
Trojan.JS.Cryxos

Kaspersky
HEUR:Trojan.Script.Miner.gen

MAX
Malware (ai Score=80)

McAfee-GW-Edition
BehavesLike.JS.CoinMiner.cm

Sangfor Engine Zero
Miner.Generic-JS.Save.lifeisall

Trellix (FireEye)
JS:Trojan.Cryxos.7406

VIPRE
JS:Trojan.Cryxos.7406

Are these code right?

The 57-61 lines of tool_error.py are as follows

        for tool in gyro_continuous:
            if tool in self.em['codes']:
                self.gyro_continuous = []          #set gyro_continuous to empty list
                self.em['codes'].move_to_end(tool)
                self.gyro_continuous.append(tool)

My question is why always set gyro_continuous to empty list before append tool into gyro_continuous

Can't interpolate md at shallowest md

When using the welleng.survey.Survey.interpolate_md method, providing an md param equal to the shallowest survey md returns an AssertionError.

It should return the shallowest md.

Add some types

Hi. I share your passion to wellbore domain. Currently I'm creating interactive tools for showing trajectory, so probably there are some area for collaborations. I write my stuff it in Rust language. Previously I was using typescript, but stick on compiled language.

I saw you are using some sort of Units-Of-Measure like

unit_weight=(68 * ureg('lbs / ft').to('kg / meters')).m,

Its absolutely must-use feature IMO.

I recommend use typing more. For example
def maximum_curvature(survey, dls_noise=1.0):
What is survey? You can say its obvious its Survey class. Ok, can I click on it to go to Survey class definition? Can I type . and see its methods?

Annotate function signatures, remove *args, **kwargs so code will be much readable and ide-friendly.

Also I recomend NewType pattern for units. Lets say we have angle-param. Is it degrees or radians?

We can do some calc(Rad(1.0), Rad(0.1)) or something like AnglePair{ azimuth: Rad, zenith: Rad}

Or lets say we have NVEVec, and NVEVec.get_angles, or AnglePair.get_vector

Cheers.

Update survey output

The current survey listing output could be updated to be a bit more thorough, useful:

def survey_to_df(survey):
    data = {
        'MD (m)': survey.md,
        'INC (deg)': survey.inc_deg,
        'AZI_GN (deg)': survey.azi_grid_deg,
        'AZI_TN (deg)': survey.azi_true_deg,
        'NORTHING (m)': survey.pos_nev[:, 0],
        'EASTING (m)': survey.pos_nev[:, 1],
        'TVDSS (m)': survey.pos_nev[:, 2],
        'X (m)': survey.pos_xyz[:, 0],
        'Y (m)': survey.pos_xyz[:, 1],
        'Z (m)': survey.pos_xyz[:, 2],
        'DLS (deg/30m)': survey.dls,
        'TOOLFACE (deg)': np.degrees(survey.toolface + 2 * np.pi) % 360,
        'BUILD RATE (deg)': np.nan_to_num(survey.build_rate, nan=0.0),
        'TURN RATE (deg)': np.nan_to_num(survey.turn_rate, nan=0.0)
    }

    df = pd.DataFrame(data)

    return df

The following code can be used to output a list of surveys to separate sheets in an Excel file:

dfs = [
    survey_to_df(survey) for survey in [
        survey_pilot, survey_horizontal
    ]
]

well_name = 'prospect_1'
filename_excel = f'{datetime.strftime(datetime.now(), "%Y%m%d%H%M%S")}_{well_name}'

with pd.ExcelWriter(f'{filename_excel}.xlsx') as writer:
    dfs[0].to_excel(writer, sheet_name="pilot", index=False)
    dfs[1].to_excel(writer, sheet_name="horizontal", index=False)

Update pint registry

Need to update the pint registry to remove the following warning:

WARNING:pint.util:Redefining 'Nm' (<class 'pint.delegates.txt_defparser.plain.UnitDefinition'>)

Potential collisions missed using standard ISCWSA clearance check

The standard ISCWSA clearance check method only interpolates between offset well survey stations and assumes that the reference well survey frequency is sufficient for a thorough collision check - however this is not always the case.

Include a check to identify potential collisions between reference well survey stations and perform more detailed checks where potential collisions may exist.

Add survey manager for tying survey legs together

Currently the errors module works for a well with a single continuous survey, but practically wells are constructed with several surveys that need to be tied together where the errors need to be correctly propagated.

Example evaluating_clearance.py doesn't work. AttributeError: 'Mesh' object has no attribute 'flag'

Example evaluating_clearance.py doesn't work. AttributeError: 'Mesh' object has no attribute 'flag'

Problem:
welleng 0.5.1 on Windows. vedo 2022.4.2

Traceback (most recent call last):
File "C:\welleng-main\examples\evaluating_clearance.py", line 209, in
we.visual.plot(scene, names=names, colors=colors)
File "C:\Users\username\anaconda3\envs\welleng\lib\site-packages\welleng\visual.py", line 287, in plot
plt = Plotter(data, **kwargs)
File "C:\Users\username\anaconda3\envs\welleng\lib\site-packages\welleng\visual.py", line 109, in init
m_vedo.flag()
AttributeError: 'Mesh' object has no attribute 'flag'
python-BaseException

Solution:
pip install --upgrade vedo==2021.0.6

Handle None value params

Change the Class params so that they can handle None values, e.g. welleng.survey.SurveyHeader(vertical_section_azimuth=None).

question: using welleng to get back to drilling window

Hi Jonny,

I am thinking how to use welleng to do a calculation to get back to the drilling window.

My question is:
With current MWD data, and planned path, I would like to calculate a best path that can get back to the planned path that use least slide , as showing in this pic
image

Or use 2 curve segment as shoing in this pic
image

Do you have suggestions on how to use welleng to calculate a best path?

CI/CD - Unit tests

Looks like a good bit of software, handling some complex computation. ๐Ÿ‘
It may be worthwhile to add some CI/CD with good unit test coverage to help encourage stability and outside contributions. ๐Ÿ‘

func_dict has wrong values

these code put wrong values into func_dict

            'MSIXY_TI1': MSIXY_TI1,  # Needs QAQC
            'MSIXY_TI2': MSIXY_TI1,  # Needs QAQC
            'MSIXY_TI3': MSIXY_TI1,  # Needs QAQC

and "DBHR" not in it.

unit weight in torque_drag

I am reading the code of torque_drag_example, and would like to understand what's the unit of unit_weight.

In the BHA, the sample code:

 bha.add_section(
        od=(6.5 * ureg.inches).to('meters').m,
        id=(4 * ureg.inches).to('meters').m,
        length=(372 * ureg.ft).to('meters').m,
        unit_weight=(146.90 * ureg('lbs / ft').to('kg / meters')).m * 9.81,
        name='6 1/2" DC'
    )

and for Wellbore:

 wellbore.add_section(
        od=9+5/8, id=8.5,
        bottom=3688 * 0.7,
        unit_weight=(68 * ureg('lbs / ft').to('kg / meters')).m,
        coeff_friction_sliding=0.39,
        name='production 9 5/8" casing'
    )

so why BHA's unit_weight * 9.81 and not Wellbore?

Interpolation error

I have the following data:

md = [0.0, 4004.0, 4050.0, 4100.0, 4150.0, 4200.0, 4250.0, 4300.0, 4350.0, 4400.0, 4500.0, 4600.0, 4700.0, 4800.0, 4900.0, 5000.0, 5100.0, 5200.0, 5300.0, 5400.0, 5500.0, 5600.0, 5700.0, 5800.0, 5900.0, 6000.0, 6100.0, 6200.0, 6300.0, 6400.0, 6500.0, 6600.0, 6700.0, 6800.0, 6900.0, 7000.0, 7100.0, 7200.0, 7300.0, 7400.0, 7500.0, 7600.0, 7700.0, 7800.0, 7900.0, 8000.0, 8100.0, 8200.0, 8300.0, 8400.0, 8500.0, 8600.0, 8700.0, 8800.0, 8900.0, 9000.0, 9100.0, 9200.0, 9300.0, 9400.0, 9500.0, 9540.0, 9571.0, 9664.0, 9757.0, 9850.0, 9942.0, 10034.0, 10130.0, 10222.0, 10316.0, 10407.0, 10499.0, 10592.0, 10685.0, 10775.0, 10868.0, 10968.0, 11060.0, 11153.0, 11246.0, 11338.0, 11432.0, 11525.0, 11623.0, 11717.0, 11811.0, 11905.0, 11999.0, 12079.0, 12177.0, 12265.0, 12364.0, 12453.0, 12548.0, 12645.0, 12739.0, 12833.0, 12924.0, 13021.0, 13115.0, 13211.0, 13302.0, 13395.0, 13492.0, 13581.0, 13642.0, 13726.0, 13766.0, 13796.0, 13873.6904296875, 14065.0, 14158.2998046875, 14337.0, 14526.0, 14895.0, 15367.0, 16479.0, 16575.0, 16667.0, 16854.0, 17041.0, 17666.5, 17763.470703125, 17853.4609375, 18224.5703125, 18319.6796875, 18412.490234375, 18504.2890625, 18599.150390625, 18695.349609375, 18785.55078125, 18881.740234375, 18972.740234375, 19067.30078125, 19161.990234375, 19341.419921875, 19442.599609375, 19533.0, 19629.0, 19717.9609375, 19818.060546875, 19914.009765625, 20501.0]

inc = [0.0, 0.0, 1.75, 2.0, 2.25, 1.75, 1.75, 1.0, 0.75, 0.75, 0.5, 0.75, 0.5, 0.5, 0.5, 0.75, 0.75, 0.5, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.0, 0.25, 0.5, 0.0, 0.25, 0.25, 0.25, 0.5, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.0, 0.25, 0.5, 0.25, 0.5, 0.25, 0.5, 0.75, 0.5, 0.5, 0.25, 0.5, 0.25, 0.25, 0.25, 0.25, 0.0, 0.25, 0.25, 0.25, 0.5199999809265137, 0.4699999988079071, 0.4000000059604645, 0.49000000953674316, 0.550000011920929, 0.4399999976158142, 0.49000000953674316, 0.5600000023841858, 0.6600000262260437, 0.5899999737739563, 0.3799999952316284, 0.4699999988079071, 0.6899999976158142, 0.7699999809265137, 0.75, 0.3799999952316284, 0.7900000214576721, 0.9800000190734863, 0.8199999928474426, 0.9599999785423279, 1.0399999618530273, 0.8899999856948853, 0.9399999976158142, 0.8199999928474426, 0.9900000095367432, 0.9700000286102295, 0.7099999785423279, 0.8500000238418579, 0.6399999856948853, 0.8199999928474426, 0.9399999976158142, 0.9399999976158142, 1.0800000429153442, 0.9700000286102295, 1.0499999523162842, 0.9599999785423279, 1.2300000190734863, 1.0800000429153442, 0.8500000238418579, 0.7599999904632568, 0.44999998807907104, 0.36000001430511475, 0.18000000715255737, 0.14000000059604645, 0.5, 0.5, 0.029999999329447746, 0.33000001311302185, 0.33000001311302185, 0.05999999865889549, 0.27000001072883606, 0.25999999046325684, 0.25999999046325684, 0.5400000214576721, 0.7699999809265137, 0.8899999856948853, 0.8899999856948853, 0.949999988079071, 0.9800000190734863, 0.7599999904632568, 0.9200000166893005, 0.9100000262260437, 0.8299999833106995, 0.9399999976158142, 0.9800000190734863, 0.8399999737739563, 0.9599999785423279, 1.1299999952316284, 1.3799999952316284, 1.409999966621399, 1.5099999904632568, 1.4600000381469727, 1.6200000047683716, 1.7100000381469727, 2.0999999046325684, 0.8999999761581421, 1.7999999523162842, 1.7000000476837158, 1.899999976158142, 2.200000047683716, 2.200000047683716, 2.200000047683716]

azi = [0.0, 358.8590393066406, 133.85903930664062, 135.85903930664062, 127.85903930664062, 138.85903930664062, 115.85903930664062, 112.85903930664062, 98.85903930664062, 113.85903930664062, 89.85903930664062, 99.85903930664062, 119.85903930664062, 66.85903930664062, 103.85903930664062, 79.85903930664062, 36.85904312133789, 38.85904312133789, 38.85904312133789, 34.85904312133789, 22.859041213989258, 6.859041690826416, 325.8590393066406, 325.8590393066406, 328.8590393066406, 358.8590393066406, 284.8590393066406, 302.8590393066406, 358.8590393066406, 321.8590393066406, 292.8590393066406, 301.8590393066406, 351.8590393066406, 322.8590393066406, 301.8590393066406, 3.859041690826416, 315.8590393066406, 339.8590393066406, 23.859041213989258, 330.8590393066406, 323.8590393066406, 6.859041690826416, 358.8590393066406, 351.8590393066406, 323.8590393066406, 346.8590393066406, 33.85904312133789, 16.859041213989258, 49.85904312133789, 14.859041213989258, 10.859041213989258, 27.859041213989258, 358.8590393066406, 22.859041213989258, 28.859041213989258, 25.859041213989258, 56.85904312133789, 29.859041213989258, 358.8590393066406, 57.85904312133789, 51.85904312133789, 68.85903930664062, 59.41904067993164, 67.71903991699219, 73.26904296875, 88.97904205322266, 64.21903991699219, 64.89904022216797, 25.749042510986328, 33.66904067993164, 359.2390441894531, 0.7190417051315308, 3.7790417671203613, 347.2290344238281, 316.8890380859375, 324.58905029296875, 323.57904052734375, 293.9390563964844, 301.9890441894531, 290.32904052734375, 304.96905517578125, 297.33905029296875, 289.279052734375, 283.0990295410156, 273.8590393066406, 270.26904296875, 247.4390411376953, 244.54904174804688, 228.50904846191406, 209.22903442382812, 209.32904052734375, 210.77903747558594, 201.54904174804688, 200.6390380859375, 200.62904357910156, 209.11904907226562, 195.49903869628906, 178.6390380859375, 179.50904846191406, 177.36904907226562, 159.16903686523438, 147.3190460205078, 165.4690399169922, 194.12904357910156, 133.6890411376953, 90.79904174804688, 197.72903442382812, 207.0590362548828, 97.04904174804688, 54.049041748046875, 89.76904296875, 251.8190460205078, 281.6190490722656, 297.8690490722656, 268.8690490722656, 257.8590393066406, 243.35903930664062, 217.23904418945312, 193.15904235839844, 198.5590362548828, 193.53904724121094, 196.25904846191406, 199.45904541015625, 212.42904663085938, 199.12904357910156, 199.1490478515625, 197.8490447998047, 187.6490478515625, 186.62904357910156, 182.54904174804688, 196.8990478515625, 208.69903564453125, 198.62904357910156, 198.48904418945312, 191.92904663085938, 187.77903747558594, 173.65904235839844, 174.35903930664062, 185.75904846191406, 187.15904235839844, 195.75904846191406, 195.02903747558594, 205.92904663085938, 205.92904663085938]

I create a survey using

survey=we.survey.Survey(md, inc, azi)

My goal is to have the well path with 10 ft step. So I do this:

survey = survey.interpolate_survey(step=10)

Since the last value of md is 20501, I expect to get 2051 values, but I get 2131 values. There are some random points between two valid md points, such as below:

19160.0 19161.990234375 19170.0

Is this a known issue? Is there a workaround for it? Thanks for your help in advance.

Massive MTI when using DD service company trajectories

Survey listings with chopped or rounded decimals can result in large MTI values when using the default parameters. Changing the Survey.modified_tortuosity_index() parameters to rtol=1.0 and dls_tol=1e-3 looks to fix this and might be more robust default values.

Installation issues with pip

Error message when attempting to install welleng with:

pip install welleng

Unable to find requirements.txt despite it being located in to the root of package.

image

Vectorize survey interpolation

The Survey.interpolate_survey() method is slow for small step values. See if the method can be vectorized for a speed bump.

Example evaluating_clearance.py doesn't work. ValueError: Data must be 1-dimensional

Example evaluating_clearance.py doesn't work. ValueError: Data must be 1-dimensional

Problem:
python version 3.7.15 (default, Nov 24 2022, 18:44:54) [MSC v.1916 64 bit (AMD64)]
welleng 0.5.1 on Windows.
pandas version 1.3.5

  1. ValueError: Data must be 1-dimensional
  2. IndexError: At least one sheet must be visible

Exporting data to data/output/output.xlsx...
Traceback (most recent call last):
File "C:\welleng-main\examples\evaluating_clearance.py", line 266, in
df = pd.DataFrame(data=data)
File "C:\Users\username\anaconda3\envs\welleng\lib\site-packages\pandas\core\frame.py", line 614, in init
mgr = dict_to_mgr(data, index, columns, dtype=dtype, copy=copy, typ=manager)
File "C:\Users\username\anaconda3\envs\welleng\lib\site-packages\pandas\core\internals\construction.py", line 465, in dict_to_mgr
arrays, data_names, index, columns, dtype=dtype, typ=typ, consolidate=copy
File "C:\Users\username\anaconda3\envs\welleng\lib\site-packages\pandas\core\internals\construction.py", line 124, in arrays_to_mgr
arrays = _homogenize(arrays, index, dtype)
File "C:\Users\username\anaconda3\envs\welleng\lib\site-packages\pandas\core\internals\construction.py", line 590, in _homogenize
val, index, dtype=dtype, copy=False, raise_cast_failure=False
File "C:\Users\username\anaconda3\envs\welleng\lib\site-packages\pandas\core\construction.py", line 576, in sanitize_array
subarr = _sanitize_ndim(subarr, data, dtype, index, allow_2d=allow_2d)
File "C:\Users\username\anaconda3\envs\welleng\lib\site-packages\pandas\core\construction.py", line 627, in _sanitize_ndim
raise ValueError("Data must be 1-dimensional")
ValueError: Data must be 1-dimensional

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "C:\welleng-main\examples\evaluating_clearance.py", line 266, in
df = pd.DataFrame(data=data)
File "C:\Users\username\anaconda3\envs\welleng\lib\site-packages\pandas\io\excel_base.py", line 1020, in exit
self.close()
File "C:\Users\username\anaconda3\envs\welleng\lib\site-packages\pandas\io\excel_base.py", line 1024, in close
content = self.save()
File "C:\Users\username\anaconda3\envs\welleng\lib\site-packages\pandas\io\excel_openpyxl.py", line 80, in save
self.book.save(self.handles.handle)
File "C:\Users\username\anaconda3\envs\welleng\lib\site-packages\openpyxl\workbook\workbook.py", line 407, in save
save_workbook(self, filename)
File "C:\Users\username\anaconda3\envs\welleng\lib\site-packages\openpyxl\writer\excel.py", line 293, in save_workbook
writer.save()
File "C:\Users\username\anaconda3\envs\welleng\lib\site-packages\openpyxl\writer\excel.py", line 275, in save
self.write_data()
File "C:\Users\username\anaconda3\envs\welleng\lib\site-packages\openpyxl\writer\excel.py", line 89, in write_data
archive.writestr(ARC_WORKBOOK, writer.write())
File "C:\Users\username\anaconda3\envs\welleng\lib\site-packages\openpyxl\workbook_writer.py", line 148, in write
self.write_views()
File "C:\Users\username\anaconda3\envs\welleng\lib\site-packages\openpyxl\workbook_writer.py", line 135, in write_views
active = get_active_sheet(self.wb)
File "C:\Users\username\anaconda3\envs\welleng\lib\site-packages\openpyxl\workbook_writer.py", line 33, in get_active_sheet
raise IndexError("At least one sheet must be visible")
IndexError: At least one sheet must be visible

Process finished with exit code -1

Solution:
?

Is this right?

The 1098-1117 lines of tool_error.py are as follows

    init_error = []  
    for i, (u, l) in enumerate(zip(
        error.survey.inc_rad[1:], error.survey.inc_rad[:-1]
    )):
        init_error.append(0.0)
        if all((
            u > kwargs['header']['XY Static Gyro']['End Inc'],
            l <= kwargs['header']['XY Static Gyro']['End Inc']
        )):
            for tool in kwargs['errors'].gyro_stationary:
                temp = kwargs['errors'].errors[tool].e_DIA[i - 1][2]
                if tool in ['GXY_RN']:
                    temp *= kwargs['header']['Noise Reduction Factor']
                init_error[-1] += temp

    temp = [0.0]
    for i, (u, e) in enumerate(zip(dpde[1:, 2], init_error)):
        temp.append(0.0)
        if u != 0.0:
            temp[-1] += np.sqrt(temp[-2] ** 2 + u * mag)

in these code, "init_error" totally unused, and the function name is "GXY_GRW", why "GXY_RN" used in code

Optimize the curve_hold_curve function

The code for balancing the radii for the upper and lower curve sections can take a couple of hundred iterations before finding an acceptable solution. This can likely be improved upon.

What is the licence?

Hi, interesting project!

The licence file says AGPL, but the badge says LGPL. Wondering which it is? (There's a very big difference; I'm hoping you say it's LGPL.)

Cheers, Matt

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.