def calculateCommandEffects(self, state): """ Calculates the (currently local) effect of a switch position change. :param state: Calculated State object with switch position :return: True if successful, False if calculation was not possible (missing values) """ try: newPosition = state.retrieveValue(self.stateKey) if newPosition: # Switch close # No chance to calculate this?? # Adverse effects possible? (yes, but not very probable?) return True else: # Switch open if self.connectedLine.startSwitch == self: removedCurrent = state.retrieveValue( self.connectedLine.startMeter.currentKey) state.updateValue(self.connectedLine.startMeter.currentKey, 0.0) state.updateValue(self.connectedLine.endMeter.currentKey, 0.0) affectedNode = self.connectedLine.startNode try: affectedLines = [ l for l in affectedNode.linesOut if state.retrieveValue(l.startSwitch.stateKey) ] endNodes = defaultdict(lambda: 0) for l in affectedLines: endNodes[ l.endNode.name] = endNodes[l.endNode.name] + 1 for l in affectedLines: try: measuredCurrent = state.retrieveValue( l.startMeter.currentKey) # split between lines with same destination if not isZero(measuredCurrent): state.updateValue( l.startMeter.currentKey, measuredCurrent + removedCurrent / endNodes[l.endNode.name]) except ValueNotStoredException, e: pass except: for l in affectedNode.linesOut: try: measuredCurrent = state.retrieveValue( l.startMeter.currentKey) # worst case for every line if not isZero(measuredCurrent): state.updateValue( l.startMeter.currentKey, measuredCurrent + removedCurrent) except ValueNotStoredException, e: pass else: removedCurrent = state.retrieveValue(
def safetyCheckR2(self, state): """ This safety rule checks that the voltage is within its allowed interval around the nominal voltage :param state: State object (observed or calculated) :return: True if safety rule holds, False otherwise (violation) """ logCheckDescription("R2", indentation=3) passed = True for l in self.getAllConnectedLines(): try: safeInterval = (l.nominalV * (1 - l.voltageBoundaryFactor), l.nominalV * (1 + l.voltageBoundaryFactor)) localVoltage = l.retrieveValue(state, self, "local", "voltage") if not isZero(localVoltage): currentPassed = safeInterval[ 0] <= localVoltage <= safeInterval[1] passed = False if not currentPassed else passed logDebugCheckValues( "Line %s. Local: V=%f (in [%3.2f;%3.2f])." % (l.name, localVoltage, safeInterval[0], safeInterval[1]), currentPassed, indentation=3) except ValueNotStoredException, e: logDebugUnknownValues(e.message, l.name, indentation=3)
def consistencyCheckP6b(self, state): """ This consistency rule checks whether the transformation rate is consistent with the current measurement. :param state: State object (observed or calculated) :return: True if consistency rule holds, False otherwise (violation) """ logCheckDescription("P6b", indentation=3) passed = True if callable(self.rateFunction): try: measuredInCurrent = self.linesIn[0].retrieveValue( state, self, "local", "current") measuredOutCurrent = self.linesOut[0].retrieveValue( state, self, "local", "current") currentTapPosition = state.retrieveValue(self.tapPositionKey) if isZero(measuredInCurrent): passed = True logDebugCheckValues( "Transformer %s. No incoming or outgoing current." % (self.name), passed, indentation=3) else: try: currentTransformerRate = self.rateFunction( currentTapPosition) expectedMeasuredTransformedOutCurrent = measuredInCurrent * float( currentTransformerRate) if isClose(expectedMeasuredTransformedOutCurrent, measuredOutCurrent): passed = True else: passed = False logDebugCheckValues( "Transformer %s. Measured input current: %fA. Measured output current: %fA. Expected output current: %fA." % (self.name, measuredInCurrent, measuredOutCurrent, expectedMeasuredTransformedOutCurrent), passed, indentation=3) except IndexError: passed = False logDebugCheckValues( "Transformer %s. Discrete tap function, tap position %d has no rate defined." % (self.name, int(round(currentTapPosition))), passed, indentation=3) except ZeroDivisionError: passed = False logDebugCheckValues( "Transformer %s. Measured input current: %fA. Measured output current: %fA. (Division by zero, not consistent)." % (self.name, measuredInCurrent, measuredOutCurrent), passed, indentation=3) except ValueNotStoredException, e: passed = True logDebugUnknownValues(e.message, indentation=3)
def safetyCheckR5b(self, state): """ This safety rule checks whether the transformer rate is safe on actual voltage :param state: State object (observed or calculated) :return: True if safety rule holds, False otherwise (violation) """ logCheckDescription("R5b", indentation=3) passed = True if callable(self.rateFunction): try: measuredInVoltage = self.linesIn[0].retrieveValue( state, self, "local", "voltage") nominalOutVoltage = self.linesOut[0].nominalV currentTapPosition = state.retrieveValue(self.tapPositionKey) if isZero(measuredInVoltage): currentPassed = True passed = False if not currentPassed else passed logDebugCheckValues( "Transformer %s. Actual input voltage: %fV. Nominal output voltage: %fV. Input voltage is zero." % (self.name, measuredInVoltage, nominalOutVoltage), currentPassed, indentation=3) else: try: currentTransformerRate = self.rateFunction( currentTapPosition) actualTransformedOutVoltage = measuredInVoltage / float( currentTransformerRate) nominalSafeInterval = ( nominalOutVoltage * (1 - self.linesOut[0].voltageBoundaryFactor), nominalOutVoltage * (1 + self.linesOut[0].voltageBoundaryFactor)) if nominalSafeInterval[ 0] <= actualTransformedOutVoltage <= nominalSafeInterval[ 1]: currentPassed = True else: currentPassed = False passed = False if not currentPassed else passed logDebugCheckValues( "Transformer %s. Actual input voltage: %fV. Nominal output voltage: %fV. Transformed actual output voltage: %fV (should be in [%3.2f;%3.2f])." % (self.name, measuredInVoltage, nominalOutVoltage, actualTransformedOutVoltage, nominalSafeInterval[0], nominalSafeInterval[1]), currentPassed, indentation=3) except IndexError: currentPassed = False passed = False if not currentPassed else passed logDebugCheckValues( "Transformer %s. Discrete tap function, tap position %d has no rate defined." % (self.name, int(round(currentTapPosition))), currentPassed, indentation=3) except ValueNotStoredException, e: passed = True logDebugUnknownValues(e.message, indentation=3)
def safetyCheckR6(self, state): """ This safety rule checks whether all consumers are connected to the power grid :param state: State object (observed or calculated) :return: True if safety rule holds, False otherwise (violation) """ logCheckDescription("R6", indentation=2) passed = True for l in getAllComponentsOfType(Consumer): if len(l.linesIn) == 0: try: consumedPower = (-1) * state.retrieveValue(l.consumedPowerKey) if isZero(consumedPower): currentPassed = True passed = False if not currentPassed else passed logDebugCheckValues("Consumer %s connected to no line, and no power consumed. %fW" % (l.name, consumedPower), currentPassed, indentation=3) else: currentPassed = False passed = False if not currentPassed else passed logDebugCheckValues("Consumer %s connected to no line, but power consumed. %fW" % (l.name, consumedPower), currentPassed, indentation=3) except ValueNotStoredException, e: logDebugUnknownValues(e.message, l.name, indentation=3) elif len(l.linesIn) == 1: try: consumedPower = (-1) * state.retrieveValue(l.consumedPowerKey) localVoltage = l.linesIn[0].retrieveValue(state, l, "local", "voltage") localSwitch = l.linesIn[0].retrieveValue(state, l, "local", "switchState") remoteSwitch = l.linesIn[0].retrieveValue(state, l, "remote", "switchState") currentPassed = localSwitch and remoteSwitch and not isZero(localVoltage) passed = False if not currentPassed else passed logDebugCheckValues("Consumer %s connected to power supply. Local Switch: %s (== True). Remote Switch: %s (== True). V=%f (>0) P=%fW." % (l.name, localSwitch, remoteSwitch, localVoltage, consumedPower), currentPassed, indentation=3) except ValueNotStoredException, e: logDebugUnknownValues(e.message, l.name, indentation=3) try: consumedPower = (-1) * state.retrieveValue(l.consumedPowerKey) localVoltage = l.linesIn[0].retrieveValue(state, l, "local", "voltage") localSwitch = l.linesIn[0].retrieveValue(state, l, "local", "switchState") currentPassed = localSwitch and not isZero(localVoltage) passed = False if not currentPassed else passed logDebugCheckValues("Consumer %s connected to power supply. Local Switch: %s (== True). Remote Switch unknown. V=%f (>0) P=%fW." % (l.name, localSwitch, localVoltage, consumedPower), currentPassed, indentation=3) except ValueNotStoredException, e: pass
def sendValue(sock, rtuTags, eventType, k, v): apdu = None try: if eventType == "C102": apdu = APDUType102(RTU_NUMBER, rtuTags[k].addresses[1]) else: if type(v) == float: if not isZero(rtuTags[k].lowerBound) and not isZero( rtuTags[k].lowerBound): v = normalizeValue(v, rtuTags[k].lowerBound, rtuTags[k].upperBound) if eventType == "COMMAND": apdu = APDUType61(RTU_NUMBER, rtuTags[k].addresses[2], v, datetime.datetime.now()) elif eventType == "MEASUREMENT": apdu = APDUType34(RTU_NUMBER, rtuTags[k].addresses[1], v, datetime.datetime.now()) else: assert False else: if eventType == "COMMAND": apdu = APDUType63(RTU_NUMBER, rtuTags[k].addresses[2], v, datetime.datetime.now()) elif eventType == "MEASUREMENT": apdu = APDUType36(RTU_NUMBER, rtuTags[k].addresses[1], v, datetime.datetime.now()) else: assert False elif type(v) == bool: if eventType == "COMMAND": apdu = APDUType58(RTU_NUMBER, rtuTags[k].addresses[2], v, datetime.datetime.now()) elif eventType == "MEASUREMENT": apdu = APDUType30(RTU_NUMBER, rtuTags[k].addresses[1], v, datetime.datetime.now()) else: assert False else: print "Value type not valid. (Allowed: Bool, Float)" assert False except Exception, e: print "Exception while creating APDUs: %s" % e.message assert False
def consistencyCheckP6a(self, state): """ This consistency rule checks whether the transformation rate is consistent with the voltage measurement. :param state: State object (observed or calculated) :return: True if consistency rule holds, False otherwise (violation) """ logCheckDescription("P6a", indentation=3) passed = True if callable(self.rateFunction): try: measuredInVoltage = self.linesIn[0].retrieveValue( state, self, "local", "voltage") measuredOutVoltage = self.linesOut[0].retrieveValue( state, self, "local", "voltage") currentTapPosition = state.retrieveValue(self.tapPositionKey) if isZero(measuredOutVoltage): passed = True logDebugCheckValues( "Transformer %s. Measured input voltage: %fV. Measured output voltage: %fV. Output voltage zero!" % (self.name, measuredInVoltage, measuredOutVoltage), passed, indentation=3) else: try: currentTransformerRate = self.rateFunction( currentTapPosition) expectedMeasuredTransformedOutVoltage = measuredInVoltage / float( currentTransformerRate) if isClose(expectedMeasuredTransformedOutVoltage, measuredOutVoltage): passed = True else: passed = False logDebugCheckValues( "Transformer %s. Measured input voltage: %fV. Measured output voltage: %fV. Expected output voltage: %fV." % (self.name, measuredInVoltage, measuredOutVoltage, expectedMeasuredTransformedOutVoltage), passed, indentation=3) except IndexError: passed = False logDebugCheckValues( "Transformer %s. Discrete tap function, tap position %d has no rate defined. " % (self.name, int(round(currentTapPosition))), passed, indentation=3) except ValueNotStoredException, e: passed = True logDebugUnknownValues(e.message, indentation=3)
class AbstractNode(AbstractComponent): def __init__(self, name, linesIn, linesOut): """ Initialize a node type. :param name: Name of the node. :param linesIn: List of ingoing lines :param linesOut: List of outgoing lines """ super(AbstractNode, self).__init__(name) assert isinstance(linesIn, list) assert isinstance(linesOut, list) self.linesIn = linesIn self.linesOut = linesOut for l in linesIn: assert isinstance(l, PowerLine) l.setEndNode(self) for l in linesOut: assert isinstance(l, PowerLine) l.setStartNode(self) def consistencyCheckP3(self, state): """ This consistency rule checks that the current is zero if a switch, fuse or protective relay has an open circuit. :param state: State object (observed or calculated) :return: True if consistency rule holds, False otherwise (violation) """ logCheckDescription("P3", indentation=3) passed = True openSwitchedLines = [] for l in self.getAllConnectedLines(): try: if l.getLocalComponent( self, "local", "switch") and not l.retrieveValue( state, self, "local", "switchState"): openSwitchedLines.append(l) elif l.getLocalComponent( self, "remote", "switch") and not l.retrieveValue( state, self, "remote", "switchState"): openSwitchedLines.append(l) elif l.getLocalComponent( self, "local", "fuse") and not l.retrieveValue( state, self, "local", "fuseState"): openSwitchedLines.append(l) elif l.getLocalComponent( self, "remote", "fuse") and not l.retrieveValue( state, self, "remote", "fuseState"): openSwitchedLines.append(l) elif l.getLocalComponent( self, "local", "protectiveRelay") and not l.retrieveValue( state, self, "local", "protectiveRelayState"): openSwitchedLines.append(l) elif l.getLocalComponent( self, "remote", "protectiveRelay") and not l.retrieveValue( state, self, "remote", "protectiveRelayState"): openSwitchedLines.append(l) except ValueNotStoredException, e: logDebugUnknownValues(e.message, l.name, indentation=3) if len(openSwitchedLines) > 0: for l in openSwitchedLines: try: # localVoltage = l.retrieveValue(state, self, "local", "voltage") localCurrent = l.retrieveValue(state, self, "local", "current") # remoteVoltage = l.retrieveValue(state, self, "remote", "voltage") remoteCurrent = l.retrieveValue(state, self, "remote", "current") # currentPassed = isZero(localVoltage) and isZero(localCurrent) and isZero(remoteVoltage) and isZero( # remoteCurrent) currentPassed = isZero(localCurrent) and isZero( remoteCurrent) passed = False if not currentPassed else passed # logDebugCheckValues( # "Open circuit (switch/fuse/protectiveRelay) on line %s. Local: V=%f (==0.0) AND A=%f (==0.0). Remote: V=%f (==0.0) AND A=%f (==0.0). %s" % ( # l.name, localVoltage, localCurrent, remoteVoltage, remoteCurrent, str(currentPassed)), # indentation=3) logDebugCheckValues( "Open circuit (switch/fuse/protectiveRelay) on line %s. Local: A=%f (==0.0). Remote: A=%f (==0.0)." % (l.name, localCurrent, remoteCurrent), currentPassed, indentation=3) except ValueNotStoredException, e: logDebugUnknownValues(e.message, l.name, indentation=3) try: # localVoltage = l.retrieveValue(state, self, "local", "voltage") localCurrent = l.retrieveValue(state, self, "local", "current") # currentPassed = isZero(localVoltage) and isZero(localCurrent) currentPassed = isZero(localCurrent) passed = False if not currentPassed else passed # logDebugCheckValues( # "Open circuit (switch/fuse/protectiveRelay) on line %s. Local: V=%f (==0.0) AND A=%f (==0.0). (Remote values unknown) %s" % ( # l.name, localVoltage, localCurrent, str(currentPassed)), indentation=3) logDebugCheckValues( "Open circuit (switch/fuse/protectiveRelay) on line %s. Local: A=%f (==0.0). Remote values unknown." % (l.name, localCurrent), currentPassed, indentation=3) except ValueNotStoredException, e: pass
class Switch(AbstractDecorator): switchesByTags = defaultdict(lambda: None) def __init__(self, name, stateKey=None): """ Initialize a switch. :param name: Name of the meter. :param stateKey: Key for retrieving switch state """ super(Switch, self).__init__(name) self.stateKey = stateKey if stateKey else "%s_STATE" % self.name.upper( ) Switch.switchesByTags[self.stateKey] = self self.interlocks = [] def calculateCommandEffects(self, state): """ Calculates the (currently local) effect of a switch position change. :param state: Calculated State object with switch position :return: True if successful, False if calculation was not possible (missing values) """ try: newPosition = state.retrieveValue(self.stateKey) if newPosition: # Switch close # No chance to calculate this?? # Adverse effects possible? (yes, but not very probable?) return True else: # Switch open if self.connectedLine.startSwitch == self: removedCurrent = state.retrieveValue( self.connectedLine.startMeter.currentKey) state.updateValue(self.connectedLine.startMeter.currentKey, 0.0) state.updateValue(self.connectedLine.endMeter.currentKey, 0.0) affectedNode = self.connectedLine.startNode try: affectedLines = [ l for l in affectedNode.linesOut if state.retrieveValue(l.startSwitch.stateKey) ] endNodes = defaultdict(lambda: 0) for l in affectedLines: endNodes[ l.endNode.name] = endNodes[l.endNode.name] + 1 for l in affectedLines: try: measuredCurrent = state.retrieveValue( l.startMeter.currentKey) # split between lines with same destination if not isZero(measuredCurrent): state.updateValue( l.startMeter.currentKey, measuredCurrent + removedCurrent / endNodes[l.endNode.name]) except ValueNotStoredException, e: pass except: for l in affectedNode.linesOut: try: measuredCurrent = state.retrieveValue( l.startMeter.currentKey) # worst case for every line if not isZero(measuredCurrent): state.updateValue( l.startMeter.currentKey, measuredCurrent + removedCurrent) except ValueNotStoredException, e: pass else: removedCurrent = state.retrieveValue( self.connectedLine.endMeter.currentKey) state.updateValue(self.connectedLine.startMeter.currentKey, 0.0) state.updateValue(self.connectedLine.endMeter.currentKey, 0.0) affectedNode = self.connectedLine.endNode try: affectedLines = [ l for l in affectedNode.linesIn if state.retrieveValue(l.endSwitch.stateKey) ] startNodes = defaultdict(lambda: 0) for l in affectedLines: startNodes[l.startNode. name] = startNodes[l.startNode.name] + 1 for l in affectedLines: try: measuredCurrent = state.retrieveValue( l.endMeter.currentKey) # split between lines with same destination if not isZero(measuredCurrent): state.updateValue( l.endMeter.currentKey, measuredCurrent + removedCurrent / startNodes[l.startNode.name]) except ValueNotStoredException, e: pass except: for l in affectedNode.linesIn: try: measuredCurrent = state.retrieveValue( l.endMeter.currentKey) # worst case for every line if not isZero(measuredCurrent): state.updateValue( l.endMeter.currentKey, measuredCurrent + removedCurrent) except ValueNotStoredException, e: pass