gstools_core/
lib.rs

1//! GSTools-Core
2//!
3//! `gstools_core` is a Rust implementation of the core algorithms of [GSTools].
4//! At the moment, it is a drop in replacement for the Cython code included in GSTools.
5//!
6//! This crate includes
7//! - [randomization methods](field) for the random field generation
8//! - the [matrix operations](krige) of the kriging methods
9//! - the [variogram estimation](variogram)
10//!
11//! [GSTools]: https://github.com/GeoStat-Framework/GSTools
12
13#![warn(missing_docs)]
14
15use numpy::{IntoPyArray, PyArray1, PyArray2, PyReadonlyArray1, PyReadonlyArray2};
16use pyo3::prelude::{pymodule, PyModule, PyResult, Python};
17
18use field::{summator, summator_incompr};
19use krige::{calculator_field_krige, calculator_field_krige_and_variance};
20use variogram::{
21    variogram_directional, variogram_ma_structured, variogram_structured, variogram_unstructured,
22};
23
24pub mod field;
25pub mod krige;
26mod short_vec;
27pub mod variogram;
28
29#[pymodule]
30fn gstools_core(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
31    m.add("__version__", env!("CARGO_PKG_VERSION"))?;
32
33    #[pyfn(m)]
34    #[pyo3(name = "summate")]
35    fn summate_py<'py>(
36        py: Python<'py>,
37        cov_samples: PyReadonlyArray2<f64>,
38        z1: PyReadonlyArray1<f64>,
39        z2: PyReadonlyArray1<f64>,
40        pos: PyReadonlyArray2<f64>,
41        num_threads: Option<usize>,
42    ) -> &'py PyArray1<f64> {
43        let cov_samples = cov_samples.as_array();
44        let z1 = z1.as_array();
45        let z2 = z2.as_array();
46        let pos = pos.as_array();
47        summator(cov_samples, z1, z2, pos, num_threads).into_pyarray(py)
48    }
49
50    #[pyfn(m)]
51    #[pyo3(name = "summate_incompr")]
52    fn summate_incompr_py<'py>(
53        py: Python<'py>,
54        cov_samples: PyReadonlyArray2<f64>,
55        z1: PyReadonlyArray1<f64>,
56        z2: PyReadonlyArray1<f64>,
57        pos: PyReadonlyArray2<f64>,
58        num_threads: Option<usize>,
59    ) -> &'py PyArray2<f64> {
60        let cov_samples = cov_samples.as_array();
61        let z1 = z1.as_array();
62        let z2 = z2.as_array();
63        let pos = pos.as_array();
64        summator_incompr(cov_samples, z1, z2, pos, num_threads).into_pyarray(py)
65    }
66
67    #[pyfn(m)]
68    #[pyo3(name = "calc_field_krige_and_variance")]
69    fn calc_field_krige_and_variance_py<'py>(
70        py: Python<'py>,
71        krige_mat: PyReadonlyArray2<f64>,
72        krig_vecs: PyReadonlyArray2<f64>,
73        cond: PyReadonlyArray1<f64>,
74        num_threads: Option<usize>,
75    ) -> (&'py PyArray1<f64>, &'py PyArray1<f64>) {
76        let krige_mat = krige_mat.as_array();
77        let krig_vecs = krig_vecs.as_array();
78        let cond = cond.as_array();
79        let (field, error) =
80            calculator_field_krige_and_variance(krige_mat, krig_vecs, cond, num_threads);
81        let field = field.into_pyarray(py);
82        let error = error.into_pyarray(py);
83        (field, error)
84    }
85
86    #[pyfn(m)]
87    #[pyo3(name = "calc_field_krige")]
88    fn calc_field_krige_py<'py>(
89        py: Python<'py>,
90        krige_mat: PyReadonlyArray2<f64>,
91        krig_vecs: PyReadonlyArray2<f64>,
92        cond: PyReadonlyArray1<f64>,
93        num_threads: Option<usize>,
94    ) -> &'py PyArray1<f64> {
95        let krige_mat = krige_mat.as_array();
96        let krig_vecs = krig_vecs.as_array();
97        let cond = cond.as_array();
98        calculator_field_krige(krige_mat, krig_vecs, cond, num_threads).into_pyarray(py)
99    }
100
101    #[pyfn(m)]
102    #[pyo3(name = "variogram_structured")]
103    fn variogram_structured_py<'py>(
104        py: Python<'py>,
105        f: PyReadonlyArray2<f64>,
106        estimator_type: Option<char>,
107        num_threads: Option<usize>,
108    ) -> &'py PyArray1<f64> {
109        let f = f.as_array();
110        let estimator_type = estimator_type.unwrap_or('m');
111        variogram_structured(f, estimator_type, num_threads).into_pyarray(py)
112    }
113
114    #[pyfn(m)]
115    #[pyo3(name = "variogram_ma_structured")]
116    fn variogram_ma_structured_py<'py>(
117        py: Python<'py>,
118        f: PyReadonlyArray2<f64>,
119        mask: PyReadonlyArray2<bool>,
120        estimator_type: Option<char>,
121        num_threads: Option<usize>,
122    ) -> &'py PyArray1<f64> {
123        let f = f.as_array();
124        let mask = mask.as_array();
125        let estimator_type = estimator_type.unwrap_or('m');
126        variogram_ma_structured(f, mask, estimator_type, num_threads).into_pyarray(py)
127    }
128
129    #[pyfn(m)]
130    #[pyo3(name = "variogram_directional")]
131    #[allow(clippy::too_many_arguments)]
132    fn variogram_directional_py<'py>(
133        py: Python<'py>,
134        f: PyReadonlyArray2<f64>,
135        bin_edges: PyReadonlyArray1<f64>,
136        pos: PyReadonlyArray2<f64>,
137        direction: PyReadonlyArray2<f64>, //should be normed
138        angles_tol: Option<f64>,
139        bandwidth: Option<f64>,
140        separate_dirs: Option<bool>,
141        estimator_type: Option<char>,
142        num_threads: Option<usize>,
143    ) -> (&'py PyArray2<f64>, &'py PyArray2<u64>) {
144        let f = f.as_array();
145        let bin_edges = bin_edges.as_array();
146        let pos = pos.as_array();
147        let direction = direction.as_array();
148        let angles_tol = angles_tol.unwrap_or(std::f64::consts::PI / 8.0);
149        let bandwidth = bandwidth.unwrap_or(-1.0);
150        let separate_dirs = separate_dirs.unwrap_or(false);
151        let estimator_type = estimator_type.unwrap_or('m');
152        let (variogram, counts) = variogram_directional(
153            f,
154            bin_edges,
155            pos,
156            direction,
157            angles_tol,
158            bandwidth,
159            separate_dirs,
160            estimator_type,
161            num_threads,
162        );
163        let variogram = variogram.into_pyarray(py);
164        let counts = counts.into_pyarray(py);
165
166        (variogram, counts)
167    }
168
169    #[pyfn(m)]
170    #[pyo3(name = "variogram_unstructured")]
171    fn variogram_unstructured_py<'py>(
172        py: Python<'py>,
173        f: PyReadonlyArray2<f64>,
174        bin_edges: PyReadonlyArray1<f64>,
175        pos: PyReadonlyArray2<f64>,
176        estimator_type: Option<char>,
177        distance_type: Option<char>,
178        num_threads: Option<usize>,
179    ) -> (&'py PyArray1<f64>, &'py PyArray1<u64>) {
180        let f = f.as_array();
181        let bin_edges = bin_edges.as_array();
182        let pos = pos.as_array();
183        let estimator_type = estimator_type.unwrap_or('m');
184        let distance_type = distance_type.unwrap_or('e');
185        let (variogram, counts) = variogram_unstructured(
186            f,
187            bin_edges,
188            pos,
189            estimator_type,
190            distance_type,
191            num_threads,
192        );
193        let variogram = variogram.into_pyarray(py);
194        let counts = counts.into_pyarray(py);
195
196        (variogram, counts)
197    }
198
199    Ok(())
200}