コード例 #1
0
    def init_sim(self, sim):

        super().init_sim(sim)

        self.clock = sim.clock
        self.scale_factor = sim.world.scale_factor

        self.home_activity_type = sim.activity_manager.as_int(
            self.config['home_activity_type'])
        self.max_tests_per_day = self.config['max_tests_per_day']

        self.do_test_to_test_results_ticks = \
            int(sim.clock.days_to_ticks(self.config['do_test_to_test_results_days']))
        self.infected_states = self.config['incubating_states'] + self.config[
            'contagious_states']

        self.agents = sim.world.agents

        # Collect data on agents for telemetry purposes
        for agent in self.agents:
            home_location = agent.locations_for_activity(
                self.home_activity_type)[0]
            self.home_locations_dict[agent] = home_location
            if home_location.typ in self.border_countries:
                self.resident_dict[agent] = False
            else:
                self.resident_dict[agent] = True

        self.test_result_events = DeferredEventPool(self.bus, self.clock)
        self.bus.subscribe("request.testing.start", self.start_test, self)
        self.bus.subscribe("notify.time.midnight", self.reset_daily_counter,
                           self)
コード例 #2
0
    def init_sim(self, sim):

        super().init_sim(sim)

        self.test_events = DeferredEventPool(self.bus, sim.clock)
        self.bus.subscribe("request.testing.book_test", self.handle_book_test,
                           self)

        # Time between selection for test and the time at which the test will take place
        self.time_to_arrange_test_no_symptoms = \
           int(sim.clock.days_to_ticks(self.config['test_booking_to_test_sample_days_no_symptoms']))
        self.time_to_arrange_test_symptoms    = \
           int(sim.clock.days_to_ticks(self.config['test_booking_to_test_sample_days_symptoms']))
コード例 #3
0
ファイル: testing.py プロジェクト: abm-covid-lux/abmlux
class LargeScaleTesting(Intervention):
    """Randomly select a number of people per day for testing."""
    def __init__(self, config, init_enabled):
        super().__init__(config, init_enabled)

        self.register_variable('invitations_per_day')

    def init_sim(self, sim):
        super().init_sim(sim)

        self.scale_factor = sim.world.scale_factor
        self.invitations_per_day = self.config['invitations_per_day']

        self.test_booking_events = DeferredEventPool(self.bus, sim.clock)
        self.world = sim.world
        self.current_day = None

        self.bus.subscribe("notify.time.midnight", self.midnight, self)

        # Assign booking delays to each agents. This is the time an agent will wait between
        # being invited to test and booking a test:
        self.invitation_to_test_booking_delay = {}
        delay_distribution = self.config['invitation_to_test_booking_days']
        for agent in self.world.agents:
            delay_days = self.prng.multinoulli_dict(delay_distribution)
            delay_ticks = int(sim.clock.days_to_ticks(int(delay_days)))
            self.invitation_to_test_booking_delay[agent] = delay_ticks

    def midnight(self, clock, t):
        """At midnight, book agents in for testing after a given delay by queuing up events
        that request a test be booked.

        This is equivalent to agents being notified that they should book, but not doing so
        immediately."""

        if not self.enabled:
            return

        if self.invitations_per_day == 0:
            return

        num_invitations = math.ceil(self.scale_factor *
                                    self.invitations_per_day)
        # Invite for testing by random selection:
        test_agents_random = self.prng.random_sample(self.world.agents,
                                                     num_invitations)
        for agent in test_agents_random:
            self.test_booking_events.add(
                "request.testing.book_test",
                self.invitation_to_test_booking_delay[agent], agent)
