예제 #1
0
def simulate(params, plt=None, plot_hourly=None, xlabel=None):

    if plot_hourly is None:
        plot_hourly = params['geometry']['n'] < 50000  # Hack, remove

    # Initialize a city's geography and its denizens
    num, num_initially_infected = int(params['geometry']['n']), int(
        params['geometry']['i'])
    num_times_of_day = int(params['motion']['t'])
    precision = int(params['geometry']['p'])
    home, work = home_and_work_locations(geometry_params=params['geometry'],
                                         num=num)
    positions = nudge(home, w=0.05 * params['motion']['w'])
    status = np.random.permutation([INFECTED] * num_initially_infected +
                                   [VULNERABLE] *
                                   (num - num_initially_infected))
    day_fraction = 1.0 / num_times_of_day

    # Population drifts to work and back, incurring viral load based on proximity to others who are infected
    day = 0
    while any(s in [INFECTED, POSITIVE, SYMPTOMATIC] for s in status):
        day = day + 1
        for step_no, time_of_day in enumerate(times_of_day(num_times_of_day)):
            stationary = [s in [DECEASED, POSITIVE] for s in status]
            attractors = destinations(status, time_of_day, home, work)
            positions = evolve_positions(positions=positions,
                                         motion_params=params['motion'],
                                         attractors=attractors,
                                         day_fraction=day_fraction,
                                         stationary=stationary)
            exposed = newly_exposed(positions=positions,
                                    status=status,
                                    precision=precision)
            status = contact_progression(status=status,
                                         health_params=params['health'],
                                         exposed=exposed)
            status = individual_progression(status,
                                            health_params=params['health'],
                                            day_fraction=day_fraction)

            if plt and (plot_hourly or step_no % 12 == 0):
                plt.clf()
                plot_points(plt=plt,
                            positions=positions,
                            status=status,
                            title="Day " + str(day) + ':' +
                            str(time_of_day * num_times_of_day))
                b = params['geometry']['b']
                plt.axis([-b, b, -b, b])
                if xlabel:
                    plt.xlabel(xlabel)
                plt.show(block=False)
                plt.pause(0.01)
            pprint(
                Counter([list(STATE_DESCRIPTIONS.values())[s]
                         for s in status]))
예제 #2
0
def homesick(params):
    """ To illustrate the OU process  """

    num, num_initially_infected = int(params['geometry']['n']),int(params['geometry']['i'])
    num_times_of_day = int(params['motion']['t'])
    day_fraction = 1.0/num_times_of_day
    home = [(0,0) for _ in range(num) ]
    w    = params['motion']['w']
    k    = params['motion']['k']
    R    = w/math.sqrt(2*k)
    b    = params['geometry']['b']
    positions = [ (x/2*b,y/2*b) for x,y in [ tuple( np.random.multivariate_normal(mean=[0,0],cov=[[1,0],[0,1]]) ) for _ in range(num)] ]
    status    = [VULNERABLE]*num

    fig, axs = plt.subplots(nrows=1, ncols=2)
    population_variances = list()
    rolling_variances = list()
    for day in range(10):
        for step_no, time_of_day in enumerate(times_of_day(num_times_of_day)):
            stationary = [ s in [DECEASED, POSITIVE] for s in status ]
            positions  = evolve_positions(positions=positions, motion_params=params['motion'], attractors=home,
                                          time_step=day_fraction, stationary=stationary)

            axs[0].clear()
            plot_points(plt=axs[0], positions=positions, status=status, sizes=[64]*6)
            b = params['geometry']['b']
            axs[0].axis([-b, b, -b, b])
            axs[0].set_title('Day '+str(day))

            circle_x, circle_y = circle(r=R)
            axs[0].scatter(x=circle_x,y=circle_y,c='g',s=1)

            axs[0].figure

            population_variance = np.mean( [ x*x+y*y for x,y in positions ])
            population_variances.append(population_variance)

            num_lagged = 5+int(0.25*len(rolling_variances))
            rolling_mean_variance = np.mean( population_variances[-num_lagged:] )
            rolling_variances.append(rolling_mean_variance)

            axs[1].clear()
            axs[1].plot([ math.sqrt(v) for v in population_variances],'+')
            axs[1].plot([ math.sqrt(v) for v in rolling_variances] )
            axs[1].plot(list(range(len(rolling_variances))),[R]*len(rolling_variances),'--')
            axs[1].axis([0,len(rolling_variances),0.75*R,1.5*max(rolling_variances[-1],R)])
            axs[1].legend(['Current','Avg last ('+str(num_lagged)+')','Theoretical'],loc='upper left')
            axs[1].set_title('Root mean square distance')
            axs[1].figure


            plt.show(block=False)
            plt.pause(0.01)
            if step_no==1 and day==0:
                plt.pause(20)
