Ejemplo n.º 1
0
    def apply(self, sim):
        ''' Perform testing '''

        t = sim.t
        if t < self.start_day:
            return

        new_diagnoses = 0
        for person in sim.people:
            new_diagnoses += person.check_diagnosed(t)

            if (person.symptomatic and cv.bt(self.symptomatic_prob)) or (
                    not person.symptomatic and cv.bt(self.asymptomatic_prob)):
                sim.results['new_tests'][t] += 1
                person.test(t, self.test_sensitivity, self.loss_prob,
                            self.test_delay)
        sim.results['new_diagnoses'][t] += new_diagnoses

        return
Ejemplo n.º 2
0
    def apply(self, sim, t):
        ''' Perform testing '''

        new_scheduled_tests = set()

        for i, person in enumerate(sim.people.values()):
            if i in self.scheduled_tests or (person.symptomatic and cv.bt(
                    self.symptomatic_prob)) or (not person.symptomatic and
                                                cv.bt(self.asymptomatic_prob)):
                self.results['n_tested'][t] += 1
                person.test(t, self.test_sensitivity)
                if person.diagnosed:
                    self.results['n_diagnosed'][t] += 1
                    for idx in person.contacts:
                        if person.diagnosed and self.trace_prob and cv.bt(
                                self.trace_prob):
                            new_scheduled_tests.add(idx)

        self.scheduled_tests = new_scheduled_tests
        return
Ejemplo n.º 3
0
    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_people(
                            max_ind=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_people_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_people(max_ind=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