Source code for smif.metadata.timestep
"""smif runs models over a series of planning timesteps.
:class:`~smif.metadata.timestep.RelativeTimestep` is used to specify one timestep relative to
another in the context of the set of planning timesteps.
For example, if a model needs to know its own outputs from a previous year, we can specify the
self-dependency using a relative timestep.
"""
from enum import Enum
from typing import List, Union
from smif.exception import SmifTimestepResolutionError
[docs]class RelativeTimestep(Enum):
"""Specify current, previous or base year timestep"""
CURRENT = "CURRENT" # current planning timestep
PREVIOUS = "PREVIOUS" # previous planning timestep
BASE = "BASE" # base year planning timestep
ALL = "ALL" # all planning timesteps
[docs] @classmethod
def from_name(cls, name):
if name == "CURRENT":
return cls.CURRENT
elif name == "PREVIOUS":
return cls.PREVIOUS
elif name == "BASE":
return cls.BASE
elif name == "ALL":
return cls.ALL
raise ValueError("Relative timestep '%s' is not recognised" % name)
[docs] def resolve_relative_to(
self, timestep: int, timesteps: List[int]
) -> Union[None, int]:
"""Resolve a relative timestep with respect to a given timestep and
sequence of timesteps.
Parameters
----------
timestep : int
timesteps : list of int
"""
if timestep not in timesteps:
raise SmifTimestepResolutionError(
"Timestep {} is not present in {}".format(timestep, timesteps)
)
# default None, e.g. for ALL
relative_timestep = None
if self.name == "CURRENT":
relative_timestep = timestep
elif self.name == "PREVIOUS":
try:
relative_timestep = element_before(timestep, timesteps)
except ValueError:
raise SmifTimestepResolutionError(
"{} has no previous timestep in {}".format(timestep, timesteps)
)
elif self.name == "BASE":
relative_timestep = timesteps[0]
return relative_timestep
[docs]def element_before(element: int, list_: List[int]) -> int:
"""Return the element before a given element in a list, or None if the
given element is first or not in the list.
"""
if element not in list_ or element == list_[0]:
raise ValueError("No element before {} in {}".format(element, list_))
else:
index = list_.index(element)
return list_[index - 1]