예제 #3
0
    def callback(self, day, day_fraction, status, positions, home, work, plt, **ignore_other_kwargs):
        """ This gets called after each computation cycle (see pandemic/simulation.py) """
        from pandemic.metrics import collision_count
        cc = collision_count(positions=positions, status=status, precision=self.params['geometry']['p'])
        self.collision_history.append(cc)
        if day_fraction == 0:
            # Daily collision TS
            self.collision_daily_history.append(sum(self.collision_history[-self.params['motion']['t']:]))

            # Standard plot of infections
            metrics = status_counts(status=status)
            self.metric_history.append(metrics)
            self.time_history.append(day + day_fraction)
            self.axs[0][0].clear
            plot_points(plt=self.axs[0][0], positions=positions, status=status, title='Ornstein-Uhlenbeck')
            self.axs[0][0].figure

            # Standard plot of vulnerable only
            metrics = status_counts(status=status)
            vulnerable_positions = [pos for pos, s in zip(positions, status) if s == 0]
            vulnerable_status = [s for s in status if s == 0]

            # Counts plot
            self.metric_history.append(metrics)
            self.time_history.append(day + day_fraction)
            self.axs[1][0].clear()
            plot_points(plt=self.axs[1][0], positions=vulnerable_positions, status=vulnerable_status,
                        title='Vulnerable')
            self.axs[1][0].figure

            # Growth curve
            infect = [m[1] for m in self.metric_history]
            self.axs[0][1].plot(self.time_history, infect, color=self.color)
            # self.axs[0][1].set_yscale('log')
            self.axs[0][1].set_title('Infected')
            self.axs[0][1].figure

            if day > 1:
                # Collisions curve
                self.axs[1][1].plot(self.collision_daily_history, color=self.color)
                self.axs[1][1].set_title('Collisions per day')
                self.axs[1][1].set_xlabel('Days since ' + str(self.params['geometry']['i']) + ' cases.')

            self.plt.show(block=False)
            self.plt.pause(0.1)
예제 #4
0
    def plot(self, plt, positions, status):

        # Population plot
        self.axs[0][0].clear()
        plot_points(plt=self.axs[0][0], positions=positions, status=status)
        circle_x, circle_y = circle(r=self.R)
        self.axs[0][0].scatter(x=circle_x, y=circle_y, c='g', s=1)
        self.axs[0][0].figure

        # Metrics plots, regular and logarithmic
        for k in range(2):
            self.axs[1][k].clear()
            self.plot_metrics(plt=self.axs[1][k], logarithmic=k)
            self.axs[1][k].figure

        # Rates of change
        self.axs[0][1].clear()
        self.plot_metrics(plt=self.axs[0][1], logarithmic=False, differences=True)
        self.axs[0][1].figure

        plt.show(block=False)
        plt.pause(0.1)