コード例 #4
0
class TestBooking(Intervention):
    """Consume a 'request to book test' signal and wait a bit whilst getting around to it.

    Represents the process of booking a test, where testing may be limited and not available
    immediately."""
    def __init__(self, config, init_enabled):
        super().__init__(config, init_enabled)

        self.symptomatic_states = config['symptomatic_states']
        self.agents_awaiting_test = set()

    def init_sim(self, sim):

        super().init_sim(sim)

        self.test_events = DeferredEventPool(self.bus, sim.clock)
        self.bus.subscribe("request.testing.book_test", self.handle_book_test,
                           self)

        # Time between selection for test and the time at which the test will take place
        self.time_to_arrange_test_no_symptoms = \
           int(sim.clock.days_to_ticks(self.config['test_booking_to_test_sample_days_no_symptoms']))
        self.time_to_arrange_test_symptoms    = \
           int(sim.clock.days_to_ticks(self.config['test_booking_to_test_sample_days_symptoms']))

    def handle_book_test(self, agent):
        """Someone has been selected for testing.  Insert a delay between the booking of the test
        and the test"""

        # If disabled, prevent new bookings.  Old bookings will still complete
        if not self.enabled:
            return

        if agent not in self.agents_awaiting_test:
            if agent.health in self.symptomatic_states:
                self.test_events.add(self.send_agent_for_test,
                                     self.time_to_arrange_test_symptoms, agent)
            else:
                self.test_events.add(self.send_agent_for_test,
                                     self.time_to_arrange_test_no_symptoms,
                                     agent)
            self.agents_awaiting_test.add(agent)

    def send_agent_for_test(self, agent):
        """Send an event requesting a test for the given agent."""

        self.agents_awaiting_test.remove(agent)  # Update index
        self.bus.publish("request.testing.start", agent)
コード例 #5
0
ファイル: testing.py プロジェクト: abm-covid-lux/abmlux
    def init_sim(self, sim):
        super().init_sim(sim)

        self.prob_test_symptoms_symptomatic = self.config[
            'prob_test_symptoms_symptomatic']
        self.prob_test_symptoms_asymptomatic = self.config[
            'prob_test_symptoms_asymptomatic']
        self.onset_of_symptoms_to_test_booking = \
            int(sim.clock.days_to_ticks(self.config['onset_of_symptoms_to_test_booking_days']))

        self.symptomatic_states = self.config['symptomatic_states']
        self.asymptomatic_states = self.config['asymptomatic_states']
        self.test_booking_events = DeferredEventPool(self.bus, sim.clock)

        self.bus.subscribe("notify.agent.health", self.handle_health_change,
                           self)
コード例 #6
0
ファイル: testing.py プロジェクト: abm-covid-lux/abmlux
class PrescriptionTesting(Intervention):
    """This refers to situations where an agent books a test without having been directed to do so
    by any of the other interventions. Chief among these are the situations in which an agent
    voluntarily books a test having developed symptoms."""
    def init_sim(self, sim):
        super().init_sim(sim)

        self.prob_test_symptoms_symptomatic = self.config[
            'prob_test_symptoms_symptomatic']
        self.prob_test_symptoms_asymptomatic = self.config[
            'prob_test_symptoms_asymptomatic']
        self.onset_of_symptoms_to_test_booking = \
            int(sim.clock.days_to_ticks(self.config['onset_of_symptoms_to_test_booking_days']))

        self.symptomatic_states = self.config['symptomatic_states']
        self.asymptomatic_states = self.config['asymptomatic_states']
        self.test_booking_events = DeferredEventPool(self.bus, sim.clock)

        self.bus.subscribe("notify.agent.health", self.handle_health_change,
                           self)

    def handle_health_change(self, agent, old_health):
        """When an agent changes health state to a symptomatic state, there is a certain chance
        that they book a test.  Booking a test takes time, so this method queues up the test
        booking event."""

        if not self.enabled:
            return

        # If no change, skip
        if old_health == agent.health:
            return

        # If moving from an asymptomatic state to a symtomatic state
        if old_health not in self.symptomatic_states and agent.health in self.symptomatic_states:
            if self.prng.boolean(self.prob_test_symptoms_symptomatic):
                self.test_booking_events.add("request.testing.book_test", \
                                             self.onset_of_symptoms_to_test_booking, agent)

        # If moving from to an asymptomatic state
        if old_health not in self.asymptomatic_states and agent.health in self.asymptomatic_states:
            if self.prng.boolean(self.prob_test_symptoms_asymptomatic):
                self.test_booking_events.add("request.testing.book_test", \
                                             self.onset_of_symptoms_to_test_booking, agent)
