internals.dimensions
Dimensions: how a model is divided into groups by the properties of people (age, sex, place, …)
A stratification is declared once and read by every module and solver, as levels held by each agent or as groups of compartments.
Used with: agents and compartments; declared and coded modules
Classes
| Name | Description |
|---|---|
| Groups | The groups of a sim: its stratifications (ss.dimensions.Strat), and how their levels combine into groups |
| Strat | One stratification: a property of people, and the levels it is split into |
| Transfer | Movement between the levels of a stratification, without a change of disease state: see ss.transfer(), which makes it |
| levels | The levels of a stratification, with the options that are needed less often; for stratify() |
Groups
internals.dimensions.Groups(sim)The groups of a sim: its stratifications (ss.dimensions.Strat), and how their levels combine into groups
In a compartmental run, each group is a row of every compartment; as agents, each agent is in one group, which is worked out from their properties when needed (see group_raw()). Made when the sim is initialized, as sim.groups.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| sim | ss.Sim |
the sim | required |
Methods
| Name | Description |
|---|---|
| check_used | That a sim with only modules written as code, once they are initialized, uses each stratification it is given: in a module’s values, or in results it keeps by group (ss.Result(..., groups=True)) |
| count | As agents: the number of people alive in each group for whom a condition holds, in one pass (each agent counted by its weight, people.scale, if they differ; not scaled by the population) |
| dim_index | The position of a stratification dimension |
| draw_joint | In an agent-based run: the levels of a split over several dimensions at once, together, for some agents, given their age group if age is one of them |
| fold | Move values for each group (e.g. a split) to the groups their people are counted in: see init_ragged() |
| fold_matrix | The same, for a matrix from each group (rows) to each group (columns) |
| folded | The groups that agents are counted in: see init_ragged() |
| grid_index | Index a grid of values over some dimensions (by position) by group: returns the grid and the index, so grid[index] is the value for each group |
| group_raw | In an agent-based run: the group of every agent, as an array indexed by UID |
| group_vals | A value for each level of a dimension (by position), as a value for each group; a group with no level of it gets outside |
| groups_changed | Say that the level of some agents in a dimension has changed (or of any agent, if uids is None), so their groups are worked out again |
| init | Collect the stratifications of the sim and its modules, and work out the groups they give |
| init_ragged | For a dimension with who= (e.g. age groups for women only): which groups have a level of it |
| init_vals | In an agent-based run: assign each agent a level of every property they do not already have |
| level | In an agent-based run: the level of every agent in one dimension, as an array indexed by UID, with -1 for people outside its who=, or outside the states it applies to (e.g. for a strain, people who are not infected) |
| level_raw | In an agent-based run: the level of every agent in one dimension (by its position), as an array indexed by UID; people outside the dimension’s who= have a level too, which counts nothing (see level()) |
| moved_by | For describe(): what moves people along a dimension, e.g. ‘; counter: +1 by delivery; +2 by twins’ |
| outside_states | In an agent-based run: whether each agent is outside the states a dimension applies to (states=, e.g. the states of an infection, for a strain), by UID, who have no level of it; None if it applies in every state |
| place_new | In an agent-based run: the levels of agents added by a module written as code (e.g. ss.Births), drawn from each dimension’s split, as the declared births draw them (see ss.solvers.Agents.add_people()) |
| regrouped | Some agents’ groups have changed by themselves (e.g. they reached the next age group): the agent engines move them between the counts they keep by group (see ss.solvers.Agents.moved_groups()) |
| set_sex | In an agent-based run with a dimension called sex: its level for some agents from people.female (or, if from_level, the other way round) |
check_used
internals.dimensions.Groups.check_used()That a sim with only modules written as code, once they are initialized, uses each stratification it is given: in a module’s values, or in results it keeps by group (ss.Result(..., groups=True))
count
internals.dimensions.Groups.count(where=None)As agents: the number of people alive in each group for whom a condition holds, in one pass (each agent counted by its weight, people.scale, if they differ; not scaled by the population)
For a module written as code that keeps its results by group (ss.Result(..., groups=True); see ss.Result.set_groups()).
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| where | BoolArr / uids / array |
who to count: a boolean array of people (e.g. sis.infected, or one by UID), or some UIDs (default: everyone alive) |
None |
Examples
sim.stratify(sex=['female', 'male'], age=[0, 15, 25, 50])
infected = sim.groups.count(sim.diseases.sis.infected) # One number for each of the 8 groupsdim_index
internals.dimensions.Groups.dim_index(name)The position of a stratification dimension
draw_joint
internals.dimensions.Groups.draw_joint(uids)In an agent-based run: the levels of a split over several dimensions at once, together, for some agents, given their age group if age is one of them
fold
internals.dimensions.Groups.fold(vals)Move values for each group (e.g. a split) to the groups their people are counted in: see init_ragged()
fold_matrix
internals.dimensions.Groups.fold_matrix(matrix)The same, for a matrix from each group (rows) to each group (columns)
folded
internals.dimensions.Groups.folded(groups)The groups that agents are counted in: see init_ragged()
grid_index
internals.dimensions.Groups.grid_index(ds, grid, count=False)Index a grid of values over some dimensions (by position) by group: returns the grid and the index, so grid[index] is the value for each group
A group with no level of a dimension (outside its who=) takes the mean over its levels, weighted by the split; or, for a number of people at each level, none.
group_raw
internals.dimensions.Groups.group_raw()In an agent-based run: the group of every agent, as an array indexed by UID
It is kept until groups_changed() says it has changed, and then only the groups of the agents named are worked out again. A dimension binned from a property that changes on its own, such as age, is checked again on every step.
group_vals
internals.dimensions.Groups.group_vals(d, vals, outside=1.0)A value for each level of a dimension (by position), as a value for each group; a group with no level of it gets outside
groups_changed
internals.dimensions.Groups.groups_changed(uids=None)Say that the level of some agents in a dimension has changed (or of any agent, if uids is None), so their groups are worked out again
Code that changes a property of people that a dimension is made from (e.g. people.patch) calls this; see group_raw().
init
internals.dimensions.Groups.init()Collect the stratifications of the sim and its modules, and work out the groups they give
init_ragged
internals.dimensions.Groups.init_ragged()For a dimension with who= (e.g. age groups for women only): which groups have a level of it
The groups stay a grid, with a level of every dimension. People in a group outside a dimension’s who= have no level of it, so they are all counted at its first level (the “fold” of their group), as people in a state that a dimension does not apply to are; the groups at its other levels stay empty.
init_vals
internals.dimensions.Groups.init_vals()In an agent-based run: assign each agent a level of every property they do not already have
level
internals.dimensions.Groups.level(dim)In an agent-based run: the level of every agent in one dimension, as an array indexed by UID, with -1 for people outside its who=, or outside the states it applies to (e.g. for a strain, people who are not infected)
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| dim | str / int |
the dimension, by name or position | required |
Example
sim.groups.level('risk') # 0, 1, 2 for each risk group; -1 for people the risk groups don't apply to
sim.groups.level('resistance') # The set of strains each person carries; -1 for people outside the states of the infectionlevel_raw
internals.dimensions.Groups.level_raw(d)In an agent-based run: the level of every agent in one dimension (by its position), as an array indexed by UID; people outside the dimension’s who= have a level too, which counts nothing (see level())
moved_by
internals.dimensions.Groups.moved_by(strat)For describe(): what moves people along a dimension, e.g. ‘; counter: +1 by delivery; +2 by twins’
outside_states
internals.dimensions.Groups.outside_states(d)In an agent-based run: whether each agent is outside the states a dimension applies to (states=, e.g. the states of an infection, for a strain), by UID, who have no level of it; None if it applies in every state
place_new
internals.dimensions.Groups.place_new(uids)In an agent-based run: the levels of agents added by a module written as code (e.g. ss.Births), drawn from each dimension’s split, as the declared births draw them (see ss.solvers.Agents.add_people())
A newborn with a parent (people.parent) is in the parent’s place (a dimension of kind “space”), and a split over age and other dimensions is drawn from the newborn’s age group.
regrouped
internals.dimensions.Groups.regrouped(uids, before, after)Some agents’ groups have changed by themselves (e.g. they reached the next age group): the agent engines move them between the counts they keep by group (see ss.solvers.Agents.moved_groups())
set_sex
internals.dimensions.Groups.set_sex(uids, from_level=False)In an agent-based run with a dimension called sex: its level for some agents from people.female (or, if from_level, the other way round)
Strat
internals.dimensions.Strat(
name,
levels,
fractions=None,
adjust=None,
kind=None,
states=None,
who=None,
mobility=None,
)One stratification: a property of people, and the levels it is split into
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| name | str |
the dimension, e.g. ‘age’ | required |
| levels | list / dict |
bin edges (for a continuous property such as age) or labels; or a dict of the fraction of the population in each, e.g. {0: 0.3, 15: 0.6, 65: 0.1} |
required |
| fractions | list |
the fraction of the population in each level (if not given: from an ss.geo.geography’s populations; for age groups, the world’s ages; for a boolean dimension, everyone at the first level; otherwise equal) |
None |
| adjust | dict |
multipliers on named transitions, one per level: on its rate (a duration is divided), or on its probability for a branch chosen with p= | None |
| kind | str |
‘age’, ‘space’, or ‘plain’; if not given, ‘space’ for an ss.geo.geography or with mobility=, ‘age’ for a dimension called age, and otherwise ‘plain’ (a strain dimension, kind ‘strain’, is made by ss.Strains: see strains) |
None |
| states | list |
the names of the states it applies to (default: every state that is people) | None |
| who | Cond / dict |
the groups it applies to: a condition on other dimensions, e.g. ss.person.female or ss.person.age >= 15 (see ss.levels()), or a dict of a dimension and the positions or labels of its levels; people in other groups have no level of it (default: every group) |
None |
| mobility | gravity / radiation / Mobility / register / array |
for a spatial stratification, the movement between its levels | None |
Attributes
| Name | Description |
|---|---|
| attr | The name of the property of people that holds each agent’s level; a dimension with labels that is named like something people already have (age) is kept apart from it |
| mids | The middle of each bin, for a binned property |
Methods
| Name | Description |
|---|---|
| add | As agents: the values of a counter after it goes up by k: a value past the last edge stays in the last level, and none goes below the first |
| draw | A level for each of some agents, from uniform random numbers: in proportion to the split, or to its row for each agent’s levels of the other dimensions |
| first | A split with everyone at the first level |
| fracs | The fraction of each group in its level of this dimension (or in levels, if given): from the split, or, for a split given the levels of other dimensions, from the row of that split for the group |
| index | The position of a level, given by position or by label |
| init_carriage | For a strain dimension whose levels are sets of strains carried at once (‘A+B’, from ss.Strains(max_strains=)): which strains each level carries, and where carrying one more leads |
| move_level | A level that people are moved to, as given in move=: its position |
| moved | As agents: the values of people moved along this dimension: to a level (its position), up a counter (('+', k)), or from each level to another (('map', levels), a change of strains) |
| people_arr | The property of people that holds each agent’s level, when they do not have it already: for a dimension with labels, the level itself, as 16-bit integers (so with one dimension it is also the group: see Groups.group_raw()); for a binned one, floats |
| same_as | Whether another stratification is this one given again: the same levels, kind, split, adjustments, and states |
| shifted | For a counter (increment=): the level that people at each level reach when it goes up by k (or down, for k < 0), staying in the last (open-ended) level or the first |
| target | Where people at each level go when moved along this dimension: as moved(), a level for each level |
| value | The value people hold for a level, given its position: the level’s lower edge for a numeric dimension (people hold values, which are binned into levels), the position itself otherwise |
| worth | The value of the property for each level, as a compartmental run takes it in an expression: the lower edge for whole numbers (a counter), and otherwise the middle of the bin |
add
internals.dimensions.Strat.add(vals, k)As agents: the values of a counter after it goes up by k: a value past the last edge stays in the last level, and none goes below the first
draw
internals.dimensions.Strat.draw(sim, uids, rvs)A level for each of some agents, from uniform random numbers: in proportion to the split, or to its row for each agent’s levels of the other dimensions
first
internals.dimensions.Strat.first()A split with everyone at the first level
fracs
internals.dimensions.Strat.fracs(coords, levels=None)The fraction of each group in its level of this dimension (or in levels, if given): from the split, or, for a split given the levels of other dimensions, from the row of that split for the group
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| coords | array |
the level of each group in every dimension of the sim, by row | required |
| levels | array |
the levels of this dimension to give the fraction of (by default, each group’s own) | None |
index
internals.dimensions.Strat.index(level)The position of a level, given by position or by label
init_carriage
internals.dimensions.Strat.init_carriage(strains)For a strain dimension whose levels are sets of strains carried at once (‘A+B’, from ss.Strains(max_strains=)): which strains each level carries, and where carrying one more leads
The first levels are the strains alone. Someone who carries several strains passes on one of them (see ss.Strains(transmit=)), and someone infected with a strain they do not carry moves to the level that adds it (once full, the level that replaces the oldest: see ss.Strains._adds()).
move_level
internals.dimensions.Strat.move_level(level)A level that people are moved to, as given in move=: its position
moved
internals.dimensions.Strat.moved(vals, level)As agents: the values of people moved along this dimension: to a level (its position), up a counter (('+', k)), or from each level to another (('map', levels), a change of strains)
people_arr
internals.dimensions.Strat.people_arr()The property of people that holds each agent’s level, when they do not have it already: for a dimension with labels, the level itself, as 16-bit integers (so with one dimension it is also the group: see Groups.group_raw()); for a binned one, floats
same_as
internals.dimensions.Strat.same_as(other)Whether another stratification is this one given again: the same levels, kind, split, adjustments, and states
shifted
internals.dimensions.Strat.shifted(k)For a counter (increment=): the level that people at each level reach when it goes up by k (or down, for k < 0), staying in the last (open-ended) level or the first
target
internals.dimensions.Strat.target(level)Where people at each level go when moved along this dimension: as moved(), a level for each level
value
internals.dimensions.Strat.value(index)The value people hold for a level, given its position: the level’s lower edge for a numeric dimension (people hold values, which are binned into levels), the position itself otherwise
worth
internals.dimensions.Strat.worth()The value of the property for each level, as a compartmental run takes it in an expression: the lower edge for whole numbers (a counter), and otherwise the middle of the bin
Transfer
internals.dimensions.Transfer(
move=None,
rate=None,
dur=None,
p=None,
states=None,
name=None,
label=None,
increment=None,
)Movement between the levels of a stratification, without a change of disease state: see ss.transfer(), which makes it
It exists so that movement such as aging or moving between risk groups is declared beside the disease, not as one transition per state.
levels
internals.dimensions.levels(
levels,
states=None,
who=None,
kind=None,
mobility=None,
fractions=None,
)The levels of a stratification, with the options that are needed less often; for stratify()
A dimension is usually given by its levels alone, e.g. sir.stratify(age={0: 0.3, 15: 0.6, 65: 0.1}, risk=['low', 'high']) (a dict gives the fraction of the population in each level; a list, levels whose fractions are guessed). ss.levels() adds the rest.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| levels | list / dict / geography |
bin edges (for a continuous property such as age) or labels, a dict of the fraction of the population in each, or an ss.geo.geography |
required |
| states | list |
the states the dimension applies to (default: every state that is people) | None |
| who | Cond |
the groups the dimension applies to, as a condition on other dimensions, e.g. ss.person.female, ss.person.age >= 15, ss.person.risk == 'high', ss.person.region.isin(['north', 'east']), or several joined with &; people in other groups have no level of it, so selecting a level of it leaves them out (default: every group) |
None |
| kind | str |
‘age’, ‘space’, or ‘plain’; if not given, from the levels: ‘space’ for an ss.geo.geography or with mobility=, ‘age’ for age=, and otherwise ‘plain’ (whatever the name); strains are strains=ss.Strains(...) on the disease |
None |
| mobility | gravity / radiation / Mobility / array |
for a place (e.g. patch=), the movement between its levels: ss.geo.gravity(), ss.geo.radiation(), ss.geo.Mobility(), or a matrix |
None |
| fractions | ss.by |
for fractions that depend on other dimensions, the fraction of people at each combination of their levels and this dimension’s, as a table over all of them, e.g. risk=ss.levels(['low', 'high'], fractions=ss.by(np.array([[0.45, 0.05], [0.2, 0.3]]), dims=['age', 'risk'])), a row for each level of age and a column for each level of risk (the fractions in each level, if they do not depend on anything else, are the levels as a dict) |
None |
Examples
sir.stratify(severity=ss.levels({'mild': 0.9, 'severe': 0.1}, states=[I]))
sir.stratify(sex=['female', 'male'], parity=ss.levels(['0', '1-2', '3+'], who=ss.person.female)) # Only women have a parity
sir.stratify(patch=ss.levels(geo, mobility=ss.geo.gravity(away=0.1)))Functions
| Name | Description |
|---|---|
| transfer | Movement between the levels of a stratification, without a change of disease state |
transfer
internals.dimensions.transfer(
move=None,
rate=None,
dur=None,
p=None,
states=None,
name=None,
label=None,
increment=None,
**kwargs,
)Movement between the levels of a stratification, without a change of disease state
People move all the time, at a rate or after a duration, and the transfer is part of the model: pass it to ss.Disease() or stratify(). A move delivered to some people, at some times, is a delivery: ss.Delivery(dict(vaccinated=True), coverage=0.7, when=2021).
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| move | dict |
the dimension, and a pair of its levels, from and to (e.g. dict(risk=('low', 'high'))), or the level people move to, from every other level (e.g. dict(vaccinated=True)), as for ss.Event(dict(...)) and ss.Transition(move=...) |
None |
| rate | any |
the per-person hazard | None |
| dur | any |
the time before moving (instead of rate): a scalar is the mean of an exponential, and a distribution is drawn for each person when they reach a level it moves them from |
None |
| p | list |
with several levels to move to (dict(method=('none', ['pill', 'iud']))), the probability of each, decided as people move; one may be None, for the rest |
None |
| states | list |
the disease states it applies to (default: every state) | None |
| name | str |
the name; if not given, taken from the keyword or variable it is assigned to | None |
| increment | str / dict |
instead of a level, a counter that goes up by one (its name), or by an amount (dict(schooling=1), dict(immunity=-1)) |
None |
Examples
ss.transfer(dict(risk=('low', 'high')), rate=ss.peryear(0.1))
ss.transfer(dict(vaccinated=True), rate=ss.peryear(0.2))
ss.transfer(increment=dict(immunity=-1), rate=ss.peryear(0.5)) # A counter, down a level at a time
ss.transfer(dict(method=('none', ['pill', 'iud'])), p=[0.6, 0.4], dur=ss.lognormal(ss.years(2), ss.years(1))) # To one of two levels, after a time drawn for each person