Example #1
0
def rerun_model_with_alpha_uncertainty(model_conf, p, config, fwd_args):
    """
    Sample from the posterior distribution, and add extra samples to sufficiently account for (prior) uncertainty in
    alpha
    :param model_conf: Model configuration of the prior members
    :param p: Probality of the prior members
    :param config: Dict with model configuration
    :return: Forward models, sampled from posterior, with added alpha uncertainty
    """
    model_conf = np.array(model_conf)
    nr_samples = config['nr_forecast_samples']
    sample_indices = np.random.choice(np.arange(len(p)), size=nr_samples, p=p)

    # Sample from posterior
    post = model_conf[sample_indices]
    # Replace alpha uncertainty with prior uncertainty
    alpha_sample_indices = np.random.choice(np.arange(len(p)), size=nr_samples)
    for i, param in enumerate(fwd_args['free_param']):
        if param == 'alpha':
            post[:, i] = model_conf[alpha_sample_indices, i]

    # Run simulation
    results = np.zeros((post.shape[0], 12, len(fwd_args['time'])))
    for i in tqdm(range(post.shape[0]), desc='Running posterior ensemble'):
        param = post[i]
        results[i] = coronaSEIR.base_seir_model(param, fwd_args)
    return results
Example #2
0
def single_run_mean(config, data):
    ndata = np.size(data[:, 0])
    m_prior, fwd_args = parse_config(config, ndata, mode='mean')
    m_prior = reshape_prior(m_prior)
    param = m_prior[0]
    res = base_seir_model(param, fwd_args)

    try:
        posterior_param = [param]
        accc_timeinterval = config['ACCC_timeinterval']
        accc_timestart = config['ACCC_timestart']
        accc_step = config['ACCC_step']
        accc_maxstep = config['ACCC_maxstep']
        accc_step_sd = config['ACCC_step_sd']
        accc_low = config['ACCC_low']
        accc_slope = config['ACCC_slope']
        accc_scale = config['ACCC_scale']
        accc_cliplow = config['ACCC_cliplow']
        accc_cliphigh = config['ACCC_cliphigh']
        time_delay = config['time_delay']
        hammer_icu = config['hammer_ICU']
        hammer_slope = config['hammer_slope']
        hammer_release = config['hammer_release']
        hammer_alpha = config['hammer_alpha']
        accc_results = apply_accc(config['output_base_filename'],
                                  posterior_param,
                                  fwd_args,
                                  accc_timeinterval,
                                  accc_timestart,
                                  accc_maxstep,
                                  accc_step,
                                  accc_step_sd,
                                  accc_low,
                                  accc_slope,
                                  accc_scale,
                                  hammer_icu,
                                  hammer_slope,
                                  hammer_alpha,
                                  hammer_release,
                                  accc_cliplow,
                                  accc_cliphigh,
                                  time_delay,
                                  data_end=data[-1, 0])
        res = accc_results[0]

    except KeyError:
        pass

    return res
Example #3
0
def apply_hammer(posterior_fw, posterior_param, fwd_args, hammer_icu,
                 hammer_alpha, data_end):
    # For each ensemble member, see when the hammer_ICU value is crossed (upward trend)
    # Stop
    hammer_time = []
    base_day_alpha = fwd_args['locked']['dayalpha']
    for p_ind, member in enumerate(posterior_fw):
        time = member[O_TIME, :]
        time_mask = time > data_end
        time = member[O_TIME, time_mask]
        icu = member[O_ICU, time_mask]
        icu_slope = np.concatenate((np.diff(icu), [-1]))
        hammer = np.logical_and(icu >= hammer_icu, icu_slope > 0)
        try:
            hammer_time.append(min(time[hammer]))
        except ValueError:  # If hammer condition is never met in this realization:
            hammer_time.append(-1)

    hammer_time = np.array(hammer_time)
    alpha_offset = (fwd_args['free_param']).index('alpha')
    new_param = []
    new_fwd_args = []
    for h_ind, ht in enumerate(hammer_time):
        if ht > 0:
            day_alpha = copy.deepcopy(base_day_alpha)
            day_alpha[day_alpha >= ht] = ht
            param = copy.deepcopy(posterior_param[h_ind])
            new_alpha = np.random.uniform(*hammer_alpha)
            change_alpha = np.where(day_alpha == ht)[0] + alpha_offset
            param[change_alpha] = new_alpha
            n_fwd = copy.deepcopy(fwd_args)
            n_fwd['locked']['dayalpha'] = day_alpha
            new_param.append(param)
            new_fwd_args.append(n_fwd)
        else:
            new_param.append(posterior_param[h_ind])
            new_fwd_args.append(copy.deepcopy(fwd_args))

    # Run the updated posterior (with hammer applied) again
    result = []
    for p_ind, param in enumerate(
            tqdm(new_param, desc='Running hammered posterior')):
        fwd = new_fwd_args[p_ind]
        result.append(base_seir_model(param, fwd))

    return result
