Skip to content

Commit ea08d4c

Browse files
committed
docs: updating docs
1 parent 63214f7 commit ea08d4c

5 files changed

Lines changed: 120 additions & 12 deletions

File tree

docs/usage/3d-modeling.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
### Background on 3D Modeling
44

5-
A **3D model** is a mathematical representation of a three-dimensional object or phenomenon. In the context of geology, 3D models are used to visualize and analyze the subsurface structure of the Earth. These models are constructed by integrating various types of geological data, such as borehole logs, geological maps, geophysical surveys, and structural measurements. The goal is to create a coherent representation of the subsurface that can be used for exploration, resource management, and scientific research.
5+
A **3D model** is a mathematical representation of a three-dimensional object. In the context of geology, 3D models are used to visualize and analyze the subsurface structure of the Earth. These models are constructed by integrating various types of geological data, such as borehole logs, geological maps, geophysical surveys, and structural measurements. The goal is to create a coherent representation of the subsurface that can be used for exploration, resource management, and scientific research.
66

77

88

@@ -11,11 +11,11 @@ A **3D model** is a mathematical representation of a three-dimensional object or
1111
Implicit modeling is a modern approach to constructing 3D geological models. Unlike traditional methods that rely on explicit surfaces and manual digitization, implicit modeling uses mathematical functions to represent geological features. These functions are defined over the entire model space and allow for the automatic generation of surfaces, such as stratigraphic boundaries and faults.
1212

1313
Key advantages of implicit modeling include:
14-
- **Efficiency**: Models can be constructed more quickly, even with large datasets.
14+
- **Efficiency**: Models can be constructed quickly, even with large datasets.
1515
- **Flexibility**: Implicit methods can handle complex geometries and data uncertainties.
1616
- **Automation**: The process is less reliant on manual interpretation, reducing subjectivity.
1717

18-
Implicit modeling has become a cornerstone of modern geological modeling, enabling geoscientists to create detailed and accurate representations of the Earth's subsurface.
18+
Implicit modeling has become widely used, enabling geoscientists to create detailed and accurate representations of the Earth's subsurface.
1919

2020
## LoopStructural
2121
LoopStructural is an open-source Python library designed for implicit geological modeling. It provides tools for creating 3D geological models based on various types of input data, including borehole data, surface data, and structural measurements. LoopStructural provides both the implicit modelling algorithms and parameterisation of geological objects.

docs/usage/install/linux.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
```
2828
2. Use `pip` to install the required dependencies for the plugin. Navigate to the directory containing the `requirements` files and run:
2929
```bash
30-
pip install LoopStructural pyvista pyvistaqt meshio geoh5py
30+
pip install -e requirements.txt
3131
```
3232

3333
### Step 3: Install the Plugin via QGIS Plugin Manager

docs/usage/install/macosx.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
```
2121
2. Use `pip` to install the required dependencies for the plugin. Navigate to the directory containing the `requirements` files and run:
2222
```bash
23-
pip install -r requirements/development.txt
23+
pip install -r requirements.txt
2424
```
2525

2626
### Step 3: Install the Plugin via QGIS Plugin Manager

docs/usage/installation.md

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,14 @@
44

55
This plugin is published on the official QGIS plugins repository: <https://plugins.qgis.org/plugins/loopstructural/>.
66

7-
LoopStructural plugin requires the installation of LoopStructural, pyvista, pyvistaqt, meshio and geoh5py Python packages.
7+
LoopStructural plugin requires the installation of `LoopStructural, loopsolver, pyvista, pyvistaqt and pyqtgraph`. Optionally meshio and geoh5py can also be installed for exporting surfaces/models into different formats.
88

99
To install these dependencies you can follow the instructions below for your operating system.
1010

11+
### Using QPIP
12+
You can also use the experimental QGIS plugin QPIP which is developed by OPENGIS.ch <https://plugins.qgis.org/plugins/qpip/> that manages the Python dependencies for your QGIS environment and keeps the dependencies up to date.
13+
14+
1115
----
1216

