Пример #1
0
def build_Var():
    """Build a Var and delete any references to external
    objects so its size can be computed."""
    obj = Var()
    obj.construct()
    obj._domain = None
    return obj
Пример #2
0
def build_Var():
    """Build a Var and delete any references to external
    objects so its size can be computed."""
    obj = Var()
    obj.construct()
    obj._domain = None
    return obj
Пример #3
0
def _indexed_Block_rule(b, i):
    b.x1 = Var()
    b.x1._domain = None
    b.x2 = Var()
    b.x2._domain = None
    b.x3 = Var()
    b.x3._domain = None
    b.x4 = Var()
    b.x4._domain = None
    b.x5 = Var()
    b.x5._domain = None
    return b
Пример #4
0
    def var(self, *args, **kwds):
        """
        Declare a variable.

        Parameters
        ----------
        \*args 
            The first argument is a string for the variable name used by Pyomo.
            The remaining arguments are assumed to be index sets for the 
            variable.
        \**kwargs
            The keyword arguments are the same as the keyword arguments
            supported by the Pyomo Var component.

        Returns
        -------
        Variable object
            If the variable is not indexed, then the return type
            is a single Pyomo variable object.  If the variable is
            indexed, then the return type is a dictionary of Pyomo
            variable objects.
        """
        _args = args[1:]
        name = args[0]
        # If the variable name is "x", then the following is equivalent to:
        #  self.model.x = Var(*_args, **kwds)
        _v = Var(*_args, **kwds)
        setattr(self.model, name, _v)
        return _v
Пример #5
0
    def set_as_constraint(self, uncertain_params, **kwargs):
        """
        Function to generate constraints for the CardinalitySet uncertainty set.

        Args:
            uncertain_params: uncertain parameter objects for writing constraint objects
        """

        # === Ensure dimensions
        if len(uncertain_params) != len(self.origin):
               raise AttributeError("Dimensions of origin and uncertain_param lists must be equal.")

        model = kwargs['model']
        set_i = list(range(len(uncertain_params)))
        model.util.cassi = Var(set_i, initialize=0, bounds=(0, 1))

        # Make n equality constraints
        conlist = ConstraintList()
        conlist.construct()
        for i in set_i:
            conlist.add(self.origin[i] + self.positive_deviation[i] * model.util.cassi[i] == uncertain_params[i])

        conlist.add(sum(model.util.cassi[i] for i in set_i) <= self.gamma)

        return conlist
Пример #6
0
    def set_as_constraint(self, uncertain_params, **kwargs):
        """
        Function to generate constraints for the FactorModelSet uncertainty set.

        Args:
            uncertain_params: uncertain parameter objects for writing constraint objects
        """
        model = kwargs['model']

        # === Ensure dimensions
        if len(uncertain_params) != len(self.origin):
                raise AttributeError("Dimensions of origin and uncertain_param lists must be equal.")

        # Make F-dim cassi variable
        n = list(range(self.number_of_factors))
        model.util.cassi = Var(n, initialize=0, bounds=(-1, 1))

        conlist = ConstraintList()
        conlist.construct()

        disturbances = [sum(self.psi_mat[i][j] * model.util.cassi[j] for j in n)
                        for i in range(len(uncertain_params))]

        # Make n equality constraints
        for i in range(len(uncertain_params)):
            conlist.add(self.origin[i] + disturbances[i] == uncertain_params[i])
        conlist.add(sum(model.util.cassi[i] for i in n) <= +self.beta * self.number_of_factors)
        conlist.add(sum(model.util.cassi[i] for i in n) >= -self.beta * self.number_of_factors)
        return conlist
Пример #7
0
    def point_in_set(self, point):
        """
        Calculates if supplied ``point`` is contained in the uncertainty set. Returns True or False.

        Args:
            point: The point being checked for membership in the set.
                   The coordinates of the point should be supplied in the same order as the elements of ``uncertain_params``
                   that is to be supplied to the PyROS solve statement.
                   This point must match the dimension of the uncertain parameters of the set.
        """

        # === Ensure point is of correct dimensionality as the uncertain parameters
        if len(point) != self.dim:
            raise AttributeError("Point must have same dimensions as uncertain parameters.")

        m = ConcreteModel()
        the_params = []
        for i in range(self.dim):
            m.add_component("x_%s" % i, Var(initialize=point[i]))
            the_params.append(getattr(m, "x_%s" % i))

        # === Generate constraint for set
        set_constraint = self.set_as_constraint(uncertain_params=the_params)

        # === value() returns True if the constraint is satisfied, False else.
        is_in_set = all(value(con.expr) for con in set_constraint.values())

        return is_in_set
Пример #8
0
    def is_empty_intersection(self, uncertain_params, nlp_solver):
        """
        Determine if intersection is empty

        Args:
            uncertain_params: list of uncertain parameters
            nlp_solver: a Pyomo Solver object for solving NLPs
        """

        # === Non-emptiness check for the set intersection
        is_empty_intersection = True
        if any(a_set.type == "discrete" for a_set in self.all_sets):
            disc_sets = (a_set for a_set in self.all_sets if a_set.type == "discrete")
            disc_set = min(disc_sets, key=lambda x: len(x.scenarios))  # minimum set of scenarios
            # === Ensure there is at least one scenario from this discrete set which is a member of all other sets
            for scenario in disc_set.scenarios:
                if all(a_set.point_in_set(point=scenario) for a_set in self.all_sets):
                    is_empty_intersection = False
                    break
        else:
            # === Compile constraints and solve NLP
            m = ConcreteModel()
            m.obj = Objective(expr=0) # dummy objective required if using baron
            m.param_vars = Var(uncertain_params.index_set())
            for a_set in self.all_sets:
                m.add_component(a_set.type + "_constraints", a_set.set_as_constraint(uncertain_params=m.param_vars))
            try:
                res = nlp_solver.solve(m)
            except:
                raise ValueError("Solver terminated with an error while checking set intersection non-emptiness.")
            if check_optimal_termination(res):
                is_empty_intersection = False
        return is_empty_intersection
