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
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
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
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
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
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