From 51ab73266d5d6f526fb50627260f38d9278ed4e7 Mon Sep 17 00:00:00 2001 From: LSchueler Date: Thu, 4 Jul 2024 16:52:00 +0200 Subject: [PATCH 01/11] Drop deprecated conditional compilation --- src/gstools/field/summator.pyx | 6 +++--- src/gstools/krige/krigesum.pyx | 6 +++--- src/gstools/variogram/estimator.pyx | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/gstools/field/summator.pyx b/src/gstools/field/summator.pyx index 8f6c6f7f8..5af23b911 100644 --- a/src/gstools/field/summator.pyx +++ b/src/gstools/field/summator.pyx @@ -6,7 +6,7 @@ This is the randomization method summator, implemented in cython. import numpy as np from cython.parallel import prange -IF OPENMP: +if OPENMP: cimport openmp cimport numpy as np @@ -17,9 +17,9 @@ def set_num_threads(num_threads): cdef int num_threads_c = 1 if num_threads is None: # OPENMP set during setup - IF OPENMP: + if OPENMP: num_threads_c = openmp.omp_get_num_procs() - ELSE: + else: ... else: num_threads_c = num_threads diff --git a/src/gstools/krige/krigesum.pyx b/src/gstools/krige/krigesum.pyx index 7611f4a0a..9a37d2af6 100644 --- a/src/gstools/krige/krigesum.pyx +++ b/src/gstools/krige/krigesum.pyx @@ -6,7 +6,7 @@ This is a summator for the kriging routines import numpy as np from cython.parallel import prange -IF OPENMP: +if OPENMP: cimport openmp cimport numpy as np @@ -16,9 +16,9 @@ def set_num_threads(num_threads): cdef int num_threads_c = 1 if num_threads is None: # OPENMP set during setup - IF OPENMP: + if OPENMP: num_threads_c = openmp.omp_get_num_procs() - ELSE: + else: ... else: num_threads_c = num_threads diff --git a/src/gstools/variogram/estimator.pyx b/src/gstools/variogram/estimator.pyx index e00824be7..f1e9bd399 100644 --- a/src/gstools/variogram/estimator.pyx +++ b/src/gstools/variogram/estimator.pyx @@ -7,7 +7,7 @@ This is the variogram estimater, implemented in cython. import numpy as np from cython.parallel import parallel, prange -IF OPENMP: +if OPENMP: cimport openmp cimport numpy as np @@ -18,9 +18,9 @@ def set_num_threads(num_threads): cdef int num_threads_c = 1 if num_threads is None: # OPENMP set during setup - IF OPENMP: + if OPENMP: num_threads_c = openmp.omp_get_num_procs() - ELSE: + else: ... else: num_threads_c = num_threads From 8fbe2ec98dc06bede24b950be843284ffac5c2c2 Mon Sep 17 00:00:00 2001 From: LSchueler Date: Fri, 5 Jul 2024 16:14:07 +0200 Subject: [PATCH 02/11] Fix the Cython-/Rust switch, update readmes --- README.md | 3 +++ docs/source/index.rst | 34 +++++++++++++++------------- src/gstools/config.py | 6 +++-- src/gstools/field/generator.py | 26 +++++++++++++++------ src/gstools/krige/base.py | 33 +++++++++++++++++++-------- src/gstools/variogram/variogram.py | 36 +++++++++++++++++++----------- 6 files changed, 92 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index 6cb699019..fd5baf639 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,9 @@ running. Install the package by typing the following command in a command termin To install the latest development version via pip, see the [documentation][doc_install_link]. +One thing to point out is that this way, the non-parallel version of GSTools +is installed. In case you want the parallel version, follow these easy +[steps][doc_install_link]. ## Citation diff --git a/docs/source/index.rst b/docs/source/index.rst index ecad05830..284e93293 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -79,17 +79,24 @@ If something went wrong during installation, try the :code:`-I` `flag from pip < **Speeding up GSTools by parallelization** -To enable the OpenMP support, you have to provide a C compiler and OpenMP. -Parallel support is controlled by an environment variable ``GSTOOLS_BUILD_PARALLEL``, -that can be ``0`` or ``1`` (interpreted as ``0`` if not present). -GSTools then needs to be installed from source: +We provide two possibilities to run GSTools in parallel, often causing a +massive improvement in runtime. In either case, the number of parallel +threads can be set with the global variable `config.NUM_THREADS`. + +***Parallelizing Cython*** + +To enable the OpenMP support in Cython, you have to provide a C compiler and +OpenMP. Parallel support is controlled by an environment variable +``GSTOOLS_BUILD_PARALLEL``, that can be ``0`` or ``1`` (interpreted as ``0`` +if not present). GSTools then needs to be installed from source: .. code-block:: none export GSTOOLS_BUILD_PARALLEL=1 pip install --no-binary=gstools gstools -Note, that the ``--no-binary=gstools`` option forces pip to not use a wheel for GSTools. +Note, that the ``--no-binary=gstools`` option forces pip to not use a wheel +for GSTools. For the development version, you can do almost the same: @@ -98,19 +105,18 @@ For the development version, you can do almost the same: export GSTOOLS_BUILD_PARALLEL=1 pip install git+git://github.com/GeoStat-Framework/GSTools.git@main -The number of parallel threads can be set with the global variable `config.NUM_THREADS`. -**Using experimental GSTools-Core for even more speed** +***Using GSTools-Core for parallelization and even more speed*** You can install the optional dependency `GSTools-Core `_, -which is a re-implementation of the main algorithms used in GSTools. The new +which is a re-implementation of the algorithms used in GSTools. The new package uses the language Rust and it should be faster (in some cases by orders of magnitude), safer, and it will potentially completely replace the current standard implementation in Cython. Once the package GSTools-Core is available on your machine, it will be used by default. In case you want to switch back to -the Cython implementation, you can set :code:`gstools.config.USE_RUST=False` in -your code. This also works at runtime. You can install the optional dependency -e.g. by +the Cython implementation, you can set +:code:`gstools.config.USE_GSTOOLS_CORE=False` in your code. This also works at +runtime. You can install the optional dependency e.g. by .. code-block:: none @@ -122,10 +128,8 @@ or by manually installing the package pip install gstools-core -GSTools-Core will automatically use all your cores in parallel, without having -to use OpenMP or a local C compiler. -In case you want to restrict the number of threads used, you can use the -global variable `config.NUM_THREADS` to the desired number. +GSTools-Core will automatically run in parallel, without having to use provide +OpenMP or a local C compiler. Citation diff --git a/src/gstools/config.py b/src/gstools/config.py index 24ce20c7e..9c399f687 100644 --- a/src/gstools/config.py +++ b/src/gstools/config.py @@ -11,6 +11,8 @@ try: # pragma: no cover import gstools_core - USE_RUST = True + _GSTOOLS_CORE_AVAIL = True + USE_GSTOOLS_CORE = True except ImportError: - USE_RUST = False + _GSTOOLS_CORE_AVAIL = False + USE_GSTOOLS_CORE = False diff --git a/src/gstools/field/generator.py b/src/gstools/field/generator.py index 5beab10db..7a5c74690 100644 --- a/src/gstools/field/generator.py +++ b/src/gstools/field/generator.py @@ -24,11 +24,15 @@ from gstools.covmodel.base import CovModel from gstools.random.rng import RNG -if config.USE_RUST: # pragma: no cover +if config._GSTOOLS_CORE_AVAIL: # pragma: no cover # pylint: disable=E0401 - from gstools_core import summate, summate_incompr -else: - from gstools.field.summator import summate, summate_incompr + from gstools_core import ( + summate as summate_gsc, + summate_incompr as summate_incompr_gsc, + ) + +from gstools.field.summator import summate as summate_c +from gstools.field.summator import summate_incompr as summate_incompr_c __all__ = ["Generator", "RandMeth", "IncomprRandMeth"] @@ -194,8 +198,8 @@ def __init__( def __call__(self, pos, add_nugget=True): """Calculate the random modes for the randomization method. - This method calls the `summate_*` Cython methods, which are the - heart of the randomization method. + This method calls the `summate_*` Rust or Cython methods, which are + the heart of the randomization method. Parameters ---------- @@ -209,6 +213,10 @@ def __call__(self, pos, add_nugget=True): :class:`numpy.ndarray` the random modes """ + if config.USE_GSTOOLS_CORE and config._GSTOOLS_CORE_AVAIL: + summate = summate_gsc + else: + summate = summate_c pos = np.asarray(pos, dtype=np.double) summed_modes = summate( self._cov_sample, self._z_1, self._z_2, pos, config.NUM_THREADS @@ -473,7 +481,7 @@ def __init__( def __call__(self, pos, add_nugget=True): """Calculate the random modes for the randomization method. - This method calls the `summate_incompr_*` Cython methods, + This method calls the `summate_incompr_*` Rust or Cython methods, which are the heart of the randomization method. In this class the method contains a projector to ensure the incompressibility of the vector field. @@ -490,6 +498,10 @@ def __call__(self, pos, add_nugget=True): :class:`numpy.ndarray` the random modes """ + if config.USE_GSTOOLS_CORE and config._GSTOOLS_CORE_AVAIL: + summate_incompr = summate_incompr_gsc + else: + summate_incompr = summate_incompr_c pos = np.asarray(pos, dtype=np.double) summed_modes = summate_incompr( self._cov_sample, diff --git a/src/gstools/krige/base.py b/src/gstools/krige/base.py index 78aa2a9f7..edf3130ca 100755 --- a/src/gstools/krige/base.py +++ b/src/gstools/krige/base.py @@ -23,15 +23,18 @@ from gstools.tools.misc import eval_func from gstools.variogram import vario_estimate -if config.USE_RUST: # pragma: no cover +if config._GSTOOLS_CORE_AVAIL: # pragma: no cover # pylint: disable=E0401 - from gstools_core import calc_field_krige, calc_field_krige_and_variance -else: - from gstools.krige.krigesum import ( - calc_field_krige, - calc_field_krige_and_variance, + from gstools_core import ( + calc_field_krige as calc_field_krige_gsc, + calc_field_krige_and_variance as calc_field_krige_and_variance_gsc, ) +from gstools.krige.krigesum import calc_field_krige as calc_field_krige_c +from gstools.krige.krigesum import ( + calc_field_krige_and_variance as calc_field_krige_and_variance_c, +) + __all__ = ["Krige"] @@ -237,6 +240,16 @@ def __call__( the kriging error variance (if return_var is True and only_mean is False) """ + if config.USE_GSTOOLS_CORE and config._GSTOOLS_CORE_AVAIL: + self._calc_field_krige = calc_field_krige_gsc + self._calc_field_krige_and_variance = ( + calc_field_krige_and_variance_gsc + ) + else: + self._calc_field_krige = calc_field_krige_c + self._calc_field_krige_and_variance = ( + calc_field_krige_and_variance_c + ) return_var &= not only_mean # don't return variance when calc. mean fld_cnt = 2 if return_var else 1 default = self.default_field_names[2] if only_mean else None @@ -284,11 +297,13 @@ def __call__( def _summate(self, field, krige_var, c_slice, k_vec, return_var): if return_var: # estimate error variance - field[c_slice], krige_var[c_slice] = calc_field_krige_and_variance( - self._krige_mat, k_vec, self._krige_cond + field[c_slice], krige_var[c_slice] = ( + self._calc_field_krige_and_variance( + self._krige_mat, k_vec, self._krige_cond + ) ) else: # solely calculate the interpolated field - field[c_slice] = calc_field_krige( + field[c_slice] = self._calc_field_krige( self._krige_mat, k_vec, self._krige_cond ) diff --git a/src/gstools/variogram/variogram.py b/src/gstools/variogram/variogram.py index afcf336f4..adc25d703 100644 --- a/src/gstools/variogram/variogram.py +++ b/src/gstools/variogram/variogram.py @@ -24,19 +24,17 @@ ) from gstools.variogram.binning import standard_bins -if config.USE_RUST: # pragma: no cover +if config._GSTOOLS_CORE_AVAIL: # pragma: no cover # pylint: disable=E0401 - from gstools_core import variogram_directional as directional - from gstools_core import variogram_ma_structured as ma_structured - from gstools_core import variogram_structured as structured - from gstools_core import variogram_unstructured as unstructured -else: - from gstools.variogram.estimator import ( - directional, - ma_structured, - structured, - unstructured, - ) + from gstools_core import variogram_directional as directional_gsc + from gstools_core import variogram_ma_structured as ma_structured_gsc + from gstools_core import variogram_structured as structured_gsc + from gstools_core import variogram_unstructured as unstructured_gsc + +from gstools.variogram.estimator import directional as directional_c +from gstools.variogram.estimator import ma_structured as ma_structured_c +from gstools.variogram.estimator import structured as structured_c +from gstools.variogram.estimator import unstructured as unstructured_c __all__ = [ "vario_estimate", @@ -366,6 +364,12 @@ def vario_estimate( # select variogram estimator cython_estimator = _set_estimator(estimator) # run + if config.USE_GSTOOLS_CORE and config._GSTOOLS_CORE_AVAIL: + unstructured = unstructured_gsc + directional = directional_gsc + else: + unstructured = unstructured_c + directional = directional_c if dir_no == 0: # "h"aversine or "e"uclidean distance type distance_type = "h" if latlon else "e" @@ -471,7 +475,7 @@ def vario_estimate_axis( if missing: field.mask = np.logical_or(field.mask, missing_mask) mask = np.ma.getmaskarray(field) - if not config.USE_RUST: + if not config.USE_GSTOOLS_CORE and config._GSTOOLS_CORE_AVAIL: mask = np.asarray(mask, dtype=np.int32) else: field = np.atleast_1d(np.asarray(field, dtype=np.double)) @@ -487,6 +491,12 @@ def vario_estimate_axis( cython_estimator = _set_estimator(estimator) + if config.USE_GSTOOLS_CORE and config._GSTOOLS_CORE_AVAIL: + ma_structured = ma_structured_gsc + structured = structured_gsc + else: + ma_structured = ma_structured_c + structured = structured_c if masked: return ma_structured( field, mask, cython_estimator, num_threads=config.NUM_THREADS From 5e89b43873b06bd3c0f3cfa948cc37b9f9eb56f9 Mon Sep 17 00:00:00 2001 From: LSchueler Date: Fri, 5 Jul 2024 16:46:23 +0200 Subject: [PATCH 03/11] Satisfy pylint --- src/gstools/field/generator.py | 21 +++++++++--------- src/gstools/krige/base.py | 35 ++++++++++++++++++------------ src/gstools/variogram/variogram.py | 31 +++++++++++++++----------- 3 files changed, 49 insertions(+), 38 deletions(-) diff --git a/src/gstools/field/generator.py b/src/gstools/field/generator.py index 7a5c74690..7cb10355d 100644 --- a/src/gstools/field/generator.py +++ b/src/gstools/field/generator.py @@ -22,17 +22,14 @@ from gstools import config from gstools.covmodel.base import CovModel +from gstools.field.summator import summate as summate_c +from gstools.field.summator import summate_incompr as summate_incompr_c from gstools.random.rng import RNG -if config._GSTOOLS_CORE_AVAIL: # pragma: no cover +if config._GSTOOLS_CORE_AVAIL: # pylint: disable=W0212; # pragma: no cover # pylint: disable=E0401 - from gstools_core import ( - summate as summate_gsc, - summate_incompr as summate_incompr_gsc, - ) - -from gstools.field.summator import summate as summate_c -from gstools.field.summator import summate_incompr as summate_incompr_c + from gstools_core import summate as summate_gsc + from gstools_core import summate_incompr as summate_incompr_gsc __all__ = ["Generator", "RandMeth", "IncomprRandMeth"] @@ -213,8 +210,10 @@ def __call__(self, pos, add_nugget=True): :class:`numpy.ndarray` the random modes """ - if config.USE_GSTOOLS_CORE and config._GSTOOLS_CORE_AVAIL: - summate = summate_gsc + if ( + config.USE_GSTOOLS_CORE and config._GSTOOLS_CORE_AVAIL + ): # pylint: disable=W0212 + summate = summate_gsc # pylint: disable=E0606 else: summate = summate_c pos = np.asarray(pos, dtype=np.double) @@ -499,7 +498,7 @@ def __call__(self, pos, add_nugget=True): the random modes """ if config.USE_GSTOOLS_CORE and config._GSTOOLS_CORE_AVAIL: - summate_incompr = summate_incompr_gsc + summate_incompr = summate_incompr_gsc # pylint: disable=E0606 else: summate_incompr = summate_incompr_c pos = np.asarray(pos, dtype=np.double) diff --git a/src/gstools/krige/base.py b/src/gstools/krige/base.py index edf3130ca..4f4ef78a7 100755 --- a/src/gstools/krige/base.py +++ b/src/gstools/krige/base.py @@ -18,22 +18,23 @@ from gstools import config from gstools.field.base import Field +from gstools.krige.krigesum import calc_field_krige as calc_field_krige_c +from gstools.krige.krigesum import ( + calc_field_krige_and_variance as calc_field_krige_and_variance_c, +) from gstools.krige.tools import get_drift_functions, set_condition from gstools.tools.geometric import rotated_main_axes from gstools.tools.misc import eval_func from gstools.variogram import vario_estimate -if config._GSTOOLS_CORE_AVAIL: # pragma: no cover +if config._GSTOOLS_CORE_AVAIL: # pylint: disable=W0212; # pragma: no cover # pylint: disable=E0401 from gstools_core import ( - calc_field_krige as calc_field_krige_gsc, - calc_field_krige_and_variance as calc_field_krige_and_variance_gsc, + calc_field_krige as calc_field_krige_gsc, # pylint: disable=E0606 + ) + from gstools_core import ( + calc_field_krige_and_variance as calc_field_krige_and_variance_gsc, # pylint: disable=E0606 ) - -from gstools.krige.krigesum import calc_field_krige as calc_field_krige_c -from gstools.krige.krigesum import ( - calc_field_krige_and_variance as calc_field_krige_and_variance_c, -) __all__ = ["Krige"] @@ -240,14 +241,20 @@ def __call__( the kriging error variance (if return_var is True and only_mean is False) """ - if config.USE_GSTOOLS_CORE and config._GSTOOLS_CORE_AVAIL: - self._calc_field_krige = calc_field_krige_gsc - self._calc_field_krige_and_variance = ( - calc_field_krige_and_variance_gsc + if ( + config.USE_GSTOOLS_CORE and config._GSTOOLS_CORE_AVAIL + ): # pylint: disable=W0212 + self._calc_field_krige = ( + calc_field_krige_gsc # pylint: disable=E0606, W0201 + ) + self._calc_field_krige_and_variance = ( # pylint: disable=W0201 + calc_field_krige_and_variance_gsc # pylint: disable=E0606 ) else: - self._calc_field_krige = calc_field_krige_c - self._calc_field_krige_and_variance = ( + self._calc_field_krige = ( + calc_field_krige_c # pylint: disable=W0201 + ) + self._calc_field_krige_and_variance = ( # pylint: disable=W0201 calc_field_krige_and_variance_c ) return_var &= not only_mean # don't return variance when calc. mean diff --git a/src/gstools/variogram/variogram.py b/src/gstools/variogram/variogram.py index adc25d703..f44d0656c 100644 --- a/src/gstools/variogram/variogram.py +++ b/src/gstools/variogram/variogram.py @@ -23,19 +23,18 @@ generate_grid, ) from gstools.variogram.binning import standard_bins +from gstools.variogram.estimator import directional as directional_c +from gstools.variogram.estimator import ma_structured as ma_structured_c +from gstools.variogram.estimator import structured as structured_c +from gstools.variogram.estimator import unstructured as unstructured_c -if config._GSTOOLS_CORE_AVAIL: # pragma: no cover +if config._GSTOOLS_CORE_AVAIL: # pylint: disable=W0212; # pragma: no cover # pylint: disable=E0401 from gstools_core import variogram_directional as directional_gsc from gstools_core import variogram_ma_structured as ma_structured_gsc from gstools_core import variogram_structured as structured_gsc from gstools_core import variogram_unstructured as unstructured_gsc -from gstools.variogram.estimator import directional as directional_c -from gstools.variogram.estimator import ma_structured as ma_structured_c -from gstools.variogram.estimator import structured as structured_c -from gstools.variogram.estimator import unstructured as unstructured_c - __all__ = [ "vario_estimate", "vario_estimate_axis", @@ -364,9 +363,11 @@ def vario_estimate( # select variogram estimator cython_estimator = _set_estimator(estimator) # run - if config.USE_GSTOOLS_CORE and config._GSTOOLS_CORE_AVAIL: - unstructured = unstructured_gsc - directional = directional_gsc + if ( + config.USE_GSTOOLS_CORE and config._GSTOOLS_CORE_AVAIL + ): # pylint: disable=W0212 + unstructured = unstructured_gsc # pylint: disable=E0606 + directional = directional_gsc # pylint: disable=E0606 else: unstructured = unstructured_c directional = directional_c @@ -475,7 +476,9 @@ def vario_estimate_axis( if missing: field.mask = np.logical_or(field.mask, missing_mask) mask = np.ma.getmaskarray(field) - if not config.USE_GSTOOLS_CORE and config._GSTOOLS_CORE_AVAIL: + if ( + not config.USE_GSTOOLS_CORE and config._GSTOOLS_CORE_AVAIL + ): # pylint: disable=W0212 mask = np.asarray(mask, dtype=np.int32) else: field = np.atleast_1d(np.asarray(field, dtype=np.double)) @@ -491,9 +494,11 @@ def vario_estimate_axis( cython_estimator = _set_estimator(estimator) - if config.USE_GSTOOLS_CORE and config._GSTOOLS_CORE_AVAIL: - ma_structured = ma_structured_gsc - structured = structured_gsc + if ( + config.USE_GSTOOLS_CORE and config._GSTOOLS_CORE_AVAIL + ): # pylint: disable=W0212 + ma_structured = ma_structured_gsc # pylint: disable=E0606 + structured = structured_gsc # pylint: disable=E0606 else: ma_structured = ma_structured_c structured = structured_c From 1307799d288a402160e703cc58bff204573ff14e Mon Sep 17 00:00:00 2001 From: LSchueler Date: Mon, 8 Jul 2024 13:30:35 +0200 Subject: [PATCH 04/11] Fix cython's buf. mismatch with numpy's 8bit bools --- src/gstools/variogram/estimator.pyx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/gstools/variogram/estimator.pyx b/src/gstools/variogram/estimator.pyx index f1e9bd399..c19093ebe 100644 --- a/src/gstools/variogram/estimator.pyx +++ b/src/gstools/variogram/estimator.pyx @@ -13,6 +13,9 @@ if OPENMP: cimport numpy as np from libc.math cimport M_PI, acos, atan2, cos, fabs, isnan, pow, sin, sqrt +# numpy's "bool" +ctypedef unsigned char uint8 + def set_num_threads(num_threads): cdef int num_threads_c = 1 @@ -342,7 +345,7 @@ def structured( def ma_structured( const double[:, :] f, - const bint[:, :] mask, + uint8[:, :] mask, # numpy's bools are 8bit vars str estimator_type='m', num_threads=None, ): @@ -365,7 +368,7 @@ def ma_structured( for i in range(i_max): for j in range(j_max): for k in prange(1, k_max-i): - if not mask[i, j] and not mask[i+k, j]: + if mask[i, j] == 0 and mask[i+k, j] == 0: counts[k] += 1 variogram[k] += estimator_func(f[i, j] - f[i+k, j]) From cbc7cb8558bf34cc0a0b0d3a6769bbf5ffdb2752 Mon Sep 17 00:00:00 2001 From: LSchueler Date: Mon, 8 Jul 2024 13:44:53 +0200 Subject: [PATCH 05/11] Disable warnings --- src/gstools/krige/base.py | 8 ++++---- src/gstools/variogram/estimator.pyx | 2 +- src/gstools/variogram/variogram.py | 9 ++++++--- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/gstools/krige/base.py b/src/gstools/krige/base.py index 4f4ef78a7..c8ffeee57 100755 --- a/src/gstools/krige/base.py +++ b/src/gstools/krige/base.py @@ -244,15 +244,15 @@ def __call__( if ( config.USE_GSTOOLS_CORE and config._GSTOOLS_CORE_AVAIL ): # pylint: disable=W0212 - self._calc_field_krige = ( - calc_field_krige_gsc # pylint: disable=E0606, W0201 + self._calc_field_krige = ( # pylint: disable=W0201 + calc_field_krige_gsc # pylint: disable=E0606 ) self._calc_field_krige_and_variance = ( # pylint: disable=W0201 calc_field_krige_and_variance_gsc # pylint: disable=E0606 ) else: - self._calc_field_krige = ( - calc_field_krige_c # pylint: disable=W0201 + self._calc_field_krige = ( # pylint: disable=W0201 + calc_field_krige_c ) self._calc_field_krige_and_variance = ( # pylint: disable=W0201 calc_field_krige_and_variance_c diff --git a/src/gstools/variogram/estimator.pyx b/src/gstools/variogram/estimator.pyx index c19093ebe..9387aa82a 100644 --- a/src/gstools/variogram/estimator.pyx +++ b/src/gstools/variogram/estimator.pyx @@ -345,7 +345,7 @@ def structured( def ma_structured( const double[:, :] f, - uint8[:, :] mask, # numpy's bools are 8bit vars + uint8[:, :] mask, # numpy's bools are 8bit vars str estimator_type='m', num_threads=None, ): diff --git a/src/gstools/variogram/variogram.py b/src/gstools/variogram/variogram.py index f44d0656c..fac50fb1e 100644 --- a/src/gstools/variogram/variogram.py +++ b/src/gstools/variogram/variogram.py @@ -364,7 +364,8 @@ def vario_estimate( cython_estimator = _set_estimator(estimator) # run if ( - config.USE_GSTOOLS_CORE and config._GSTOOLS_CORE_AVAIL + config.USE_GSTOOLS_CORE + and config._GSTOOLS_CORE_AVAIL # pylint: disable=W0212 ): # pylint: disable=W0212 unstructured = unstructured_gsc # pylint: disable=E0606 directional = directional_gsc # pylint: disable=E0606 @@ -477,7 +478,8 @@ def vario_estimate_axis( field.mask = np.logical_or(field.mask, missing_mask) mask = np.ma.getmaskarray(field) if ( - not config.USE_GSTOOLS_CORE and config._GSTOOLS_CORE_AVAIL + not config.USE_GSTOOLS_CORE + and config._GSTOOLS_CORE_AVAIL # pylint: disable=W0212 ): # pylint: disable=W0212 mask = np.asarray(mask, dtype=np.int32) else: @@ -495,7 +497,8 @@ def vario_estimate_axis( cython_estimator = _set_estimator(estimator) if ( - config.USE_GSTOOLS_CORE and config._GSTOOLS_CORE_AVAIL + config.USE_GSTOOLS_CORE + and config._GSTOOLS_CORE_AVAIL # pylint: disable=W0212 ): # pylint: disable=W0212 ma_structured = ma_structured_gsc # pylint: disable=E0606 structured = structured_gsc # pylint: disable=E0606 From 574845bdae632e2c7cd85dd9a76e2681da20b7fc Mon Sep 17 00:00:00 2001 From: LSchueler Date: Mon, 8 Jul 2024 13:59:17 +0200 Subject: [PATCH 06/11] Improve readme --- docs/source/index.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/source/index.rst b/docs/source/index.rst index 284e93293..0f5e181f8 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -81,12 +81,14 @@ If something went wrong during installation, try the :code:`-I` `flag from pip < We provide two possibilities to run GSTools in parallel, often causing a massive improvement in runtime. In either case, the number of parallel -threads can be set with the global variable `config.NUM_THREADS`. +threads can be set with the global variable `config.NUM_THREADS`. If not set, +all cores are used. +When using conda, the parallel version of GSTools is installed per default. ***Parallelizing Cython*** -To enable the OpenMP support in Cython, you have to provide a C compiler and -OpenMP. Parallel support is controlled by an environment variable +To enable the OpenMP support in Cython when using pip, you have to provide a C +compiler and OpenMP. Parallel support is controlled by an environment variable ``GSTOOLS_BUILD_PARALLEL``, that can be ``0`` or ``1`` (interpreted as ``0`` if not present). GSTools then needs to be installed from source: From 4854aec997918e524e96ffe8e8776c78d3452d7e Mon Sep 17 00:00:00 2001 From: LSchueler Date: Fri, 12 Jul 2024 14:34:25 +0200 Subject: [PATCH 07/11] Move messy wrapper stuff to separate fct's. --- src/gstools/field/generator.py | 52 +++++++++-- src/gstools/krige/base.py | 76 +++++++++++----- src/gstools/variogram/variogram.py | 141 +++++++++++++++++++++++++---- 3 files changed, 220 insertions(+), 49 deletions(-) diff --git a/src/gstools/field/generator.py b/src/gstools/field/generator.py index 7cb10355d..89f2d539f 100644 --- a/src/gstools/field/generator.py +++ b/src/gstools/field/generator.py @@ -37,6 +37,48 @@ SAMPLING = ["auto", "inversion", "mcmc"] +def summate(cov_samples, z_1, z_2, pos, num_threads=config.NUM_THREADS): + """ + A wrapper function for calling the randomization algorithm. + + See :any:`Generator` for more details. + + Notes + ----- + Most of the time, this should not be called directly. + """ + if ( + config.USE_GSTOOLS_CORE + and config._GSTOOLS_CORE_AVAIL # pylint: disable=W0212 + ): + summate_fct = summate_gsc # pylint: disable=E0606 + else: + summate_fct = summate_c + return summate_fct(cov_samples, z_1, z_2, pos, num_threads) + + +def summate_incompr( + cov_samples, z_1, z_2, pos, num_threads=config.NUM_THREADS +): + """ + A wrapper function for calling the incompressible randomization algorithm. + + See :any:`Generator` for more details. + + Notes + ----- + Most of the time, this should not be called directly. + """ + if ( + config.USE_GSTOOLS_CORE + and config._GSTOOLS_CORE_AVAIL # pylint: disable=W0212 + ): + summate_incompr_fct = summate_incompr_gsc # pylint: disable=E0606 + else: + summate_incompr_fct = summate_incompr_c + return summate_incompr_fct(cov_samples, z_1, z_2, pos, num_threads) + + class Generator(ABC): """ Abstract generator class. @@ -210,12 +252,6 @@ def __call__(self, pos, add_nugget=True): :class:`numpy.ndarray` the random modes """ - if ( - config.USE_GSTOOLS_CORE and config._GSTOOLS_CORE_AVAIL - ): # pylint: disable=W0212 - summate = summate_gsc # pylint: disable=E0606 - else: - summate = summate_c pos = np.asarray(pos, dtype=np.double) summed_modes = summate( self._cov_sample, self._z_1, self._z_2, pos, config.NUM_THREADS @@ -497,10 +533,6 @@ def __call__(self, pos, add_nugget=True): :class:`numpy.ndarray` the random modes """ - if config.USE_GSTOOLS_CORE and config._GSTOOLS_CORE_AVAIL: - summate_incompr = summate_incompr_gsc # pylint: disable=E0606 - else: - summate_incompr = summate_incompr_c pos = np.asarray(pos, dtype=np.double) summed_modes = summate_incompr( self._cov_sample, diff --git a/src/gstools/krige/base.py b/src/gstools/krige/base.py index c8ffeee57..44d70b94a 100755 --- a/src/gstools/krige/base.py +++ b/src/gstools/krige/base.py @@ -43,6 +43,58 @@ """dict: Standard pseudo-inverse routines""" +def calc_field_krige( + krig_mat, krig_vecs, cond, num_threads=config.NUM_THREADS +): + """ + A wrapper function for calling the krige algorithm. + + See :any:`Krige` for more details. + + Notes + ----- + Most of the time, this should not be called directly. + """ + if ( + config.USE_GSTOOLS_CORE + and config._GSTOOLS_CORE_AVAIL # pylint: disable=W0212 + ): # pylint: disable=W0212 + calc_field_krige_fct = ( # pylint: disable=W0201 + calc_field_krige_gsc # pylint: disable=E0606 + ) + else: + calc_field_krige_fct = calc_field_krige_c # pylint: disable=W0201 + return calc_field_krige_fct(krig_mat, krig_vecs, cond, num_threads) + + +def calc_field_krige_and_variance( + krig_mat, krig_vecs, cond, num_threads=config.NUM_THREADS +): + """ + A wrapper function for calling the krige algorithm. + + See :any:`Krige` for more details. + + Notes + ----- + Most of the time, this should not be called directly. + """ + if ( + config.USE_GSTOOLS_CORE + and config._GSTOOLS_CORE_AVAIL # pylint: disable=W0212 + ): + calc_field_krige_and_variance_fct = ( # pylint: disable=W0201 + calc_field_krige_and_variance_gsc # pylint: disable=E0606 + ) + else: + calc_field_krige_and_variance_fct = ( # pylint: disable=W0201 + calc_field_krige_and_variance_c + ) + return calc_field_krige_and_variance_fct( + krig_mat, krig_vecs, cond, num_threads + ) + + class Krige(Field): """ A Swiss Army knife for kriging. @@ -241,22 +293,6 @@ def __call__( the kriging error variance (if return_var is True and only_mean is False) """ - if ( - config.USE_GSTOOLS_CORE and config._GSTOOLS_CORE_AVAIL - ): # pylint: disable=W0212 - self._calc_field_krige = ( # pylint: disable=W0201 - calc_field_krige_gsc # pylint: disable=E0606 - ) - self._calc_field_krige_and_variance = ( # pylint: disable=W0201 - calc_field_krige_and_variance_gsc # pylint: disable=E0606 - ) - else: - self._calc_field_krige = ( # pylint: disable=W0201 - calc_field_krige_c - ) - self._calc_field_krige_and_variance = ( # pylint: disable=W0201 - calc_field_krige_and_variance_c - ) return_var &= not only_mean # don't return variance when calc. mean fld_cnt = 2 if return_var else 1 default = self.default_field_names[2] if only_mean else None @@ -304,13 +340,11 @@ def __call__( def _summate(self, field, krige_var, c_slice, k_vec, return_var): if return_var: # estimate error variance - field[c_slice], krige_var[c_slice] = ( - self._calc_field_krige_and_variance( - self._krige_mat, k_vec, self._krige_cond - ) + field[c_slice], krige_var[c_slice] = calc_field_krige_and_variance( + self._krige_mat, k_vec, self._krige_cond ) else: # solely calculate the interpolated field - field[c_slice] = self._calc_field_krige( + field[c_slice] = calc_field_krige( self._krige_mat, k_vec, self._krige_cond ) diff --git a/src/gstools/variogram/variogram.py b/src/gstools/variogram/variogram.py index fac50fb1e..a551368eb 100644 --- a/src/gstools/variogram/variogram.py +++ b/src/gstools/variogram/variogram.py @@ -47,6 +47,129 @@ AXIS_DIR = {"x": 0, "y": 1, "z": 2} +def directional( + field, + bin_edges, + pos, + direction, + angles_tol=np.pi / 8.0, + bandwidth=-1.0, + separate_dirs=False, + estimator_type="m", + num_threads=config.NUM_THREADS, +): + """ + A wrapper function for calling the directional variogram algorithms. + + See :any:`vario_estimate` for more details. + + Notes + ----- + Most of the time, this should not be called directly. + """ + if ( + config.USE_GSTOOLS_CORE + and config._GSTOOLS_CORE_AVAIL # pylint: disable=W0212 + ): # pylint: disable=W0212 + directional_fct = directional_gsc # pylint: disable=E0606 + else: + directional_fct = directional_c + return directional_fct( + field, + bin_edges, + pos, + direction, + angles_tol, + bandwidth, + separate_dirs, + estimator_type, + num_threads, + ) + + +def unstructured( + field, + bin_edges, + pos, + estimator_type="m", + distance_type="e", + num_threads=config.NUM_THREADS, +): + """ + A wrapper function for calling the unstructured variogram algorithms. + + See :any:`vario_estimate` for more details. + + Notes + ----- + Most of the time, this should not be called directly. + """ + if ( + config.USE_GSTOOLS_CORE + and config._GSTOOLS_CORE_AVAIL # pylint: disable=W0212 + ): # pylint: disable=W0212 + unstructured_fct = unstructured_gsc # pylint: disable=E0606 + else: + unstructured_fct = unstructured_c + return unstructured_fct( + field, + bin_edges, + pos, + estimator_type, + distance_type, + num_threads, + ) + + +def structured( + field, + estimator_type="m", + num_threads=config.NUM_THREADS, +): + """ + A wrapper function for calling the structured variogram algorithms. + + See :any:`vario_estimate` for more details. + + Notes + ----- + Most of the time, this should not be called directly. + """ + if ( + config.USE_GSTOOLS_CORE + and config._GSTOOLS_CORE_AVAIL # pylint: disable=W0212 + ): # pylint: disable=W0212 + structured_fct = structured_gsc # pylint: disable=E0606 + else: + structured_fct = structured_c + return structured_fct(field, estimator_type, num_threads) + + +def ma_structured( + field, + mask, + estimator_type="m", + num_threads=config.NUM_THREADS, +): + """ + A wrapper function for calling the masked struct. variogram algorithms. + + See :any:`vario_estimate` for more details. + + Notes + ----- + Most of the time, this should not be called directly. + """ + if ( + config.USE_GSTOOLS_CORE + and config._GSTOOLS_CORE_AVAIL # pylint: disable=W0212 + ): # pylint: disable=W0212 + ma_structured_fct = ma_structured_gsc # pylint: disable=E0606 + else: + ma_structured_fct = ma_structured_c + return ma_structured_fct(field, mask, estimator_type, num_threads) + + def _set_estimator(estimator): """Translate the verbose Python estimator identifier to single char.""" if estimator.lower() == "matheron": @@ -363,15 +486,6 @@ def vario_estimate( # select variogram estimator cython_estimator = _set_estimator(estimator) # run - if ( - config.USE_GSTOOLS_CORE - and config._GSTOOLS_CORE_AVAIL # pylint: disable=W0212 - ): # pylint: disable=W0212 - unstructured = unstructured_gsc # pylint: disable=E0606 - directional = directional_gsc # pylint: disable=E0606 - else: - unstructured = unstructured_c - directional = directional_c if dir_no == 0: # "h"aversine or "e"uclidean distance type distance_type = "h" if latlon else "e" @@ -496,15 +610,6 @@ def vario_estimate_axis( cython_estimator = _set_estimator(estimator) - if ( - config.USE_GSTOOLS_CORE - and config._GSTOOLS_CORE_AVAIL # pylint: disable=W0212 - ): # pylint: disable=W0212 - ma_structured = ma_structured_gsc # pylint: disable=E0606 - structured = structured_gsc # pylint: disable=E0606 - else: - ma_structured = ma_structured_c - structured = structured_c if masked: return ma_structured( field, mask, cython_estimator, num_threads=config.NUM_THREADS From 7bd5ca6a41b7c41457ed6e7118982796f7fe7680 Mon Sep 17 00:00:00 2001 From: LSchueler Date: Sun, 14 Jul 2024 14:35:49 +0200 Subject: [PATCH 08/11] Make Rust/Cython wrappers private & consist. default args --- src/gstools/field/generator.py | 33 +++++---------- src/gstools/krige/base.py | 36 +++++------------ src/gstools/variogram/variogram.py | 64 ++++++++---------------------- 3 files changed, 37 insertions(+), 96 deletions(-) diff --git a/src/gstools/field/generator.py b/src/gstools/field/generator.py index 89f2d539f..d19bd6d31 100644 --- a/src/gstools/field/generator.py +++ b/src/gstools/field/generator.py @@ -37,16 +37,8 @@ SAMPLING = ["auto", "inversion", "mcmc"] -def summate(cov_samples, z_1, z_2, pos, num_threads=config.NUM_THREADS): - """ - A wrapper function for calling the randomization algorithm. - - See :any:`Generator` for more details. - - Notes - ----- - Most of the time, this should not be called directly. - """ +def _summate(cov_samples, z_1, z_2, pos, num_threads=None): + """A wrapper function for calling the randomization algorithms.""" if ( config.USE_GSTOOLS_CORE and config._GSTOOLS_CORE_AVAIL # pylint: disable=W0212 @@ -57,18 +49,15 @@ def summate(cov_samples, z_1, z_2, pos, num_threads=config.NUM_THREADS): return summate_fct(cov_samples, z_1, z_2, pos, num_threads) -def summate_incompr( - cov_samples, z_1, z_2, pos, num_threads=config.NUM_THREADS +def _summate_incompr( + cov_samples, + z_1, + z_2, + pos, + num_threads=None, ): - """ - A wrapper function for calling the incompressible randomization algorithm. - - See :any:`Generator` for more details. + """A wrapper function for calling the incompr. randomization algorithms.""" - Notes - ----- - Most of the time, this should not be called directly. - """ if ( config.USE_GSTOOLS_CORE and config._GSTOOLS_CORE_AVAIL # pylint: disable=W0212 @@ -253,7 +242,7 @@ def __call__(self, pos, add_nugget=True): the random modes """ pos = np.asarray(pos, dtype=np.double) - summed_modes = summate( + summed_modes = _summate( self._cov_sample, self._z_1, self._z_2, pos, config.NUM_THREADS ) nugget = self.get_nugget(summed_modes.shape) if add_nugget else 0.0 @@ -534,7 +523,7 @@ def __call__(self, pos, add_nugget=True): the random modes """ pos = np.asarray(pos, dtype=np.double) - summed_modes = summate_incompr( + summed_modes = _summate_incompr( self._cov_sample, self._z_1, self._z_2, diff --git a/src/gstools/krige/base.py b/src/gstools/krige/base.py index 44d70b94a..b30190c2f 100755 --- a/src/gstools/krige/base.py +++ b/src/gstools/krige/base.py @@ -43,18 +43,8 @@ """dict: Standard pseudo-inverse routines""" -def calc_field_krige( - krig_mat, krig_vecs, cond, num_threads=config.NUM_THREADS -): - """ - A wrapper function for calling the krige algorithm. - - See :any:`Krige` for more details. - - Notes - ----- - Most of the time, this should not be called directly. - """ +def _calc_field_krige(krig_mat, krig_vecs, cond, num_threads=None): + """A wrapper function for calling the krige algorithms.""" if ( config.USE_GSTOOLS_CORE and config._GSTOOLS_CORE_AVAIL # pylint: disable=W0212 @@ -67,18 +57,10 @@ def calc_field_krige( return calc_field_krige_fct(krig_mat, krig_vecs, cond, num_threads) -def calc_field_krige_and_variance( - krig_mat, krig_vecs, cond, num_threads=config.NUM_THREADS +def _calc_field_krige_and_variance( + krig_mat, krig_vecs, cond, num_threads=None ): - """ - A wrapper function for calling the krige algorithm. - - See :any:`Krige` for more details. - - Notes - ----- - Most of the time, this should not be called directly. - """ + """A wrapper function for calling the krige algorithms.""" if ( config.USE_GSTOOLS_CORE and config._GSTOOLS_CORE_AVAIL # pylint: disable=W0212 @@ -340,11 +322,13 @@ def __call__( def _summate(self, field, krige_var, c_slice, k_vec, return_var): if return_var: # estimate error variance - field[c_slice], krige_var[c_slice] = calc_field_krige_and_variance( - self._krige_mat, k_vec, self._krige_cond + field[c_slice], krige_var[c_slice] = ( + _calc_field_krige_and_variance( + self._krige_mat, k_vec, self._krige_cond + ) ) else: # solely calculate the interpolated field - field[c_slice] = calc_field_krige( + field[c_slice] = _calc_field_krige( self._krige_mat, k_vec, self._krige_cond ) diff --git a/src/gstools/variogram/variogram.py b/src/gstools/variogram/variogram.py index a551368eb..3df2dfa3e 100644 --- a/src/gstools/variogram/variogram.py +++ b/src/gstools/variogram/variogram.py @@ -47,7 +47,7 @@ AXIS_DIR = {"x": 0, "y": 1, "z": 2} -def directional( +def _directional( field, bin_edges, pos, @@ -56,17 +56,9 @@ def directional( bandwidth=-1.0, separate_dirs=False, estimator_type="m", - num_threads=config.NUM_THREADS, + num_threads=None, ): - """ - A wrapper function for calling the directional variogram algorithms. - - See :any:`vario_estimate` for more details. - - Notes - ----- - Most of the time, this should not be called directly. - """ + """A wrapper function for calling the directional variogram algorithms.""" if ( config.USE_GSTOOLS_CORE and config._GSTOOLS_CORE_AVAIL # pylint: disable=W0212 @@ -87,23 +79,15 @@ def directional( ) -def unstructured( +def _unstructured( field, bin_edges, pos, estimator_type="m", distance_type="e", - num_threads=config.NUM_THREADS, + num_threads=None, ): - """ - A wrapper function for calling the unstructured variogram algorithms. - - See :any:`vario_estimate` for more details. - - Notes - ----- - Most of the time, this should not be called directly. - """ + """A wrapper function for calling the unstructured variogram algorithms.""" if ( config.USE_GSTOOLS_CORE and config._GSTOOLS_CORE_AVAIL # pylint: disable=W0212 @@ -121,20 +105,12 @@ def unstructured( ) -def structured( +def _structured( field, estimator_type="m", - num_threads=config.NUM_THREADS, + num_threads=None, ): - """ - A wrapper function for calling the structured variogram algorithms. - - See :any:`vario_estimate` for more details. - - Notes - ----- - Most of the time, this should not be called directly. - """ + """A wrapper function for calling the structured variogram algorithms.""" if ( config.USE_GSTOOLS_CORE and config._GSTOOLS_CORE_AVAIL # pylint: disable=W0212 @@ -145,21 +121,13 @@ def structured( return structured_fct(field, estimator_type, num_threads) -def ma_structured( +def _ma_structured( field, mask, estimator_type="m", - num_threads=config.NUM_THREADS, + num_threads=None, ): - """ - A wrapper function for calling the masked struct. variogram algorithms. - - See :any:`vario_estimate` for more details. - - Notes - ----- - Most of the time, this should not be called directly. - """ + """A wrapper function for calling the masked struct. variogram algorithms.""" if ( config.USE_GSTOOLS_CORE and config._GSTOOLS_CORE_AVAIL # pylint: disable=W0212 @@ -489,7 +457,7 @@ def vario_estimate( if dir_no == 0: # "h"aversine or "e"uclidean distance type distance_type = "h" if latlon else "e" - estimates, counts = unstructured( + estimates, counts = _unstructured( field, bin_edges, pos, @@ -498,7 +466,7 @@ def vario_estimate( num_threads=config.NUM_THREADS, ) else: - estimates, counts = directional( + estimates, counts = _directional( field, bin_edges, pos, @@ -611,10 +579,10 @@ def vario_estimate_axis( cython_estimator = _set_estimator(estimator) if masked: - return ma_structured( + return _ma_structured( field, mask, cython_estimator, num_threads=config.NUM_THREADS ) - return structured(field, cython_estimator, num_threads=config.NUM_THREADS) + return _structured(field, cython_estimator, num_threads=config.NUM_THREADS) # for backward compatibility From 4b270afbfd972252ba97742ae78484fe69285595 Mon Sep 17 00:00:00 2001 From: LSchueler Date: Mon, 15 Jul 2024 11:17:30 +0200 Subject: [PATCH 09/11] Fix default value to be consistent with the rest --- src/gstools/krige/krigesum.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gstools/krige/krigesum.pyx b/src/gstools/krige/krigesum.pyx index 9a37d2af6..a8f7bd196 100644 --- a/src/gstools/krige/krigesum.pyx +++ b/src/gstools/krige/krigesum.pyx @@ -60,7 +60,7 @@ def calc_field_krige( const double[:, :] krig_mat, const double[:, :] krig_vecs, const double[:] cond, - const int num_threads=1, + const int num_threads=None, ): cdef int mat_i = krig_mat.shape[0] From b8a190b1ceda20935d921e3847d4452332ff8d36 Mon Sep 17 00:00:00 2001 From: LSchueler Date: Mon, 15 Jul 2024 11:17:44 +0200 Subject: [PATCH 10/11] Remove superfluous code --- src/gstools/variogram/variogram.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/gstools/variogram/variogram.py b/src/gstools/variogram/variogram.py index 3df2dfa3e..6c51f1726 100644 --- a/src/gstools/variogram/variogram.py +++ b/src/gstools/variogram/variogram.py @@ -559,11 +559,6 @@ def vario_estimate_axis( if missing: field.mask = np.logical_or(field.mask, missing_mask) mask = np.ma.getmaskarray(field) - if ( - not config.USE_GSTOOLS_CORE - and config._GSTOOLS_CORE_AVAIL # pylint: disable=W0212 - ): # pylint: disable=W0212 - mask = np.asarray(mask, dtype=np.int32) else: field = np.atleast_1d(np.asarray(field, dtype=np.double)) missing_mask = None # free space From 4911823d23c07ddd1d8d8225d84d8b9243ad2783 Mon Sep 17 00:00:00 2001 From: LSchueler Date: Mon, 15 Jul 2024 11:19:55 +0200 Subject: [PATCH 11/11] Fix Cython type problem --- src/gstools/krige/krigesum.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gstools/krige/krigesum.pyx b/src/gstools/krige/krigesum.pyx index a8f7bd196..b32c70a74 100644 --- a/src/gstools/krige/krigesum.pyx +++ b/src/gstools/krige/krigesum.pyx @@ -60,7 +60,7 @@ def calc_field_krige( const double[:, :] krig_mat, const double[:, :] krig_vecs, const double[:] cond, - const int num_threads=None, + num_threads=None, ): cdef int mat_i = krig_mat.shape[0]