Пример #9
0
def build_BlockData_with_objects():
    """Build an empty _BlockData"""
    obj = _BlockData(build_BlockData_with_objects.owner)
    obj.x = Var()
    obj.x._domain = None
    obj.c = Constraint()
    obj.o = Objective()
    obj._component = None
    return obj
Пример #10
0
def build_Block_with_objects():
    """Build an empty Block"""
    obj = Block(concrete=True)
    obj.construct()
    obj.x = Var()
    obj.x._domain = None
    obj.c = Constraint()
    obj.o = Objective()
    return obj
Пример #11
0
def build_indexed_Var():
    """Build an indexed Var with no references to external
    objects so its size can be computed."""
    model = build_indexed_Var.model
    model.indexed_Var = Var(model.ndx,
                            domain=Integers,
                            bounds=build_indexed_Var.bounds_rule,
                            initialize=build_indexed_Var.initialize_rule)
    model.indexed_Var._domain = None
    model.indexed_Var._component = None
    return model.indexed_Var
Пример #12
0
def get_hessian_of_constraint(constraint, wrt1=None, wrt2=None, nlp=None):
    constraints = [constraint]
    if wrt1 is None and wrt2 is None:
        variables = list(
            identify_variables(constraint.expr, include_fixed=False))
        wrt1 = variables
        wrt2 = variables
    elif wrt1 is not None and wrt2 is not None:
        variables = wrt1 + wrt2
    elif wrt1 is not None:  # but wrt2 is None
        wrt2 = wrt1
        variables = wrt1
    else:
        # wrt2 is not None and wrt1 is None
        wrt1 = wrt2
        variables = wrt1

    if nlp is None:
        block = create_subsystem_block(constraints, variables=variables)
        # Could fix input_vars so I don't evaluate the Hessian with respect
        # to variables I don't care about...

        # HUGE HACK: Variables not included in a constraint are not written
        # to the nl file, so we cannot take the derivative with respect to
        # them, even though we know this derivative is zero. To work around,
        # we make sure all variables appear on the block in the form of a
        # dummy constraint. Then we can take derivatives of any constraint
        # with respect to them. Conveniently, the extract_submatrix_
        # call deals with extracting the variables and constraint we care
        # about, in the proper order.
        block._dummy_var = Var()
        block._dummy_con = Constraint(expr=sum(variables) == block._dummy_var)
        block._obj = Objective(expr=0.0)
        nlp = PyomoNLP(block)

    saved_duals = nlp.get_duals()
    saved_obj_factor = nlp.get_obj_factor()
    temp_duals = np.zeros(len(saved_duals))

    # NOTE: This makes some assumption about how the Lagrangian is constructed.
    # TODO: Define the convention we assume and convert if necessary.
    idx = nlp.get_constraint_indices(constraints)[0]
    temp_duals[idx] = 1.0
    nlp.set_duals(temp_duals)
    nlp.set_obj_factor(0.0)

    # NOTE: The returned matrix preserves explicit zeros. I.e. it contains
    # coordinates for every entry that could possibly be nonzero.
    submatrix = nlp.extract_submatrix_hessian_lag(wrt1, wrt2)

    nlp.set_obj_factor(saved_obj_factor)
    nlp.set_duals(saved_duals)
    return submatrix
Пример #13
0
    def __call__(self):
        deprecation_warning(
            "Relying on core.logical_to_linear to transform "
            "BooleanVars that do not appear in LogicalConstraints "
            "is deprecated. Please associate your own binaries if "
            "you have BooleanVars not used in logical expressions.",
            version='6.2')

        parent_block = self._boolvar().parent_block()
        new_var = Var(domain=Binary)
        parent_block.add_component(
            unique_component_name(parent_block,
                                  self._boolvar().local_name + "_asbinary"),
            new_var)
        self._boolvar()._associated_binary = None
        self._boolvar().associate_binary_var(new_var)
        return new_var
Пример #14
0
    def __init__(self, sVar, **kwds):

        if not isinstance(sVar,Var):
            raise DAE_Error(
                "%s is not a variable. Can only take the derivative of a Var component." % (sVar))
        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)

        try:
            num_contset = len(sVar._contset)
        except:
            sVar._contset = {} 
            sVar._derivative = {}
            if sVar.dim() == 0:
                num_contset = 0
            elif sVar.dim() == 1:
                sidx_sets = sVar._index
                if sidx_sets.type() is ContinuousSet:
                    sVar._contset[sidx_sets] = 0
            else:
                sidx_sets = sVar._implicit_subsets
                for i,s in enumerate(sidx_sets):
                    if s.type() is ContinuousSet:
                        sVar._contset[s] = i
            num_contset = len(sVar._contset)

        if num_contset == 0:
            raise DAE_Error("The variable %s is not indexed by any ContinuousSets. A derivative may "
                            "only be taken with respect to a continuous domain" % (sVar))

        if wrt == None:
            # Check to be sure Var is indexed by single ContinuousSet and take
            # first deriv wrt that set
            if num_contset != 1:
                raise DAE_Error(
                    "The variable %s is indexed by multiple ContinuousSets. The desired "
                    "ContinuousSet must be specified using the keyword argument 'wrt'" % (sVar))
            wrt = [next(iterkeys(sVar._contset)),]
        elif type(wrt) is ContinuousSet:
            if wrt not in sVar._contset:
                raise DAE_Error(
                    "Invalid derivative: The variable %s is not indexed by "
                    "the ContinuousSet %s" %(sVar,wrt))
            wrt = [wrt,]
        elif type(wrt) is tuple or type(wrt) is list:
            for i in wrt:
                if type(i) is not ContinuousSet:
                    raise DAE_Error(
                        "Cannot take the derivative with respect to %s. "
                        "Expected a ContinuousSet or a tuple of ContinuousSets"% (i))
                if i not in sVar._contset:
                    raise DAE_Error(
                        "Invalid derivative: The variable %s is not indexed by "
                        "the ContinuousSet %s" %(sVar,i))           
            wrt = list(wrt)
        else:
            raise DAE_Error(
                "Cannot take the derivative with respect to %s. "
                "Expected a ContinuousSet or a tuple of ContinuousSets"% (i))
        
        wrtkey = [str(i) for i in wrt]
        wrtkey.sort()
        wrtkey = tuple(wrtkey)

        if wrtkey in sVar._derivative:
            raise DAE_Error(
                "Cannot create a new derivative variable for variable "
                "%s: derivative already defined as %s" 
                % ( sVar.cname(True), sVar.get_derivative(*tuple(wrt)).cname(True) ) )
 
        sVar._derivative[wrtkey] = weakref.ref(self)
        self._sVar = sVar
        self._wrt = wrt

        kwds.setdefault('ctype', DerivativeVar)

        if sVar._implicit_subsets is None:
            arg = (sVar.index_set(),)
        else:
            arg = tuple(sVar._implicit_subsets)
        
        Var.__init__(self,*arg,**kwds)
