Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
"examples_dirs": "../../examples", # path to your example scripts
"gallery_dirs": "auto_examples", # path to where to save gallery generated output
"filename_pattern": "/plot_", # pattern to match example files
"ignore_pattern": "__init__\.py", # ignore __init__.py files
"ignore_pattern": "__init__.py", # ignore __init__.py files
"download_all_examples": False,
"min_reported_time": 0,
"thumbnail_size": (200, 200),
Expand All @@ -71,7 +71,7 @@
"icon_links": [
{
"name": "GitHub",
"url": "https://github.com/loop3d/LoopStructural",
"url": "https://github.com/loop3d/loopresources",
"icon": "fab fa-github-square",
},
{
Expand Down
2 changes: 1 addition & 1 deletion docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ The library has three main goals:
.. toctree::
:hidden:

auto_examples/index
_auto_examples/index
tutorials/index

.. toctree::
Expand Down
16 changes: 8 additions & 8 deletions docs/source/tutorials/00-desurvey.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
# 1 - Desurveying Drillholes

Desurveying converts downhole survey measurements into 3D spatial coordinates along the drillhole path. This is critical for accurate subsurface modeling and resource estimation.
Desurveying converts downhole survey measurements into 3D spatial coordinates along the drillhole path.

### **Assumptions**
### Assumptions

* **Azimuth**: Angle measured clockwise from **true north** (degrees).
* **Dip**: Angle from **horizontal**, where **negative values indicate downward inclination**.
* **Depth**: Measured along the drillhole from the collar.



### **Methods**
### Methods

* **Minimum Curvature**
Applied when more than two survey points exist. This method assumes a smooth arc between points, minimizing deviation from true curvature.
* **Tangent Method**
Used when only two points exist (collar and one survey), assuming a straight line between them.

### **Resampling**
### Resampling

Drillhole paths can be resampled into smaller intervals for modelling or interpolation.

* Loopresources uses **Slerp (Spherical Linear Interpolation)** to interpolate orientations smoothly between survey points, preserving directional accuracy.
* Loopresources uses **Slerp (Spherical Linear Interpolation)** to interpolate orientations smoothly between survey points, preserving directional accuracy and then performs minimum curvature desurveying on these interpolated points.

***

Would you like me to **extend this with a code snippet showing how to call your desurvey function**, or **add a diagram illustrating azimuth/dip conventions and curvature vs tangent paths**?
### Mapping properties
LoopResouces allows mapping of additional properties (e.g., lithology, assay, structure) along the drillhole path during desurveying. This can either be done by desurveying the
mid point of each interval, or the to and from depths of each interval. Or by resampling the property

87 changes: 87 additions & 0 deletions examples/plot_find_intersection_to_function.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
"""
Find Drillhole intersection
=============================

This example demonstrates the basic usage of the DrillholeDatabase class
for a single drillhole and finding the intersection with a LoopStructural function
and visualising the model, drillhole and intersection point using Loop3DView/Pyvista
"""

import pandas as pd
from loopresources import DrillholeDatabase
import pyvista as pv
import numpy as np
from LoopStructural import GeologicalModel
from LoopStructural.utils import strikedip2vector
from LoopStructural.visualisation import Loop3DView

#############################################################################
# Create our LoopStrutural Model
# -----------------------------
model = GeologicalModel([0, 0, 0], [10, 10, 10])
data = pd.DataFrame(
{
"X": [1, 2, 3, 4, 5],
"Y": [5, 5, 5, 5, 5],
"Z": [10, 10, 10, 10, 10],
"val": [0] * 5,
"nx": [4.32978028e-17] * 5,
"ny": [-7.07106781e-01] * 5,
"nz": [7.07106781e-01] * 5,
'feature_name': ['fault'] * 5,
}
)
model.create_and_add_fault('fault', displacement=1.0, data=data)

#############################################################################
# Create Drillhole Data
# -----------------------------
collar = pd.DataFrame(
{
"HOLEID": ["DH1"],
"EAST": [0],
"NORTH": [0],
"RL": [10],
"DEPTH": [5],
}
)
survey = pd.DataFrame(
{
"HOLEID": ["DH1", "DH1", "DH1"],
"DEPTH": [0, 2, 5],
"AZIMUTH": [0, 0, 0],
"DIP": [-60, -62, -50],
}
)

dhdb = DrillholeDatabase(survey=survey, collar=collar)

#############################################################################
# Find Intersection
# -----------------------------
# Find intersection of drillhole with geological model fault
# LoopStructural uses a global and local coordinate system, we need to ensure that
# the implicit functions are evaluated using the global coordinates.
# To do this we can use the model.evaluate_feature_value(feature_name, coords) method
# The `find_implicit_function_intersection` method of the DrillHole class can be used to find the intersection.
# It requires a function that takes coords as an input and returns the implicit function value.
# We can use a lambda function to wrap the model's method.
#

pts = dhdb["DH1"].find_implicit_function_intersection(
lambda xyz: model.evaluate_feature_value('fault', xyz)
)
print(f"\nIntersection points: \n {pts}")

viewer = Loop3DView(model)
viewer.plot_surface(model['fault'], 0.0)
viewer.add_mesh(model.bounding_box.vtk().outline(), color='black')
viewer.add_mesh(dhdb['DH1'].vtk())
viewer.add_points(pts[['x', 'y', 'z']].values, color='blue', point_size=10)
viewer.show()

#############################################################################
# We can also calculate the orientation of the implicit function at the intersection points

normals = model.evaluate_feature_gradient('fault', pts[['x', 'y', 'z']].values)
print(f"\nIntersection normals: \n {normals}")
5 changes: 5 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ optional-dependencies.dev = [
"sphinx",
"sphinx-rtd-theme",
]
optional-dependencies.docs = [
"sphinx",
"sphinx-rtd-theme",
"sphinx-gallery",
]
optional-dependencies.loop = [ "loopstructural>=1.6.21" ]
optional-dependencies.vtk = [ "pyvista" ]

Expand Down