1317
```{toctree}
@@ -17,12 +21,7 @@ To install these dependencies you can follow the instructions below for your ope
1721
install/windows
1822
install/linux
1923
install/macosx
24+
2025
```
2126

22-
---
23-
```{toctree}
24-
:caption: Development
25-
:maxdepth: 1
2627

27-
install/development
28-
```

tests/conftest.py

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import os
2+
import pickle
3+
import importlib
4+
import pytest
5+
6+
from qgis.core import QgsApplication, QgsProcessingContext, QgsProcessingFeedback
7+
8+
9+
@pytest.fixture(scope="session", autouse=True)
10+
def qgis_app():
11+
"""Start a headless QGIS application for tests.
12+
13+
Requires QGIS_PREFIX_PATH to be set in the environment (pointing to the QGIS install).
14+
"""
15+
prefix = os.environ.get("QGIS_PREFIX_PATH")
16+
if not prefix:
17+
raise RuntimeError(
18+
"QGIS_PREFIX_PATH environment variable must be set to your QGIS install path for tests to run."
19+
)
20+
21+
app = QgsApplication([], False)
22+
app.setPrefixPath(prefix, True)
23+
app.initQgis()
24+
25+
yield app
26+
27+
app.exitQgis()
28+
29+
30+
@pytest.fixture
31+
def qgis_context():
32+
"""Return a fresh processing context."""
33+
return QgsProcessingContext()
34+
35+
36+
@pytest.fixture
37+
def feedback():
38+
"""Return a simple QgsProcessingFeedback instance for algorithms."""
39+
return QgsProcessingFeedback()
40+
41+
42+
@pytest.fixture
43+
def ensure_loopstructural(monkeypatch):
44+
"""If the real LoopStructural classes are not available, inject minimal fakes into
45+
the algorithm module so tests can run without the external dependency.
46+
47+
The algorithm module imports FaultTopology and FaultRelationshipType at import-time
48+
and uses those module-level names; this fixture patches the algorithm module
49+
attributes when they are missing.
50+
"""
51+
mod_name = "loopstructural.processing.algorithms.modelling.add_fault_topology"
52+
mod = importlib.import_module(mod_name)
53+
54+
if getattr(mod, "FaultTopology", None) is not None and getattr(mod, "FaultRelationshipType", None) is not None:
55+
# real dependency present; nothing to do
56+
return
57+
58+
class _FakeFaultTopology:
59+
def __init__(self, strat_col=None):
60+
self.strat_col = strat_col
61+
self.faults = set()
62+
# store relationships in a dict for simple inspection
63+
self._rels = {}
64+
65+
def add_fault(self, name):
66+
self.faults.add(name)
67+
68+
def update_fault_relationship(self, a, b, rel):
69+
self._rels[(a, b)] = rel
70+
71+
def __repr__(self):
72+
return f"FakeFaultTopology(faults={sorted(self.faults)})"
73+
74+
class _FakeFaultRelationshipType:
75+
ABUTTING = 1
76+
77+
monkeypatch.setattr(mod, "FaultTopology", _FakeFaultTopology, raising=False)
78+
monkeypatch.setattr(mod, "FaultRelationshipType", _FakeFaultRelationshipType, raising=False)
79+
80+
return
81+
82+
83+
@pytest.fixture
84+
def simple_model_pickle(tmp_path):
85+
"""Create and return a path to a simple pickled model object suitable for tests.
86+
87+
The returned object has a `features` attribute with simple feature-like objects
88+
exposing a `name` attribute so the algorithm can find faults.
89+
"""
90+
class DummyFeature:
91+
def __init__(self, name):
92+
self.name = name
93+
94+
def __repr__(self):
95+
return f"DummyFeature({self.name})"
96+
97+
class DummyModel:
98+
def __init__(self, names=("fault1", "fault2")):
99+
self.features = [DummyFeature(n) for n in names]
100+
101+
def __repr__(self):
102+
return f"DummyModel(features={self.features})"
103+
104+
model = DummyModel()
105+
path = tmp_path / "model.pkl"
106+
with open(path, "wb") as fh:
107+
pickle.dump(model, fh)
108+
109+
return str(path)

0 commit comments

Comments
 (0)