Пример #15
0
    def _Split(port, name, index_set, include_splitfrac=False,
            write_var_sum=True):
        port_parent = port.parent_block()
        var = port.vars[name]
        out_vars = []
        no_splitfrac = False
        dests = port.dests(active=True)

        if not len(dests):
            return out_vars

        if len(dests) == 1:
            # No need for splitting on one outlet.
            # Make sure they do not try to fix splitfrac not at 1.
            splitfracspec = port.get_split_fraction(dests[0])
            if splitfracspec is not None:
                if splitfracspec[0] != 1 and splitfracspec[1] == True:
                    raise ValueError(
                        "Cannot fix splitfrac not at 1 for port '%s' with a "
                        "single dest '%s'" % (port.name, dests[0].name))

            no_splitfrac = True

            if len(dests[0].destination.sources(active=True)) == 1:
                # This is a 1-to-1 connection, no need for evar, just equality.
                arc = dests[0]
                Port._add_equality_constraint(arc, name, index_set)
                return out_vars

        for arc in dests:
            eblock = arc.expanded_block

            # Make and record new variables for every arc with this member.
            evar = Port._create_evar(port.vars[name], name, eblock, index_set)
            out_vars.append(evar)

            if no_splitfrac:
                continue

            # Create and potentially initialize split fraction variables.
            # This function will be called for every Extensive member of this
            # port, but we only need one splitfrac variable per arc, so check
            # if it already exists before making a new one. However, we do not
            # need a splitfrac if there is only one Extensive data object,
            # so first check whether or not we need it.

            if eblock.component("splitfrac") is None:
                if not include_splitfrac:
                    num_data_objs = 0
                    for k, v in iteritems(port.vars):
                        if port.is_extensive(k):
                            if v.is_indexed():
                                num_data_objs += len(v)
                            else:
                                num_data_objs += 1
                            if num_data_objs > 1:
                                break

                    if num_data_objs <= 1:
                        # Do not make splitfrac, do not make split constraints.
                        # Make sure they didn't specify splitfracs.
                        # This inner loop will only run once.
                        for arc in dests:
                            if port.get_split_fraction(arc) is not None:
                                raise ValueError(
                                    "Cannot specify splitfracs for port '%s' "
                                    "(found arc '%s') because this port only "
                                    "has one variable. To have control over "
                                    "splitfracs, please pass the "
                                    " include_splitfrac=True argument." %
                                    (port.name, arc.name))
                        no_splitfrac = True
                        continue

                eblock.splitfrac = Var()
                splitfracspec = port.get_split_fraction(arc)
                if splitfracspec is not None:
                    eblock.splitfrac = splitfracspec[0]
                    if splitfracspec[1]:
                        eblock.splitfrac.fix()

            # Create constraint for this member using splitfrac.
            cname = "%s_split" % name
            def rule(m, *args):
                if len(args):
                    return evar[args] == eblock.splitfrac * var[args]
                else:
                    return evar == eblock.splitfrac * var
            con = Constraint(index_set, rule=rule)
            eblock.add_component(cname, con)

        if write_var_sum:
            # Create var total sum constraint: var == sum of evars
            # Need to alphanum port name in case it is indexed.
            cname = unique_component_name(port_parent, "%s_%s_outsum" %
                (alphanum_label_from_name(port.local_name), name))
            def rule(m, *args):
                if len(args):
                    return sum(evar[args] for evar in out_vars) == var[args]
                else:
                    return sum(evar for evar in out_vars) == var
            con = Constraint(index_set, rule=rule)
            port_parent.add_component(cname, con)
        else:
            # OR create constraint on splitfrac vars: sum == 1
            if no_splitfrac:
                raise ValueError(
                    "Cannot choose to write split fraction sum constraint for "
                    "ports with a single destination or a single Extensive "
                    "variable.\nSplit fractions are skipped in this case to "
                    "simplify the model.\nPlease use write_var_sum=True on "
                    "this port (the default).")
            cname = unique_component_name(port_parent,
                "%s_frac_sum" % alphanum_label_from_name(port.local_name))
            con = Constraint(expr=
                sum(a.expanded_block.splitfrac for a in dests) == 1)
            port_parent.add_component(cname, con)

        return out_vars
