示例#1
0
def _survivorship(lx_year, ruler, ruler_extended, **kwargs):
    """Iterate over survivorship by week.

    The survivorship is used to age the population week-by-week, starting
    from the last past year.

    Because pop is reported at the mid-year point, we first age the last
    past year by 1/2 year (using last past year's lx).  Then, for all forecast
    years, we age all weeks of each year by that year's lx.  For example,
    if 2017 is the last past year, we use lx from 2017 to age the 2017 pop for
    half a year (26 weeks) to reach 01-01-2018.  Then we use lx from 2018 to
    age the pop for an entire year (52 weeks) to reach 01-01-2019, and so on.

    Args:
        lx_year (np.array): lx in shape (sex_id, age_group_id).
        ruler (Ruler): ruler object that maps fbd age groups to weeks.
        ruler_extended (Ruler): identical to ruler, but with 5-year age groups
            within the fhs terminal age group.

    Returns:
        (np.array): for every week, returns np.array in the shape of
            (sex_id, 1 + len(ruler.x_ww)), where 1 corresponds to nL0 and
            len(ruler.x_ww) corresponds to the survivorship elements of the
            Leslie matrix.
    """
    nLx = lx_to_nLx_weeks(lx_year, ruler, ruler_extended)
    traceplot("nLx", nLx[1])
    survivorship = nLx_to_survivorship(nLx)
    traceplot("surv", survivorship[1])
    return survivorship
示例#2
0
def _migration(migration_year, ruler, **kwargs):
    """Iterate over migration by week, analogous to method in _survivorship().

    Args:
        migration_year (np.array): in shape of (year_id, sex_id, age_group_id).
        ruler (Ruler): maps migration data age groups to weeks.

    Returns:
        (np.array): weekly iterated migration.
    """
    migration_weekly = _migration_to_weeks(migration_year, ruler)
    traceplot("migrationw", migration_weekly[0])
    return migration_weekly
示例#3
0
def population_to_weeks_by_projection(population, ruler):
    """
    Converts population on age group Ids to weekly populations
    using a simple projection matrix, so you get a stairwise step
    function of population.
    """
    assert population.shape[0] == 2
    averaging = uneven_average(ruler.nx_gw)
    LOGGER.debug("averaging shape {}".format(averaging.shape))
    pop_weeks = np.einsum("wa,sa->sw", averaging, population)
    traceplot("pop_weeks", pop_weeks[0])
    assert pop_weeks.shape[0] == 2
    return pop_weeks
示例#4
0
def _asfr(asfr_year, ruler, **kwargs):
    """Iterate over ASFR by week, analogous to method in _survivorship().

    Args:
        asfr_year (np.array): array in shape of (year_id, age_group_id).
        ruler (Ruler): maps asfr age groups to weeks.

    Returns:
        (np.array): weekly iterated asfr.
        (np.array): fertile age group ids.
    """
    projected = asfr_to_weeks(asfr_year)
    traceplot("asfr_projected", projected)
    return projected, ruler.fertile
示例#5
0
def lx_to_nLx_weeks(lx, ruler, ruler_extended):
    """
    Integrates a fitted lx curve to compute nLx, which would be used to compute
    survivorship downstream.

    Args:
        lx (np.array): lx with extrapolated values beyond fhs terminal age
            group start.
        ruler (Ruler): ruler for the fhs age groups.  This ruler determines
            #the age group starts that need to be returned2
        ruler_extended (Ruler): ruler that matches lx.  This ruler, along with
            lx, provide the points for interpolation.

    Returns:
        (np.array): nLx, in shape of (sex, age), where age corresponds to
            fhs age group ids.
    """
    assert has_dims(lx, "sex age")
    LOGGER.debug("lx dims {}".format(lx.shape))

    # We need 2 extra data points beyond the terminal age group start to
    # compute its survivorship: terminal_age_start + 1 week, and 110 years.
    x_all_weeks = np.concatenate(
        [ruler.x_ww, [ruler.x_ww[-1] + 1,
                      ruler_extended.x_ww[-1]]])  # all in weeks

    integrated_lx = list()
    for sex in [0, 1]:
        # first interpolate lx over the "extended" fhs age groups (in weeks)
        fit = PchipInterpolator(ruler_extended.x_gw, lx[sex], extrapolate=True)
        # now integrate lx and evaluate over all weeks
        integrate_once = 1
        integrated = fit.antiderivative(integrate_once)(x_all_weeks)
        LOGGER.debug("integrated lx end {}".format(integrated[-5:]))
        traceplot("integrated_lx", x_all_weeks, integrated)
        integrated_lx.append(integrated)
    lx_int_sexed = np.vstack(integrated_lx)
    # Will be one less than number of weeks
    return np.diff(lx_int_sexed, 1, axis=1)
