def det_cont_fct_accum(err, pred, obs):
    """Accumulate the forecast error in the verification error object.

    Parameters
    ----------
    err: dict
        A verification error object initialized with
        :py:func:`pysteps.verification.detcontscores.det_cont_fct_init`.
    pred: array_like
        Array of predictions. NaNs are ignored.
    obs: array_like
        Array of verifying observations. NaNs are ignored.

    References
    ----------
    Chan, Tony F.; Golub, Gene H.; LeVeque, Randall J. (1979), "Updating
    Formulae and a Pairwise Algorithm for Computing Sample Variances.",
    Technical Report STAN-CS-79-773, Department of Computer Science,
    Stanford University.

    Schubert, Erich; Gertz, Michael (2018-07-09). "Numerically stable parallel
    computation of (co-)variance". ACM: 10. doi:10.1145/3221269.3223036.
    """

    pred = np.asarray(pred.copy())
    obs = np.asarray(obs.copy())
    axis = tuple(range(pred.ndim)) if err["axis"] is None else err["axis"]

    # checks
    if pred.shape != obs.shape:
        raise ValueError(
            "the shape of pred does not match the shape of obs %s!=%s"
            % (pred.shape, obs.shape)
        )

    if pred.ndim <= np.max(axis):
        raise ValueError(
            "axis %d is out of bounds for array of dimension %d"
            % (np.max(axis), len(pred.shape))
        )

    idims = [dim not in axis for dim in range(pred.ndim)]
    nshape = tuple(np.array(pred.shape)[np.array(idims)])
    if err["cov"] is None:
        # initialize the error arrays in the verification object
        err["cov"] = np.zeros(nshape)
        err["vobs"] = np.zeros(nshape)
        err["vpred"] = np.zeros(nshape)
        err["mobs"] = np.zeros(nshape)
        err["mpred"] = np.zeros(nshape)
        err["me"] = np.zeros(nshape)
        err["mse"] = np.zeros(nshape)
        err["mss"] = np.zeros(nshape)
        err["mae"] = np.zeros(nshape)
        err["n"] = np.zeros(nshape)

    else:
        # check dimensions
        if err["cov"].shape != nshape:
            raise ValueError(
                "the shape of the input arrays does not match "
                + "the shape of the "
                + "verification object %s!=%s" % (nshape, err["cov"].shape)
            )

    # conditioning
    if err["conditioning"] is not None:
        if err["conditioning"] == "single":
            idx = np.logical_or(obs > err["thr"], pred > err["thr"])
        elif err["conditioning"] == "double":
            idx = np.logical_and(obs > err["thr"], pred > err["thr"])
        else:
            raise ValueError("unkown conditioning %s" % err["conditioning"])
        obs[~idx] = np.nan
        pred[~idx] = np.nan

    # add dummy axis in case integration is not required
    if np.max(axis) < 0:
        pred = pred[None, :]
        obs = obs[None, :]
        axis = (0,)
    axis = tuple([a for a in axis if a >= 0])

    # compute residuals
    res = pred - obs
    sum = pred + obs
    n = np.sum(np.isfinite(res), axis=axis)

    # new means
    mobs = np.nanmean(obs, axis=axis)
    mpred = np.nanmean(pred, axis=axis)
    me = np.nanmean(res, axis=axis)
    mse = np.nanmean(res**2, axis=axis)
    mss = np.nanmean(sum**2, axis=axis)
    mae = np.nanmean(np.abs(res), axis=axis)

    # expand axes for broadcasting
    for ax in sorted(axis):
        mobs = np.expand_dims(mobs, ax)
        mpred = np.expand_dims(mpred, ax)

    # new cov matrix
    cov = np.nanmean((obs - mobs) * (pred - mpred), axis=axis)
    vobs = np.nanmean(np.abs(obs - mobs) ** 2, axis=axis)
    vpred = np.nanmean(np.abs(pred - mpred) ** 2, axis=axis)

    mobs = mobs.squeeze()
    mpred = mpred.squeeze()

    # update variances
    _parallel_var(err["mobs"], err["n"], err["vobs"], mobs, n, vobs)
    _parallel_var(err["mpred"], err["n"], err["vpred"], mpred, n, vpred)

    # update covariance
    _parallel_cov(err["cov"], err["mobs"], err["mpred"], err["n"], cov, mobs, mpred, n)

    # update means
    _parallel_mean(err["mobs"], err["n"], mobs, n)
    _parallel_mean(err["mpred"], err["n"], mpred, n)
    _parallel_mean(err["me"], err["n"], me, n)
    _parallel_mean(err["mse"], err["n"], mse, n)
    _parallel_mean(err["mss"], err["n"], mss, n)
    _parallel_mean(err["mae"], err["n"], mae, n)

    # update number of samples
    err["n"] += n
Accumulate the forecast error in the verification error object.

Parameters
----------
err: dict
A verification error object initialized with
:py:func:`pysteps.verification.detcontscores.det_cont_fct_init`.
pred: array_like
Array of predictions. NaNs are ignored.
obs: array_like
Array of verifying observations. NaNs are ignored.

References
----------
Chan, Tony F.; Golub, Gene H.; LeVeque, Randall J. (1979), "Updating
Formulae and a Pairwise Algorithm for Computing Sample Variances.",
Technical Report STAN-CS-79-773, Department of Computer Science,
Stanford University.

Schubert, Erich; Gertz, Michael (2018-07-09). "Numerically stable parallel
computation of (co-)variance". ACM: 10. doi:10.1145/3221269.3223036.
pysteps/verification/detcontscores.py