smif.decision.decision module

The decision module handles the three planning levels

Currently, only pre-specified planning is implemented.

The choices made in the three planning levels influence the set of interventions and assets available within a model run.

The interventions available in a model run are stored in a dict keyed by name.

Summary

Data:

DecisionManager A DecisionManager is initialised with one or more model run strategies that refer to DecisionModules such as pre-specified planning, a rule-based models or multi-objective optimisation.
DecisionModule Abstract class which provides the interface to user defined decision modules.
RuleBased Rule-base decision modules

Reference

class smif.decision.decision.DecisionManager(store: smif.data_layer.store.Store, timesteps: List[int], modelrun_name: str, sos_model, decision: int = 0)[source]

Bases: object

A DecisionManager is initialised with one or more model run strategies that refer to DecisionModules such as pre-specified planning, a rule-based models or multi-objective optimisation. These implementations influence the combination and ordering of decision iterations and model timesteps that need to be performed by the model runner.

The DecisionManager presents a simple decision loop interface to the model runner, in the form of a generator which allows the model runner to iterate over the collection of independent simulations required at each step.

The DecisionManager collates the output of the decision algorithms and writes the post-decision state through a ResultsHandle. This allows Models to access a given decision state (identified uniquely by timestep and decision iteration id).

The get_decisions() method passes a ResultsHandle down to a DecisionModule, allowing the DecisionModule to access model results from previous timesteps and decision iterations when making decisions

Parameters:store (smif.data_layer.store.Store) –
available_interventions

Returns a register of available interventions, i.e. those not planned

get_intervention(value)[source]
decision_loop()[source]

Generate bundles of simulation steps to run

Each call to this method returns a dict:

{

‘decision_iterations’: list of decision iterations (int), ‘timesteps’: list of timesteps (int), ‘decision_links’: (optional) dict of {

decision iteration in current bundle: decision iteration of previous bundle

}

}

A bundle is composed differently according to the implementation of the contained DecisionModule. For example:

With only pre-specified planning, there is a single step in the loop, with a single decision iteration with timesteps covering the entire model horizon.

With a rule based approach, there might be many steps in the loop, each with a single decision iteration and single timestep, moving on once some threshold is satisfied.

With a genetic algorithm, there might be a configurable number of steps in the loop, each with multiple decision iterations (one for each member of the algorithm’s population) and timesteps covering the entire model horizon.

Implicitly, if the bundle returned in an iteration contains multiple decision iterations, they can be performed in parallel. If each decision iteration contains multiple timesteps, they can also be parallelised, so long as there are no temporal dependencies.

Decision links are only required if the bundle timesteps do not start from the first timestep of the model horizon.

get_and_save_decisions(iteration, timestep)[source]

Retrieves decisions for given timestep and decision iteration from each decision module and writes them to the store as state.

Calls each contained DecisionModule for the given timestep and decision iteration in the data_handle, retrieving a list of decision dicts (keyed by intervention name and build year).

These decisions are then written to a state file using the data store.

Parameters:
  • timestep (int) –
  • iteration (int) –

Notes

State contains all intervention names which are present in the system at the given timestep for the current iteration. This must include planned interventions from a previous timestep that are still within their lifetime, and interventions picked by a decision module in the previous timesteps.

After loading all historical interventions, and screening them to remove interventions from the previous timestep that have reached the end of their lifetime, new decisions are added to the list of current interventions.

Finally, the new state is written to the store.

retire_interventions(state: List[Tuple[int, str]], timestep: int) → List[Tuple[int, str]][source]
buildable(build_year, timestep) → bool[source]

Interventions are deemed available if build_year is less than next timestep

For example, if a is built in 2011 and timesteps are [2005, 2010, 2015, 2020] then buildable returns True for timesteps 2010, 2015 and 2020 and False for 2005.

Parameters:
  • build_year (int) – The build year of the intervention
  • timestep (int) – The current timestep
static within_lifetime(build_year, timestep, lifetime) → bool[source]

Interventions are deemed active if build_year + lifetime >= timestep

Parameters:
  • build_year (int) –
  • timestep (int) –
  • lifetime (int) –
Returns:

Return type:

bool

class smif.decision.decision.DecisionModule(timesteps: List[int], register: mappingproxy)[source]

Bases: object

Abstract class which provides the interface to user defined decision modules.

These mechanisms could include a Rule-based Approach or Multi-objective Optimisation.

This class provides two main methods, __next__ which is normally called implicitly as a call to the class as an iterator, and get_decision() which takes as arguments a smif.data_layer.data_handle.ResultsHandle object.

Parameters:
  • timesteps (list) – A list of planning timesteps
  • register (dict) – Reference to a dict of iterventions
first_timestep
last_timestep
get_previous_state(results_handle: smif.data_layer.data_handle.ResultsHandle) → List[Dict[KT, VT]][source]

Return the state of the previous timestep

available_interventions(state: List[Dict[KT, VT]]) → List[T][source]

Return the collection of available interventions

Available interventions are the subset of interventions that have not been implemented in a prior iteration or timestep

Returns:
Return type:List
get_intervention(name)[source]

Return an intervention dict

Returns:
Return type:dict
get_decision(results_handle: smif.data_layer.data_handle.ResultsHandle) → List[Dict[KT, VT]][source]

Return decisions for a given timestep and decision iteration

Parameters:results_handle (smif.data_layer.data_handle.ResultsHandle) –
Returns:
Return type:list of dict

Examples

>>> register = {'intervention_a': {'capital_cost': {'value': 1234}}}
>>> dm = DecisionModule([2010, 2015], register)
>>> dm.get_decision(results_handle)
[{'name': 'intervention_a', 'build_year': 2010}])
class smif.decision.decision.RuleBased(timesteps, register)[source]

Bases: smif.decision.decision.DecisionModule

Rule-base decision modules

get_previous_iteration_timestep() → Optional[Tuple[int, int]][source]

Returns the timestep, iteration pair that describes the previous iteration

Returns:Contains (timestep, iteration)
Return type:tuple
get_previous_state(results_handle: smif.data_layer.data_handle.ResultsHandle) → List[Dict[KT, VT]][source]

Return the state of the previous timestep

next_timestep
previous_timestep
get_previous_year_iteration()[source]
get_decision(results_handle) → List[Dict[KT, VT]][source]

Return decisions for a given timestep and decision iteration

Parameters:results_handle (smif.data_layer.data_handle.ResultsHandle) –
Returns:
Return type:list of dict

Examples

>>> register = {'intervention_a': {'capital_cost': {'value': 1234}}}
>>> dm = DecisionModule([2010, 2015], register)
>>> dm.get_decision(results_handle)
[{'name': 'intervention_a', 'build_year': 2010}])