Skip to main content

internals.timeline

internals.timeline

Timelines: the time vectors of a sim and of each of its modules

They exist so that sim.t and module.t give the current step and date, and a module can step at its own rate.

How a time is read is decided once, from the sim’s start: if it is a date or a year (a bare number from 1800 on), the sim has a calendar, and every bare number given as a time (a stop, when=, the times of ss.schedule and ss.timeseries) is a year; otherwise, a bare time is a time in the sim’s unit from 0. With no start, the stop decides, as long as the unit is years (or not given): ss.Sim(unit='day', stop=3650) runs 3,650 days from 0. A duration given as a time (when=ss.days(30)) is that long after the sim’s start in a sim with a calendar (ss.years(5) is five years in), and with none a time on the sim’s own axis, counted from 0 as sim.t.tvec is (which is the same thing when the start is 0). The sim’s own stop= is a time, read as the start is; its length is dur= (the stop is then the start plus it; given both, the start is the stop minus it).

Used with: agents and compartments; declared and coded modules

Classes

Name Description
Timeline Handle time vectors and sequencing (“timelines”) for both simulations and modules.
schedule When something is due: on a calendar cadence (e.g. every 3 months), at a list of times, whenever a function of the date is true, or at every step between a start and a stop (with neither, at every step)

Timeline

internals.timeline.Timeline(
    start=None,
    stop=None,
    dt=None,
    dur=None,
    name=None,
    init=None,
    sim=None,
)

Handle time vectors and sequencing (“timelines”) for both simulations and modules.

Each module can have its own time instance, in the case where the time vector is defined by absolute dates, these time vectors are by definition aligned. Otherwise they can be specified using dur objects which express relative times (they can be added to a date to get an absolute time)

Parameters

Name Type Description Default
start str/int/float/ss.date/ss.Duration when the simulation/module starts. For the sim: a date (e.g. ‘2000-01-01’) or a year (a bare number from 1800 on, e.g. 2000) gives it a calendar; any other number, or a duration, is a time in its unit from 0 (default: 2000 for a model in years, else 0). For a module: a time on the sim’s timeline (a bare number as for the sim’s stop; a duration is that long after the sim’s start, in a sim with a calendar) None
stop str/int/float/ss.date/ss.Duration when the simulation/module ends, read as the start is: a date, a bare number (a year if the sim has a calendar, else a time in its unit from 0), or a duration (a time from 0, for a sim with no calendar; ss.years(2030) in a sim of calendar years is the year 2030) (default: a run of 100 days in days, else 50 of the sim’s unit) None
dur int/float/ss.Duration the length of the run, from its start (a bare number is in years in a sim of calendar years, as a bare stop is, else in the sim’s unit): start=2000, dur=10 is the same as start=2000, stop=2010, and so is stop=2010, dur=10 (any two define the third; all three must agree) None
dt int/float/ss.Duration the step (a bare number is in the sim’s unit) None
name str if provided, name the Timeline object None
init bool whether or not to immediately initialize the Timeline object (by default, yes if start and stop are provided; otherwise no) None
sim Sim if provided, initialize the Timeline with this as the parent (i.e. populating missing values) None

The Timeline object, after initialization, has the following time vectors, each representing a different way of representing time:

  • tvec: ground truth simulation time, either as absolute ss.date instances, or relative ss.Duration instances, e.g. DateArray([<2021-01-01>, <2021-01-03>, <2021-01-05>, <2021-01-07>])
  • tivec: the vector of time indices (np.arange(len(tvec)))
  • timevec: the “human-friendly” representation of tvec: same as tvec if using ss.date, else floats if using ss.Duration
  • yearvec: time represented as floating-point years
  • datevec: time represented as ss.date instances
  • relvec: relative time, in the unit of the sim’s step (dt)

The Timeline object also has the following attributes/methods:

  • ti (int): the current time point, which is also the current step: step ti runs from time point ti to the next, and its results go at ti
  • npts (int): the total number of time points in the timeline, which is also the number of steps (see note below)
  • now() (ss.date/float/str): the current time, time point ti, the start of the current step, based on tvec by default or a different vector if specified
  • calendar (str): ‘dates’, ‘years’, or None (see ss.timeline.calendar_of()), and unit, the class of the sim’s unit (e.g. ss.days)
  • dur (ss.Duration): the length of the run, from its start to its stop

Note: the time vectors include both the start and stop endpoints, and a step is taken from each of them, so each time point is a period: a stock at it is the state at its start, and a flow at it is the total over the step that starts there. For example, start=0, stop=1, dt=1 produces two time points ([0, 1]) and takes two steps; the state after the last one is not recorded. Giving the length (dur) is the same as giving the stop (start=2000, dur=1 is the same timeline as start=2000, stop=2001). See the time user guide for the rationale behind the inclusive endpoint.

Examples

t1 = ss.Timeline(start=2000, stop=2020, dt=1.0)
t2 = ss.Timeline(start='2021-01-01', stop='2021-04-04', dt=ss.days(2))
t3 = ss.Timeline(start='2021-01-01', dur=ss.days(90), dt=ss.days(1)) # 90 days from the start

