def _Combine(port, name, index_set): port_parent = port.parent_block() var = port.vars[name] in_vars = [] sources = port.sources(active=True) if not len(sources): return in_vars if len(sources) == 1 and len( sources[0].source.dests(active=True)) == 1: # This is a 1-to-1 connection, no need for evar, just equality. arc = sources[0] Port._add_equality_constraint(arc, name, index_set) return in_vars for arc in sources: 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) in_vars.append(evar) if len(sources) == 1: tighten_var_domain(port.vars[name], in_vars[0], index_set) # Create constraint: var == sum of evars # Same logic as Port._Split cname = unique_component_name( port_parent, "%s_%s_insum" % (alphanum_label_from_name(port.local_name), name)) if index_set is not UnindexedComponent_set: def rule(m, *args): return sum(evar[args] for evar in in_vars) == var[args] else: def rule(m): return sum(evar for evar in in_vars) == var con = Constraint(index_set, rule=rule) port_parent.add_component(cname, con) return in_vars
def _Split(port, name, index_set, include_splitfrac=None, write_var_sum=True): port_parent = port.parent_block() var = port.vars[name] out_vars = [] 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)) if include_splitfrac is not True: include_splitfrac = False 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 include_splitfrac is False: 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 port.vars.items(): 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)) include_splitfrac = False 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 if index_set is not UnindexedComponent_set: def rule(m, *args): return evar[args] == eblock.splitfrac * var[args] else: def rule(m): return evar == eblock.splitfrac * var con = Constraint(index_set, rule=rule) eblock.add_component(cname, con) if len(dests) == 1: tighten_var_domain(port.vars[name], out_vars[0], index_set) 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)) if index_set is not UnindexedComponent_set: def rule(m, *args): return sum(evar[args] for evar in out_vars) == var[args] else: def rule(m): 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 include_splitfrac is False: 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