"""
GStools subpackage providing tools for Normalizers.
.. currentmodule:: gstools.normalizer.tools
The following classes and functions are provided
.. autosummary::
apply_mean_norm_trend
remove_trend_norm_mean
"""
import numpy as np
from gstools.normalizer.base import Normalizer
from gstools.tools.geometric import (
format_struct_pos_shape,
format_unstruct_pos_shape,
)
from gstools.tools.misc import eval_func
__all__ = ["apply_mean_norm_trend", "remove_trend_norm_mean"]
def _check_normalizer(normalizer):
if isinstance(normalizer, type) and issubclass(normalizer, Normalizer):
normalizer = normalizer()
elif normalizer is None:
normalizer = Normalizer()
elif not isinstance(normalizer, Normalizer):
raise ValueError("Check: 'normalizer' not of type 'Normalizer'.")
return normalizer
[docs]def apply_mean_norm_trend(
pos,
field,
mean=None,
normalizer=None,
trend=None,
mesh_type="unstructured",
value_type="scalar",
check_shape=True,
stacked=False,
):
"""
Apply mean, de-normalization and trend to given field.
Parameters
----------
pos : :any:`iterable`
Position tuple, containing main direction and transversal directions.
field : :class:`numpy.ndarray` or :class:`list` of :class:`numpy.ndarray`
The spatially distributed data.
You can pass a list of fields, that will be used simultaneously.
Then you need to set ``stacked=True``.
mean : :any:`None` or :class:`float` or :any:`callable`, optional
Mean of the field if wanted. Could also be a callable.
The default is None.
normalizer : :any:`None` or :any:`Normalizer`, optional
Normalizer to be applied to the field.
The default is None.
trend : :any:`None` or :class:`float` or :any:`callable`, optional
Trend of the denormalized fields. If no normalizer is applied,
this behaves equal to 'mean'.
The default is None.
mesh_type : :class:`str`, optional
'structured' / 'unstructured'
Default: 'unstructured'
value_type : :class:`str`, optional
Value type of the field. Either "scalar" or "vector".
The default is "scalar".
check_shape : :class:`bool`, optional
Whether to check pos and field shapes. The default is True.
stacked : :class:`bool`, optional
Whether the field is stacked or not. The default is False.
Returns
-------
field : :class:`numpy.ndarray`
The transformed field.
"""
normalizer = _check_normalizer(normalizer)
if check_shape:
if mesh_type != "unstructured":
pos, shape, dim = format_struct_pos_shape(
pos, field.shape, check_stacked_shape=stacked
)
else:
pos, shape, dim = format_unstruct_pos_shape(
pos, field.shape, check_stacked_shape=stacked
)
field = np.asarray(field, dtype=np.double).reshape(shape)
else:
dim = len(pos)
if not stacked:
field = [field]
field_cnt = len(field)
for i in range(field_cnt):
field[i] += eval_func(mean, pos, dim, mesh_type, value_type, True)
field = normalizer.denormalize(field)
for i in range(field_cnt):
field[i] += eval_func(trend, pos, dim, mesh_type, value_type, True)
return field if stacked else field[0]
[docs]def remove_trend_norm_mean(
pos,
field,
mean=None,
normalizer=None,
trend=None,
mesh_type="unstructured",
value_type="scalar",
check_shape=True,
stacked=False,
fit_normalizer=False,
):
"""
Remove trend, de-normalization and mean from given field.
Parameters
----------
pos : :any:`iterable`
Position tuple, containing main direction and transversal directions.
field : :class:`numpy.ndarray` or :class:`list` of :class:`numpy.ndarray`
The spatially distributed data.
You can pass a list of fields, that will be used simultaneously.
Then you need to set ``stacked=True``.
mean : :any:`None` or :class:`float` or :any:`callable`, optional
Mean of the field if wanted. Could also be a callable.
The default is None.
normalizer : :any:`None` or :any:`Normalizer`, optional
Normalizer to be applied to the field.
The default is None.
trend : :any:`None` or :class:`float` or :any:`callable`, optional
Trend of the denormalized fields. If no normalizer is applied,
this behaves equal to 'mean'.
The default is None.
mesh_type : :class:`str`, optional
'structured' / 'unstructured'
Default: 'unstructured'
value_type : :class:`str`, optional
Value type of the field. Either "scalar" or "vector".
The default is "scalar".
check_shape : :class:`bool`, optional
Whether to check pos and field shapes. The default is True.
stacked : :class:`bool`, optional
Whether the field is stacked or not. The default is False.
fit_normalizer : :class:`bool`, optional
Whether to fit the data-normalizer to the given (detrended) field.
Default: False
Returns
-------
field : :class:`numpy.ndarray`
The cleaned field.
normalizer : :any:`Normalizer`, optional
The fitted normalizer for the given data.
Only provided if `fit_normalizer` is True.
"""
normalizer = _check_normalizer(normalizer)
if check_shape:
if mesh_type != "unstructured":
pos, shape, dim = format_struct_pos_shape(
pos, field.shape, check_stacked_shape=stacked
)
else:
pos, shape, dim = format_unstruct_pos_shape(
pos, field.shape, check_stacked_shape=stacked
)
field = np.asarray(field, dtype=np.double).reshape(shape)
else:
dim = len(pos)
if not stacked:
field = [field]
field_cnt = len(field)
for i in range(field_cnt):
field[i] -= eval_func(trend, pos, dim, mesh_type, value_type, True)
if fit_normalizer:
normalizer.fit(field)
field = normalizer.normalize(field)
for i in range(field_cnt):
field[i] -= eval_func(mean, pos, dim, mesh_type, value_type, True)
out = field if stacked else field[0]
return (out, normalizer) if fit_normalizer else out