コード例 #7
0
ファイル: quarantine.py プロジェクト: abm-covid-lux/abmlux
    def init_sim(self, sim):
        super().init_sim(sim)

        self.default_duration_days = self.config['default_duration_days']
        self.default_duration_ticks = int(
            sim.clock.days_to_ticks(self.default_duration_days))
        early_end_days = self.config[
            'negative_test_result_to_end_quarantine_days']
        self.early_end_ticks = int(sim.clock.days_to_ticks(early_end_days))
        self.location_blacklist = self.config['location_blacklist']
        self.home_activity_type = sim.activity_manager.as_int(
            self.config['home_activity_type'])
        self.disable_releases_immediately = self.config[
            'disable_releases_immediately']

        self.health_states = sim.disease_model.states
        self.clock = sim.clock

        self.end_quarantine_events = DeferredEventPool(self.bus, sim.clock)
        self.agents_in_quarantine = set()

        # What to do this tick
        self.agents_to_add = []
        self.agents_to_remove = []

        # Enter/leave quarantine
        self.bus.subscribe("notify.time.tick", self.update_quarantine_status,
                           self)
        # Queue people up to enter/leave quarantine this tick
        self.bus.subscribe("notify.testing.result", self.handle_test_result,
                           self)
        self.bus.subscribe("request.quarantine.start",
                           self.handle_start_quarantine, self)
        self.bus.subscribe("request.quarantine.stop",
                           self.handle_end_quarantine, self)
        # Respond to requested location changes by moving people home
        self.bus.subscribe("request.agent.location",
                           self.handle_location_change, self)
        self.bus.subscribe("notify.time.midnight",
                           self.record_number_in_quarantine, self)

        self.register_variable('default_duration_days')
コード例 #8
0
ファイル: testing.py プロジェクト: abm-covid-lux/abmlux
    def init_sim(self, sim):
        super().init_sim(sim)

        self.scale_factor = sim.world.scale_factor
        self.invitations_per_day = self.config['invitations_per_day']

        self.test_booking_events = DeferredEventPool(self.bus, sim.clock)
        self.world = sim.world
        self.current_day = None

        self.bus.subscribe("notify.time.midnight", self.midnight, self)

        # Assign booking delays to each agents. This is the time an agent will wait between
        # being invited to test and booking a test:
        self.invitation_to_test_booking_delay = {}
        delay_distribution = self.config['invitation_to_test_booking_days']
        for agent in self.world.agents:
            delay_days = self.prng.multinoulli_dict(delay_distribution)
            delay_ticks = int(sim.clock.days_to_ticks(int(delay_days)))
            self.invitation_to_test_booking_delay[agent] = delay_ticks
コード例 #9
0
class Laboratory(Intervention):
    """A testing laboratory."""
    def __init__(self, config, init_enabled):
        super().__init__(config, init_enabled)

        self.prob_false_positive = config['prob_false_positive']
        self.prob_false_negative = config['prob_false_negative']

        self.border_countries = config['border_countries']

        self.tests_performed_today = 0
        self.home_locations_dict = {}
        self.resident_dict = {}

        self.register_variable('max_tests_per_day')

    def init_sim(self, sim):

        super().init_sim(sim)

        self.clock = sim.clock
        self.scale_factor = sim.world.scale_factor

        self.home_activity_type = sim.activity_manager.as_int(
            self.config['home_activity_type'])
        self.max_tests_per_day = self.config['max_tests_per_day']

        self.do_test_to_test_results_ticks = \
            int(sim.clock.days_to_ticks(self.config['do_test_to_test_results_days']))
        self.infected_states = self.config['incubating_states'] + self.config[
            'contagious_states']

        self.agents = sim.world.agents

        # Collect data on agents for telemetry purposes
        for agent in self.agents:
            home_location = agent.locations_for_activity(
                self.home_activity_type)[0]
            self.home_locations_dict[agent] = home_location
            if home_location.typ in self.border_countries:
                self.resident_dict[agent] = False
            else:
                self.resident_dict[agent] = True

        self.test_result_events = DeferredEventPool(self.bus, self.clock)
        self.bus.subscribe("request.testing.start", self.start_test, self)
        self.bus.subscribe("notify.time.midnight", self.reset_daily_counter,
                           self)

    def reset_daily_counter(self, clock, t):
        """Reset daily test count"""

        self.tests_performed_today = 0

    def start_test(self, agent):
        """Start the test.

        Agents are tested by selecting a weighted random result according to the class' config,
        and then queueing up a result to be sent out after a set amount of time.  This delay
        represents the time taken to complete the test itself.
        """

        # If disabled, don't start new tests.  Tests underway will still complete
        if not self.enabled:
            return

        if self.tests_performed_today >= math.ceil(
                self.max_tests_per_day * self.scale_factor):
            return

        test_result = False
        if agent.health in self.infected_states:
            if self.prng.boolean(1 - self.prob_false_negative):
                test_result = True
        else:
            if self.prng.boolean(self.prob_false_positive):
                test_result = True

        self.tests_performed_today += 1

        self.test_result_events.add("notify.testing.result",
                                    self.do_test_to_test_results_ticks, agent,
                                    test_result)

        self.report("notify.testing.result", self.clock, test_result,
                    agent.age, agent.health,
                    self.home_locations_dict[agent].uuid,
                    self.home_locations_dict[agent].coord,
                    self.resident_dict[agent])
