First time here? We are a friendly community of Power Systems Engineers. Check out the FAQ!
1 | initial version |
Just an idea, the attached code can be run in PSSE to get the shortest path between two buses. If you use your slack bus as one, and the queried bus as the other, the length of the result will be your path length. It is feasible to step through your buses and save the path lengths for each and sort. It is computational expensive however.
# Delivers shortest path (miles) between two buses
# The two buses must be the same voltage level (the script cannot see past transformers)
# Can't default to swing bus for everything if it's a different voltage level than bus1.
from collections import defaultdict
class Graph():
def __init__(self):
"""
self.edges is a dict of all possible next nodes e.g. {'X': ['A', 'B', 'C', 'E'], ...}
self.weights has all the weights between two nodes, with the two nodes as a tuple as the key
e.g. {('X', 'A'): 7, ('X', 'B'): 2, ...}
"""
self.edges = defaultdict(list)
self.weights = {}
def add_edge(self, from_node, to_node, weight):
# Note: assumes edges are bi-directional
self.edges[from_node].append(to_node)
self.edges[to_node].append(from_node)
self.weights[(from_node, to_node)] = weight
self.weights[(to_node, from_node)] = weight
def dijsktra(graph, initial, end):
# shortest paths is a dict of nodes whose value is a tuple of (previous node, weight)
shortest_paths = {initial: (None, 0)}
current_node = initial
visited = set()
while current_node != end:
visited.add(current_node)
jbus = 1
ierr = psspy.inibrn(current_node,2)
# nxtbrn provides neighboring buses until all have been provided. Then it returns jbus = 0
while jbus > 0:
ierr, jbus, kbus, ickt = psspy.nxtbrn3(current_node)
if jbus > 0:
# Get the length of the line between these two buses (in miles)
ierr, weight = psspy.brndat(current_node,jbus,ickt,'LENGTH') # gives the literal shortest path
weight = 1.0 #override weight to minimize the number of bus hops (longer line miles)
if weight is None:
weight=0.0
edge = (current_node,jbus,weight)
# Add this edge to the graph if it's not there already
if edge not in graph.edges:
graph.add_edge(*edge)
# Destinations: all the buses we can go to from the bus we're currently at
destinations = graph.edges[current_node]
# weight_to_current_node: how far we've travelled so far to get to this node
weight_to_current_node = shortest_paths[current_node][1]
for next_node in destinations:
weight = graph.weights[(current_node, next_node)] + weight_to_current_node
if next_node not in shortest_paths:
shortest_paths[next_node] = (current_node, weight)
else:
current_shortest_weight = shortest_paths[next_node][1]
if current_shortest_weight > weight:
shortest_paths[next_node] = (current_node, weight)
# Don't visit the same node twice. This would lead to an infinite loop
next_destinations = {node: shortest_paths[node] for node in shortest_paths if node not in visited}
if not next_destinations:
return "Route Not Possible"
# next node is the destination with the lowest weight
current_node = min(next_destinations, key = lambda k: next_destinations[k][1])
# Work back through destinations in shortest path
path = []
while current_node is not None:
path.append(current_node)
next_node = shortest_paths[current_node][0]
current_node = next_node
# Reverse path
path = path[::-1]
return path
if __name__ == '__main__': ## Main program!!!
# cases = glob.glob("*.sav")
# case = cases[0]
# ierr = psspy.case(case)
# if len(cases) > 1:
# 'More than 1 sav case found. Using: ' + case
print "Enter first bus number"
s = raw_input('--> ')
try:
bus1 = int(s)
except:
print "Please enter integer"
s = raw_intput('--> ')
bus1 = int(s)
print "Enter second bus number"
s = raw_input('--> ')
try:
bus2 = int(s)
except:
print "Please enter integer"
s = raw_intput('--> ')
bus2 = int(s)
graph = Graph()
shortestPath = dijsktra(graph,bus1,bus2)
output = []
for bus in shortestPath:
# Look up each bus number's corresponding bus name and pair this info into tuples for output
ierr, name = psspy.notona(bus)
output.append((bus,name))
print "The shortest path is: "
for i in output:
print str(i)
2 | No.2 Revision |
Just an idea, the attached code can be run in PSSE to get the shortest path between two buses. If you use your slack bus as one, and the queried bus as the other, the length of the result will be your path length. It is feasible to step through your buses and save the path lengths for each and sort. It is computational computationally expensive however.
# Delivers shortest path (miles) between two buses
# The two buses must be the same voltage level (the script cannot see past transformers)
# Can't default to swing bus for everything if it's a different voltage level than bus1.
from collections import defaultdict
class Graph():
def __init__(self):
"""
self.edges is a dict of all possible next nodes e.g. {'X': ['A', 'B', 'C', 'E'], ...}
self.weights has all the weights between two nodes, with the two nodes as a tuple as the key
e.g. {('X', 'A'): 7, ('X', 'B'): 2, ...}
"""
self.edges = defaultdict(list)
self.weights = {}
def add_edge(self, from_node, to_node, weight):
# Note: assumes edges are bi-directional
self.edges[from_node].append(to_node)
self.edges[to_node].append(from_node)
self.weights[(from_node, to_node)] = weight
self.weights[(to_node, from_node)] = weight
def dijsktra(graph, initial, end):
# shortest paths is a dict of nodes whose value is a tuple of (previous node, weight)
shortest_paths = {initial: (None, 0)}
current_node = initial
visited = set()
while current_node != end:
visited.add(current_node)
jbus = 1
ierr = psspy.inibrn(current_node,2)
# nxtbrn provides neighboring buses until all have been provided. Then it returns jbus = 0
while jbus > 0:
ierr, jbus, kbus, ickt = psspy.nxtbrn3(current_node)
if jbus > 0:
# Get the length of the line between these two buses (in miles)
ierr, weight = psspy.brndat(current_node,jbus,ickt,'LENGTH') # gives the literal shortest path
weight = 1.0 #override weight to minimize the number of bus hops (longer line miles)
if weight is None:
weight=0.0
edge = (current_node,jbus,weight)
# Add this edge to the graph if it's not there already
if edge not in graph.edges:
graph.add_edge(*edge)
# Destinations: all the buses we can go to from the bus we're currently at
destinations = graph.edges[current_node]
# weight_to_current_node: how far we've travelled so far to get to this node
weight_to_current_node = shortest_paths[current_node][1]
for next_node in destinations:
weight = graph.weights[(current_node, next_node)] + weight_to_current_node
if next_node not in shortest_paths:
shortest_paths[next_node] = (current_node, weight)
else:
current_shortest_weight = shortest_paths[next_node][1]
if current_shortest_weight > weight:
shortest_paths[next_node] = (current_node, weight)
# Don't visit the same node twice. This would lead to an infinite loop
next_destinations = {node: shortest_paths[node] for node in shortest_paths if node not in visited}
if not next_destinations:
return "Route Not Possible"
# next node is the destination with the lowest weight
current_node = min(next_destinations, key = lambda k: next_destinations[k][1])
# Work back through destinations in shortest path
path = []
while current_node is not None:
path.append(current_node)
next_node = shortest_paths[current_node][0]
current_node = next_node
# Reverse path
path = path[::-1]
return path
if __name__ == '__main__': ## Main program!!!
# cases = glob.glob("*.sav")
# case = cases[0]
# ierr = psspy.case(case)
# if len(cases) > 1:
# 'More than 1 sav case found. Using: ' + case
print "Enter first bus number"
s = raw_input('--> ')
try:
bus1 = int(s)
except:
print "Please enter integer"
s = raw_intput('--> ')
bus1 = int(s)
print "Enter second bus number"
s = raw_input('--> ')
try:
bus2 = int(s)
except:
print "Please enter integer"
s = raw_intput('--> ')
bus2 = int(s)
graph = Graph()
shortestPath = dijsktra(graph,bus1,bus2)
output = []
for bus in shortestPath:
# Look up each bus number's corresponding bus name and pair this info into tuples for output
ierr, name = psspy.notona(bus)
output.append((bus,name))
print "The shortest path is: "
for i in output:
print str(i)