Giter Club home page Giter Club logo

covpol's Introduction

COVPOL: An agent-based model of the international COVID-19 policy response

This repository is for the publication

Oswald, Malleson, Suchak (2023). An agent-based model of the 2020 international policy diffusion in response to the COVID-19 pandemic with particle filter

available as preprint at https://arxiv.org/abs/2302.11277

This work has been implemented using the Python Anaconda distribution and the agent-based model package MESA in particular. It is provided with a .yml file specifying a conda environment which contains the required packages. In order to set up the environment, run the following command from the terminal/conda prompt:

conda env create -f env.yml

This will create a new conda environment titled cov-pol. The environment can then be activated using the following command:

conda activate cov-pol

To reproduce the full body of work, take the following steps:

  1. Run the script file run_base_model_and_filter_with_plotting.py in the covpol directory as follows:

    cd covpol
    python run_base_model_and_filter_with_plotting.py
    

    This reproduces a substantial amount of the above paper including Figure 2, 4 and 5. To reproduce Figure 4 exactly, the notebook has to take the parameter no_of_iterations = 100. To reproduce Figure 5 exactly, the notebeook has to take the parameter no_of_iterations = 1000.

  2. To reproduce Figure 6 in full several intermediate steps are necessary (time-expensive):

    1. Run the script file number_of_particles_experiment_MSE.py to reproduce the data points where iterations = 20.

    2. To reproduce the datapoints where iterations = 1, run the following:

      1. particle_filter_only.py and collect the data.
      2. run_base_model_only_parallelized.py and collect the data.
    3. Alternatively Figure 6 can be reproduced exactly in a time-cheap manner as it is from the script file graph_mse_number_of_particles_experiment.py.

    Best run from anaconda command prompt.

  3. To reproduce Figure 7 run the script experiment_da_window_size.py (time-expensive). Best run from anaconda command prompt.

covpol's People

Contributors

ksuchak1990 avatar yannickoswald avatar

Stargazers

 avatar  avatar

Watchers

 avatar  avatar  avatar

Forkers

nickmalleson

covpol's Issues

Building the environment failed

I couldn't build the environment because anaconda couldn't find some of the packages. But lots of these are dependencies so the precise version might not matter. One thing you could try is building an environment file that only includes the packages that you explicitly ask for, then leave anaconda to find the dependencies itself. You can do this with the --from-history flag. See:
Exporting an environment file across platforms

If you do that you'll see that the env.yml file is much shorter because it doesn't list all the dependencies, only the packages that you have explicitly installed.

(base) macbook:Covid_policy_response_abm nick$ conda env create -f env.yml 
Collecting package metadata (repodata.json): done
Solving environment: failed

ResolvePackageNotFound: 
  - libgcc-ng=11.2.0
  - click=8.1.3
  - python-slugify=6.1.2
  - libxcb=1.15
  - _openmp_mutex=5.1
  - cookiecutter=2.1.1
  - chardet=5.0.0
  - charset-normalizer=2.1.1
  - libgomp=11.2.0
  - networkx=2.8.7
  - libxkbcommon=1.0.1
  - libclang=10.0.1
  - python_abi=3.10
  - unidecode=1.3.6
  - ld_impl_linux-64=2.38
  - libstdcxx-ng=11.2.0
  - mesa=1.1.1

A collection of minor comments ...

Variable and class names

The convention in python is to have these lower case (so n in the following), but with underscores (which you do :-) )

https://github.com/eeyouol/Covid_policy_response_abm/blob/da92205d3542eac18b6a499d9cc7bfb1aadcf04f/code/run_base_model_and_filter_with_plotting.py#L54

Classes should be in camel case (each word capitalised with no underscore) which I think you do throughout

Paralelisation

You can find out how many cores the computer has with multiprocessing.cpu_count() so don't need to hard-code the number of cores (not that this matters particularly

https://github.com/eeyouol/Covid_policy_response_abm/blob/da92205d3542eac18b6a499d9cc7bfb1aadcf04f/code/run_base_model_only_parallelized.py#L66

else: pass

I gues you know that this kind of thing is unnecessary:

https://github.com/eeyouol/Covid_policy_response_abm/blob/da92205d3542eac18b6a499d9cc7bfb1aadcf04f/code/agent_class.py#L226

as it doesn't do anything. But its fine to leave it in, in some ways it may help readability.

List comprehensions

... are really useful but sometimes they might make things more complicated than they need to be. E.g. with the following I'm not sure if the list comprehension is better than the more verbose version:

https://github.com/eeyouol/Covid_policy_response_abm/blob/da92205d3542eac18b6a499d9cc7bfb1aadcf04f/code/agent_class.py#L210

Original:

           total_differences_array = np.sort(np.array(
               [  1/3 * abs(y1 - x.income) / range_income 
                + 1/3 * abs(y2 - x.politicalregime) / range_politicalregime
                + 1/3 * (geo_distance(y3_1, x.latitude,
                                      y3_2, x.longitude) / max_distance_on_earth)
                 for x in self.model.schedule.agents if x.state == 1]
                  )
               )

Without list comprehension: (which, by the way, I got ChatGTP to write for me :-) , but I think it's right .. )