Пример #16
0
def declare_variables(model):
    model.area_beta = Var(model.HP,
                          model.CP,
                          model.ST,
                          initialize=0,
                          domain=NonNegativeReals)
    model.area_cu_beta = Var(model.HP, initialize=0, domain=NonNegativeReals)
    model.area_hu_beta = Var(model.CP, initialize=0, domain=NonNegativeReals)

    # Flow rates
    model.fh = Var(model.HP, model.CP, model.ST, bounds=fh_bounds,\
            doc="Flow rate entering heat exchanger ijk cold side" )
    model.fc = Var(model.HP, model.CP, model.ST, bounds=fc_bounds,\
            doc="Flow rate entering heat exchanger ijk hot side"  )

    # Per exchanger outlet
    model.thx = Var(model.HP, model.CP, model.ST, bounds=thx_bounds,\
            doc="Outlet temperature of the heat exchanger ijk hot side"  )
    model.tcx = Var(model.HP, model.CP, model.ST, bounds=tcx_bounds,\
            doc="Outlet temperature of the heat exchanger ijk cold side" )

    # Temperature approaches
    model.dt    = Var(model.HP, model.CP, model.K, bounds=dt_bounds,\
            doc="Approach between i and j in location k"  )
    model.dt_cu = Var(model.HP,                    bounds=dt_cu_bounds,\
            doc="Approach between i and the cold utility" )
    model.dt_hu = Var(model.CP,                    bounds=dt_hu_bounds,\
            doc="Approach between j and the hot utility"  )

    # Log mean temperature differences raised to the beta-th power
    model.reclmtd_beta = Var(model.HP, model.CP, model.ST,  bounds=reclmtd_beta_bounds,\
            doc="Log mean temperature difference between hot stream i and cold stream j at stage k raised to the beta-th power")
    model.reclmtd_cu_beta = Var(model.HP,                   bounds=reclmtd_cu_beta_bounds,\
            doc="Log mean temperature difference between hot stream i and cold utility raised to the beta-th power")
    model.reclmtd_hu_beta = Var(model.CP,                   bounds=reclmtd_hu_beta_bounds,\
            doc="Log mean temperature difference between cold stream j and hot utility raised to the beta-th power")

    # Heat loads
    model.q    = Var(model.HP, model.CP, model.ST, bounds=q_bounds, initialize = 0,\
            doc="heat load between hot stream i and cold stream j at stage k" )
    model.q_cu = Var(model.HP,                     bounds=q_cu_bounds, initialize = 0,\
            doc="heat load between hot stream i and cold utility"             )
    model.q_hu = Var(model.CP,                     bounds=q_hu_bounds, initialize = 0,\
            doc="heat load between cold stream j and hot utility"             )

    # Heat loads to the beta-th power
    model.q_beta    = Var(model.HP, model.CP, model.ST, bounds=q_beta_bounds, initialize = 0,\
            doc="heat load between hot stream i and cold stream j at stage k raised to the beta-th power" )
    model.q_cu_beta = Var(model.HP,                     bounds=q_cu_beta_bounds, initialize = 0,\
            doc="heat load between hot stream i and cold utility raised to the beta-th power"             )
    model.q_hu_beta = Var(model.CP,                     bounds=q_hu_beta_bounds, initialize = 0,\
            doc="heat load between cold stream j and hot utility raised to the beta-th power"             )

    # Per stage temperatures
    model.th = Var(model.HP, model.K, bounds=th_bounds,\
            doc="temperature of hot stream i at hot end of stage k"  )
    model.tc = Var(model.CP, model.K, bounds=tc_bounds,\
            doc="temperature of cold stream j at hot end of stage k" )

    # Binary variables
    model.z    = Var(model.HP, model.CP, model.ST, initialize = 0, domain=Binary,\
            doc="existence of the match between hot stream i and cold stream j at stage k" )
    model.z_cu = Var(model.HP,                     initialize = 0, domain=Binary,\
            doc="existence of the match between hot stream i and cold utility"             )
    model.z_hu = Var(model.CP,                     initialize = 0, domain=Binary,\
            doc="existence of the match between cold stream j and hot utility"             )

    model.z_q_beta = Var(z_q_beta_index, domain=Binary)
    model.z_q_cu_beta = Var(z_q_cu_beta_index, domain=Binary)
    model.z_q_hu_beta = Var(z_q_hu_beta_index, domain=Binary)

    model.z_area_beta_q = Var(z_area_beta_q_index, domain=Binary)
    model.z_area_beta_q_cu = Var(z_area_beta_q_cu_index, domain=Binary)
    model.z_area_beta_q_hu = Var(z_area_beta_q_hu_index, domain=Binary)

    model.var_delta_reclmtd_beta = Var(z_area_beta_q_index,
                                       domain=NonNegativeReals)
    model.var_delta_reclmtd_cu_beta = Var(z_area_beta_q_cu_index,
                                          domain=NonNegativeReals)
    model.var_delta_reclmtd_hu_beta = Var(z_area_beta_q_hu_index,
                                          domain=NonNegativeReals)

    # New variables
    model.bh_in = Var(model.HP, model.CP, model.ST, bounds=bh_bounds)
    model.bh_out = Var(model.HP, model.CP, model.ST, bounds=bh_bounds)
    model.bc_in = Var(model.HP, model.CP, model.ST, bounds=bc_bounds)
    model.bc_out = Var(model.HP, model.CP, model.ST, bounds=bc_bounds)

    model.z_th = Var(z_th_index, domain=Binary)
    model.z_thx = Var(z_thx_index, domain=Binary)
    model.z_tc = Var(z_tc_index, domain=Binary)
    model.z_tcx = Var(z_tcx_index, domain=Binary)

    model.var_delta_fh = Var(var_delta_fh_index, domain=NonNegativeReals)
    model.var_delta_fhx = Var(var_delta_fhx_index, domain=NonNegativeReals)
    model.var_delta_fc = Var(var_delta_fc_index, domain=NonNegativeReals)
    model.var_delta_fcx = Var(var_delta_fcx_index, domain=NonNegativeReals)