예제 #5
0
    def callback(self, day, day_fraction, status, positions, home, work, plt,
                 **ignore_other_kwargs):
        """ This gets called after each computation cycle (see pandemic/simulation.py) """
        from pandemic.metrics import collision_count
        # Unique collisions with Joe
        from geohash import encode

        approx_precision = self.params['geometry']['p'] - 2

        for joe in range(self.num_joes):
            joes_hash = encode(positions[joe][0],
                               positions[joe][1],
                               precision=approx_precision)
            rough_positions = [
                (encode(pos[0],
                        pos[1],
                        precision=self.params['geometry']['p'] - 2), j)
                for j, pos in enumerate(positions)
            ]
            joes_collisions = [
                j for (h, j) in rough_positions
                if h == joes_hash and not j == joe
            ]
            joes_new_collisions = [
                j for j in joes_collisions if not j in self.friends[joe]
            ]
            self.friends[joe].update(joes_new_collisions)
            self.collision_history.append(len(joes_collisions))
            self.unique_collions_history.append(len(joes_new_collisions))
        num_rolling = 48
        if len(self.collision_history) > num_rolling * self.num_joes:
            rolling_collisions = sum(self.collision_history[-num_rolling *
                                                            self.num_joes:])
            rolling_unique_collisions = sum(
                self.unique_collions_history[-num_rolling * self.num_joes:])
            if day_fraction == 0:
                self.attenuation_history.append(
                    (0.1 + rolling_unique_collisions) /
                    (0.1 + rolling_collisions))
                self.herd_history.append(
                    sum([s in [VULNERABLE] for s in status]) / len(status))

        if day_fraction == 0:
            # Daily collision TS
            self.collision_daily_history.append(
                sum(self.collision_history[-self.params['motion']['t']:]))

            # Standard plot of infections
            metrics = status_counts(status=status)
            self.metric_history.append(metrics)
            self.time_history.append(day + day_fraction)
            self.axs[0][0].clear
            plot_points(plt=self.axs[0][0],
                        positions=positions,
                        status=status,
                        title='Ornstein-Uhlenbeck')
            self.axs[0][0].figure

            if day > 1:
                # Collisions curve
                self.axs[1][0].plot(self.attenuation_history, marker='*')
                self.axs[1][0].plot(self.herd_history, marker='o')
                self.axs[1][0].set_title('Novelty versus Herd effect')

                self.axs[1][0].set_xlabel('Days since ' +
                                          str(self.params['geometry']['i']) +
                                          ' cases.')
                self.axs[1][0].set_ylabel('Attenuation')
            # Growth curve
            infect = [m[1] for m in self.metric_history]
            self.axs[0][1].plot(self.time_history, infect, color=self.color)
            #self.axs[0][1].set_yscale('log')
            self.axs[0][1].set_title('Infected')
            self.axs[0][1].figure

            if day > 1:
                # Collisions curve
                self.axs[1][1].plot(self.collision_daily_history,
                                    color=self.color,
                                    marker='*')
                self.axs[1][1].set_title('Daily collisions')
                self.axs[1][1].set_xlabel('Days since ' +
                                          str(self.params['geometry']['i']) +
                                          ' cases.')

            self.plt.show(block=False)
            figManager = plt.get_current_fig_manager()
            figManager.full_screen_toggle()
            self.plt.pause(2)
예제 #6
0
                   (-10 * np.random.rand(), 0), (0, -10 * np.random.rand())]

    work_sprawls = list()
    for center in centers:
        work_sprawls.append([
            (pos[0] + center[0], pos[1] + center[1])
            for pos in sprawl(geometry_params=geometry_params, num=num)
        ])
    work = [random.choice(ws) for ws in zip(*work_sprawls)]

    geometry_params['r'] = 4 * geometry_params['r']
    home_sprawls = list()
    for center in centers:
        home_sprawls.append([
            (pos[0] + center[0], pos[1] + center[1])
            for pos in sprawl(geometry_params=geometry_params, num=num)
        ])
    home = [random.choice(hs) for hs in zip(*home_sprawls)]

    work = [random.choice([w, h])
            for w, h in zip(work, home)]  # Half stay home
    return home, work


if __name__ == "__main__":
    import matplotlib.pyplot as plt
    from pandemic.conventions import EXAMPLE_PARAMETERS
    from pandemic.plotting import plot_points
    city = sprawl(geometry_params=EXAMPLE_PARAMETERS['geometry'], num=500)
    plot_points(plt, city, status=None)
    plt.show()
