Skip to content

Add sum model #364

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 60 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
94b6c29
plot: handle len_scale of 0
MuellerSeb Jul 26, 2024
abbb062
covmodel: init len_scale with integral_scale if given; remove unused …
MuellerSeb Jul 26, 2024
c39866a
bounds: allow interval with equal bounds if closed
MuellerSeb Jul 26, 2024
df9f2ba
CovModel: add force_values logic
MuellerSeb Jul 26, 2024
a3f1ec6
generator: shortcut for 0 variance
MuellerSeb Jul 27, 2024
8b3ad81
CovModel: safer usage of privat attr; anis set bug fix; simpler int s…
MuellerSeb Jul 28, 2024
a60b3d7
CovModel: check _init in bounds setter; also compare geo_scale; simpl…
MuellerSeb Jul 28, 2024
92210ad
CovModel: remove force arguments mechanic
MuellerSeb Jul 28, 2024
8999bf9
pylint fixes
MuellerSeb Jul 28, 2024
d643b45
TPL: remove var_raw and var_factor logic and only add intensity as pr…
MuellerSeb Aug 11, 2024
81e5421
tests: remove tests for var_raw
MuellerSeb Aug 11, 2024
669e9a2
CovModel: remove mechanism for fixed args again
MuellerSeb Aug 11, 2024
01d1d82
CovModel: simplify fitting routines
MuellerSeb Aug 11, 2024
418038f
CovModel: fix setting integral scale as list of values
MuellerSeb Aug 12, 2024
d8b037f
no need to set var last anymore
MuellerSeb Aug 12, 2024
0b63225
fit: add comment
MuellerSeb Aug 12, 2024
21d0e4a
add ratio error class; better arg checking routines
MuellerSeb Aug 14, 2024
e6374db
CovModel: better dim setting
MuellerSeb Aug 15, 2024
dcb003b
add sum_tools submodule
MuellerSeb Aug 15, 2024
057c888
add SumModel class
MuellerSeb Aug 15, 2024
656125a
add pure Nugget model
MuellerSeb Aug 15, 2024
dbdfa27
CovModel: let the sum magic happen
MuellerSeb Aug 15, 2024
2858f06
pylint fixes
MuellerSeb Aug 15, 2024
947619a
fix doc-string of SumModel for docs
MuellerSeb Aug 15, 2024
480fa32
CovModel: add switch to add doc string
MuellerSeb Aug 15, 2024
171efba
Fourier: fix doc
MuellerSeb Aug 15, 2024
e7838cf
SumModel: models need to either be all instances or all subclasses of…
MuellerSeb Aug 19, 2024
0e35a22
SumModel: sum models have a constant rescale factor of 1 since they a…
MuellerSeb Aug 19, 2024
2ded2e0
CovModel: add 'needs_fourier_transform' attribute
MuellerSeb Jan 1, 2025
aee1985
covmodel.tools: allow setting bounds of sub-args
MuellerSeb Jan 6, 2025
f30ebb7
sum-tools: prepare setting sub-args by weights
MuellerSeb Jan 6, 2025
a8ef32f
SumModel: prepare sum models for fitting
MuellerSeb Jan 6, 2025
050cc37
fit: enable fitting of sum-models; refactor fitting in general
MuellerSeb Jan 6, 2025
b120d93
tests: update tests to check for new var/nugget/sill handling
MuellerSeb Jan 6, 2025
302a056
CI: update to include py3.13
MuellerSeb Jan 6, 2025
9c2673e
Doc: use myst_parser instead of m2r2 and update docs
MuellerSeb Jan 6, 2025
eda015d
Merge branch 'main' into add_sum_model
MuellerSeb Jan 6, 2025
d03146f
lint
MuellerSeb Jan 6, 2025
ee485c2
Merge branch 'add_sum_model' of github.com:GeoStat-Framework/GSTools …
MuellerSeb Jan 6, 2025
5dc6b16
pylint: set all config in pyproject
MuellerSeb Jan 6, 2025
64b102e
Normalizer: implement simple derivative to remove scipy dependency
MuellerSeb Jan 6, 2025
f475c1e
fit: correctly check for parameters to fit
MuellerSeb Jan 6, 2025
8ea78f8
fit: fix init guess for var_i
MuellerSeb Jan 6, 2025
3eee1dd
fix typo
MuellerSeb Jan 6, 2025
e3b944e
Doc: add mini-gallery to tutorials
MuellerSeb Jan 6, 2025
8a97d0d
typo
MuellerSeb Jan 7, 2025
f0b113e
Docs: add first examples for sum models
MuellerSeb Jan 7, 2025
361860a
Merge branch 'main' into add_sum_model
MuellerSeb Jan 30, 2025
af06e49
SumModel: copy CovModel instances to prevent strange errors
MuellerSeb Feb 7, 2025
fb0a01e
SumModel: also copy models of other summodels
MuellerSeb Feb 7, 2025
e8ea93c
make sum-models comparable
MuellerSeb Feb 7, 2025
c64af49
SumModel: remove RatioError, use ValueError instead
MuellerSeb Feb 8, 2025
c885952
SumModel: add tests
MuellerSeb Feb 8, 2025
c66d722
add test data to manifest
MuellerSeb Feb 8, 2025
942bca7
Merge branch 'add_sum_model' of github.com:GeoStat-Framework/GSTools …
MuellerSeb Feb 8, 2025
fedb294
pylint fix
MuellerSeb Feb 8, 2025
48ec88c
SumModel: more tests
MuellerSeb Feb 8, 2025
4010e86
update sum-model examples after review
MuellerSeb Apr 22, 2025
342efbe
tests: better structure sum-model tests
MuellerSeb Apr 22, 2025
e7f28c8
sum-model: update doc-strings and error messages from review
MuellerSeb Apr 22, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
prune **
recursive-include tests *.py
recursive-include tests *.py *.txt
recursive-include src/gstools *.py *.pyx
include AUTHORS.md LICENSE README.md pyproject.toml setup.py
2 changes: 2 additions & 0 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ def setup(app):
"../../examples/08_geo_coordinates/",
"../../examples/09_spatio_temporal/",
"../../examples/10_normalizer/",
"../../examples/11_sum_model/",
],
# path where to save gallery generated examples
"gallery_dirs": [
Expand All @@ -314,6 +315,7 @@ def setup(app):
"examples/08_geo_coordinates/",
"examples/09_spatio_temporal/",
"examples/10_normalizer/",
"examples/11_sum_model/",
],
# Pattern to search for example files
"filename_pattern": r"\.py",
Expand Down
1 change: 1 addition & 0 deletions docs/source/tutorials.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ explore its whole beauty and power.
examples/08_geo_coordinates/index
examples/09_spatio_temporal/index
examples/10_normalizer/index
examples/11_sum_model/index
examples/00_misc/index

