Electrical Diagrams - statnett/Talk2PowerSystem GitHub Wiki

Table of Contents

Intro

We use PowSyBl Diagram (docs) to generate two kinds of electrical diagrams:

img/PowSyBl-nad-sld-diagrams.png

  • Network-area diagrams (NAD).
    • These show voltage levels as nodes, and the lines and transformers between voltage levels as edges
    • Can display the whole grid, one or several voltage levels, and the neighborhood of one or several voltage levels up to a given depth
  • Single-line diagrams (SLD).
    • These show equipment (switches, disconnectors, busbars, voltage levels, power transformers, loads, generators), adjacent lines, voltages and input/output flows
    • Can display one or several substations, voltage levels or areas
    • If several substations are requested, the user needs to provide a 2D array of their MRIDs and they are laid out in a matrix exactly like the 2D array

Section Example Diagrams shows the 4 types of diagram that we have generated (2 NAD and 2 SLD).

Other kinds of electrical diagrams can be found in:

Diagrammable PSRs

Let's count Nordic44+Telemark120 Power System Resources (PSR) that can be diagrammed by PowSyBl. TODO: amend the page Areas and Zones

PREFIX nc: <https://cim4.eu/ns/nc#>
PREFIX cim: <https://cim.ucaiug.io/ns#>
select ?type (count(*) as ?c) {
  values ?type {
    cim:Substation cim:VoltageLevel
    cim:ConformLoad cim:NonConformLoad cim:ConformLoadGroup cim:NonConformLoadGroup
    cim:GeographicalRegion cim:SubGeographicalRegion
    cim:ControlArea nc:SchedulingArea nc:BiddingZone
    cim:LoadArea cim:SubLoadArea
  }
  ?x a ?type
} group by ?type order by ?type
?type ?c
cim:ConformLoad 50
cim:ConformLoadGroup 37
cim:ControlArea 5
cim:GeographicalRegion 1
cim:LoadArea 5
cim:NonConformLoad 13
cim:NonConformLoadGroup 13
cim:SubGeographicalRegion 11
cim:SubLoadArea 12
cim:Substation 55
cim:VoltageLevel 60
nc:BiddingZone 45
nc:SchedulingArea 11

Note: PowSyBl can diagram directly substations and voltage levels. But we can diagram all voltage levels within an area, so we also count different kinds of areas present in our data.

Let's count relations between all these PSRs:

PREFIX onto: <http://www.ontotext.com/>
PREFIX nc: <https://cim4.eu/ns/nc#>
PREFIX cim: <https://cim.ucaiug.io/ns#>
select ?type1 ?p ?type2 (count(*) as ?c)
from onto:explicit {
  values ?type1 {
    cim:Substation cim:VoltageLevel
    cim:ConformLoad cim:NonConformLoad cim:ConformLoadGroup cim:NonConformLoadGroup
    cim:GeographicalRegion cim:SubGeographicalRegion
    cim:ControlArea nc:SchedulingArea nc:BiddingZone
    cim:LoadArea cim:SubLoadArea
  }
  values ?type2 {
    cim:Substation cim:VoltageLevel
    cim:ConformLoad cim:NonConformLoad cim:ConformLoadGroup cim:NonConformLoadGroup
    cim:GeographicalRegion cim:SubGeographicalRegion
    cim:ControlArea nc:SchedulingArea nc:BiddingZone
    cim:LoadArea cim:SubLoadArea
  }
  ?x a ?type1.
  ?x ?p ?y.
  ?y a ?type2.
} group by ?type1 ?p ?type2 order by ?type1 ?p ?type2
?type1 ?p ?type2 ?c
cim:ConformLoad cim:ConformLoad.LoadGroup cim:ConformLoadGroup 50
cim:ConformLoad cim:Equipment.EquipmentContainer cim:VoltageLevel 50
cim:ConformLoadGroup cim:LoadGroup.SubLoadArea cim:SubLoadArea 37
cim:ControlArea cim:ControlArea.EnergyArea cim:LoadArea 4
cim:NonConformLoad cim:Equipment.EquipmentContainer cim:VoltageLevel 13
cim:NonConformLoad cim:NonConformLoad.LoadGroup cim:NonConformLoadGroup 13
cim:NonConformLoadGroup cim:LoadGroup.SubLoadArea cim:SubLoadArea 13
cim:SubGeographicalRegion cim:SubGeographicalRegion.Region cim:GeographicalRegion 11
cim:SubLoadArea cim:SubLoadArea.LoadArea cim:LoadArea 12
cim:Substation cim:Substation.Region cim:SubGeographicalRegion 55
cim:VoltageLevel cim:VoltageLevel.Substation cim:Substation 60
nc:SchedulingArea nc:SchedulingArea.BiddingZone nc:BiddingZone 11
nc:SchedulingArea nc:SchedulingArea.ControlArea cim:ControlArea 11

