Source code for pyphysim.simulations.parameters

#!/usr/bin/env python
"""Module containing simulation parameter classes."""

import copy
import functools
import itertools
import operator
from collections import OrderedDict
from collections.abc import Iterable

import numpy as np

from ..util.serialize import JsonSerializable
from .configobjvalidation import (integer_numpy_array_check,
                                  integer_scalar_or_integer_numpy_array_check,
                                  real_numpy_array_check,
                                  real_scalar_or_real_numpy_array_check)

# TODO: Change configobj to yaml + voluptuous (for validation)
# https://pypi.org/project/voluptuous/

try:
    # noinspection PyUnresolvedReferences
    from configobj import ConfigObj, Section, flatten_errors
    # noinspection PyUnresolvedReferences
    from validate import Validator
except ImportError:  # pragma: no cover
    pass

try:
    import cPickle as pickle
except ImportError as e:  # pragma: no cover
    import pickle

__all__ = ["combine_simulation_parameters", "SimulationParameters"]


# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# xxxxxxxxxxxxxxx Module Functions xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
[docs]def combine_simulation_parameters(params1, params2): """ Combine two SimulationParameters objects and return a new SimulationParameters object corresponding to the union of them. The union is only valid if both objects have the same parameters and only the values of the unpacked parameters are different. Parameters ---------- params1 : SimulationParameters The first SimulationParameters object. params2 : SimulationParameters The second SimulationParameters object. Returns ------- union : SimulationParameters The union of 'params1' and 'params2'. """ if set(params1.parameters.keys()) != set(params2.parameters.keys()): raise RuntimeError('Both SimulationParameters objects must have' ' the same parameters.') if set(params1.unpacked_parameters) != set(params2.unpacked_parameters): raise RuntimeError('Both SimulationParameters objects must have' ' the same unpacked parameters (only the values' ' should can be different).') fixed_parameters = params1.fixed_parameters for key in fixed_parameters: if params1[key] != params2[key]: raise RuntimeError('The fixed parameters in both ' 'SimulationParameters objects must have the' ' same value.') union = SimulationParameters() # Add the fixed parameters to the 'union' object. for key in fixed_parameters: union.add(key, copy.copy(params1[key])) # Add the union of the unpacked parameters to the 'union' object. for key in params1.unpacked_parameters: union.add(key, np.union1d(params1[key], params2[key])) # Set the parameters to be unpacked. for p in params1.unpacked_parameters: union.set_unpack_parameter(p) return union
# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxxxxxxx SimulationParameters - START xxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
[docs]class SimulationParameters(JsonSerializable): """Class to store the simulation parameters. A SimulationParameters object acts as a container for all simulation parameters. To add a new parameter to the object just call the :meth:`add` method passing the name and the value of the parameter. The value can be anything as long as the :meth:`.SimulationRunner._run_simulation` method can understand it. Alternatively, you can create a SimulationParameters object with all the parameters with the static method :meth:`create`, which receives a dictionary with the parameter names as keys. Parameters can be marked to be "unpacked", as long as they are iterable, by calling the :meth:`set_unpack_parameter` method. Different simulations will be performed for every combination of parameters marked to be unpacked, with the other parameters kept constant. Examples -------- - Create a new empty SimulationParameters object and add the individual parameters to it by calling its :meth:`add` method. .. code-block:: python params = SimulationParameters() params.add('p1', [1,2,3]) params.add('p2', ['a','b']) params.add('p3', 15) - Creating a new SimulationParameters object with the static :meth:`create` function. .. code-block:: python p = {'p1':[1,2,3], 'p2':['a','b'],'p3':15} params=SimulationParameters.create(p) params.set_unpack_parameter('p1') params.set_unpack_parameter('p2') - We can then set some of the parameters to be unpacked with .. code-block:: python params.set_unpack_parameter('p1') See also -------- .SimulationResults : Class to store simulation results. .SimulationRunner : Base class to implement Monte Carlo simulations. """ def __init__(self): # Dictionary that will store the parameters. The key is the # parameter name and the value is the parameter value. self.parameters = {} # A set to store the names of the parameters that will be unpacked. # Note there is a property to get the parameters marked to be # unpacked, that is, the unpacked_parameters property. self._unpacked_parameters_set = set() # If this SimulationParameters object was unpacked into a list of # SimulationParameters objects then each of these new objects will # set this variable with its index in that list. In other words, if # this member variable in a SimulationParameters object was set to # a non-negative integer then that SimulationParameters object is # actually one of the unpacked variations of another # SimulationParameters object. The original SimulationParameters # object will be stored in the _original_sim_params member # variable. self._unpack_index = -1 self._original_sim_params = None @property def unpack_index(self): """Get method for the unpack_index property. Returns ------- int The unpack index. Ir this SimulationParameters object is not an unpacked SimulationParameters then -1 is returned. """ return self._unpack_index @property def unpacked_parameters(self): """ Names of the parameters marked to be unpacked. Returns ------- list[str] """ return sorted(self._unpacked_parameters_set) @property def fixed_parameters(self): """ Names of the parameters which are NOT marked to be unpacked. Returns ------- list[str] List with the names of the fixed parameter. """ fixed_params = [ name for name in self.parameters.keys() if name not in self._unpacked_parameters_set ] return fixed_params
[docs] @staticmethod def _create(params_dict, unpack_index=-1, original_sim_params=None): """ Creates a new SimulationParameters object. This static method provides a different way to create a SimulationParameters object, already containing the parameters in the `params_dict` dictionary. Parameters ---------- params_dict : dict Dictionary containing the parameters. Each dictionary key corresponds to a parameter's name, while the dictionary value corresponds to the actual parameter value.. unpack_index : int Index of the created SimulationParameters object when it is part of the unpacked variations of another SimulationParameters object. See :meth:`get_unpacked_params_list`. original_sim_params : SimulationParameters The original SimulationParameters object from which the SimulationParameters object that will be created by this method came from. Returns ------- sim_params : SimulationParameters The corresponding SimulationParameters object. """ sim_params = SimulationParameters() sim_params.parameters = copy.deepcopy(params_dict) if unpack_index < 0: unpack_index = -1 # pylint: disable=W0212 sim_params._unpack_index = unpack_index # pylint: disable=W0212 sim_params._original_sim_params = original_sim_params return sim_params
[docs] @staticmethod def create(params_dict): """ Creates a new SimulationParameters object. This static method provides a different way to create a SimulationParameters object, already containing the parameters in the `params_dict` dictionary. Parameters ---------- params_dict : dict Dictionary containing the parameters. Each dictionary key corresponds to a parameter's name, while the dictionary value corresponds to the actual parameter value.. Returns ------- sim_params : SimulationParameters The corresponding SimulationParameters object. """ return SimulationParameters._create(params_dict)
[docs] def add(self, name, value): """Adds a new parameter to the SimulationParameters object. If there is already a parameter with the same name it will be replaced. Parameters ---------- name : str Name of the parameter. value : anything Value of the parameter. """ self.parameters[name] = value
[docs] def remove(self, name): """ Remove the parameter with name `name` from the SimulationParameters object Parameters ---------- name : str Name of the parameter to be removed. Raises ------ KeyError If `name` is not in parameters. """ del self.parameters[name] if name in self._unpacked_parameters_set: self._unpacked_parameters_set.remove(name)
[docs] def set_unpack_parameter(self, name, unpack_bool=True): """Set the unpack property of the parameter with name `name`. The parameter `name` must be already added to the SimulationParameters object and be an iterable. This is used in the :class:`.SimulationRunner` class. Parameters ---------- name : str Name of the parameter to be unpacked. unpack_bool : bool, optional True activates unpacking for `name`, False deactivates it. Raises ------ ValueError If `name` is not in parameters or is not iterable. """ if name in self.parameters.keys(): if isinstance(self.parameters[name], Iterable): if unpack_bool is True: self._unpacked_parameters_set.add(name) else: self._unpacked_parameters_set.remove(name) else: raise ValueError("Parameter {0} is not iterable".format(name)) else: raise ValueError("Unknown parameter: `{0}`".format(name))
def __getitem__(self, name): """Return the parameter with name `name`. Easy access to a given parameter using the brackets syntax. Parameters ---------- name : str Name of the desired parameter. Returns ------- desired_param : anything The value of the parameter with name `name`. """ return self.parameters[name] def __setitem__(self, key, value): self.parameters[key] = value def __repr__(self): # pragma: no cover """ Get the object representation as a string. Returns ------- str The object representation as a string. """ def modify_name(p_name): """ Add an * in p_name if it is set to be unpacked Parameters ---------- p_name : str The original name. """ if p_name in self._unpacked_parameters_set: p_name += '*' return p_name repr_list = [] for name, value in self.parameters.items(): repr_list.append("'{0}': {1}".format(modify_name(name), value)) return '{%s}' % ', '.join(repr_list) def __len__(self): """ Get the number of different parameters stored in the SimulationParameters object. Returns ------- length : int The number of different parameters stored in the SimulationParameters object """ return len(self.parameters) def __iter__(self): # pragma: no cover """ Get an iterator to the parameters in the SimulationParameters object. Returns ------- iterator An iterator to the SimulationParameters object. """ return iter(self.parameters) def __eq__(self, other): """ Check if two SimulationParameters objects are equal. Two simulation parameters objects are considered equal if all parameters stored in both objects are the same, except for a parameter object called 'rep_max'. Parameters ---------- other: SimulationParameters The other SimulationParameters to be compared with self. Returns ------- bool True if both objects are considered to be equal, returns False otherwise. Notes ----- The main usage for comparing if two SimulationParameters objects are equal is when loading partial results in the :class:`.SimulationRunner` class, where we need to assure we are not combining results for different simulation parameters. The :class:`.SimulationRunner` class must check if the loaded results parameters match the current parameters to be simulated and thus require the "==" operator (or the "!=" operator) to be implemented. However, it makes sense to ignore a parameter called 'rep_max', since it is not a parameter related to a 'scenario'. It is used in the :class:`.SimulationRunner` class to indicate the maximum number of iterations to perform and there is no problem when its value is different. """ if self is other: # pragma: no cover return True if not isinstance(other, self.__class__): return False # pylint: disable=W0212 if self._unpacked_parameters_set != other._unpacked_parameters_set: return False if set(self.parameters.keys()) != set(other.parameters.keys()): return False if self._unpack_index != other._unpack_index: return False for key in self.parameters.keys(): # We care about all keys, except for a key called 'rep_max' # whose value does not matter when comparing if two # SimulationResults objects are equal or not. if key != "rep_max": # noinspection PyTypeChecker if np.any(self.parameters[key] != other.parameters[key]): return False # If we didn't return until we reach this point then the objects # are equal return True def __ne__(self, other): """ Check if two SimulationParameters objects are different. See documentation for __eq__. Parameters ---------- other: SimulationParameters The other SimulationParameters to be compared with self. Returns ------- bool True if both objects are considered to be different, returns False otherwise. """ return not self.__eq__(other)
[docs] def get_num_unpacked_variations(self): """ Get the number of variations when the parameters are unpacked. If no parameter was marked to be unpacked, then return 1. If this SimulationParameters object is actually a 'unpacked variation' of another SimulationParameters object, return the number of variations of the parent SimulationParameters object instead. Returns ------- num : int The number of variations when the parameters are unpacked. """ # If self._original_sim_params is not None, that means that this # SimulationParameters object is in fact one of the unpacked # variations of another SimulationParameters object. In that case, # we return the number of unpacked variations of the original # object. if self._original_sim_params is not None: return self._original_sim_params.get_num_unpacked_variations() if len(self._unpacked_parameters_set) == 0: return 1 # Generator for the lengths of the parameters set to be # unpacked gen_values = (len(self.parameters[i]) for i in self._unpacked_parameters_set) # Just multiply all the lengths return functools.reduce(operator.mul, gen_values)
[docs] def get_pack_indexes(self, fixed_params_dict=None): """ When you call the function get_unpacked_params_list you get a list of SimulationParameters objects corresponding to all combinations of the parameters. The function get_pack_indexes allows you to provided all parameters marked to be unpacked except one, and returns the indexes of the list returned by get_unpacked_params_list that you want. Parameters ---------- fixed_params_dict : dict[str, anything] A dictionary with the name of the fixed parameters as keys and the fixed value as value. Returns ------- indexes : np.ndarray The desired indexes (1D numpy array or an integer). Examples -------- Suppose we have >>> p={'p1':[1,2,3], 'p2':['a','b'],'p3':15} >>> params=SimulationParameters.create(p) >>> params.set_unpack_parameter('p1') >>> params.set_unpack_parameter('p2') If we call params.get_unpacked_params_list we will get a list of six SimulationParameters objects, one for each combination of the values of p1 and p2. That is, >>> len(params.get_unpacked_params_list()) 6 Likewise, in the simulation the :class:`.SimulationRunner` object will return a list of results in the order corresponding to the order of the list of parameters. The get_pack_indexes is used to get the index of the results corresponding to a specific configuration of parameters. Suppose now you want the results when 'p2' is varying, but with the other parameters fixed to some specific value. For this create a dictionary specifying all parameters except 'p2' and call get_pack_indexes with this dictionary. You will get an array of indexes that can be used in the results list to get the desired results. For instance >>> fixed={'p1':3,'p3':15} >>> indexes = params.get_pack_indexes(fixed) >>> index0 = indexes[0] >>> index1 = indexes[1] >>> unpacked_list = params.get_unpacked_params_list() >>> unpacked_list[index0]['p1'] 3 >>> unpacked_list[index0]['p3'] 15 >>> unpacked_list[index1]['p1'] 3 >>> unpacked_list[index1]['p3'] 15 """ if fixed_params_dict is None: # pragma: no cover fixed_params_dict = {} # Get the only parameter that was not fixed varying_param = list(self._unpacked_parameters_set - set(fixed_params_dict.keys())) # List to store the indexes (as strings) of the fixed parameters, # as well as ":" for the varying parameter, param_indexes = [] # Note that self.unpacked_parameters is a sorted list, which # guarantees a predictable order for i in self.unpacked_parameters: if i in varying_param: param_indexes.append(':') else: fixed_param_value_index = list(self.parameters[i]).index( fixed_params_dict[i]) param_indexes.append(str(fixed_param_value_index)) # xxxxx Get the indexes xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # For this we create a auxiliary numpy array going from 0 to the # number of unpack variations. Then we use param_indexes to build a # string that we can evaluate using the auxiliary numpy array in # order to get the linear indexes. # Get the lengths of the parameters marked to be unpacked dimensions = [ len(self.parameters[i]) for i in self.unpacked_parameters ] aux = np.arange(0, self.get_num_unpacked_variations()) aux.shape = dimensions indexes = eval("aux" + "[{0}]".format(",".join(param_indexes))).flatten() # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # if indexes.size == 1: # indexes = indexes[0] return indexes
[docs] def get_unpacked_params_list(self): """ Get a list of SimulationParameters objects, each one corresponding to a possible combination of (unpacked) parameters. Returns ------- list[SimulationParameters] A list of SimulationParameters objects. Examples -------- Suppose you have a SimulationParameters object with the parameters 'a', 'b', 'c' and 'd' as below >>> simparams = SimulationParameters() >>> simparams.add('a', 1) >>> simparams.add('b', 2) >>> simparams.add('c', [3, 4]) >>> simparams.add('d', [5, 6]) and the parameters 'c' and 'd' were set to be unpacked. >>> simparams.set_unpack_parameter('c') >>> simparams.set_unpack_parameter('d') Then get_unpacked_params_list would return a list of four SimulationParameters objects as below >>> len(simparams.get_unpacked_params_list()) 4 That is .. code-block:: python [{'a': 1, 'c': 3, 'b': 2, 'd': 5}, {'a': 1, 'c': 3, 'b': 2, 'd': 6}, {'a': 1, 'c': 4, 'b': 2, 'd': 5}, {'a': 1, 'c': 4, 'b': 2, 'd': 6}] """ # If unpacked_parameters is empty, return self if not self._unpacked_parameters_set: return [self] # Lambda function to get an iterator to a (iterable) parameter # given its name. This only works if self.parameters[name] is an # iterable. def get_iter_from_name(name): return iter(self.parameters[name]) # Dictionary that stores the name and an iterator of a parameter # marked to be unpacked unpacked_params_iter_dict = OrderedDict() # The sorted function is important to guarantee that the keys # returned from _unpacked_parameters_set will have a predictable # order for i in sorted(self._unpacked_parameters_set): unpacked_params_iter_dict[i] = get_iter_from_name(i) keys = list(unpacked_params_iter_dict.keys()) # Using itertools.product we can convert the multiple iterators # (for the different parameters marked to be unpacked) to a single # iterator that returns all the possible combinations (cartesian # product) of the individual iterators. all_combinations = itertools.product( *(unpacked_params_iter_dict.values())) # Names of the parameters that don't need to be unpacked regular_params = (set(self.parameters.keys()) - self._unpacked_parameters_set) # Constructs a list with dictionaries, where each dictionary # corresponds to a possible parameters combination unpack_params_length = len(self._unpacked_parameters_set) all_possible_dicts_list = [] for comb in all_combinations: new_dict = {} # Add current combination of the unpacked parameters for index in range(unpack_params_length): new_dict[keys[index]] = comb[index] # Add the regular parameters for param in regular_params: new_dict[param] = self.parameters[param] all_possible_dicts_list.append(new_dict) # Map the list of dictionaries to a list of SimulationParameters # objects and return it. # # Note that since we are passing the index "i" to each new object # in the list as well as the original SimulationParameters object # "self", then each SimulationParameters object in the returned # list will know its index in that list (the _unpack_index # variable) as well as the original SimulationParameters object # from where it came from (stored in the _original_sim_params # variable). sim_params_list = [ SimulationParameters._create(v, i, self) for i, v in enumerate(all_possible_dicts_list) ] return sim_params_list
[docs] def save_to_pickled_file(self, filename): """ Save the SimulationParameters object to the file `filename` using pickle. Parameters ---------- filename : str Name of the file to save the parameters. """ with open(filename, 'wb') as output: pickle.dump(self, output, protocol=2)
[docs] @staticmethod def load_from_pickled_file(filename): """ Load the SimulationParameters from the file 'filename' previously stored (using pickle) with `save_to_pickled_file`. Parameters ---------- filename : str Name of the file from where the results will be loaded. Returns ------- SimulationParameters The loaded SimulationParameters object. """ with open(filename, 'rb') as input_file: obj = pickle.load(input_file) return obj
[docs] @staticmethod def load_from_config_file(filename, spec=None, save_parsed_file=False): """ Load the SimulationParameters from a config file using the configobj module. If the config file has a parameter called ``unpacked_parameters``, which should be a list of strings with the names of other parameters, then these parameters will be set to be unpacked. Parameters ---------- filename : str Name of the file from where the results will be loaded. spec : list[str], optional A list of strings with the config spec. See "validation" in the configobj module documentation for more info. save_parsed_file : bool If `save_parsed_file` is True, then the parsed config file will be written back to disk. This will add any missing values in the config file whose default values are provided in the `spec`. This will even create the file if all default values are provided in `spec` and the file does not exist yet. Notes ----- Besides the usual checks that the configobj validation has such as ``integer``, ``string``, ``option``, etc., you can also use `real_numpy_array` for numpy float arrays. Note that when this validation function is used you can set the array in the config file in several ways such as SNR=0,5,10,15:20 for instance. """ if spec is None: spec = [] # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx def add_params(simulation_params, config): """ Add the parameters in `config`. Parameters ---------- simulation_params : SimulationParameters The SimulationParameters object where the parameters will be added. config : configobj.ConfigObj | configobj.Section A ConfigObj object or a Section object. The `config` object can contain parameters (called scalars) or sections which can contain either parameters or other sections. """ # Add scalar parameters for v in config.scalars: simulation_params.add(v, config[v]) for s in config.sections: add_params(simulation_params, config[s]) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx conf_file_parser = ConfigObj(filename, list_values=True, configspec=spec) # Dictionary with custom validation functions. Here we add a # validation function for numpy float arrays. fdict = { 'real_numpy_array': real_numpy_array_check, 'integer_numpy_array': integer_numpy_array_check, 'integer_scalar_or_integer_numpy_array_check': integer_scalar_or_integer_numpy_array_check, 'real_scalar_or_real_numpy_array_check': real_scalar_or_real_numpy_array_check } validator = Validator(fdict) # The 'copy' argument indicates that if we save the ConfigObj # object to a file after validating, the default values will also # be written to the file. result = conf_file_parser.validate(validator, preserve_errors=True, copy=True) # Note that if there was no parsing errors, then "result" will be # 'True'. It there was an error, then result will be a dictionary # with each parameter as a key. The value of each key will be # either 'True' if that parameter was parsed without error or a # "validate.something" object (since we set preserve_errors to # True) describing the error. # if result != True: # print 'Config file validation failed!' # sys.exit(1) # xxxxx Test if there was some error in parsing the file xxxxxxxxxx # The flatten_errors function will return only the parameters whose # parsing failed. errors_list = flatten_errors(conf_file_parser, result) if len(errors_list) != 0: first_error = errors_list[0] # The exception will only describe the error for the first # incorrect parameter. if first_error[2] is False: msg = ("Error loading file {0}. Parameter '{1}' in section " "'{2}' must be provided.") raise Exception( msg.format(filename, first_error[1], first_error[0][0])) msg = ("Error loading file {0}. Parameter '{1}' in section " "'{2}' is invalid. {3}") raise Exception( msg.format(filename, first_error[1], first_error[0][0], str(first_error[2]).capitalize())) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxx Finally add the parsed parameters to the params object xxxx params = SimulationParameters() add_params(params, conf_file_parser) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx if save_parsed_file is True: # pragma: no cover # xxxxx Write the parsed config file to disk xxxxxxxxxxxxxxxxxx # This will add the default values if they are not present. If # the file does not exist yet and all default values are # provided in the spec then the file will be created. If some # parameter without a default value was not provided then when # exception would already have been thrown and we wouldn't be # here. conf_file_parser.write() # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # If the special parameter 'unpacked_parameters' is in the config # file, then we will set the parameters whose name are in it to be # unpacked try: unpacked_parameters_list = params['unpacked_parameters'] except KeyError: unpacked_parameters_list = [] for name in unpacked_parameters_list: params.set_unpack_parameter(name) # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx return params
[docs] def _to_dict(self): """ Convert the SimulationParameters object to a dictionary for easier further serialization. """ original_sim_params = self._original_sim_params ":type: SimulationParameters" if original_sim_params is not None: original_sim_params = original_sim_params._to_dict() out = { 'parameters': self.parameters, 'unpacked_parameters_set': self._unpacked_parameters_set, 'unpack_index': self.unpack_index, 'original_sim_params': original_sim_params } return out
[docs] @staticmethod def _from_dict(d): """ Create a new SimulationParameters object from a dictionary. Parameters ---------- d : dict The dictionary with the data. Returns ------- SimulationParameters The new SimulationParameters object. """ sim_params = SimulationParameters() sim_params.parameters = d['parameters'] sim_params._unpacked_parameters_set = d['unpacked_parameters_set'] sim_params._unpack_index = d['unpack_index'] original_sim_params = d['original_sim_params'] if original_sim_params is not None: original_sim_params = SimulationParameters._from_dict( original_sim_params) sim_params._original_sim_params = original_sim_params return sim_params
# xxxxxxxxxx SimulationParameters - END xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx