Source code for gstools.field.cond_srf

# -*- coding: utf-8 -*-
"""
GStools subpackage providing a class for conditioned spatial random fields.

.. currentmodule:: gstools.field.cond_srf

The following classes are provided

.. autosummary::
   CondSRF
"""
# pylint: disable=C0103, W0231, W0221, W0222, E1102
import numpy as np
from gstools.field.generator import RandMeth
from gstools.field.base import Field
from gstools.krige import Krige

__all__ = ["CondSRF"]

GENERATOR = {
    "RandMeth": RandMeth,
}
"""dict: Standard generators for conditioned spatial random fields."""


[docs]class CondSRF(Field): """A class to generate conditioned spatial random fields (SRF). Parameters ---------- krige : :any:`Krige` Kriging setup to condition the spatial random field. generator : :class:`str`, optional Name of the field generator to be used. At the moment, only the following generator is provided: * "RandMeth" : The Randomization Method. See: :any:`RandMeth` Default: "RandMeth" **generator_kwargs Keyword arguments that are forwarded to the generator in use. Have a look at the provided generators for further information. """ def __init__(self, krige, generator="RandMeth", **generator_kwargs): if not isinstance(krige, Krige): raise ValueError("CondSRF: krige should be an instance of Krige.") self._krige = krige # initialize attributes self.pos = None self.mesh_type = None self.field = None self.raw_field = None # initialize private attributes self._generator = None # initialize attributes self.set_generator(generator, **generator_kwargs)
[docs] def __call__(self, pos, seed=np.nan, mesh_type="unstructured", **kwargs): """Generate the conditioned spatial random field. The field is saved as `self.field` and is also returned. Parameters ---------- pos : :class:`list` the position tuple, containing main direction and transversal directions seed : :class:`int`, optional seed for RNG for reseting. Default: keep seed from generator mesh_type : :class:`str` 'structured' / 'unstructured' **kwargs keyword arguments that are forwarded to the kriging routine in use. Returns ------- field : :class:`numpy.ndarray` the conditioned SRF """ kwargs["mesh_type"] = mesh_type kwargs["only_mean"] = False # overwrite if given kwargs["return_var"] = True # overwrite if given kwargs["post_process"] = False # overwrite if given # update the model/seed in the generator if any changes were made self.generator.update(self.model, seed) # get isometrized positions and the resulting field-shape iso_pos, shape = self.pre_pos(pos, mesh_type) # generate the field self.raw_field = np.reshape( self.generator(iso_pos, add_nugget=False), shape ) field, krige_var = self.krige(pos, **kwargs) var_scale, nugget = self.get_scaling(krige_var, shape) # need to use a copy to not alter "field" by reference self.krige.post_field(self.krige.field.copy()) return self.post_field(field + var_scale * self.raw_field + nugget)
[docs] def get_scaling(self, krige_var, shape): """ Get scaling coefficients for the random field. Parameters ---------- krige_var : :class:`numpy.ndarray` Kriging variance. shape : :class:`tuple` of :class:`int` Field shape. Returns ------- var_scale : :class:`numpy.ndarray` Variance scaling factor for the random field. nugget : :class:`numpy.ndarray` or :class:`int` Nugget to be added to the field. """ if self.model.nugget > 0: var_scale = np.maximum(krige_var - self.model.nugget, 0) nug_scale = np.sqrt((krige_var - var_scale) / self.model.nugget) var_scale = np.sqrt(var_scale / self.model.var) nugget = nug_scale * self.generator.get_nugget(shape) else: var_scale = np.sqrt(krige_var / self.model.var) nugget = 0 return var_scale, nugget
[docs] def set_generator(self, generator, **generator_kwargs): """Set the generator for the field. Parameters ---------- generator : :class:`str`, optional Name of the generator to use for field generation. Default: "RandMeth" **generator_kwargs keyword arguments that are forwarded to the generator in use. """ if generator in GENERATOR: gen = GENERATOR[generator] self._generator = gen(self.model, **generator_kwargs) self.value_type = self.generator.value_type else: raise ValueError(f"gstools.CondSRF: Unknown generator {generator}")
@property def krige(self): """:any:`Krige`: The underlying kriging class.""" return self._krige @property def generator(self): """:any:`callable`: The generator of the field.""" return self._generator @property def model(self): """:any:`CovModel`: The covariance model of the field.""" return self.krige.model @model.setter def model(self, model): self.krige.model = model @property def mean(self): """:class:`float` or :any:`callable`: The mean of the field.""" return self.krige.mean @mean.setter def mean(self, mean): self.krige.mean = mean @property def normalizer(self): """:any:`Normalizer`: Normalizer of the field.""" return self.krige.normalizer @normalizer.setter def normalizer(self, normalizer): self.krige.normalizer = normalizer @property def trend(self): """:class:`float` or :any:`callable`: The trend of the field.""" return self.krige.trend @trend.setter def trend(self, trend): self.krige.trend = trend @property def value_type(self): """:class:`str`: Type of the field values (scalar, vector).""" return self.krige.value_type @value_type.setter def value_type(self, value_type): self.krige.value_type = value_type def __repr__(self): """Return String representation.""" return "CondSRF(krige={0}, generator={1})".format( self.krige, self.generator.name )