Source code for openmdao.main.hasparameters

import ordereddict

from openmdao.main.expreval import ExprEvaluator
from openmdao.util.typegroups import real_types, int_types

try:
    from numpy import array, ndarray, ndindex, ones
except ImportError as err:
    import logging
    logging.warn("In %s: %r", __file__, err)
    from openmdao.main.numpy_fallback import array, ndarray, ones

__missing = object()


[docs]class ParameterBase(object): """Abstract base class for parameters.""" def __init__(self, target, high=None, low=None, scaler=None, adder=None, start=None, fd_step=None, scope=None, name=None, _expreval=None): """If scaler and/or adder are not None, then high, low, and start, if not None, are assumed to be expressed in unscaled form. If high and low are not supplied, then their values will be pulled from the target variable (along with a start value), and are assumed to be in scaled form, so their values will be unscaled prior to being stored in the Parameter. """ if scaler is None and adder is None: self._transform = self._do_nothing self._untransform = self._do_nothing if scaler is None: scaler = 1.0 if adder is None: adder = 0.0 self.low = low self.high = high self.scaler = scaler self.adder = adder self.start = start self.fd_step = fd_step self.name = name or target if _expreval is None: try: _expreval = ExprEvaluator(target, scope) except Exception as err: raise err.__class__("Can't add parameter: %s" % str(err)) if not _expreval.is_valid_assignee(): raise ValueError("Can't add parameter: '%s' is not a valid" " parameter expression" % _expreval.text) self._expreval = _expreval try: self._metadata = self._expreval.get_metadata() except AttributeError: raise AttributeError("Can't add parameter '%s' because it doesn't" " exist." % target) # 'raw' metadata is in the form [(varname, metadata)], # so use [0][1] to get the actual metadata dict metadata = self._metadata[0][1] if 'iotype' in metadata and metadata['iotype'] == 'out': raise RuntimeError("Can't add parameter '%s' because '%s' is an" " output." % (target, target)) try: # So, our traits might not have a vartypename? self.vartypename = metadata['vartypename'] except KeyError: self.vartypename = None def __str__(self): return self._expreval.text def _transform(self, val): """ Unscales the variable (parameter space -> var space). """ return (val + self.adder) * self.scaler def _untransform(self, val): """ Scales the variable (var space -> parameter space). """ return val / self.scaler - self.adder def _do_nothing(self, val): """ Used to overlay _transform and _untransform. """ return val def _get_scope(self): """Return scope of target expression.""" return self._expreval.scope @property
[docs] def target(self): """The target of this parameter.""" return self._expreval.text
@property
[docs] def targets(self): """A one element list containing the target of this parameter.""" return [self._expreval.text]
[docs] def initialize(self, scope): """Set parameter to initial value.""" if self.start is None: self.set(self._untransform(self._expreval.evaluate(scope))) else: self.set(self.start, scope)
[docs] def set(self, value, scope=None): """Assigns the given value to the array referenced by this parameter, must be overridden.""" raise NotImplementedError('set')
[docs] def get_metadata(self, metaname=None): """Returns a list of tuples of the form (varname, metadata), with one entry for each variable referenced by the parameter expression. The metadata value found in the tuple will be either the specified piece of metadata, if metaname is provided, or the whole metadata dictionary for that variable if it is not. """ if metaname is None: return self._metadata[0] else: return [(name, self._metadata.get(metaname)) for name, val in self._metadata]
[docs] def get_referenced_compnames(self): """Return a set of Component names based on the pathnames of Variables referenced in our target string. """ return self._expreval.get_referenced_compnames()
[docs] def get_referenced_varpaths(self): """Return a set of Variable names referenced in our target string.""" return self._expreval.get_referenced_varpaths(copy=False)
[docs] def get_config(self): """Return configuration arguments.""" return (self.target, self.low, self.high, self.fd_step, self.scaler, self.adder, self.start, self.name)
[docs]class Parameter(ParameterBase): """ A scalar parameter. """ def __init__(self, target, high=None, low=None, scaler=None, adder=None, start=None, fd_step=None, scope=None, name=None, _expreval=None, _val=None): """If scaler and/or adder are not None, then high, low, and start, if not None, are assumed to be expressed in unscaled form. If high and low are not supplied, then their values will be pulled from the target variable (along with a start value), and are assumed to be in scaled form, so their values will be unscaled prior to being stored in the Parameter. """ super(Parameter, self).__init__(target, high, low, scaler, adder, start, fd_step, scope, name, _expreval) if scaler is not None: try: scaler = float(scaler) except (TypeError, ValueError): raise ValueError("Bad value given for parameter's 'scaler'" " attribute.") if adder is not None: try: adder = float(adder) except (TypeError, ValueError): raise ValueError("Bad value given for parameter's 'adder'" " attribute.") if _val is None: try: _val = self._expreval.evaluate() except Exception: raise ValueError("Can't add parameter because I can't evaluate" " '%s'." % target) self.valtypename = type(_val).__name__ if self.vartypename == 'Enum': return # it's an Enum, so no need to set high or low if not isinstance(_val, real_types) and not isinstance(_val, int_types): raise ValueError("The value of parameter '%s' must be a real or" " integral type, but its type is '%s'." % (target, type(_val).__name__)) # metadata is in the form (varname, metadata), so use [1] to get # the actual metadata dict metadata = self.get_metadata()[1] meta_low = metadata.get('low') # this will be None if 'low' isn't there if meta_low is not None: if low is None: self.low = self._untransform(meta_low) elif low < self._untransform(meta_low): raise ValueError("Trying to add parameter '%s', but the lower" " limit supplied (%s) exceeds the built-in" " lower limit (%s)." % (target, low, meta_low)) else: if low is None: raise ValueError("Trying to add parameter '%s', " "but no lower limit was found and no " "'low' argument was given. One or the " "other must be specified." % target) meta_high = metadata.get('high') # will be None if 'high' isn't there if meta_high is not None: if high is None: self.high = self._untransform(meta_high) elif high > self._untransform(meta_high): raise ValueError("Trying to add parameter '%s', but the upper" " limit supplied (%s) exceeds the built-in" " upper limit (%s)." % (target, high, meta_high)) else: if high is None: raise ValueError("Trying to add parameter '%s', " "but no upper limit was found and no " "'high' argument was given. One or the " "other must be specified." % target) if self.low > self.high: raise ValueError("Parameter '%s' has a lower bound (%s) that" " exceeds its upper bound (%s)" % (target, self.low, self.high)) def __eq__(self, other): if not isinstance(other, Parameter): return False return (self._expreval,self.scaler,self.adder,self.low,self.high,self.fd_step,self.start,self.name) == \ (other._expreval,other.scaler,other.adder,other.low,other.high,other.fd_step,other.start,self.name) def __repr__(self): return '<Parameter(target=%s,low=%s,high=%s,fd_step=%s,scaler=%s,adder=%s,start=%s,name=%s)>' % \ self.get_config() @property
[docs] def names(self): """A one element list containing the name of this parameter.""" return [self.name]
@property
[docs] def size(self): """Total scalar items in this parameter.""" return 1
[docs] def get_high(self): """Returns upper limits as a sequence.""" return [self.high]
[docs] def get_low(self): """Returns lower limits as a sequence.""" return [self.low]
[docs] def get_fd_step(self): """Returns finite difference step size as a sequence.""" return [self.fd_step]
[docs] def evaluate(self, scope=None): """Returns the value of this parameter as a sequence.""" return [self._untransform(self._expreval.evaluate(scope))]
[docs] def set(self, val, scope=None): """Assigns the given value to the target of this parameter.""" self._expreval.set(self._transform(val), scope)
[docs] def copy(self): """Return a copy of this Parameter.""" return Parameter(self._expreval.text, high=self.high, low=self.low, scaler=self.scaler, adder=self.adder, start=self.start, fd_step=self.fd_step, scope=self._get_scope(), name=self.name)
[docs] def override(self, low=None, high=None, scaler=None, adder=None, start=None, fd_step=None, name=None): """Called by add_parameter() when the target is this Parameter.""" if low is not None: self.low = low if high is not None: self.high = high if scaler is not None: self.scaler = scaler if adder is not None: self.adder = adder if start is not None: self.start = start if fd_step is not None: self.fd_step = fd_step if name is not None: self.name = name
[docs]class ParameterGroup(object): """A group of Parameters that are treated as one, i.e., they are all set to the same value. """ def __init__(self, params): for param in params: # prevent multiply nested ParameterGroups if not isinstance(param, (Parameter, ArrayParameter)): raise ValueError("tried to add a non-Parameter object to a" " ParameterGroup") self._params = params[:] param0 = self._params[0] self.low = max([x.low for x in self._params]) self.high = min([x.high for x in self._params]) self.start = param0.start self.scaler = param0.scaler self.adder = param0.adder self.fd_step = param0.fd_step self.name = param0.name self.typename = param0.valtypename def __eq__(self, other): if not isinstance(other, ParameterGroup): return False return (self._params,self.low,self.high,self.start,self.scaler,self.adder,self.fd_step,self.name) == \ (other._params,other.low,other.high,other.start,other.scaler,other.adder,other.fd_step,self.name) def __str__(self): return "%s" % self.targets def __repr__(self): return '<ParameterGroup(targets=%s,low=%s,high=%s,fd_step=%s,scaler=%s,adder=%s,start=%s,name=%s)>' % \ (self.targets, self.low, self.high, self.fd_step, self.scaler, self.adder, self.start, self.name) @property
[docs] def names(self): """A one element list containing the name of this parameter.""" return self._params[0].names
@property
[docs] def size(self): """Total scalar items in this parameter.""" return self._params[0].size
@property
[docs] def target(self): """The target of the first parameter in the group.""" return self._params[0].target
@property
[docs] def targets(self): """A list containing the targets of this parameter.""" return [p.target for p in self._params]
[docs] def get_high(self): """Returns upper limits as a sequence.""" return self._params[0].get_high()
[docs] def get_low(self): """Returns lower limits as a sequence.""" return self._params[0].get_low()
[docs] def get_fd_step(self): """Returns finite difference step size as a sequence.""" return self._params[0].get_fd_step()
[docs] def set(self, value, scope=None): """Set all targets to the given value.""" for param in self._params: param.set(value, scope)
[docs] def evaluate(self, scope=None): """Return the value of the first parameter in our target list as a sequence. Values of all of our targets are assumed to be the same. """ return self._params[0].evaluate(scope)
[docs] def get_metadata(self, metaname=None): """Returns a list of tuples of the form (varname, metadata), with one entry for each variable referenced by a target expression. The metadata value found in the tuple will be either the specified piece of metadata, if metaname is provided, or the whole metadata dictionary for that variable if it is not. """ dct = {'low':self.low, 'high':self.high, 'start':self.start, 'scaler':self.scaler, 'adder':self.adder, 'fd_step':self.fd_step, 'name':self.name} if metaname is not None: val = dct.get(metaname, __missing) if val is __missing: val = None return [(p.target, val) for p in self._params] else: return [(p.target, dct) for p in self._params]
[docs] def get_referenced_compnames(self): """Return a set of Component names based on the pathnames of Variables referenced in our target strings. """ result = set() for param in self._params: result.update(param.get_referenced_compnames()) return result
[docs] def get_referenced_vars_by_compname(self): """Return a mapping from component name to referencing parameters.""" result = dict() for param in self._params: comp = param.get_referenced_compnames().pop() try: result[comp].update([param,]) except KeyError: result[comp] = set([param,]) return result
[docs] def get_referenced_varpaths(self): """Return a set of Variable names referenced in our target strings.""" result = set() for param in self._params: result.update(param.get_referenced_varpaths()) return result
[docs] def copy(self): """Return a copy of this ParameterGroup.""" return ParameterGroup([p.copy() for p in self._params])
[docs] def get_config(self): """Return list of configuration argument tuples.""" return [p.get_config() for p in self._params]
def _get_scope(self): """Return scope of first parameter in group.""" return self._params[0]._get_scope()
[docs] def override(self, low=None, high=None, scaler=None, adder=None, start=None, fd_step=None, name=None): """Called by add_parameter() when the target is this ParameterGroup.""" if low is not None: self.low = low if high is not None: self.high = high if scaler is not None: self.scaler = scaler if adder is not None: self.adder = adder if start is not None: self.start = start if fd_step is not None: self.fd_step = fd_step if name is not None: self.name = name
[docs] def initialize(self, scope): """Set parameter to initial value.""" for param in self._params: param.initialize(scope)
[docs]class ArrayParameter(ParameterBase): """A parameter whose target is an array. If scaler and/or adder are not None, then high, low, and start, if not None, are assumed to be expressed in unscaled form. If high and low are not supplied, then their values will be pulled from the target variable (along with a start value), and are assumed to be in scaled form, so their values will be unscaled prior to being stored in the ArrayParameter. """ def __init__(self, target, high=None, low=None, scaler=None, adder=None, start=None, fd_step=None, scope=None, name=None, _expreval=None, _val=None): super(ArrayParameter, self).__init__(target, high, low, scaler, adder, start, fd_step, scope, name, _expreval) if _val is None: try: _val = self._expreval.evaluate() except Exception: raise ValueError("Can't add parameter because I can't evaluate" " '%s'." % target) self.valtypename = _val.dtype.name if _val.dtype.kind not in ('fi'): raise TypeError('Only float or int arrays are supported') dtype = self.dtype = _val.dtype self.shape = _val.shape self._size = _val.size # Use scalar arithmetic for transform/untransform if possible. if scaler is None: self._scaler = 1. else: _scaler = self._convert_sequence(scaler, dtype) if isinstance(_scaler, ndarray): self._scaler = _scaler else: self._scaler = float(scaler) if adder is None: self._adder = 0. else: _adder = self._convert_sequence(adder, dtype) if isinstance(_adder, ndarray): self._adder = _adder else: self._adder = float(adder) high = self._convert_sequence(high, dtype) low = self._convert_sequence(low, dtype) # metadata is in the form (varname, metadata), so use [1] to get # the actual metadata dict metadata = self.get_metadata()[1] meta_low = self._convert_sequence(metadata.get('low'), dtype) meta_high = self._convert_sequence(metadata.get('high'), dtype) highs = [] lows = [] for i in range(_val.size): _high = self._fetch('high', high, i) _low = self._fetch('low', low, i) if meta_low is not None: _meta_low = self._fetch('meta_low', meta_low, i) if _low is None: _low = self._untransform(_meta_low) elif _low < self._untransform(_meta_low): raise ValueError("Trying to add parameter '%s', but the" " lower limit supplied (%s) exceeds the" " built-in lower limit (%s)." % (target, _low, _meta_low)) else: if _low is None: raise ValueError("Trying to add parameter '%s'," " but no lower limit was found and no" " 'low' argument was given. One or the" " other must be specified." % target) if meta_high is not None: _meta_high = self._fetch('meta_high', meta_high, i) if _high is None: _high = self._untransform(_meta_high) elif _high > self._untransform(_meta_high): raise ValueError("Trying to add parameter '%s', but the" " upper limit supplied (%s) exceeds the" " built-in upper limit (%s)." % (target, _high, _meta_high)) else: if _high is None: raise ValueError("Trying to add parameter '%s'," " but no upper limit was found and no" " 'high' argument was given. One or the" " other must be specified." % target) if _low > _high: raise ValueError("Parameter '%s' has a lower bound (%s) that" " exceeds its upper bound (%s)" % (target, _low, _high)) highs.append(_high) lows.append(_low) self._high = array(highs, dtype) self._low = array(lows, dtype) @staticmethod def _convert_sequence(val, dtype): """Convert sequence to array of dtype.""" if isinstance(val, (list, tuple)): val = array(val, dtype).ravel() return val def _fetch(self, attr, val, i): """Fetch value for ith element of val (if it's an array).""" if isinstance(val, ndarray): if val.size == self._size: return val.flat[i] else: raise ValueError('%r size is %s but parameter size is %s' % (attr, val.size, self._size)) else: return val def __eq__(self, other): if not isinstance(other, ArrayParameter): return False return self.get_config() == other.get_config() def __repr__(self): return '<ArrayParameter(target=%s,low=%s,high=%s,fd_step=%s,scaler=%s,adder=%s,start=%s,name=%s)>' \ % self.get_config() @property
[docs] def names(self): """A list containing the names of this parameter's scalar items.""" names = [] for index in ndindex(*self.shape): index = ''.join(['[%s]' % i for i in index]) names.append('%s%s' % (self.name, index)) return names
@property
[docs] def size(self): """Total scalar items in this parameter.""" return self._size
[docs] def get_high(self): """Returns upper limits as a sequence.""" return self._high
[docs] def get_low(self): """Returns lower limits as a sequence.""" return self._low
[docs] def get_fd_step(self): """Returns finite difference step size as a sequence.""" _fd_step = self._convert_sequence(self.fd_step, self.dtype) if isinstance(_fd_step, ndarray): return _fd_step.ravel() else: return [self.fd_step] * self._size
[docs] def evaluate(self, scope=None): """Returns the value of this parameter as a sequence.""" # Use .flatten() rather than .flat to force a copy. # Forcing a copy to isolate data ownership. return self._untransform(self._expreval.evaluate(scope)).flatten()
[docs] def set(self, value, scope=None): """Assigns the given value to the array referenced by this parameter.""" copied = False if isinstance(value, (list, tuple)): value = self._convert_sequence(value, self.dtype) copied = True if isinstance(value, ndarray): if value.size == self._size: value = value.reshape(self.shape) if not copied: # Forcing a copy to isolate data ownership. value = value.copy() else: raise ValueError('value size is %s but parameter size is %s' % (value.size, self._size)) else: value = value * ones(self.shape, self.dtype) self._expreval.set(self._transform(value), scope)
[docs] def copy(self): """Return a copy of this ParameterArray.""" return ArrayParameter(self.target, high=self.high, low=self.low, scaler=self.scaler, adder=self.adder, start=self.start, fd_step=self.fd_step, scope=self._get_scope(), name=self.name)
[docs] def override(self, low=None, high=None, scaler=None, adder=None, start=None, fd_step=None, name=None): """Called by add_parameter() when the target is this ArrayParameter.""" self._override('low', low) self._override('high', high) self._override('scaler', scaler) self._override('adder', adder) self._override('start', start) self._override('fd_step', fd_step) if name is not None: self.name = name
def _override(self, attr, val): """Helper for override().""" if val is not None: val = self._convert_sequence(val, self.dtype) if isinstance(val, ndarray): if val.size != self._size: raise ValueError('%s size is %s but parameter size is %s' % (attr, val.size, self._size)) val = val.ravel() setattr(self, attr, val) # Set 'external' attribute. if attr in ('low', 'high', 'fd_step'): # Force array. if not isinstance(val, ndarray): val = val * ones(self._size, self.dtype) setattr(self, '_'+attr, val) # Set 'internal' attribute.
[docs]class HasParameters(object): """This class provides an implementation of the IHasParameters interface.""" _do_not_promote = ['get_expr_depends', 'get_referenced_compnames', 'get_referenced_varpaths', 'get_metadata'] def __init__(self, parent): self._parameters = ordereddict.OrderedDict() self._parent = parent self._allowed_types = ['continuous'] def _item_count(self): """This is used by the replace function to determine if a delegate from the target object is 'empty' or not. If it's empty, it's not an error if the replacing object doesn't have this delegate. """ return len(self._parameters)
[docs] def add_parameter(self, target, low=None, high=None, scaler=None, adder=None, start=None, fd_step=None, name=None, scope=None): """Adds a parameter or group of parameters to the driver. target: string or iter of strings or Parameter What the driver should vary during execution. A *target* is an expression that can reside on the left-hand side of an assignment statement, so typically it will be the name of a variable or possibly a subscript expression indicating an entry within an array variable, e.g., x[3]. If an iterator of targets is given, then the driver will set all targets given to the same value whenever it varies this parameter during execution. If a Parameter instance is given, then that instance is copied into the driver with any other arguments specified, overiding the values in the given parameter. low: float (optional) Minimum allowed value of the parameter. If scaler and/or adder is supplied, use the transformed value here. If target is an array, this may also be an array, but must have the same size. high: float (optional) Maximum allowed value of the parameter. If scaler and/or adder is supplied, use the transformed value here. If target is an array, this may also be an array, but must have the same size. scaler: float (optional) Value to multiply the possibly offset parameter value by. If target is an array, this may also be an array, but must have the same size. adder: float (optional) Value to add to parameter prior to possible scaling. If target is an array, this may also be an array, but must have the same size. start: any (optional) Value to set into the target or targets of a parameter before starting any executions. If not given, analysis will start with whatever values are in the target or targets at that time. If target is an array, this may also be an array, but must have the same size. fd_step: float (optional) Step-size to use for finite difference calculation. If no value is given, the differentiator will use its own default. If target is an array, this may also be an array, but must have the same size. name: str (optional) Name used to refer to the parameter in place of the name of the variable referred to in the parameter string. This is sometimes useful if, for example, multiple entries in the same array variable are declared as parameters. scope: object (optional) The object to be used as the scope when evaluating the expression. If neither "low" nor "high" is specified, the min and max will default to the values in the metadata of the variable being referenced. If they are not specified in the metadata and not provided as arguments, a ValueError is raised. """ if self._parent.parent: parent_cnns = self._parent.parent.list_connections() for lhs, rhs in parent_cnns: if rhs == target: self._parent.raise_exception("'%s' is already a Parameter" " target" % target, RuntimeError) if isinstance(target, (ParameterBase, ParameterGroup)): self._parameters[target.name] = target target.override(low, high, scaler, adder, start, fd_step, name) else: if isinstance(target, basestring): names = [target] key = target else: names = target key = tuple(target) if name is not None: key = name dups = set(self.list_param_targets()).intersection(names) if len(dups) == 1: self._parent.raise_exception("'%s' is already a Parameter" " target" % dups.pop(), ValueError) elif len(dups) > 1: self._parent.raise_exception("%s are already Parameter targets" % sorted(list(dups)), ValueError) if key in self._parameters: self._parent.raise_exception("%s is already a Parameter" % key, ValueError) try: _scope = self._get_scope(scope) if len(names) == 1: target = self._create(names[0], low, high, scaler, adder, start, fd_step, key, _scope) else: # defining a ParameterGroup parameters = [self._create(n, low, high, scaler, adder, start, fd_step, key, _scope) for n in names] types = set([p.valtypename for p in parameters]) if len(types) > 1: raise ValueError("Can't add parameter %s because " "%s are not all of the same type" % (key," and ".join(names))) target = ParameterGroup(parameters) self._parameters[key] = target except Exception as err: self._parent.reraise_exception() self._parent.config_changed()
def _create(self, target, low, high, scaler, adder, start, fd_step, key, scope): """ Create one Parameter or ArrayParameter. """ try: expreval = ExprEvaluator(target, scope) except Exception as err: raise err.__class__("Can't add parameter: %s" % err) if not expreval.is_valid_assignee(): raise ValueError("Can't add parameter: '%s' is not a" " valid parameter expression" % expreval.text) try: val = expreval.evaluate() except Exception as err: val = None # Let Parameter code sort out why. name = key[0] if isinstance(key, tuple) else key if isinstance(val, ndarray): return ArrayParameter(target, low=low, high=high, scaler=scaler, adder=adder, start=start, fd_step=fd_step, name=name, scope=scope, _expreval=expreval, _val=val) else: return Parameter(target, low=low, high=high, scaler=scaler, adder=adder, start=start, fd_step=fd_step, name=name, scope=scope, _expreval=expreval, _val=val)
[docs] def remove_parameter(self, name): """Removes the parameter with the given name.""" param = self._parameters.get(name) if param: del self._parameters[name] else: self._parent.raise_exception("Trying to remove parameter '%s' " "that is not in this driver." % (name,), AttributeError) self._parent.config_changed()
[docs] def get_references(self, name): """Return references to component `name` in preparation for subsequent :meth:`restore_references` call. name: string Name of component being removed. """ refs = ordereddict.OrderedDict() for pname, param in self._parameters.items(): if name in param.get_referenced_compnames(): refs[pname] = param return refs
[docs] def remove_references(self, name): """Remove references to component `name`. name: string Name of component being removed. """ to_remove = [] for pname, param in self._parameters.items(): if name in param.get_referenced_compnames(): to_remove.append(pname) for pname in to_remove: self.remove_parameter(pname)
[docs] def restore_references(self, refs): """Restore references to component `name` from `refs`. refs: object Value returned by :meth:`get_references`. """ for pname, param in refs.items(): try: self.add_parameter(param) except Exception as err: self._parent._logger.warning("Couldn't restore parameter '%s': %s" % (pname, str(err)))
[docs] def list_param_targets(self): """Returns a list of parameter targets. Note that this list may contain more entries than the list of Parameter, ParameterGroup, and ArrayParameter objects since ParameterGroup instances have multiple targets. """ targets = [] for param in self._parameters.values(): targets.extend(param.targets) return targets
[docs] def list_param_group_targets(self): """Returns a list of tuples that contain the targets for each parameter group. """ targets = [] for param in self.get_parameters().values(): targets.append(tuple(param.targets)) return targets
[docs] def clear_parameters(self): """Removes all parameters.""" for name in self._parameters.keys(): self.remove_parameter(name) self._parameters = ordereddict.OrderedDict()
[docs] def get_parameters(self): """Returns an ordered dict of parameter objects.""" return self._parameters
[docs] def total_parameters(self): """Returns the total number of values to be set.""" return sum([param.size for param in self._parameters.values()])
[docs] def init_parameters(self): """Sets all parameters to their start value if a start value is given """ scope = self._get_scope() for param in self._parameters.itervalues(): if param.start is not None: param.set(param.start, scope) self._parent._invalidate()
[docs] def set_parameter_by_name(self, name, value, case=None, scope=None): """Sets a single parameter by its name attribute. name: str Name of the parameter. This is either the name alias given when the parameter was added or the variable path of the parameter's target if no name was given. value: object (typically a float) Value of the parameter to be set. case: Case (optional) If supplied, the values will be associated with their corresponding targets and added as inputs to the Case instead of being set directly into the model. """ param = self._parameters[name] if case is None: param.set(value, self._get_scope(scope)) else: for target in param.targets: case.add_input(target, value) return case
[docs] def set_parameters(self, values, case=None, scope=None): """Pushes the values in the iterator 'values' into the corresponding variables in the model. If the 'case' arg is supplied, the values will be set into the case and not into the model. values: iterator Iterator of input values with an order defined to match the order of parameters returned by the get_parameters method. All 'values' must support the len() function. case: Case (optional) If supplied, the values will be associated with their corresponding targets and added as inputs to the Case instead of being set directly into the model. """ if len(values) != self.total_parameters(): raise ValueError("number of input values (%s) != expected number of" " values (%s)" % (len(values), self.total_parameters())) if case is None: scope = self._get_scope(scope) start = 0 for param in self._parameters.values(): size = param.size if size == 1: param.set(values[start], scope) start += 1 else: end = start + size param.set(values[start:end], scope) start = end else: start = 0 for param in self._parameters.values(): size = param.size if size == 1: for target in param.targets: case.add_input(target, values[start]) start += 1 else: end = start + size for target in param.targets: case.add_input(target, values[start:end]) start = end return case
[docs] def eval_parameters(self, scope=None, dtype='d'): """Return evaluated parameter values. dtype: string or None If not None, return an array of this dtype. Otherwise just return a list (useful if parameters may be of different types). """ result = [] for param in self._parameters.values(): result.extend(param.evaluate(scope)) if dtype: result = array(result, dtype) return result
[docs] def get_lower_bounds(self, dtype='d'): """Return lower bound values. dtype: string or None If not None, return an array of this dtype. Otherwise just return a list (useful if parameters may be of different types). """ result = [] for param in self._parameters.values(): result.extend(param.get_low()) if dtype: result = array(result, dtype) return result
[docs] def get_upper_bounds(self, dtype='d'): """Return upper bound values. dtype: string or None If not None, return an array of this dtype. Otherwise just return a list (useful if parameters may be of different types). """ result = [] for param in self._parameters.values(): result.extend(param.get_high()) if dtype: result = array(result, dtype) return result
[docs] def get_fd_steps(self, dtype='d'): """Return fd_step values, they may include None. dtype: string or None If not None, return an array of this dtype. Otherwise just return a list (useful if it's valid to have None for a step size). """ result = [] for param in self._parameters.values(): result.extend(param.get_fd_step()) if dtype: result = array(result, dtype) return result
[docs] def get_expr_depends(self): """Returns a list of tuples of the form (src_comp_name, dest_comp_name) for each dependency introduced by a parameter. """ conn_list = [] pname = self._parent.name for param in self._parameters.values(): for cname in param.get_referenced_compnames(): conn_list.append((pname, cname)) return conn_list
[docs] def get_referenced_compnames(self): """Return a set of Component names based on the pathnames of Variables referenced in our target strings. """ result = set() for param in self._parameters.values(): result.update(param.get_referenced_compnames()) return result
[docs] def get_referenced_varpaths(self): """Return a set of Variable names referenced in our target strings. """ result = set() for param in self._parameters.values(): result.update(param.get_referenced_varpaths()) return result
def _get_scope(self, scope=None): if scope is None: try: return self._parent.get_expr_scope() except AttributeError: pass return scope
[docs] def mimic(self, target): old = self._parameters self.clear_parameters() try: for name, param in target.get_parameters().items(): self._parameters[name] = param.copy() except Exception: self._parameters = old raise
OpenMDAO Home