loop

loop

Parent class for the integration loop.

Classes

Name Description
Loop Define the integration loop

Loop

loop.Loop(self, sim)

Define the integration loop

The Loop handles the order in which each function is called in the sim. The order is defined in Loop.collect_funcs(), which searches through the sim and collects all methods to call, in order, in the integration loop.

Each type of module is called at a different time. Within each module type, they are called in the order listed. The default loop order is:

1. sim:               start_step()     # Initialize the sim, including plotting progress
2. all modules:       start_step()     # Initialize the modules, including the random number distribution
3. sim.modules:       step()           # Run any custom modules
4. sim.demographics:  step()           # Update the demographics, including adding new agents
5. sim.diseases:      step_state()     # Update the disease states, e.g. exposed -> infected
6. sim.connectors:    step()           # Run the connectors
7. sim.networks:      step()           # Run the networks, including adding/removing edges
8. sim.interventions: step()           # Run the interventions
9. sim.diseases:      step()           # Run the diseases, including transmission
10. people:           step_die()       # Figure out who died on this timestep
11. people:           update_results() # Update basic state results
12. all modules:      update_results() # Update any results
13. sim.analyzers:    step()           # Run the analyzers
14. all modules:      finish_step()    # Do any final tidying
15. people:           finish_step()    # Clean up dead agents
16. sim:              finish_step()    # Increment the timestep

Methods

Name Description
collect_abs_tvecs Collect numerical time arrays for each module
collect_funcs Collect all the callable functions (methods) that comprise the step
init Parse the sim into the integration plan
insert Insert a function into the loop plan at the specified location.
make_plan Combine the module ordering and the time vectors into the integration plan
plot Plot a diagram of all the events
plot_cpu Plot the CPU time spent on each event; visualization of Loop.cpu_df.
plot_step_order Plot the order of the module steps across timesteps – useful for debugging
run Actually run the integration loop; usually called by sim.run()
run_one_step Take a single step, i.e. call a single function; only used for debugging purposes.
shrink Shrink the size of the loop for saving to disk
store_time Store the current time in as high resolution as possible
to_df Return a user-friendly version of the plan, omitting object columns
collect_abs_tvecs
loop.Loop.collect_abs_tvecs()

Collect numerical time arrays for each module

collect_funcs
loop.Loop.collect_funcs()

Collect all the callable functions (methods) that comprise the step

init
loop.Loop.init()

Parse the sim into the integration plan

insert
loop.Loop.insert(
    func,
    label=None,
    match_fn=None,
    before=False,
    verbose=True,
    die=True,
)

Insert a function into the loop plan at the specified location.

The loop plan is a dataframe with columns including time (e.g. date('2025-05-05')), label (e.g. 'randomnet.step'), module (’randomnet'), and function name ('step'). By default, this method will match the conditions in the plan based on the criteria specified.

This functionality is similar to an analyzer or an intervention, but gives additional flexibility since can be inserted at (almost) any point in a sim.

Note: the loop must be initialized (sim.init()) before you can call this.

Parameters
Name Type Description Default
func func the function to insert; must take a single argument, sim required
label str the label (module.name) of the function to match; see sim.loop.plan.label.unique() for choices None
match_fn func if supplied, use this function to perform the matching on the plan dataframe, returning a boolean array or list of indices of matching rows (see example below) None
before bool if true, insert the function before rather than after the match False
die bool whether to raise an exception if no matches found True

Examples:

# Simple label matching with analyzer-like functionality
def check_pop_size(sim):
    print(f'Population size is {len(sim.people)}')

sim = ss.Sim(diseases='sir', networks='random', demographics=True)
sim.init()
sim.loop.insert(check_pop_size, label='people.finish_step')
sim.run()

# Function-based matching with intervention-like functionality
def match_fn(plan):
    past_2010 = plan.time > ss.date(2010)
    is_step = (plan.label == 'sir.step') | (plan.label == 'randomnet.step')
    return past_2010 * is_step

def update_betas(sim):
    if not sim.metadata.get('updated'):
        print(f'Updating beta values on {sim.now}')
        sim.diseases.sis.beta = 0.1
        sim.networks.randomnet.edges.beta[:] = 0.5
        sim.metadata.updated = True
    return

sim = ss.Sim(diseases='sis', networks='random')
sim.init()
sim.loop.insert(update_betas, match_fn=match_fn, before=True)
sim.run()
make_plan
loop.Loop.make_plan()

Combine the module ordering and the time vectors into the integration plan

plot
loop.Loop.plot(
    simplify=False,
    max_len=100,
    fig_kw=None,
    plot_kw=None,
    scatter_kw=None,
)

Plot a diagram of all the events

Parameters
Name Type Description Default
simplify bool if True, skip update_results and finish_step events, which are automatically applied False
max_len int maximum number of entries to plot 100
fig_kw dict passed to plt.figure() None
plot_kw dict passed to plt.plot() None
scatter_kw dict passed to plt.scatter() None
plot_cpu
loop.Loop.plot_cpu(bytime=True, max_entries=10, fig_kw=None, bar_kw=None)

Plot the CPU time spent on each event; visualization of Loop.cpu_df.

Parameters
Name Type Description Default
bytime bool if True, order events by total time rather than actual order True
fig_kw dict passed to plt.figure() None
bar_kw dict passed to plt.bar() None
plot_step_order
loop.Loop.plot_step_order(
    which='default',
    max_len=500,
    plot_kw=None,
    scatter_kw=None,
    fig_kw=None,
    legend_kw=None,
)

Plot the order of the module steps across timesteps – useful for debugging when using different time units.

Note: generates a lot of data, best to debug with a small number of timesteps first!

Parameters
Name Type Description Default
which dict columns and values to filter to (default: {‘func_name’:‘step’}; if None, do not filter) 'default'
max_len int maximum number of entries to plot 500
plot_kw dict passed to plt.plot() None
scatter_kw dict passed to plt.scatter() None
fig_kw dict passed to plt.figure() None
legend_kw dict passed to plt.legend() None

Example:

sis = ss.SIS(dt=0.1)
net = ss.RandomNet(dt=0.5)
births = ss.Births(dt=1)
sim = ss.Sim(dt=0.1, dur=5, diseases=sis, networks=net, demographics=births)
sim.init()
sim.loop.plot_step_order()
run
loop.Loop.run(until=None, verbose=None)

Actually run the integration loop; usually called by sim.run()

run_one_step
loop.Loop.run_one_step()

Take a single step, i.e. call a single function; only used for debugging purposes.

Compare sim.run_one_step(), which runs a full timestep (which involves multiple function calls).

shrink
loop.Loop.shrink()

Shrink the size of the loop for saving to disk

store_time
loop.Loop.store_time()

Store the current time in as high resolution as possible

to_df
loop.Loop.to_df()

Return a user-friendly version of the plan, omitting object columns