Source code for atmos_flux_inversion.covariances
"""Support classes for covariances.
See Also
--------
atmos_flux_inversion.correlations
"""
from __future__ import absolute_import
import numpy as np
from numpy import newaxis, sqrt
from .linalg import (
    ProductLinearOperator, SelfAdjointLinearOperator,
    DiagonalOperator, matrix_sqrt)
OBSERVATION_INTERVAL = np.array(1, dtype="m8[h]")
"""The time between individual observations at one site.
More precisely, these are the units used with the correlation function
used in :func:`observation_covariance_matrix`.
"""
[docs]class CorrelationStandardDeviation(ProductLinearOperator,
                                   SelfAdjointLinearOperator):
    """Represent correlation-std product."""
    def __init__(self, correlation, std):
        """Set up instance to use given parameters.
        Parameters
        ----------
        correlation: LinearOperator[N, N]
            Correlations
        std: array_like[N]
            Standard deviations
        """
        std_matrix = DiagonalOperator(std)
        super(CorrelationStandardDeviation, self).__init__(
            std_matrix, correlation, std_matrix)
    def _transpose(self):
        """Return transpose of self."""
        return self  # pragma: no cover
    def _adjoint(self):
        """Return adjoint of self."""
        return self
[docs]    def sqrt(self):
        """Find S such that S.T @ S == self."""
        std_matrix, correlation, _ = self._operators
        return ProductLinearOperator(
            matrix_sqrt(correlation), std_matrix) 
    _sqrt = sqrt 
[docs]def observation_covariance_matrix(variance_series, correlation_function):
    """Create the observation covariance matrix given parammeters.
    Assumes the observations are far enough apart to be uncorrelated.
    Parameters
    ----------
    variance_series : pandas.Series[n_observations]
    correlation_function : DistanceCorrelationFunction
    Returns
    -------
    np.ndarray
    """
    obs_time_name = [name for name in variance_series.index.names
                     if "time" in name][0]
    obs_site_name = [name for name in variance_series.index.names
                     if "site" in name or "name" in name][0]
    obs_times = variance_series.index.get_level_values(obs_time_name)
    obs_sites = variance_series.index.get_level_values(obs_site_name)
    # Only correlations for now
    observation_covariance = correlation_function(
        abs(obs_times[:, newaxis] - obs_times[newaxis, :]) /
        OBSERVATION_INTERVAL
    )
    observation_covariance[
        obs_sites.values[:, newaxis] != obs_sites.values[newaxis, :]
    ] = 0
    # now turn it into covariance
    obs_stds = sqrt(variance_series.values)
    observation_covariance *= obs_stds[:, newaxis]
    observation_covariance *= obs_stds[newaxis, :]
    return observation_covariance