Source code for smif.modelrun
"""The Model Run collects scenarios, timesteps, narratives, and
model collection into a package which can be built and passed to
the ModelRunner to run.
The ModelRunner is responsible for running a ModelRun, including passing
in the correct data to the model between timesteps and calling to the
DecisionManager to obtain decisions.
ModeRun has attributes:
- id
- description
- sosmodel
- timesteps
- scenarios
- narratives
- strategy
- status
"""
from logging import getLogger
from smif.convert.area import get_register as get_region_register
from smif.convert.area import RegionSet
from smif.convert.interval import get_register as get_interval_register
from smif.convert.interval import IntervalSet
from smif.model.sos_model import SosModelBuilder
[docs]class ModelRun(object):
"""
"""
def __init__(self):
self._name = ""
self.description = ""
self.sos_model = None
self._model_horizon = []
self.narratives = None
self.strategies = None
self.status = 'Empty'
self.logger = getLogger(__name__)
# space and time
self.regions = get_region_register()
self.intervals = get_interval_register()
@property
def name(self):
"""Unique identifier of the ModelRun
"""
return self._name
@property
def model_horizon(self):
"""Returns the list of timesteps
Returns
=======
list
A list of timesteps, distinct and sorted in ascending order
"""
return self._model_horizon
@model_horizon.setter
def model_horizon(self, value):
self._model_horizon = sorted(list(set(value)))
[docs] def run(self):
"""Builds all the objects and passes them to the ModelRunner
The idea is that this will add ModelRuns to a queue for asychronous
processing
"""
self.logger.debug("Running model run %s", self.name)
if self.status == 'Built':
self.status = 'Running'
modelrunner = ModelRunner()
modelrunner.solve_model(self)
self.status = 'Successful'
else:
raise ValueError("Model is not yet built.")
[docs]class ModelRunner(object):
"""Runs a ModelRun
"""
def __init__(self):
self.logger = getLogger(__name__)
[docs] def solve_model(self, model_run):
"""Solve a ModelRun
Arguments
---------
model_run : :class:`smif.modelrun.ModelRun`
"""
for timestep in model_run.model_horizon:
self.logger.debug('Running model for timestep %s', timestep)
model_run.sos_model.simulate(timestep)
[docs]class ModelRunBuilder(object):
"""Builds the ModelRun object from the configuration
"""
def __init__(self):
self.model_run = ModelRun()
self.logger = getLogger(__name__)
[docs] def construct(self, config_data):
"""Set up the whole ModelRun
Parameters
----------
config_data : dict
A valid system-of-systems model configuration dictionary
"""
self._add_timesteps(config_data['timesteps'])
self.load_region_sets(config_data['region_sets'])
self.load_interval_sets(config_data['interval_sets'])
self._add_sos_model(config_data)
self.model_run.status = 'Built'
[docs] def finish(self):
"""Returns a configured model run ready for operation
"""
if self.model_run.status == 'Built':
return self.model_run
else:
raise RuntimeError("Run construct() method before finish().")
def _add_sos_model(self, config_data):
"""
"""
builder = SosModelBuilder()
builder.construct(config_data, self.model_run.model_horizon)
self.model_run.sos_model = builder.finish()
def _add_timesteps(self, timesteps):
"""Set the timesteps of the system-of-systems model
Parameters
----------
timesteps : list
A list of timesteps
"""
self.logger.info("Adding timesteps to model run")
self.model_run.model_horizon = timesteps
[docs] def load_region_sets(self, region_sets):
"""Loads the region sets into the system-of-system model
Parameters
----------
region_sets: list
A dict, where key is the name of the region set, and the value
the data
"""
assert isinstance(region_sets, dict)
region_set_definitions = region_sets.items()
if len(region_set_definitions) == 0:
msg = "No region sets have been defined"
self.logger.warning(msg)
for name, data in region_set_definitions:
msg = "Region set data is not a list"
assert isinstance(data, list), msg
self.model_run.regions.register(RegionSet(name, data))
[docs] def load_interval_sets(self, interval_sets):
"""Loads the time-interval sets into the system-of-system model
Parameters
----------
interval_sets: list
A dict, where key is the name of the interval set, and the value
the data
"""
interval_set_definitions = interval_sets.items()
if len(interval_set_definitions) == 0:
msg = "No interval sets have been defined"
self.logger.warning(msg)
for name, data in interval_set_definitions:
interval_set = IntervalSet(name, data)
self.model_run.intervals.register(interval_set)