utils

utils

STIsim utilities

Classes

Name Description
TimeSeries Store time-series data.

TimeSeries

utils.TimeSeries(t=None, vals=None, units=None, assumption=None, sigma=None)

Store time-series data.

Internally values are stored as lists rather than numpy arrays because insert/remove operations on lists tend to be faster (and working with sparse data is a key role of TimeSeries objects). Note that methods like interpolate() return numpy arrays, so the output types from such functions should generally match up with what is required by the calling function.

Parameters

Name Type Description Default
t Optionally specify a scalar, list, or array of time values. None
vals Optionally specify a scalar, list, or array of values (must be same size as t). None
units str Optionally specify units (as a string). None
assumption float Optionally specify a scalar assumption. None
sigma float Optionally specify a scalar uncertainty. None

Attributes

Name Description
has_data Check if any data has been provided
has_time_data Check if time-specific data has been provided

Methods

Name Description
copy Return a copy of the TimeSeries
get Retrieve value at a particular time
get_arrays Return arrays with the contents of this TimeSeries
insert Insert a value or list of at a particular time
interpolate Return interpolated values
remove Remove single time point
remove_after Remove times from start
remove_before Remove times from start
remove_between Remove a range of times
sample Return a sampled copy of the TimeSeries
copy
utils.TimeSeries.copy()

Return a copy of the TimeSeries

:return: An independent copy of the TimeSeries

get
utils.TimeSeries.get(t)

Retrieve value at a particular time

This function will automatically retrieve the value of the assumption if no time specific values have been provided, or if any time specific values are provided, will return the value entered at that time. If time specific values have been entered and the requested time is not explicitly present, an error will be raised.

This function may be deprecated in future because generally it is more useful to either call TimeSeries.interpolate() if interested in getting values at arbitrary times, or TimeSeries.get_arrays() if interested in retrieving values that have been entered.

:param t: A time value. If None, will return assumption regardless of whether time data has been entered or not :return: The value at the corresponding time. Returns None if the value no value present

get_arrays
utils.TimeSeries.get_arrays()

Return arrays with the contents of this TimeSeries

The TimeSeries instance may have time values, or may simply have an assumption. If obtaining raw arrays is desired, this function will return arrays with values extracted from the appropriate attribute of the TimeSeries. However, in general, it is usually .interpolate() that is desired, rather than .get_arrays()

:return: Tuple with two arrays - the first item is times (with a single NaN if the TimeSeries only has an assumption) and the second item is values

insert
utils.TimeSeries.insert(t, v)

Insert a value or list of at a particular time

If the value already exists in the TimeSeries, it will be overwritten/updated. The arrays are internally sorted by time value, and this order will be maintained.

:param t: Time value to insert or update. If None, the value will be assigned to the assumption :param v: Value to insert. If None, this function will return immediately without doing anything

interpolate
utils.TimeSeries.interpolate(t2, method='linear', **kwargs)

Return interpolated values

This method returns interpolated values from the time series at time points t2 according to a given interpolation method. There are 4 possibilities for the method

  • ‘linear’ - normal linear interpolation (with constant, zero-gradient extrapolation)
  • ‘pchip’ - legacy interpolation with some curvature between points (with constant, zero-gradient extrapolation)
  • ‘previous’ - stepped interpolation, maintain value until the next timepoint is reached (with constant, zero-gradient extrapolation)
  • Interpolation class or generator function

That final option allows the use of arbitrary interpolation methods. The underlying call will be::

c = method(t1, v1, **kwargs)
return c(t2)

so for example, if you wanted to use the base Scipy pchip method with no extrapolation, then could pass in::

TimeSeries.interpolate(...,method=scipy.interpolate.PchipInterpolator)

Note that the following special behaviours apply:

  • If there is no data at all, this function will return np.nan for all requested time points

  • If only an assumption exists, this assumption will be returned for all requested time points

  • Otherwise, arrays will be formed with all finite time values

    • If no finite time values remain, an error will be raised (in general, a TimeSeries should not store such values anyway)
    • If only one finite time value remains, then that value will be returned for all requested time points
    • Otherwise, the specified interpolation method will be used

:param t2: float, list, or array, with times :param method: A string ‘linear’, ‘pchip’ or ‘previous’ OR a callable item that returns an Interpolator :return: array the same length as t2, with interpolated values

remove
utils.TimeSeries.remove(t)

Remove single time point

:param t: Time value to remove. Set to None to remove the assumption

remove_after
utils.TimeSeries.remove_after(t_remove)

Remove times from start

:param tval: Remove times up to but not including this time

remove_before
utils.TimeSeries.remove_before(t_remove)

Remove times from start

:param tval: Remove times up to but not including this time

remove_between
utils.TimeSeries.remove_between(t_remove)

Remove a range of times

Note that the endpoints are not included

:param t_remove: two element iterable e.g. array, with [min,max] times

sample
utils.TimeSeries.sample(constant=True)

Return a sampled copy of the TimeSeries

This method returns a copy of the TimeSeries in which the values have been perturbed based on the uncertainty value.

:param constant: If True, time series will be perturbed by a single constant offset. If False, an different perturbation will be applied to each time specific value independently. :return: A copied TimeSeries with perturbed values

Functions

Name Description
route_pars Sort mixed user-supplied pars into categories (sim, sti, nw, dem, connector).

route_pars

utils.route_pars(
    pars=None,
    sim_pars=None,
    sti_pars=None,
    nw_pars=None,
    dem_pars=None,
    connector_pars=None,
    *,
    strict=False,
    verbose=True,
    **kwargs,
)

Sort mixed user-supplied pars into categories (sim, sti, nw, dem, connector).

Flat keys (from pars and **kwargs) are matched against an internal registry of per-category par-classes. A key valid in N categories is broadcast to all N (with a printed note if verbose). Pre-categorized dicts (sim_pars, sti_pars, nw_pars, dem_pars, connector_pars) are merged into their bucket as-is.

Design — when does broadcasting happen?

STIsim’s par-name registry (stisim/parameters.py) is intentionally designed so that names do not collide across categories — except in two deliberate cases where broadcasting is the desired behavior:

  1. Universal pars (e.g. dt). Every module has these, and Starsim already broadcasts them: sti.Sim(dt=ss.years(0.5)) sets dt on every module. This isn’t STIsim doing anything new.

  2. Multi-disease shared pars (e.g. beta_m2f, init_prev). Several STI disease modules register the same par name on purpose. sti.Sim(diseases=['hiv','syph'], beta_m2f=0.04) sets beta_m2f on both — that’s the convenience the registry is built for. Override per-disease via sti_pars=dict(hiv=dict(beta_m2f=...), syph=...) or by passing instances: diseases=[sti.HIV(beta_m2f=...), ...].

Custom modules supplied by the user can introduce unintended name clashes with the built-in registry. In that case route_pars prints a one-line note (verbose=True) listing the categories the key landed in. This is allowed, not an error — the print is the documentation.

Parameters

Name Type Description Default
pars dict Flat pars to route by registry lookup. None
sim_pars, sti_pars, nw_pars, dem_pars, connector_pars dict Pre-categorized pars; merged into their bucket as-is. required
strict bool If True, raise on flat-pars keys that match no category. If False, unmatched keys appear in routed.unmatched. False
verbose bool If True, print one line per cross-category broadcast. True
**kwargs Same routing as pars. {}

Returns

Name Type Description
sc.objdict with keys sim, sti, nw, dem, connector,
unmatched. Each value is a dict.