Example #1
0
    def __init__(self, mu=0, C=0, M=None):
        """Init allowing for shortcut notation."""
        if isinstance(mu, CovMat):
            raise TypeError("Got a covariance paramter as mu. " +
                            "Use kword syntax (C=...) ?")

        # Set mu
        mu = np.atleast_1d(mu)
        assert mu.ndim == 1
        if len(mu) > 1:
            if M is None:
                M = len(mu)
            else:
                assert len(mu) == M
        else:
            if M is not None:
                mu = np.ones(M) * mu

        # Set C
        if isinstance(C, CovMat):
            if M is None:
                M = C.M
        else:
            if np.isscalar(C) and C == 0:
                pass  # Assign as pure 0!
            else:
                if np.isscalar(C):
                    M = len(mu)
                    C = CovMat(C * np.ones(M), 'diag')
                else:
                    C = CovMat(C)
                    if M is None:
                        M = C.M

        # Validation
        if len(mu) not in (1, M):
            raise TypeError("Inconsistent shapes of (M,mu,C)")
        if M is None:
            raise TypeError("Could not deduce the value of M")
        try:
            if M != C.M:
                raise TypeError("Inconsistent shapes of (M,mu,C)")
        except AttributeError:
            pass

        # Assign
        self.M = M
        self.mu = mu
        self.C = C
Example #2
0
    def assimilate(self, HMM, xx, yy):
        muC = np.mean(xx, 0)
        AC = xx - muC
        PC = CovMat(AC, 'A')

        self.stats.assess(0, mu=muC, Cov=PC)
        self.stats.trHK[:] = 0

        for k, ko, _, _ in progbar(HMM.tseq.ticker):
            fau = 'u' if ko is None else 'fau'
            self.stats.assess(k, ko, fau, mu=muC, Cov=PC)
Example #3
0
    def assimilate(self, HMM, xx, yy):
        chrono, stats = HMM.t, self.stats

        muC = np.mean(xx, 0)
        AC  = xx - muC
        PC  = CovMat(AC, 'A')

        stats.assess(0, mu=muC, Cov=PC)
        stats.trHK[:] = 0

        for k, kObs, _, _ in progbar(chrono.ticker):
            fau = 'u' if kObs is None else 'fau'
            stats.assess(k, kObs, fau, mu=muC, Cov=PC)
Example #4
0
    def assimilate(self, HMM, xx, yy):
        Dyn, Obs, chrono, X0, stats = HMM.Dyn, HMM.Obs, HMM.t, HMM.X0, self.stats
        R, KObs = HMM.Obs.noise.C, HMM.t.KObs
        Rm12 = R.sym_sqrt_inv
        Nx = Dyn.M

        # Set background covariance. Note that it is static (compare to iEnKS).
        if self.B in (None, 'clim'):
            # Use climatological cov, ...
            B = np.cov(xx.T)  # ... estimated from truth
        elif self.B == 'eye':
            B = np.eye(Nx)
        else:
            B = self.B
        B *= self.xB
        B12 = CovMat(B).sym_sqrt

        # Init
        x = X0.mu
        stats.assess(0, mu=x, Cov=B)

        # Loop over DA windows (DAW).
        for kObs in progbar(np.arange(-1, KObs + self.Lag + 1)):
            kLag = kObs - self.Lag
            DAW = range(max(0, kLag + 1), min(kObs, KObs) + 1)

            # Assimilation (if ∃ "not-fully-assimlated" obs).
            if 0 <= kObs <= KObs:

                # Init iterations.
                w = np.zeros(Nx)  # Control vector for the mean state.
                x0 = x.copy()  # Increment reference.

                for iteration in np.arange(self.nIter):
                    # Reconstruct smoothed state.
                    x = x0 + B12 @ w
                    X = B12  # Aggregate composite TLMs onto B12
                    # Forecast.
                    for kCycle in DAW:
                        for k, t, dt in chrono.cycle(kCycle):  # noqa
                            X = Dyn.linear(x, t - dt, dt) @ X
                            x = Dyn(x, t - dt, dt)

                    # Assess forecast stats
                    if iteration == 0:
                        stats.assess(k, kObs, 'f', mu=x, Cov=X @ X.T)

                    # Observe.
                    Y = Obs.linear(x, t) @ X
                    xo = Obs(x, t)

                    # Analysis prep.
                    y = yy[kObs]  # Get current obs.
                    dy = Rm12 @ (y - xo)  # Transform obs space.
                    Y = Rm12 @ Y  # Transform obs space.
                    V, s, UT = svd0(Y.T)  # Decomp for lin-alg update comps.

                    # Post. cov (approx) of w,
                    # estimated at current iteration, raised to power.
                    Cow1 = (V * (pad0(s**2, Nx) + 1)**-1.0) @ V.T

                    # Compute analysis update.
                    grad = Y.T @ dy - w  # Cost function gradient
                    dw = Cow1 @ grad  # Gauss-Newton step
                    w += dw  # Step

                    if dw @ dw < self.wtol * Nx:
                        break

                # Assess (analysis) stats.
                final_increment = X @ dw
                stats.assess(k,
                             kObs,
                             'a',
                             mu=x + final_increment,
                             Cov=X @ Cow1 @ X.T)
                stats.iters[kObs] = iteration + 1

                # Final (smoothed) estimate at [kLag].
                x = x0 + B12 @ w
                X = B12

            # Slide/shift DAW by propagating smoothed ('s') state from [kLag].
            if -1 <= kLag < KObs:
                if kLag >= 0:
                    stats.assess(chrono.kkObs[kLag],
                                 kLag,
                                 's',
                                 mu=x,
                                 Cov=X @ Cow1 @ X.T)
                for k, t, dt in chrono.cycle(kLag + 1):
                    stats.assess(k - 1, None, 'u', mu=x, Cov=Y @ Y.T)
                    X = Dyn.linear(x, t - dt, dt) @ X
                    x = Dyn(x, t - dt, dt)

        stats.assess(k, KObs, 'us', mu=x, Cov=X @ Cow1 @ X.T)