Attributes

Name Description
datevec Time vector as ss.date objects (derived lazily from tvec/yearvec)
dt_year The timestep size in years
is_absolute Check whether the fundamental simulation unit is absolute
npts The number of time points (inclusive of both endpoints, so one more than the number of steps)
ready Check if all parameters are in place to be initialized
relvec Time since the start of the sim, as numbers in the unit of the sim’s step, dt (e.g. weeks for dt=ss.weeks(1), whatever the sim’s unit); derived lazily
timevec Human-friendly (plotting-friendly) representation of tvec (derived lazily)
year The current time in years

Methods

Name Description
date_of The date of a time point (default: now), as a function of the date in when= (or ss.schedule()) reads it: the time point itself
dur_time A duration given as a time (see to_time()): with a calendar, that long after the sim’s start (or a calendar year,
init Initialize all vectors
now Get the current simulation time: time point ti, the start of the current step, which is when the step
reconcile_args Read the start, stop, and step as given: for the sim (or a timeline on its own), the calendar is decided from the start; a module’s are on the sim’s timeline
reconcile_module A module’s timeline: its start and stop as times on the sim’s (a bare number or a duration as for the sim’s), or the sim’s; or its start plus a length (dur)
reconcile_own The sim’s timeline (or one standing alone): decide the calendar from the start (or, with none, the stop), then read the rest on it; the stop is a time, as the start is, or else the start plus the length (dur); given the stop and the length, the start is the stop minus it
to_dict Return a dictionary of all time vectors
to_time A time (a date, a bare number, or a duration) as the same kind of time as the timeline’s: a date (ss.date) if its
update Update the time parameters, reinitializing the timeline if it was initialized and any changed
date_of
internals.timeline.Timeline.date_of(now=None)

The date of a time point (default: now), as a function of the date in when= (or ss.schedule()) reads it: the time point itself if the times are dates, or the date of the year if they are years (e.g. 2000.5 is 2000-07-02); a sim with no calendar has no dates

Parameters
Name Type Description Default
now ss.date/ss.Duration the time point, one of tvec (default: now()) None
dur_time
internals.timeline.Timeline.dur_time(val, name='time', own_stop=False)

A duration given as a time (see to_time()): with a calendar, that long after the sim’s start (or a calendar year, e.g. ss.years(2005)); with none, a point on the timeline’s own axis from 0

Parameters
Name Type Description Default
val ss.Duration the duration required
name str what the time is, for the error message (e.g. ‘until=’) 'time'
own_stop bool whether it is the sim’s own stop, which with a calendar is an error (its length is dur=) False
init
internals.timeline.Timeline.init(sim=None, max_steps=None, force=False)

Initialize all vectors

Parameters
Name Type Description Default
sim ss.Sim the sim to take missing values from; if None, the timeline stands alone None
max_steps int the number of steps above which to warn; if None, use ss.options.max_steps None
force bool whether to initialize again False
now
internals.timeline.Timeline.now(key=None)

Get the current simulation time: time point ti, the start of the current step, which is when the step happens, what it reads its inputs at, and where its results go (see ss.loop.Loop)

Parameters
Name Type Description Default
key str which type of time to get: “tvec” (default), “time”, “year”, “date”, or “str” None
Examples
t = ss.Timeline(start='2021-01-01', stop='2022-02-02', dt='week')
t.ti = 25 # The step from time point 25 to 26
t.now() # Returns <2021-06-25>
t.now('date') # Returns <2021-06-25>
t.now('year') # Returns 2021.479
t.now('str') # Returns '2021-06-25'
reconcile_args
internals.timeline.Timeline.reconcile_args(sim=None)

Read the start, stop, and step as given: for the sim (or a timeline on its own), the calendar is decided from the start; a module’s are on the sim’s timeline

reconcile_module
internals.timeline.Timeline.reconcile_module(start, stop, dur, dt, sim)

A module’s timeline: its start and stop as times on the sim’s (a bare number or a duration as for the sim’s), or the sim’s; or its start plus a length (dur)

reconcile_own
internals.timeline.Timeline.reconcile_own(start, stop, dur, dt, sim=None)

The sim’s timeline (or one standing alone): decide the calendar from the start (or, with none, the stop), then read the rest on it; the stop is a time, as the start is, or else the start plus the length (dur); given the stop and the length, the start is the stop minus it

to_dict
internals.timeline.Timeline.to_dict()

Return a dictionary of all time vectors

to_time
internals.timeline.Timeline.to_time(val, name='time')

A time (a date, a bare number, or a duration) as the same kind of time as the timeline’s: a date (ss.date) if its times are dates, else a duration (ss.years with a calendar of years, else the sim’s unit)

A bare number is a calendar year if the timeline has a calendar, else a time in its unit from 0. A duration is that long after the sim’s start if the timeline has a calendar (ss.years(5) in a sim from 2000 is 2005, and ss.months(3) in one from ‘2020-01-15’ is ‘2020-04-15’), unless it is a calendar year (ss.years(2005), from 1800 on, as the tvec of a sim of calendar years holds); with no calendar, it is a time on the timeline’s own axis, counted from 0, as its start and tvec are (so ss.days(10) is day 10, which is 10 days in when the start is 0). Its unit should then be the sim’s or the module’s (else a warning).

Parameters
Name Type Description Default
val str/float/ss.date/ss.Duration the time required
name str what the time is, for the error message (e.g. ‘when=’) 'time'
update
internals.timeline.Timeline.update(**kwargs)

Update the time parameters, reinitializing the timeline if it was initialized and any changed

Parameters
Name Type Description Default
kwargs the time parameters to change (start, stop, dt, dur); those not given (or None) are kept, except that a new stop replaces the length (dur), and a new length the stop

schedule

internals.timeline.schedule(
    *args,
    at=None,
    every=None,
    start=None,
    stop=None,
    **kwargs,
)

When something is due: on a calendar cadence (e.g. every 3 months), at a list of times, whenever a function of the date is true, or at every step between a start and a stop (with neither, at every step)

Make one as an attribute (or parameter) of a module, which links it to the module’s timeline when the sim is initialized; then sched.due(), in the module’s step(), is how many of its times fall in this step (from now up to the next step’s now): usually 0 or 1, so if sched.due(): works. A module can have as many as it needs.

Parameters

Name Type Description Default
at date / dur / list / func optionally (by position or keyword): the times (a time or a list of them, e.g. ['2021-06-01', '2023-06-01'], or years, or durations, as ss.days(10), which is 10 days after the start of the sim, not every 10 days), or a function of the date of the start of each step (its now), true when it is due (e.g. lambda now: now.month == 1); told apart by type. A single duration by position is an error, since it could be either: give every= or at= None
every dur how often; whole months and years are calendar offsets, so every month is the same day of the month None
start date / dur the first time, as a date, a year, or a duration after the start of the sim (default: the start of the timeline), for every None
stop date / dur no times after this, likewise (default: the end of the timeline) None

With only start and/or stop, it is due at every step between them (a window): as the when= of an ss.Event, routine delivery between those times. With no arguments, it is due at every step, so code with an optional every=, start=, and stop= can always make one. A duration given as a time is that long after the sim’s start in a sim with a calendar, and with none a time from 0 (the same when the start is 0).

Examples

class Clinic(ss.Module):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.poll = ss.schedule(every=ss.months(3), start='2020-04-01') # Every 3 months from April 2020
        self.checkup = ss.schedule(every=ss.years(1), start=ss.months(6)) # Yearly, the first 6 months after the sim's start
        self.campaigns = ss.schedule(['2021-06-01', '2023-06-01'])
        self.report = ss.schedule(lambda now: now.month == 1 and now.day == 1) # New Year's Day
        self.weekly = ss.schedule(every=ss.weeks(1)) # How often is always every=
        self.window = ss.schedule(start='2025-01-01', stop='2026-01-01') # Every step in 2025

    def step(self):
        if self.poll.due():
            ...

Attributes

Name Description
steps The steps (their indices, ti) in which it is due

Methods

Name Description
due The number of times due in this step (or step ti), usually 0 or 1
init Link to a timeline (of a module or sim, or a ss.Timeline itself), and work out the number due in each of its steps
due
internals.timeline.schedule.due(ti=None)

The number of times due in this step (or step ti), usually 0 or 1

init
internals.timeline.schedule.init(obj)

Link to a timeline (of a module or sim, or a ss.Timeline itself), and work out the number due in each of its steps

Functions

Name Description
calendar_of Whether times are on a calendar, decided from the start (or, with no start, from the stop): ‘dates’ for a date
how_bare How a bare number is read as a time on a timeline, for error messages
of_date A function of the date (in when=, or ss.schedule()), called on the date of a time point of timeline t (default: now; see Timeline.date_of())
same Whether two time arguments are the same, for update()

calendar_of

internals.timeline.calendar_of(start, stop=None, unit=None)

Whether times are on a calendar, decided from the start (or, with no start, from the stop): ‘dates’ for a date (e.g. ‘2020-01-01’), ‘years’ for a bare year (a number from 1800 on, e.g. 2000), else None (a time from 0 in the sim’s unit)

With no start, a bare stop from 1800 on is a year only if the unit is years (or not given): with another, it is a time in that unit from 0 (unit='day', stop=3650 is 3,650 days), since the unit is explicit and the stop is not.

Parameters

Name Type Description Default
start str/float/ss.date/ss.Duration the start, as given required
stop str/float/ss.date/ss.Duration the stop, as given, read only if there is no start None
unit str the unit given to the sim (unit=), if any None

how_bare

internals.timeline.how_bare(t)

How a bare number is read as a time on a timeline, for error messages

of_date

internals.timeline.of_date(fn, t, now=None)

A function of the date (in when=, or ss.schedule()), called on the date of a time point of timeline t (default: now; see Timeline.date_of())

same

internals.timeline.same(a, b)

Whether two time arguments are the same, for update()