コード例 #10
0
ファイル: quarantine.py プロジェクト: abm-covid-lux/abmlux
class Quarantine(Intervention):
    """Intervention that applies quarantine rules.

    Agents are forced to return to certain locations when they request to move."""
    def init_sim(self, sim):
        super().init_sim(sim)

        self.default_duration_days = self.config['default_duration_days']
        self.default_duration_ticks = int(
            sim.clock.days_to_ticks(self.default_duration_days))
        early_end_days = self.config[
            'negative_test_result_to_end_quarantine_days']
        self.early_end_ticks = int(sim.clock.days_to_ticks(early_end_days))
        self.location_blacklist = self.config['location_blacklist']
        self.home_activity_type = sim.activity_manager.as_int(
            self.config['home_activity_type'])
        self.disable_releases_immediately = self.config[
            'disable_releases_immediately']

        self.health_states = sim.disease_model.states
        self.clock = sim.clock

        self.end_quarantine_events = DeferredEventPool(self.bus, sim.clock)
        self.agents_in_quarantine = set()

        # What to do this tick
        self.agents_to_add = []
        self.agents_to_remove = []

        # Enter/leave quarantine
        self.bus.subscribe("notify.time.tick", self.update_quarantine_status,
                           self)
        # Queue people up to enter/leave quarantine this tick
        self.bus.subscribe("notify.testing.result", self.handle_test_result,
                           self)
        self.bus.subscribe("request.quarantine.start",
                           self.handle_start_quarantine, self)
        self.bus.subscribe("request.quarantine.stop",
                           self.handle_end_quarantine, self)
        # Respond to requested location changes by moving people home
        self.bus.subscribe("request.agent.location",
                           self.handle_location_change, self)
        self.bus.subscribe("notify.time.midnight",
                           self.record_number_in_quarantine, self)

        self.register_variable('default_duration_days')

    def record_number_in_quarantine(self, clock, t):
        """Record data on number of agents in quarantine and their health status"""

        self.default_duration_ticks = int(
            clock.days_to_ticks(self.default_duration_days))
        num_in_quarantine = len(self.agents_in_quarantine)
        agents_in_quarantine_by_health_state = {
            str(hs): len([
                agent for agent in self.agents_in_quarantine
                if agent.health == hs
            ])
            for hs in self.health_states
        }
        total_age = sum([agent.age for agent in self.agents_in_quarantine])
        self.report("quarantine_data", self.clock, num_in_quarantine,
                    agents_in_quarantine_by_health_state, total_age)

    def update_quarantine_status(self, clock, t):
        """Take lists of things to do and apply them."""
        for agent in self.agents_to_add:
            if agent not in self.agents_in_quarantine:
                self.agents_in_quarantine.add(agent)
                self.end_quarantine_events.add("request.quarantine.stop", \
                                               self.default_duration_ticks, agent)
                self.bus.publish("notify.quarantine.start", agent)
        self.agents_to_add = []

        for agent in self.agents_to_remove:
            if agent in self.agents_in_quarantine:
                self.agents_in_quarantine.remove(agent)
                self.bus.publish("notify.quarantine.end", agent)
        self.agents_to_remove = []

    def handle_test_result(self, agent, result):
        """Respond to positive test results by starting quarantine.
        Respond to negative test results by ending quarantine."""

        if agent in self.agents_in_quarantine and not result:
            self.end_quarantine_events.add("request.quarantine.stop",
                                           self.early_end_ticks, agent)

        elif agent not in self.agents_in_quarantine and result:
            self.agents_in_quarantine.add(agent)
            self.end_quarantine_events.add("request.quarantine.stop",
                                           self.default_duration_ticks, agent)

    def handle_start_quarantine(self, agent):
        """Queues up agents to start quarantine next time quarantine status is updated."""

        # If intervention is disabled, don't ever put people in quarantine
        if not self.enabled:
            return

        if agent in self.agents_in_quarantine or agent in self.agents_to_add:
            return

        self.agents_to_add.append(agent)
        return MessageBus.CONSUME

    def handle_end_quarantine(self, agent):
        """Queues up agents to end quarantine next time quarantine status is updated."""

        if agent in self.agents_in_quarantine and agent not in self.agents_to_remove:
            self.agents_to_remove.append(agent)
        return MessageBus.CONSUME

    def handle_location_change(self, agent, new_location):
        """Catch any location changes that will move quarantined agents out of their home,
        and rebroadcast an event to move them home again.
        """

        # If we've been told to curtail all quarantines, allow people out.
        # They retain their quarantined status, so will be restricted again if quarantine
        # re-enables, but for now they're good.
        if self.disable_releases_immediately and not self.enabled:
            return

        if agent in self.agents_in_quarantine:
            home_location = agent.locations_for_activity(
                self.home_activity_type)[0]
            if new_location != home_location:
                if new_location.typ not in self.location_blacklist:
                    self.bus.publish("request.agent.location", agent,
                                     home_location)
                    return MessageBus.CONSUME