.. only:: html
Expand Down
61 changes: 61 additions & 0 deletions examples/11_sum_model/00_simple_sum_model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
r"""
Creating a Sum Model
--------------------

This tutorial demonstrates how to create and use sum models in GSTools.
We'll combine a Spherical and a Gaussian covariance model to construct
a sum model, visualize its variogram, and generate spatial random fields.

Let's start with importing GSTools and setting up the domain size.
"""

import gstools as gs

x = y = range(100)

###############################################################################
# First, we create two individual covariance models: a :any:`Spherical` model and a
# :any:`Gaussian` model. The Spherical model with its short length scale
# will emphasize small-scale variability, while the Gaussian model with a larger length scale
# captures larger-scale patterns.

m0 = gs.Spherical(dim=2, var=2.0, len_scale=5.0)
m1 = gs.Gaussian(dim=2, var=1.0, len_scale=10.0)

###############################################################################
# Next, we create a sum model by adding these two models together.
# Let's visualize the resulting variogram alongside the individual models.

model = m0 + m1
ax = model.plot(x_max=20)
m0.plot(x_max=20, ax=ax)
m1.plot(x_max=20, ax=ax)

###############################################################################
# As shown, the Spherical model controls the behavior at shorter distances,
# while the Gaussian model dominates at longer distances. The ratio of influence
# is thereby controlled by the provided variances of the individual models.
#
# Using the sum model, we can generate a spatial random field. Let's visualize
# the field created by the sum model.