total_differences_array = []
for x in self.model.schedule.agents:
    if x.state == 1:
        total_differences =  1/3 * abs(y1 - x.income) / range_income + 1/3 * abs(y2 - x.politicalregime) / range_politicalregime + 1/3 * (geo_distance(y3_1, x.latitude, y3_2, x.longitude) / max_distance_on_earth)
        total_differences_array.append(total_differences)
total_differences_array = np.sort(np.array(total_differences_array))

File paths only work on Yannick's laptop

File paths point to a specific location on Yannick's laptop. E.g os.chdir("C:/Users/earyo/Dropbox/Arbeit/postdoc_leeds/ABM_python_first_steps/implement_own_covid_policy_model"). This means that other people wont be able to run the code. You should use relative paths.

In a notebook this is quite straightforward as I think the notebook directory is always set to be the place where the notebook is stored. E.g. if I open run_base_model_and_filter_with_plotting_jupyter.ipynb and do %pwd (it's a notebook command that says show me the _p_resent _w_orking _d_irectory) then I get /Users/nick/gp/Covid_policy_response_abm, which is the directory on my machine where the notebook is stored. So any other files can be referenced from that directory.

This means that lines like this:

with open('C:/Users/earyo/Dropbox/Arbeit/postdoc_leeds/ABM_python_first_steps/implement_own_covid_policy_model/data/correlation_between_policies_and_metrics.csv') as f:

can be replaced with simply:

with open('./data/correlation_between_policies_and_metrics.csv') as f:

(the . is unnecessary but I like it because it says explicitly that the directory to start from is the current directory)

Sometimes it is slightly trickier with code and packages, but we can come on to that if it's a problem...

Change `./code/` to `./src/`

When I try to run the jupyter notebook with the update environment, I'm getting some errors that mean that the notebook cannot connect to the kernel. This looks like it arises from the python scripts being in a directory called code which apparently causes some conflicts somewhere. I've tried changing the directory name on my machine and the notebook can now connect to the kernel.

Can we change the name of this directory to something like src?

Comments on Yannick's code

Hi Yannick,

Here are some comments on your code. It's all minor stuff, very impressive how much the code has come on.

I'm not sure if using a github issue is the best way to do this, but at least it makes it easy to reference the source directly.

First general comment: now that you're using gitub you don't need to save different file version (model1.py, model2.py, etc.). Every time you commits, github saves the old and new versions of the files, so you can go back to old file versions if you need to. You can also 'tag' the code to label it and make it easy to find a old version )

You should add a .gitignore file to your repository so that it contains the things you need to run the code (mainly source and documentation), but no temporary files that are created when you run it. Here's an example of one I have used: https://github.com/Urban-Analytics/dust/blob/main/.gitignore You should ignore things that are specific to your local installation, like temporary python compiled files (e.g. __pycache__ directory https://github.com/eeyouol/Covid_policy_response_abm/tree/master/__pycache__ ) and possibily your spyder project stuff (https://github.com/eeyouol/Covid_policy_response_abm/tree/master/.spyproject/config) (although maybe google 'sypder project files github' to see what should and shouldn't be included in a repository). These don't need to be in the repo because when someone runs the code they will be created automatically.

Some specific comments:

`ClassMethod`

In the agent_class.reset() function:

https://github.com/eeyouol/Covid_policy_response_abm/blob/da92205d3542eac18b6a499d9cc7bfb1aadcf04f/code/agent_class.py#L269

you should explicitly tell python that it is a class method, not an object method.

Currently it is:

    def reset(cls):
        CountryAgent.instances = []

But I think it should be:

    @clasmethod
    def reset(cls):
        cls.instances = []

The beaviour is the same for both functions, but for the first one you need an agent object to access it (e.g. agent.reset()) whereas with the other you can call it without access to a particular agent object (e.g. CountryAgent.reset()).

Use random seed for reproducibility

Would it be worth us setting a random seed at the top of the script for producing figures so that every time someone runs the script they get reproducible results?

Submission

I will submit today or latest by Monday.

I think the replication should work now (or soon at least with minor changes). I reproduced everything many times now and tested all scripts many times now so that should be fine :).

thanks for all your help with this paper. I learned so much about coding, version control and collaborative development. Looking forward to the next one. @ksuchak1990 @nickmalleson

Great readme!

This isn't an issue as such, but I thought it worth pointing out where I thought things are imporessive. Otherwise you only get my suggestions for changes, not the more positive comments :-)

Code at the beginning of class source files

In https://github.com/eeyouol/Covid_policy_response_abm/blob/master/code/agent_class.py there is a load of code at the beginning of the script that reads data and sets some variables. @ksuchak1990 may know more about this, but I think it may be bad practice because it means whenever this script is accessed by pythom, then that code will be run, even if you don't want it to. E.g. just putting import agent_class will cause all the code to be run but you might not actually want that (maybe you want to use another function in agent_class and don't care about loading data first). Or if you start a parallel process it may re-read that file and run the code in each of the child processes (we came across something similar before).

Instead, you could put that code into the CountryAgent class, so that it is only run the first time an object of tyle CountryAgent is created. (I think). Or you could put it into a specific function in CountryAgent and call it directly. Lets discuss

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.