コード例 #11
0
ファイル: vaccination.py プロジェクト: abm-covid-lux/abmlux
    def init_sim(self, sim):
        super().init_sim(sim)

        # This controls how many first doses are able to be distributed per day. The total number
        # of doses per day will be this number plus the number of second doses delivered that day.
        self.scale_factor = sim.world.scale_factor
        self.max_first_doses_per_day = self.config['max_first_doses_per_day']

        # A certain amount of time after the first dose, a second dose will be administered
        time_between_doses_days = int(self.config['time_between_doses_days'])
        self.time_between_doses_ticks = int(
            sim.clock.days_to_ticks(time_between_doses_days))
        self.second_dose_events = DeferredEventPool(self.bus, sim.clock)

        self.bus.subscribe("notify.time.midnight", self.midnight, self)
        # self.bus.subscribe("notify.testing.result", self.update_vaccination_priority_list, self)
        self.bus.subscribe("request.vaccination.second_dose",
                           self.administer_second_dose, self)

        # A list of agents to be vaccinated
        self.vaccination_priority_list = []

        # A precomuted record of where agents live and work, for telemetry purposes
        self.home_location_type_dict = {}
        self.work_location_type_dict = {}

        # Order the agents according to the desired preferential scheme
        carehome_residents_workers = []
        hospital_workers = []
        other_agents = []

        care_home_location_type = self.config['care_home_location_type']
        hospital_location_type = self.config['hospital_location_type']
        home_activity_type = sim.activity_manager.as_int(
            self.config['home_activity_type'])
        work_activity_type = sim.activity_manager.as_int(
            self.config['work_activity_type'])

        self.first_dose_successful = self.config['prob_first_dose_successful']
        self.second_dose_successful = self.config[
            'prob_second_dose_successful']

        min_age = self.config['min_age']

        age_low = self.config['age_low']
        age_high = self.config['age_high']

        prob_low = self.config['prob_low']
        prob_med = self.config['prob_med']
        prob_high = self.config['prob_high']

        # A dictionary of who doesn't refuse the vaccine
        self.agent_wants_vaccine = {}

        # Decide in advance who will refuse the vaccine
        for agent in sim.world.agents:
            if agent.age >= min_age:
                if agent.age < age_low:
                    self.agent_wants_vaccine[agent] = self.prng.boolean(
                        prob_low)
                if agent.age >= age_low and agent.age < age_high:
                    self.agent_wants_vaccine[agent] = self.prng.boolean(
                        prob_med)
                if agent.age >= age_high:
                    self.agent_wants_vaccine[agent] = self.prng.boolean(
                        prob_high)

        # Dictionaries of efficacy for each agent
        self.first_dose_effective = {}
        self.second_dose_effective = {}

        # Determine in advance the effecitveness of the vaccine on each agent
        for agent in sim.world.agents:
            if agent.age >= min_age:
                self.first_dose_effective[agent] = self.prng.boolean(
                    self.first_dose_successful)
                self.second_dose_effective[agent] = self.prng.boolean(
                    self.second_dose_successful)

        # Determine which agents live or work in carehomes and which agents work in hospitals. Note
        # that workplaces are assigned to everybody, so some agents will be assigned hospitals or
        # carehomes as places of work but, due to their routines, will not actually go to work at
        # these places due to not working at all. So this is somewhat approximate.
        for agent in sim.world.agents:
            if agent.age >= min_age:
                home_location = agent.locations_for_activity(
                    home_activity_type)[0]
                self.home_location_type_dict[agent] = home_location.typ
                work_location = agent.locations_for_activity(
                    work_activity_type)[0]
                self.work_location_type_dict[agent] = work_location.typ
                if home_location.typ in care_home_location_type or\
                    work_location.typ in care_home_location_type:
                    carehome_residents_workers.append(agent)
                elif work_location.typ in hospital_location_type:
                    hospital_workers.append(agent)
                else:
                    other_agents.append(agent)

        # Sort the lists of agents by age, with the oldest first
        def return_age(agent):
            return agent.age

        carehome_residents_workers.sort(key=return_age, reverse=True)
        hospital_workers.sort(key=return_age, reverse=True)
        other_agents.sort(key=return_age, reverse=True)

        # Combine these lists together to get the order of agents to be vaccinated
        self.vaccination_priority_list = carehome_residents_workers + hospital_workers\
                                                                    + other_agents