Пример #17
0
    def apply(self, **kwds):
        if __debug__ and logger.isEnabledFor(logging.DEBUG):   #pragma:nocover
            logger.debug("Calling ConnectorExpander")

        instance = kwds['instance']
        blockList = list(instance.block_data_objects(active=True))
        noConnectors = True
        for b in blockList:
            if b.component_map(Connector):
                noConnectors = False
                break
        if noConnectors:
            return

        if __debug__ and logger.isEnabledFor(logging.DEBUG):   #pragma:nocover
            logger.debug("   Connectors found!")

        #
        # At this point, there are connectors in the model, so we must
        # look for constraints that involve connectors and expand them.
        #
        #options = kwds['options']
        #model = kwds['model']

        # In general, blocks should be relatively self-contained, so we
        # should build the connectors from the "bottom up":
        blockList.reverse()

        # Expand each constraint involving a connector
        for block in blockList:
            if __debug__ and logger.isEnabledFor(logging.DEBUG): #pragma:nocover
                logger.debug("   block: " + block.name)

            CCC = {}
            for name, constraint in itertools.chain\
                    ( iteritems(block.component_map(Constraint)),
                      iteritems(block.component_map(ConstraintList)) ):
                cList = []
                CCC[name+'.expanded'] = cList
                for idx, c in iteritems(constraint._data):
                    if __debug__ and logger.isEnabledFor(logging.DEBUG):   #pragma:nocover
                        logger.debug("   (looking at constraint %s[%s])", name, idx)
                    connectors = []
                    self._gather_connectors(c.body, connectors)
                    if len(connectors) == 0:
                        continue
                    if __debug__ and logger.isEnabledFor(logging.DEBUG):   #pragma:nocover
                        logger.debug("   (found connectors in constraint)")

                    # Validate that all connectors match
                    errors, ref, skip = self._validate_connectors(connectors)
                    if errors:
                        logger.error(
                            ( "Connector mismatch: errors detected when "
                              "constructing constraint %s\n    " %
                              (name + (idx and '[%s]' % idx or '')) ) +
                            '\n    '.join(reversed(errors)) )
                        raise ValueError(
                            "Connector mismatch in constraint %s" % \
                            name + (idx and '[%s]' % idx or ''))

                    if __debug__ and logger.isEnabledFor(logging.DEBUG):   #pragma:nocover
                        logger.debug("   (connectors valid)")

                    # Fill in any empty connectors
                    for conn in connectors:
                        if conn.vars:
                            continue
                        for var in ref.vars:
                            if var in skip:
                                continue
                            v = Var()
                            block.add_component(conn.local_name + '.auto.' + var, v)
                            conn.vars[var] = v
                            v.construct()

                    # OK - expand this constraint
                    self._expand_constraint(block, name, idx, c, ref, skip, cList)
                    # Now deactivate the original constraint
                    c.deactivate()
            for name, exprs in iteritems(CCC):
                cList = ConstraintList()
                block.add_component( name, cList )
                cList.construct()
                for expr in exprs:
                    cList.add(expr)

        # Now, go back and implement VarList aggregators
        for block in blockList:
            for conn in itervalues(block.component_map(Connector)):
                for var, aggregator in iteritems(conn.aggregators):
                    c = Constraint(expr=aggregator(block, var))
                    block.add_component(
                        conn.local_name + '.' + var.local_name + '.aggregate', c)
                    c.construct()
Пример #18
0
    def __init__(self, sVar, **kwds):

        if not isinstance(sVar, Var):
            raise DAE_Error(
                "%s is not a variable. Can only take the derivative of a Var"
                "component." % sVar)

        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)

        try:
            num_contset = len(sVar._contset)
        except AttributeError:
            # This dictionary keeps track of where the ContinuousSet appears
            # in the index. This implementation assumes that every element
            # in an indexing set has the same dimension.
            sVar._contset = ComponentMap()
            sVar._derivative = {}
            if sVar.dim() == 0:
                num_contset = 0
            else:
                sidx_sets = list(sVar.index_set().subsets())
                loc = 0
                for i, s in enumerate(sidx_sets):
                    if s.ctype is ContinuousSet:
                        sVar._contset[s] = loc
                    _dim = s.dimen
                    if _dim is None:
                        raise DAE_Error(
                            "The variable %s is indexed by a Set (%s) with a "
                            "non-fixed dimension.  A DerivativeVar may only be "
                            "indexed by Sets with constant dimension" %
                            (sVar, s.name))
                    elif _dim is UnknownSetDimen:
                        raise DAE_Error(
                            "The variable %s is indexed by a Set (%s) with an "
                            "unknown dimension.  A DerivativeVar may only be "
                            "indexed by Sets with known constant dimension" %
                            (sVar, s.name))
                    loc += s.dimen
            num_contset = len(sVar._contset)

        if num_contset == 0:
            raise DAE_Error(
                "The variable %s is not indexed by any ContinuousSets. A "
                "derivative may only be taken with respect to a continuous "
                "domain" % sVar)

        if wrt is None:
            # Check to be sure Var is indexed by single ContinuousSet and take
            # first deriv wrt that set
            if num_contset != 1:
                raise DAE_Error(
                    "The variable %s is indexed by multiple ContinuousSets. "
                    "The desired ContinuousSet must be specified using the "
                    "keyword argument 'wrt'" % sVar)
            wrt = [
                next(iter(sVar._contset.keys())),
            ]
        elif type(wrt) is ContinuousSet:
            if wrt not in sVar._contset:
                raise DAE_Error(
                    "Invalid derivative: The variable %s is not indexed by "
                    "the ContinuousSet %s" % (sVar, wrt))
            wrt = [
                wrt,
            ]
        elif type(wrt) is tuple or type(wrt) is list:
            for i in wrt:
                if type(i) is not ContinuousSet:
                    raise DAE_Error(
                        "Cannot take the derivative with respect to %s. "
                        "Expected a ContinuousSet or a tuple of "
                        "ContinuousSets" % i)
                if i not in sVar._contset:
                    raise DAE_Error(
                        "Invalid derivative: The variable %s is not indexed "
                        "by the ContinuousSet %s" % (sVar, i))
            wrt = list(wrt)
        else:
            raise DAE_Error(
                "Cannot take the derivative with respect to %s. "
                "Expected a ContinuousSet or a tuple of ContinuousSets" % i)

        wrtkey = [str(i) for i in wrt]
        wrtkey.sort()
        wrtkey = tuple(wrtkey)

        if wrtkey in sVar._derivative:
            raise DAE_Error(
                "Cannot create a new derivative variable for variable "
                "%s: derivative already defined as %s" %
                (sVar.name, sVar._derivative[wrtkey]().name))

        sVar._derivative[wrtkey] = weakref.ref(self)
        self._sVar = sVar
        self._wrt = wrt

        kwds.setdefault('ctype', DerivativeVar)

        Var.__init__(self, sVar.index_set(), **kwds)
