Skip to main content

internals.dimensions

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 groups
dim_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 infection
level_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