コード例 #12
0
ファイル: vaccination.py プロジェクト: abm-covid-lux/abmlux
class Vaccination(Intervention):
    """Vaccinate agents using a two dose vaccine prioritizing certain agents first"""
    def __init__(self, config, init_enabled):
        super().__init__(config, init_enabled)

        # This represents the daily vaccination capacity
        self.register_variable('max_first_doses_per_day')

    def init_sim(self, sim):
        super().init_sim(sim)

        # This controls how many first doses are able to be distributed per day. The total number
        # of doses per day will be this number plus the number of second doses delivered that day.
        self.scale_factor = sim.world.scale_factor
        self.max_first_doses_per_day = self.config['max_first_doses_per_day']

        # A certain amount of time after the first dose, a second dose will be administered
        time_between_doses_days = int(self.config['time_between_doses_days'])
        self.time_between_doses_ticks = int(
            sim.clock.days_to_ticks(time_between_doses_days))
        self.second_dose_events = DeferredEventPool(self.bus, sim.clock)

        self.bus.subscribe("notify.time.midnight", self.midnight, self)
        # self.bus.subscribe("notify.testing.result", self.update_vaccination_priority_list, self)
        self.bus.subscribe("request.vaccination.second_dose",
                           self.administer_second_dose, self)

        # A list of agents to be vaccinated
        self.vaccination_priority_list = []

        # A precomuted record of where agents live and work, for telemetry purposes
        self.home_location_type_dict = {}
        self.work_location_type_dict = {}

        # Order the agents according to the desired preferential scheme
        carehome_residents_workers = []
        hospital_workers = []
        other_agents = []

        care_home_location_type = self.config['care_home_location_type']
        hospital_location_type = self.config['hospital_location_type']
        home_activity_type = sim.activity_manager.as_int(
            self.config['home_activity_type'])
        work_activity_type = sim.activity_manager.as_int(
            self.config['work_activity_type'])

        self.first_dose_successful = self.config['prob_first_dose_successful']
        self.second_dose_successful = self.config[
            'prob_second_dose_successful']

        min_age = self.config['min_age']

        age_low = self.config['age_low']
        age_high = self.config['age_high']

        prob_low = self.config['prob_low']
        prob_med = self.config['prob_med']
        prob_high = self.config['prob_high']

        # A dictionary of who doesn't refuse the vaccine
        self.agent_wants_vaccine = {}

        # Decide in advance who will refuse the vaccine
        for agent in sim.world.agents:
            if agent.age >= min_age:
                if agent.age < age_low:
                    self.agent_wants_vaccine[agent] = self.prng.boolean(
                        prob_low)
                if agent.age >= age_low and agent.age < age_high:
                    self.agent_wants_vaccine[agent] = self.prng.boolean(
                        prob_med)
                if agent.age >= age_high:
                    self.agent_wants_vaccine[agent] = self.prng.boolean(
                        prob_high)

        # Dictionaries of efficacy for each agent
        self.first_dose_effective = {}
        self.second_dose_effective = {}

        # Determine in advance the effecitveness of the vaccine on each agent
        for agent in sim.world.agents:
            if agent.age >= min_age:
                self.first_dose_effective[agent] = self.prng.boolean(
                    self.first_dose_successful)
                self.second_dose_effective[agent] = self.prng.boolean(
                    self.second_dose_successful)

        # Determine which agents live or work in carehomes and which agents work in hospitals. Note
        # that workplaces are assigned to everybody, so some agents will be assigned hospitals or
        # carehomes as places of work but, due to their routines, will not actually go to work at
        # these places due to not working at all. So this is somewhat approximate.
        for agent in sim.world.agents:
            if agent.age >= min_age:
                home_location = agent.locations_for_activity(
                    home_activity_type)[0]
                self.home_location_type_dict[agent] = home_location.typ
                work_location = agent.locations_for_activity(
                    work_activity_type)[0]
                self.work_location_type_dict[agent] = work_location.typ
                if home_location.typ in care_home_location_type or\
                    work_location.typ in care_home_location_type:
                    carehome_residents_workers.append(agent)
                elif work_location.typ in hospital_location_type:
                    hospital_workers.append(agent)
                else:
                    other_agents.append(agent)

        # Sort the lists of agents by age, with the oldest first
        def return_age(agent):
            return agent.age

        carehome_residents_workers.sort(key=return_age, reverse=True)
        hospital_workers.sort(key=return_age, reverse=True)
        other_agents.sort(key=return_age, reverse=True)

        # Combine these lists together to get the order of agents to be vaccinated
        self.vaccination_priority_list = carehome_residents_workers + hospital_workers\
                                                                    + other_agents

    # def update_vaccination_priority_list(self, agent, test_result):
    #     """Agents who have tested positive are removed from the list of agents to be vaccinated"""

    #     if test_result:
    #         try:
    #             self.vaccination_priority_list.remove(agent)
    #         except ValueError:
    #             pass

    def administer_second_dose(self, agent):
        """Administers agents with a second dose of the vaccine"""

        if self.second_dose_effective[agent]:
            agent.vaccinated = True

    def midnight(self, clock, t):
        """At midnight, remove from the priority list agents who have tested positive that day
        and vaccinate an appropriate number of the remainder"""

        if not self.enabled:
            return

        if self.max_first_doses_per_day == 0:
            return

        max_rescaled = math.ceil(self.scale_factor *
                                 self.max_first_doses_per_day)
        num_to_vaccinate = min(max_rescaled,
                               len(self.vaccination_priority_list))

        agents_to_vaccinate = self.vaccination_priority_list[
            0:num_to_vaccinate]
        del self.vaccination_priority_list[0:num_to_vaccinate]

        agent_data = []
        for agent in agents_to_vaccinate:
            if self.agent_wants_vaccine[agent]:
                if self.first_dose_effective[agent]:
                    agent.vaccinated = True
                self.second_dose_events.add("request.vaccination.second_dose",
                                            self.time_between_doses_ticks,
                                            agent)

                # For telemetry
                agent_data.append([
                    agent.age, agent.health, agent.nationality,
                    self.home_location_type_dict[agent],
                    self.work_location_type_dict[agent]
                ])

        self.report("notify.vaccination.first_doses", clock, agent_data)