CovidGridContagion
To show how the Melodie.Grid
module can be used,
we provide this CovidGridContagion model,
which is based the CovidContagion model.
So, if you haven’t, we will strongly suggest to read the Tutorial section first.
The differences are:
Agents walk on a 2D
grid
randomly.The
grid
is constructed with spots. Eachspot
has an attributestay_prob
, which decides if the agent standing on this spot will move probabilistically.The infected agents can pass the virus to the other uninfected agents in the neighborhood.
Project Structure
The project structure is as below.
Compared with the structure of the CovidContagion model,
one grid.py
file is added in the source
folder,
and one Parameter_GridStayProb.xlsx
file is added in the data/input
folder.
CovidGridContagion
├── data
│ ├── input
│ │ ├── SimulatorScenarios.xlsx
│ │ ├── ID_HealthState.xlsx
│ │ ├── ID_AgeGroup.xlsx
│ │ ├── Parameter_GridStayProb.xlsx
│ │ └── Parameter_AgeGroup_TransitionProb.xlsx
│ └── output
│ ├── CovidGridContagion.sqlite
│ ├── PopulationInfection_S0R0.png
│ └── PopulationInfection_S1R0.png
├── source
│ ├── agent.py
│ ├── environment.py
│ ├── grid.py
│ ├── data_collector.py
│ ├── data_info.py
│ ├── data_loader.py
│ ├── scenario.py
│ ├── model.py
│ └── analyzer.py
├── config.py
├── run_simulator.py
├── run_analyzer.py
└── readme.md
Grid and Spot
To include such differences about grid
, Melodie
provides two classes Grid
and Spot
,
based on which the CovidGrid
and CovidSpot
classes are defined.
1from Melodie import Spot, Grid
2from source import data_info
3
4
5class CovidSpot(Spot):
6
7 def setup(self):
8 self.stay_prob = 0.0
9
10
11class CovidGrid(Grid):
12
13 def setup(self):
14 self.set_spot_property(
15 "stay_prob", self.scenario.get_matrix(data_info.grid_stay_prob)
16 )
As shown, the two classes are defined in brief, i.e., most functions and attributes are inherited from Melodie
.
The only reason to define this CovidGrid
class for the model, is to include the stay_prob
attribute of each CovidSpot
.
Or, one can also use the Grid
and Spot
classes of Melodie
directly.
Matrix Data
The stay_prob
values of the spots are saved in a matrix, which is the same size with the grid.
Like other dataframes, the matrix is first registered in the data_info.py
and loaded by the data_loader
,
then can be accessed by the scenario
object by using get_matrix
function (Line 15).
The registry of the matrix is as follows.
1import sqlalchemy
2
3from Melodie import MatrixInfo
4
5
6grid_stay_prob = MatrixInfo(
7 mat_name="grid_stay_prob",
8 data_type=sqlalchemy.Float(),
9 file_name="Parameter_GridStayProb.xlsx",
10)
Model
With the classes and data, the next step is to include the grid
object as a new component of the model
.
As shown in Line 24, Melodie.Model
provides a create_grid
function,
taking the two class variables as input - CovidGrid
and CovidSpot
.
1from typing import TYPE_CHECKING
2
3from Melodie import Model
4
5from source import data_info
6from source.agent import CovidAgent
7from source.data_collector import CovidDataCollector
8from source.environment import CovidEnvironment
9from source.grid import CovidGrid
10from source.grid import CovidSpot
11from source.scenario import CovidScenario
12
13if TYPE_CHECKING:
14 from Melodie import AgentList
15
16
17class CovidModel(Model):
18 scenario: "CovidScenario"
19
20 def create(self):
21 self.agents: "AgentList[CovidAgent]" = self.create_agent_list(CovidAgent)
22 self.environment = self.create_environment(CovidEnvironment)
23 self.data_collector = self.create_data_collector(CovidDataCollector)
24 self.grid = self.create_grid(CovidGrid, CovidSpot)
25
26 def setup(self):
27 self.agents.setup_agents(
28 agents_num=self.scenario.agent_num,
29 params_df=self.scenario.get_dataframe(data_info.agent_params),
30 )
31 self.grid.setup_params(
32 width=self.scenario.grid_x_size,
33 height=self.scenario.grid_y_size
34 )
35 self.grid.setup_agent_locations(self.agents)
In the setup
function, the grid
needs to be initialized with size parameters from scenario
.
Then, the agents need to be located on the grid
,
which requires that they are already initialized with the attributes x
and y
.
GridAgent
The agents that can walk on the grid are defined by inheriting the GridAgent
class of Melodie
.
They have three additional attributes: category
, x
, and y
.
Additionally, they also have access to the grid
(Line 26) and some grid-related functions,
e.g., rand_move_agent
in Line 32.
1import random
2from typing import TYPE_CHECKING
3
4from Melodie import GridAgent
5
6if TYPE_CHECKING:
7 from source.scenario import CovidScenario
8 from Melodie import AgentList
9 from source.grid import CovidSpot
10 from source.grid import CovidGrid
11
12
13class CovidAgent(GridAgent):
14 scenario: "CovidScenario"
15 grid: "CovidGrid[CovidSpot]"
16 spot: "CovidSpot"
17
18 def set_category(self):
19 self.category = 0
20
21 def setup(self):
22 self.x: int = 0
23 self.y: int = 0
24 self.health_state: int = 0
25 self.age_group: int = 0
26
27 def move(self):
28 spot: "CovidSpot" = self.grid.get_spot(self.x, self.y)
29 stay_prob = spot.stay_prob
30 if random.uniform(0, 1) > stay_prob:
31 move_radius = 1
32 self.rand_move_agent(move_radius, move_radius)
33
34 def infection(self, agents: "AgentList[CovidAgent]"):
35 neighbors = self.grid.get_neighbors(self)
36 for neighbor_category, neighbor_id in neighbors:
37 neighbor_agent: "CovidAgent" = agents.get_agent(neighbor_id)
38 if neighbor_agent.health_state == 1:
39 if random.uniform(0, 1) < self.scenario.infection_prob:
40 self.health_state = 1
41 break
One thing that might be confused: Why is there the category
attribute?
The category
attribute is to make sure that, when there are multiple groups of agents walking on the grid
,
the grid
can distinguish them and work well.
So, the function set_category
much be implemented in a class that inherits the GridAgent
class.
For example, as shown in Line 35-36, when iterating through the neighbors
returned by grid.get_neighbors
,
each neighbor is indexed with both category
and the id
of the agent.
For more details of the Grid
and Spot
modules,
please refer to the API Reference section.