Example #4
0
def find_N(config, data, imatch=I_DEAD, itarget=10):
    """
    Create a prior ensemble of model runs.
    :param config: The entire model configuration in dict-form
    :param  imatch:  column in data to match N
    :param  itarget: number of target value to match N
    :return: N to use
    """

    np.random.seed(1)
    # Parse parameters
    #  get just 1 base case sample corresponding to average

    # results = np.zeros((len(m_prior), 13, len(fwd_args['time'])))

    i_mod = o_calmodes[imatch]
    i_obs = i_calmodes[imatch]
    obsdead = data[:, i_obs]
    time_delay = config['time_delay']
    obsdead_index = np.where(obsdead > itarget)[0][0] + time_delay
    found = False
    icount = 0
    ncountmax = 50
    nnew = 1000

    ndata = np.size(data[:, 0])
    m_prior, fwd_args = parse_config(config, ndata, mode='mean')
    m_prior = reshape_prior(m_prior)
    param = m_prior[0]

    while not found and icount < ncountmax:
        fwd_args['locked']['n'] = nnew
        res = base_seir_model(param, fwd_args)
        moddead = res[i_mod, :]
        moddead_index = np.where(moddead > itarget)

        print('moddead index, obsdead index ', moddead_index[0][0],
              obsdead_index)
        found = moddead_index[0][0] >= obsdead_index
        if not found:
            icount += 1
            nnew = fwd_args['locked']['n'] * 2
            fwd_args['locked']['n'] = nnew

    return nnew
Example #5
0
def run_prior(config):
    """
    Create a prior ensemble of model runs.
    :param config: The entire model configuration in dict-form
    :return: Forward model results, the parameter sets used to create them, and an array of timesteps
    """
    np.random.seed(1)
    # Parse parameters
    m_prior, fwd_args = parse_config(config)
    m_prior = reshape_prior(m_prior)

    # Run simulation
    results = np.zeros((len(m_prior), 12, len(fwd_args['time'])))
    for i in tqdm(range(len(m_prior)), desc='Running prior ensemble'):
        param = m_prior[i]
        results[i] = coronaSEIR.base_seir_model(param, fwd_args)

    tnew = fwd_args['time'] - fwd_args['time_delay']

    return results, tnew, m_prior, fwd_args