srf = gs.SRF(model, seed=20250107)
srf.structured((x, y))
srf.plot()

###############################################################################
# For comparison, we generate random fields using the individual models
# to observe their contributions more clearly.

srf0 = gs.SRF(m0, seed=20250107)
srf0.structured((x, y))
srf0.plot()

srf1 = gs.SRF(m1, seed=20250107)
srf1.structured((x, y))
srf1.plot()

###############################################################################
# As seen, the Gaussian model introduces large-scale structures, while the
# Spherical model influences the field's roughness. The sum model combines
# these effects, resulting in a field that reflects multi-scale variability.
80 changes: 80 additions & 0 deletions examples/11_sum_model/01_fitting_sum_model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
r"""
Fitting a Sum Model
--------------------

In this tutorial, we demonstrate how to fit a sum model consisting of two
covariance models to an empirical variogram.

We will generate synthetic data, compute an empirical variogram, and fit a
sum model combining a Spherical and Gaussian model to it.
"""

import gstools as gs

x = y = range(100)

###############################################################################
# First, we create a synthetic random field based on a known sum model.
# This will serve as the ground truth for fitting.

# Define the true sum model
m0 = gs.Spherical(dim=2, var=2.0, len_scale=5.0)
m1 = gs.Gaussian(dim=2, var=1.0, len_scale=10.0)
true_model = m0 + m1

# Generate synthetic field
srf = gs.SRF(true_model, seed=20250405)
field = srf.structured((x, y))

###############################################################################
# Next, we calculate the empirical variogram from the synthetic data.

# Compute empirical variogram
bin_center, gamma = gs.vario_estimate((x, y), field)

###############################################################################
# Now we define a sum model to fit to the empirical variogram.
# Initially, the parameters of the models are arbitrary.
#
# A sum model can also be created by a list of model classes together with
# the common arguments (like dim in this case).

fit_model = gs.SumModel(gs.Spherical, gs.Gaussian, dim=2)

###############################################################################
# We fit the sum model to the empirical variogram using GSTools' built-in
# fitting capabilities. We deactivate the nugget fitting to not overparameterize
# our model.

fit_model.fit_variogram(bin_center, gamma, nugget=False)
print(f"{true_model=}")
print(f" {fit_model=}")

###############################################################################
# The variance of a sum model is the sum of the sub variances (:any:`SumModel.vars`)
# from the contained models. The length scale is a weighted sum of the sub
# length scales (:any:`SumModel.len_scales`) where the weights are the ratios
# of the sub variances to the total variance of the sum model.

print(f"{true_model.var=:.2}, {true_model.len_scale=:.2}")
print(f" {fit_model.var=:.2}, {fit_model.len_scale=:.2}")

###############################################################################
# After fitting, we can visualize the empirical variogram alongside the
# fitted sum model and its components. A Sum Model is subscriptable to access
# the individual models its contains.

ax = fit_model.plot(x_max=max(bin_center))
ax.scatter(bin_center, gamma)
# Extract individual components
fit_model[0].plot(x_max=max(bin_center), ax=ax)
fit_model[1].plot(x_max=max(bin_center), ax=ax)
# True models
true_model.plot(x_max=max(bin_center), ax=ax, ls="--", c="C0", label="")
true_model[0].plot(x_max=max(bin_center), ax=ax, ls="--", c="C1", label="")
true_model[1].plot(x_max=max(bin_center), ax=ax, ls="--", c="C2", label="")