Пример #19
0
    def __init__(self, sVar, **kwds):

        if not isinstance(sVar, Var):
            raise DAE_Error(
                "%s is not a variable. Can only take the derivative of a Var component."
                % (sVar))
        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)

        try:
            num_contset = len(sVar._contset)
        except:
            sVar._contset = {}
            sVar._derivative = {}
            if sVar.dim() == 0:
                num_contset = 0
            elif sVar.dim() == 1:
                sidx_sets = sVar._index
                if sidx_sets.type() is ContinuousSet:
                    sVar._contset[sidx_sets] = 0
            else:
                sidx_sets = sVar._implicit_subsets
                for i, s in enumerate(sidx_sets):
                    if s.type() is ContinuousSet:
                        sVar._contset[s] = i
            num_contset = len(sVar._contset)

        if num_contset == 0:
            raise DAE_Error(
                "The variable %s is not indexed by any ContinuousSets. A derivative may "
                "only be taken with respect to a continuous domain" % (sVar))

        if wrt == None:
            # Check to be sure Var is indexed by single ContinuousSet and take
            # first deriv wrt that set
            if num_contset != 1:
                raise DAE_Error(
                    "The variable %s is indexed by multiple ContinuousSets. The desired "
                    "ContinuousSet must be specified using the keyword argument 'wrt'"
                    % (sVar))
            wrt = [
                next(iterkeys(sVar._contset)),
            ]
        elif type(wrt) is ContinuousSet:
            if wrt not in sVar._contset:
                raise DAE_Error(
                    "Invalid derivative: The variable %s is not indexed by "
                    "the ContinuousSet %s" % (sVar, wrt))
            wrt = [
                wrt,
            ]
        elif type(wrt) is tuple or type(wrt) is list:
            for i in wrt:
                if type(i) is not ContinuousSet:
                    raise DAE_Error(
                        "Cannot take the derivative with respect to %s. "
                        "Expected a ContinuousSet or a tuple of ContinuousSets"
                        % (i))
                if i not in sVar._contset:
                    raise DAE_Error(
                        "Invalid derivative: The variable %s is not indexed by "
                        "the ContinuousSet %s" % (sVar, i))
            wrt = list(wrt)
        else:
            raise DAE_Error(
                "Cannot take the derivative with respect to %s. "
                "Expected a ContinuousSet or a tuple of ContinuousSets" % (i))

        wrtkey = [str(i) for i in wrt]
        wrtkey.sort()
        wrtkey = tuple(wrtkey)

        if wrtkey in sVar._derivative:
            raise DAE_Error(
                "Cannot create a new derivative variable for variable "
                "%s: derivative already defined as %s" %
                (sVar.cname(True),
                 sVar.get_derivative(*tuple(wrt)).cname(True)))

        sVar._derivative[wrtkey] = weakref.ref(self)
        self._sVar = sVar
        self._wrt = wrt

        kwds.setdefault('ctype', DerivativeVar)

        if sVar._implicit_subsets is None:
            arg = (sVar.index_set(), )
        else:
            arg = tuple(sVar._implicit_subsets)

        Var.__init__(self, *arg, **kwds)
Пример #20
0
    def __init__(self, sVar, **kwds):

        if not isinstance(sVar, Var):
            raise DAE_Error(
                "%s is not a variable. Can only take the derivative of a Var"
                "component." % sVar)

        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)

        try:
            num_contset = len(sVar._contset)
        except AttributeError:
            # This dictionary keeps track of where the ContinuousSet appears
            # in the index. This implementation assumes that every element
            # in an indexing set has the same dimension.
            sVar._contset = {}
            sVar._derivative = {}
            if sVar.dim() == 0:
                num_contset = 0
            elif sVar.dim() == 1:
                sidx_sets = sVar._index
                if sidx_sets.type() is ContinuousSet:
                    sVar._contset[sidx_sets] = 0
            else:
                sidx_sets = sVar._implicit_subsets
                loc = 0
                for i, s in enumerate(sidx_sets):
                    if s.type() is ContinuousSet:
                        sVar._contset[s] = loc
                    loc += s.dimen
            num_contset = len(sVar._contset)

        if num_contset == 0:
            raise DAE_Error(
                "The variable %s is not indexed by any ContinuousSets. A "
                "derivative may only be taken with respect to a continuous "
                "domain" % sVar)

        if wrt is None:
            # Check to be sure Var is indexed by single ContinuousSet and take
            # first deriv wrt that set
            if num_contset != 1:
                raise DAE_Error(
                    "The variable %s is indexed by multiple ContinuousSets. "
                    "The desired ContinuousSet must be specified using the "
                    "keyword argument 'wrt'" % sVar)
            wrt = [next(iterkeys(sVar._contset)), ]
        elif type(wrt) is ContinuousSet:
            if wrt not in sVar._contset:
                raise DAE_Error(
                    "Invalid derivative: The variable %s is not indexed by "
                    "the ContinuousSet %s" % (sVar, wrt))
            wrt = [wrt, ]
        elif type(wrt) is tuple or type(wrt) is list:
            for i in wrt:
                if type(i) is not ContinuousSet:
                    raise DAE_Error(
                        "Cannot take the derivative with respect to %s. "
                        "Expected a ContinuousSet or a tuple of "
                        "ContinuousSets" % i)
                if i not in sVar._contset:
                    raise DAE_Error(
                        "Invalid derivative: The variable %s is not indexed "
                        "by the ContinuousSet %s" % (sVar, i))
            wrt = list(wrt)
        else:
            raise DAE_Error(
                "Cannot take the derivative with respect to %s. "
                "Expected a ContinuousSet or a tuple of ContinuousSets" % i)

        wrtkey = [str(i) for i in wrt]
        wrtkey.sort()
        wrtkey = tuple(wrtkey)

        if wrtkey in sVar._derivative:
            raise DAE_Error(
                "Cannot create a new derivative variable for variable "
                "%s: derivative already defined as %s"
                % (sVar.name, sVar._derivative[wrtkey]().name))

        sVar._derivative[wrtkey] = weakref.ref(self)
        self._sVar = sVar
        self._wrt = wrt

        kwds.setdefault('ctype', DerivativeVar)

        if sVar._implicit_subsets is None:
            arg = (sVar.index_set(),)
        else:
            arg = tuple(sVar._implicit_subsets)

        Var.__init__(self,*arg,**kwds)