Example #6
0
def apply_accc(base_filename, posterior_param, fwd_args, accc_timeinterval,
               accc_timestart, accc_maxstep, accc_step, accc_step_sd, accc_low,
               accc_slope, accc_scale, hammer_icu, hammer_slope, hammer_alpha,
               hammer_release, accc_cliplow, accc_cliphigh, time_delay,
               data_end):
    # For each ensemble member, see when the hammer_ICU value is crossed (upward trend)
    # Stop
    hammer_time = []
    base_day_alpha = fwd_args['locked']['dayalpha']
    # print('isample,hammertime,icu@hammer,icuslope@hammer,icumaxtime,icumax')

    #day_mon = int (data_end +time_delay)

    #day_mon += (accc_timestart - data_end)

    alpha_offset = (fwd_args['free_param']).index('alpha')

    result = []

    table_diagnostics = []
    table_hammer_diagnostics = []
    # numberofdays forward in baseSEIR
    ndaysforward = 800
    ndaysforward = max(accc_timeinterval, ndaysforward)

    # for p_ind, member in enumerate(posterior_fw):
    for p_ind in tqdm(range(len(posterior_param)),
                      desc='running ACCC posterior'):
        day_alpha = copy.deepcopy(base_day_alpha)

        day_mon_start = int(data_end + time_delay)
        day_mon_start += int(accc_timestart - data_end)
        day_mon_start_accc = max(day_mon_start,
                                 day_alpha[-1])  #2*accc_timeinterval

        # run default forward just in case
        res = base_seir_model(posterior_param[p_ind], fwd_args)
        time = res[O_TIME, :]
        time_end = time[-1]
        # start with a copy of the base_day_alpha
        param = copy.deepcopy(posterior_param[p_ind])
        n_fwd = copy.deepcopy(fwd_args)
        alpha_scale_last = 0

        nlookahead = 7  # 7 #accc_timeinterval

        day_mon = day_mon_start

        #ndayshammer = 28
        #lastday_hammer = day_mon-ndayshammer
        # flag hammer has been released
        lastday_hammer = -1
        isteps = 0
        alpha_scale_sum = 0
        while day_mon < time_end:

            accc_ok = (day_mon - day_mon_start_accc) >= 0
            icu = res[O_ICU, :]
            icu_slope = np.concatenate((np.diff(icu), [-1]))
            icu_slope = np.roll(icu_slope, 1)
            icu_slope2 = icu_slope[day_mon +
                                   nlookahead] - icu_slope[day_mon +
                                                           nlookahead - 1]

            # check if the hammer needs to be applied
            if lastday_hammer > 0:
                if icu[day_mon] < hammer_release and icu_slope[day_mon] < 0:
                    lastday_hammer = -1
            donothing = (lastday_hammer > 0)
            #donothing = ((day_mon- lastday_hammer) < ndayshammer )
            dohammer = signal_hammer(icu[day_mon], icu_slope[day_mon],
                                     hammer_icu, hammer_slope)
            if donothing:
                pass
            elif dohammer:
                ht = day_mon
                a = hammer_alpha
                hammer_mean = 0.5 * (a[0] + a[1])
                hammer_sd = ((1.0 / np.sqrt(12)) * (a[1] - a[0]))
                hammer_alpha_normal = [hammer_mean, hammer_sd]
                alphastep = np.random.normal(hammer_mean, hammer_sd)
                fwd_freeparam1 = n_fwd['free_param'][0:alpha_offset]

                fwd_alfa = n_fwd['free_param'][alpha_offset:len(day_alpha) +
                                               alpha_offset]
                fwd_freeparam2 = n_fwd['free_param'][len(day_alpha) +
                                                     alpha_offset:]
                freeparamdict = copy.deepcopy(fwd_freeparam1)
                for i, element in enumerate(fwd_alfa):
                    freeparamdict.append(element)
                    # add one more alpha
                    if i == 0:
                        freeparamdict.append(element)
                for i, element in enumerate(fwd_freeparam2):
                    freeparamdict.append(element)

                # append day alpha
                day_alpha = np.append(day_alpha, ht)
                change_alpha = alpha_offset + len(day_alpha) - 1
                alphanew = alphastep

                # restructure param to include alphanew
                param = np.concatenate(
                    (param[0:change_alpha], [alphanew], param[change_alpha:]),
                    axis=None)

                n_fwd['locked']['dayalpha'] = day_alpha
                n_fwd['free_param'] = freeparamdict

                # res = base_seir_model(param, n_fwd, trestart= day_mon, tend= day_mon+ndaysforward, lastresult=res)
                res = base_seir_model(param,
                                      n_fwd,
                                      trestart=day_mon,
                                      lastresult=res)

                alpha_scale_last = 0
                # collect hammer diagnostics
                icu = res[O_ICU, :]
                icuconsider = icu[day_mon:day_mon + ndaysforward]
                icumax = max(icuconsider)
                icumin = min(icuconsider)
                day_max = np.where(
                    icuconsider >= icumax)[0][0] - time_delay + day_mon
                day_min = np.where(
                    icuconsider <= icumin)[0][0] - time_delay + day_mon
                row_diagnostics = np.array([
                    p_ind, day_mon - time_delay, day_min, day_max,
                    icu[day_mon], icu_slope[day_mon], icumin, icumax, alphastep
                ])
                table_hammer_diagnostics.append(row_diagnostics)
                lastday_hammer = day_mon
                alpha_scale_sum = 0
                #  check if it is time to adapt the ACCC
            elif accc_ok and ((day_mon - day_mon_start) %
                              accc_timeinterval) == 0:

                model_forecast = False
                if model_forecast:
                    icu_forecast = icu[day_mon + nlookahead]
                    icu_slope_forecast = icu_slope[day_mon + nlookahead]
                    icu_slope2_forecast = icu_slope[
                        day_mon + nlookahead] - icu_slope[day_mon +
                                                          nlookahead - 1]
                else:
                    icu_slope2_forecast = icu_slope[day_mon] - icu_slope[
                        day_mon - 1]
                    icu_slope_forecast = icu_slope[
                        day_mon] + nlookahead * icu_slope2_forecast
                    # use second order taylor approximation for forecast
                    icu_forecast = icu[day_mon] + nlookahead * icu_slope[day_mon] + \
                                   0.5 * (nlookahead**2) * icu_slope2_forecast

                alpha_scale = get_alpha_scale(icu_forecast, icu_slope_forecast,
                                              icu_slope2_forecast, accc_low,
                                              accc_scale, accc_slope)

                alpha_scale_sum += alpha_scale
                # if (alpha_scale_last==alpha_scale):
                #    alpha_scale = 0
                alphastep = 0
                if alpha_scale != 0 and alpha_scale_sum >= -accc_maxstep:
                    # change the last active alpha active before daymon

                    ht = day_mon
                    # sign = 0
                    alphastep = np.random.normal(
                        accc_step * alpha_scale,
                        accc_step_sd * abs(alpha_scale))
                    # print('pind step at day, level icu,slope, sign, alphastep ', p_ind, ht,
                    #       icu[day_mon], icu_slope[day_mon], sign, alphastep)

                    fwd_freeparam1 = n_fwd['free_param'][0:alpha_offset]
                    # last_alpha = np.where(day_alpha == ht)[0] + alpha_offset

                    fwd_alfa = n_fwd['free_param'][alpha_offset:len(day_alpha
                                                                    ) +
                                                   alpha_offset]
                    fwd_freeparam2 = n_fwd['free_param'][len(day_alpha) +
                                                         alpha_offset:]
                    freeparamdict = copy.deepcopy(fwd_freeparam1)
                    for i, element in enumerate(fwd_alfa):
                        freeparamdict.append(element)
                        # add one more alpha
                        if i == 0:
                            freeparamdict.append(element)
                    for i, element in enumerate(fwd_freeparam2):
                        freeparamdict.append(element)

                    # append day alpha
                    day_alpha = np.append(day_alpha, ht)
                    change_alpha = alpha_offset + len(day_alpha) - 1
                    alphanew = param[change_alpha - 1] + alphastep
                    alphanew = max(accc_cliplow, min(accc_cliphigh, alphanew))

                    # restructure param to include alphanew
                    param = np.concatenate(
                        (param[0:change_alpha], [alphanew
                                                 ], param[change_alpha:]),
                        axis=None)

                    n_fwd['locked']['dayalpha'] = day_alpha
                    n_fwd['free_param'] = freeparamdict

                    #res = base_seir_model(param, n_fwd, trestart= day_mon, tend= day_mon+ndaysforward, lastresult=res)
                    res = base_seir_model(param,
                                          n_fwd,
                                          trestart=day_mon,
                                          lastresult=res)
                    #res = base_seir_model(param, n_fwd)

                alpha_scale_last = alpha_scale

                icuconsider = icu[day_mon - accc_timeinterval:day_mon + 1]
                icumax = max(icuconsider)
                icumin = min(icuconsider)
                day_max = np.where(
                    icuconsider >= icumax
                )[0][0] - time_delay - day_mon - accc_timeinterval
                day_min = np.where(
                    icuconsider <= icumin
                )[0][0] - time_delay - day_mon - accc_timeinterval
                row_diagnostics = np.array([
                    p_ind, day_mon - time_delay, day_min, day_max,
                    icu[day_mon], icu_slope[day_mon], icumin, icumax, alphastep
                ])
                table_diagnostics.append(row_diagnostics)

            day_mon = day_mon + 1

        result.append(res)

    # save the diagnostics file of the
    # Add this to have a output folder in main directory
    outpath = os.path.join(os.getcwd(), 'bin', 'output', base_filename)
    # outpath = os.path.join(os.path.split(os.getcwd())[0], 'output', base_filename)

    header = 'sampleid,daymon,daymin, daymax,icu,icurate,icumin,icumax,alphastep'
    table = np.array(table_diagnostics)
    # table =  table[:,0:5] #np.concatenate((datanew[:, 0:6]), axis=-1)
    np.savetxt('{}_accc_diagnostics{}.csv'.format(outpath, '', ''),
               table,
               header=header,
               delimiter=',',
               comments='',
               fmt='%.2f')
    table = np.array(table_hammer_diagnostics)
    # table =  table[:,0:5] #np.concatenate((datanew[:, 0:6]), axis=-1)
    np.savetxt('{}_hammer_diagnostics{}.csv'.format(outpath, '', ''),
               table,
               header=header,
               delimiter=',',
               comments='',
               fmt='%.2f')
    return result