def _create_evar(member, name, eblock, index_set): # Name is same, conflicts are prevented by a check in Port.add. # The new var will mirror the original var and have same index set. # We only need one evar per arc, so check if it already exists # before making a new one. evar = eblock.component(name) if evar is None: evar = replicate_var(member, name, eblock, index_set) return evar
def _validate_and_expand_port_set(self, ports): ref = {} # First, go through the ports and get the superset of all fields for p in ports: for k, v in iteritems(p.vars): if k in ref: # We have already seen this var continue if v is None: # This is an implicit var continue # OK: New var, so add it to the reference list _len = (-1 if not v.is_indexed() else len(v)) ref[k] = (v, _len, p, p.rule_for(k)) if not ref: logger.warning("Cannot identify a reference port: no ports " "in the port set have assigned variables:\n\t(%s)" % ', '.join(sorted(p.name for p in itervalues(ports)))) return ref # Now make sure that ports match empty_or_partial = [] for p in ports: p_is_partial = False if not p.vars: # This is an empty port and should be defined with # "auto" vars empty_or_partial.append(p) continue for k, v in iteritems(ref): if k not in p.vars: raise ValueError( "Port mismatch: Port '%s' missing variable " "'%s' (appearing in reference port '%s')" % (p.name, k, v[2].name)) _v = p.vars[k] if _v is None: if not p_is_partial: empty_or_partial.append(p) p_is_partial = True continue _len = (-1 if not _v.is_indexed() else len(_v)) if (_len >= 0) ^ (v[1] >= 0): raise ValueError( "Port mismatch: Port variable '%s' mixing " "indexed and non-indexed targets on ports '%s' " "and '%s'" % (k, v[2].name, p.name)) if _len >= 0 and _len != v[1]: raise ValueError( "Port mismatch: Port variable '%s' index " "mismatch (%s elements in reference port '%s', " "but %s elements in port '%s')" % (k, v[1], v[2].name, _len, p.name)) if v[1] >= 0 and len(v[0].index_set() ^ _v.index_set()): raise ValueError( "Port mismatch: Port variable '%s' has " "mismatched indices on ports '%s' and '%s'" % (k, v[2].name, p.name)) if p.rule_for(k) is not v[3]: raise ValueError("Port mismatch: Port variable '%s' has " "different rules on ports '%s' and '%s'" % (k, v[2].name, p.name)) # as we are adding things to the model, sort by key so that # the order things are added is deterministic sorted_refs = sorted(iteritems(ref)) if len(empty_or_partial) > 1: # This is expensive (names aren't cheap), but does result in # a deterministic ordering empty_or_partial.sort(key=lambda x: x.getname( fully_qualified=True, name_buffer=self._name_buffer)) # Fill in any empty ports for p in empty_or_partial: block = p.parent_block() for k, v in sorted_refs: if k in p.vars and p.vars[k] is not None: continue vname = unique_component_name( block, '%s_auto_%s' % (p.getname(fully_qualified=True, name_buffer=self._name_buffer), k)) new_var = replicate_var(v[0], vname, block) # add this new variable to the port so that it has a rule p.add(new_var, k, rule=v[3]) return ref
def _validate_and_expand_port_set(self, ports): ref = {} # First, go through the ports and get the superset of all fields for p in ports: for k, v in iteritems(p.vars): if k in ref: # We have already seen this var continue if v is None: # This is an implicit var continue # OK: New var, so add it to the reference list _len = ( -1 if not v.is_indexed() else len(v)) ref[k] = (v, _len, p, p.rule_for(k)) if not ref: logger.warning( "Cannot identify a reference port: no ports " "in the port set have assigned variables:\n\t(%s)" % ', '.join(sorted(p.name for p in itervalues(ports)))) return ref # Now make sure that ports match empty_or_partial = [] for p in ports: p_is_partial = False if not p.vars: # This is an empty port and should be defined with # "auto" vars empty_or_partial.append(p) continue for k, v in iteritems(ref): if k not in p.vars: raise ValueError( "Port mismatch: Port '%s' missing variable " "'%s' (appearing in reference port '%s')" % (p.name, k, v[2].name)) _v = p.vars[k] if _v is None: if not p_is_partial: empty_or_partial.append(p) p_is_partial = True continue _len = ( -1 if not _v.is_indexed() else len(_v)) if (_len >= 0) ^ (v[1] >= 0): raise ValueError( "Port mismatch: Port variable '%s' mixing " "indexed and non-indexed targets on ports '%s' " "and '%s'" % (k, v[2].name, p.name)) if _len >= 0 and _len != v[1]: raise ValueError( "Port mismatch: Port variable '%s' index " "mismatch (%s elements in reference port '%s', " "but %s elements in port '%s')" % (k, v[1], v[2].name, _len, p.name)) if v[1] >= 0 and len(v[0].index_set() ^ _v.index_set()): raise ValueError( "Port mismatch: Port variable '%s' has " "mismatched indices on ports '%s' and '%s'" % (k, v[2].name, p.name)) if p.rule_for(k) is not v[3]: raise ValueError( "Port mismatch: Port variable '%s' has " "different rules on ports '%s' and '%s'" % (k, v[2].name, p.name)) # as we are adding things to the model, sort by key so that # the order things are added is deterministic sorted_refs = sorted(iteritems(ref)) if len(empty_or_partial) > 1: # This is expensive (names aren't cheap), but does result in # a deterministic ordering empty_or_partial.sort(key=lambda x: x.getname( fully_qualified=True, name_buffer=self._name_buffer)) # Fill in any empty ports for p in empty_or_partial: block = p.parent_block() for k, v in sorted_refs: if k in p.vars and p.vars[k] is not None: continue vname = unique_component_name( block, '%s_auto_%s' % (p.getname( fully_qualified=True, name_buffer=self._name_buffer),k)) new_var = replicate_var(v[0], vname, block) # add this new variable to the port so that it has a rule p.add(new_var, k, rule=v[3]) return ref