###############################################################################
# As we can see, the fitted sum model closely matches the empirical variogram,
# demonstrating its ability to capture multi-scale variability effectively.
# The "true" variograms are shown with dashed lines for comparison.
30 changes: 30 additions & 0 deletions examples/11_sum_model/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
Summing Covariance Models
=========================

In geostatistics, the spatial relations of natural phenomena is often represented using covariance models,
which describe how values of a property correlate over distance.
A single covariance model may capture specific features of the spatial correlation, such as smoothness or the range of influence.
However, many real-world spatial processes are complex, involving multiple overlapping structures
that cannot be adequately described by a single covariance model.

This is where **sum models** come into play.
A sum model combines multiple covariance models into a single representation,
allowing for a more flexible and comprehensive description of spatial variability.
By summing covariance models, we can:

1. **Capture Multi-Scale Variability:** Many spatial phenomena exhibit variability at different scales.
For example, soil properties may have small-scale variation due to local heterogeneities and large-scale variation due to regional trends.
A sum model can combine short-range and long-range covariance models to reflect this behavior.
2. **Improve Model Fit and Prediction Accuracy:** By combining models, sum models can better match empirical variograms or other observed data,
leading to more accurate predictions in kriging or simulation tasks.
3. **Enhance Interpretability:** Each component of a sum model can be associated with a specific spatial process or scale,
providing insights into the underlying mechanisms driving spatial variability.

The new :any:`SumModel` introduced in GSTools makes it straightforward to define and work with such composite covariance structures.
It allows users to combine any number of base models, each with its own parameters, in a way that is both intuitive and computationally efficient.

In the following tutorials, we'll explore how to use the :any:`SumModel` in GSTools,
including practical examples that demonstrate its utility in different scenarios.

Examples
--------
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ target-version = [
max-locals = 50
max-branches = 30
max-statements = 85
max-attributes = 25
max-attributes = 30
max-public-methods = 80
max-positional-arguments=20

Expand Down
6 changes: 6 additions & 0 deletions src/gstools/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@

.. autosummary::
CovModel
SumModel

Covariance Models
^^^^^^^^^^^^^^^^^
Expand All @@ -62,6 +63,7 @@
~~~~~~~~~~~~~~~~~~~~~~~~~~

.. autosummary::
Nugget
Gaussian
Exponential
Matern
Expand Down Expand Up @@ -153,9 +155,11 @@
JBessel,
Linear,
Matern,
Nugget,
Rational,
Spherical,
Stable,
SumModel,
SuperSpherical,
TPLExponential,
TPLGaussian,
Expand Down Expand Up @@ -198,6 +202,8 @@
__all__ += ["transform", "normalizer", "config"]
__all__ += [
"CovModel",
"SumModel",
"Nugget",
"Gaussian",
"Exponential",
"Matern",
Expand Down
7 changes: 6 additions & 1 deletion src/gstools/covmodel/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
:toctree:

CovModel
SumModel

Covariance Models
^^^^^^^^^^^^^^^^^
Expand All @@ -27,6 +28,7 @@
.. autosummary::
:toctree:

Nugget
Gaussian
Exponential
Matern
Expand All @@ -53,7 +55,7 @@
TPLSimple
"""

from gstools.covmodel.base import CovModel
from gstools.covmodel.base import CovModel, SumModel
from gstools.covmodel.models import (
Circular,
Cubic,
Expand All @@ -64,6 +66,7 @@
JBessel,
Linear,
Matern,
Nugget,
Rational,
Spherical,
Stable,
Expand All @@ -78,6 +81,8 @@

__all__ = [
"CovModel",
"SumModel",
"Nugget",
"Gaussian",
"Exponential",
"Matern",
Expand Down
Loading
Loading