예제 #7
0
def intensity(params):
    """ To illustrate the OU process with commuting  """

    num, num_initially_infected = int(params['geometry']['n']), int(
        params['geometry']['i'])
    assert num % 2 == 0

    HOME_1 = (-1.5, 1.5)
    HOME_2 = (-1.5, -1.5)
    HOME_3 = (1.5, 1.5)
    HOME_4 = (1.5, -1.5)
    HOMES = [HOME_1, HOME_2, HOME_3, HOME_4]
    WORK = (0, 0)
    home = [HOME_1] * int(num / 4) + [HOME_2] * int(num / 4) + [HOME_3] * int(
        num / 4) + [HOME_4] * int(num / 4)
    work = [WORK] * num

    def is_working(time_of_day):
        return time_of_day > 0.4 and time_of_day < 0.6

    def is_home(time_of_day):
        return time_of_day < 0.0 or time_of_day > 0.75

    num, num_initially_infected = int(params['geometry']['n']), int(
        params['geometry']['i'])
    num_times_of_day = int(params['motion']['t'])
    day_fraction = 1.0 / num_times_of_day
    w = params['motion']['w']
    k = params['motion']['k']
    R = w / math.sqrt(2 * k)
    b = params['geometry']['b']
    positions = [(x / 2 * b, y / 2 * b) for x, y in [
        tuple(np.random.multivariate_normal(mean=[0, 0], cov=[[1, 0], [0, 1]]))
        for _ in range(num)
    ]]
    status = [VULNERABLE] * num

    fig, axs = plt.subplots(nrows=2, ncols=2)

    population_variances = list()
    rolling_variances = list()
    collisions = list()
    rolling_mean_collisions = list()

    for day in range(50):
        for step_no, time_of_day in enumerate(times_of_day(num_times_of_day)):
            stationary = [s in [DECEASED, POSITIVE] for s in status]
            attractors = [w for w in work
                          ] if time_of_day < 0.5 else [h for h in home]
            positions = evolve_positions(positions=positions,
                                         motion_params=params['motion'],
                                         attractors=attractors,
                                         time_step=day_fraction,
                                         stationary=stationary)

            axs[0][0].clear()
            plot_points(plt=axs[0][0],
                        positions=positions,
                        status=status,
                        sizes=[16] * 6)
            b = params['geometry']['b']
            axs[0][0].axis([-b, b, -b, b])
            axs[0][0].axis([-b, b, -b, b])
            axs[0][0].set_title('Day ' + str(day) + ' ' + str(time_of_day))

            for offsets in HOMES + [WORK]:
                circle_x, circle_y = circle(r=R, offset=offsets)
                axs[0][0].scatter(x=circle_x, y=circle_y, c='g', s=1)

            axs[0][0].figure

            # Collision count
            locations = [
                encode(pos[0], pos[1], precision=6) for pos in positions
            ]
            num_collisions = num - len(set(locations))
            collisions.append(num_collisions)

            precision = 1.0 / (params['motion']['w']**2)
            inv_sqs = [
                np.mean([
                    1. / (0.00001 + sq_dist(positions[j], pos))
                    for k, pos in enumerate(positions) if not j == k
                ]) for j in range(num)
            ]

            population_variances.append(np.mean(inv_sqs))

            num_lagged = 4 * int(num_times_of_day / 30)
            rolling_mean_variance = np.mean(population_variances[-num_lagged:])
            rolling_mean_collisions.append(np.mean(collisions[-num_lagged:]))
            rolling_variances.append(rolling_mean_variance)

            axs[0][1].clear()
            axs[0][1].plot([math.sqrt(v) for v in population_variances], 'x')
            axs[0][1].plot([math.sqrt(v) for v in rolling_variances])
            axs[0][1].plot(list(range(len(rolling_variances))),
                           [R] * len(rolling_variances), '--')
            axs[0][1].legend(
                ['Current time step', 'Avg last (' + str(num_lagged) + ')'],
                loc='lower right')
            axs[0][1].set_title('Mean inverse squared distance)')
            axs[0][1].figure

            axs[1][1].plot(collisions, '+')
            axs[1][1].plot(rolling_mean_collisions, '--')
            axs[1][1].set_title('Collisions')
            axs[1][1].legend(
                ['Current time step', 'Avg last (' + str(num_lagged) + ')'],
                loc='upper left')
            axs[1][1].figure

            if day > 0:
                rmc = rolling_mean_collisions[num_times_of_day:]
                pv = population_variances[num_times_of_day:]
                axs[1][0].clear()
                axs[1][0].loglog(pv, rmc, '+')
                axs[1][0].set_xlabel('Mean inverse squared distance)')
                axs[1][0].set_ylabel('Mean collisions')
                b, m = polyfit(pv, rmc, 1)
                axs[1][0].plot(pv, [b + m * pv_ for pv_ in pv], '-')
                axs[1][0].set_title('Slope is ' + str(m))
                axs[1][0].figure

            if step_no % 2 == 0:
                plt.show(block=False)
                plt.pause(0.5)
                if step_no == 1 and day == 0:
                    plt.pause(5)