Let's show this as a diagram:

Connectivity:

  • cim:GeographicalRegion, cim:SubGeographicalRegion are related to cim:VoltageLevel through cim:Substation
  • cim:LoadArea, cim:SubLoadArea are related to cim:VoltageLevel through ConformLoad or NonConformLoad and LoadGroup, namely this property path (we have checked that each VoltageLevel relates to only one SubLoadArea):
  ?voltageLevel cim:EquipmentContainer.Equipments/(cim:ConformLoad.LoadGroup|cim:NonConformLoad.LoadGroup)/cim:LoadGroup.SubLoadArea ?subLoadArea

Generate Diagram Metadata

We write a number of CONSTRUCT queries to make RDF that describes diagram instances. These queries select appropriate PSRs for PowSyBl diagramming:

Query cimr:DiagramKind.PowSyBl- PSRs
PowSyBl-SLD-substation.rq SingleLineDiagram Substation
PowSyBl-SLD-2substations.rq SingleLineDiagram-Multi Substation pairs connected through a Line or directly (that's a Nordic44 modeling shortcut)
PowSyBl-NAD-all.rq NetworkAreaDiagram Full NAD of all voltage levels
PowSyBl-NAD-SubGeographicalRegion.rq NetworkAreaDiagram NAD of voltage levels in a SubGeographicalRegion
PowSyBl-NAD-LoadArea.rq NetworkAreaDiagram NAD of voltage levels in a LoadArea
PowSyBl-NAD-SubLoadArea.rq NetworkAreaDiagram NAD of voltage levels in a SubLoadArea

The metadata uses cimr:Diagram terms as described at page Diagrams, and as defined in cimr-diagrams.ttl.

The query 2substations is most complicated because it picks pairs of substations and It looks like this:

PREFIX cimd: <https://cim.ucaiug.io/diagrams#> 
PREFIX cimr: <https://cim.ucaiug.io/rules#> 
PREFIX cim:  <https://cim.ucaiug.io/ns#>
PREFIX afn:  <http://jena.apache.org/ARQ/function#>
PREFIX dct:  <http://purl.org/dc/terms/>
prefix geo:  <http://www.opengis.net/ont/geosparql#>

construct {
  ?diag a cimd:Diagram; cimd:Diagram.kind cimd:DiagramKind.PowSyBl-SingleLineDiagram-Multi;
    cim:IdentifiedObject.name ?diagName; cim:IdentifiedObject.mRID ?diagMrid; cim:IdentifiedObject.description ?diagDescr;
    cimd:Diagram.PowerSystemResource ?psr1,?psr2; cimd:Diagram.mRIDs ?mrids; cimd:Diagram.link ?link; dct:format "image/svg+xml"
} 
where {
  {select distinct ?psr1 ?psr2 ?psr1Name ?psr2Name ?psr1Mrid ?psr2Mrid ?x1 ?x2 {
    ?psr1 a cim:Substation; cim:IdentifiedObject.name ?psr1Name; cim:IdentifiedObject.mRID ?psr1Mrid.
    ?psr2 a cim:Substation; cim:IdentifiedObject.name ?psr2Name; cim:IdentifiedObject.mRID ?psr2Mrid.
    {?psr1 cimr:connectedThroughPart ?psr2} 
    union {?psr1 cimr:connectedThroughPart ?line. ?line a cim:Line. ?psr2 cimr:connectedThroughPart ?line}
    filter(?psr1Name < ?psr2Name)
    optional {
      ?psr1 geo:hasGeometry/geo:asWKT ?geo1.
      ?psr2 geo:hasGeometry/geo:asWKT ?geo2
      bind(xsd:decimal(replace(str(?geo1),".*POINT *[(]([0-9.]+) ([0-9.]+)[)]","$1","i")) as ?x1)
      bind(xsd:decimal(replace(str(?geo2),".*POINT *[(]([0-9.]+) ([0-9.]+)[)]","$1","i")) as ?x2)
    }
  }}
  bind(coalesce(?x1 > ?x2, false) as ?swap)
  bind(replace(?psr1Name," ","-") as ?psr1Slug)
  bind(replace(?psr2Name," ","-") as ?psr2Slug)
  bind(uuid() as ?diag)
  bind(afn:localname(?diag) as ?diagMrid)
  bind(concat("Diagram of substations ",
              if(?swap,?psr2Name,?psr1Name)," and ",if(?swap,?psr1Name,?psr2Name)) as ?diagName)
  bind(concat("PowSyBl Single-Line-Diagram of substations ",
              if(?swap,?psr2Name,?psr1Name)," and ",if(?swap,?psr1Name,?psr2Name)) as ?diagDescr)
  bind(concat('["',if(?swap,?psr2Mrid,?psr1Mrid),'","',if(?swap,?psr1Mrid,?psr2Mrid),'"](/statnett/Talk2PowerSystem/wiki/"',if(?swap,?psr2Mrid,?psr1Mrid),'","',if(?swap,?psr1Mrid,?psr2Mrid),'")') as ?mrids)
  bind(concat("PowSyBl-SLD-2substations-",
              if(?swap,?psr2Slug,?psr1Slug),"-and-",if(?swap,?psr1Slug,?psr2Slug),".svg") as ?link)
}

Notes:

  • The triple patterns are in a subquery before invoking uuid() to work around the bug uuid() sometimes yields same result over different query solutions.
  • We select pairs of substations that are connected:
    • Either directly through some of their parts (this is a modeling shortcut in Nordic44)
    • Or through a shared Line
  • We eliminate pair permutations by a filter ?psr1Name < ?psr2Name
  • However, we want to order each pair by Longitude (the more western substation first, the more eastern substaion second). This is
    • So we fetch the geo:asWKT (GeoSPARQL WKT) geometries of both substations
    • Extract the x1, x2 coordinates through regex replace() because GraphDB doesn't have the GeoSPARQL 1.1 functions geof:minX, maxX
    • Compute a flag ?swap: whether the order of the two substations (which is alphabetical) needs to be swapped
  • Then we transform each Name to Slug by converting spaces to dashes
  • Generate a new URN for the Diagram object: bind(uuid() as ?diag)
  • Fetch only the UUID part of the URN as ?diagMrid
  • Form several strings (name, descr, mrids, link) by using a pattern like concat(if(?swap...)) to account for the order of the two substations
    • mrids is a list of mRIDs of the PSRs to show on the diagram, as needs to be passed to PowSyBl. See next section for details.

It produces metadata like this:

<urn:uuid:2a665063-e775-404f-80a2-ecd0a3774b8d> a cimd:Diagram;
  cimd:Diagram.kind cimd:DiagramKind.PowSyBl-SingleLineDiagram-Multi;
  cim:IdentifiedObject.name "Diagram of substations NEDENES and TELEMA2 04 CB6";
  cim:IdentifiedObject.mRID "2a665063-e775-404f-80a2-ecd0a3774b8d";
  cim:IdentifiedObject.description "PowSyBl Single-Line-Diagram of substations NEDENES and TELEMA2 04 CB6";
  cimd:Diagram.PowerSystemResource <urn:uuid:681a2179-5a55-11eb-a658-74e5f963e191>,
    <urn:uuid:811613d5-c44f-4daa-9dc1-03005740a4e5>;
  cimd:Diagram.mRIDs "[\"681a2179-5a55-11eb-a658-74e5f963e191\",\"811613d5-c44f-4daa-9dc1-03005740a4e5\"](/statnett/Talk2PowerSystem/wiki/\"681a2179-5a55-11eb-a658-74e5f963e191\",\"811613d5-c44f-4daa-9dc1-03005740a4e5\")";
  cimd:Diagram.link "PowSyBl-SLD-2substations-NEDENES-and-TELEMA2-04-CB6.svg";
  dct:format "image/svg+xml" .

The metadata for all diagrams is concatenated as diagrams.ttl.

Generate Diagrams

This query SELECTS a table of parameters to drive PowSyBl diagram generation:

select ?kind ?mrids ?link {
  ?x a cimr:Diagram;
    cimr:Diagram.kind ?kindUrl;
    cimr:Diagram.mRIDs ?mrids;
    cimr:Diagram.link ?link.
  bind(strafter(str(?kindUrl),"PowSyBl-") as ?kind)
}

It can be run in two ways:

  • On diagrams.ttl using Jena ARQ (currently we use this way)
  • Or the turtle file can be loaded in GraphDB first, then the query can be run using curl

The result is saved as diagrams.tsv and looks like this. mrids is a string representation of the Python parameter that needs to be passed to PowSyBl

?kind ?mrids ?link What is mrids
"SingleLineDiagram" ""f17696b8-9aeb-11e5-91da-b8763fd99c5f"" "PowSyBl-SLD-substation-VYBORG_HVDC.svg" single substation
"SingleLineDiagram-Multi" ""f17695fe-9aeb-11e5-91da-b8763fd99c5f",..." "PowSyBl-SLD-2substations-AJAURE-and-GRUNDFORS.svg" 2D vector consisting of a single row of 2 substations
"NetworkAreaDiagram" "PowSyBl-NAD-all.svg" none
"NetworkAreaDiagram" "("d82114b7-09c0-4cb4-b9c8-19a5fdaf991a",...)" "PowSyBl-NAD-SubGeographicalRegion-DSO-V.svg" array of VoltageLevels in that SubGeographicalRegion
"NetworkAreaDiagram" "("d82114b7-09c0-4cb4-b9c8-19a5fdaf991a",...)" "PowSyBl-NAD-SubLoadArea-FI-SLA.svg" array of VoltageLevels in that SubLoadArea
"NetworkAreaDiagram" "("d82114b7-09c0-4cb4-b9c8-19a5fdaf991a",...)" "PowSyBl-NAD-LoadArea-FI-LA.svg" array of VoltageLevels in that LoadArea

IMPORTANT: I hoped that TSV export will omit all the ugly quoting but unfortunately that's not the case. So we need to use proper TSV parsing to ensure that mrids pases through ok.

Running Python

We use the Python version of PowSyBl (which is on par with the Java version).

The Python script TODO:

  • Loads a zip of Nordic44 and Telemark120 Grid data to PowSyBl
  • Loads the above TSV and iterates over each row
  • Saves each genrated diagram to folder tsv using the filename provided in link

Example Diagrams

This section gives an example of each of the generated diagrams:

Single-Line-Diagram of Substation

Arendal:

Single-Line-Diagram of Two Substations

Kristiansand and Arendal:

Network Area Diagram

All voltage levels in Nordic44 (Telemark120 is not shown, but is present in PowSyBl-NAD-all.svg).

Network Area Diagram of SubGeographicalArea

TODO