Пример #21
0
    def apply(self, **kwds):
        if __debug__ and logger.isEnabledFor(logging.DEBUG):   #pragma:nocover
            logger.debug("Calling ConnectorExpander")
                
        instance = kwds['instance']
        blockList = list(instance.block_data_objects(active=True))
        noConnectors = True
        for b in blockList:
            if b.component_map(Connector):
                noConnectors = False
                break
        if noConnectors:
            return

        if __debug__ and logger.isEnabledFor(logging.DEBUG):   #pragma:nocover
            logger.debug("   Connectors found!")

        #
        # At this point, there are connectors in the model, so we must
        # look for constraints that involve connectors and expand them.
        #
        #options = kwds['options']
        #model = kwds['model']

        # In general, blocks should be relatively self-contained, so we
        # should build the connectors from the "bottom up":
        blockList.reverse()

        # Expand each constraint involving a connector
        for block in blockList:
            if __debug__ and logger.isEnabledFor(logging.DEBUG):   #pragma:nocover
                logger.debug("   block: " + block.cname())

            CCC = {}
            for name, constraint in itertools.chain\
                    ( iteritems(block.component_map(Constraint)), 
                      iteritems(block.component_map(ConstraintList)) ):
                cList = []
                CCC[name+'.expanded'] = cList
                for idx, c in iteritems(constraint._data):
                    if __debug__ and logger.isEnabledFor(logging.DEBUG):   #pragma:nocover
                        logger.debug("   (looking at constraint %s[%s])", name, idx)
                    connectors = []
                    self._gather_connectors(c.body, connectors)
                    if len(connectors) == 0:
                        continue
                    if __debug__ and logger.isEnabledFor(logging.DEBUG):   #pragma:nocover
                        logger.debug("   (found connectors in constraint)")
                    
                    # Validate that all connectors match
                    errors, ref, skip = self._validate_connectors(connectors)
                    if errors:
                        logger.error(
                            ( "Connector mismatch: errors detected when "
                              "constructing constraint %s\n    " %
                              (name + (idx and '[%s]' % idx or '')) ) +
                            '\n    '.join(reversed(errors)) )
                        raise ValueError(
                            "Connector mismatch in constraint %s" % \
                            name + (idx and '[%s]' % idx or ''))
                    
                    if __debug__ and logger.isEnabledFor(logging.DEBUG):   #pragma:nocover
                        logger.debug("   (connectors valid)")

                    # Fill in any empty connectors
                    for conn in connectors:
                        if conn.vars:
                            continue
                        for var in ref.vars:
                            if var in skip:
                                continue
                            v = Var()
                            block.add_component(conn.cname() + '.auto.' + var, v)
                            conn.vars[var] = v
                            v.construct()
                    
                    # OK - expand this constraint
                    self._expand_constraint(block, name, idx, c, ref, skip, cList)
                    # Now deactivate the original constraint
                    c.deactivate()
            for name, exprs in iteritems(CCC):
                cList = ConstraintList()
                block.add_component( name, cList )
                cList.construct()
                for expr in exprs:
                    cList.add(expr)
                

        # Now, go back and implement VarList aggregators
        for block in blockList:
            for conn in itervalues(block.component_map(Connector)):
                for var, aggregator in iteritems(conn.aggregators):
                    c = Constraint(expr=aggregator(block, var))
                    block.add_component(
                        conn.cname() + '.' + var.cname() + '.aggregate', c)
                    c.construct()
