def validate_pars(self): ''' Some parameters can take multiple types; this makes them consistent ''' # Handle start day start_day = self['start_day'] # Shorten if start_day in [None, 0]: # Use default start day start_day = dt.datetime(2020, 1, 1) if not isinstance(start_day, dt.datetime): start_day = sc.readdate(start_day) self['start_day'] = start_day # Convert back # Handle population data popdata_choices = ['random', 'bayesian', 'data'] if sc.isnumber(self['usepopdata']) or isinstance( self['usepopdata'], bool): # Convert e.g. usepopdata=1 to 'bayesian' self['usepopdata'] = popdata_choices[int( self['usepopdata'])] # Choose one of these if self['usepopdata'] not in popdata_choices: choice = self['usepopdata'] choicestr = ', '.join(popdata_choices) errormsg = f'Population data option "{choice}" not available; choices are: {choicestr}' raise ValueError(errormsg) # Handle interventions self['interventions'] = sc.promotetolist(self['interventions'], keepnone=False) return
def make_safegraph(sim, mobility_file): ''' Create interventions representing SafeGraph data ''' # Load data.values if mobility_file is None: fn = safegraph_file else: fn = mobility_file df = pd.read_csv(fn) week = df['week'] w = c = df['p.tot'].values # w = df['p.emp'].values # c = df['p.cust'].values # Do processing npts = len(week) start_date = sc.readdate(week[0], dateformat='%Y-%m-%d') start_day = sim.day(start_date) sg_days = start_day + 7 * np.arange(npts) # Create interventions interventions = [ cv.clip_edges(days=sg_days, changes=w, layers='w', label='clip_w'), cv.clip_edges(days=sg_days, changes=c, layers='c', label='clip_c'), ] return interventions
def validate_pars(self): ''' Some parameters can take multiple types; this makes them consistent ''' # Handle start day start_day = self['start_day'] # Shorten if start_day in [None, 0]: # Use default start day start_day = dt.date(2020, 1, 1) elif sc.isstring(start_day): start_day = sc.readdate(start_day) if isinstance(start_day,dt.datetime): start_day = start_day.date() self['start_day'] = start_day # Handle contacts contacts = self['contacts'] if sc.isnumber(contacts): # It's a scalar instead of a dict, assume it's all contacts self['contacts'] = {'a':contacts} self['beta_layers'] = {'a':1.0} # Handle population data popdata_choices = ['random', 'microstructure', 'synthpops'] if sc.isnumber(self['pop_type']) or isinstance(self['pop_type'], bool): # Convert e.g. pop_type=1 to 'microstructure' self['pop_type'] = popdata_choices[int(self['pop_type'])] # Choose one of these if self['pop_type'] not in popdata_choices: choice = self['pop_type'] choicestr = ', '.join(popdata_choices) errormsg = f'Population type "{choice}" not available; choices are: {choicestr}' raise ValueError(errormsg) # Handle interventions self['interventions'] = sc.promotetolist(self['interventions'], keepnone=False) return
def day(obj, *args, start_day=None): ''' Convert a string, date/datetime object, or int to a day (int), the number of days since the start day. See also date() and daydiff(). Used primarily via sim.day() rather than directly. Args: obj (str, date, int, or list): convert any of these objects to a day relative to the start day args (list): additional days start_day (str or date): the start day; if none is supplied, return days since 2020-01-01. Returns: days (int or str): the day(s) in simulation time **Example**:: sim.day('2020-04-05') # Returns 35 ''' # Do not process a day if it's not supplied if obj is None: return None if start_day is None: start_day = '2020-01-01' # Convert to list if sc.isstring(obj) or sc.isnumber(obj) or isinstance( obj, (dt.date, dt.datetime)): obj = sc.promotetolist(obj) # Ensure it's iterable elif isinstance(obj, np.ndarray): obj = obj.tolist() # Convert to list if it's an array obj.extend(args) days = [] for d in obj: if d is None: days.append(d) elif sc.isnumber(d): days.append(int(d)) # Just convert to an integer else: try: if sc.isstring(d): d = sc.readdate(d).date() elif isinstance(d, dt.datetime): d = d.date() d_day = (d - date(start_day) ).days # Heavy lifting -- actually compute the day days.append(d_day) except Exception as E: errormsg = f'Could not interpret "{d}" as a date: {str(E)}' raise ValueError(errormsg) # Return an integer rather than a list if only one provided if len(days) == 1: days = days[0] return days
def validate_pars(self): ''' Some parameters can take multiple types; this makes them consistent ''' # Handle types for key in ['pop_size', 'pop_infected', 'pop_size', 'n_days']: self[key] = int(self[key]) # Handle start day start_day = self['start_day'] # Shorten if start_day in [None, 0]: # Use default start day start_day = dt.date(2020, 1, 1) elif sc.isstring(start_day): start_day = sc.readdate(start_day) if isinstance(start_day, dt.datetime): start_day = start_day.date() self['start_day'] = start_day # Handle contacts contacts = self['contacts'] if sc.isnumber( contacts ): # It's a scalar instead of a dict, assume it's all contacts self['contacts'] = {'a': contacts} # Handle key mismaches beta_layer_keys = set(self.pars['beta_layer'].keys()) contacts_keys = set(self.pars['contacts'].keys()) quar_eff_keys = set(self.pars['quar_eff'].keys()) if not (beta_layer_keys == contacts_keys == quar_eff_keys): errormsg = f'Layer parameters beta={beta_layer_keys}, contacts={contacts_keys}, quar_eff={quar_eff_keys} have inconsistent keys' raise cvm.KeyNotFoundError(errormsg) if self.people is not None: pop_keys = set(self.people.contacts.keys()) if pop_keys != beta_layer_keys: errormsg = f'Please update your parameter keys {beta_layer_keys} to match population keys {pop_keys}. You may find sim.reset_layer_pars() helpful.' raise cvm.KeyNotFoundError(errormsg) # Handle population data popdata_choices = ['random', 'hybrid', 'clustered', 'synthpops'] choice = self['pop_type'] if choice not in popdata_choices: choicestr = ', '.join(popdata_choices) errormsg = f'Population type "{choice}" not available; choices are: {choicestr}' raise cvm.KeyNotFoundError(errormsg) # Handle interventions self['interventions'] = sc.promotetolist(self['interventions'], keepnone=False) return
def begin_day(self, date): ''' Called at the beginning of each day to configure the school layer ''' dayname = sc.readdate(date).strftime('%A') group = self.schedule[dayname] self.school_day = group == 'all' # Could modify layer based on group if group == 'all': # Start with the original layer, will remove uids at home later self.layer = sc.dcp(self.base_layer) # needed? uids = self.uids else: self.layer = cv.Layer() # Empty uids = np.empty(0, dtype='int64') return uids # Everyone is scheduled for school today, unless it's a weekend
def date(obj, *args, **kwargs): ''' Convert a string or a datetime object to a date object. To convert to an integer from the start day, use sim.date() instead. Args: obj (str, date, datetime): the object to convert args (str, date, datetime): additional objects to convert Returns: dates (date or list): either a single date object, or a list of them **Examples**:: cv.date('2020-04-05') # Returns datetime.date(2020, 4, 5) ''' # Convert to list if sc.isstring(obj) or sc.isnumber(obj) or isinstance( obj, (dt.date, dt.datetime)): obj = sc.promotetolist(obj) # Ensure it's iterable obj.extend(args) dates = [] for d in obj: try: if type( d ) == dt.date: # Do not use isinstance, since must be the exact type pass elif sc.isstring(d): d = sc.readdate(d).date() elif isinstance(d, dt.datetime): d = d.date() else: errormsg = f'Could not interpret "{d}" of type {type(d)} as a date' raise TypeError(errormsg) dates.append(d) except Exception as E: errormsg = f'Conversion of "{d}" to a date failed: {str(E)}' raise ValueError(errormsg) # Return an integer rather than a list if only one provided if len(dates) == 1: dates = dates[0] return dates
def day(self, day, *args): ''' Convert a string, date/datetime object, or int to a day (int). Args: day (str, date, int, or list): convert any of these objects to a day relative to the simulation's start day Returns: days (int or str): the day(s) in simulation time **Example**:: sim.day('2020-04-05') # Returns 35 ''' # Do not process a day if it's not supplied if day is None: return None # Convert to list if sc.isstring(day) or sc.isnumber(day) or isinstance( day, (dt.date, dt.datetime)): day = sc.promotetolist(day) # Ensure it's iterable day.extend(args) days = [] for d in day: if sc.isnumber(d): days.append(int(d)) # Just convert to an integer else: try: if sc.isstring(d): d = sc.readdate(d).date() elif isinstance(d, dt.datetime): d = d.date() d_day = (d - self['start_day']).days days.append(d_day) except Exception as E: errormsg = f'Could not interpret "{d}" as a date: {str(E)}' raise ValueError(errormsg) # Return an integer rather than a list if only one provided if len(days) == 1: days = days[0] return days
def begin_day(self, date): ''' Called at the beginning of each day to configure the school layer ''' dayname = sc.readdate(date).strftime('%A') group = self.schedule[dayname] self.school_day = group in ['A', 'B'] # Could modify layer based on group if group == 'A': self.layer = sc.dcp(self.A_base_layer) # needed? uids = self.A_group elif group == 'B': self.layer = sc.dcp(self.B_base_layer) # needed? uids = self.B_group else: uids = np.empty(0, dtype='int64') self.layer = cv.Layer() # Empty return uids # Hybrid scheduling
def test_readdate(): sc.heading('Test string-to-date conversion') string1 = '2020-Mar-21' string2 = '2020-03-21' string3 = 'Sat Mar 21 23:13:56 2020' dateobj1 = sc.readdate(string1) dateobj2 = sc.readdate(string2) sc.readdate(string3) assert dateobj1 == dateobj2 with pytest.raises(ValueError): sc.readdate('Not a date') # Automated tests formats_to_try = sc.readdate(return_defaults=True) for key, fmt in formats_to_try.items(): datestr = sc.getdate(dateformat=fmt) dateobj = sc.readdate(datestr, dateformat=fmt) print(f'{key:15s} {fmt:22s}: {dateobj}') return dateobj1
def test_base(): sc.heading('Testing base.py sim...') json_path = 'base_tests.json' sim_path = 'base_tests.sim' # Create a small sim for later use sim = cv.Sim(pop_size=100, verbose=verbose) sim.run() # Check setting invalid key with pytest.raises(sc.KeyNotFoundError): po = cv.ParsObj(pars={'a': 2, 'b': 3}) po.update_pars({'c': 4}) # Printing result r = cv.Result() print(r) print(r.npts) # Day and date conversion daystr = '2020-04-04' sim.day(daystr) sim.day(sc.readdate(daystr)) with pytest.raises(ValueError): sim.day('not a date') sim.date(34) sim.date([34, 54]) sim.date(34, 54, as_date=True) # BaseSim methods sim.copy() sim.export_results(filename=json_path) sim.export_pars(filename=json_path) sim.shrink(in_place=False) for keep_people in [True, False]: sim.save(filename=sim_path, keep_people=keep_people) cv.Sim.load(sim_path) # Tidy up remove_files(json_path, sim_path) return
def validate_pars(self): ''' Some parameters can take multiple types; this makes them consistent ''' # Handle start day start_day = self['start_day'] # Shorten if start_day in [None, 0]: # Use default start day start_day = dt.date(2020, 1, 1) elif sc.isstring(start_day): start_day = sc.readdate(start_day) if isinstance(start_day, dt.datetime): start_day = start_day.date() self['start_day'] = start_day # Handle contacts contacts = self['contacts'] if sc.isnumber( contacts ): # It's a scalar instead of a dict, assume it's all contacts self['contacts'] = {'a': contacts} # Handle key mismaches beta_layer_keys = set(self.pars['beta_layer'].keys()) contacts_keys = set(self.pars['contacts'].keys()) quar_eff_keys = set(self.pars['quar_eff'].keys()) if not (beta_layer_keys == contacts_keys == quar_eff_keys): errormsg = f'Layer parameters beta={beta_layer_keys}, contacts={contacts_keys}, quar_eff={quar_eff_keys} are not consistent' raise ValueError(errormsg) # Handle population data popdata_choices = ['random', 'hybrid', 'clustered', 'synthpops'] choice = self['pop_type'] if choice not in popdata_choices: choicestr = ', '.join(popdata_choices) errormsg = f'Population type "{choice}" not available; choices are: {choicestr}' raise ValueError(errormsg) # Handle interventions self['interventions'] = sc.promotetolist(self['interventions'], keepnone=False) return
def make_safegraph(sim, use_interp=True): ''' Create interventions representing SafeGraph data ''' # Load data.values fn = safegraph_file df = pd.read_csv(fn) week = df['week'] w = df["p.emp.no.schools"].values c = df["p.cust.no.schools"].values s = df["p.tot.schools"].values # Do processing npts = len(week) start_date = sc.readdate(week[0], dateformat='%Y-%m-%d') start_day = sim.day(start_date) sg_days = start_day + 7 * np.arange(npts) # Create interventions interventions = [ cv.clip_edges(days=sg_days, changes=w, layers='w', label='clip_w'), cv.clip_edges(days=sg_days, changes=c, layers='c', label='clip_c'), cv.clip_edges(days=sg_days, changes=s, layers='s', label='clip_s'), ] return interventions
def test_misc(): sc.heading('Testing miscellaneous functions') sim_path = 'test_misc.sim' json_path = 'test_misc.json' gitinfo_path = 'test_misc.gitinfo' fig_path = 'test_misc.png' fig_comments = 'Test comment' # Data loading cv.load_data(csv_file) cv.load_data(xlsx_file) with pytest.raises(NotImplementedError): cv.load_data('example_data.unsupported_extension') with pytest.raises(ValueError): cv.load_data(xlsx_file, columns=['missing_column']) # Dates d1 = cv.date('2020-04-04') d2 = cv.date(sc.readdate('2020-04-04')) ds = cv.date('2020-04-04', d2) assert d1 == d2 assert d2 == ds[0] with pytest.raises(ValueError): cv.date([(2020, 4, 4)]) # Raises a TypeError which raises a ValueError with pytest.raises(ValueError): cv.date('Not a date') cv.daydiff('2020-04-04') # Run sim for more investigations sim = cv.Sim(pop_size=500, verbose=0) sim.run() sim.plot(do_show=False) # Saving and loading cv.savefig(fig_path, comments=fig_comments) cv.save(filename=sim_path, obj=sim) cv.load(filename=sim_path) # Version checks cv.check_version('0.0.0') # Nonsense version print('↑ Should complain about version') with pytest.raises(ValueError): cv.check_version('0.0.0', die=True) # Git checks cv.git_info(json_path) cv.git_info(json_path, check=True) # Poisson tests c1 = 5 c2 = 8 for alternative in ['two-sided', 'larger', 'smaller']: cv.poisson_test(c1, c2, alternative=alternative) for method in ['score', 'wald', 'sqrt', 'exact-cond']: cv.poisson_test(c1, c2, method=method) with pytest.raises(ValueError): cv.poisson_test(c1, c2, method='not a method') # Test locations for location in [None, 'viet-nam']: cv.data.show_locations(location) # Test versions with pytest.raises(ValueError): cv.check_save_version('1.3.2', die=True) cv.check_save_version(cv.__version__, filename=gitinfo_path, comments='Test') # Test PNG try: metadata = cv.get_png_metadata(fig_path, output=True) assert metadata['Covasim version'] == cv.__version__ assert metadata['Covasim comments'] == fig_comments except ImportError as E: print( f'Cannot test PNG function since pillow not installed ({str(E)}), skipping' ) # Tidy up remove_files(sim_path, json_path, fig_path, gitinfo_path) return
def single_sim_new(end_day='2020-05-10', rand_seed=1, dist='lognormal', par1=10, par2=170): pop_type = 'hybrid' pop_size = 225000 pop_scale = 2.25e6 / pop_size start_day = '2020-01-27' # end_day = '2020-05-01' # for calibration plots # end_day = '2020-06-30' # for projection plots pars = { 'verbose': 0, 'pop_size': pop_size, 'pop_infected': 30, # 300 'pop_type': pop_type, 'start_day': start_day, 'n_days': (sc.readdate(end_day) - sc.readdate(start_day)).days, 'pop_scale': pop_scale, 'rescale': True, 'beta': 0.015, 'rand_seed': rand_seed, } sim = cv.Sim(pars, datafile=datafile) # Define beta interventions b_days = ['2020-03-04', '2020-03-12', '2020-03-23'] b_ch = sc.objdict() b_ch.h = [1.00, 1.10, 1.20] b_ch.s = [1.00, 0.00, 0.00] b_ch.w = [0.60, 0.40, 0.25] b_ch.c = [0.60, 0.40, 0.25] # Define testing interventions daily_tests = sim.data['new_tests'] test_kwargs = { 'quar_test': 0, 'sensitivity': 1.0, 'test_delay': 0, 'loss_prob': 0 } interventions = [ cv.test_num(daily_tests=daily_tests, symp_test=70, start_day='2020-01-27', end_day=None, swab_delay_dist={ 'dist': dist, 'par1': par1, 'par2': par2 }, **test_kwargs), ] for lkey, ch in b_ch.items(): interventions.append( cv.change_beta(days=b_days, changes=b_ch[lkey], layers=lkey)) sim.update_pars(interventions=interventions) sim.initialize() # Define age susceptibility mapping = { 0: 0.2, 20: 0.9, 40: 1.0, 70: 2.5, 80: 5.0, 90: 10.0, } for age, val in mapping.items(): sim.people.rel_sus[sim.people.age > age] = val return sim
90: 10.0, } for age, val in mapping.items(): sim.people.rel_sus[sim.people.age > age] = val return sim if __name__ == "__main__": time_num_old = [] time_num_new = [] time_num_flat = [] # 2020-05-10 - 2020-01-27 days = (sc.readdate("2020-05-10") - sc.readdate("2020-01-27")).days + 1 yield_num_old = np.zeros(days) yield_num_new = np.zeros(days) yield_num_flat = np.zeros(days) # Need a couple of sims to make sure we are not looking at noise stage_old = {'mild': 0, 'sev': 0, 'crit': 0} stage_new = {'mild': 0, 'sev': 0, 'crit': 0} stage_flat = {'mild': 0, 'sev': 0, 'crit': 0} start = 1 end = 2 n_run = end - start for i in range(start, end): sim = single_sim_old(rand_seed=i) t = sc.tic() sim.run()
def create_sim(pars=None, use_safegraph=True, label=None, show_intervs=False, people=None, adjust_ORs=False, num_pos=None, test_prob=None, trace_prob=None, NPI_schools=None, test_freq=None, network_change=False, schedule=None, school_start_day=None, intervention_start_day=None, ttq_scen=None ): ''' Create a single simulation for further use ''' p = sc.objdict(sc.mergedicts(define_pars(which='best', kind='both', use_safegraph=use_safegraph), pars)) if 'rand_seed' not in p: seed = 1 print(f'Note, could not find random seed in {pars}! Setting to {seed}') p['rand_seed'] = seed # Ensure this exists # Basic parameters and sim creation pars = {'pop_size': 225e3, 'pop_scale': 10, 'pop_type': 'synthpops', 'pop_infected': p.pop_infected, 'beta': p.beta, 'start_day': '2020-02-01', 'end_day': p['end_day'], 'rescale': True, 'rescale_factor': 1.1, 'verbose': 0.1, 'rand_seed': p.rand_seed, 'analyzers': [cv.age_histogram(datafile=age_data_file, states=['exposed', 'dead', 'tested', 'diagnosed', 'severe'])], 'beta_layer': dict(h=p.bl_h, s=p.bl_s, w=p.bl_w, c=p.bl_c, l=p.bl_l), } # If supplied, use an existing people object if people: popfile = people else: # Generate the population filename n_popfiles = 5 popfile = popfile_stem + str(pars['rand_seed'] % n_popfiles) + '.ppl' popfile_change = popfile_stem_change + str(pars['rand_seed'] % n_popfiles) + '.ppl' # Check that the population file exists if not os.path.exists(popfile): errormsg = f'WARNING: could not find population file {popfile}! Please regenerate first' raise FileNotFoundError(errormsg) # Create and initialize the sim print(f'Creating sim! safegraph={use_safegraph}, seed={p.rand_seed}') sim = cv.Sim(pars, label=label, popfile=popfile, load_pop=True, datafile=epi_data_file) # Create this here so can be used for test numbers etc. interventions = [] # Testing bins df = pd.read_csv(age_series_file) age_bins = [0, 20, 40, 60, 80, np.inf] test_num_subtargs = [ftest_num_subtarg1, ftest_num_subtarg2, ftest_num_subtarg3, ftest_num_subtarg4, ftest_num_subtarg5] for ia in range(len(age_bins) - 1): label = '{}-{}'.format(age_bins[ia], age_bins[ia + 1] - 1) df_ = df[(df['age'] >= age_bins[ia]) & (df['age'] < age_bins[ia + 1])] # sum for the dates df_ = df_.groupby('date').sum() df_['age'] = age_bins[ia] df_['datetime'] = [sc.readdate(d) for d in df_.index.values] df_ = df_.set_index('datetime') # make sure we have all the days we care about new_index = pd.date_range(df_.index[0], df_.index[-1], freq='1d') df_ = df_.reindex(new_index, fill_value=0.0, method='nearest') test_kwargs = dict(daily_tests=df_['new_tests'], quar_test=1.0, test_delay=2, subtarget=test_num_subtargs[ia]) interventions += [cv.test_num(symp_test=p.tn1, start_day='2020-01-27', end_day='2020-03-23', **test_kwargs, label='tn1 ' + label)] interventions += [cv.test_num(symp_test=p.tn2, start_day='2020-03-24', end_day='2020-04-14', **test_kwargs, label='tn2 ' + label)] interventions += [cv.test_num(symp_test=p.tn3, start_day='2020-04-15', end_day='2020-05-07', **test_kwargs, label='tn3 ' + label)] interventions += [cv.test_num(symp_test=p.tn4, start_day='2020-05-08', end_day='2020-06-04', **test_kwargs, label='tn4 ' + label)] interventions += [cv.test_num(symp_test=p.tn5, start_day='2020-06-17', end_day='2020-06-18', **test_kwargs, label='tn5 ' + label)] interventions += [cv.test_num(symp_test=p.tn6, start_day='2020-06-19', end_day=None, **test_kwargs, label='tn6 ' + label)] # Seed in LTCF interventions += [seed_ltcf(days=[15], seeds=[p.lseeds])] # Define beta interventions b_days = ['2020-03-02', '2020-03-12', '2020-03-23', '2020-04-15', '2020-05-08', '2020-06-05', '2020-06-19' ] # Home and school beta changes interventions += [ cv.change_beta(days=b_days[1], changes=p.bc_s, layers='s', label="beta_s") ] # Work and community beta changes b_days_wc = np.arange(sim.day(b_days[0]), sim.day(b_days[1]) + 1).tolist() + b_days[2:] b_ch_wc = np.linspace(1.0, p.bc_wc1, len(b_days_wc) - 5).tolist() + [p.bc_wc2, p.bc_wc3, p.bc_wc4, p.bc_wc5, p.bc_wc6] for lkey in ['w', 'c']: interventions += [cv.change_beta(days=b_days_wc, changes=b_ch_wc, layers=lkey, label=f'beta_{lkey}')] # LTCF beta change b_days_l = np.arange(sim.day(b_days[0]), sim.day(b_days[2]) + 1) b_ch_l = np.linspace(1.0, p.bc_lf, len(b_days_l)) interventions += [cv.change_beta(days=b_days_l, changes=b_ch_l, layers='l', label='beta_l')] # sim.people.contacts['c'] = remove_ltcf_community(sim) # Remove community contacts from LTCF # Age-based beta changes b_age_days = ["2020-05-08", "2020-06-05", "2020-06-19"] b_age_changes = [[p.bc_age_u10_a, # 0 p.bc_age_10_20_a, # 10 p.bc_age_20_30_a, # 20 p.bc_age_30_40_a, # 30 1.0, # 40 1.0, # 50 p.bc_age_65u_a, # 65 p.bc_age_65u_a, # 70 p.bc_age_65u_a, # 80 p.bc_age_65u_a, # 90 ], [p.bc_age_u10_b, # 0 p.bc_age_10_20_b, # 10 p.bc_age_20_30_b, # 20 p.bc_age_30_40_b, # 30 1.0, # 40 1.0, # 50 p.bc_age_65u_b, # 65 p.bc_age_65u_b, # 70 p.bc_age_65u_b, # 80 p.bc_age_65u_b, # 90 ], [p.bc_age_u10_c, # 0 p.bc_age_10_20_c, # 10 p.bc_age_20_30_c, # 20 p.bc_age_30_40_c, # 30 1.0, # 40 1.0, # 50 p.bc_age_65u_c, # 65 p.bc_age_65u_c, # 70 p.bc_age_65u_c, # 80 p.bc_age_65u_c, # 90 ] ] interventions += [beta_change_age.change_beta_age(b_age_days, b_age_changes)] # SafeGraph intervention & tidy up if use_safegraph: interventions += make_safegraph(sim) if ttq_scen == 'lower': tp = sc.objdict( symp_prob=0.08, asymp_prob=0.001, symp_quar_prob=0.8, asymp_quar_prob=0.1, test_delay=2.0, ) ct = sc.objdict( trace_probs=0.01, trace_time=3.0, ) elif ttq_scen == 'medium': tp = sc.objdict( symp_prob=0.12, asymp_prob=0.0015, symp_quar_prob=0.8, asymp_quar_prob=0.1, test_delay=2.0, ) ct = sc.objdict( trace_probs=0.25, trace_time=3.0, ) elif ttq_scen == 'upper': tp = sc.objdict( symp_prob=0.24, asymp_prob=0.003, symp_quar_prob=0.8, asymp_quar_prob=0.1, test_delay=2.0, ) ct = sc.objdict( trace_probs=0.5, trace_time=3.0, ) if ttq_scen is not None: interventions += [cv.test_prob(start_day='2020-07-10', **tp), cv.contact_tracing(start_day='2020-07-10', **ct)] if network_change: popfile_new = popfile_change else: popfile_new = None if NPI_schools is not None: interventions += [cv.change_beta(days=sim.day('2020-09-01'), changes=NPI_schools, layers='s')] interventions += [cv.close_schools(day_schools_closed='2020-03-12', start_day=school_start_day, pop_file=popfile_new)] interventions += [cv.reopen_schools(start_day=intervention_start_day, num_pos=num_pos, test=test_prob, trace=trace_prob, ili_prev=0.002, test_freq=test_freq, schedule=schedule)] sim['interventions'] = interventions # Don't show interventions in plots, there are too many for interv in sim['interventions']: interv.do_plot = False # Prognoses (particularly to severe/hospitalizations) need attention prognoses = sc.dcp(cv.get_prognoses()) prognoses['severe_probs'] *= prognoses[ 'symp_probs'] # Conditional probability of symptoms becoming severe, given symptomatic prognoses['crit_probs'] *= prognoses[ 'severe_probs'] # Conditional probability of symptoms becoming critical, given severe prognoses['death_probs'] *= prognoses['crit_probs'] # Conditional probability of dying, given critical symptoms prognoses.update({'age_cutoff': np.array([0, 10, 20, 30, 40, 50, 65, 70, 80, 90])}) prognoses.update({'severe_probs': np.array([1, 1, 1, p.rsp1, p.rsp1, p.rsp1, p.rsp1, p.rsp1, p.rsp2, p.rsp2]) * prognoses['severe_probs']}) prognoses['death_probs'] /= prognoses['crit_probs'] # Conditional probability of dying, given critical symptoms prognoses['crit_probs'] /= prognoses[ 'severe_probs'] # Conditional probability of symptoms becoming critical, given severe prognoses['severe_probs'] /= prognoses[ 'symp_probs'] # Conditional probability of symptoms becoming severe, given symptomatic sim.pars.update({'prognoses': prognoses}) return sim
def test_base(): sc.heading('Testing base.py...') json_path = 'base_tests.json' sim_path = 'base_tests.sim' # Create a small sim for later use sim = cv.Sim(pop_size=100, verbose=verbose) sim.run() # Check setting invalid key with pytest.raises(sc.KeyNotFoundError): po = cv.ParsObj(pars={'a': 2, 'b': 3}) po.update_pars({'c': 4}) # Printing result r = cv.Result() print(r) print(r.npts) # Day and date conversion daystr = '2020-04-04' sim.day(daystr) sim.day(sc.readdate(daystr)) with pytest.raises(ValueError): sim.day('not a date') sim.date(34) sim.date([34, 54]) sim.date(34, 54, as_date=True) # BaseSim methods sim.copy() sim.export_results(filename=json_path) sim.export_pars(filename=json_path) sim.shrink(in_place=False) for keep_people in [True, False]: sim.save(filename=sim_path, keep_people=keep_people) cv.Sim.load(sim_path) # BasePeople methods ppl = sim.people ppl.get(['susceptible', 'infectious']) ppl.keys(which='all_states') ppl.index() ppl.resize(pop_size=200) ppl.to_df() ppl.to_arr() ppl.person(50) people = ppl.to_people() ppl.from_people(people) with pytest.raises(sc.KeyNotFoundError): ppl.make_edgelist([{'invalid_key': [0, 1, 2]}]) # Contacts methods contacts = ppl.contacts df = contacts['a'].to_df() ppl.remove_duplicates(df) with pytest.raises(sc.KeyNotFoundError): contacts['invalid_key'] contacts.values() len(contacts) # Transmission tree methods ppl.transtree.make_targets() ppl.make_detailed_transtree() ppl.transtree.plot() ppl.transtree.animate(animate=False) # Tidy up remove_files(json_path, sim_path) return
90: 10.0, } for age, val in mapping.items(): sim.people.rel_sus[sim.people.age > age] = val return sim if __name__ == "__main__": time_prob_old = [] time_prob_new = [] time_prob_flat = [] # 2020-05-10 - 2020-01-27 days = (sc.readdate("2020-05-10") - sc.readdate("2020-01-27")).days + 1 yield_prob_old = np.zeros(days) yield_prob_new = np.zeros(days) yield_prob_flat = np.zeros(days) # Need a couple of sims to make sure we are not looking at noise stage_old = {'mild': 0, 'sev': 0, 'crit': 0} stage_new = {'mild': 0, 'sev': 0, 'crit': 0} stage_flat = {'mild': 0, 'sev': 0, 'crit': 0} start = 1 end = 11 n_run = end - start for i in range(start, end): sim = single_sim_old(rand_seed=i) t = sc.tic() sim.run()
sim = msim.base_sim tt = sim.make_transtree() #tt = sc.loadobj(f'{resfolder}/tt.obj') layer_keys = list(sim.people.layer_keys()) layer_mapping = {k:i for i,k in enumerate(layer_keys)} n_layers = len(layer_keys) colors = sc.gridcolors(n_layers) layer_counts = np.zeros((sim.npts, n_layers)) for source_ind, target_ind in tt.transmissions: dd = tt.detailed[target_ind] date = dd['date'] layer_num = layer_mapping[dd['layer']] layer_counts[date, layer_num] += sim.rescale_vec[date] lockdown1 = [sc.readdate('2020-03-23'),sc.readdate('2020-05-31')] lockdown2 = [sc.readdate('2020-11-05'),sc.readdate('2020-12-03')] lockdown3 = [sc.readdate('2021-01-04'),sc.readdate('2021-02-08')] labels = ['Household', 'School', 'Workplace', 'Community'] for l in range(n_layers): ax.plot(sim.datevec, layer_counts[:,l], c=colors[l], lw=3, label=labels[l]) ax.axvspan(lockdown1[0], lockdown1[1], color='steelblue', alpha=0.2, lw=0) ax.axvspan(lockdown2[0], lockdown2[1], color='steelblue', alpha=0.2, lw=0) ax.axvspan(lockdown3[0], lockdown3[1], color='lightblue', alpha=0.2, lw=0) sc.setylim(ax=ax) sc.boxoff(ax=ax) ax.set_ylabel('Transmissions per day') ax.set_xlim([sc.readdate('2020-01-21'), sc.readdate('2021-03-01')]) ax.xaxis.set_major_formatter(mdates.DateFormatter('%b\n%y'))
do_plot = 1 do_save = 1 do_show = 1 verbose = 1 seed = 1 version = 'v1' date = '2020may26' folder = f'results_FINAL_{date}' file_path = f'{folder}/phase_{version}' # Completed below data_path = 'UK_Covid_cases_may21.xlsx' pop_path = f'{file_path}.pop' fig_path = f'{file_path}.png' #ig_paths = [f'results/testing_scen_{i}.png' for i in range(3)] start_day = sc.readdate('2020-01-21') end_day = sc.readdate('2021-05-31') n_days = (end_day - start_day).days # Set the parameters #quar_eff = 0.8 #quar_effs = {k:quar_eff for k in 'hwsc'} total_pop = 67.86e6 # UK population size pop_size = 100e3 # Actual simulated population ratio = int(total_pop / pop_size) pop_scale = ratio pop_type = 'hybrid' #100% transmissibility of kids also ps=0.0135 for May and June pop_infected = 4000 #beta=0.00485 beta = 0.007661
''' import sciris as sc import covasim as cv intervs1 = [ cv.change_beta(30, 0.5), cv.test_prob(symp_prob=0.1, start_day=20), ] s1 = cv.Sim(start_day='2020-03-01', interventions=intervs1) s1.run() intervs2 = [ cv.change_beta('2020-03-31', 0.5), cv.test_prob(symp_prob=0.1, start_day='2020-03-21'), ] s2 = cv.Sim(start_day='2020-03-01', interventions=intervs2) s2.run() assert s1.summary == s2.summary intervs3 = [ cv.change_beta(days=['2020-03-31', sc.readdate('2020-04-07'), 50], changes=[0.5, 0.3, 0.0]), ] s3 = cv.Sim(start_day='2020-03-01', interventions=intervs3) s3.run() s3.plot()
def single_sim_old(end_day='2020-05-10', rand_seed=1): pop_type = 'hybrid' pop_size = 225000 pop_scale = 2.25e6 / pop_size start_day = '2020-01-27' # end_day = '2020-05-01' # for calibration plots # end_day = '2020-06-30' # for projection plots pars = { 'verbose': 0, 'pop_size': pop_size, 'pop_infected': 30, # 300 'pop_type': pop_type, 'start_day': start_day, 'n_days': (sc.readdate(end_day) - sc.readdate(start_day)).days, 'pop_scale': pop_scale, 'beta': 0.015, 'rand_seed': rand_seed, } sim = cv.Sim(pars, datafile=datafile) # Define beta interventions b_days = ['2020-03-04', '2020-03-12', '2020-03-23'] b_ch = sc.objdict() b_ch.h = [1.00, 1.10, 1.20] b_ch.s = [1.00, 0.00, 0.00] b_ch.w = [0.60, 0.40, 0.25] b_ch.c = [0.60, 0.40, 0.25] # Define testing interventions test_kwargs = { 'symp_prob': 0.05, 'asymp_prob': 0.0008, 'symp_quar_prob': 0, 'asymp_quar_prob': 0, 'test_delay': 0, 'test_sensitivity': 1.0, 'loss_prob': 0.0 } interventions = [ test_prob_old(start_day='2020-01-27', **test_kwargs), ] for lkey, ch in b_ch.items(): interventions.append( cv.change_beta(days=b_days, changes=b_ch[lkey], layers=lkey)) sim.update_pars(interventions=interventions) sim.initialize() # Define age susceptibility mapping = { 0: 0.2, 20: 0.9, 40: 1.0, 70: 2.5, 80: 5.0, 90: 10.0, } for age, val in mapping.items(): sim.people.rel_sus[sim.people.age > age] = val return sim
def test_misc(): sc.heading('Testing miscellaneous functions') sim_path = 'test_misc.sim' json_path = 'test_misc.json' # Data loading cv.load_data(csv_file) cv.load_data(xlsx_file) with pytest.raises(NotImplementedError): cv.load_data('example_data.unsupported_extension') with pytest.raises(ValueError): cv.load_data(xlsx_file, columns=['missing_column']) # Dates d1 = cv.date('2020-04-04') d2 = cv.date(sc.readdate('2020-04-04')) ds = cv.date('2020-04-04', d2) assert d1 == d2 assert d2 == ds[0] with pytest.raises(ValueError): cv.date([(2020, 4, 4)]) # Raises a TypeError which raises a ValueError with pytest.raises(ValueError): cv.date('Not a date') cv.daydiff('2020-04-04') # Saving and loading sim = cv.Sim() cv.save(filename=sim_path, obj=sim) cv.load(filename=sim_path) # Version checks cv.check_version('0.0.0') # Nonsense version print('↑ Should complain about version') with pytest.raises(ValueError): cv.check_version('0.0.0', die=True) # Git checks cv.git_info(json_path) cv.git_info(json_path, check=True) # Poisson tests c1 = 5 c2 = 8 for alternative in ['two-sided', 'larger', 'smaller']: cv.poisson_test(c1, c2, alternative=alternative) for method in ['score', 'wald', 'sqrt', 'exact-cond']: cv.poisson_test(c1, c2, method=method) with pytest.raises(ValueError): cv.poisson_test(c1, c2, method='not a method') # Tidy up remove_files(sim_path, json_path) return
def covid_tracking_date_to_date(d): ''' Date is in format e.g. 20201031 ''' out = sc.readdate(str(d)) # Should be a supported format return out
def plot(): fig = pl.figure(num='Fig. 2: Transmission dynamics', figsize=(20,14)) piey, tsy, r3y = 0.68, 0.50, 0.07 piedx, tsdx, r3dx = 0.2, 0.9, 0.25 piedy, tsdy, r3dy = 0.2, 0.47, 0.35 pie1x, pie2x = 0.12, 0.65 tsx = 0.07 dispx, cumx, sympx = tsx, 0.33+tsx, 0.66+tsx ts_ax = pl.axes([tsx, tsy, tsdx, tsdy]) pie_ax1 = pl.axes([pie1x, piey, piedx, piedy]) pie_ax2 = pl.axes([pie2x, piey, piedx, piedy]) symp_ax = pl.axes([sympx, r3y, r3dx, r3dy]) disp_ax = pl.axes([dispx, r3y, r3dx, r3dy]) cum_ax = pl.axes([cumx, r3y, r3dx, r3dy]) off = 0.06 txtdispx, txtcumx, txtsympx = dispx-off, cumx-off, sympx-off+0.02 tsytxt = tsy+tsdy r3ytxt = r3y+r3dy labelsize = 40-wf pl.figtext(txtdispx, tsytxt, 'a', fontsize=labelsize) pl.figtext(txtdispx, r3ytxt, 'b', fontsize=labelsize) pl.figtext(txtcumx, r3ytxt, 'c', fontsize=labelsize) pl.figtext(txtsympx, r3ytxt, 'd', fontsize=labelsize) #%% Fig. 2A -- Time series plot layer_keys = list(sim.layer_keys()) layer_mapping = {k:i for i,k in enumerate(layer_keys)} n_layers = len(layer_keys) colors = sc.gridcolors(n_layers) layer_counts = np.zeros((sim.npts, n_layers)) for source_ind, target_ind in tt.count_transmissions(): dd = tt.detailed[target_ind] date = dd['date'] layer_num = layer_mapping[dd['layer']] layer_counts[date, layer_num] += sim.rescale_vec[date] mar12 = cv.date('2020-03-12') mar23 = cv.date('2020-03-23') mar12d = sim.day(mar12) mar23d = sim.day(mar23) labels = ['Household', 'School', 'Workplace', 'Community', 'LTCF'] for l in range(n_layers): ts_ax.plot(sim.datevec, layer_counts[:,l], c=colors[l], lw=3, label=labels[l]) sc.setylim(ax=ts_ax) sc.boxoff(ax=ts_ax) ts_ax.set_ylabel('Transmissions per day') ts_ax.set_xlim([sc.readdate('2020-01-18'), sc.readdate('2020-06-09')]) ts_ax.xaxis.set_major_formatter(mdates.DateFormatter('%b-%d')) ts_ax.set_xticks([sim.date(d, as_date=True) for d in np.arange(0, sim.day('2020-06-09'), 14)]) ts_ax.legend(frameon=False, bbox_to_anchor=(0.85,0.1)) color = [0.2, 0.2, 0.2] ts_ax.axvline(mar12, c=color, linestyle='--', alpha=0.4, lw=3) ts_ax.axvline(mar23, c=color, linestyle='--', alpha=0.4, lw=3) yl = ts_ax.get_ylim() labely = yl[1]*1.015 ts_ax.text(mar12, labely, 'Schools close ', color=color, alpha=0.9, style='italic', horizontalalignment='center') ts_ax.text(mar23, labely, ' Stay-at-home', color=color, alpha=0.9, style='italic', horizontalalignment='center') #%% Fig. 2A inset -- Pie charts pre_counts = layer_counts[0:mar12d, :].sum(axis=0) post_counts = layer_counts[mar23d:, :].sum(axis=0) pre_counts = pre_counts/pre_counts.sum()*100 post_counts = post_counts/post_counts.sum()*100 lpre = [ f'Household\n{pre_counts[0]:0.1f}%', f'School\n{pre_counts[1]:0.1f}% ', f'Workplace\n{pre_counts[2]:0.1f}% ', f'Community\n{pre_counts[3]:0.1f}%', f'LTCF\n{pre_counts[4]:0.1f}%', ] lpost = [ f'Household\n{post_counts[0]:0.1f}%', f'School\n{post_counts[1]:0.1f}%', f'Workplace\n{post_counts[2]:0.1f}%', f'Community\n{post_counts[3]:0.1f}%', f'LTCF\n{post_counts[4]:0.1f}%', ] pie_ax1.pie(pre_counts, colors=colors, labels=lpre, **pieargs) pie_ax2.pie(post_counts, colors=colors, labels=lpost, **pieargs) pie_ax1.text(0, 1.75, 'Transmissions by layer\nbefore schools closed', style='italic', horizontalalignment='center') pie_ax2.text(0, 1.75, 'Transmissions by layer\nafter stay-at-home', style='italic', horizontalalignment='center') #%% Fig. 2B -- histogram by overdispersion # Process targets n_targets = tt.count_targets(end_day=mar12) # Handle bins max_infections = n_targets.max() edges = np.arange(0, max_infections+2) # Analysis counts = np.histogram(n_targets, edges)[0] bins = edges[:-1] # Remove last bin since it's an edge norm_counts = counts/counts.sum() raw_counts = counts*bins total_counts = raw_counts/raw_counts.sum()*100 n_bins = len(bins) index = np.linspace(0, 100, len(n_targets)) sorted_arr = np.sort(n_targets) sorted_sum = np.cumsum(sorted_arr) sorted_sum = sorted_sum/sorted_sum.max()*100 change_inds = sc.findinds(np.diff(sorted_arr) != 0) pl.set_cmap('Spectral_r') sscolors = sc.vectocolor(n_bins) width = 1.0 for i in range(n_bins): disp_ax.bar(bins[i], total_counts[i], width=width, facecolor=sscolors[i]) disp_ax.set_xlabel('Number of transmissions per case') disp_ax.set_ylabel('Proportion of transmissions (%)') sc.boxoff() disp_ax.set_xlim([0.5, 32.5]) disp_ax.set_xticks(np.arange(0, 32.5, 4)) sc.boxoff(ax=disp_ax) dpie_ax = pl.axes([dispx+0.05, 0.20, 0.2, 0.2]) trans1 = total_counts[1:3].sum() trans2 = total_counts[3:5].sum() trans3 = total_counts[5:8].sum() trans4 = total_counts[8:].sum() labels = [ f'1-2:\n{trans1:0.0f}%', f' 3-4:\n {trans2:0.0f}%', f'5-7: \n{trans3:0.0f}%\n', f'>7: \n{trans4:0.0f}%\n', ] dpie_args = sc.mergedicts(pieargs, dict(labeldistance=1.2)) # Slightly smaller label distance dpie_ax.pie([trans1, trans2, trans3, trans4], labels=labels, colors=sscolors[[0,4,7,12]], **dpie_args) #%% Fig. 2C -- cumulative distribution function rev_ind = 100 - index n_change_inds = len(change_inds) change_bins = bins[counts>0][1:] for i in range(n_change_inds): ib = int(change_bins[i]) ci = change_inds[i] ici = index[ci] sci = sorted_sum[ci] color = sscolors[ib] if i>0: cim1 = change_inds[i-1] icim1 = index[cim1] scim1 = sorted_sum[cim1] cum_ax.plot([icim1, ici], [scim1, sci], lw=4, c=color) cum_ax.scatter([ici], [sci], s=150, zorder=50-i, c=[color], edgecolor='w', linewidth=0.2) if ib<=6 or ib in [8, 10, 25]: xoff = 5 - 2*(ib==1) + 3*(ib>=10) + 1*(ib>=20) yoff = 2*(ib==1) cum_ax.text(ici-xoff, sci+yoff, ib, fontsize=18-wf, color=color) cum_ax.set_xlabel('Proportion of primary infections (%)') cum_ax.set_ylabel('Proportion of transmissions (%)') xmin = -2 ymin = -2 cum_ax.set_xlim([xmin, 102]) cum_ax.set_ylim([ymin, 102]) sc.boxoff(ax=cum_ax) # Draw horizontal lines and annotations ancol1 = [0.2, 0.2, 0.2] ancol2 = sscolors[0] ancol3 = sscolors[6] i01 = sc.findlast(sorted_sum==0) i20 = sc.findlast(sorted_sum<=20) i50 = sc.findlast(sorted_sum<=50) cum_ax.plot([xmin, index[i01]], [0, 0], '--', lw=2, c=ancol1) cum_ax.plot([xmin, index[i20], index[i20]], [20, 20, ymin], '--', lw=2, c=ancol2) cum_ax.plot([xmin, index[i50], index[i50]], [50, 50, ymin], '--', lw=2, c=ancol3) # Compute mean number of transmissions for 80% and 50% thresholds q80 = sc.findfirst(np.cumsum(total_counts)>20) # Count corresponding to 80% of cumulative infections (100-80) q50 = sc.findfirst(np.cumsum(total_counts)>50) # Count corresponding to 50% of cumulative infections n80, n50 = [sum(bins[q:]*norm_counts[q:]/norm_counts[q:].sum()) for q in [q80, q50]] # Plot annotations kw = dict(bbox=dict(facecolor='w', alpha=0.9, lw=0), fontsize=20-wf) cum_ax.text(2, 3, f'{index[i01]:0.0f}% of infections\ndo not transmit', c=ancol1, **kw) cum_ax.text(8, 23, f'{rev_ind[i20]:0.0f}% of infections cause\n80% of transmissions\n(mean: {n80:0.1f} per infection)', c=ancol2, **kw) cum_ax.text(14, 53, f'{rev_ind[i50]:0.0f}% of infections cause\n50% of transmissions\n(mean: {n50:0.1f} per infection)', c=ancol3, **kw) #%% Fig. 2D -- histogram by date of symptom onset # Calculate asymp_count = 0 symp_counts = {} minind = -5 maxind = 15 for _, target_ind in tt.transmissions: dd = tt.detailed[target_ind] date = dd['date'] delta = sim.rescale_vec[date] # Increment counts by this much if dd['s']: if tt.detailed[dd['source']]['date'] <= date: # Skip dynamical scaling reinfections sdate = dd['s']['date_symptomatic'] if np.isnan(sdate): asymp_count += delta else: ind = int(date - sdate) if ind not in symp_counts: symp_counts[ind] = 0 symp_counts[ind] += delta # Convert to an array xax = np.arange(minind-1, maxind+1) sympcounts = np.zeros(len(xax)) for i,val in symp_counts.items(): if i<minind: ind = 0 elif i>maxind: ind = -1 else: ind = sc.findinds(xax==i)[0] sympcounts[ind] += val # Plot total_count = asymp_count + sympcounts.sum() sympcounts = sympcounts/total_count*100 presymp = sc.findinds(xax<=0)[-1] colors = ['#eed15b', '#ee943a', '#c3211a'] asymp_frac = asymp_count/total_count*100 pre_frac = sympcounts[:presymp].sum() symp_frac = sympcounts[presymp:].sum() symp_ax.bar(xax[0]-2, asymp_frac, label='Asymptomatic', color=colors[0]) symp_ax.bar(xax[:presymp], sympcounts[:presymp], label='Presymptomatic', color=colors[1]) symp_ax.bar(xax[presymp:], sympcounts[presymp:], label='Symptomatic', color=colors[2]) symp_ax.set_xlabel('Days since symptom onset') symp_ax.set_ylabel('Proportion of transmissions (%)') symp_ax.set_xticks([minind-3, 0, 5, 10, maxind]) symp_ax.set_xticklabels(['Asymp.', '0', '5', '10', f'>{maxind}']) sc.boxoff(ax=symp_ax) spie_ax = pl.axes([sympx+0.05, 0.20, 0.2, 0.2]) labels = [f'Asymp-\ntomatic\n{asymp_frac:0.0f}%', f' Presymp-\n tomatic\n {pre_frac:0.0f}%', f'Symp-\ntomatic\n{symp_frac:0.0f}%'] spie_ax.pie([asymp_frac, pre_frac, symp_frac], labels=labels, colors=colors, **pieargs) return fig
def date(obj, *args, start_date=None, dateformat=None, as_date=True): ''' Convert a string or a datetime object to a date object. To convert to an integer from the start day, it is recommended you supply a start date, or use sim.date() instead; otherwise, it will calculate the date counting days from 2020-01-01. This means that the output of cv.date() will not necessarily match the output of sim.date() for an integer input. Args: obj (str, date, datetime, list, array): the object to convert args (str, date, datetime): additional objects to convert start_date (str, date, datetime): the starting date, if an integer is supplied dateformat (str): the format to return the date in as_date (bool): whether to return as a datetime date instead of a string Returns: dates (date or list): either a single date object, or a list of them **Examples**:: cv.date('2020-04-05') # Returns datetime.date(2020, 4, 5) cv.date('2020-04-14', start_date='2020-04-04', as_date=False) # Returns 10 cv.date([35,36,37], as_date=False) # Returns ['2020-02-05', '2020-02-06', '2020-02-07'] ''' if obj is None: return None # Convert to list and handle other inputs if isinstance(obj, np.ndarray): obj = obj.tolist() # If it's an array, convert to a list obj = sc.promotetolist(obj) # Ensure it's iterable obj.extend(args) if dateformat is None: dateformat = '%Y-%m-%d' if start_date is None: start_date = '2020-01-01' dates = [] for d in obj: if d is None: dates.append(d) continue try: if type( d ) == dt.date: # Do not use isinstance, since must be the exact type pass elif sc.isstring(d): d = sc.readdate(d).date() elif isinstance(d, dt.datetime): d = d.date() elif sc.isnumber(d): if start_date is None: errormsg = f'To convert the number {d} to a date, you must supply start_date' raise ValueError(errormsg) d = date(start_date) + dt.timedelta(days=int(d)) else: errormsg = f'Cannot interpret {type(d)} as a date, must be date, datetime, or string' raise TypeError(errormsg) if as_date: dates.append(d) else: dates.append(d.strftime(dateformat)) except Exception as E: errormsg = f'Conversion of "{d}" to a date failed: {str(E)}' raise ValueError(errormsg) # Return an integer rather than a list if only one provided if len(dates) == 1: dates = dates[0] return dates
def test_base(): sc.heading('Testing base.py...') json_path = 'base_tests.json' sim_path = 'base_tests.sim' # Create a small sim for later use sim = cv.Sim(pop_size=100, verbose=verbose) sim.run() # Check setting invalid key with pytest.raises(sc.KeyNotFoundError): po = cv.ParsObj(pars={'a':2, 'b':3}) po.update_pars({'c':4}) # Printing result r = cv.Result() print(r) print(r.npts) # Day and date conversion daystr = '2020-04-04' sim.day(daystr) sim.day(sc.readdate(daystr)) with pytest.raises(ValueError): sim.day('not a date') sim.date(34) sim.date([34, 54]) sim.date(34, 54, as_date=True) # BaseSim methods sim.copy() sim.export_results(filename=json_path) sim.export_pars(filename=json_path) sim.shrink(in_place=False) for keep_people in [True, False]: sim.save(filename=sim_path, keep_people=keep_people) cv.Sim.load(sim_path) # BasePeople methods ppl = sim.people ppl.get(['susceptible', 'infectious']) ppl.keys() ppl.person_keys() ppl.state_keys() ppl.date_keys() ppl.dur_keys() ppl.indices() ppl._resize_arrays(pop_size=200) # This only resizes the arrays, not actually create new people ppl._resize_arrays(pop_size=100) # Change back ppl.to_df() ppl.to_arr() ppl.person(50) people = ppl.to_people() ppl.from_people(people) ppl.make_edgelist([{'new_key':[0,1,2]}]) ppl.brief() # Contacts methods contacts = ppl.contacts df = contacts['a'].to_df() ppl.remove_duplicates(df) with pytest.raises(sc.KeyNotFoundError): contacts['invalid_key'] contacts.values() len(contacts) print(contacts) print(contacts['a']) # Layer methods hospitals_layer = cv.Layer() contacts.add_layer(hospitals=hospitals_layer) contacts.pop_layer('hospitals') df = hospitals_layer.to_df() hospitals_layer.from_df(df) # Tidy up remove_files(json_path, sim_path) return