def test_choose(): sc.heading('Choose people') x1 = cv.choose(10, 5) with pytest.raises(Exception): cv.choose_w(10, 5) # Requesting mroe people than are available print(f'Uniform sample from 0-9: {x1}') return x1
def test_choose_w(): sc.heading('Choose weighted people') n = 100 samples = 5 lin = np.arange(n) lin = lin / lin.sum() x0 = cv.choose_w([0.01] * n, samples) x1 = cv.choose_w(lin, samples) x2 = cv.choose_w([1, 0, 0, 0, 0], 1) x3 = cv.choose_w([0.5, 0.5, 0, 0, 0], 1) assert x2[0] == 0 assert x3[0] in [0, 1] assert len(x0) == len(x1) == samples with pytest.raises(Exception): cv.choose_w([0.5, 0.5], 10) # Requesting mroe people than are available print(f'Uniform sample 0-99: x0 = {x0}, mean {x0.mean()}') print(f'Weighted sample 0-99: x1 = {x1}, mean {x1.mean()}') print(f'All weight on 0: x2 = {x2}') print(f'All weight on 0 or 1: x3 = {x3}') return x1
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 = 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 = 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_w(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 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 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""")