atomica.utils

Define utility classes used throughout Atomica

Functions

evaluate_plot_string(plot_string) Evaluate a plotting output specification
format_duration(t[, pluralize]) User-friendly string format of a duration
nested_loop(inputs, loop_order) Zip list of lists in order
parent_dir()

Classes

NDict(*args, **kwargs) Store and sync items with a name property
NamedItem([name])
TimeSeries([t, vals, units, assumption, sigma]) Class to store time-series data
class atomica.utils.NDict(*args, **kwargs)[source]

Store and sync items with a name property

append(value)[source]

Support an append method, like a list

copy(old, new)[source]

Copy an item and return the copy

Parameters:
  • old – The key of the existing item
  • new – The new name for the item
Returns:

The copied item

Example usage: >>> new_parset = proj.parsets.copy(‘old_name’,’new_name’)

class atomica.utils.NamedItem(name=None)[source]
copy(name=None)[source]
class atomica.utils.TimeSeries(t=None, vals=None, units=None, assumption=None, sigma=None)[source]

Class to 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:
  • t – Optionally specify a scalar, list, or array of time values
  • vals – Optionally specify a scalar, list, or array of values (must be same size as t)
  • units (Optional[str]) – Optionally specify units (as a string)
  • assumption (Optional[float]) – Optionally specify a scalar assumption
  • sigma (Optional[float]) – Optionally specify a scalar uncertainty
_sampled = None

Flag to indicate whether sampling has been performed. Once sampling has been performed, cannot sample again

assumption = None

The time-independent scalar assumption

copy()[source]

Return a copy of the TimeSeries

Returns:An independent copy of the TimeSeries
get(t)[source]

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.

Parameters:t – A time value. If None, will return assumption regardless of whether time data has been entered or not
Return type:float
Returns:The value at the corresponding time. Returns None if the value no value present
get_arrays()[source]

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()

Returns: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
has_data

Check if any data has been provided

Return type:bool
Returns:True if any data has been entered (assumption or time-specific)
has_time_data

Check if time-specific data has been provided

Unlike has_data, this will return False if only an assumption has been entered

Return type:bool
Returns:True if any time-specific data has been entered
insert(t, v)[source]

Insert a value 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.

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

None

interpolate(t2, method='linear', **kwargs)[source]

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
Parameters:
  • t2 (<built-in function array>) – float, list, or array, with times
  • method – A string ‘linear’, ‘pchip’ or ‘stepped’ OR a callable item that returns an Interpolator
Return type:

<built-in function array>

Returns:

array the same length as t2, with interpolated values

remove(t)[source]

Remove single time point

Parameters:t – Time value to remove. Set to None to remove the assumption
Return type:None
remove_after(t_remove)[source]

Remove times from start

Parameters:tval – Remove times up to but not including this time
Return type:None
remove_before(t_remove)[source]

Remove times from start

Parameters:tval – Remove times up to but not including this time
Return type:None
remove_between(t_remove)[source]

Remove a range of times

Note that the endpoints are not included

Parameters:t_remove – two element iterable e.g. array, with [min,max] times
Return type:None
sample(constant=True)[source]

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.

Parameters: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.
Returns:A copied TimeSeries with perturbed values
sigma = None

Uncertainty value, assumed to be a standard deviation

t = None

Sorted array of time points. Normally interacted with via methods like insert()

units = None

The units of the quantity

vals = None

Time-specific values - indices correspond to self.t

atomica.utils.evaluate_plot_string(plot_string)[source]

Evaluate a plotting output specification

The plots in the framework are specified as strings - for example,

>>> plot_string = "{'New active DS-TB':['pd_div:flow','nd_div:flow']}"

This needs to be (safely) evaluated so that the actual dict can be used. This function evaluates a string like this and returns a variable accordingly. For example

>>> x = evaluate_plot_string("{'New active DS-TB':['pd_div:flow','nd_div:flow']}")

is the same as

>>> x = {'New active DS-TB':['pd_div:flow','nd_div:flow']}

This will only happen if tokens associated with dicts and lists are present - otherwise the original string will just be returned directly

Parameters:plot_string (str) – A string representation of Python structures (e.g., lists, dicts)
Returns:Evaluated expression, the same as if it has originally been entered in a .py file
atomica.utils.format_duration(t, pluralize=False)[source]

User-friendly string format of a duration

This helper function is used when displaying durations in plots. It takes in a duration in units of years, and returns a string representation in user-friendly units. This function is mainly intended to be used to format denominators e.g., going from ‘probability’ and ‘1/365’ to ‘probability/day’

Parameters:
  • t (float) – A duration in units of years
  • pluralize – Always return a plural suffix
Return type:

str

Returns:

A string

Example usage:

>>> format_duration(1)
'year'
>>> format_duration(1, pluralize=True)
'years'
>>> format_duration(1/365)
'day'
>>> format_duration(2/365)
'2 days'
>>> format_duration(1.5/52)
'1.5 weeks'
>>> format_duration(2/52)
'fortnight'
>>> format_duration(2.5/12)
'2.5 months'
atomica.utils.nested_loop(inputs, loop_order)[source]

Zip list of lists in order

This is used in plot_bars() to control whether ‘times’ or ‘results’ are the outer grouping. This function takes in a list of lists to iterate over, and their nesting order. It then yields tuples of items in the given order. Only tested for two levels (which are all that get used in plot_bars() but in theory supports an arbitrary number of items.

Parameters:
  • inputs – List of lists. All lists should have the same length
  • loop_order – Nesting order for the lists
Returns:

Generator yielding tuples of items, one for each list

Example usage:

>>> list(nested_loop([['a','b'],[1,2]],[0,1]))
[['a', 1], ['a', 2], ['b', 1], ['b', 2]]

Notice how the first two items have the same value for the first list while the items from the second list vary. If the loop_order is reversed, then:

>>> list(nested_loop([['a','b'],[1,2]],[1,0]))
[['a', 1], ['b', 1], ['a', 2], ['b', 2]]

Notice now how now the first two items have different values from the first list but the same items from the second list.

atomica.utils.parent_dir()[source]