def __init__(self, *args, **kwds): self._units = kwds.pop('units', None) if self._units is not None: self._units = units.get_units(self._units) self._arg_units = kwds.pop('arg_units', None) if self._arg_units is not None: self._arg_units = [units.get_units(u) for u in self._arg_units] kwds.setdefault('ctype', ExternalFunction) Component.__init__(self, **kwds) self._constructed = True ### HACK ### # FIXME: We must declare an _index attribute because # block._add_temporary_set assumes ALL components define an # index. Sigh. self._index = None
def set_value(self, value, idx=NOTSET): # # If this param has units, then we need to check the incoming # value and see if it is "units compatible". We only need to # check here in set_value, because all united Params are # required to be mutable. # _comp = self.parent_component() if type(value) in native_types: # TODO: warn/error: check if this Param has units: assigning # a dimensionless value to a united param should be an error pass elif _comp._units is not None: _src_magnitude = expr_value(value) _src_units = units.get_units(value) value = units.convert_value(num_value=_src_magnitude, from_units=_src_units, to_units=_comp._units) old_value, self._value = self._value, value try: _comp._validate_value(idx, value, data=self) except: self._value = old_value raise
def set_value(self, val, valid=False): """ Set the value of this numeric object, after validating its value. If the 'valid' flag is True, then the validation step is skipped. """ if not valid and val is not None: # TODO: warn/error: check if this Var has units: assigning # a dimensionless value to a united variable should be an error if type(val) not in native_numeric_types: if self.parent_component()._units is not None: _src_magnitude = value(val) _src_units = units.get_units(val) val = units.convert_value( num_value=_src_magnitude, from_units=_src_units, to_units=self.parent_component()._units) if val not in self.domain: raise ValueError("Numeric value `%s` (%s) is not in " "domain %s for Var %s" % (val, type(val), self.domain, self.name)) self.value = val self.stale = False
def value(self, val): """Set the value for this variable.""" if type(val) in native_numeric_types: # TODO: warn/error: check if this Var has units: assigning # a dimensionless value to a united variable should be an error pass elif val is not None and self.parent_component()._units is not None: _src_magnitude = value(val) _src_units = units.get_units(val) val = units.convert_value(num_value=_src_magnitude, from_units=_src_units, to_units=self.parent_component()._units) self._value = val
def __init__(self, *args, **kwd): # # Default keyword values # initialize = kwd.pop('initialize', None) initialize = kwd.pop('rule', initialize) domain = kwd.pop('within', Reals) domain = kwd.pop('domain', domain) bounds = kwd.pop('bounds', None) self._dense = kwd.pop('dense', True) self._units = kwd.pop('units', None) if self._units is not None: self._units = units.get_units(self._units) # # Initialize the base class # kwd.setdefault('ctype', Var) IndexedComponent.__init__(self, *args, **kwd) # # Determine if the domain argument is a functor or other object # self._domain_init_value = None self._domain_init_rule = None if is_functor(domain): self._domain_init_rule = domain else: self._domain_init_value = domain # # Allow for functions or functors for value initialization, # without confusing with Params, etc (which have a __call__ method). # self._value_init_value = None self._value_init_rule = None if is_functor(initialize) and (not isinstance(initialize, NumericValue)): self._value_init_rule = initialize else: self._value_init_value = initialize # # Determine if the bound argument is a functor or other object # self._bounds_init_rule = None self._bounds_init_value = None if is_functor(bounds): self._bounds_init_rule = bounds elif type(bounds) is tuple: self._bounds_init_value = bounds elif bounds is not None: raise ValueError( "Variable 'bounds' keyword must be a tuple or function")
def set_value(self, val, skip_validation=False): """Set the current variable value. Set the value of this variable. The incoming value is converted to a numeric value (i.e., expressions are evaluated). If the variable has units, the incoming value is converted to the correct units before storing the value. The final value is checked against both the variable domain and bounds, and an exception is raised if the value is not valid. Domain and bounds checking can be bypassed by setting the ``skip_validation`` argument to :const:`True`. """ # Special case: setting a variable to None "clears" the variable. if val is None: self._value = None self._stale = 0 # True return # TODO: generate a warning/error: # # Check if this Var has units: assigning dimensionless # values to a variable with units should be an error if type(val) not in native_numeric_types: if self.parent_component()._units is not None: _src_magnitude = value(val) _src_units = units.get_units(val) val = units.convert_value( num_value=_src_magnitude, from_units=_src_units, to_units=self.parent_component()._units) else: val = value(val) if not skip_validation: if val not in self.domain: logger.warning( "Setting Var '%s' to a value `%s` (%s) not in domain %s." % (self.name, val, type(val).__name__, self.domain), extra={'id': 'W1001'}, ) elif (self._lb is not None and val < value(self._lb)) or (self._ub is not None and val > value(self._ub)): logger.warning( "Setting Var '%s' to a numeric value `%s` " "outside the bounds %s." % (self.name, val, self.bounds), extra={'id': 'W1002'}, ) self._value = val self._stale = StaleFlagManager.get_flag(self._stale)
def __init__(self, *args, **kwd): _init = self._pop_from_kwargs('Param', kwd, ('rule', 'initialize'), NOTSET) self._rule = Initializer(_init, treat_sequences_as_mappings=False, arg_not_specified=NOTSET) self.domain = self._pop_from_kwargs('Param', kwd, ('domain', 'within')) if self.domain is None: self.domain = _ImplicitAny(owner=self, name='Any') self._validate = kwd.pop('validate', None) self._mutable = kwd.pop('mutable', Param.DefaultMutable) self._default_val = kwd.pop('default', Param.NoValue) self._dense_initialize = kwd.pop('initialize_as_dense', False) self._units = kwd.pop('units', None) if self._units is not None: self._units = units.get_units(self._units) self._mutable = True kwd.setdefault('ctype', Param) IndexedComponent.__init__(self, *args, **kwd)
def __init__(self, *args, **kwargs): # # Default keyword values # self._rule_init = Initializer(self._pop_from_kwargs( 'Var', kwargs, ('rule', 'initialize'), None)) self._rule_domain = SetInitializer(self._pop_from_kwargs( 'Var', kwargs, ('domain', 'within'), Reals)) _bounds_arg = kwargs.pop('bounds', None) self._dense = kwargs.pop('dense', True) self._units = kwargs.pop('units', None) if self._units is not None: self._units = units.get_units(self._units) # # Initialize the base class # kwargs.setdefault('ctype', Var) IndexedComponent.__init__(self, *args, **kwargs) # # Now that we can call is_indexed(), process bounds initializer # if self.is_indexed(): treat_bounds_sequences_as_mappings = not ( isinstance(_bounds_arg, Sequence) and len(_bounds_arg) == 2 and not isinstance(_bounds_arg[0], Sequence) ) else: treat_bounds_sequences_as_mappings = False if not self._dense: logger.warning( "ScalarVar object '%s': dense=False is not allowed " "for scalar variables; converting to dense=True" % (self.name,)) self._dense = True self._rule_bounds = Initializer( _bounds_arg, treat_sequences_as_mappings=treat_bounds_sequences_as_mappings )
def __init__(self, *args, **kwd): self._rule = kwd.pop('rule', Param.NoValue ) self._rule = kwd.pop('initialize', self._rule ) self._validate = kwd.pop('validate', None ) self.domain = kwd.pop('domain', None ) self.domain = kwd.pop('within', self.domain ) self._mutable = kwd.pop('mutable', Param.DefaultMutable ) self._default_val = kwd.pop('default', Param.NoValue ) self._dense_initialize = kwd.pop('initialize_as_dense', False) self._units = kwd.pop('units', None) if self._units is not None: self._units = units.get_units(self._units) self._mutable = True # if 'repn' in kwd: logger.error( "The 'repn' keyword is not a validate keyword argument for Param") # if self.domain is None: self.domain = _ImplicitAny(owner=self, name='Any') # kwd.setdefault('ctype', Param) IndexedComponent.__init__(self, *args, **kwd)
def setlb(self, val): """ Set the lower bound for this variable after validating that the value is fixed (or None). """ # Note: is_fixed(None) returns True if not is_fixed(val): raise ValueError( "Non-fixed input of type '%s' supplied as variable lower " "bound - legal types must be fixed expressions or variables." % (type(val),)) if type(val) in native_numeric_types or val is None: # TODO: warn/error: check if this Var has units: assigning # a dimensionless value to a united variable should be an error pass else: if self.parent_component()._units is not None: _src_magnitude = value(val) _src_units = units.get_units(val) val = units.convert_value( num_value=_src_magnitude, from_units=_src_units, to_units=self.parent_component()._units) self._lb = val
def __init__(self, *args, **kwargs): """Construct a reference to an external function. There are two fundamental interfaces supported by :class:`ExternalFunction`: Python callback functions and AMPL external functions. **Python callback functions** (:class:`PythonCallbackFunction` interface) Python callback functions can be specified one of two ways: 1. FGH interface: A single external function call with a signature matching the :meth:`evaluate_fgh()` method. 2. Independent functions: One to three functions that can evaluate the function value, gradient of the function [partial derivatives] with respect to its inputs, and the Hessian of the function [partial second derivatives]. The ``function`` interface expects a function matching the prototype: .. code:: def function(*args): float The ``gradient`` and ``hessian`` interface expect functions matching the prototype: .. code:: def gradient_or_hessian(args, fixed=None): List[float] Where ``args`` is a tuple of function arguments and ``fixed`` is either None or a list of values equal in length to ``args`` indicating which arguments are currently fixed (``True``) or variable (``False``). **ASL function libraries** (:class:`AMPLExternalFunction` interface) Pyomo can also call functions compiled as part of an AMPL External Function library (see the `User-defined functions <https://www.ampl.com/REFS/HOOKING/#userdefinedfuncs>`_ section in the `Hooking your solver to AMPL <https://www.ampl.com/REFS/hooking3.pdf>`_ report). Links to these functions are declared by creating an :class:`ExternalFunction` and passing the compiled library name (or path) to the ``library`` keyword and the name of the function to the ``function`` keyword. """ self._units = kwargs.pop('units', None) if self._units is not None: self._units = units.get_units(self._units) self._arg_units = kwargs.pop('arg_units', None) if self._arg_units is not None: self._arg_units = [units.get_units(u) for u in self._arg_units] kwargs.setdefault('ctype', ExternalFunction) Component.__init__(self, **kwargs) self._constructed = True ### HACK ### # FIXME: We must declare an _index attribute because # block._add_temporary_set assumes ALL components define an # index. Sigh. self._index_set = None
def create_stream_table_dataframe(streams, true_state=False, time_point=0, orient="columns", add_units=False): """ Method to create a stream table in the form of a pandas dataframe. Method takes a dict with name keys and stream values. Use an OrderedDict to list the streams in a specific order, otherwise the dataframe can be sorted later. Args: streams : dict with name keys and stream values. Names will be used as display names for stream table, and streams may be Arcs, Ports or StateBlocks. true_state : indicated whether the stream table should contain the display variables define in the StateBlock (False, default) or the state variables (True). time_point : point in the time domain at which to generate stream table (default = 0) orient : orientation of stream table. Accepted values are 'columns' (default) where streams are displayed as columns, or 'index' where stream are displayed as rows. add_units : Add a Units column to the dataframe representing the units of the stream values. Returns: A pandas DataFrame containing the stream table data. """ stream_attributes = OrderedDict() stream_states = stream_states_dict(streams=streams, time_point=time_point) full_keys = [] # List of all rows in dataframe to fill in missing data if add_units and stream_states: stream_attributes['Units'] = {} for key, sb in stream_states.items(): stream_attributes[key] = {} if true_state: disp_dict = sb.define_state_vars() else: disp_dict = sb.define_display_vars() for k in disp_dict: for i in disp_dict[k]: stream_key = k if i is None else f"{k} {i}" stream_attributes[key][stream_key] = value(disp_dict[k][i]) if add_units: pyomo_unit = units.get_units(disp_dict[k][i]) if pyomo_unit is not None: pint_unit = pyomo_unit._get_pint_unit() stream_attributes['Units'][stream_key] = { 'raw': str(pyomo_unit), 'html': '{:~H}'.format(pint_unit), 'latex': '{:~L}'.format(pint_unit) } else: stream_attributes['Units'][stream_key] = None if stream_key not in full_keys: full_keys.append(stream_key) # Check for missing rows in any stream, and fill with "-" if needed for k, v in stream_attributes.items(): for r in full_keys: if r not in v.keys(): # Missing row, fill with placeholder v[r] = "-" return DataFrame.from_dict(stream_attributes, orient=orient)