def get_tracking_cost_expression( variables, time, setpoint_data, weight_data=None, dereference=True, ): """ Arguments --------- variables: list List of time-indexed variables to include in the tracking cost expression. setpoint_data: dict Maps variable names to setpoint values weight_data: dict Maps variable names to tracking cost weights Returns ------- Pyomo expression. Sum of weighted squared difference between variables and setpoint values. """ # TODO: Should setpoints be mutable params? Indexed by variable names? # This is tempting as it makes changing the setpoint easy. variable_names = [ # NOTE: passing strings through ComponentUID. # This may break things that rely on a particular form of the string. # I believe this approach is more consistent, however. # This is a temporary measure before I switch to using CUIDs as keys. str(ComponentUID(str(get_time_indexed_cuid(var)))) for var in variables ] # str(ComponentUID(var)) # if not var.is_reference() or not dereference # else str(ComponentUID(var.referent)) # for var in variables #] if weight_data is None: weight_data = {name: 1.0 for name in variable_names} def tracking_rule(m, t): return sum(weight_data[name] * (var[t] - setpoint_data[name])**2 for name, var in zip(variable_names, variables)) # Note that I don't enforce that variables are actually indexed # by time. "time" could just be a list of sample points... tracking_expr = Expression(time, rule=tracking_rule) return tracking_expr
def __init__(self, *args, **kwds): if "wrt" in kwds and "withrespectto" in kwds: raise TypeError( "Cannot specify both 'wrt' and 'withrespectto keywords") wrt = kwds.pop('wrt', None) wrt = kwds.pop('withrespectto', wrt) if wrt is None: # Check to be sure Integral is indexed by single # ContinuousSet and take Integral with respect to that # ContinuousSet if len(args) != 1: raise ValueError( "Integral indexed by multiple ContinuousSets. " "The desired ContinuousSet must be specified using the " "keyword argument 'wrt'") wrt = args[0] if type(wrt) is not ContinuousSet: raise ValueError( "Cannot take the integral with respect to '%s'. Must take an " "integral with respect to a ContinuousSet" % wrt) self._wrt = wrt loc = None for i, s in enumerate(args): if s is wrt: loc = i # Check that the wrt ContinuousSet is in the argument list if loc is None: raise ValueError( "The ContinuousSet '%s' was not found in the indexing sets " "of the Integral" % wrt.name) self.loc = loc # Remove the index that the integral is being expanded over arg = args[0:loc] + args[loc + 1:] # Check that if bounds are given bounds = kwds.pop('bounds', None) if bounds is not None: raise DAE_Error( "Setting bounds on integrals has not yet been implemented. " "Integrals may only be taken over an entire ContinuousSet") # Create integral expression and pass to the expression initialization intexp = kwds.pop('expr', None) intexp = kwds.pop('rule', intexp) if intexp is None: raise ValueError( "Must specify an integral expression") def _trap_rule(m, *a): ds = sorted(m.find_component(wrt.local_name)) return sum(0.5 * (ds[i + 1] - ds[i]) * (intexp(m, * (a[0:loc] + (ds[i + 1],) + a[loc:])) + intexp(m, * (a[0:loc] + (ds[i],) + a[loc:]))) for i in range(len(ds) - 1)) kwds['rule'] = _trap_rule kwds.setdefault('ctype', Integral) Expression.__init__(self, *arg, **kwds)
def __init__(self, *args, **kwds): if "wrt" in kwds and "withrespectto" in kwds: raise TypeError( "Cannot specify both 'wrt' and 'withrespectto keywords " "in a DerivativeVar") wrt = kwds.pop('wrt',None) wrt = kwds.pop('withrespectto',wrt) if wrt == None: # Check to be sure Integral is indexed by single # ContinuousSet and take Integral with respect to that # ContinuousSet if len(args) != 1: raise ValueError( "The Integral %s is indexed by multiple ContinuousSets. The desired " "ContinuousSet must be specified using the keyword argument 'wrt'" % (self.name)) wrt = args[0] if type(wrt) is not ContinuousSet: raise ValueError( "Cannot take the integral with respect to '%s'. Must take an integral "\ "with respect to a ContinuousSet" %(wrt)) self._wrt = wrt loc = None for i,s in enumerate(args): if s is wrt: loc = i # Check that the wrt ContinuousSet is in the argument list if loc is None: raise ValueError( "The ContinuousSet '%s' was not found in the indexing sets of the " "Integral '%s'" %(wrt.name,self.name)) self.loc = loc # Remove the index that the integral is being expanded over arg = args[0:loc]+args[loc+1:] # Check that if bounds are given bounds = kwds.pop('bounds',None) if bounds is not None: raise DAE_Error( "Setting bounds on integrals has not yet been implemented. Integrals may only be "\ "taken over an entire ContinuousSet") # Create integral expression and pass to the expression initialization intexp = kwds.pop('expr', None) intexp = kwds.pop('rule', intexp) if intexp is None: raise ValueError( "Must specify an integral expression for Integral '%s'" %(self)) def _trap_rule(m,*a): ds = sorted(m.find_component(wrt.local_name)) return sum(0.5*(ds[i+1]-ds[i])* (intexp(m,*(a[0:loc]+(ds[i+1],)+a[loc:]))+intexp(m,*(a[0:loc]+(ds[i],)+a[loc:]))) for i in range(len(ds)-1)) kwds['rule'] = _trap_rule kwds.setdefault('ctype', Integral) Expression.__init__(self,*arg,**kwds)