예제 #8
0
def commute(params):
    """ To illustrate the OU process with commuting  """

    num, num_initially_infected = int(params['geometry']['n']), int(
        params['geometry']['i'])
    assert num % 2 == 0

    HOME_1 = (-1.5, 1.5)
    HOME_2 = (-1.5, -1.5)
    WORK = (1.5, 0)
    home = [HOME_1] * int(num / 2) + [HOME_2] * int(num / 2)
    work = [WORK] * num

    def is_working(time_of_day):
        return time_of_day > 0.4 and time_of_day < 0.6

    def is_home(time_of_day):
        return time_of_day < 0.0 or time_of_day > 0.75

    num, num_initially_infected = int(params['geometry']['n']), int(
        params['geometry']['i'])
    num_times_of_day = int(params['motion']['t'])
    day_fraction = 1.0 / num_times_of_day
    w = params['motion']['w']
    k = params['motion']['k']
    R = w / math.sqrt(2 * k)
    b = params['geometry']['b']
    positions = [(x / 2 * b, y / 2 * b) for x, y in [
        tuple(np.random.multivariate_normal(mean=[0, 0], cov=[[1, 0], [0, 1]]))
        for _ in range(num)
    ]]
    status = [VULNERABLE] * num

    fig, axs = plt.subplots(nrows=1, ncols=2)

    population_variances = list()
    rolling_variances = list()

    for day in range(10):
        for step_no, time_of_day in enumerate(times_of_day(num_times_of_day)):
            stationary = [s in [DECEASED, POSITIVE] for s in status]
            attractors = [w for w in work
                          ] if time_of_day < 0.5 else [h for h in home]
            positions = evolve_positions(positions=positions,
                                         motion_params=params['motion'],
                                         attractors=attractors,
                                         day_fraction=day_fraction,
                                         stationary=stationary)

            axs[0].clear()
            plot_points(plt=axs[0],
                        positions=positions,
                        status=status,
                        sizes=[64] * 6)
            b = params['geometry']['b']
            axs[0].axis([-b, b, -b, b])
            axs[0].set_title('Day ' + str(day) + ' ' + str(time_of_day))

            for offsets in [HOME_1, HOME_2, WORK]:
                circle_x, circle_y = circle(r=R, offset=offsets)
                axs[0].scatter(x=circle_x, y=circle_y, c='g', s=1)

            axs[0].figure

            if is_home(time_of_day):
                population_variance = np.mean(
                    [sq_dist(pos, hm) for pos, hm in zip(positions, home)])

                population_variances.append(population_variance)

                num_lagged = 5 + int(0.25 * len(rolling_variances))
                rolling_mean_variance = np.mean(
                    population_variances[-num_lagged:])
                rolling_variances.append(rolling_mean_variance)

                axs[1].clear()
                axs[1].plot([math.sqrt(v) for v in population_variances], '+')
                axs[1].plot([math.sqrt(v) for v in rolling_variances])
                axs[1].plot(list(range(len(rolling_variances))),
                            [R] * len(rolling_variances), '--')
                axs[1].axis([
                    0,
                    len(rolling_variances), 0.75 * R,
                    1.5 * max(rolling_variances[-1], R)
                ])
                axs[1].legend([
                    'Current', 'Avg last (' + str(num_lagged) + ')',
                    'Theoretical'
                ],
                              loc='upper left')
                axs[1].set_title('RMS Distance to home after 6pm')
                axs[1].figure

            plt.show(block=False)
            plt.pause(0.01)
            if step_no == 1 and day == 0:
                plt.pause(20)