op.delete_study(storage=storage, study_name=name) except: pass output = op.create_study(storage=storage, study_name=name, load_if_exists=not (restart)) return output if __name__ == '__main__': t0 = sc.tic() make_study() run_workers() study = op.load_study(storage=storage, study_name=name) best_pars = study.best_params T = sc.toc(t0, output=True) print(f'Output: {best_pars}, time: {T}') sc.heading('Loading data...') best = cs.define_pars('best') bounds = cs.define_pars('bounds') sc.heading('Making results structure...') results = [] n_trials = len(study.trials) failed_trials = [] for trial in study.trials: data = {'index': trial.number, 'mismatch': trial.value} for key, val in trial.params.items(): data[key] = val if data['mismatch'] is None:
def run(self, start=None, stop=None, initialize=None, finalize=None, do_plot=False, verbose=None, **kwargs): ''' Run the simulation. Args: start (int): when to start the simulation relative to the time vector; default 0 stop (int): when to stop; default -1 initialize (bool): whether to initialize people and results objects finalize (bool): whether or not to calculate final results objects after the time loop do_plot (bool): whether to plot verbose (int): level of detail to print kwargs (dict): passed to self.plot() Returns: results: the results object (also modifies in-place) ''' T = sc.tic() # Reset settings and results if start is None: start = 0 if initialize is None: if start > 0: initialize = False else: initialize = True if finalize is None: finalize = True if verbose is None: verbose = self['verbose'] if initialize: self.initialize() # Create people, results, etc. # Main simulation loop self.stopped = False # We've just been asked to run, so ensure we're unstopped tvec = self.tvec[start:stop] for t in tvec: self.t = t # Store the current time # Check timing and stopping function elapsed = sc.toc(T, output=True) if elapsed > self['timelimit']: print( f"Time limit ({self['timelimit']} s) exceeded; stopping..." ) self.stopped = { 'why': 'timelimit', 'message': 'Time limit exceeded at step {t}', 't': t } if self['stop_func']: self.stopped = self['stop_func']( self) # Feed in the current simulation object and the time # If this gets set, stop running -- e.g. if the time limit is exceeded if self.stopped: break # Zero counts for this time step: stocks n_susceptible = 0 n_exposed = 0 n_infectious = 0 n_symptomatic = 0 n_severe = 0 n_critical = 0 # Zero counts for this time step: flows new_recoveries = 0 new_deaths = 0 new_infections = 0 # Extract these for later use. The values do not change in the person loop and the dictionary lookup is expensive. rand_popdata = (self['usepopdata'] == 'random') beta = self['beta'] asymp_factor = self['asymp_factor'] diag_factor = self['diag_factor'] cont_factor = self['cont_factor'] beta_pop = self['beta_pop'] n_beds = self['n_beds'] bed_constraint = False # Print progress if verbose >= 1: string = f' Running day {t:0.0f} of {self.pars["n_days"]} ({elapsed:0.2f} s elapsed)...' if verbose >= 2: sc.heading(string) else: print(string) # Update each person, skipping people who are susceptible not_susceptible = filter(lambda p: not p.susceptible, self.people.values()) n_susceptible = len(self.people) for person in not_susceptible: n_susceptible -= 1 # If exposed, check if the person becomes infectious or develops symptoms if person.exposed: n_exposed += 1 if not person.infectious and t == person.date_infectious: # It's the day they become infectious person.infectious = True sc.printv( f' Person {person.uid} became infectious!', 2, verbose) # If infectious, check if anyone gets infected if person.infectious: # Check whether the person died on this timestep new_death = person.check_death(t) new_deaths += new_death # Check whether the person recovered on this timestep new_recovery = person.check_recovery(t) new_recoveries += new_recovery # No recovery: check symptoms if not new_recovery: n_symptomatic += person.check_symptomatic(t) n_severe += person.check_severe(t) n_critical += person.check_critical(t) if n_severe > n_beds: bed_constraint = True # If the person didn't die or recover, check for onward transmission if not new_death and not new_recovery: n_infectious += 1 # Count this person as infectious # Calculate transmission risk based on whether they're asymptomatic/diagnosed/have been isolated thisbeta = beta * \ (asymp_factor if person.symptomatic else 1.) * \ (diag_factor if person.diagnosed else 1.) * \ (cont_factor if person.known_contact else 1.) # Determine who gets infected if rand_popdata: # Flat contacts transmission_inds = cvu.bf(thisbeta, person.contacts) else: # Dictionary of contacts -- extra loop over layers transmission_inds = [] for ckey in self.contact_keys: layer_beta = thisbeta * beta_pop[ckey] transmission_inds.extend( cvu.bf(layer_beta, person.contacts[ckey])) # Loop over people who do for contact_ind in transmission_inds: target_person = self.get_person( contact_ind) # Stored by integer # This person was diagnosed last time step: time to flag their contacts if person.date_diagnosed is not None and person.date_diagnosed == t - 1: target_person.known_contact = True # Skip people who are not susceptible if target_person.susceptible: new_infections += target_person.infect( t, bed_constraint, source=person) # Actually infect them sc.printv( f' Person {person.uid} infected person {target_person.uid}!', 2, verbose) sc.printv( f'Number of beds available: {n_beds-n_severe}, bed constraint: {bed_constraint}', 2, verbose) # End of person loop; apply interventions for intervention in self['interventions']: intervention.apply(self) if self['interv_func'] is not None: # Apply custom intervention function self = self['interv_func'](self) # Update counts for this time step: stocks self.results['n_susceptible'][t] = n_susceptible self.results['n_exposed'][t] = n_exposed self.results['n_infectious'][ t] = n_infectious # Tracks total number infectious at this timestep self.results['n_symptomatic'][ t] = n_symptomatic # Tracks total number symptomatic at this timestep self.results['n_severe'][ t] = n_severe # Tracks total number of severe cases at this timestep self.results['n_critical'][ t] = n_critical # Tracks total number of critical cases at this timestep self.results['bed_capacity'][ t] = n_severe / n_beds if n_beds > 0 else None # Update counts for this time step: flows self.results['new_infections'][ t] = new_infections # New infections on this timestep self.results['new_recoveries'][ t] = new_recoveries # Tracks new recoveries on this timestep self.results['new_deaths'][t] = new_deaths # End of time loop; compute cumulative results outside of the time loop if finalize: self.finalize(verbose=verbose) # Finalize the results sc.printv(f'\nRun finished after {elapsed:0.1f} s.\n', 1, verbose) self.summary = self.summary_stats(verbose=verbose) if do_plot: # Optionally plot self.plot(**kwargs) return self.results
ns = (1 + np.arange(10)) * 100e3 fig = pl.figure(figsize=(14, 22)) count = 0 for which in ['mult', 'cond']: for jit in [0]: #[0,1]: print(which, jit) ts = [] for n in ns: nt = NumbaTests(n=n) sc.tic() nt.run(which=which, jit=jit) t = sc.toc(output=True) ts.append(t) print(n, t) count += 1 pl.subplot(4, 2, count) pl.scatter(ns / 1e6, ts) sc.setylim() pl.xlabel('Number of points (millions)') pl.ylabel('Calculation time') pl.title(f'Which = {which}, jit={jit}') count += 1 pl.subplot(4, 2, count) pl.scatter(ns / 1e6, np.array(ts) / ns * 1e6) sc.setylim()
import sciris as sc import covasim as cv sc.tic() people = cv.People(pop_size=2000) sc.toc(label='default') plist = people.to_people() sc.toc(label='to people') ppl2 = cv.People() ppl2.from_people(plist) sc.toc(label='from people') ppl3 = people + ppl2 sim = cv.Sim(pop_type='random', pop_size=20000) cv.make_people(sim) ppl4 = sim.people sc.toc(label='as sim') df = ppl4.to_df() arr = ppl4.to_arr() sc.toc(label='to df/arr')
if pn == 1: ax[pn] = sns.swarmplot(x="variable", y="value", data=df2, color="grey", alpha=0.5) ax[pn] = sns.violinplot(x="variable", y="value", data=df2, color="lightblue", alpha=0.5, inner=None) ax[pn] = sns.pointplot(x="variable", y="value", data=df2, ci=None, color="steelblue", markers='D', scale=1.2) ax[pn].set_ylabel('Cumulative infections, 1 Dec 2020 - 1 Mar 2021') ax[pn].set_xlabel('Symptomatic testing rate') cv.savefig(f'{figsfolder}/fig4_multiscens.pdf') print([np.median(cuminf[tn]) for tn in range(len(thresholds))]) print([np.quantile(cuminf[tn], q=0.025) for tn in range(len(thresholds))]) print([np.quantile(cuminf[tn], q=0.975) for tn in range(len(thresholds))]) sc.toc(T)
def test_generate_microstructures_with_non_teaching_staff(): # # generate and write to file population1 = sp.make_population(datadir=datadir, location=location, state_location=state_location, country_location=country_location, n=n, use_two_group_reduction=use_two_group_reduction, average_LTCF_degree=average_LTCF_degree, ltcf_staff_age_min=ltcf_staff_age_min, ltcf_staff_age_max=ltcf_staff_age_max, with_school_types=with_school_types, school_mixing_type=school_mixing_type, average_class_size=average_class_size, inter_grade_mixing=inter_grade_mixing, average_student_teacher_ratio=average_student_teacher_ratio, average_teacher_teacher_degree=average_teacher_teacher_degree, teacher_age_min=teacher_age_min, teacher_age_max=teacher_age_max, average_student_all_staff_ratio=average_student_all_staff_ratio, average_additional_staff_degree=average_additional_staff_degree, staff_age_min=staff_age_min, staff_age_max=staff_age_max, write=write, plot=plot, return_popdict=return_popdict, use_default=use_default) # # # read in from file population2 = sp.make_population(datadir=datadir, location=location, state_location=state_location, country_location=country_location, n=n, use_two_group_reduction=use_two_group_reduction, average_LTCF_degree=average_LTCF_degree, with_school_types=with_school_types, school_mixing_type=school_mixing_type, average_class_size=average_class_size, inter_grade_mixing=inter_grade_mixing, average_student_teacher_ratio=average_student_teacher_ratio, average_teacher_teacher_degree=average_teacher_teacher_degree, average_student_all_staff_ratio=average_student_all_staff_ratio, average_additional_staff_degree=average_additional_staff_degree) # # generate on the fly sc.tic() population3 = sp.make_population(n=n, generate=True, with_facilities=True, use_two_group_reduction=use_two_group_reduction, average_LTCF_degree=average_LTCF_degree, ltcf_staff_age_min=ltcf_staff_age_min, ltcf_staff_age_max=ltcf_staff_age_max, with_school_types=with_school_types, school_mixing_type=school_mixing_type, average_class_size=average_class_size, inter_grade_mixing=inter_grade_mixing, average_student_teacher_ratio=average_student_teacher_ratio, average_teacher_teacher_degree=average_teacher_teacher_degree, teacher_age_min=teacher_age_min, teacher_age_max=teacher_age_max, with_non_teaching_staff=with_non_teaching_staff, average_student_all_staff_ratio=average_student_all_staff_ratio, average_additional_staff_degree=average_additional_staff_degree, staff_age_min=staff_age_min, staff_age_max=staff_age_max, rand_seed=rand_seed) sc.toc() check_all_residents_are_connected_to_staff(population3) return population1, population2, population3
def run(self, seed_infections=1, verbose=None, calc_likelihood=False, do_plot=False, **kwargs): ''' Run the simulation ''' T = sc.tic() # Reset settings and results if verbose is None: verbose = self['verbose'] self.init_results() self.init_people( seed_infections=seed_infections) # Actually create the people daily_tests = self.data[ 'new_tests'] # Number of tests each day, from the data evacuated = self.data['evacuated'] # Number of people evacuated # Main simulation loop for t in range(self.npts): # Print progress if verbose >= 1: string = f' Running day {t:0.0f} of {self["n_days"]}...' if verbose >= 2: sc.heading(string) else: print(string) test_probs = { } # Store the probability of each person getting tested # Update each person for person in self.people.values(): # Count susceptibles if person.susceptible: self.results['n_susceptible'][t] += 1 continue # Don't bother with the rest of the loop # Handle testing probability if person.infectious: test_probs[person.uid] = self[ 'symptomatic'] # They're infectious: high probability of testing else: test_probs[person.uid] = 1.0 # If exposed, check if the person becomes infectious if person.exposed: self.results['n_exposed'][t] += 1 if not person.infectious and t >= person.date_infectious: # It's the day they become infectious person.infectious = True if verbose >= 2: print( f' Person {person.uid} became infectious!' ) # If infectious, check if anyone gets infected if person.infectious: # First, check for recovery if person.date_recovered and t >= person.date_recovered: # It's the day they become infectious person.exposed = False person.infectious = False person.recovered = True self.results['recoveries'][t] += 1 else: self.results['n_infectious'][ t] += 1 # Count this person as infectious n_contacts = cv.pt( person.contacts ) # Draw the number of Poisson contacts for this person contact_inds = cv.choose( max_n=len(self.people), n=n_contacts) # Choose people at random for contact_ind in contact_inds: exposure = cv.bt(self['r_contact'] ) # Check for exposure per person if exposure: target_person = self.people[contact_ind] if target_person.susceptible: # Skip people who are not susceptible self.results['infections'][t] += 1 target_person.susceptible = False target_person.exposed = True target_person.date_exposed = t incub_pars = dict(dist='normal_int', par1=self['incub'], par2=self['incub_std']) dur_pars = dict(dist='normal_int', par1=self['dur'], par2=self['dur_std']) incub_dist = cv.sample(**incub_pars) dur_dist = cv.sample(**dur_pars) target_person.date_infectious = t + incub_dist target_person.date_recovered = target_person.date_infectious + dur_dist if verbose >= 2: print( f' Person {person.uid} infected person {target_person.uid}!' ) # Count people who recovered if person.recovered: self.results['n_recovered'][t] += 1 # Implement testing -- this is outside of the loop over people, but inside the loop over time if t < len( daily_tests ): # Don't know how long the data is, ensure we don't go past the end n_tests = daily_tests.iloc[t] # Number of tests for this day if n_tests and not pl.isnan( n_tests): # There are tests this day self.results['tests'][ t] = n_tests # Store the number of tests test_probs = pl.array(list(test_probs.values())) test_probs /= test_probs.sum() test_inds = cv.choose_weighted(probs=test_probs, n=n_tests) uids_to_pop = [] for test_ind in test_inds: tested_person = self.people[test_ind] if tested_person.infectious and cv.bt( self['sensitivity'] ): # Person was tested and is true-positive self.results['diagnoses'][t] += 1 tested_person.diagnosed = True if self['evac_positives']: uids_to_pop.append(tested_person.uid) if verbose >= 2: print( f' Person {person.uid} was diagnosed!' ) for uid in uids_to_pop: # Remove people from the ship once they're diagnosed self.off_ship[uid] = self.people.pop(uid) # Implement quarantine if t == self['quarantine']: if verbose >= 1: print(f'Implementing quarantine on day {t}...') for person in self.people.values(): if 'quarantine_eff' in self.pars.keys(): quarantine_eff = self['quarantine_eff'] # Both else: if person.crew: quarantine_eff = self['quarantine_eff_c'] # Crew else: quarantine_eff = self['quarantine_eff_g'] # Guests person.contacts *= quarantine_eff # Implement testing change if t == self['testing_change']: if verbose >= 1: print(f'Implementing testing change on day {t}...') self['symptomatic'] *= self[ 'testing_symptoms'] # Reduce the proportion of symptomatic testing # Implement evacuations if t < len(evacuated): n_evacuated = evacuated.iloc[ t] # Number of evacuees for this day if n_evacuated and not pl.isnan( n_evacuated ): # There are evacuees this day # TODO -- refactor with n_tests if verbose >= 1: print(f'Implementing evacuation on day {t}') evac_inds = cv.choose(max_n=len(self.people), n=n_evacuated) uids_to_pop = [] for evac_ind in evac_inds: evac_person = self.people[evac_ind] if evac_person.infectious and cv.bt( self['sensitivity']): self.results['evac_diagnoses'][t] += 1 uids_to_pop.append(evac_person.uid) for uid in uids_to_pop: # Remove people from the ship once they're diagnosed self.off_ship[uid] = self.people.pop(uid) # Compute cumulative results self.results['cum_exposed'] = pl.cumsum(self.results['infections']) self.results['cum_tested'] = pl.cumsum(self.results['tests']) self.results['cum_diagnosed'] = pl.cumsum(self.results['diagnoses']) # Compute likelihood if calc_likelihood: self.likelihood() # Tidy up self.results['ready'] = True elapsed = sc.toc(T, output=True) if verbose >= 1: print(f'\nRun finished after {elapsed:0.1f} s.\n') summary = self.summary_stats() print(f"""Summary: {summary['n_susceptible']:5.0f} susceptible {summary['n_exposed']:5.0f} exposed {summary['n_infectious']:5.0f} infectious """) if do_plot: self.plot(**kwargs) return self.results
if animate_all: pl.pause(idelay) for f in flist: if f.e: pl.plot(f.x[1], f.y[1], '*', c=f.c, markersize=msize, **plargs) if tlist: for dq in tlist: pl.plot(dq.d, dq.t, 'o', c=dq.c, markersize=msize * 2, fillstyle='none', **plargs) if dlist: for dq in dlist: pl.plot(dq.d, dq.t, 's', c=dq.c, markersize=msize * 1.2, **plargs) if qlist: for dq in qlist: pl.plot(dq.d, dq.t, 'x', c=dq.c, markersize=msize * 2.0) pl.plot([0, day], [0.5, 0.5], c='k', lw=5) if animate: pl.pause(daydelay) sc.toc(tstart)
def run(self, do_plot=False, until=None, restore_pars=True, reset_seed=True, verbose=None, **kwargs): ''' Run the simulation. Args: do_plot (bool): whether to plot until (int): day to run until restore_pars (bool): whether to make a copy of the parameters before the run and restore it after, so runs are repeatable reset_seed (bool): whether to reset the random number stream immediately before run verbose (float): level of detail to print, e.g. 0 = no output, 0.2 = print every 5th day, 1 = print every day kwargs (dict): passed to sim.plot() Returns: results (dict): the results object (also modifies in-place) ''' # Initialization steps -- start the timer, initialize the sim and the seed, and check that the sim hasn't been run T = sc.tic() if verbose is None: verbose = self['verbose'] if not self.initialized: self.initialize() self._orig_pars = sc.dcp(self.pars) # Create a copy of the parameters, to restore after the run, in case they are dynamically modified if reset_seed: # Reset the RNG. If the simulation is newly created, then the RNG will be reset by sim.initialize() so the use case # for resetting the seed here is if the simulation has been partially run, and changing the seed is required self.set_seed() until = self.npts if until is None else self.day(until) if until > self.npts: raise AlreadyRunError(f'Requested to run until t={until} but the simulation end is t={self.npts}') if self.complete: raise AlreadyRunError('Simulation is already complete (call sim.initialize() to re-run)') if self.t >= until: # NB. At the start, self.t is None so this check must occur after initialization raise AlreadyRunError(f'Simulation is currently at t={self.t}, requested to run until t={until} which has already been reached') # Main simulation loop while self.t < until: # Check if we were asked to stop elapsed = sc.toc(T, output=True) if self['timelimit'] and elapsed > self['timelimit']: sc.printv(f"Time limit ({self['timelimit']} s) exceeded; call sim.finalize() to compute results if desired", 1, verbose) return elif self['stopping_func'] and self['stopping_func'](self): sc.printv("Stopping function terminated the simulation; call sim.finalize() to compute results if desired", 1, verbose) return # Print progress if verbose: simlabel = f'"{self.label}": ' if self.label else '' string = f' Running {simlabel}{self.datevec[self.t]} ({self.t:2.0f}/{self.pars["n_days"]}) ({elapsed:0.2f} s) ' if verbose >= 2: sc.heading(string) else: if not (self.t % int(1.0/verbose)): sc.progressbar(self.t+1, self.npts, label=string, length=20, newline=True) # Do the heavy lifting -- actually run the model! self.step() # If simulation reached the end, finalize the results if self.complete: self.finalize(verbose=verbose, restore_pars=restore_pars) sc.printv(f'Run finished after {elapsed:0.2f} s.\n', 1, verbose) if do_plot: # Optionally plot self.plot(**kwargs) return self.results else: return # If not complete, return nothing
popsize = popsizes[1] print(f'Working on {popsize} for {cv.defaults.default_int}...') sim = cv.Sim(pop_size=popsize, verbose=0) sim.run() popsize = popsizes[2] print(f'Working on {popsize} for {cv.defaults.default_int}...') sim = cv.Sim(pop_size=popsize, verbose=0) sim.run() return sim sc.mprofile(mrun, mrun) #%% Now check timings timings = [] for popsize in popsizes: for r in range(repeats): print( f'Working on {popsize} for {cv.defaults.default_int}, iteration {r}...' ) T = sc.tic() sim = cv.Sim(pop_size=popsize, verbose=0) sim.run() out = sc.toc(T, output=True) timings.append({'popsize': popsize, 'elapsed': out}) df = pd.DataFrame.from_dict(timings) print(df)
def test_estimates(doplot=False, verbose=False): # Set input data parameters ntrain = 200 ntest = 50 npars = 2 noise = 0.5 seed = 1 # Set algorithm parameters k = 3 nbootstrap = 10 weighted = 1 # Set up training and test arrays pl.seed(seed) train_arr = pl.rand(ntrain, npars) train_vals = pl.sqrt(((train_arr-0.5)**2).sum(axis=1)) + noise*pl.rand(ntrain) # Distance from center test_arr = pl.rand(ntest, npars) # Calculate the estimates t1 = sc.tic() test_vals = pe.bootknn(test=test_arr, train=train_arr, values=train_vals, k=k, nbootstrap=nbootstrap, weighted=weighted) t2 = sc.toc(t1, output=True) timestr = f'time = {t2*1e3:0.2f} ms' print(timestr) if doplot: # Setup xind = 0 yind = 1 offset = 0.015 cmap = 'parula' x_off = offset*pl.array([0, -1, 0, 1, 0]) # Offsets in the x direction y_off = offset*pl.array([-1, 0, 0, 0, 1]) # Offsets in the y direction train_args = dict(marker='o', s=50) test_args = dict(marker='s', s=80) minval = min(train_vals.min(), test_vals.array.min()) maxval = min(train_vals.max(), test_vals.array.max()) train_colors = sc.arraycolors(train_vals, cmap=cmap, minval=minval, maxval=maxval) test_colors = sc.arraycolors(test_vals.array, cmap=cmap, minval=minval, maxval=maxval) # Make the figure pl.figure(figsize=eqfigsize) pl.scatter(train_arr[:,xind], train_arr[:,yind], c=train_colors, **train_args, label='Training') # Plot the data for q in range(ntest): for i in range(5): label = 'Predicted' if i==0 and q==0 else None # To avoid appearing multiple times x = test_arr[q,xind]+x_off[i] y = test_arr[q,yind]+y_off[i] v = test_vals.array[i,q] c = test_colors[i,q] pl.scatter(x, y, c=[c], **test_args, label=label) if verbose: print(f'i={i}, q={q}, x={x:0.3f}, y={y:0.3f}, v={v:0.3f}, c={c}') pl.pause(0.3) pl.xlabel('Parameter 1') pl.ylabel('Parameter 2') pl.title(f'Parameter estimates; {timestr}') pl.legend() pl.set_cmap(cmap) pl.clim((minval, maxval)) pl.axis('square') pl.colorbar() return test_vals
def cache_populations(seed, pop_size, popfile, do_save=True): ''' Pre-generate the synthpops population ''' use_two_group_reduction = True average_LTCF_degree = 20 ltcf_staff_age_min = 20 ltcf_staff_age_max = 60 with_school_types = True average_class_size = 20 inter_grade_mixing = 0.1 average_student_teacher_ratio = 20 average_teacher_teacher_degree = 3 teacher_age_min = 25 teacher_age_max = 75 with_non_teaching_staff = True average_student_all_staff_ratio = 11 average_additional_staff_degree = 20 staff_age_min = 20 staff_age_max = 75 school_mixing_type = { 'pk': 'age_clustered', 'es': 'age_clustered', 'ms': 'age_clustered', 'hs': 'random', 'uv': 'random' } T = sc.tic() print(f'Making "{popfile}"...') popdict = sp.make_population( n=pop_size, rand_seed=seed, generate=True, with_facilities=True, use_two_group_reduction=use_two_group_reduction, average_LTCF_degree=average_LTCF_degree, ltcf_staff_age_min=ltcf_staff_age_min, ltcf_staff_age_max=ltcf_staff_age_max, with_school_types=with_school_types, school_mixing_type=school_mixing_type, average_class_size=average_class_size, inter_grade_mixing=inter_grade_mixing, average_student_teacher_ratio=average_student_teacher_ratio, average_teacher_teacher_degree=average_teacher_teacher_degree, teacher_age_min=teacher_age_min, teacher_age_max=teacher_age_max, with_non_teaching_staff=with_non_teaching_staff, average_student_all_staff_ratio=average_student_all_staff_ratio, average_additional_staff_degree=average_additional_staff_degree, staff_age_min=staff_age_min, staff_age_max=staff_age_max, ) if do_save: sc.saveobj(popfile, popdict) sc.toc(T) print(f'Done, saved to {popfile}') return popdict
''' Test different parallelization options ''' import covasim as cv import sciris as sc # Set the parallelization to use -- 0 = none, 1 = safe, 2 = rand parallel = 1 pars = dict( pop_size = 1e6, n_days = 200, verbose = 0.1, ) cv.options.set(numba_cache=0, numba_parallel=parallel) parstr = f'Parallel={cv.options.numba_parallel}' print('Initializing (always single core)') sim = cv.Sim(**pars, label=parstr) sim.initialize() print(f'Running ({parstr})') sc.tic() sim.run() sc.toc(label=parstr)
def make_population(seed=0, popfile=None): ''' Pre-generate the synthpops population ''' pars = sc.objdict( pop_size = pop_size, pop_type = 'synthpops', rand_seed = seed, ) use_two_group_reduction = True average_LTCF_degree = 20 ltcf_staff_age_min = 20 ltcf_staff_age_max = 60 with_school_types = True average_class_size = 20 inter_grade_mixing = 0.1 average_student_teacher_ratio = 20 average_teacher_teacher_degree = 3 teacher_age_min = 25 teacher_age_max = 75 with_non_teaching_staff = True # if with_non_teaching_staff is False, but generate is True, then average_all_staff_ratio should be average_student_teacher_ratio or 0 average_student_all_staff_ratio = 11 average_additional_staff_degree = 20 staff_age_min = 20 staff_age_max = 75 cohorting = True if cohorting: strategy = 'clustered' school_mixing_type = {'pk': 'clustered', 'es': 'clustered', 'ms': 'clustered', 'hs': 'random', 'uv': 'random'} else: strategy = 'normal' school_mixing_type = {'pk': 'age_and_class_clustered', 'es': 'age_and_class_clustered', 'ms': 'age_and_class_clustered', 'hs': 'random', 'uv': 'random'} if popfile is None: popfile = f'inputs/transtree_synthpops_{strategy}_withstaff_seed{pars.rand_seed}.ppl' T = sc.tic() print(f'Making "{popfile}"...') sim = cv.Sim(pars) cv.make_people(sim, popfile=popfile, save_pop=True, generate=True, with_facilities=True, use_two_group_reduction=use_two_group_reduction, average_LTCF_degree=average_LTCF_degree, ltcf_staff_age_min=ltcf_staff_age_min, ltcf_staff_age_max=ltcf_staff_age_max, with_school_types=with_school_types, school_mixing_type=school_mixing_type, average_class_size=average_class_size, inter_grade_mixing=inter_grade_mixing, average_student_teacher_ratio=average_student_teacher_ratio, average_teacher_teacher_degree=average_teacher_teacher_degree, teacher_age_min=teacher_age_min, teacher_age_max=teacher_age_max, with_non_teaching_staff=with_non_teaching_staff, average_student_all_staff_ratio=average_student_all_staff_ratio, average_additional_staff_degree=average_additional_staff_degree, staff_age_min=staff_age_min, staff_age_max=staff_age_max ) sc.toc(T) print('Done') return
def make_pop(seed=0): ''' Pre-generate the synthpops population ''' pars = sc.objdict( # pop_size = 2.25e6, pop_size=11e3, #2.25e5, pop_type='synthpops', rand_seed=seed, ) use_two_group_reduction = True average_LTCF_degree = 20 ltcf_staff_age_min = 20 ltcf_staff_age_max = 60 with_school_types = True average_class_size = 20 inter_grade_mixing = 0.1 average_student_teacher_ratio = 20 average_teacher_teacher_degree = 3 teacher_age_min = 25 teacher_age_max = 75 with_non_teaching_staff = True # if with_non_teaching_staff is False, but generate is True, then average_all_staff_ratio should be average_student_teacher_ratio or 0 average_student_all_staff_ratio = 11 average_additional_staff_degree = 20 staff_age_min = 20 staff_age_max = 75 # For reference re: school_types # school_mixing_type = 'random' means that students in the school have edges randomly chosen from other students, teachers, and non teaching staff across the school. Students, teachers, and non teaching staff are treated the same in terms of edge generation. # school_mixing_type = 'age_clustered' means that students in the school have edges mostly within their own age/grade, with teachers, and non teaching staff. Strict classrooms are not generated. Teachers have some additional edges with other teachers. # school_mixing_type = 'age_and_class_clustered' means that students are cohorted into classes of students of the same age/grade with at least 1 teacher, and then some have contact with non teaching staff. Teachers have some additional edges with other teachers. cohorting = True if cohorting: strategy = 'clustered' # students in pre-k, elementary, and middle school are cohorted into strict classrooms school_mixing_type = { 'pk': 'age_and_class_clustered', 'es': 'age_and_class_clustered', 'ms': 'age_and_class_clustered', 'hs': 'random', 'uv': 'random' } else: strategy = 'normal' school_mixing_type = { 'pk': 'age_clustered', 'es': 'age_clustered', 'ms': 'age_clustered', 'hs': 'random', 'uv': 'random' } T = sc.tic() print(f'Making "{popfile}"...') sim = cv.Sim(pars) cv.make_people( sim, popfile=popfile, save_pop=True, generate=True, with_facilities=True, use_two_group_reduction=use_two_group_reduction, average_LTCF_degree=average_LTCF_degree, ltcf_staff_age_min=ltcf_staff_age_min, ltcf_staff_age_max=ltcf_staff_age_max, with_school_types=with_school_types, school_mixing_type=school_mixing_type, average_class_size=average_class_size, inter_grade_mixing=inter_grade_mixing, average_student_teacher_ratio=average_student_teacher_ratio, average_teacher_teacher_degree=average_teacher_teacher_degree, teacher_age_min=teacher_age_min, teacher_age_max=teacher_age_max, with_non_teaching_staff=with_non_teaching_staff, average_student_all_staff_ratio=average_student_all_staff_ratio, average_additional_staff_degree=average_additional_staff_degree, staff_age_min=staff_age_min, staff_age_max=staff_age_max, layer_mapping={'LTCF': 'l'}, ) sc.toc(T) print('Done') return
def run(self, do_plot=False, until=None, verbose=None, **kwargs): ''' Run the simulation. Args: do_plot (bool): whether to plot until (int): day to run until verbose (int): level of detail to print kwargs (dict): passed to self.plot() Returns: results: the results object (also modifies in-place) ''' # Initialize T = sc.tic() if not self.initialized: self.initialize() else: self.validate_pars() # We always want to validate the parameters before running self.init_interventions() # And interventions if verbose is None: verbose = self['verbose'] if until: until = self.day(until) # Main simulation loop for t in self.tvec: # Print progress if verbose >= 1: elapsed = sc.toc(output=True) simlabel = f'"{self.label}": ' if self.label else '' string = f' Running {simlabel}{self.datevec[t]} ({t:2.0f}/{self.pars["n_days"]}) ({elapsed:0.2f} s) ' if verbose >= 2: sc.heading(string) elif verbose == 1: sc.progressbar(t+1, self.npts, label=string, length=20, newline=True) # Do the heavy lifting -- actually run the model! self.step() # Check if we were asked to stop elapsed = sc.toc(T, output=True) if elapsed > self['timelimit']: sc.printv(f"Time limit ({self['timelimit']} s) exceeded", 1, verbose) break elif self['stopping_func'] and self['stopping_func'](self): sc.printv("Stopping function terminated the simulation", 1, verbose) break if self.t == until: # If until is specified, just stop here return # End of time loop; compute cumulative results outside of the time loop self.finalize(verbose=verbose) # Finalize the results sc.printv(f'Run finished after {elapsed:0.2f} s.\n', 1, verbose) self.summary = self.summary_stats(verbose=verbose) if do_plot: # Optionally plot self.plot(**kwargs) return self.results
def run(self, do_plot=False, until=None, restore_pars=True, reset_seed=True, verbose=None, **kwargs): ''' Run the simulation. Args: do_plot (bool): whether to plot until (int): day to run until restore_pars (bool): whether to make a copy of the parameters before the run and restore it after, so runs are repeatable reset_seed (bool): whether to reset the random number stream immediately before run verbose (float): level of detail to print, e.g. 0 = no output, 0.2 = print every 5th day, 1 = print every day kwargs (dict): passed to sim.plot() Returns: results (dict): the results object (also modifies in-place) ''' # Initialize T = sc.tic() if not self.initialized: self.initialize() else: self.validate_pars() # We always want to validate the parameters before running self.init_interventions() # And interventions if reset_seed: self.set_seed() # Ensure the random number generator is freshly initialized if restore_pars: orig_pars = sc.dcp(self.pars) # Create a copy of the parameters, to restore after the run, in case they are dynamically modified if verbose is None: verbose = self['verbose'] if until: until = self.day(until) # Main simulation loop for t in self.tvec: # Print progress if verbose: elapsed = sc.toc(output=True) simlabel = f'"{self.label}": ' if self.label else '' string = f' Running {simlabel}{self.datevec[t]} ({t:2.0f}/{self.pars["n_days"]}) ({elapsed:0.2f} s) ' if verbose >= 2: sc.heading(string) else: if not (t % int(1.0/verbose)): sc.progressbar(t+1, self.npts, label=string, length=20, newline=True) # Do the heavy lifting -- actually run the model! self.step() # Check if we were asked to stop elapsed = sc.toc(T, output=True) if self['timelimit'] and elapsed > self['timelimit']: sc.printv(f"Time limit ({self['timelimit']} s) exceeded", 1, verbose) break elif self['stopping_func'] and self['stopping_func'](self): sc.printv("Stopping function terminated the simulation", 1, verbose) break if self.t == until: # If until is specified, just stop here return # End of time loop; compute cumulative results outside of the time loop self.finalize(verbose=verbose) # Finalize the results sc.printv(f'Run finished after {elapsed:0.2f} s.\n', 1, verbose) if restore_pars: self.restore_pars(orig_pars) if do_plot: # Optionally plot self.plot(**kwargs) return self.results
def test_benchmark(do_save=do_save): ''' Compare benchmark performance ''' print('Running benchmark...') previous = sc.loadjson(benchmark_filename) repeats = 5 t_inits = [] t_runs = [] def normalize_performance(): ''' Normalize performance across CPUs -- simple Numpy calculation ''' t_bls = [] bl_repeats = 5 n_outer = 10 n_inner = 1e6 for r in range(bl_repeats): t0 = sc.tic() for i in range(n_outer): a = np.random.random(int(n_inner)) b = np.random.random(int(n_inner)) a*b t_bl = sc.toc(t0, output=True) t_bls.append(t_bl) t_bl = min(t_bls) reference = 0.112 # Benchmarked on an Intel i9-8950HK CPU @ 2.90GHz ratio = reference/t_bl return ratio # Test CPU performance before the run r1 = normalize_performance() # Do the actual benchmarking for r in range(repeats): # Create the sim sim = make_sim(verbose=0) # Time initialization t0 = sc.tic() sim.initialize() t_init = sc.toc(t0, output=True) # Time running t0 = sc.tic() sim.run() t_run = sc.toc(t0, output=True) # Store results t_inits.append(t_init) t_runs.append(t_run) # Test CPU performance after the run r2 = normalize_performance() ratio = (r1+r2)/2 t_init = min(t_inits)*ratio t_run = min(t_runs)*ratio # Construct json n_decimals = 3 json = {'time': { 'initialize': round(t_init, n_decimals), 'run': round(t_run, n_decimals), }, 'parameters': { 'pop_size': sim['pop_size'], 'pop_type': sim['pop_type'], 'n_days': sim['n_days'], }, 'cpu_performance': ratio, } print('Previous benchmark:') sc.pp(previous) print('\nNew benchmark:') sc.pp(json) if do_save: sc.savejson(filename=benchmark_filename, obj=json, indent=2) print('Done.') return json
def run(self, initialize=True, do_plot=False, verbose=None, **kwargs): ''' Run the simulation ''' T = sc.tic() # Reset settings and results if verbose is None: verbose = self['verbose'] if initialize: self.initialize() # Create people, results, etc. # Main simulation loop self.stopped = False # We've just been asked to run, so ensure we're unstopped for t in range(self.npts): # Check timing and stopping function elapsed = sc.toc(T, output=True) if elapsed > self['timelimit']: print( f"Time limit ({self['timelimit']} s) exceeded; stopping..." ) self.stopped = { 'why': 'timelimit', 'message': 'Time limit exceeded at step {t}', 't': t } if self['stop_func']: self.stopped = self['stop_func']( self, t) # Feed in the current simulation object and the time # If this gets set, stop running -- e.g. if the time limit is exceeded if self.stopped: break # Zero counts for this time step. n_susceptible = 0 n_exposed = 0 n_deaths = 0 n_recoveries = 0 n_infectious = 0 n_infections = 0 n_symptomatic = 0 n_severe = 0 n_recovered = 0 # Extract these for later use. The values do not change in the person loop and the dictionary lookup is expensive. rand_popdata = (self['usepopdata'] == 'random') beta = self['beta'] asymp_factor = self['asymp_factor'] diag_factor = self['diag_factor'] cont_factor = self['cont_factor'] beta_pop = self['beta_pop'] n_beds = self['n_beds'] bed_constraint = False # Print progress if verbose >= 1: string = f' Running day {t:0.0f} of {self.pars["n_days"]} ({elapsed:0.2f} s elapsed)...' if verbose >= 2: sc.heading(string) else: print(string) # Update each person, skipping people who are susceptible not_susceptible = filter(lambda p: not p.susceptible, self.people.values()) n_susceptible = len(self.people) for person in not_susceptible: n_susceptible -= 1 # If exposed, check if the person becomes infectious or develops symptoms if person.exposed: n_exposed += 1 if not person.infectious and t >= person.date_infectious: # It's the day they become infectious person.infectious = True sc.printv( f' Person {person.uid} became infectious!', 2, verbose) # If infectious, check if anyone gets infected if person.infectious: # Check for death died = person.check_death(t) n_deaths += died # Check for recovery recovered = person.check_recovery(t) n_recoveries += recovered # No recovery: check symptoms if not recovered: n_symptomatic += person.check_symptomatic(t) n_severe += person.check_severe(t) if n_severe > n_beds: bed_constraint = True # If the person didn't die or recover, check for onward transmission if not died and not recovered: n_infectious += 1 # Count this person as infectious # Calculate transmission risk based on whether they're asymptomatic/diagnosed/have been isolated thisbeta = beta * \ (asymp_factor if person.symptomatic else 1.) * \ (diag_factor if person.diagnosed else 1.) * \ (cont_factor if person.known_contact else 1.) # Determine who gets infected if rand_popdata: # Flat contacts transmission_inds = cvu.bf(thisbeta, person.contacts) else: # Dictionary of contacts -- extra loop over layers transmission_inds = [] for ckey in self.contact_keys: layer_beta = thisbeta * beta_pop[ckey] transmission_inds.extend( cvu.bf(layer_beta, person.contacts[ckey])) # Loop over people who do for contact_ind in transmission_inds: target_person = self.get_person( contact_ind) # Stored by integer # This person was diagnosed last time step: time to flag their contacts if person.date_diagnosed is not None and person.date_diagnosed == t - 1: target_person.known_contact = True # Skip people who are not susceptible if target_person.susceptible: n_infections += target_person.infect( t, bed_constraint, source=person) # Actually infect them sc.printv( f' Person {person.uid} infected person {target_person.uid}!', 2, verbose) # Count people who recovered if person.recovered: n_recovered += 1 sc.printv( f'Number of beds available: {n_beds-n_severe}, bed constraint: {bed_constraint}', 2, verbose) # End of person loop; apply interventions for intervention in self['interventions']: intervention.apply(self, t) if self['interv_func'] is not None: # Apply custom intervention function self = self['interv_func'](self, t) # Update counts for this time step self.results['n_susceptible'][t] = n_susceptible self.results['n_exposed'][t] = n_exposed self.results['deaths'][t] = n_deaths self.results['recoveries'][t] = n_recoveries self.results['n_infectious'][t] = n_infectious self.results['infections'][t] = n_infections self.results['n_symptomatic'][t] = n_symptomatic self.results['n_severe'][t] = n_severe self.results['n_recovered'][t] = n_recovered self.results['bed_capacity'][ t] = n_severe / n_beds if n_beds > 0 else None # End of time loop; compute cumulative results outside of the time loop self.results['cum_exposed'].values = pl.cumsum( self.results['infections'].values) + self[ 'n_infected'] # Include initially infected people self.results['cum_tested'].values = pl.cumsum( self.results['tests'].values) self.results['cum_diagnosed'].values = pl.cumsum( self.results['diagnoses'].values) self.results['cum_deaths'].values = pl.cumsum( self.results['deaths'].values) self.results['cum_recoveries'].values = pl.cumsum( self.results['recoveries'].values) # Add in the results from the interventions for intervention in self['interventions']: intervention.finalize(self) # Execute any post-processing # Scale the results for reskey in self.reskeys: if self.results[reskey].scale: self.results[reskey].values *= self['scale'] # Perform calculations on results self.compute_doubling() self.compute_r_eff() self.likelihood() # Tidy up self.results_ready = True sc.printv(f'\nRun finished after {elapsed:0.1f} s.\n', 1, verbose) self.results['summary'] = self.summary_stats() if do_plot: self.plot(**kwargs) # Convert to an odict to allow e.g. sim.people[25] later, and results to an objdict to allow e.g. sim.results.diagnoses self.people = sc.odict(self.people) self.results = sc.objdict(self.results) return self.results
} scens = cv.Scenarios(sim=sim, basepars=basepars, metapars=metapars, scenarios=scenarios) scens.run(verbose=verbose, debug=debug) if do_plot: scens.plot(do_save=do_save, do_show=do_show, fig_path=fig_path) return scens #%% Run as a script if __name__ == '__main__': sc.tic() bed_scens = test_beds(do_plot=do_plot, do_save=do_save, do_show=do_show, fig_path=fig_path) border_scens = test_borderclosure(do_plot=do_plot, do_save=do_save, do_show=do_show, fig_path=fig_path) sc.toc() print('Done.')
inter_grade_mixing=0.1, teacher_age_min=25, teacher_age_max=75, staff_age_min=20, staff_age_max=75, average_student_teacher_ratio=20, average_teacher_teacher_degree=3, average_student_all_staff_ratio=15, average_additional_staff_degree=20, ) if __name__ == '__main__': T = sc.tic() pop = sp.make_population(**pars) elapsed = sc.toc(T, output=True) for person in [6, 66, 666]: print(f'\n\nPerson {person}') sc.pp(pop[person]) print('\n\n') print(sc.gitinfo(sp.__file__)) print(sp.version.__version__) popkeys = list(pop.keys()) stridekeys = [popkeys[i] for i in range(0, len(pop), stride)] subpop = {k: pop[k] for k in stridekeys} if do_save: sc.savejson(f'pop_v{sp.version.__version__}.json', subpop, indent=2)