Пример #22
0
    def build(self):
        """
        Begin building model (pre-DAE transformation).

        Args:
            None

        Returns:
            None
        """
        # Call UnitModel.build to build default attributes
        super(MBRData, self).build()

        # Set flow directions for the control volume blocks
        # Gas flows from 0 to 1, solid flows from 1 to 0
        # An if statement is used here despite only one option to allow for
        # future extensions to other flow configurations
        if self.config.flow_type == "counter_current":
            set_direction_gas = FlowDirection.forward
            set_direction_solid = FlowDirection.backward

            # Set transformation scheme to be in the "opposite
            # direction" as flow.
            self.GAS_TRANSFORM_SCHEME = "BACKWARD"
            self.SOLID_TRANSFORM_SCHEME = "FORWARD"
        else:
            raise BurntToast("{} encountered unrecognized argument "
                             "for flow type. Please contact the IDAES"
                             " developers with this bug.".format(self.name))
        # Set arguments for gas sides if homoogeneous reaction block
        if self.config.gas_phase_config.reaction_package is not None:
            has_rate_reaction_gas_phase = True
        else:
            has_rate_reaction_gas_phase = False

        # Set arguments for gas and solid sides if heterogeneous reaction block
        if self.config.solid_phase_config.reaction_package is not None:
            has_rate_reaction_solid_phase = True
            has_mass_transfer_gas_phase = True
        else:
            has_rate_reaction_solid_phase = False
            has_mass_transfer_gas_phase = False

        # Set heat transfer terms
        if self.config.energy_balance_type != EnergyBalanceType.none:
            has_heat_transfer = True
        else:
            has_heat_transfer = False

        # Set heat of reaction terms
        if (self.config.energy_balance_type != EnergyBalanceType.none
                and self.config.gas_phase_config.reaction_package is not None):
            has_heat_of_reaction_gas_phase = True
        else:
            has_heat_of_reaction_gas_phase = False

        if (self.config.energy_balance_type != EnergyBalanceType.none and
                self.config.solid_phase_config.reaction_package is not None):
            has_heat_of_reaction_solid_phase = True
        else:
            has_heat_of_reaction_solid_phase = False

        # Create two different length domains; one for each phase.
        # Add them to this block so I can use one of them to index
        # all the variables on this block.
        # I can then call discretization on this block, which will
        # discretize the variables on the control volume blocks.
        self.solid_length_domain = ContinuousSet(
            bounds=(0.0, 1.0),
            initialize=self.config.length_domain_set,
            doc="Normalized length domain",
        )
        self.gas_length_domain = ContinuousSet(
            bounds=(0.0, 1.0),
            initialize=self.config.length_domain_set,
            doc="Normalized length domain",
        )
        self.bed_height = Var(domain=Reals, initialize=1, doc="Bed length [m]")
        super(_BlockData, self).__setattr__(
            'length_domain',
            self.solid_length_domain,
        )

        # =========================================================================
        """ Build Control volume 1D for gas phase and
            populate gas control volume"""

        self.gas_phase = ControlVolume1DBlock(
            default={
                "transformation_method":
                self.config.transformation_method,
                #"transformation_scheme": self.config.transformation_scheme,
                "transformation_scheme":
                self.GAS_TRANSFORM_SCHEME,
                "finite_elements":
                self.config.finite_elements,
                "collocation_points":
                self.config.collocation_points,
                "dynamic":
                self.config.dynamic,
                "has_holdup":
                self.config.has_holdup,
                "area_definition":
                DistributedVars.variant,
                "property_package":
                self.config.gas_phase_config.property_package,
                "property_package_args":
                self.config.gas_phase_config.property_package_args,
                "reaction_package":
                self.config.gas_phase_config.reaction_package,
                "reaction_package_args":
                self.config.gas_phase_config.reaction_package_args
            })

        # Pass gas_length_domain to the gas phase control volume
        # Note that length_domain_set is redundant as the set is
        # already initialized.
        self.gas_phase.add_geometry(
            length_domain=self.gas_length_domain,
            length_domain_set=self.config.length_domain_set,
            flow_direction=set_direction_gas,
        )

        self.gas_phase.add_state_blocks(information_flow=set_direction_gas,
                                        has_phase_equilibrium=False)

        if self.config.gas_phase_config.reaction_package is not None:
            self.gas_phase.add_reaction_blocks(
                has_equilibrium=self.config.gas_phase_config.
                has_equilibrium_reactions)

        self.gas_phase.add_material_balances(
            balance_type=self.config.material_balance_type,
            has_phase_equilibrium=False,
            has_mass_transfer=has_mass_transfer_gas_phase,
            has_rate_reactions=has_rate_reaction_gas_phase)

        self.gas_phase.add_energy_balances(
            balance_type=self.config.energy_balance_type,
            has_heat_transfer=has_heat_transfer,
            has_heat_of_reaction=has_heat_of_reaction_gas_phase)

        self.gas_phase.add_momentum_balances(
            balance_type=self.config.momentum_balance_type,
            has_pressure_change=self.config.has_pressure_change)

        # =========================================================================
        """ Build Control volume 1D for solid phase and
            populate solid control volume"""

        # Set argument for heterogeneous reaction block
        self.solid_phase = ControlVolume1DBlock(
            default={
                "transformation_method":
                self.config.transformation_method,
                "transformation_scheme":
                self.SOLID_TRANSFORM_SCHEME,
                "finite_elements":
                self.config.finite_elements,
                "collocation_points":
                self.config.collocation_points,
                # ^ These arguments have no effect as the transformation
                # is applied in this class.
                "dynamic":
                self.config.dynamic,
                "has_holdup":
                self.config.has_holdup,
                "area_definition":
                DistributedVars.variant,
                "property_package":
                self.config.solid_phase_config.property_package,
                "property_package_args":
                self.config.solid_phase_config.property_package_args,
                "reaction_package":
                self.config.solid_phase_config.reaction_package,
                "reaction_package_args":
                self.config.solid_phase_config.reaction_package_args
            })

        # Same comment as made for the gas phase.
        # Pass in the set we've constructed for this purpose.
        self.solid_phase.add_geometry(
            length_domain=self.solid_length_domain,
            length_domain_set=self.config.length_domain_set,
            flow_direction=set_direction_solid)

        # These constraints no longer are created by make_performance,
        # So I make them here...
        # Length of gas side, and solid side
        @self.Constraint(doc="Gas side length")
        def gas_phase_length(b):
            return (b.gas_phase.length == b.bed_height)

        @self.Constraint(doc="Solid side length")
        def solid_phase_length(b):
            return (b.solid_phase.length == b.bed_height)

        # Many other methods of the MBR base class actually rely on this
        # attribute, so here I slap on a reference. The particular set
        # I use shouldn't matter, as long as the derivatives are constructed
        # wrt the correct set.

        self.solid_phase.add_state_blocks(information_flow=set_direction_solid,
                                          has_phase_equilibrium=False)

        if self.config.solid_phase_config.reaction_package is not None:
            # TODO - a generalization of the heterogeneous reaction block
            # The heterogeneous reaction block does not use the
            # add_reaction_blocks in control volumes as control volumes are
            # currently setup to handle only homogeneous reaction properties.
            # Thus appending the heterogeneous reaction block to the
            # solid state block is currently hard coded here.

            tmp_dict = dict(
                **self.config.solid_phase_config.reaction_package_args)
            tmp_dict["gas_state_block"] = self.gas_phase.properties
            tmp_dict["solid_state_block"] = self.solid_phase.properties
            tmp_dict["has_equilibrium"] = (
                self.config.solid_phase_config.has_equilibrium_reactions)
            tmp_dict["parameters"] = (
                self.config.solid_phase_config.reaction_package)
            self.solid_phase.reactions = (
                self.config.solid_phase_config.reaction_package.
                reaction_block_class(
                    self.flowsheet().config.time,
                    self.length_domain,
                    doc="Reaction properties in control volume",
                    default=tmp_dict))

        self.solid_phase.add_material_balances(
            balance_type=self.config.material_balance_type,
            has_phase_equilibrium=False,
            has_mass_transfer=False,
            has_rate_reactions=has_rate_reaction_solid_phase)

        self.solid_phase.add_energy_balances(
            balance_type=self.config.energy_balance_type,
            has_heat_transfer=has_heat_transfer,
            has_heat_of_reaction=has_heat_of_reaction_solid_phase)

        self.solid_phase.add_momentum_balances(
            balance_type=MomentumBalanceType.none, has_pressure_change=False)

        # =========================================================================
        """ Add ports"""
        # Add Ports for gas side
        self.add_inlet_port(name="gas_inlet", block=self.gas_phase)
        self.add_outlet_port(name="gas_outlet", block=self.gas_phase)

        # Add Ports for solid side
        self.add_inlet_port(name="solid_inlet", block=self.solid_phase)
        self.add_outlet_port(name="solid_outlet", block=self.solid_phase)

        # =========================================================================
        """ Add performace equation method"""
        self._apply_transformation()
        self._make_performance()