Skip to content

Commit 21e5572

Browse files
fix: Removing cython dependency (#168)
* fix: adding json exports * fix: moving and renaming conversion functions also adding some type hints and a generic numeric type * tests: adding tests for conversions need to add some better tests not just 0 and 1s * fix: remove process_map2loop not required, can be done using processor * fix: adding synthetic horizontal layers model * fix: adding corners property to bounding box * fix: substituting pli for p1 same interpolator but this implementation uses numpy instead of cython * tests: test that horizontal layers are working * fix: making structured tetra compatible with p1 interp * fix: making p1 interpolator work * fix: cast input to np array * fix: adding type enums * fix: adding sparse matrix neighbour calculator this means no more cython code * fix: adding some type hints * refactor: ➖ removing model builder there is no real advantage to using a builder design pattern for loopstructural * fix: ✨ adding ability to calculate normalised value of a feature this just makes it easier to scale scalar field between 0 and 1 * fix: adding map for interpolator to support type * fix: enabling support builder with interpolator factory * fix: updating imports for maths functions * fix: adding support creator from bbox * fix: when reset clear the constraints dictionary * fix: reset when setting up interpolator * fix: removing old pli interpolator * fix: fixing tetra indexing and masks * fix: removing unused imports * fix: speeding up element getter * fix: adding onGeometryChange function for supports * fix: reset change number of constraints * fix: adding gradient orthogonal to p1interpolator * fix: changing instrusion example to rescale points * fix: setting model tolerance using new bounding box * fix: updating fold to use p1 interpolator * fix: renaming variables * fix: adding name and vector args to min edge jumps * fix: removing old imports * fix: fixing orthogonal constraints for p1 * fix: moving fault setup into fault builder frm model * fix: flake8 error * fix: add bb origin to surfaces * fix: fold constraints added in setup interpolator this allows for interpolator to be reset and doesn't remove the fold constraints when resetting * fix: temp fix for issue with np types * Replace reqs with correct theme Theme being loaded by requirements.txt was wrong (an old one?) So have updated with the pydata_sphinx_theme so now builds correctly * Adding PyPI custom link to navigation * Replacing square icon with (nicer) round icon * Adding navbar options and metadata Image is a placeholder for now, but this is an (onvs opinionated) view on a nicer format. Adds a limit to the number of nav items, adds a logo, changes the title to look cleaner (and not say "documentation" at the end), adds metadata * Fixing svg img * Updating the contributors docs * removing accidental tab * docs: fixing missing automodule * fix: adding length to bbox * fix: removing dof and name from interpolator json * docs: adding explicit imports for submodules Without explicit import of submodules and using __ALL__ the majority of the code isn't imported so sphinx doesn't document it. * docs: adding citations to documentation * fix: removing reference to dtm creator and using get interpolator correctly * fix: face table resize when geometry reset * fix: elements property for base structured support * fix: adding imports to api * fix: changing from interpolator type string to enum * fix: removing cython * fix: only axial foliation is constrained by fold frame * Update release-please.yml * Update release-please.yml * Update release-please.yml * ci: updating to use pip wheel . * Update release-please.yml * fix: disable progress bar for model update * ci: remove numpy version for conda * fix: changing to interpolator factory required changing how fold interpolator is setup. Rather than initialising with a fold, the fold is added to the interpolator added map between stringinterpolator names and the interpolatortypes enum * fix: identify points that fall on face of shared tetras. Automatically chooses the second one. * fix: rename surface vtk property to vtk from pyvista * fix: add docstring and cast isinside to an array * docs: adding docs to surface datatype * fix: removing cython code * fix: removing model api for time being * build: adding conda builds to git ignore * typo * ci: using conda convert to create osx * ci: removing cython * ci: typo in yml * ci: again * ci: again --------- Co-authored-by: Sam <samuel.joseph.roberts@hotmail.co.uk>
1 parent c3a7221 commit 21e5572

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+1758
-2010
lines changed

.github/workflows/release-please.yml

Lines changed: 52 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,30 @@ on:
33
name: release-please
44
jobs:
55
continuous-integration:
6-
name: Continuous integration ${{ matrix.os }} python ${{ matrix.python-version }}
6+
name: Continuous integration ${{ matrix.os }} python ${{ matrix.python-version }}
77
runs-on: ${{ matrix.os }}
88
strategy:
99
fail-fast: false
1010
matrix:
11-
os: ["ubuntu-latest", "windows-latest"] #"macos-latest",
12-
python-version: ["3.8","3.9","3.10"]
11+
os: ${{ fromJSON(vars.BUILD_OS)}}
12+
python-version: ${{ fromJSON(vars.PYTHON_VERSIONS)}}
1313
steps:
1414
- uses: actions/checkout@v2
1515
- uses: conda-incubator/setup-miniconda@v2
1616
with:
17-
python-version: ${{ matrix.python }}
17+
python-version: ${{ matrix.python }}
1818
- name: Installing dependencies
1919
shell: bash -l {0}
2020
run: |
2121
conda install -c conda-forge cython numpy scipy scikit-image scikit-learn pyamg flake8 pytest networkx osqp matplotlib -y
2222
- name: Checking formatting of code
2323
shell: bash -l {0}
2424
run: |
25-
# stop the build if there are Python syntax errors or undefined names
26-
flake8 LoopStructural --count --select=E9,F63,F7,F82 --show-source --statistics
27-
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
28-
flake8 LoopStructural --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
29-
- name: Building and install
25+
# stop the build if there are Python syntax errors or undefined names
26+
flake8 LoopStructural --count --select=E9,F63,F7,F82 --show-source --statistics
27+
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
28+
flake8 LoopStructural --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
29+
- name: Building and install
3030
shell: bash -l {0}
3131
run: |
3232
python setup.py install build_ext --inplace
@@ -78,109 +78,88 @@ jobs:
7878
with:
7979
branch: gh-pages # The branch the action should deploy to.
8080
folder: docs/build/html # The folder the action should deploy.
81-
81+
8282
conda-deploy:
8383
name: Uploading to Loop3d for python ${{ matrix.os }})
8484
needs: ["documentation-test", "continuous-integration"]
85-
runs-on: ${{ matrix.os }}
85+
runs-on: ${{matrix.os}}
8686
strategy:
8787
fail-fast: false
8888
matrix:
89-
os: ["ubuntu-latest", "windows-latest"]
90-
python-version: ["3.10","3.9","3.8"]
89+
os: ["ubuntu-latest"]
90+
python-version: ${{ fromJSON(vars.PYTHON_VERSIONS)}}
9191
steps:
9292
- uses: conda-incubator/setup-miniconda@v2
9393
with:
9494
auto-update-conda: true
9595
python-version: ${{ matrix.python-version }}
96-
96+
9797
- uses: actions/checkout@v2
9898
- name: update submodules
99-
# shell: bash -l {0}
99+
# shell: bash -l {0}
100100
run: |
101-
git submodule update --init --recursive
102-
- name: Add msbuild to PATH
103-
if: matrix.os == 'windows-latest'
104-
uses: microsoft/setup-msbuild@v1.0.2
105-
- name: Conda build'
101+
git submodule update --init --recursive
102+
- name: Conda build
106103
env:
107104
ANACONDA_API_TOKEN: ${{ secrets.ANACONDA_TOKEN }}
108105
shell: bash -l {0}
109106
run: |
110-
conda install -c conda-forge conda-build scikit-build numpy cython anaconda-client -y
111-
conda build -c anaconda -c conda-forge -c loop3d --output-folder conda conda --numpy 1.21
112-
conda install anaconda-client -y
107+
conda install -c conda-forge conda-build scikit-build numpy cython anaconda-client -y
108+
conda build -c anaconda -c conda-forge -c loop3d --output-folder conda conda
109+
conda convert -p all conda/linux-64/*.tar.bz2 -f -o conda
110+
conda install anaconda-client -y
113111
- name: upload artifacts
114112
uses: actions/upload-artifact@v3
115113
with:
116114
name: conda
117115
path: conda
118-
119116

120117
make_sdist:
121118
needs: ["documentation-test", "continuous-integration"]
122119
name: Make SDist
123120
runs-on: ubuntu-latest
124121
steps:
125-
- uses: actions/checkout@v3
126-
127-
- name: Build SDist
128-
run: |
129-
pip install numpy cython
130-
python setup.py sdist
122+
- uses: actions/checkout@v3
131123

132-
- uses: actions/upload-artifact@v3
133-
with:
134-
name: dist
135-
path: dist/*.tar.gz
136-
137-
build_wheels:
138-
needs: ["documentation-test", "continuous-integration"]
139-
name: Build wheels
140-
runs-on: ${{ matrix.os }}
141-
strategy:
142-
fail-fast: false
143-
matrix:
144-
os: [ubuntu-latest, windows-latest, macos-latest]
145-
steps:
146-
- uses: actions/checkout@v2
124+
- name: Build SDist
125+
run: |
126+
pip install numpy
127+
python setup.py sdist
128+
pip wheel -w wheelhouse .
147129
148-
- name: Build wheels
149-
uses: pypa/cibuildwheel@v2.12.0
150-
env:
151-
CIBW_ARCHS_MACOS: x86_64 universal2
152-
CIBW_BUILD: "cp36-* cp37-* cp38-* cp39-* cp310*"
153-
CIBW_BEFORE_BUILD: "pip install numpy cython" #make sure numpy is the same version as required by LS
154130
- uses: actions/upload-artifact@v3
155131
with:
156132
name: dist
157-
path: ./wheelhouse/*.whl
158-
133+
path: dist/*.tar.gz
134+
- uses: actions/upload-artifact@v3
135+
with:
136+
name: dist
137+
path: wheelhouse/*.whl
138+
159139
upload_to_pypi:
160-
needs: ["release-please","build_wheels","make_sdist","conda-deploy"]
140+
needs: ["release-please", "make_sdist", "conda-deploy"]
161141
runs-on: ubuntu-latest
162142
if: ${{ needs.release-please.outputs.release_created }}
163143
steps:
164-
- uses: actions/download-artifact@v3
165-
with:
144+
- uses: actions/download-artifact@v3
145+
with:
166146
name: dist
167147
path: dist
168-
- uses: actions/download-artifact@v3
169-
with:
148+
- uses: actions/download-artifact@v3
149+
with:
170150
name: conda
171151
path: conda
172-
- uses: pypa/gh-action-pypi-publish@v1.6.4
173-
with:
174-
skip_existing: true
175-
verbose: true
176-
user: ${{ secrets.PYPI_USERNAME }}
177-
password: ${{ secrets.PYPI_PASSWORD }}
178-
- uses: conda-incubator/setup-miniconda@v2
179-
- name: upload all files to conda-forge
180-
shell: bash -l {0}
181-
env:
182-
ANACONDA_API_TOKEN: ${{ secrets.ANACONDA_TOKEN }}
183-
run: |
184-
conda install -c anaconda anaconda-client -y
185-
anaconda upload --label main conda/*/*.tar.bz2
186-
152+
- uses: pypa/gh-action-pypi-publish@v1.6.4
153+
with:
154+
skip_existing: true
155+
verbose: true
156+
user: ${{ secrets.PYPI_USERNAME }}
157+
password: ${{ secrets.PYPI_PASSWORD }}
158+
- uses: conda-incubator/setup-miniconda@v2
159+
- name: upload all files to conda-forge
160+
shell: bash -l {0}
161+
env:
162+
ANACONDA_API_TOKEN: ${{ secrets.ANACONDA_TOKEN }}
163+
run: |
164+
conda install -c anaconda anaconda-client -y
165+
anaconda upload --label main conda/*/*.tar.bz2

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,3 +132,7 @@ examples/*.png
132132
dev/scalar_field
133133
dev/unconf
134134
docs/source/sg_execution_times.rst
135+
conda/index.html
136+
conda/channeldata.json
137+
conda/noarch
138+
conda/win-64

LoopStructural/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""
2-
LoopStructural API
3-
=======================
2+
LoopStructural
3+
==============
44
55
"""
66

LoopStructural/api/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
from ._interpolate import LoopInterpolator
2+
from ._surface import LoopIsosurfacer

LoopStructural/api/_interpolate.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from LoopStructural.interpolators import (
77
GeologicalInterpolator,
88
InterpolatorFactory,
9+
InterpolatorType,
910
)
1011
from LoopStructural.utils import BoundingBox
1112
from LoopStructural.utils import getLogger
@@ -18,7 +19,7 @@ def __init__(
1819
self,
1920
bounding_box: BoundingBox,
2021
dimensions: int = 3,
21-
type: str = "FDI",
22+
type=InterpolatorType.FINITE_DIFFERENCE,
2223
nelements: int = 1000,
2324
):
2425
"""Scikitlearn like interface for LoopStructural interpolators

LoopStructural/api/_surface.py

Lines changed: 66 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
from typing import Optional, Union
1+
from typing import Optional, Union, Callable
22
import numpy as np
3+
import numpy.typing as npt
34
from LoopStructural.utils import getLogger
45

56
logger = getLogger(__name__)
@@ -13,23 +14,81 @@
1314
from LoopStructural.utils import BoundingBox
1415
from LoopStructural.datatypes import Surface
1516

16-
surface_list = dict[str, tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]]
17+
surface_list = dict[
18+
str, tuple[npt.ArrayLike, npt.ArrayLike, npt.ArrayLike, npt.ArrayLike]
19+
]
1720

1821

1922
class LoopIsosurfacer:
20-
def __init__(self, bounding_box: BoundingBox, interpolator: GeologicalInterpolator):
23+
def __init__(
24+
self,
25+
bounding_box: BoundingBox,
26+
interpolator: Optional[GeologicalInterpolator] = None,
27+
callable: Optional[Callable[[npt.ArrayLike], npt.ArrayLike]] = None,
28+
):
29+
"""Extract isosurfaces from a geological interpolator or a callable function.
30+
31+
32+
Parameters
33+
----------
34+
bounding_box : BoundingBox
35+
_description_
36+
interpolator : Optional[GeologicalInterpolator], optional
37+
interpolator object, by default None
38+
callable : Optional[Callable[[npt.ArrayLike], npt.ArrayLike]], optional
39+
callable object, by default None
40+
41+
Raises
42+
------
43+
ValueError
44+
_description_
45+
ValueError
46+
_description_
47+
ValueError
48+
_description_
49+
"""
2150
self.bounding_box = bounding_box
22-
self.interpolator = interpolator
51+
self.callable = callable
52+
if interpolator is None and callable is None:
53+
raise ValueError("Must specify either interpolator or callable")
54+
if interpolator is not None and self.callable is not None:
55+
raise ValueError("Must specify either interpolator or callable")
56+
57+
if interpolator is not None:
58+
self.callable = interpolator.evaluate_value
59+
if self.callable is None:
60+
raise ValueError("Must specify either interpolator or callable")
2361

2462
def fit(self, values: Union[list, int, float]) -> surface_list:
63+
"""Extract isosurfaces from the interpolator
64+
65+
Parameters
66+
----------
67+
values : Union[list, int, float]
68+
Either a list of values to extract isosurfaces for, or a single value
69+
to extract a single isosurface for, or an integer to extract that many
70+
isosurfaces evenly spaced between the minimum and maximum values of the
71+
interpolator.
72+
73+
Returns
74+
-------
75+
surface_list
76+
a dictionary containing the extracted isosurfaces
77+
"""
78+
if not callable(self.callable):
79+
raise ValueError("No interpolator of callable function set")
2580
surfaces = {}
26-
all_values = self.interpolator.evaluate_value(self.bounding_box.regular_grid())
81+
all_values = self.callable(self.bounding_box.regular_grid())
2782
if isinstance(values, list):
2883
isovalues = values
2984
elif isinstance(values, float):
3085
isovalues = [values]
3186
elif isinstance(values, int):
32-
isovalues = np.linspace(np.min(all_values), np.max(all_values), values)
87+
isovalues = np.linspace(
88+
np.min(all_values) + np.finfo(float).eps,
89+
np.max(all_values) + np.finfo(float).eps,
90+
values,
91+
)
3392
for isovalue in isovalues:
3493
verts, faces, normals, values = marching_cubes(
3594
all_values.reshape(self.bounding_box.nsteps, order="C"),
@@ -38,7 +97,7 @@ def fit(self, values: Union[list, int, float]) -> surface_list:
3897
)
3998
values = np.zeros(verts.shape[0]) + isovalue
4099
surfaces[f"surface_{isovalue}"] = Surface(
41-
vertices=verts,
100+
vertices=verts + self.bounding_box.origin,
42101
triangles=faces,
43102
normals=normals,
44103
name=f"surface_{isovalue}",

LoopStructural/api/model.py

Lines changed: 0 additions & 6 deletions
This file was deleted.

LoopStructural/datasets/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,4 @@
1919
from ._base import load_tabular_intrusion
2020
from ._base import load_geological_map_data
2121
from ._base import load_fault_trace
22+
from ._base import load_horizontal

LoopStructural/datasets/_base.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,46 @@
11
from os.path import dirname, join
22
from pathlib import Path
3+
from typing import Tuple
34
import numpy as np
45
import pandas as pd
56

67

8+
def load_horizontal() -> Tuple[pd.DataFrame, np.ndarray]:
9+
"""Synthetic model for horizontal layers
10+
11+
Returns
12+
-------
13+
Tuple[pd.DataFrame, np.ndarray]
14+
dataframe with feature_name 'strati', bounding box array
15+
"""
16+
bb = np.array([[0, 0, 0], [10, 10, 10]])
17+
xy = np.mgrid[0:10, 0:10].reshape(2, -1).T
18+
data = pd.DataFrame(
19+
np.vstack(
20+
[
21+
np.hstack(
22+
[
23+
xy,
24+
np.zeros(xy.shape[0])[:, None] + 2,
25+
np.zeros(xy.shape[0])[:, None] + 2,
26+
]
27+
),
28+
np.hstack(
29+
[
30+
xy,
31+
np.zeros(xy.shape[0])[:, None] + 3,
32+
np.zeros(xy.shape[0])[:, None] + 3,
33+
]
34+
),
35+
]
36+
),
37+
columns=["X", "Y", "Z", "val"],
38+
)
39+
40+
data["feature_name"] = "strati"
41+
return data, bb
42+
43+
744
def load_claudius():
845
"""Model dataset sampled from 3D seismic data
946

0 commit comments

Comments
 (0)