Source code for uncertainpy.models.model

from __future__ import absolute_import, division, print_function, unicode_literals

import six
import numpy as np

from ..utils.logger import setup_module_logger, get_logger

[docs]class Model(object): """ Class for storing the model to perform uncertainty quantification and sensitivity analysis on. The ``run`` method must either be implemented or set to a function, and is responsible for running the model. If you want to calculate features directly from the original model results, but still need to postprocess the model results to perform the uncertainty quantification, you can implement the postprocessing in the ``postprocess`` method. Parameters ---------- run : {None, callable}, optional A function that implements the model. See the ``run`` method for requirements of the function. Default is None. interpolate : bool, optional True if the model is irregular, meaning it has a varying number of return values between different model evaluations, and an interpolation of the results is performed. Default is False. labels : list, optional A list of label names for the axes when plotting the model. On the form ``["x-axis", "y-axis", "z-axis"]``, with the number of axes that is correct for the model output. Default is an empty list. postprocess : {None, callable}, optional A function that implements the postprocessing of the model. See the ``postprocess`` method for requirements of the function. Default is None. ignore : bool, optional Ignore the model results when calculating uncertainties, which means the uncertainty is not calculated for the model. Default is False. suppress_graphics : bool, optional Suppress all graphics created by the model. Default is False. logger_level : {"info", "debug", "warning", "error", "critical", None}, optional Set the threshold for the logging level. Logging messages less severe than this level is ignored. If None, no logging to file is performed. Default logger level is "info". **model_kwargs Any number of arguments passed to the model function when it is run. Attributes ---------- labels : list A list of label names for the axes when plotting the model. On the form ``["x-axis", "y-axis", "z-axis"]``, with the number of axes that is correct for the model output. interpolate : bool True if the model is irregular, meaning it has a varying number of return values between different model evaluations, and an interpolation of the results is performed. Default is False. name : str Name of the model. Either the name of the class or the name of the function set as run. suppress_graphics : bool Suppress all graphics created by the model. ignore : bool Ignore the model results when calculating uncertainties, which means the uncertainty is not calculated for the model. The model results are still postprocessed if a postprocessing is implemented. Default is False. See Also -------- uncertainpy.models.Model.run uncertainpy.models.Model.postprocess """ def __init__(self, run=None, interpolate=False, labels=[], postprocess=None, ignore=False, suppress_graphics=False, logger_level="info", **model_kwargs): self.interpolate = interpolate self.labels = labels self.ignore = ignore self.suppress_graphics = suppress_graphics self.model_kwargs = model_kwargs if run is not None: self.run = run else: self.name = self.__class__.__name__ setup_module_logger(class_instance=self, level=logger_level) if postprocess is not None: self.postprocess = postprocess @property def run(self): """ Run the model and return time and model result. This method must either be implemented or set to a function and is responsible for running the model. See Notes for requirements. Parameters ---------- **parameters : A number of named arguments (name=value). The parameters of the model. These parameters must be assigned to the model, either setting them with Python, or assigning them to the simulator. Returns ------- time : {None, numpy.nan, array_like} Time values of the model, if no time values returns None or numpy.nan. values : array_like Result of the model. Note that `values` myst either be regular (have the same number of points for different paramaters) or be able to be interpolated. info, optional Any number of info objects that is passed on to feature calculations. It is recommended to use a single dictionary with the information stored as key-value pairs. This is what the implemented features requires, as well as require that specific keys to be present. Raises ------ NotImplementedError If no run method have been implemented or set to a function. Notes ----- The ``run`` method must either be implemented or set to a function. Both options have the following requirements: 1. **Input.** The model function takes a number of arguments which define the uncertain parameters of the model. 2. **Run the model.** The model must then be run using the parameters given as arguments. 3. **Output.** The model function must return at least two objects, the model time (or equivalent, if applicable) and model output. Additionally, any number of optional info objects can be returned. In Uncertainpy, we refer to the time object as ``time``, the model output object as ``values``, and the remaining objects as ``info``. Note that while we refer to these objects as ``time``, ``values`` and ``info`` in Uncertainpy, it does not matter what you call the objects returned by the run function. 1. **Time** (``time``). The ``time`` can be interpreted as the x-axis of the model. It is used when interpolating (see below), and when certain features are calculated. We can return ``None`` if the model has no time associated with it. 2. **Model output** (``values``). The model output must either be regular, or it must be possible to interpolate or postprocess the output to a regular form. 3. **Additional info** (``info``). Some of the methods provided by Uncertainpy, such as the later defined model postprocessing, feature preprocessing, and feature calculations, require additional information from the model (e.g., the time a neuron receives an external stimulus). We recommend to use a single dictionary as info object, with key-value pairs for the information, to make debugging easier. Uncertainpy always uses a single dictionary as the ``info`` object. Certain features require that specific keys are present in this dictionary. The model does not need to be implemented in Python, you can use any model/simulator as long as you are able to set the model parameters of the model from the run method Python and return the results from the model into the run method. If you want to calculate features directly from the original model results, but still need to postprocess the model results to perform the uncertainty quantification, you can implement the postprocessing in the ``postprocess`` method. See also -------- uncertainpy.features uncertainpy.features.Features.preprocess : Preprocessing of model results before feature calculation uncertainpy.model.Model.postprocess : Postprocessing of model result. """ return self._run @run.setter def run(self, new_run): if not callable(new_run): raise TypeError("run function must be callable") self._run = new_run self.name = new_run.__name__ def _run(self, **parameters): raise NotImplementedError("No run method implemented or set in {class_name}".format(class_name=__name__))
[docs] def evaluate(self, **parameters): """ Run the model with parameters and default model_kwargs options, and validate the result. Parameters ---------- **parameters : A number of named arguments (name=value). The parameters of the model. These parameters must be assigned to the model, either setting them with Python, or assigning them to the simulator. Returns ------- time : {None, numpy.nan, array_like} Time values of the model, if no time values returns None or numpy.nan. values : array_like Result of the model. Note that `values` myst either be regular (have the same number of points for different paramaters) or be able to be interpolated. info, optional Any number of info objects that is passed on to feature calculations. It is recommended to use a single dictionary with the information stored as key-value pairs. This is what the implemented features requires, as well as require that specific keys to be present. See also -------- uncertainpy.models.Model.run : Requirements for the model run function. """ all_parameters = self.model_kwargs.copy() all_parameters.update(parameters) model_result = self.run(**all_parameters) self.validate_run(model_result) return model_result
@property def postprocess(self, *model_result): """ Postprocessing of the time and results from the model. No postprocessing is performed, and the direct model results are currently returned. If postprocessing is needed it should follow the below format. Parameters ---------- *model_result Variable length argument list. Is the values that ``run`` returns. It contains `time` and `values`, and then any number of optional `info` values. time : {None, numpy.nan, array_like} Time values of the model. If no time values the model should return ``None`` or ``numpy.nan``. values : array_like Result of the model. info, optional Any number of info objects that is passed on to feature calculations. It is recommended to use a single dictionary with the information stored as key-value pairs. This is what the implemented features requires, as well as require that specific keys to be present. Returns ------- time : {None, numpy.nan, array_like} Time values of the model, if no time values returns ``None`` or ``numpy.nan``. values : array_like The postprocessed model results, `values` must either be regular (have the same number of points for different paramaters) or be able to be interpolated. Notes ----- Perform a postprocessing of the model results before they are sent to the uncertainty quantification. The model results must either be regular or be able to be interpolated. This is because the uncertainty quantification methods needs results with the same number of points for each set of parameters to be able to perform the uncertainty quantification. ``postprocess`` is implemented to make the model results regular, or on a form that can be interpolated. The results from the postprocessing is not used to calculate features, and is therefore used if you want to calculate features directly from the original model results, but still need to postprocess the model results to perform the uncertainty quantification. The requirements for a ``postprocess`` function are: 1. **Input.** ``postprocess`` must take the objects returned by the model function as input arguments. 2. **Postprocessing.** The model time (``time``) and output (``values``) must be postprocessed to a regular form, or to a form that can be interpolated to a regular form by Uncertainpy. If additional information is needed from the model, it can be passed along in the ``info`` object. 3. **Output.** The ``postprocess`` function must return two objects: 1. **Model time** (``time_postprocessed``). The first object is the postprocessed time (or equivalent) of the model. We can return ``None`` if the model has no time. Note that the automatic interpolation of the postprocessed time can only be performed if a postprocessed time is returned (if an interpolation is required). 2. **Model output** (``values_postprocessed``). The second object is the postprocessed model output. """ return self._postprocess def _postprocess(self, *model_result): return model_result[:2] @postprocess.setter def postprocess(self, new_postprocess_function): if not callable(new_postprocess_function): raise TypeError("postprocess function must be callable") self._postprocess = new_postprocess_function
[docs] def validate_run(self, model_result): """ Validate the results from ``run``. This method ensures ``run`` returns `time`, `values`, and optional info objects. Parameters ---------- model_results Any type of model results returned by ``run``. Raises ------ ValueError If the model result does not fit the requirements. TypeError If the model result does not fit the requirements. Notes ----- Tries to verify that at least, `time` and `values` are returned from ``run``. ``model_result`` should follow the format: ``return time, values, info_1, info_2, ...``. Where: * ``time`` : ``{None, numpy.nan, array_like}``. Time values of the model. If no time values it should return None or numpy.nan. * ``values`` : ``array_like`` Result of the model. * ``info``, optional. Any number of info objects that is passed on to feature calculations. It is recommended to use a single dictionary with the information stored as key-value pairs. This is what the implemented features requires, as well as require that specific keys to be present. See Also -------- uncertainpy.models.Model.run """ if isinstance(model_result, np.ndarray): raise ValueError("model.run() returns an numpy array. " "This indicates only time or values is returned. " "model.run() or model function must return " "time and values " "(return time, values | return None, values)") if isinstance(model_result, six.string_types): raise ValueError("model.run() returns an string. " "This indicates only time or values is returned. " "model.run() or model function must return " "time and values " " (return time, values | return None, values)") try: time, values = model_result[:2] except (ValueError, TypeError) as error: msg = "model.run() or model function must return time and values (return time, values | return None, values)" if not error.args: error.args = ("",) error.args = error.args + (msg,) raise
[docs] def validate_postprocess(self, postprocess_result): """ Validate the results from ``postprocess``. This method ensures that ``postprocess`` returns `time` and `values`. Parameters ---------- model_results Any type of postprocessed model results returned by ``postprocess``. Raises ------ ValueError If the postprocessed model result does not fit the requirements. TypeError If the postprocessed model result does not fit the requirements. Notes ----- Tries to verify that `time` and `values` are returned from ``postprocess``. ``postprocess`` must return two objects on the format: ``return time, values``, where: * ``time_postprocessed`` : ``{None, numpy.nan, array_like}``. The first object is the postprocessed time (or equivalent) of the model. We can return ``None`` if the model has no time. Note that the automatic interpolation of the postprocessed time can only be performed if a postprocessed time is returned (if an interpolation is required). * ``values_postprocessed`` : ``array_like``. The second object is the postprocessed model output. Both of these must be regular or on a form that can be interpolated. See Also -------- uncertainpy.models.Model.postprocess """ if isinstance(postprocess_result, np.ndarray): raise ValueError("model.postprocess() returns an numpy array. " "This indicates only time or values is returned. " "model.postprocess() or model function must return " "time and values " "(return time, values | return None, values)") if isinstance(postprocess_result, six.string_types): raise ValueError("model.postprocess() returns an string. " "This indicates only time or values is returned. " "model.postprocess() or model function must return " "time and values " " (return time, values | return None, values)") try: time_postprocess, values_postprocess = postprocess_result except (ValueError, TypeError) as error: msg = "model.postprocess() must return time and values (return time, values | return None, values)" if not error.args: error.args = ("",) error.args = error.args + (msg,) raise
[docs] def set_parameters(self, **parameters): """ Set all named arguments as attributes of the model class. Parameters ---------- **parameters : A number of named arguments (name=value). All set as attributes of the class. """ for parameter in parameters: setattr(self, parameter, parameters[parameter])