Skip to content

Commit ce978b8

Browse files
authored
Merge pull request #215 from GeoStat-Framework/rust-core
Add optional dependency GSTools-Core
2 parents 490ad20 + 0049a31 commit ce978b8

File tree

10 files changed

+99
-19
lines changed

10 files changed

+99
-19
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,15 @@
33
All notable changes to **GSTools** will be documented in this file.
44

55

6+
## [1.3.4] - Pure Pink ?
7+
8+
### Enhancements
9+
- add GStools-Core as optional dependency [#215](https://github.com/GeoStat-Framework/GSTools/pull/215)
10+
11+
### Changes
12+
- remove unnecessary `dim` argument in Cython code [#216](https://github.com/GeoStat-Framework/GSTools/issues/216)
13+
14+
615
## [1.3.3] - Pure Pink - 2021-08
716

817
### Enhancements

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,7 @@ in memory for immediate 3D plotting in Python.
345345

346346
### Optional
347347

348+
- [GSTools-Core >= 0.2.0](https://github.com/GeoStat-Framework/GSTools-Core)
348349
- [matplotlib](https://matplotlib.org)
349350
- [pyvista](https://docs.pyvista.org/)
350351

docs/source/index.rst

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ To get the latest development version you can install it directly from GitHub:
7070
7171
If something went wrong during installation, try the :code:`-I` `flag from pip <https://pip-python3.readthedocs.io/en/latest/reference/pip_install.html?highlight=i#cmdoption-i>`_.
7272

73+
**Speeding up GSTools by parallelization**
74+
7375
To enable the OpenMP support, you have to provide a C compiler and OpenMP.
7476
Parallel support is controlled by an environment variable ``GSTOOLS_BUILD_PARALLEL``,
7577
that can be ``0`` or ``1`` (interpreted as ``0`` if not present).
@@ -89,6 +91,33 @@ For the development version, you can do almost the same:
8991
export GSTOOLS_BUILD_PARALLEL=1
9092
pip install git+git://github.com/GeoStat-Framework/GSTools.git@main
9193
94+
**Using experimental GSTools-Core for even more speed**
95+
96+
You can install the optional dependency `GSTools-Core <https://github.com/GeoStat-Framework/GSTools-Core>`_,
97+
which is a re-implementation of the main algorithms used in GSTools. The new
98+
package uses the language Rust and it should be faster (in some cases by orders
99+
of magnitude), safer, and it will potentially completely replace the current
100+
standard implementation in Cython. Once the package GSTools-Core is available
101+
on your machine, it will be used by default. In case you want to switch back to
102+
the Cython implementation, you can set :code:`gstools.config.USE_RUST=False` in
103+
your code. This also works at runtime. You can install the optional dependency
104+
e.g. by
105+
106+
.. code-block:: none
107+
108+
pip install gstools[rust]
109+
110+
or by manually installing the package
111+
112+
.. code-block:: none
113+
114+
pip install gstools-core
115+
116+
GSTools-Core will automatically use all your cores in parallel, without having
117+
to use OpenMP or a local C compiler.
118+
In case you want to restrict the number of threads used, you can set the
119+
environment variable ``RAYON_NUM_THREADS`` to the desired amount.
120+
92121

93122
Citation
94123
========
@@ -387,6 +416,7 @@ Requirements
387416
Optional
388417
--------
389418

419+
- `GSTools-Core >= 0.2.0 <https://github.com/GeoStat-Framework/GSTools-Core>`_
390420
- `matplotlib <https://matplotlib.org>`_
391421
- `pyvista <https://docs.pyvista.org>`_
392422

gstools/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@
127127
"""
128128
# Hooray!
129129
from gstools import (
130+
config,
130131
covmodel,
131132
field,
132133
krige,

gstools/config.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# -*- coding: utf-8 -*-
2+
"""
3+
GStools subpackage providing global variables.
4+
5+
.. currentmodule:: gstools.config
6+
7+
"""
8+
# pylint: disable=W0611
9+
try: # pragma: no cover
10+
import gstools_core
11+
12+
USE_RUST = True
13+
except ImportError:
14+
USE_RUST = False

gstools/field/generator.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,22 @@
1010
RandMeth
1111
IncomprRandMeth
1212
"""
13-
# pylint: disable=C0103, W0222
13+
# pylint: disable=C0103, W0222, C0412
1414
import warnings
1515
from copy import deepcopy as dcp
1616

1717
import numpy as np
1818

19+
from gstools import config
1920
from gstools.covmodel.base import CovModel
20-
from gstools.field.summator import summate, summate_incompr
2121
from gstools.random.rng import RNG
2222

23+
if config.USE_RUST: # pragma: no cover
24+
# pylint: disable=E0401
25+
from gstools_core import summate, summate_incompr
26+
else:
27+
from gstools.field.summator import summate, summate_incompr
28+
2329
__all__ = ["RandMeth", "IncomprRandMeth"]
2430

2531

gstools/krige/base.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,29 @@
99
.. autosummary::
1010
Krige
1111
"""
12-
# pylint: disable=C0103, W0221, E1102, R0201
12+
# pylint: disable=C0103, W0221, E1102, R0201, C0412
1313
import collections
1414

1515
import numpy as np
1616
import scipy.linalg as spl
1717
from scipy.spatial.distance import cdist
1818

19+
from gstools import config
1920
from gstools.field.base import Field
20-
from gstools.krige.krigesum import (
21-
calc_field_krige,
22-
calc_field_krige_and_variance,
23-
)
2421
from gstools.krige.tools import get_drift_functions, set_condition
2522
from gstools.tools.geometric import rotated_main_axes
2623
from gstools.tools.misc import eval_func
2724
from gstools.variogram import vario_estimate
2825

26+
if config.USE_RUST: # pragma: no cover
27+
# pylint: disable=E0401
28+
from gstools_core import calc_field_krige, calc_field_krige_and_variance
29+
else:
30+
from gstools.krige.krigesum import (
31+
calc_field_krige,
32+
calc_field_krige_and_variance,
33+
)
34+
2935
__all__ = ["Krige"]
3036

3137

gstools/variogram/estimator.pyx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,6 @@ cdef _normalization_func_vec choose_estimator_normalization_vec(str estimator_ty
178178

179179

180180
def directional(
181-
const int dim,
182181
const double[:,:] f,
183182
const double[:] bin_edges,
184183
const double[:,:] pos,
@@ -203,6 +202,7 @@ def directional(
203202
choose_estimator_normalization_vec(estimator_type)
204203
)
205204

205+
cdef int dim = pos.shape[0]
206206
cdef int d_max = direction.shape[0]
207207
cdef int i_max = bin_edges.shape[0] - 1
208208
cdef int j_max = pos.shape[1] - 1
@@ -237,13 +237,13 @@ def directional(
237237
return np.asarray(variogram), np.asarray(counts)
238238

239239
def unstructured(
240-
const int dim,
241240
const double[:,:] f,
242241
const double[:] bin_edges,
243242
const double[:,:] pos,
244243
str estimator_type='m',
245244
str distance_type='e',
246245
):
246+
cdef int dim = pos.shape[0]
247247
cdef _dist_func distance
248248

249249
if distance_type == 'e':

gstools/variogram/variogram.py

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@
1010
vario_estimate
1111
vario_estimate_axis
1212
"""
13+
# pylint: disable=C0412
1314
import numpy as np
1415

16+
from gstools import config
1517
from gstools.normalizer.tools import remove_trend_norm_mean
1618
from gstools.tools.geometric import (
1719
ang2dir,
@@ -20,12 +22,20 @@
2022
generate_grid,
2123
)
2224
from gstools.variogram.binning import standard_bins
23-
from gstools.variogram.estimator import (
24-
directional,
25-
ma_structured,
26-
structured,
27-
unstructured,
28-
)
25+
26+
if config.USE_RUST: # pragma: no cover
27+
# pylint: disable=E0401
28+
from gstools_core import variogram_directional as directional
29+
from gstools_core import variogram_ma_structured as ma_structured
30+
from gstools_core import variogram_structured as structured
31+
from gstools_core import variogram_unstructured as unstructured
32+
else:
33+
from gstools.variogram.estimator import (
34+
directional,
35+
ma_structured,
36+
structured,
37+
unstructured,
38+
)
2939

3040
__all__ = [
3141
"vario_estimate",
@@ -59,7 +69,8 @@ def _separate_dirs_test(direction, angles_tol):
5969
for j in range(i + 1, direction.shape[0]):
6070
s_prod = np.minimum(np.abs(np.dot(direction[i], direction[j])), 1)
6171
separate_dirs &= np.arccos(s_prod) >= 2 * angles_tol
62-
return separate_dirs
72+
# gstools-core doesn't like the type `numpy.bool_`
73+
return bool(separate_dirs)
6374

6475

6576
def vario_estimate(
@@ -341,7 +352,6 @@ def vario_estimate(
341352
# "h"aversine or "e"uclidean distance type
342353
distance_type = "h" if latlon else "e"
343354
estimates, counts = unstructured(
344-
dim,
345355
field,
346356
bin_edges,
347357
pos,
@@ -350,7 +360,6 @@ def vario_estimate(
350360
)
351361
else:
352362
estimates, counts = directional(
353-
dim,
354363
field,
355364
bin_edges,
356365
pos,
@@ -441,7 +450,9 @@ def vario_estimate_axis(
441450
field = np.ma.array(field, ndmin=1, dtype=np.double)
442451
if missing:
443452
field.mask = np.logical_or(field.mask, missing_mask)
444-
mask = np.asarray(np.ma.getmaskarray(field), dtype=np.int32)
453+
mask = np.ma.getmaskarray(field)
454+
if not config.USE_RUST:
455+
mask = np.asarray(mask, dtype=np.int32)
445456
else:
446457
field = np.array(field, ndmin=1, dtype=np.double, copy=False)
447458
missing_mask = None # free space

setup.cfg

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ doc =
6666
plotting =
6767
matplotlib>=3,<4
6868
pyvista>=0.29,<1
69+
rust =
70+
gstools_core>=0.2.0,<1
6971
test =
7072
coverage[toml]>=5.2.1,<6
7173
pytest>=6.0,<7

0 commit comments

Comments
 (0)