Source code for smif.model.model
"""Model abstract class
"""
import sys
from enum import Enum
from logging import getLogger
from smif.metadata import Spec
[docs]class ModelOperation(Enum):
""" Enumerate that describes the possible operations on Models
"""
BEFORE_MODEL_RUN = 'before_model_run'
SIMULATE = 'simulate'
[docs]class Model():
"""Abstract class represents the interface used to implement the model classes
`SectorModel` and `ScenarioModel`.
Arguments
---------
name : str
"""
def __init__(self, name):
self.logger = getLogger(__name__)
self.name = name
self.description = ''
self._inputs = {}
self._parameters = {}
self._outputs = {}
def __repr__(self):
return "<{} name='{}'>".format(self.__class__.__name__, self.name)
[docs] @classmethod
def from_dict(cls, config):
"""Create object from dictionary serialisation
"""
model = cls(config['name'])
model.description = config['description']
for input_ in config['inputs']:
model.add_input(Spec.from_dict(input_))
for output in config['outputs']:
model.add_output(Spec.from_dict(output))
for param in config['parameters']:
model.add_parameter(Spec.from_dict(param))
return model
[docs] def as_dict(self):
"""Serialize the SectorModel object as a dictionary
Returns
-------
dict
"""
config = {
'name': self.name,
'description': self.description,
'path': sys.modules[self.__module__].__file__,
'classname': self.__class__.__name__,
'inputs': [inp.as_dict() for inp in self.inputs.values()],
'outputs': [out.as_dict() for out in self.outputs.values()],
'parameters': [param.as_dict() for param in self.parameters.values()]
}
return config
@property
def inputs(self):
"""All model inputs defined at this layer
Returns
-------
dict of {input_name: smif.metadata.Spec}
"""
return self._inputs
@property
def parameters(self):
"""Model parameters
Returns
-------
dict of {parameter_name: smif.data_layer.data_array.DataArray}
"""
return self._parameters
[docs] def add_parameter(self, spec):
"""Add a parameter
Arguments
---------
spec: smif.metadata.Spec
"""
self.parameters[spec.name] = spec
@property
def outputs(self):
"""All model outputs defined at this layer
Returns
-------
dict of {output_name: smif.metadata.Spec}
"""
return self._outputs
[docs] def add_output(self, spec):
"""Add an output
Arguments
---------
spec: smif.metadata.Spec
"""
self.outputs[spec.name] = spec
[docs] def simulate(self, data):
"""Override to implement the generation of model results
Generate ``results`` for ``timestep`` using ``data``
Arguments
---------
data: smif.data_layer.DataHandle
Access state, parameter values, dependency inputs.
"""
[docs]class ScenarioModel(Model):
"""Represents exogenous scenario data
Arguments
---------
name : str
The name of this scenario (scenario set/abstract
scenario/scenario group) - like sector model name
Attributes
----------
name : str
Name of this scenario
scenario : str
Instance of scenario (concrete instance)
"""
def __init__(self, name):
super().__init__(name)
self.scenario = None
[docs] @classmethod
def from_dict(cls, data):
"""Create ScenarioModel from dict serialisation
"""
scenario = cls(data['name'])
scenario.scenario = data['scenario']
if 'description' in data:
scenario.description = data['description']
for output in data['outputs']:
spec = Spec.from_dict(output)
scenario.add_output(spec)
return scenario
[docs] def as_dict(self):
"""Serialise ScenarioModel to dict
"""
config = {
'name': self.name,
'description': self.description,
'scenario': self.scenario,
'outputs': [
output.as_dict()
for output in self.outputs.values()
]
}
return config
[docs] def simulate(self, data):
"""No-op, as the data is assumed to be already available in the store
"""
return data