def _getDependentBranch(thisNetwork, branchObj, *args, **kwargs): """GETDEPENDENTBRANCH get all branches that depend on branchObj another branch's potential depends on the potential of branchObj if branchObj is a twig another branch's flow depends on the flow of branchObj if branchObj is a chord """ twigVec, chordVec = thisNetwork.getTwigChordVec() B_t, D_c = thisNetwork.getTwigLoopChordCutsetMatrix() if branchObj.isTwig() == True: # get the index of the branchObj in the twig vector twigIdx = find(twigVec == branchObj) # A non-zero element there means that we have a chord whose # potential value depends on the potential value on the # branchObj. depChordIdx = find(B_t[:, twigIdx] != 0) depBranchVec = chordVec[depChordIdx] else: if branchObj.isChord() == True: # get the index of the branchObj in the chordVec chordIdx = find(chordVec == branchObj) # The location of a non-zero element in D_c points to the index # of a branch whose flow depends on the flow of branchObj. depTwigIdx = find(D_c[:, chordIdx] != 0) depBranchVec = twigVec[depTwigIdx] else: error( 'This branch has not been marked either as a twig'\ ' or a chord!' ) return depBranchVec
def resetDerivativeToZero(self, derivObj): # this function is used to generate equations like # d_varname_dervarname__ = 0; # These are required in some cases. # For an explanation see the comments in # the # IrVisitorGenerateDerivative.visitAssignment() # method varObj = self.varObj varSfx = self.VARSFX if derivObj == varObj: error(( 'Derivative of %s is being set to zero with respect '\ 'to itself!'\ % varObj.getName() )) else: if varObj.isDependentOnDerivObj(derivObj): derVarName = varObj.getDerivLabel(derivObj) + varSfx topModule = self.getModule() derVarObj = topModule.addVar(derVarName, utils.getConstantNode(0)) derVarObj.setDerivative() derVarNode = IrNodeVariable(derVarObj) headNode = IrNodeAssignment() headNode.addChild(derVarNode) zeroNode = utils.getConstantNode(0) headNode.addChild(zeroNode) else: headNode = IrNodeNumericalNull() return headNode
def visitVar(self, varNode = None, *args, **kwargs): out = [False, None] # Here varNode can be a parameter or a variable module = self.module varOrParmName = varNode.get_name() out[0] = True isNodeParm = module.isParm(varOrParmName) isNodeVar = module.isVar(varOrParmName) if isNodeParm == True and isNodeVar == True: error(( 'The parameter %s was redeclared as a variable!' % varOrParmName )) else: if isNodeParm == False and isNodeVar == False: error(( 'The variable or parameter %s was not defined in '\ 'this the module %s!'\ % (varOrParmName, module.getName()) )) else: if module.isParm(varOrParmName): parmObj = module.getParm(varOrParmName) out[1] = IrNodeParameter(parmObj) else: if module.isVar(varOrParmName): varObj = module.getVar(varOrParmName) out[1] = IrNodeVariable(varObj) return out
def generateDerivative(self, derivObj): # valid node types for derivatives: # +,-,*,/,u+,u-,** opType = self.getOpType() if self.hasOpType( ['+', '-', '*', '/', 'u+', 'u-', '**', '?:', '>', '>=', '<', '<=']) == False: error( 'The operation %s cannot be used in a derivative!' \ % opType ) if self.hasOpType(['+', '-', 'u+', 'u-']): headNode = IrNodeOperation(opType) generateSub = True else: if self.hasOpType('*'): generateSub = False headNode = self.derivMultiplication(derivObj) elif self.hasOpType('/'): generateSub = False headNode = self.derivDivision(derivObj) elif self.hasOpType('**'): generateSub = False headNode = self.derivPower(derivObj) elif self.hasOpType('?:'): generateSub = False headNode = self.derivQmcol(derivObj) elif self.hasOpType(['>', '>=', '<', '<=']): generateSub = False headNode = self.derivGreaterSmaller(derivObj) return (headNode, generateSub)
def _getCutNodes(thisNetwork,twigObj): # GETCUTNODES returns the node objects that are inside of a given cut # The cut is described by the twigObj (since every twig corresponds to # a cut). if twigObj.isTwig() == False: error( 'The argument to this function must be a branch'\ ' object which has been marked as a twig!' ) # A cut separates a network into two unconnected components. # One of these components will inlcude the reference node. # Because we don't have access to the flow into the reference # node (unless we sum all the other flows into the remaining # terminals), we will always use the set of nodes that don't # include the reference node. twigNode1, twigNode2 = twigObj.getNodes() refNode = thisNetwork.getRefNode() cutNodeVec = _traverseTreeComponent(twigNode1, twigObj) direction = 1 if (refNode in cutNodeVec) == True: cutNodeVec = _traverseTreeComponent(twigNode2, twigObj) direction = -1 # note: this should be cheaper than doing a setdiff return cutNodeVec,direction
def __init__(self, nodeObj1, nodeObj2): # MSBRANCH # NOTE: we will receive an error if the two nodes are already # connected if nodeObj1.hasCompatibleDiscipline(nodeObj2) == False: error(( 'Cannot create branch: node "%s" and node "%s" do'\ ' not have the same discipline!'\ % (nodeObj1.getLabel(), nodeObj2.getLabel()) )) self.node1 = nodeObj1 self.node2 = nodeObj2 nodeObj1.addBranch(self) nodeObj2.addBranch(self) self.label = nodeObj1.getLabel() + nodeObj2.getLabel() self.discipline = MsDiscipline() discipline = nodeObj1.getDiscipline() self.discipline = discipline self.aliasMap = AttrDict() self.flowObj = MsFlow(self) self.potentialObj = MsPotential(self) self.twig = False self.chord = False self.collapsed = False self.toBeCollapsed = False self.collapsedWarningDisplayed = False
def sprintRhs(self, fOrQ): # SPRINTRHS outStr = '' rhsPfVec = self.rhsPfVec nRhsPf = len(rhsPfVec) signVec = self.rhsSignVec varSfx = self.VARSFX if len(signVec) != nRhsPf: error('Number of rhs nodes and number of signs do not match!') if strcmp(fOrQ, 'f'): labelFunc = self.getFLabel elif strcmp(fOrQ, 'q'): labelFunc = self.getQLabel for i in range(nRhsPf): label = labelFunc(rhsPfVec[i]) if len(label) != 0: if signVec[i] == 1: signStr = '+' else: signStr = '-' outStr = ''.join([ outStr, signStr, label, varSfx ]) return outStr
def addChild(self, childNode): # ADDCHILD if self.nChild == 3: error(( 'Error adding a child to an IrNodeIfElse. This node'\ ' already has 3 children!' )) IrNode.addChild(self, childNode) return
def setOutIdx(self, outIdx): # SETOUTIDX if self.outIdx != 0: error( 'Cannot set output index because this output object '\ 'has already another one!' ) else: self.outIdx = outIdx return
def setPrintMode(self, printMode): # SETPRINTMODE if (printMode in IrNodeModel.VALIDPRINTMODES): self.printMode = printMode else: error( 'Error in IrNodeModel: %s is not a valid print mode!'\ % printMode ) return
def isConnectedTo(self, aNode): # ISCONNECTEDTO if aNode == self: error('You are probing if this node is connected to itself!') branch = self.getBranch(aNode) if branch is not None: out=True else: out=False return out
def setChord(self): # SETCHORD if self.twig == True: error( 'Cannot set branch as chord because it is marked as'\ ' a twig.' ) else: self.chord = True return
def setTwig(self): # SETTWIG if self.chord == True: error( 'Cannot set branch as twig because it is marked as'\ ' a chord.' ) else: self.twig = True return
def getNegativeOfNode(irNode): # GETNEGATIVEOFNODE if isinstance(irNode, IrNodeNumerical) == False: error(''.join([ 'This node cannot be used in the getNegativeOfNode ', 'function because it is not of class IrNodeNumerical!' ])) uMinusNode = IrNodeOperation('u-') uMinusNode.addChild(irNode) return uMinusNode
def isAliasReversed(self, aliasStr): # ISALIASREVERSED if self.hasAlias(aliasStr): out = (self.aliasMap(aliasStr) == -1) else: error( 'This branch does not have the alias \'%s\'' \ % aliasStr ) return out
def addChild(self, childNode): # ADDCHILD if self.nChild >= 2: error( 'This assignment already has 2 children. The number'\ ' of children in an assignment cannot be more than 2!' ) else: IrNode.addChild(self, childNode) return
def setContribIdx(self, cIdx): """SETCONTRIBIDX """ if self.contribIdx > cIdx: error(( 'Error setting contribIdx. The new contribIdx'\ ' cannot be smaller than the old one!' )) else: self.contribIdx = cIdx return
def setParent(self, parentNode=None, *args, **kwargs): if self.parent is None: self.parent = parentNode if parentNode.isConnectedToModule() == True: self.setConnectedToModule() else: error(''.join([ 'This node has already a parent. ', 'Use removeParent function first to remove it.' ])) return
def setNodes(self, nodeObj1, nodeObj2): # SETNODES self.node1 = nodeObj1 self.node2 = nodeObj2 if nodeObj1.isConnectedTo(nodeObj2) == True: branchObj = nodeObj1.getBranch(nodeObj2) else: error("Cannot create MsBranch object here!\n") # branchObj = MsBranch(nodeObj1,nodeObj2) self.branch = branchObj return
def setNetwork(self,networkObj): # SETNETWORK if self.network is None: self.network = networkObj else: error(( 'Cannot set network of node %s because it already '\ 'belongs to a network!' % self.label )) return
def hasTwigOtherThan(self, twig): # HASTWIGOTHERTHAN out = False if self.hasBranch(twig) == False: error('This node does not have this twig (%s)!' % twig.getLabel()) for branch in self.branchVec: if (branch.isTwig() == True and (branch != twig)): out=True break return out
def addDependPf(self, pfObj): # ADDDEPENDPF if self.inNodeCollapse == True: error(( 'A node collapse statement depends on the variable'\ ' "%s" whose value depends on the potential/flow'\ ' "%s". Bias dependent node collapse statements are'\ ' not allowed!'\ % (self.getLabel(),pfObj.getLabel()) )) MsDifferentiable.addDependPf(self, pfObj) return
def setProbeIdx(self, pIdx): """ SETPROBEIDX """ if self.probeIdx < pIdx: error(( 'Error setting probeIdx. The new probeIdx cannot be'\ ' greater than the old one!' )) else: self.probeIdx = pIdx return
def getNodeOrder(self, nodeObj1, nodeObj2): # NAME if (nodeObj1 == self.node1) and (nodeObj2 == self.node2): out = 1 elif nodeObj2 == self.node1 and nodeObj1 == self.node2: out = -1 else: error( 'The supplied nodes do not match with the nodes of'\ 'this branch!' ) return out
def getDisciplineName(self): # GETDISCIPLINENAME if self.discipline is not None: discipName = self.discipline.name else: error(( 'The node %s has no discipline set for it.'\ ' Discipline statements have to come before, e.g.,'\ ' branch declarations.'\ % self.label )) return discipName
def getOtherNode(self, aNode): # GETOTHERNODE if self.node1 == aNode: otherNode = self.node2 elif self.node2 == aNode: otherNode = self.node1 else: error(( 'Error this branch is not connected to %s!' \ % aNode.getLabel() )) return otherNode
def getTerminalNode(self): if self.isReference() == True: nodeObj1 = self.node1 nodeObj2 = self.node2 if nodeObj1.isTerminal() == True: tNode = nodeObj1 else: tNode = nodeObj2 else: error( 'Cannot get terminal node. This branch is not a'\ ' reference branch!') return tNode
def getDirection(self, nodeObj): """ GETDIRECTION returns the diretion of the branch with respect to the nodeObj bDir = 1 if branch goes out of nodeObj bDir = -1 if branch goes into nodeObj """ bDir = self.getIncidenceCoeff(nodeObj) if bDir == 0: error(( 'This branch is not connected to node %s!' \ % nodeObj.getLabel() )) return bDir
def addBranch(self, branchObj): otherNode = branchObj.getOtherNode(self) if self.getBranch(otherNode) is None: self.branchVec.append(branchObj) else: error(( 'Cannot add this branch! '\ '%s is already connected to %s with another ' 'branch.'\ % (self.getLabel(), otherNode.getLabel()) )) if self.network is not None: self.network.addBranch(branchObj) return
def getPotentialOrFlow(self, accessLabel): # GETPOTENTIALORFLOW potentialAccess = self.discipline.potential.access flowAccess = self.discipline.flow.access if (accessLabel == potentialAccess): pfObj = self.potentialObj elif (accessLabel == flowAccess): pfObj = self.flowObj else: error(( 'Access label (%s) does not match neither the flow'\ ' (%s) nor the potential (%s) access of this branch!'\ % (accessLabel, flowAccess, potentialAccess) )) return pfObj