Power Grid
Do you have questions or comments about this model? Ask them here! (You'll first need to log in.)
The Dynamics of Power-Grid Degradation
Thomas Rieth IABG mbH, Einsteinstraße 20, D-85521 Ottobrun, Germany rieth(at)iabg.de
WHAT IS IT?
This application can be used for editing and simulating the stability of power-grids. Here, a power-grid is build by nodes that are connected by edges, and power is transfered from sources to sinks using the provided network.
HOW IT WORKS
The Structure of the Network
The power-grid here is build from a set of nodes that are connected by edges. Some of the nodes are either sources or sinks of power. The sign of the values of actual and available power specify the type of node:
- connecting node (green) with
available-power = 0
- dangling nodes (yellow), i.e., nodes just connected by a single edge to the network
- power sources (blue) with
available-power > 0
- power sinks (red) with
available-power < 0
The size of power sources or sinks is given by a logarithmic scale:
set size 1 + log abs actual-power 10
The edges are characterized by an actual load and a capacity they can carry. The thickness of edges is given by:
if load > 0
[ set thickness (1 - exp (- load)) ]
[ set thickness (1 - exp (- capacity)) ]
The color indicates if the actual load exceeds the capacity:
- grey in case
load = 0
- green if
0 < load < capacity
- yellow for
capacity < load < 2 * capacity
- orange for
2 * capacity < load < 4 * capacity
- red for
load > 4 * capacity
The Dynamic of the Network
The dynamic behaviour of the network starts with an optimisation of the flow in the network.
let is-isolated? true
let targets nodes with [available-power < 0]
ask targets [
let sources nodes with [can-provide?]
ask min-n-of (count sources) sources [distance myself] [
if [is-needing?] of myself [
set is-grid-disrupted? not update-net-structure self myself
set is-isolated? is-isolated? and is-grid-disrupted?
]
]
]
For optimisation of the power flow an A* (A-star) search algorithm is used. The costs of an edge are given by the value one. If the load of a used edge exceeds its capacity, then additional costs are considered.
Depending on the power flow and the capacity of the edges their life-time is calculated using a random-exponential distribution.
ask edges [
ifelse load > 0
[ set life-time random-exponential capacity / load ]
[ set life-time -1 ]
]
During a simulation tick the simulation time (see the current-time monitor) is increased to next smallest life-time, and the respective edge is removed from the network. Then the network is optimised again, and the life-times of the edges in the new network are calculated repeatedly.
The simulation continues until either all edges or nodes are removed or all sources and sinks are seperated from each other, i.e., any flow is impossible between sources and sinks (see the monitor is-grid-isolated?)
The monitor is-grid-disrupted becomes true, whenever the search algorithm is unable to find a connection between one of the source and one of the sinks. One should notice that the network might have divided into two unconnected components quite earlier.
HOW TO USE IT
During startup the application tries to read the file grid.dat
if it exists. Pressing setup a blank scenario is created.
The data of the power-grid can be stored in files using the buttons save-grid or load-grid.
An export of the power-grid data in special network file formats is possible. Currently supported format are:
- Netdraw VNA format: The VNA format is commonly used by Netdraw, and is very similar to Pajek format. It defines nodes and edges (ties), and supports attributes.
- Pajek NET Format: This format use NET extension and is easy to use. Attributes support is however missing, only the network topology can be currently represented with a Pajek File.
Layout of the Network
By pressing add-nodes further nodes are added randomly to the network. The number of these newly added nodes is set by the slider number-of-nodes. The algorithm connects all nodes with edges randomly. The number of edges is specified by the average-node-degree slider.
Nodes and edges can be inserted or deleted by pressing the buttons and selecting one or two nodes using the mouse.
The monitors on the right side provide information about the number of nodes, edges, sources, sinks, and dangles.
Nodes can be moved using the move-node button. The spring-layout - as well as the circle-layout and the radial-layout button (you have to selct the central nodes using the mouse) - can be used to distribute the nodes in the network in a more uniform layout.
Adding Sources and Sinks
A power-grid created initially has nowhere power flowing from sources to sinks. Here the load on all edges is zero, as well as the actual power of sources or sinks. During optimization shortest paths are searched between randomly chosen combination of power sources and sinks, and the power flow is put as an additional load onto edges. The actual power of sources or sinks is increased or decreased accordingly.
By pressing add-power sources and sinks of varying size are randomly put into the power grid. The slider total-power-flux specifies the dimension of the additional power-flow.
Individual nodes can be changed by pressing either increase-power or decrease-power first, and then by selecting a node. The available power will be changed by a value of one.
The monitors (right side) show:
- power-input: the total available power input into network
- power-output:the total available power output from the network
- power-variance: a measure of difference between available and actual power supply and demand in all nodes
- flux-variance: a measure of difference between load and capacity of all edges
- edge-mean: the mean value of the edges' distribution
- edgevariance_: the standard deviation of the edges' distribution
power-variance = sqrt ( sum over all nodes ( available - actual power)2) flux-variance = sqrt ( sum over all edges ( load - capacity)2)
By pressing remove-power all power sources and sinks are removed, and they will change to standard connecting nodes (green). The load and capacity of the edges will be set to standard load = 0
and capacity = 1
.
By pressing remove-labels all labels on the nodes are removed, but whenever the network is saved, then new labels will be calculated.
Optimization of the Network
The power-flow in the network can be optimized in three steps:
- optimize-flow: find the paths of the flow between power sources and sinks in the network. With the over-capacity-costs sliders the additional costs for edges with load greater than their capacity can be set.
- remove-unused: remove edges with no load and nodes without any connecting edges
- adjust-capacities: change the edges' capacities to their current load (all edges will become gray)
- optimize-structure: the procedures
optimize-flow
andadjust-structure
are repeated optimize-steps times.
Simulation of the Network
The simulation is started with:
- go will start the simulation of the degrading network.
- step allows to perform just a single simulation step until the next tick.
The following switches may be used:
- data-output : after every simulation step (tick) the resulting grid will be stored
- in a file with name "grid-sim-tick#.dat" when set to "each" or "all"
- in files "grid-nodes-R-number-of-run.dat" and "grid-edges-R-number-of-run.dat" when set to "for R" or "all"
- number-of-run : the counter for the output. This number can be used in NetLogo's Behavior Space to produce varying output files.
- output-level: print more or less detailed informations about the A*-search algorithm into NetLogo's Command Center (a level of zero has no output)
- show-destroyed : whenever an edge is removed from the network, a fire symbol will be placed at the middle between the edge's both nodes for the duration of the tick. By pressing the remove-labels button the symbol is removed, too.
A movie can be produced by pressing the movie button. The simulation will run until finished.
THINGS TO NOTICE
Usually, the counting of (simulation) ticks corresponds to physical time. Here the physical time of the model is described by the variable monitor current-time. Whenever in the simulation an edge collapsed (is destroyed) after a randomly determined life-time, the tick counter of the simulation is increased by one.
Somehow, by unknown reasons, inserting and deleting edges does not always work properly in dense networks.
THINGS TO TRY
Suggested things for the user to try to do (move sliders, switches, etc.) with the model are whatever the user wants.
EXTENDING THE MODEL
Calculation of centrality measure might be a good help for the identification of important nodes in the network.
NETLOGO FEATURES
The network, link, and mouse features from netlogo are heavily used.
RELATED MODELS
(models in the NetLogo Models Library and elsewhere which are of related interest)
CREDITS AND REFERENCES
Amit Patel. Introduction to A*. From Amit’s Thoughts on Pathfinding. http://theory.stanford.edu/~amitp/GameProgramming/AStarComparison.html (11 July 2014)
Wikipedia, the free encyclopedia. A search algorithm. http://en.wikipedia.org/wiki/Asearchalgorithm (11 July 2014)
Wilensky, U. 1999. NetLogo. http://ccl.northwestern.edu/netlogo/. Center for Connected Learning and Computer-Based Modeling, Northwestern University. Evanston, IL
Comments and Questions
extensions [vid] breed [nodes node] undirected-link-breed [edges edge] breed [fires fire] nodes-own [ key available-power actual-power search-parent search-costs-from-start ] edges-own [ capacity load life-time ] fires-own [ fire-key1 fire-key2 fire-capacity fire-load fire-life-time ] globals [ mouse-first-node mouse-second-node search-open-node-list search-closed-node-list search-over-capacity-costs current-time is-grid-disrupted? is-grid-isolated? initial-number-of-edges _recording-save-file-name ] to setup-globals set-default-shape nodes "circle" set-default-shape fires "fire" set mouse-first-node nobody set mouse-second-node nobody set current-time 0 set is-grid-disrupted? false set is-grid-isolated? false set initial-number-of-edges 0 end to startup setup let file "grid.dat" if file-exists? file [ read-grid-data-from-file file ] set total-power-flux 30 set number-of-nodes 100 set average-node-degree 5 mouse-reset end to setup clear-all setup-globals setup-world reset-ticks setup-fire go-output end to go ; beep ; user-message "The procedure 'go' is not implemented yet!" ; stop if go-finished? [ stop ] ifelse ticks > 0 [ go-failure-of-a-edge ] [ set initial-number-of-edges count edges numerize-nodes ] optimize-flow go-calculate-life-time-of-edges if data-output != "no" [ write-data-to-files ] go-output tick end to setup-world ask patches [ set pcolor white ] end to go-output clear-output output-print (word "Current time: " precision current-time 4) output-print (word "# nodes: " count nodes " # edges: " count edges " # sources: "count nodes with [available-power > 0] " # sinks: " count nodes with [available-power < 0]) output-print (word "# critical edges: " count edges with [capacity < load] " # dangling nodes: " count nodes with [is-dangling?] ) output-print (word "GRID isolated? " is-grid-isolated? " disrupted? " is-grid-disrupted?) if any? nodes and any? edges [ output-print (word "average degree: " (precision (mean [count my-edges] of nodes) 4) " +/- " (precision (standard-deviation [count my-edges] of nodes) 4) ) ] output-print (word "POWER supply: " (precision power-supply 2) " demand: " (precision power-demand 2) " input: " (precision power-input 2) " output: " (precision power-output 2) ) output-print (word "Variance nodes: " (precision power-variance 2) " edges: " (precision flux-variance 2) ) end to-report go-finished? report is-grid-isolated? or count edges = 0 or count nodes = 0 end ;; ============= Simulate network dynamics ================= to go-failure-of-a-edge if any? edges with [life-time > 0 ] [ ask min-one-of edges with [life-time > 0 ] [life-time] [ if output-level = 1 [ show "selected!" ] set current-time current-time + life-time go-create-fire-at-destroyed-edge die ] ] end to go-calculate-life-time-of-edges ask edges [ ifelse load > 0 [ set life-time random-exponential capacity / load ] [ set life-time -1 ] ] end to go-create-fire-at-destroyed-edge let x 0.5 * ( [xcor] of end1 + [xcor] of end2) let y 0.5 * ( [ycor] of end1 + [ycor] of end2) let key1 [key] of end1 let key2 [key] of end2 ask one-of fires [ set xcor x set ycor y ifelse show-destroyed [ show-turtle ][ hide-turtle ] set fire-key1 key1 set fire-key2 key2 set fire-capacity [capacity] of myself set fire-load [load] of myself ] end to setup-fire create-fires 1 [ set size 2 set color white hide-turtle set fire-key1 -1 set fire-key2 -1 set fire-capacity -1 set fire-load -1 ] end ;; ============= Draw nodes and edges ====================== to draw-structure ask nodes [ draw-node ] ask edges [ draw-edge ] end to draw-node ifelse actual-power != 0 [ set size 1 + log abs actual-power 10 ] [ set size 1 ] let power available-power ifelse is-dangling? [ set color yellow ] [ set color green ] if power > 0 [ set color blue ] if power < 0 [ set color red ] end to-report is-dangling? report count edges with [end1 = myself or end2 = myself] < 2 end to draw-edge ifelse load > 0 [ set color green set thickness (1 - exp (- 0.5 * load)) if load > capacity [ ifelse load > 2 * capacity [ ifelse load > 4 * capacity [ set color red ] [ set color orange ] ] [ set color yellow ] ] ] [ set color grey set thickness (1 - exp (- 0.5 * capacity)) ] end to numerize-nodes if any? nodes with [key < 0] [ let counter 0 ask nodes [ set counter counter + 1 set key counter ] ] end to-report nodes-degree ifelse any? nodes and any? edges [ report (word (precision (mean [count my-edges] of nodes) 2) "+/-" (precision (standard-deviation [count my-edges] of nodes) 2) ) ] [ report "---" ] end to-report edge-mean report mean [count my-edges] of nodes end to-report edge-variance report standard-deviation [count my-edges] of nodes end ;;============== Design the net-structure =================== to add-nodes setup-nodes setup-spatially-clustered-network draw-structure end to setup-nodes create-nodes number-of-nodes [ ; for visual reasons, we don't put any nodes *too* close to the edges setxy (random-xcor * 0.95) (random-ycor * 0.95) setup-node ] end to setup-node set available-power 0 set actual-power 0 set key -1 end to setup-spatially-clustered-network let number-of-edges (average-node-degree * count nodes) / 2 while [count edges < number-of-edges ] [ ask one-of nodes [ let choice ( min-one-of ( other nodes with [not edge-neighbor? myself] ) [distance myself] ) if choice != nobody [ create-edge-with choice [ set capacity 1 set load 0 ] ] ] ] end to add-power let total-power total-power-flux while [total-power > 0] [ let power 1 if random-type = "float" [ set power power + random-float 2 ] if random-type = "integer" [ set power power + random 2 ] if power > total-power [ set power total-power ] set total-power total-power - power ask one-of nodes with [available-power <= 0] [ set available-power available-power - power ] ask one-of nodes with [available-power >= 0] [ set available-power available-power + power ] ] draw-structure end to remove-power ask nodes [ set available-power 0 set actual-power 0 draw-node ] ask edges [ set load 0 set capacity 1 draw-edge ] end to-report edge-level let value 100. if initial-number-of-edges > 0 [ set value 100.0 * count edges / initial-number-of-edges ] report value end to-report disrupted-level let value 0 if is-grid-disrupted? [ set value 100 ] report value end ;;============== Editing the nodes and edges ========= to set-selected set size size * 2 end to set-unselected set size size * 0.5 end to mouse-reset if is-turtle? mouse-first-node and mouse-first-node != nobody [ ask mouse-first-node [ draw-node ] ] if is-turtle? mouse-second-node and mouse-second-node != nobody [ ask mouse-second-node [ draw-node ] ] set mouse-first-node nobody set mouse-second-node nobody end to-report select-nearest-node report one-of nodes with-min [distancexy mouse-xcor mouse-ycor] end to insert-node if mouse-down? and mouse-inside? [ create-nodes 1 [ setxy mouse-xcor mouse-ycor setup-node draw-node ] stop ] end to delete-node if not any? nodes [ stop ] if mouse-down? and mouse-inside? [ ask select-nearest-node [ die ] draw-structure stop ] end to move-node if not any? nodes [ stop ] ifelse mouse-down? and mouse-inside? [ if mouse-first-node = nobody [ set mouse-first-node select-nearest-node ] if mouse-first-node != nobody [ ask mouse-first-node [ setxy mouse-xcor mouse-ycor ] ] ] [ if mouse-first-node != nobody [ mouse-reset stop ] ] end to insert-edge if mouse-first-node = nobody [ if mouse-down? and mouse-inside? [ set mouse-first-node select-nearest-node ask mouse-first-node [ set-selected ] ] ] if mouse-second-node = nobody or mouse-second-node = mouse-first-node [ if mouse-down? and mouse-inside? [ set mouse-second-node select-nearest-node ] ] if (mouse-first-node != nobody and mouse-second-node != nobody and mouse-second-node != mouse-first-node) [ ask mouse-first-node [ set-unselected ifelse edge-neighbor? mouse-second-node [ ask edge-with mouse-second-node [ set capacity capacity + 1 ] ] [ create-edge-with mouse-second-node [ set capacity 1 set load 0 ] ] ] draw-structure mouse-reset stop ] end to-report edges-between [node1 node2] report edges with [end1 = node1 and end2 = node2] end to delete-edge if not any? edges [ stop ] ifelse mouse-first-node = nobody [ if mouse-down? and mouse-inside? [ set mouse-first-node select-nearest-node ask mouse-first-node [ set-selected ] show (word "First: " [key] of mouse-first-node) ] ] [ if (mouse-second-node = nobody or mouse-second-node = mouse-first-node) [ if mouse-down? and mouse-inside? [ set mouse-second-node select-nearest-node ifelse (not [edge-neighbor? mouse-first-node] of mouse-second-node) [ set mouse-second-node nobody ] [ show (word "Second: " [key] of mouse-second-node) ] ] ] ] if (mouse-first-node != nobody and mouse-second-node != nobody and mouse-second-node != mouse-first-node) [ let found-edges edges-between mouse-first-node mouse-second-node ifelse any? found-edges [ show (word "Delete edge between " [key] of mouse-first-node " and " [key] of mouse-second-node) ask one-of found-edges [ die ] ask mouse-first-node [ set-unselected ] mouse-reset draw-structure stop ] [ mouse-reset ] ] end to increase-power if mouse-down? and mouse-inside? [ ask select-nearest-node [ set available-power available-power + 1 draw-node ] stop ] end to decrease-power if mouse-down? and mouse-inside? [ ask select-nearest-node [ set available-power available-power - 1 draw-node ] stop ] end to radial-layout if mouse-down? and mouse-inside? [ layout-radial nodes edges select-nearest-node stop ] end to spring-layout let spring-force 1 let spring-length world-width / (sqrt count nodes) let repulsion-force 1 repeat 30 [ layout-spring nodes edges spring-force spring-length repulsion-force ] end to circle-layout let radius 0.4 * min (list world-width world-height) let node-set max-n-of 3 nodes [count edge-neighbors ] repeat 10 [ layout-tutte node-set edges radius ] end ;;============== Save and load net-structure =================== to write-data-to-files if data-output = "each" or data-output = "all" [ let file-name (word "grid-sim-" ticks) let network-file (word file-name ".dat") if is-string? network-file [ if file-exists? network-file [ file-delete network-file ] write-grid-data-to-file network-file ] ] if data-output = "for R" or data-output = "all" [ write-data-to-R-files ] end to write-data-to-R-files numerize-nodes let file-name (word "grid-nodes-R-" number-of-run ".dat") if ticks = 0 and file-exists? file-name [ file-delete file-name ] file-open file-name if ticks = 0 [ file-print "key current-time xcor ycor available-power actual-power" ] ask nodes [ file-write key file-write current-time file-write xcor file-write ycor file-write available-power file-write actual-power file-print " " ] file-close set file-name (word "grid-edges-R-" number-of-run ".dat") if ticks = 0 and file-exists? file-name [ file-delete file-name ] file-open file-name if ticks = 0 [ file-print "key1 key2 current-time capacity load life-time deleted?" ] ask fires [ if fire-key1 >= 0 [ file-write fire-key1 file-write fire-key2 file-write current-time file-write fire-capacity file-write fire-load file-write fire-life-time file-print " 1 " ] ] ask edges [ file-write [key] of end1 file-write [key] of end2 file-write current-time file-write capacity file-write load file-write life-time file-print " 0 " ] file-close end to-report check-file-name [file-name file-tag] if is-string? file-name [ let found substring file-name (length file-name - length file-tag) length file-name if found != file-tag [ set file-name (word file-name file-tag) ] ] report file-name end to save-grid let network-file check-file-name user-new-file ".dat" if is-string? network-file [ if file-exists? network-file [ file-delete network-file ] write-grid-data-to-file network-file ] end to write-grid-data-to-file [network-file] numerize-nodes file-open network-file file-print count nodes file-print "* node data key label x y available-power actual-power" foreach sort-on [key] nodes [ [?1] -> ask ?1 [ if empty? label [ set label (word key)] file-write key file-write label file-write xcor file-write ycor file-write available-power file-write actual-power file-print " " ] ] file-print "* edge data key1 key2 capacity load" ask edges [ file-write [key] of end1 file-write [key] of end2 file-write capacity file-write load file-print " " ] file-close end to load-grid setup let network-file user-file if is-string? network-file and file-exists? network-file [ read-grid-data-from-file network-file ] end to read-grid-data-from-file [network-file] file-open network-file let counter file-read let dummy file-read-line while [counter > 0] [ create-nodes 1 [ set color green set key file-read set label file-read setxy file-read file-read set available-power file-read set actual-power file-read ] set counter counter - 1 ] set dummy file-read-line while [not file-at-end? ] [ let token file-read let next-token file-read let first-node one-of nodes with [key = token] let second-node one-of nodes with [key = next-token] ask first-node [ create-edge-with second-node [ set capacity file-read set load file-read ] ] ] file-close draw-structure go-output end ;;============== Export net-structure in various formats === to export numerize-nodes if format = "NET" [ let network-file check-file-name user-new-file".net" if is-string? network-file [ if file-exists? network-file [ file-delete network-file ] write-NET-data-to-file network-file ] ] if format = "VNA" [ let network-file check-file-name user-new-file ".vna" if is-string? network-file [ if file-exists? network-file [ file-delete network-file ] write-VNA-data-to-file network-file ] ] if format = "R" [ let node-file check-file-name user-new-file ".nodes.imp" let edge-file (word (remove ".nodes.imp" node-file ) ".edges.imp") if is-string? node-file and is-string? edge-file [ if file-exists? node-file [ file-delete node-file ] if file-exists? edge-file [ file-delete edge-file ] write-R-node-data-to-file node-file write-R-edge-data-to-file edge-file ] ] end to write-NET-data-to-file [network-file] file-open network-file file-type "*Vertices " file-print count nodes foreach sort-on [key] nodes [ [?1] -> ask ?1 [ file-write key file-write label file-write xcor file-write ycor file-print " " ] ] file-print "*Arcs" ask edges [ file-write [key] of end1 file-type " " file-write [key] of end2 file-type " " file-write 1 + load file-print " " ] file-close end to write-VNA-data-to-file [network-file] file-open network-file file-print "*Node data" file-print "id available-power actual-power" foreach sort-on [key] nodes [ [?1] -> ask ?1 [ if empty? label [ set label (word key)] file-write key file-write precision available-power 2 file-write precision actual-power 2 file-print " " ] ] let size-factor 10 file-print "*Node properties" file-print "id x y color shape size shortlabel" let vshape 1 foreach sort-on [key] nodes [ [?1] -> ask ?1 [ file-write key file-write precision (size-factor * (xcor - min-pxcor)) 0 file-write precision (size-factor * (ycor - min-pycor)) 0 file-write integer-color file-write vshape file-write precision (size-factor * size) 0 file-write label file-print " " ] ] file-print "*Tie data" file-print "from to strength load capapcity" ask edges [ file-write [key] of end1 file-write [key] of end2 file-write 1 file-write load file-write capacity file-print " " file-write [key] of end2 file-write [key] of end1 file-write 1 file-write load file-write capacity file-print " " ] file-print "*Tie properties" file-print "from to color size headcolor headsize active" let headsize 0 let active -1 ask edges [ let lcolor integer-color file-write [key] of end1 file-write [key] of end2 file-write lcolor file-write precision (size-factor * thickness) 0 file-write lcolor file-write headsize file-write active file-print " " file-write [key] of end2 file-write [key] of end1 file-write lcolor file-write precision (size-factor * thickness) 0 file-write lcolor file-write headsize file-write active file-print " " ] file-close end to write-R-node-data-to-file [network-file] file-open network-file file-print "key x y available actual" ask nodes [ file-write key file-write xcor file-write ycor file-write available-power file-write actual-power file-print " " ] file-close end to write-R-edge-data-to-file [network-file] file-open network-file file-print "key1 key2 capacity load " ask edges [ file-write [key] of end1 file-write [key] of end2 file-write capacity file-write load file-print " " ] file-close end to-report integer-color let value 0 let color-list extract-rgb color let red-value item 0 color-list let green-value item 1 color-list let blue-value item 2 color-list set value red-value + 256 * green-value + 256 * 256 * blue-value report value end ;;============== provide characteristic values for net-structure == to-report power-supply-level let value 0 let total power-supply if total > 0 [ set value 100.0 * power-input / total ] report value end to-report power-demand-level let value 0 let total power-demand if total > 0 [ set value 100.0 * power-output / total ] report value end to-report power-supply let power 0 ask nodes with [available-power > 0] [ set power power + available-power ] report power end to-report power-demand let power 0 ask nodes with [available-power < 0] [ set power power + available-power ] report power * -1 end to-report power-input let power 0 ask nodes with [available-power > 0] [ set power power + actual-power ] report power end to-report power-output let power 0 ask nodes with [available-power < 0] [ set power power + actual-power ] report power * -1 end to-report power-variance let value 0 ask nodes [ let delta available-power - actual-power set value value + delta * delta ] report sqrt value end to-report flux-variance let value 0 ask edges [ let delta capacity - load set value value + delta * delta ] report sqrt value end ;; ================= Optimize the flux in net-structure ========== to reset-structure ask nodes [ set actual-power 0 draw-node ] ask edges [ set load 0 draw-edge ] end to optimize-flow reset-structure let is-isolated? true let is-disrupted? false let targets nodes with [available-power < 0] ask targets [ let sources nodes with [can-provide?] ask min-n-of (count sources) sources [distance myself] [ if [is-needing?] of myself [ set is-disrupted? not update-net-structure self myself set is-isolated? is-isolated? and is-disrupted? set is-grid-disrupted? is-disrupted? or is-grid-disrupted? ] ] ] set is-grid-isolated? is-isolated? draw-structure end to-report is-needing? report available-power < 0 and actual-power > available-power end to-report can-provide? report available-power > 0 and actual-power < available-power end to change-power [this-load] if available-power > 0 [ set actual-power actual-power + this-load ] if available-power < 0 [ set actual-power actual-power - this-load ] end to-report calculate-net-flow [start-node target-node] let this-flow 0 ask start-node [ set this-flow available-power - actual-power ] ask target-node [ let that-flow actual-power - available-power if that-flow < this-flow [ set this-flow that-flow ] ] report this-flow end to change-flow-structure [start-node target-node edge-list this-load] if not empty? edge-list [ ask start-node [ change-power this-load draw-node ] ask target-node [ change-power this-load draw-node ] foreach edge-list [ [?1] -> ask ?1 [ set load load + this-load draw-edge ] ] ] end to-report update-net-structure [start-node target-node] let path-found? true let edge-list search-go start-node target-node let found-path? not empty? edge-list ifelse found-path? [ let this-load calculate-net-flow start-node target-node if output-level = 1 [ show (word "Power flow: " this-load " with " (length edge-list) " edges between " start-node " and " target-node) ] if this-load > 0 [ change-flow-structure start-node target-node edge-list this-load ] ] [ if output-level = 1 [ show (word "No path found between " start-node " and " target-node) ] set path-found? false ] report path-found? end to adjust-capacities ask edges [ if load > capacity [ set capacity load ] draw-edge ] end to remove-unused ask edges with [load = 0] [ die ] ask nodes with [ count my-edges = 0] [die] draw-structure end to optimize-structure repeat optimize-steps [ optimize-flow adjust-capacities ] optimize-flow end ;; ================= Search shortest path in net-structure ======= to-report search-go [start-node target-node] let node-list search-path start-node target-node let edge-list search-transfer-node-list-to-edge-list node-list report edge-list end to-report search-path [start-node target-node] if output-level = 2 [ show ( word "Search path between " start-node " and " target-node ) ] let new-path ( list ) search-init start-node if search-do target-node [ set new-path search-path-back target-node ] report new-path end to search-init [ start-node ] if output-level = 2 [ show ( word "Init search from " start-node ) ] ask nodes [ set search-parent nobody set search-costs-from-start 0 ] set search-open-node-list fput start-node ( list ) set search-closed-node-list ( list ) end to-report search-rank report search-costs-from-start end to-report search-do [target-node] if output-level = 2 [ show ( word "Do search to " target-node ) ] let current-node nobody while [target-node != current-node] [ if empty? search-open-node-list [ if output-level = 2 [ show ( word "No path to " target-node ) ] report false ] ; remove lowest rank item from open list of patches and add it to the closed list set search-open-node-list sort-by [ [?1 ?2] -> [ search-rank ] of ?1 < [ search-rank ] of ?2 ] search-open-node-list set current-node first search-open-node-list set search-open-node-list but-first search-open-node-list set search-closed-node-list fput current-node search-closed-node-list if output-level = 2 [ show ( word "Current node " current-node ) ] ; check adjacent nodes if target-node != current-node [ ask current-node [ search-handle-neighbors self target-node] ] ] if output-level = 2 [ show ( word "Found target " current-node ) ] report true end to search-handle-neighbors [parent-node target-node] ask my-edges [ let costs [ search-costs-from-start ] of parent-node + 1 if load > capacity [ set costs costs + over-capacity-costs ] ask other-end [ if member? self search-open-node-list and costs < search-costs-from-start [ set search-open-node-list remove self search-open-node-list if output-level = 2 [ show ( word "Neighbor node " self " removed from open " search-open-node-list ) ] ] if member? self search-closed-node-list and costs < search-costs-from-start [ set search-closed-node-list remove self search-closed-node-list if output-level = 2 [ show ( word "Neighbor node " self " removed from closed " search-closed-node-list ) ] ] if ( not member? self search-open-node-list ) and ( not member? self search-closed-node-list ) [ if output-level = 2 [ show ( word "Neighbor node " self " with costs=" costs " to parent " parent-node ) ] set search-parent parent-node set search-costs-from-start costs set search-open-node-list fput self search-open-node-list ] ] ] end to-report search-path-back [target-node] let found-path fput target-node ( list ) let current-node target-node if output-level = 2 [ show ( word "Revert search " current-node ) ] while [ [ search-parent ] of current-node != nobody ] [ set current-node [ search-parent ] of current-node set found-path fput current-node found-path if output-level = 2 [ show ( word "Revert search " current-node ) ] ] report found-path end to-report search-edge-for-nodes [that-node this-node] report one-of edges with [ (end1 = that-node and end2 = this-node) or (end2 = that-node and end1 = this-node) ] end to-report search-transfer-node-list-to-edge-list [node-list] let edge-list (list) let last-node nobody foreach node-list [ [?1] -> let current-node ?1 if last-node != nobody [ let found-edge search-edge-for-nodes current-node last-node if output-level = 2 [ show (word "Found " found-edge " of " current-node " " last-node) ] set edge-list fput found-edge edge-list ] set last-node current-node ] report edge-list end ;; ============== plotting =========================== to plot-histogram-of [that-distribution] ifelse length that-distribution > 0 [ let x-max ( ceiling max that-distribution ) if x-max <= 0 [ set x-max 1.0 ] let y-max length that-distribution set-plot-x-range 0 x-max set-plot-y-range 0 y-max set-histogram-num-bars 20 histogram that-distribution ] [ clear-plot ] end
There are 7 versions of this model.
Attached files
File | Type | Description | Last updated | |
---|---|---|---|---|
grid.dat | data | Demo grid data file | about 1 year ago, by Thomas Rieth | Download |
Power Grid.png | preview | Preview for 'Power Grid' | over 9 years ago, by Thomas Rieth | Download |
This model does not have any ancestors.
This model does not have any descendants.
Hernando Diaz
Model not running (Question)
Model is not running neither in Netlogo Web nor locally after download. Downloaded version can't be openned. "expected nlogo file to hav 12 sections. This has 1.
Posted almost 4 years ago