Пример #1
0
def _mask_valid(obs: DataArray, sim: DataArray) -> Tuple[DataArray, DataArray]:
    # mask of invalid entries. NaNs in simulations can happen during validation/testing
    idx = (~sim.isnull()) & (~obs.isnull())

    obs = obs[idx]
    sim = sim[idx]

    return obs, sim
Пример #2
0
def _is_all_nan(obs: DataArray, sim: DataArray) -> bool:
    """Check if all observations or simulations are NaN and log a warning if this is the case. """
    all_nan = False
    if all(obs.isnull()):
        LOGGER.warning(
            "All observed values are NaN, thus metrics will be NaN, too.")
        all_nan = True
    if all(sim.isnull()):
        LOGGER.warning(
            "All simulated values are NaN, thus metrics will be NaN, too.")
        all_nan = True

    return all_nan
Пример #3
0
def _check_all_nan(obs: DataArray, sim: DataArray):
    """Check if all observations or simulations are NaN and raise an exception if this is the case.

    Raises
    ------
    AllNaNError
        If all observations or all simulations are NaN.
    """
    if all(obs.isnull()):
        raise AllNaNError(
            "All observed values are NaN, thus metrics will be NaN, too.")
    if all(sim.isnull()):
        raise AllNaNError(
            "All simulated values are NaN, thus metrics will be NaN, too.")
def _mask_valid(obs: DataArray, sim: DataArray) -> (DataArray, DataArray):
    # mask of invalid entries
    idx = (obs >= 0) & (~obs.isnull())

    obs = obs[idx]
    sim = sim[idx]

    return obs, sim
Пример #5
0
def stream_elas(da: DataArray, prcp: DataArray, coord: str = 'date') -> float:

    # rename precip coordinate name (to avoid problems with 'index' or 'date')
    prcp = prcp.rename({list(prcp.coords.keys())[0]: coord})

    # slice prcp to the same time window as the discharge
    prcp = prcp.sel({coord: slice(da.coords[coord][0], da.coords[coord][-1])})

    # determine the date of the first October 1st in the data period
    first_date = da.coords[coord][0].values.astype('datetime64[s]').astype(
        datetime)
    last_date = da.coords[coord][-1].values.astype('datetime64[s]').astype(
        datetime)

    if first_date > datetime.strptime(f'{first_date.year}-10-01', '%Y-%m-%d'):
        start_date = datetime.strptime(f'{first_date.year + 1}-10-01',
                                       '%Y-%m-%d')
    else:
        start_date = datetime.strptime(f'{first_date.year}-10-01', '%Y-%m-%d')

    end_date = start_date + relativedelta(years=1) - relativedelta(days=1)

    # mask only valid time steps (only discharge has missing values)
    idx = (da >= 0) & (~da.isnull())
    da = da[idx]
    prcp = prcp[idx]

    # calculate long-term means
    q_mean_total = da.mean()
    p_mean_total = prcp.mean()

    values = []
    while end_date < last_date:
        q = da.sel({coord: slice(start_date, end_date)})
        p = prcp.sel({coord: slice(start_date, end_date)})

        val = (q.mean() - q_mean_total) / (p.mean() - p_mean_total) * (
            p_mean_total / q_mean_total)
        values.append(val)

        start_date += relativedelta(years=1)
        end_date += relativedelta(years=1)

    return np.median([float(v) for v in values])
Пример #6
0
def stream_elas(da: DataArray,
                prcp: DataArray,
                datetime_coord: str = None) -> float:
    """Calculate stream elasticity.

    Streamflow precipitation elasticity (sensitivity of streamflow to changes in precipitation at
    the annual time scale) [#]_.

    Parameters
    ----------
    da : DataArray
        Array of flow values.
    prcp : DataArray
        Array of precipitation values.
    datetime_coord : str, optional
        Datetime coordinate in the passed DataArray. Tried to infer automatically if not specified.

    Returns
    -------
    float
        Stream elasticity.

    References
    ----------
    .. [#] Sankarasubramanian, A., Vogel, R. M., and Limbrunner, J. F.: Climate elasticity of streamflow in the
        United States. Water Resources Research, 2001, 37, 1771--1781, doi:10.1029/2000WR900330
    """
    if datetime_coord is None:
        datetime_coord = utils.infer_datetime_coord(da)

    # rename precip coordinate name (to avoid problems with 'index' or 'date')
    prcp = prcp.rename({list(prcp.coords.keys())[0]: datetime_coord})

    # slice prcp to the same time window as the discharge
    prcp = prcp.sel({
        datetime_coord:
        slice(da.coords[datetime_coord][0], da.coords[datetime_coord][-1])
    })

    # determine the date of the first October 1st in the data period
    first_date = da.coords[datetime_coord][0].values.astype(
        'datetime64[s]').astype(datetime)
    last_date = da.coords[datetime_coord][-1].values.astype(
        'datetime64[s]').astype(datetime)

    if first_date > datetime.strptime(f'{first_date.year}-10-01', '%Y-%m-%d'):
        start_date = datetime.strptime(f'{first_date.year + 1}-10-01',
                                       '%Y-%m-%d')
    else:
        start_date = datetime.strptime(f'{first_date.year}-10-01', '%Y-%m-%d')

    end_date = start_date + relativedelta(years=1) - relativedelta(seconds=1)

    # mask only valid time steps (only discharge has missing values)
    idx = (da >= 0) & (~da.isnull())
    da = da[idx]
    prcp = prcp[idx]

    # calculate long-term means
    q_mean_total = da.mean()
    p_mean_total = prcp.mean()

    values = []
    while end_date < last_date:
        q = da.sel({datetime_coord: slice(start_date, end_date)})
        p = prcp.sel({datetime_coord: slice(start_date, end_date)})

        val = (q.mean() - q_mean_total) / (p.mean() - p_mean_total) * (
            p_mean_total / q_mean_total)
        values.append(val)

        start_date += relativedelta(years=1)
        end_date += relativedelta(years=1)

    return np.median([float(v) for v in values])