Custom variables¶
In the last example we got metawards
to model a lockdown. However,
we put a lot of hard-coded parameters into iterate_lockdown
function
we wrote. One of the main purposes of metawards
is to enable us
to scan through multiple variables to see their affect on the
population trajectories.
User variables¶
metawards
supports the use of any custom user variables. For example,
create a new file called custom.inp
and copy in the below;
# first state
user.scale[0] = 0.2
user.flag[0] = False
# second state
user.scale[1] = 0.5
user.flag[1] = True
# third state
user.scale[2] = 0.7
user.flag[2] = True
Note
Comments start with a ‘#’. The file format is very flexible. You can use an ‘=’ sign or a ‘:’ or even nothing, e.g. “user.scale[1] 0.5”. You can abbreviate “user.variable” to “.variable” too if you want.
This file is going to be used to define three states. The first (at index 0)
has a scale factor of 0.2, and a flag set to False
. The second has
a scale factor of 0.5 and a flag set to True
. The third has a
scale factor of 0.7 and a flag set also to True
.
We can pass this input file into metawards
using the --user-variables
(or -u
) parameter, e.g. try typing;
metawards -d lurgy3 --user-variables custom.inp
In the output you should see a line that reads;
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Custom parameters and seeds ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Adjusting variables to (.scale[0]=0.2, .flag[0]=False, .scale[1]=0.5, .flag[1]=True,
.scale[2]=0.7, .flag[2]=True)[repeat 1]
Note
See how “user.variable” has been abbreviated to “.variable” in this output
This shows that metawards
has read your custom parameters into the
program. They are stored as user_params
in a
Parameters
object that is stored in the
Network
that holds the network of wards being modelled.
Reading user variables in custom iterators¶
You can access these parameters in an iterator or advance function using
network.params.user_params[X]
when X
is the name of the parameter
you want. For example, network.params.user_params["scale[0]"] returns
``0.2
. For example, copy the below into a file called custom.py
;
from metawards.utils import Console
def get_state(population):
if population.day < 2:
return 0
elif population.day < 4:
return 1
else:
return 2
def advance_lockdown(network, population, **kwargs):
params = network.params
state = get_state(population)
scale = params.user_params["scale"][state]
Console.debug("Hello advance_lockdown", variables=[scale])
def advance_relaxed(network, population, **kwargs):
params = network.params
state = get_state(population)
scale = params.user_params["scale"][state]
Console.debug("Hello advance_relaxed", variables=[scale])
def iterate_custom(network, population, **kwargs):
params = network.params
state = get_state(population)
flag = params.user_params["flag"][state]
Console.debug("Hello iterate_custom", variables=[scale, flag])
if flag:
return [advance_lockdown]
else:
return [advance_relaxed]
This code defines four functions:
get_state
- this returns the state that the population should be set to. In this case, the state is 0, 1 or 2 depending on the day of the outbreak.iterate_custom
- this gets the state usingget_state
. It then looks up theflag
custom parameter at indexstate
. If the flag is True, then it returnsadvance_lockdown
. Otherwise it returnsadvance_relaxed
.advance_lockdown
- this gets the state usingget_state
. It then looks up thescale
custom parameter at indexstate
. It prints this to the screen.advance_relaxed
- this does the same asadvance_lockdown
, but prints a different message to the screen.
Use this iterator by running metawards
via;
metawards -d lurgy3 -u custom.inp --iterator custom --debug
You should now see printed to the screen something very similar to the below;
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Day 0 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[15:56:50] Hello iterate_custom custom.py:31
Name │ Value
═══════╪═══════
state │ 0
flag │ False
Hello advance_relaxed custom.py:24
Name │ Value
═══════╪═══════
scale │ 0.2
S: 56082077 E: 0 I: 0 R: 0 IW: 0 POPULATION: 56082077
Number of infections: 0
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Day 1 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Hello iterate_custom custom.py:31
Name │ Value
═══════╪═══════
state │ 0
flag │ False
Hello advance_relaxed custom.py:24
Name │ Value
═══════╪═══════
scale │ 0.2
S: 56082077 E: 0 I: 0 R: 0 IW: 0 POPULATION: 56082077
Number of infections: 0
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Day 2 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Hello iterate_custom custom.py:31
Name │ Value
═══════╪═══════
state │ 1
flag │ True
Hello advance_lockdown custom.py:17
Name │ Value
═══════╪═══════
scale │ 0.5
S: 56082077 E: 0 I: 0 R: 0 IW: 0 POPULATION: 56082077
Number of infections: 0
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Day 3 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Hello iterate_custom custom.py:31
Name │ Value
═══════╪═══════
state │ 1
flag │ True
Hello advance_lockdown custom.py:17
Name │ Value
═══════╪═══════
scale │ 0.5
S: 56082077 E: 0 I: 0 R: 0 IW: 0 POPULATION: 56082077
Number of infections: 0
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Day 4 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Hello iterate_custom custom.py:31
Name │ Value
═══════╪═══════
state │ 2
flag │ True
[15:56:51] Hello advance_lockdown custom.py:17
Name │ Value
═══════╪═══════
scale │ 0.7
S: 56082077 E: 0 I: 0 R: 0 IW: 0 POPULATION: 56082077
Number of infections: 0
Infection died ... Ending on day 5
Hopefully the change between state, functions called and values of the scale factor printed makes sense and follows what you expected.
Scanning custom variables¶
You can also adjust your custom variables by scanning in the same way that we adjusted in-built variables like beta and progress in an earlier part of this tutorial.
In this case, we use the full (user.variable
) or abbreviated
(.variable
) names as titles in the metawards
input file.
For example, create a new file called scan.csv
and copy in the below;
.scale[0] .flag[0]
0.1 False
0.2 False
0.3 False
0.1 True
0.2 True
0.3 True
This tells metawards
to perform six model runs, with user.scale[0]
varied from 0.1-0.3, and user.flag[0]
varied from “True” to “False”.
Perform these model runs using;
metawards -d lurgy3 -u custom.inp --iterator custom -i scan.csv
You should get output that is very similar to this;
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ MULTIPROCESSING ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Computing model run ✔
┌────────────────────────────────────────────────────────────────────────────────────────┐
│ │
│ Completed job 1 of 6 │
│ (.scale[0]=0.1, .flag[0]=False)[repeat 1] │
│ 2020-05-25: DAY: 5 S: 56082077 E: 0 I: 0 R: 0 IW: 0 UV: 1.0 TOTAL │
│ POPULATION 56082077 │
│ │
└────────────────────────────────────────────────────────────────────────────────────────┘
Computing model run ✔
┌────────────────────────────────────────────────────────────────────────────────────────┐
│ │
│ Completed job 2 of 6 │
│ (.scale[0]=0.2, .flag[0]=False)[repeat 1] │
│ 2020-05-25: DAY: 5 S: 56082077 E: 0 I: 0 R: 0 IW: 0 UV: 1.0 TOTAL │
│ POPULATION 56082077 │
│ │
└────────────────────────────────────────────────────────────────────────────────────────┘
Computing model run ✔
┌────────────────────────────────────────────────────────────────────────────────────────┐
│ │
│ Completed job 3 of 6 │
│ (.scale[0]=0.3, .flag[0]=False)[repeat 1] │
│ 2020-05-25: DAY: 5 S: 56082077 E: 0 I: 0 R: 0 IW: 0 UV: 1.0 TOTAL │
│ POPULATION 56082077 │
│ │
└────────────────────────────────────────────────────────────────────────────────────────┘
Computing model run ✔
┌────────────────────────────────────────────────────────────────────────────────────────┐
│ │
│ Completed job 4 of 6 │
│ (.scale[0]=0.1, .flag[0]=True)[repeat 1] │
│ 2020-05-25: DAY: 5 S: 56082077 E: 0 I: 0 R: 0 IW: 0 UV: 1.0 TOTAL │
│ POPULATION 56082077 │
│ │
└────────────────────────────────────────────────────────────────────────────────────────┘
Computing model run ✔
┌────────────────────────────────────────────────────────────────────────────────────────┐
│ │
│ Completed job 5 of 6 │
│ (.scale[0]=0.2, .flag[0]=True)[repeat 1] │
│ 2020-05-25: DAY: 5 S: 56082077 E: 0 I: 0 R: 0 IW: 0 UV: 1.0 TOTAL │
│ POPULATION 56082077 │
│ │
└────────────────────────────────────────────────────────────────────────────────────────┘
Computing model run ✔
┌────────────────────────────────────────────────────────────────────────────────────────┐
│ │
│ Completed job 6 of 6 │
│ (.scale[0]=0.3, .flag[0]=True)[repeat 1] │
│ 2020-05-25: DAY: 5 S: 56082077 E: 0 I: 0 R: 0 IW: 0 UV: 1.0 TOTAL │
│ POPULATION 56082077 │
│ │
└────────────────────────────────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────────────────────────────────┐
│ │
│ Writing a summary of all results into the csv file │
│ /Users/chris/GitHub/tutorial/weekend/output/results.csv.bz2. You can use this to │
│ quickly look at statistics across all runs using e.g. R or pandas │
│ │
└────────────────────────────────────────────────────────────────────────────────────────┘
A quick look in the output/results.csv.bz2
file, e.g. using pandas,
shows that the fingerprint and columns for custom variables are
constructed identially to in-built variables, e.g.
>>> import pandas as pd
>>> df = pd.read_csv("output/results.csv.bz2")
>>> print(df)
ingerprint repeat .scale[0] .flag[0] day date S E I R IW UV
0 0i1vF 1 0.1 False 0 2020-05-20 56082077 0 0 0 0 1.0
1 0i1vF 1 0.1 False 1 2020-05-21 56082077 0 0 0 0 1.0
2 0i1vF 1 0.1 False 2 2020-05-22 56082077 0 0 0 0 1.0
3 0i1vF 1 0.1 False 3 2020-05-23 56082077 0 0 0 0 1.0
4 0i1vF 1 0.1 False 4 2020-05-24 56082077 0 0 0 0 1.0
5 0i1vF 1 0.1 False 5 2020-05-25 56082077 0 0 0 0 1.0
6 0i2vF 1 0.2 False 0 2020-05-20 56082077 0 0 0 0 1.0
7 0i2vF 1 0.2 False 1 2020-05-21 56082077 0 0 0 0 1.0
8 0i2vF 1 0.2 False 2 2020-05-22 56082077 0 0 0 0 1.0
9 0i2vF 1 0.2 False 3 2020-05-23 56082077 0 0 0 0 1.0
10 0i2vF 1 0.2 False 4 2020-05-24 56082077 0 0 0 0 1.0
11 0i2vF 1 0.2 False 5 2020-05-25 56082077 0 0 0 0 1.0
12 0i3vF 1 0.3 False 0 2020-05-20 56082077 0 0 0 0 1.0
13 0i3vF 1 0.3 False 1 2020-05-21 56082077 0 0 0 0 1.0
14 0i3vF 1 0.3 False 2 2020-05-22 56082077 0 0 0 0 1.0
15 0i3vF 1 0.3 False 3 2020-05-23 56082077 0 0 0 0 1.0
16 0i3vF 1 0.3 False 4 2020-05-24 56082077 0 0 0 0 1.0
17 0i3vF 1 0.3 False 5 2020-05-25 56082077 0 0 0 0 1.0
18 0i1vT 1 0.1 True 0 2020-05-20 56082077 0 0 0 0 1.0
19 0i1vT 1 0.1 True 1 2020-05-21 56082077 0 0 0 0 1.0
20 0i1vT 1 0.1 True 2 2020-05-22 56082077 0 0 0 0 1.0
21 0i1vT 1 0.1 True 3 2020-05-23 56082077 0 0 0 0 1.0
22 0i1vT 1 0.1 True 4 2020-05-24 56082077 0 0 0 0 1.0
23 0i1vT 1 0.1 True 5 2020-05-25 56082077 0 0 0 0 1.0
24 0i2vT 1 0.2 True 0 2020-05-20 56082077 0 0 0 0 1.0
25 0i2vT 1 0.2 True 1 2020-05-21 56082077 0 0 0 0 1.0
26 0i2vT 1 0.2 True 2 2020-05-22 56082077 0 0 0 0 1.0
27 0i2vT 1 0.2 True 3 2020-05-23 56082077 0 0 0 0 1.0
28 0i2vT 1 0.2 True 4 2020-05-24 56082077 0 0 0 0 1.0
29 0i2vT 1 0.2 True 5 2020-05-25 56082077 0 0 0 0 1.0
30 0i3vT 1 0.3 True 0 2020-05-20 56082077 0 0 0 0 1.0
31 0i3vT 1 0.3 True 1 2020-05-21 56082077 0 0 0 0 1.0
32 0i3vT 1 0.3 True 2 2020-05-22 56082077 0 0 0 0 1.0
33 0i3vT 1 0.3 True 3 2020-05-23 56082077 0 0 0 0 1.0
34 0i3vT 1 0.3 True 4 2020-05-24 56082077 0 0 0 0 1.0
35 0i3vT 1 0.3 True 5 2020-05-25 56082077 0 0 0 0 1.0