Power systems are evolving; however, the availability of efficient collaborative engineering design and analysis tools lags the technological deployment in the field. This project leverages the complete design model of the PSS®E Raw-file and a future extension to the Dyr-file and Common Grid Model Exchange Specifications (CGMES) Common Information Model (CIM) to facilitate the exchange of operational and grid planning data among transmission operators. Once translated, the depth of Wolfram Language and System Modeler combined with OpenIPSL can be used to analyze the data.
Parsing the Files
Parsing the Files
Introduction
Introduction
Transmission planning involves a grid model that has thousands of buses and components such as generators, transformers, and shunts . Not only are there large numbers of components, each component has many parameters that must be used to find a solution . Starting with a Raw - file can lead to extensible analysis because of the flexibility of Wolfram Language .
Even small educational models are 322 lines of code in a PSS®E Raw-file to create a 44-bus system. This makes it difficult to run proof-of-concept analysis of electric power system models without a translation script. The translated Raw-file is analyzable using the many Wolfram Language tools. This post breaks the file down into lists of components which can easily be assembled for analysis that is otherwise not possible. The “ad-hoc” comes from the Wolfram System Modeler (WSM) library OpenIPSL which can use reassembled components to recreate the starting point and extend the analysis with newly created components. Granted, this is an advanced feature. Rapidly creating various load scenarios is a more reasonable extension.
Please download the file placing it in the same directory that you have downloaded this notebook and remove the .txt ending.
N44_BC.raw.txt
Typically, the working directory is added to the notebook :
In[]:=
$Path=Append[$Path,NotebookDirectory[]];
The Raw-file is loaded as a list of lines and comments are excluded:
In[]:=
rawFile=StringReplace[DeleteCases[Import["N44_BC.raw","Lines"],str_String/;StringMatchQ[str,StartOfString~~"@!"~~___~~EndOfString]],Except["0"]~~" / "~~___~~EndOfString->""];
Structure
Structure
The file is structured with simulation parameters at the beginning that identify not only what PSS®E uses, but hints at how to set up WSM. This paper breaks down each component into a dataset for viewing or a group of associations for assembly. For demonstration purposes, graphing functions can show relationships between the buses, lines, and loads. Various analysis will show the load distribution.
You can see we will parse on 322 lines:
In[]:=
Length[StringSplit[rawFile,"\n"]]
Out[]=
322
We’ll break the lines into categories in order to match as a list for each component:
In[]:=
Cases[rawFile,str_String/;StringMatchQ[str,StartOfString~~"0 / "~~___]]//Column
Out[]=
0 / END OF BUS DATA, BEGIN LOAD DATA |
0 / END OF LOAD DATA, BEGIN FIXED SHUNT DATA |
0 / END OF FIXED SHUNT DATA, BEGIN GENERATOR DATA |
0 / END OF GENERATOR DATA, BEGIN BRANCH DATA |
0 / END OF BRANCH DATA, BEGIN TRANSFORMER DATA |
0 / END OF TRANSFORMER DATA, BEGIN AREA DATA |
0 / END OF AREA DATA, BEGIN TWO-TERMINAL DC DATA |
0 / END OF TWO-TERMINAL DC DATA, BEGIN VSC DC LINE DATA |
0 / END OF VSC DC LINE DATA, BEGIN IMPEDANCE CORRECTION DATA |
0 / END OF IMPEDANCE CORRECTION DATA, BEGIN MULTI-TERMINAL DC DATA |
0 / END OF MULTI-TERMINAL DC DATA, BEGIN MULTI-SECTION LINE DATA |
0 / END OF MULTI-SECTION LINE DATA, BEGIN ZONE DATA |
0 / END OF ZONE DATA, BEGIN INTER-AREA TRANSFER DATA |
0 / END OF INTER-AREA TRANSFER DATA, BEGIN OWNER DATA |
0 / END OF OWNER DATA, BEGIN FACTS DEVICE DATA |
0 / END OF FACTS DEVICE DATA, BEGIN SWITCHED SHUNT DATA |
0 / END OF SWITCHED SHUNT DATA, BEGIN GNE DATA |
0 / END OF GNE DATA, BEGIN INDUCTION MACHINE DATA |
0 / END OF INDUCTION MACHINE DATA |
In this post, we’ll focus on the buses (vertices), non-transformer branches (edges), and load sections. Similar work is completed in the download notebook for the rest of the types.
Mechanics
Mechanics
The main purpose of parsing a file is to break it into usable data. We’ll manipulate the Raw-file primarily by Rearranging and Restructuring Lists since the imported file is a list. Each line is a comma-separated string. Here are the first 5 lines:
In[]:=
Take[rawFile,5]//Map[InputForm]
Out[]=
{"0, 1000.00, 33, 0, 1, 50.00 ","PSS/E VERSION 33 RAW DATA EXPORT FROM PSS/O","2015-08-12 NORDIC44_BZ (NORDIC44)"," 3000,'FORSMARK ', 420.0000,2, 23, 1, 1,1.00000, -2.8801,1.10000,0.90000,1.10000,0.90000"," 3020,'DANNEBO_HVDC', 420.0000,1, 23, 1, 1,0.99590, -3.5820,1.10000,0.90000,1.10000,0.90000"}
Case information is contained in the first line. We accommodate different versions of Raw-files by splitting the first line at the commas. Select the third entry, 33, into variable. Use to assign to either 2 or the position where the value “0 / END OF SYSTEM-WIDE DATA, BEGIN BUS DATA” is located. Finally, we assign the variable to all of the homogeneous bus information.
revision
revision
myStart
myBus
In[]:=
myCase=StringSplit[rawFile[[1]],","]
Out[]=
{0, 1000.00, 33, 0, 1, 50.00 }
In[]:=
revision=myCase[[3]]//ToExpression;
In[]:=
busPosition=Position[rawFile,"0 / END OF BUS DATA, BEGIN LOAD DATA"][[1]][[1]]-1;
In[]:=
myBus=rawFile[[If[revision==33,4,Position[rawFile,"0 / END OF SYSTEM-WIDE DATA, BEGIN BUS DATA"][[1]][[1]]+1];;busPosition]];
The variable contains the string list of buses which we’ll convert to associations for use:
myBus
In[]:=
Take[myBus,5]//Map[InputForm]
Out[]=
{" 3000,'FORSMARK ', 420.0000,2, 23, 1, 1,1.00000, -2.8801,1.10000,0.90000,1.10000,0.90000"," 3020,'DANNEBO_HVDC', 420.0000,1, 23, 1, 1,0.99590, -3.5820,1.10000,0.90000,1.10000,0.90000"," 3100,'HJALTA ', 420.0000,1, 22, 1, 1,1.03796, 2.5052,1.10000,0.90000,1.10000,0.90000"," 3115,'PORJUS ', 420.0000,2, 21, 1, 1,1.00000, 6.5710,1.10000,0.90000,1.10000,0.90000"," 3200,'TENHULT ', 420.0000,1, 23, 1, 1,1.03223, 0.1040,1.10000,0.90000,1.10000,0.90000"}
StringRiffle
ImportString
Real
Integer
String
In[]:=
myBusData=Map[ReplacePart[#,2->StringTrim[StringReplace[#[[2]],"'"->""]]]&,ImportString[StringRiffle[myBus,"\n"],"CSV"]];
In[]:=
Take[myBusData,5]//Map[InputForm]
Out[]=
{{3000,"FORSMARK",420.,2,23,1,1,1.,-2.8801,1.1,0.9,1.1,0.9},{3020,"DANNEBO_HVDC",420.,1,23,1,1,0.9959,-3.582,1.1,0.9,1.1,0.9},{3100,"HJALTA",420.,1,22,1,1,1.03796,2.5052,1.1,0.9,1.1,0.9},{3115,"PORJUS",420.,2,21,1,1,1.,6.571,1.1,0.9,1.1,0.9},{3200,"TENHULT",420.,1,23,1,1,1.03223,0.104,1.1,0.9,1.1,0.9}}
Data visualization using Associations, Datasets, and Units
Data visualization using Associations, Datasets, and Units
Associations are a lightweight, helpful construct to name columns of data and can be used as key-value pairs for search. Buses have two associations: the first associates the bus number to the rest of the line, the second associates entries with each column of data. Converting the lists of associations into a Dataset allows easy selection and computation on the data.
$busTitles
In[]:=
$busTitles={"Id","Name","Voltage","Type","Area","Zone","Owner","Vpu","Vangle","High","Low","EHigh","ELow"};
In[]:=
myBusDataset=AssociationThread[First/@myBusData,AssociationThread[Rest@$busTitles,Rest[#]]&/@myBusData]//Dataset;
Quantities are proliferated through the dataset to the graph at the end.
In[]:=
myBusDataset=myBusDataset[All,MapAt[Quantity[#,"Kilovolts"]&,#,"Voltage"]&]
Out[]=
Branches and loads are updated with a similar approach.
Loads
Loads
Analysis Using Graphs
Analysis Using Graphs
Not surprisingly, a graph can be constructed of the power grid system. We won’t include the transformers for this example. Therefore, the graph will be made up of bus vertices and transmission line as edges.
This approach naturally separates the voltages and unconnected systems so that we’re looking at two separated graphs of a 420 kV and a 300 kV system:
We can further describe the bigger system by adding bus numbers and names, and loads that are present on the system with two helper functions which output a list of associations:
We totaled the loads at each bus of the 300 kV DC system and inserted them into a tooltip so that you can mouse over the vertex to see the result:
Concluding Remarks
Concluding Remarks
This analysis is just the tip of the iceberg. The ability to quickly translate a model and start validating and using the data is incredible. In the future, we’ll reassemble the the parameters into Modelica statements that can be used in Wolfram System Modeler. Then components can rapidly be created and tested.
Acknowledgments
Acknowledgments
I would like to acknowledge the help from my Wolfram Summer School Mentor, Bob Nachbar and project collaboration with Stephen Wolfram. Without his experience and code expertise this would not have been possible.
References
References
1
.G. K. Halley, L. Vanfretti and M. de Castro, “Interactive Model Transformations from the Common Information Model (CIM) to Modelica,” 2024 9th International Conference on Smart and Sustainable Technologies 2024 (SpliTech), June 25-28, 2024, Split-Bol, Croatia. https://www.researchgate.net/publication/381039589_Interactive_Model_Transformations_from_the_Common_Information_Model_CIM_to_Modelica
2
.G. K. Halley, “Model Transformation for Smart Grid Applications”, 2022 Wolfram Technology Conference, Champaign, Illinois. https://www.wolfram.com/events/technology-conference/2022/presentations/
Cite This Notebook
Cite This Notebook