示例#6
0
def project_draw(asfr, lx, migration, pop_start_year, srb, ruler,
                 ruler_extended, migration_ruler, forecast_years):
    """
    Take datasets and produce future populations.
    The datasets have to start with the year for the observed population.
    This data is all Numpy arrays, all for the same
    location, scenario, and draw. That means it will be organized by
    (year_id, sex_id, age_group_id) with exceptions as noted below.

    Args:
        asfr (np.ndarray): Age-specific fertility rate, organized as
            (year_id, age_group_id).

        lx (np.ndarray): :math:`l_x`, organized as
            (year_id, sex_id, age_group_id).

        migration (np.ndarray): Migration, organized as
            (year_id, sex_id, age_group_id).

        pop_start_year (np.ndarray): Starting population, organized as
            (sex_id, age_group_id).

        srb (np.ndarray): Sex ratio at birth with just one value
            for the last past year

        ruler (Ruler): Time scales for conversion to weeks.

        ruler_extended (Ruler): identical to ruler, but with 5-year age groups
            within the fhs terminal age group.

        migration_ruler (Ruler): Time scales for conversion from years to
            weeks.

        forecast_years (list): The list of all years in the forecast

    Returns:
        np.ndarray: Population at starting and all future years.
    """
    # All ndarrays at this point.
    assert has_dims(asfr, "year age")
    assert has_dims(lx, "year, sex, age")
    assert has_dims(migration, "year sex age")
    assert has_dims(pop_start_year, "sex, age")

    # Project from middle of first year to middle of last year.
    year_cnt = len(forecast_years)
    assert year_cnt <= lx.shape[0] - 1, "Not enough years in lx"
    assert year_cnt <= asfr.shape[0] - 1, "Not enough years in asfr"
    pop_save = np.zeros((year_cnt, ) + pop_start_year.shape, dtype=np.double)
    pop_buffer = population_to_weeks(pop_start_year, ruler)

    survivorship_iter = _pop_aging_iterator(_survivorship,
                                            lx,
                                            ruler,
                                            ruler_extended=ruler_extended)
    asfr_iter = _pop_aging_iterator(_asfr, asfr, ruler)
    migration_iter = _pop_aging_iterator(_migration, migration,
                                         migration_ruler)

    save_year = 0

    for step_idx in range(ruler.ratio * year_cnt):
        asfr, age_limits = next(asfr_iter)
        survivorship = next(survivorship_iter)
        migration = next(migration_iter)
        traceplot("pop_buffer_in", pop_buffer[1])

        leslie = LeslieMatrix(asfr, age_limits[0], survivorship, float(srb))
        pop_t_plus_one = leslie.increment(pop_buffer)

        pop_buffer = pop_t_plus_one + migration

        if np.any(pop_buffer < 0):
            leslie_error_cnt = np.sum(pop_t_plus_one < 0)
            survivorship_neg = np.sum(survivorship < 0)
            asfr_neg = np.sum(asfr < 0)
            if leslie_error_cnt > 0:
                LOGGER.error("Leslie matrix negative values {} {} {}".format(
                    leslie_error_cnt, survivorship_neg, asfr_neg))
            pop_buffer[pop_buffer < 0] = 0

        LOGGER.debug("pop_mig young F {}".format(pop_buffer[1, :10]))
        traceplot("pop_buffer_out", pop_buffer[1])
        LOGGER.debug("pop {:3g}".format(pop_buffer.sum()))

        year_idx = (step_idx + 1) // ruler.ratio
        if save_year != year_idx:
            pop_save[year_idx - 1] = \
                population_to_groups(pop_buffer, ruler.nx_gw)
            LOGGER.debug("pop save step {} {:3g}".format(
                step_idx, pop_save[year_idx - 1].sum()))
            save_year = year_idx

    if POP_MINIMUM is not None:
        pop_save[pop_save < POP_MINIMUM] = POP_MINIMUM
    return pop_save