Demo5 CimSparql - statnett/Talk2PowerSystem GitHub Wiki
Intro
Task #131
The statnett/CimSparql project includes complex real-world queries that were implemented to provide data scientists with convenient access to CIM data.
This wiki page contains AI-generated analysis of each query. The analysis is automatically produced by ChatGPT 5 (using a custom GPT), instructed to provide:
- a natural language question that bes summarises the query
- a very brief explanation of what the query does (TLDR)
- a detailed explanation of the way the query works
Each Original SPARQL is followed by a subsection Fixed SPARQL that:
- Rationalizes/simplifies when possible
- Adapts the query for Nordic+Telemark (which e.g. don't keep different profiles in different repos and don't use SPARQL Federation).
- Replaces each external param (eg
cim:IdentifiedObject.name '${rate}') with an uppercase variable (egcim:IdentifiedObject.name '$RATE'). This is used during query development, then we will parameterize before adding to our Q&A dataset
TOC
- ac_lines — AC line segments with electrical data, topology, status, limits, and loss allocation
- associated_switches — Switches sharing a connectivity node with non-switch equipment
- base_voltage — Average operating voltage per BaseVoltage vs nominal Un
- borders — AC lines crossing between two geographical regions
- branch_node_withdraw — Branch terminals in region with node mapping and p/q flows
- bus — Topological buses with voltage, substation, bidzone, and swing bus flag
- connectivity_nodes — Active connectivity nodes with container, voltage, and bidzone
- converter_hvdc_bidzones — HVDC converters mapped to connected bidding zones
- converters — Converters with electrical parameters, connectivity, control, and losses
- coordinates — Coordinates (EPSG) of substations and AC line segments
- dc_active_power_flow — Terminal active power and flow direction in region
- disconnected — Equipment currently marked as disconnected in the model
- exchange — Cross-border power exchanges between bidding zones
- full_model — Metadata about the full model contents and timestamps
- gen_unit_and_sync_machine_mapping — Mapping between generating units and synchronous machines
- hvdc — HVDC connections with converter and resistance details
- loads — Loads in a region with p/q, substation, and connectivity details
- market_dates — Market definition sets with activation dates
- phase_tap_changer — Phase tap changers with step size, neutral, and mode
- power_flow — SvPowerFlow values with in-service status for terminals
- ras_equipment — RAS protective action equipment with mRID and name
- regions — Geographical and sub-geographical regions with IDs and aliases
- series_compensators — Series compensators with electrical parameters and losses
- station_group_code_and_names — Station groups with their codes and names
- station_group_for_power_unit — Station group assignments for individual power units
- substation_voltage_level — Voltage levels per substation with max nominal voltage
- sv_branch — AC line segments with p/q and v/angle at both ends
- sv_injection — SvInjection values for topological nodes (p, q)
- sv_power_deviation — Terminal flow vs reported node injection comparison
- switches — Switch state, type, connectivity nodes, and name
- synchronous_machines — Synchronous machines with ratings, p/q, and substation
- transformer_branches — Transformer windings with electrical data and connectivity
- transformer_center_nodes — Transformer-related connectivity node info
- transformer_winding_angle — Phase shift angle of transformer winding from tap changer settings
- transformer_windings — Power transformer windings with end numbers
- transformers — Power transformers with windings, impedances, and ratings
- transformers_connected_to_converter — Transformers connected to HVDC converters
- type_mapper — Mapping SPARQL property types to their data ranges
- wind_generating_units — Wind generating units with ratings, connectivity, and operational data
- winding — Transformer windings with connectivity and electrical parameters
- winding_loss — Transformer winding losses and allocation details
ac_lines
Question
Which AC line segments (with electrical parameters, connectivity, status, limits, and loss assignment per terminal) exist in a given region, and what are their key properties?
TLDR;
Returns one row per cim:ACLineSegment in the selected ${region} with R/X/B/G, base voltage, length, connectivity nodes, terminal-connected flags, service status, optional active power limit named ${rate}, and assigns total active power losses to the terminal with the lower export (via SvPowerFlow.p). Filters out self-loops, incomplete terminals, disabled-for-analysis equipment, and lines with fewer than two terminals.
Explanation
Scope & prefixes.
The query operates on IEC CIM v16 plus a Statnett extension (SN:) and XSD. It expects equipment data to be reachable via an ENTSO-E equipment graph IRI obtained from ?_eq_subject <http://entsoe.eu/CIM/EquipmentCore/3/1> ?eq_repo and then accessed in a federated SERVICE ?eq_repo { ... } block.
Core extraction (SERVICE block).
- Selects each
?acline a cim:ACLineSegmentand reads its series/shunt parameters:cim:ACLineSegment.r→?rcim:ACLineSegment.x→?xcim:ACLineSegment.bch→?b- Optional
cim:ACLineSegment.gch→?g
- Identifiers:
cim:IdentifiedObject.mRID(?mrid) andcim:IdentifiedObject.name(?name). - Nominal voltage via the base voltage chain:
cim:ConductingEquipment.BaseVoltage / cim:BaseVoltage.nominalVoltage→?un. - Physical length:
cim:Conductor.length→?length. - Terminals & topology:
?terminal cim:Terminal.ConductingEquipment ?acline?terminal cim:Terminal.ConnectivityNode ?con_node- Terminal sequence number
?nrfromcim:Terminal.sequenceNumberorcim:ACDCTerminal.sequenceNumber(covers AC/DC terminal property alternatives).
- Topology → Substation → Area:
?con_node cim:ConnectivityNode.ConnectivityNodeContainer / cim:VoltageLevel.Substation ?substation?substation cim:Substation.Region / cim:SubGeographicalRegion.Region / cim:IdentifiedObject.name ?area
- Optional equipment-level flag:
SN:Equipment.networkAnalysisEnable ?analysis_enabled(used later to exclude equipment unless analysis is enabled; defaults toTrueif absent). - Optional active power limit:
Finds an
cim:ActivePowerLimitthat belongs to a set attached to this?acline, with a specific name${rate}, and returns itscim:ActivePowerLimit.valueas?rate.
State & flows (outside SERVICE).
- Optional steady-state service status: inverse path from
cim:SvStatus:?acline ^cim:SvStatus.ConductingEquipment / cim:SvStatus.inService ?in_service. - Terminal online flag and active power:
?terminal cim:ACDCTerminal.connected ?connected- Optional flow
?pvia?terminal ^cim:SvPowerFlow.Terminal / cim:SvPowerFlow.p ?p.
Terminal-specific splitting (node 1 vs. node 2).
Using BIND with the terminal sequence number ?nr:
- For
?nr = 1, populate?p_1(as string),?connected_1, and?connectivity_node_1; otherwise set empty string ('') orFalse. - For
?nr = 2, similarly populate?p_2,?connected_2, and?connectivity_node_2. This pattern lets laterMAX()aggregation recover the single non-empty value among grouped rows.
Regional filter.
FILTER (REGEX(?area, '${region}')) keeps only equipment whose area name matches the provided ${region regex.
Aggregation & computed outputs.
Grouping key is ?acline, so results collapse to one row per line segment. The SELECT uses extensive MAX() aggregation to pick the single meaningful value from each group:
- Scalar picks:
?mrid,?name,?r,?x,?b,?g,?un,?length,?rate,?connectivity_node_1,?connectivity_node_ 2. - Status:
?statusisCOALESCE(MAX(?in_service), MAX(?connected_1) && MAX(?connected_2), True):- Prefer explicit
SvStatus.inService; - Else, both terminals must be connected;
- Else default
True(assume in service if no info).
- Prefer explicit
- Loss allocation per terminal:
Convert the (string-bounded)
?p_1/?p_2to doubles viaxsd:double(MAX(?p_1)), etc.- Compute total active power loss as
MAX(?p_1) + MAX(?p_2). - If
p_1 < p_2, assign this sum to?ploss_1, else 0. - If
p_1 > p_2, assign the sum to?ploss_2, else 0. This ensures only one terminal receives the loss number (ties yield 0 on both sides).
- Compute total active power loss as
- Rationale for
MAX()on strings/booleans:- For strings, the non-empty string is lexicographically greater than
'', soMAX()selects the populated one. - For booleans,
True > False, soMAX()returnsTrueif any grouped row has it.
- For strings, the non-empty string is lexicographically greater than
Post-aggregation filters (HAVING).
The result keeps only “valid” line segments:
- Not a self-loop:
MAX(?connectivity_node_1) != MAX(?connectivity_node_2) - Both terminals present and non-empty.
- At least two grouped rows (two terminals):
COUNT(*) > 1. - Equipment is enabled for analysis if the flag exists:
COALESCE(MAX(?analysis_enabled), True).
Parameters you supply:
${region}— a regex to match area names (e.g.,^NO[12]$).${rate}— the name of theActivePowerLimitto fetch (e.g.,"NTC summer").
Overall, this produces a clean, one-row-per-ACLineSegment table with electrical characteristics, topology endpoints, operational status, optional limits, and a deterministic loss allocation to one of the two terminals.
Original SPARQL
# Name: AC Lines
PREFIX cim: <http://iec.ch/TC57/2013/CIM-schema-cim16#>
PREFIX SN: <http://www.statnett.no/CIM-schema-cim15-extension#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
SELECT
# Below a lot of max aggregation is performed. For variables without any suffix (_1 og _2) all values within the
# group are equal and we might as well just pick the maximum value. For variables with the suffix _1 og _2, the
# value we want to extract either exist as one entry in the group. The other entry is an empty string. Since
# all strings are greater than the empty string, max-aggregation will pick the value we want. For the boolan
# value ?connected_1 (or_2), the default value is False. By a similar argument True is larger than False,
# thus max-aggregation will pick True if it exists in the group
(MAX(?mrid) AS ?mrid) (MAX(?name) AS ?name)
# If SvPower at node 1 is smaller than SvPower at node 2, we assign the loss (sum of the two) to node_1. In case
# SvPower at node 1 is larger than on node 2, the loss is assigned to node_2
(IF(xsd:double(MAX(?p_1)) < xsd:double(MAX(?p_2)),xsd:double(MAX(?p_1)) + xsd:double(MAX(?p_2)),xsd:double(0.0)) AS ?ploss_1) (IF(xsd:double(MAX(?p_1)) > xsd:double(MAX(?p_2)),xsd:double(MAX(?p_1)) + xsd:double(MAX(?p_2)),xsd:double(0.0)) AS ?ploss_2) (MAX(?r) AS ?r) (MAX(?rate) AS ?rate) (COALESCE(MAX(?in_service), MAX(?connected_1) && MAX(?connected_2), True) AS ?status) (MAX(?un) AS ?un) (MAX(?x) AS ?x) (MAX(?b) AS ?b) (MAX(?g) AS ?g) (MAX(?length) AS ?length) (MAX(?connectivity_node_1) AS ?connectivity_node_1) (MAX(?connectivity_node_2) AS ?connectivity_node_2) WHERE {
# TODO: Check if SN:Equipment.networkAnalysisEnable is on it's way into the standard
# Assume π equivalent with at least r,x and b shunt.
# Extract properties for ACLineSegments
?_eq_subject <http://entsoe.eu/CIM/EquipmentCore/3/1> ?eq_repo
SERVICE ?eq_repo {
?acline cim:ACLineSegment.r ?r ;
cim:ACLineSegment.x ?x ;
cim:ACLineSegment.bch ?b ;
cim:IdentifiedObject.mRID ?mrid ;
cim:IdentifiedObject.name ?name ;
cim:ConductingEquipment.BaseVoltage/cim:BaseVoltage.nominalVoltage ?un ;
cim:Conductor.length ?length .
?terminal cim:Terminal.ConductingEquipment ?acline ;
cim:Terminal.ConnectivityNode ?con_node ;
cim:Terminal.sequenceNumber | cim:ACDCTerminal.sequenceNumber ?nr .
# Find substation of each connectivity node of the terminals above
?con_node cim:ConnectivityNode.ConnectivityNodeContainer/cim:VoltageLevel.Substation ?substation ;
cim:IdentifiedObject.mRID ?connectivity_node .
# Find area and optionally bidzone for each substation
?substation cim:Substation.Region/cim:SubGeographicalRegion.Region/cim:IdentifiedObject.name ?area .
OPTIONAL {
?acline cim:ACLineSegment.gch ?g .
}
OPTIONAL {
?acline SN:Equipment.networkAnalysisEnable ?analysis_enabled .
}
# If exists, extract active power limit for acline
OPTIONAL {
?_lim cim:OperationalLimit.OperationalLimitSet/cim:OperationalLimitSet.Equipment ?acline ;
a cim:ActivePowerLimit ;
cim:IdentifiedObject.name '${rate}' ;
cim:ActivePowerLimit.value ?rate .
}
} .
OPTIONAL {
# Search for acline SV status will be combined with SSH connected
?acline ^cim:SvStatus.ConductingEquipment/cim:SvStatus.inService ?in_service .
}
# Find properties in TP/SV/SSH profile for each terminal.
?terminal cim:ACDCTerminal.connected ?connected .
OPTIONAL {
?terminal ^cim:SvPowerFlow.Terminal/cim:SvPowerFlow.p ?p .
}
# Create variables for node 1 and node 2
BIND (IF(?nr = 1,STR(?p),'') AS ?p_1)
BIND (IF(?nr = 1,?connected,False) AS ?connected_1)
BIND (IF(?nr = 2,STR(?p),'') AS ?p_2)
BIND (IF(?nr = 2,?connected,False) AS ?connected_2)
BIND (IF(?nr = 1,?connectivity_node,'') AS ?connectivity_node_1)
BIND (IF(?nr = 2,?connectivity_node,'') AS ?connectivity_node_2)
FILTER (REGEX(?area,'${region}'))
}
GROUP BY ?acline
# Filtration rules
# 1) We don't need lines connecting nodes to themselves
# 2) Only extract lines where at least two nodes exist
# 3) Only extract lines where SN:Equipment.networkAnalysisEnable is True (if the field exists)
HAVING ((MAX(?connectivity_node_1) != MAX(?connectivity_node_2)) && (MAX(?connectivity_node_1) != "") && (MAX(?connectivity_node_2) != "") && (COUNT(*) > 1) && COALESCE(MAX(?analysis_enabled), True))```
Query Rationalization
Posted as https://github.com/statnett/cimsparql/issues/369
The original query can be simplified significantly:
- It selects both terminals of
aclineand their params in one set of variables (?terminal, ?petc) - Then dispatches each to separate variables:
Terminal-specific splitting (node 1 vs. node 2). Using
BINDwith the terminal sequence number?nr: For?nr = 1, populate?p_1(as string),?connected_1, and?connectivity_node_1; otherwise set empty string ('') orFalse...
- then does an ugly hack: MAX aggregation on strings and booleans
The simplified query below simply selects ?terminal1 with sequenceNumber=1 and ?terminal2 with sequenceNumber=2,
and their characteristics in similarly numbered variables. No GROUP, HAVING, or MAX is needed.
- Fixed prop name from
SN:Equipment.networkAnalysisEnabletocim:Equipment.networkAnalysisEnabled
Fixed SPARQL
# Name: AC Lines
PREFIX cim: <https://cim.ucaiug.io/ns#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
SELECT
# Rather than using max aggregation, we pick two terminals by sequenceNumber=1,2
?mrid ?name ?area
# If SvPower at node 1 is smaller than SvPower at node 2, we assign the loss (sum of the two) to node1.
# In case SvPower at node 1 is larger than on node 2, the loss is assigned to node 2
(IF(?p1<?p2, ?p1+?p2, "0"^^xsd:float) AS ?ploss1)
(IF(?p1>?p2, ?p1+?p2, "0"^^xsd:float) AS ?ploss2)
?r $RATE ?rate
(COALESCE(?in_service, ?connected1 && ?connected2, True) AS ?status)
?un ?x ?b ?g ?length ?connectivity_node1 ?connectivity_node2
WHERE {
# Assume π equivalent with at least r, x and b shunt.
# Extract properties for ACLineSegments
?acline cim:ACLineSegment.r ?r ;
cim:ACLineSegment.x ?x ;
cim:ACLineSegment.bch ?b ;
cim:IdentifiedObject.mRID ?mrid ;
cim:IdentifiedObject.name ?name ;
cim:ConductingEquipment.BaseVoltage/cim:BaseVoltage.nominalVoltage ?un ;
cim:Conductor.length ?length .
# Fetch Terminal1 with sequenceNumber=1 and Terminal2 with sequenceNumber=2
?terminal1 cim:Terminal.ConductingEquipment ?acline ;
cim:Terminal.ConnectivityNode ?con_node1 ;
cim:Terminal.sequenceNumber | cim:ACDCTerminal.sequenceNumber 1 .
?terminal2 cim:Terminal.ConductingEquipment ?acline ;
cim:Terminal.ConnectivityNode ?con_node2 ;
cim:Terminal.sequenceNumber | cim:ACDCTerminal.sequenceNumber 2 .
# Find substation of the connectivity node of terminal1.
# terminal2 might be connected to different substation, but it will be in the same area, so we use only terminal1
?con_node1 cim:ConnectivityNode.ConnectivityNodeContainer/cim:VoltageLevel.Substation ?substation ;
cim:IdentifiedObject.mRID ?connectivity_node1 .
?con_node2
cim:IdentifiedObject.mRID ?connectivity_node2 .
# Find area for the substation (TODO: and optionally bidzone)
?substation cim:Substation.Region/cim:IdentifiedObject.name ?area .
OPTIONAL {?acline cim:ACLineSegment.gch ?g .}
OPTIONAL {?acline cim:Equipment.networkAnalysisEnabled ?analysis_enabled .}
# If exists, extract active power limit for acline. In our dataset, there are limits only on Terminal1
OPTIONAL {
?_lim cim:OperationalLimit.OperationalLimitSet/cim:OperationalLimitSet.Terminal ?terminal1 ;
a cim:ActivePowerLimit ;
cim:IdentifiedObject.name $RATE ;
cim:ActivePowerLimit.value ?rate .
}
# Search for acline SV status will be combined with SSH connected
OPTIONAL {?acline ^cim:SvStatus.ConductingEquipment/cim:SvStatus.inService ?in_service .}
# Find properties in TP/SV/SSH profile for each terminal.
?terminal1 cim:ACDCTerminal.connected ?connected1 .
?terminal2 cim:ACDCTerminal.connected ?connected2 .
OPTIONAL {?terminal1 ^cim:SvPowerFlow.Terminal/cim:SvPowerFlow.p ?p1 .}
OPTIONAL {?terminal2 ^cim:SvPowerFlow.Terminal/cim:SvPowerFlow.p ?p2 .}
# Filtration rules
# 0) Only lines in desired $REGION
# FILTER (REGEX(?area,$REGION))
# 1) We don't need lines connecting nodes to themselves
FILTER(?connectivity_node1 != ?connectivity_node2)
# 2) Only extract lines where at least two nodes exist: guaranteed
# 3) Only extract lines where Equipment.networkAnalysisEnabled is True (if the field exists)
FILTER(COALESCE(?analysis_enabled, True))
}
associated_switches
Question
For each non-switch piece of conducting equipment, which nearby switches share a connectivity node with it (i.e., are associated at the same node), and what are their mRIDs and names?
TLDR;
Finds, per non-switch ConductingEquipment, all connected switches that have at least two terminals (so they can actually connect/disconnect), then aggregates the switches’ mRIDs and names into comma‑separated lists.
Explanation
- Core idea: Start from a piece of
cim:ConductingEquipment(?equipment), walk to its terminals and the sharedcim:ConnectivityNode, then back out to other conducting equipment on that same node. Among those neighbors, keep only those that arecim:Switchinstances. - Graph path:
?equipment ^cim:Terminal.ConductingEquipment / cim:Terminal.ConnectivityNode / ^cim:Terminal.ConnectivityNode / cim:Terminal.ConductingEquipment ?switchThis means: from?equipment←(has Terminal)— go to itsConnectivityNode— then to all other Terminals on that node — and finally to theirConductingEquipment(?switch). This finds equipment that is co‑incident at the same node as?equipment. - Ensure the neighbor is a switch:
?switch cim:Switch.normalOpen ?_normalOpenleverages theSwitch-specific property to both type‑narrow to switches and capture their normal open state. - Require a usable (two-terminal) switch:
?switch ^cim:Terminal.ConductingEquipment / cim:ACDCTerminal.sequenceNumber 2ensures the switch has a terminal numbered2, excluding single‑terminal switches that cannot actually connect/disconnect circuits. - Exclude the starting equipment if it’s a switch:
MINUS { ?equipment cim:Switch.normalOpen ?_open }removes any?equipmentthat is itself a switch; the query is about switches associated to other equipment. - Outputs & aggregation:
SAMPLE(?equipment_mrid)andSAMPLE(?name)pick a representative mRID and name for the grouped?equipment(since weGROUP BY ?equipmentthese are stable per group).GROUP_CONCAT(?switch_mrid)andGROUP_CONCAT(?switch_name)aggregate all associated switches’ identifiers and names into comma‑separated strings.
- Result: One row per non-switch conducting equipment, listing all co‑located (same node) operational switches with at least two terminals.
Original SPARQL
# Name: Associated switches
PREFIX cim: <http://iec.ch/TC57/2013/CIM-schema-cim16#>
SELECT (SAMPLE(?equipment_mrid) AS ?mrid) (SAMPLE(?name) AS ?name) (GROUP_CONCAT(?switch_mrid; SEPARATOR=',') AS ?switch_mrids) (GROUP_CONCAT(?switch_name; SEPARATOR=',') AS ?switch_names) WHERE {
{
?equipment ^cim:Terminal.ConductingEquipment/cim:Terminal.ConnectivityNode/^cim:Terminal.ConnectivityNode/cim:Terminal.ConductingEquipment ?switch ;
cim:IdentifiedObject.name ?name ;
cim:IdentifiedObject.mRID ?equipment_mrid .
?switch cim:Switch.normalOpen ?_normalOpen ;
cim:IdentifiedObject.mRID ?switch_mrid ;
cim:IdentifiedObject.name ?switch_name ;
# Only included switches that has a "second" terminal. There are switches
# that only have one terminal. These switches can not connect/disconnect anything
^cim:Terminal.ConductingEquipment/cim:ACDCTerminal.sequenceNumber 2 .
}
MINUS {
?equipment cim:Switch.normalOpen ?_open
}
}
GROUP BY ?equipment
Query Rationalization
https://github.com/statnett/cimsparql/issues/370
- It's good to pose the requested type at the beginning
- Checking for
cim:Switch.normalOpen(then not using the value) is a weird way to find switches. Better use the type (we have subclass reasoning, else userdf:type/rdfs:subClassOf*) - The MINUS is a weird way to say "The equipment should not be a switch": changed to FILTER NOT EXISTS
- We can use the derived relation cimr:connectedTo
- Rather than SAMPLE it's better to add these attributes to GROUP BY
Fixed SPARQL
# Name: Associated switches
PREFIX cim: <https://cim.ucaiug.io/ns#>
SELECT ?mrid ?name
(GROUP_CONCAT(?switch_mrid; SEPARATOR=',') AS ?switch_mrids)
(GROUP_CONCAT(?switch_name; SEPARATOR=',') AS ?switch_names)
WHERE {
?equipment a cim:ConductingEquipment; cimr:connectedTo ?switch ;
cim:IdentifiedObject.name ?name ;
cim:IdentifiedObject.mRID ?mrid .
filter not exists {?equipment a cim:Switch}
?switch a cim:Switch ;
cim:IdentifiedObject.mRID ?switch_mrid ;
cim:IdentifiedObject.name ?switch_name ;
# Only included switches that has a "second" terminal. There are switches
# that only have one terminal. These switches can not connect/disconnect anything
cim:ConductingEquipment.Terminals/cim:ACDCTerminal.sequenceNumber 2 .
}
GROUP BY ?mrid ?name
base_voltage
Question
What is the average operating voltage observed on each BaseVoltage and what are the corresponding BaseVoltage mRID and nominal voltage (Un)?
TLDR;
For each cim:BaseVoltage, compute the average of positive SvVoltage.v values on its topological nodes, then return that average alongside the BaseVoltage’s mRID and nominal voltage Un via a federated lookup.
Explanation
The query is structured in two parts:
-
Aggregation subquery (operating voltage per BaseVoltage)
- It starts from each TopologicalNode (
?top_node) and walks backwards along the property path^cim:SvVoltage.TopologicalNodeto find allcim:SvVoltagestate variables that reference that node. - For each such
SvVoltage, it reads the measured/estimated voltagecim:SvVoltage.vas?voltageand the node’s associatedcim:TopologicalNode.BaseVoltageas?base_voltage. - It filters out non‑positive readings:
FILTER (xsd:double(STR(?voltage)) > 0.0). TheSTR(...)thenxsd:double(...)casts ensure a numeric comparison regardless of the literal’s original datatype. - It groups by
?base_voltageand computesAVG(...)across all includedSvVoltage.vvalues to produce?operating_voltage. The result is one row per BaseVoltage with its average observed operating voltage.
- It starts from each TopologicalNode (
-
Federated enrichment (nominal Un and identifiers)
- The triple
?_eq_subject <http://entsoe.eu/CIM/EquipmentCore/3/1> ?eq_repoprovides the endpoint IRI of an equipment repository in?eq_repo. - A
SERVICE ?eq_repo { ... }block then dereferences each?base_voltageto:- fetch its nominal voltage
cim:BaseVoltage.nominalVoltageas?un, and - fetch its identifier
cim:IdentifiedObject.mRIDas?mrid.
- fetch its nominal voltage
- The outer
SELECTreturns?mrid(BaseVoltage ID),?un(nominal), and the aggregated?operating_voltageside by side, letting you compare actual average operating voltage against the BaseVoltage’s nominal Un.
- The triple
Result semantics: Each result row corresponds to a single cim:BaseVoltage resource: its unique mRID, its nominal voltage Un, and the average of positive SvVoltage.v values observed on all topological nodes that reference that BaseVoltage.
Original SPARQL
# Name: Base voltage
PREFIX cim: <http://iec.ch/TC57/2013/CIM-schema-cim16#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
SELECT ?mrid ?un ?operating_voltage {
{
SELECT ?base_voltage (AVG(xsd:double(STR(?voltage))) AS ?operating_voltage) {
?top_node ^cim:SvVoltage.TopologicalNode/cim:SvVoltage.v ?voltage ;
cim:TopologicalNode.BaseVoltage ?base_voltage .
FILTER (xsd:double(STR(?voltage)) > 0.0)
}
GROUP BY ?base_voltage
}
?_eq_subject <http://entsoe.eu/CIM/EquipmentCore/3/1> ?eq_repo .
SERVICE ?eq_repo {
# Find the nominal voltage from the base voltage associated with the topological node
?base_voltage cim:BaseVoltage.nominalVoltage ?un ;
cim:IdentifiedObject.mRID ?mrid
}
}
Query Rationalization
- Don't need to use
xsd:double(STR(..))shenanigans since our literals have proper datatypes - We have all inverses, so don't need to use inverse prop paths (
^) and the field names read more natural (notice the parallelism of the two?top_nodefields below)
Fixed SPARQL
PREFIX cim: <https://cim.ucaiug.io/ns#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
SELECT ?mrid ?un ?operating_voltage {
# Find nominal voltages of all base voltages
?base_voltage cim:BaseVoltage.nominalVoltage ?un ;
cim:IdentifiedObject.mRID ?mrid
{
SELECT ?base_voltage (AVG(?voltage) AS ?operating_voltage) {
?top_node
cim:TopologicalNode.SvVoltage/cim:SvVoltage.v ?voltage ;
cim:TopologicalNode.BaseVoltage ?base_voltage .
FILTER (?voltage > 0.0)
}
GROUP BY ?base_voltage
}
}
borders
Question
Which AC lines connect two different geographical regions (borders), and what are their terminal and market details—limited to lines touching a given ${region}?
TLDR;
Find ACLineSegments whose two terminals lie in different top-level regions, optionally return their market code, include terminal mRIDs, and restrict results to lines where either end matches ${region}. Excludes HVDC and only includes equipment enabled for network analysis (or missing that flag).
Explanation
-
Target equipment The query selects
cim:ACLineSegmentinstances and extracts their identifiers and names:?acline a cim:ACLineSegment ; cim:IdentifiedObject.mRID ?mrid ; cim:IdentifiedObject.name ?name .
-
Optional metadata Two optional lookups enrich the lines:
?market_code: via the equipment container to aSN:Lineextension:cim:Equipment.EquipmentContainer / SN:Line.marketCode ?market_code?_analysis_enabled: Statnett extension flag on the equipment:SN:Equipment.networkAnalysisEnable ?_analysis_enabled
-
Terminals and area derivation Each AC line should have two terminals. The query explicitly fetches both ends by sequence number:
- For terminal 1 (
?terminal1):(cim:Terminal.sequenceNumber | cim:ACDCTerminal.sequenceNumber) 1 - For terminal 2 (
?terminal2):(cim:Terminal.sequenceNumber | cim:ACDCTerminal.sequenceNumber) 2The union|in the property path covers models where the sequence number may be stated on eithercim:Terminalorcim:ACDCTerminal.
From each terminal it climbs the network containment hierarchy to get the top-level region name:
Terminal → cim:Terminal.ConnectivityNode → cim:ConnectivityNode.ConnectivityNodeContainer → cim:VoltageLevel.Substation → cim:Substation.Region → cim:SubGeographicalRegion.Region → cim:IdentifiedObject.name → ?area_1 / ?area_2It also keeps each terminal’s mRID as
?t_mrid_1and?t_mrid_2. - For terminal 1 (
-
Border logic (different regions)
FILTER (?area_1 != ?area_2)ensures the two terminal ends sit in different top-level regions—i.e., the line crosses a regional border. -
Region scoping
FILTER (REGEX(?area_1,'${region}') || REGEX(?area_2,'${region}'))limits results to lines that touch the user-supplied${region}on either end. (Regex is case-sensitive unless your engine defaults otherwise.) -
Exclude HVDC lines
FILTER (!REGEX(?name,'HVDC'))removes lines whose name contains “HVDC”, focusing the result set on AC interconnectors. (This relies on naming convention.) -
Network-analysis enablement (default permissive) The flag is made truthy-by-default using:
BIND (COALESCE(?_analysis_enabled, True) AS ?analysis_enabled) FILTER (?analysis_enabled)If the
SN:Equipment.networkAnalysisEnableproperty is missing, the line is treated as enabled; if present andfalse, the line is excluded. -
Output columns The
SELECTprojects:- Line identity:
?mrid,?name - Optional market:
?market_code - Areas at each end:
?area_1,?area_2 - Terminal identities:
?t_mrid_1,?t_mrid_2
- Line identity:
Overall, the query returns AC inter-regional tie-lines (borders) relevant to a given ${region}, with helpful terminal and market context.
Original SPARQL
# Name: Borders
PREFIX cim: <http://iec.ch/TC57/2013/CIM-schema-cim16#>
PREFIX SN: <http://www.statnett.no/CIM-schema-cim15-extension#>
SELECT ?mrid ?name ?market_code ?area_1 ?area_2 ?t_mrid_1 ?t_mrid_2 WHERE {
# Extract mRID, name and optionally market_code for aclines
?acline a cim:ACLineSegment ;
cim:IdentifiedObject.mRID ?mrid ;
cim:IdentifiedObject.name ?name .
OPTIONAL {
?acline cim:Equipment.EquipmentContainer/SN:Line.marketCode ?market_code
} .
OPTIONAL {
?acline SN:Equipment.networkAnalysisEnable ?_analysis_enabled .
}
# Extract properties for the terminal connected to one end of the acline (sequenceNumber 1)
?terminal1 a cim:Terminal ;
cim:Terminal.ConductingEquipment ?acline ;
cim:Terminal.sequenceNumber | cim:ACDCTerminal.sequenceNumber 1 ;
cim:Terminal.ConnectivityNode/cim:ConnectivityNode.ConnectivityNodeContainer/cim:VoltageLevel.Substation/cim:Substation.Region/cim:SubGeographicalRegion.Region/cim:IdentifiedObject.name ?area_1 ;
cim:IdentifiedObject.mRID ?t_mrid_1 .
# Extract properties for the terminal connected to the other end of the acline (sequenceNumber 2)
?terminal2 a cim:Terminal ;
cim:Terminal.ConductingEquipment ?acline ;
cim:Terminal.sequenceNumber | cim:ACDCTerminal.sequenceNumber 2 ;
cim:Terminal.ConnectivityNode/cim:ConnectivityNode.ConnectivityNodeContainer/cim:VoltageLevel.Substation/cim:Substation.Region/cim:SubGeographicalRegion.Region/cim:IdentifiedObject.name ?area_2 ;
cim:IdentifiedObject.mRID ?t_mrid_2 .
FILTER (?area_1 != ?area_2)
FILTER (REGEX(?area_1,'${region}') || REGEX(?area_2,'${region}'))
FILTER (!REGEX(?name,'HVDC')) # Ignore HVDC
BIND (COALESCE(?_analysis_enabled, True) AS ?analysis_enabled)
FILTER (?analysis_enabled)
}
Fixed SPARQL
PREFIX cim: <https://cim.ucaiug.io/ns#>
SELECT ?mrid ?name ?market_code ?area_1 ?area_2 ?t_mrid_1 ?t_mrid_2 WHERE {
# Extract mRID, name and optionally market_code for aclines
?acline a cim:ACLineSegment ;
cim:IdentifiedObject.mRID ?mrid ;
cim:IdentifiedObject.name ?name .
# We don't have any prop "marketCode"
OPTIONAL {?acline cim:Equipment.EquipmentContainer/cim:Line.marketCode ?market_code}
OPTIONAL {?acline cim:Equipment.networkAnalysisEnabled ?_analysis_enabled}
# Extract properties for the terminal connected to one end of the acline (sequenceNumber 1)
?terminal1 a cim:Terminal ;
cim:Terminal.ConductingEquipment ?acline ;
cim:Terminal.sequenceNumber | cim:ACDCTerminal.sequenceNumber 1 ;
cim:Terminal.ConnectivityNode/cim:ConnectivityNode.ConnectivityNodeContainer/cim:VoltageLevel.Substation/cim:Substation.Region/cim:IdentifiedObject.name ?area_1 ;
cim:IdentifiedObject.mRID ?t_mrid_1 .
# Extract properties for the terminal connected to the other end of the acline (sequenceNumber 2)
?terminal2 a cim:Terminal ;
cim:Terminal.ConductingEquipment ?acline ;
cim:Terminal.sequenceNumber | cim:ACDCTerminal.sequenceNumber 2 ;
cim:Terminal.ConnectivityNode/cim:ConnectivityNode.ConnectivityNodeContainer/cim:VoltageLevel.Substation/cim:Substation.Region/cim:IdentifiedObject.name ?area_2 ;
cim:IdentifiedObject.mRID ?t_mrid_2 .
FILTER (?area_1 != ?area_2)
#FILTER (REGEX(?area_1,'${region}') || REGEX(?area_2,'${region}'))
FILTER (!REGEX(?name,'HVDC')) # Ignore HVDC
FILTER (COALESCE(?_analysis_enabled, True))
}
branch_node_withdraw
Question
Which connected terminals of AC line segments, series compensators, and power transformers within a given region are associated with which topological nodes, and what are their instantaneous active/reactive power flows (p, q) and connectivity-node mRIDs—considering only equipment enabled for network analysis?
TLDR;
Filters to ACLineSegment / SeriesCompensator / PowerTransformer terminals in a target region, pulls their SvPowerFlow (p, q), resolves the terminal’s topological node via either the connectivity node or the terminal, defaults networkAnalysisEnable to true, and returns only connected, analysis-enabled results.
Explanation
-
Equipment-scope subquery (inside
SERVICE ?eq_repo)?_eq_subject <http://entsoe.eu/CIM/EquipmentCore/3/1> ?eq_repo .locates the Equipment profile repository/graph IRI and binds it to?eq_repo.SERVICE ?eq_repo { ... }runs the inner pattern specifically against that Equipment graph.VALUES ?rdf_type { cim:ACLineSegment cim:SeriesCompensator cim:PowerTransformer }restricts the query to the three branch-like equipment classes.?component a ?rdf_type .picks each equipment instance of those classes.OPTIONAL { ?component SN:Equipment.networkAnalysisEnable ?_analysis_enabled . }captures a vendor/extension flag that can disable an equipment from analysis.- Each equipment’s terminal is retrieved:
?terminal cim:Terminal.ConductingEquipment ?component ;cim:IdentifiedObject.mRID ?mrid ;— note: here?mridis the terminal’s mRID (not the equipment’s).cim:Terminal.ConnectivityNode ?con_node .
- The terminal’s connectivity node mRID is exposed:
?con_node cim:IdentifiedObject.mRID ?connectivity_node . - Regional filter: Navigates from the connectivity node up the container hierarchy to an area name:
Then?con_node cim:ConnectivityNode.ConnectivityNodeContainer/ cim:VoltageLevel.Substation/ cim:Substation.Region/ cim:SubGeographicalRegion.Region/ cim:IdentifiedObject.name ?area .FILTER (REGEX(?area,'${region}'))restricts results to the requested region (placeholder${region}is meant to be substituted by the caller).
-
Status and state variables (outside the SERVICE block)
?terminal cim:ACDCTerminal.connected ?connected .keeps only terminals currently in the connected state (later enforced by a filter).- Joins to the SV (state variables) profile to bring in the terminal’s power flow:
?_sv_t cim:SvPowerFlow.Terminal ?terminal ; cim:SvPowerFlow.p ?p ; cim:SvPowerFlow.q ?q .
-
Resolving the topological node (two paths with
UNION)- Preferred path via connectivity node:
?con_node cim:ConnectivityNode.TopologicalNode ?topological_node . - Fallback when CN→TN mapping is absent:
FILTER NOT EXISTS { ?con_node cim:ConnectivityNode.TopologicalNode ?topological_node }- Use terminal’s mapping instead:
?terminal cim:Terminal.TopologicalNode ?topological_node .
- Expose the topological node identifier:
?topological_node cim:IdentifiedObject.mRID ?node .
- Preferred path via connectivity node:
-
Analysis-enable defaulting and final filters
BIND (COALESCE(?_analysis_enabled, True) AS ?analysis_enabled)treats missingnetworkAnalysisEnableasTrue.FILTER (?analysis_enabled)andFILTER (?connected)yield only analysis-enabled and currently connected terminals.
-
Outputs
SELECT ?mrid ?node ?p ?q ?connectivity_node- For each qualifying terminal:
?mrid: terminal mRID?node: associated topological node mRID?p,?q: active/reactive power flow fromSvPowerFlow?connectivity_node: the CN mRID the terminal is attached to
Net effect: The query “withdraws”/extracts branch-end (terminal-level) injections for specified branch equipment in a region, mapped to the operative topological nodes, constrained to equipment that is both analysis-enabled (or unspecified) and electrically connected.
Original SPARQL
# Name: Branch node withdraw
PREFIX cim: <http://iec.ch/TC57/2013/CIM-schema-cim16#>
PREFIX SN: <http://www.statnett.no/CIM-schema-cim15-extension#>
SELECT ?mrid ?node ?p ?q ?connectivity_node WHERE {
{
SELECT * WHERE {
?_eq_subject <http://entsoe.eu/CIM/EquipmentCore/3/1> ?eq_repo .
SERVICE ?eq_repo {
# Specify components wer are interested in
VALUES ?rdf_type { cim:ACLineSegment cim:SeriesCompensator cim:PowerTransformer } .
?component a ?rdf_type .
OPTIONAL {
?component SN:Equipment.networkAnalysisEnable ?_analysis_enabled .
}
?terminal cim:Terminal.ConductingEquipment ?component ;
cim:IdentifiedObject.mRID ?mrid ;
cim:Terminal.ConnectivityNode ?con_node .
?con_node cim:IdentifiedObject.mRID ?connectivity_node .
# Find area for the connectivity node of the terminal
?con_node cim:ConnectivityNode.ConnectivityNodeContainer/cim:VoltageLevel.Substation/cim:Substation.Region/cim:SubGeographicalRegion.Region/cim:IdentifiedObject.name ?area .
FILTER (REGEX(?area,'${region}'))
}
}
}
# Extract properties of each terminal from the SV/TP/SSH profile.
# If exists, the mRID of the topological node associated with the terminal is etracted
?terminal cim:ACDCTerminal.connected ?connected .
?_sv_t cim:SvPowerFlow.Terminal ?terminal ;
cim:SvPowerFlow.p ?p ;
cim:SvPowerFlow.q ?q .
{
?con_node cim:ConnectivityNode.TopologicalNode ?topological_node .
}
UNION {
FILTER NOT EXISTS {
?con_node cim:ConnectivityNode.TopologicalNode ?topological_node
}
?terminal cim:Terminal.TopologicalNode ?topological_node .
}
?topological_node cim:IdentifiedObject.mRID ?node .
# Assign analysis enabled (all True if not exist)
BIND (COALESCE(?_analysis_enabled, True) AS ?analysis_enabled)
FILTER (?analysis_enabled)
FILTER (?connected)
}
Query Rationalization
https://github.com/statnett/cimsparql/issues/371
- Cosmetic: put single-triple OPTIONAL patterns on one line
- Cosmetic: remove superfluous
.(before and after}, before FILTER and OPTIONAL) - Instead of UNION ... FILTER NOT EXISTS to select amongst two alternatives, we use two consecutive OPTIONAL.
This is a beautiful trick that's very logical when you grok it:
- If the first OPTIONAL succeeds then it will bind
?topological_node - Which will preclude the second OPTIONAL from selecting another value for
?topological_node
- If the first OPTIONAL succeeds then it will bind
- (Note: I've moved
?topological_node cim:IdentifiedObject.mRIDinside the OPTIONAL to match the comment "If exists, the mRID of the topological node...")
Fixed SPARQL
PREFIX cim: <https://cim.ucaiug.io/ns#>
SELECT ?mrid ?node ?p ?q ?connectivity_node WHERE {
# Specify components we are interested in
VALUES ?rdf_type { cim:ACLineSegment cim:SeriesCompensator cim:PowerTransformer }
?component a ?rdf_type .
OPTIONAL {?component cim:Equipment.networkAnalysisEnabled ?_analysis_enabled}
FILTER (COALESCE(?_analysis_enabled, True))
?terminal cim:Terminal.ConductingEquipment ?component ;
cim:IdentifiedObject.mRID ?mrid ;
cim:Terminal.ConnectivityNode ?con_node .
?con_node cim:IdentifiedObject.mRID ?connectivity_node .
# Find area for the connectivity node of the terminal
?con_node cim:ConnectivityNode.ConnectivityNodeContainer/cim:VoltageLevel.Substation/cim:Substation.Region/cim:IdentifiedObject.name ?area .
# FILTER (REGEX(?area,$REGION))
# Extract properties of each terminal from the SV/TP/SSH profile.
?terminal cim:ACDCTerminal.connected ?connected .
FILTER (?connected)
?_sv_t cim:SvPowerFlow.Terminal ?terminal ;
cim:SvPowerFlow.p ?p ;
cim:SvPowerFlow.q ?q .
# If exists, the mRID of the topological node associated with the terminal is extracted
optional {?con_node cim:ConnectivityNode.TopologicalNode ?topological_node. ?topological_node cim:IdentifiedObject.mRID ?node}
optional {?terminal cim:Terminal.TopologicalNode ?topological_node. ?topological_node cim:IdentifiedObject.mRID ?node}
}
bus
Question
Which topological buses (nodes) exist in a given region, what are their names, voltages, substations, bidding zones, and state‑variable voltages, and which of them act as swing buses?
TLDR;
Return one row per TopologicalNode (bus) filtered by region, enriched with equipment (EQ) data for nominal/base voltage and substation context, plus real‑time SvVoltage, island membership, bidding zone (if any), and a boolean flag indicating whether the bus is the island angle reference (swing bus).
Explanation
This SPARQL query targets a Common Information Model (CIM) dataset with multiple profiles (TP/SV/EQ/SSH) and some profile extensions. It composes information primarily from the Topology Processing (TP) and State Variables (SV) profiles, and federates to the Equipment (EQ) repository to fetch nominal voltages and substation/region context.
Prefixes
cim:Core CIM 16 schema.SN:Statnett CIM extension.entsoeSecretariat:ENTSO‑E profile extension used for EIC codes.
Core node selection (TP/SV)
?top_node
cim:TopologicalNode.BaseVoltage ?base_voltage ;
cim:TopologicalNode.ConnectivityNodeContainer ?container ;
cim:IdentifiedObject.mRID ?mrid ;
cim:IdentifiedObject.name ?busname ;
^cim:SvVoltage.TopologicalNode/cim:SvVoltage.v ?sv_voltage .
- Selects each
TopologicalNode(a bus). - Captures its:
BaseVoltagelink (?base_voltage).- Owning container (
?container), typically aVoltageLevel. - CIM identifiers/name (
?mrid,?busname). - Current state variable voltage magnitude (
?sv_voltage) via a reverse property path:^cim:SvVoltage.TopologicalNodefinds theSvVoltagetied to this node, thencim:SvVoltage.vgets the value.
Optional island context (TP)
OPTIONAL {
?top_node ^cim:TopologicalIsland.TopologicalNodes/cim:IdentifiedObject.name ?island_name .
}
OPTIONAL {
?top_node ^cim:TopologicalIsland.AngleRefTopoligicalNode ?angle_ref .
}
- First block: gets the topological island name that contains the node (reverse path from island to its nodes).
- Second block: checks whether this node is the angle reference of its island (i.e., the swing bus). If the triple is present,
?angle_refis bound.
Dynamic federation to the EQ repository
?_eq_subject <http://entsoe.eu/CIM/EquipmentCore/3/1> ?eq_repo .
SERVICE ?eq_repo { ... }
- The dataset contains a triple that binds
?eq_repoto the SPARQL endpoint (or service graph IRI) for the Equipment profile. SERVICE ?eq_repo { ... }uses this dynamically discovered endpoint/graph to pull equipment‑side metadata:- From the node’s
BaseVoltage:
Retrieves nominal voltage (?base_voltage cim:BaseVoltage.nominalVoltage ?un ; cim:IdentifiedObject.mRID ?base_voltage_mrid .?un) and the BaseVoltage mRID. - From the node’s container (
VoltageLevel) up to its Substation:?container cim:VoltageLevel.Substation ?_substation . ?_substation cim:IdentifiedObject.mRID ?substation_mrid ; cim:IdentifiedObject.name ?substation_name ; cim:Substation.Region/ cim:SubGeographicalRegion.Region/ cim:IdentifiedObject.name ?area .- Finds the hosting Substation, its mRID/name, and the enclosing Geographical/SubGeographical Region name (
?area).
- Finds the hosting Substation, its mRID/name, and the enclosing Geographical/SubGeographical Region name (
- Optional bidding area via Statnett + ENTSO‑E extensions:
OPTIONAL { ?_substation SN:Substation.MarketDeliveryPoint/ SN:MarketDeliveryPoint.BiddingArea/ entsoeSecretariat:IdentifiedObject.energyIdentCodeEIC ?bidzone }- If present, returns the EIC code of the bidding zone (
?bidzone).
- If present, returns the EIC code of the bidding zone (
- From the node’s
Regional filter
FILTER REGEX(?area,'${region}')
- Keeps only rows whose
?areamatches the suppliedregionparameter (string/regex). This parameter is intended to be injected by the client at runtime.
Derived flags and defaults
BIND (IF(BOUND(?angle_ref),True,False) AS ?is_swing_bus)
BIND (COALESCE(?island_name, "Unknown") AS ?island)
?is_swing_bus:Trueif the optionalAngleRefTopoligicalNodetriple existed for the node (node is the island’s angle reference), elseFalse.?island: uses the island name if found; otherwise the literal"Unknown".
Output columns (SELECT)
?node— the TopologicalNode mRID (?mridas?node).?busname— Topological node (bus) name.?substation— Substation name.?un— Nominal voltage (fromBaseVoltage.nominalVoltage).?base_voltage_mrid— BaseVoltage mRID.?substation_mrid— Substation mRID.?bidzone— Optional EIC code of the bidding area for the substation.?sv_voltage— Measured/estimated SV voltage magnitude at the bus.?island— Topological island name (or"Unknown").?is_swing_bus— Boolean flag indicating swing bus status.
Notes & assumptions
- The reverse paths (
^...) are used to traverse fromTopologicalNodeback to related resources defined in other classes. - The federation pattern assumes your dataset exposes a triple that maps to a valid EQ
SERVICEtarget; without it, theSERVICE ?eq_repo { ... }block would not execute. - The filter uses a regex over
?area; tune it (e.g., anchors / case‑insensitive flag) as needed for your region strings.
Original SPARQL
# Name: Bus
PREFIX cim: <http://iec.ch/TC57/2013/CIM-schema-cim16#>
PREFIX SN: <http://www.statnett.no/CIM-schema-cim15-extension#>
PREFIX entsoeSecretariat: <http://entsoe.eu/Secretariat/ProfileExtension/1#>
SELECT (?mrid AS ?node) ?busname (?substation_name AS ?substation) ?un ?base_voltage_mrid ?substation_mrid ?bidzone ?sv_voltage ?island ?is_swing_bus WHERE {
# Extract propertoes from the TP/SV/SSH profile for each topological node
?top_node cim:TopologicalNode.BaseVoltage ?base_voltage ;
cim:TopologicalNode.ConnectivityNodeContainer ?container ;
cim:IdentifiedObject.mRID ?mrid ;
cim:IdentifiedObject.name ?busname ;
^cim:SvVoltage.TopologicalNode/cim:SvVoltage.v ?sv_voltage .
OPTIONAL {
?top_node ^cim:TopologicalIsland.TopologicalNodes/cim:IdentifiedObject.name ?island_name .
}
OPTIONAL {
?top_node ^cim:TopologicalIsland.AngleRefTopoligicalNode ?angle_ref .
}
?_eq_subject <http://entsoe.eu/CIM/EquipmentCore/3/1> ?eq_repo .
SERVICE ?eq_repo {
# Find the nominal voltage from the base voltage associated with the topological node
?base_voltage cim:BaseVoltage.nominalVoltage ?un ;
cim:IdentifiedObject.mRID ?base_voltage_mrid .
# Extract properties from the connectivity node container associated with each topoligical node
?container cim:VoltageLevel.Substation ?_substation .
# Extract information about the substation associated with the connectivity node container
?_substation cim:IdentifiedObject.mRID ?substation_mrid ;
cim:IdentifiedObject.name ?substation_name ;
cim:Substation.Region/cim:SubGeographicalRegion.Region/cim:IdentifiedObject.name ?area .
# Extract the bidzone of each substation if it exists
OPTIONAL {
?_substation SN:Substation.MarketDeliveryPoint/SN:MarketDeliveryPoint.BiddingArea/entsoeSecretariat:IdentifiedObject.energyIdentCodeEIC ?bidzone
}
} .
FILTER REGEX(?area,'${region}')
BIND (IF(BOUND(?angle_ref),True,False) AS ?is_swing_bus)
BIND (COALESCE(?island_name, "Unknown") AS ?island)
}
Query Rationalization
AngleRefTopologicalNodewas misspelled, fixed- Fix namespace and casing of
eu:IdentifiedObject.energyIdentCodeEic- However, neither the latest CIM/NC nor Nordic44/Telemark120 have such data:
SN:Substation.MarketDeliveryPoint/SN:MarketDeliveryPoint.BiddingArea
- However, neither the latest CIM/NC nor Nordic44/Telemark120 have such data:
- Reverse the direction of several props so we don't need to use inverse prop path
- Simplify
IF(...., True, False)to simply... - Note: on Nordic44, the query appears to return duplicate results (having same names and attributes") until you notice that there are Buses (TopologicalNodes) with the same name but different mRID, eg
47eb7c33-d0f6-11e7-9f7b-b46d83638f70 KRISTIANSAND
47eb7c30-d0f6-11e7-9f7b-b46d83638f70 KRISTIANSAND
Fixed SPARQL
PREFIX eu: <https://cim.ucaiug.io/ns/eu#>
PREFIX cim: <https://cim.ucaiug.io/ns#>
PREFIX SN: <http://www.statnett.no/CIM-schema-cim15-extension#>
SELECT ?node ?busname ?substation ?un ?base_voltage_mrid ?substation_mrid ?bidzone ?sv_voltage ?island ?is_swing_bus
WHERE {
# Extract properties from the TP/SV/SSH profile for each topological node
?top_node cim:TopologicalNode.BaseVoltage ?base_voltage ;
cim:TopologicalNode.ConnectivityNodeContainer ?container ;
cim:IdentifiedObject.mRID ?node ;
cim:IdentifiedObject.name ?busname ;
cim:TopologicalNode.SvVoltage/cim:SvVoltage.v ?sv_voltage .
OPTIONAL {?top_node cim:TopologicalNode.TopologicalIsland/cim:IdentifiedObject.name ?island_name}
OPTIONAL {?top_node ^cim:TopologicalIsland.AngleRefTopologicalNode ?angle_ref}
# Find the nominal voltage from the base voltage associated with the topological node
?base_voltage cim:BaseVoltage.nominalVoltage ?un ;
cim:IdentifiedObject.mRID ?base_voltage_mrid .
# Extract properties from the connectivity node container associated with each topoligical node
?container cim:VoltageLevel.Substation ?_substation .
# Extract information about the substation associated with the connectivity node container
?_substation cim:IdentifiedObject.mRID ?substation_mrid ;
cim:IdentifiedObject.name ?substation ;
cim:Substation.Region/cim:IdentifiedObject.name ?area .
# Extract the bidzone of each substation if it exists.
# NOTE: no such props in latest CIM/NC, and no such data in Nordic44/Telemark120
OPTIONAL {?_substation SN:Substation.MarketDeliveryPoint/SN:MarketDeliveryPoint.BiddingArea/eu:IdentifiedObject.energyIdentCodeEic ?bidzone}
#FILTER REGEX(?area,$REGION)
BIND (BOUND(?angle_ref) AS ?is_swing_bus)
BIND (COALESCE(?island_name, "Unknown") AS ?island)
}
connectivity_nodes
Question
Which active connectivity nodes exist in the network, along with their container (substation or line), voltage level, bidding zone, and related identifiers?
TLDR;
This query retrieves all active connectivity nodes and details about their associated container (either a substation or a line), including voltage level, bidding zone, container name, and IDs.
Explanation
The query identifies active connectivity nodes in the CIM model and collects metadata about their context within the network.
-
Active Connectivity Nodes
- The inner subquery checks if each connectivity node is linked to any conducting equipment with
SN:Equipment.networkAnalysisEnableset toTrue(supports both typed and string"true"values). - Only nodes with at least one such active link (
?num_active > 0) are included.
- The inner subquery checks if each connectivity node is linked to any conducting equipment with
-
Connectivity Node Container
- Every connectivity node belongs to a
ConnectivityNodeContainer, which can be either:- A Substation (via a VoltageLevel)
- A Line (directly)
- Every connectivity node belongs to a
-
Substation branch (first block)
- For substations:
- Retrieves the BaseVoltage and its nominal voltage (
?un) andmRID. - Retrieves substation metadata:
mRID,name, and the geographical region (?area). - Attempts to find the bidding zone:
- First tries to get it directly from the substation's
MarketDeliveryPoint. - If none exists, runs another subquery to find it from nearby substations connected via conducting equipment.
- First tries to get it directly from the substation's
- Assigns container type
"Substation".
- Retrieves the BaseVoltage and its nominal voltage (
- For substations:
-
Line branch (second block)
- For lines:
- Retrieves line metadata: name,
mRID, andarea. - Since lines have no direct
BaseVoltage, it searches for voltage via connected equipment and picks the highest nominal voltage found (by ordering in descending numeric value and limiting to 1). - Assigns container type
"Line".
- Retrieves line metadata: name,
- For lines:
-
Common output fields
?mrid: Connectivity node ID?container: ID of the containing substation or line?container_name: Name of the container?un: Nominal voltage (kV)?base_voltage_mrid: Voltage level ID?bidzone: Bidding zone EIC code?container_type: Either"Substation"or"Line"
-
Filtering
- The
FILTER REGEX(?area,'.*')ensures that?areais bound, effectively requiring a geographical area to be associated with the node.
- The
Overall, this query is useful for network analysis and market integration, as it links the physical network topology (connectivity nodes) with market and voltage information.
Original SPARQL
# Name: Connectivity nodes
PREFIX cim: <http://iec.ch/TC57/2013/CIM-schema-cim16#>
PREFIX SN: <http://www.statnett.no/CIM-schema-cim15-extension#>
PREFIX entsoeSecretariat: <http://entsoe.eu/Secretariat/ProfileExtension/1#>
SELECT ?mrid (?container_mrid AS ?container) ?container_name ?un ?base_voltage_mrid ?bidzone ?container_type WHERE {
?con_node cim:ConnectivityNode.ConnectivityNodeContainer ?con_node_container ;
cim:IdentifiedObject.mRID ?mrid .
{
SELECT ?con_node (COUNT(*) AS ?num_active) {
# Support both typed and not typed networkAnalysisEnable flag
VALUES ?true { True "true" }
?con_node ^cim:Terminal.ConnectivityNode/cim:Terminal.ConductingEquipment/SN:Equipment.networkAnalysisEnable ?true
}
GROUP BY ?con_node
}
FILTER (?num_active > 0)
# Extract properties from the connectivity node container associated with each topoligical node
{
?con_node_container cim:VoltageLevel.BaseVoltage ?base_voltage ;
cim:VoltageLevel.Substation ?_substation .
?base_voltage cim:BaseVoltage.nominalVoltage ?un ;
cim:IdentifiedObject.mRID ?base_voltage_mrid .
# Extract information about the substation associated with the connectivity node container
?_substation cim:IdentifiedObject.mRID ?container_mrid ;
cim:IdentifiedObject.name ?container_name ;
cim:Substation.Region/cim:IdentifiedObject.name ?area .
# Extract the bidzone of each substation if it exists
OPTIONAL {
?_substation SN:Substation.MarketDeliveryPoint/SN:MarketDeliveryPoint.BiddingArea/entsoeSecretariat:IdentifiedObject.energyIdentCodeEIC ?direct_bidzone
} .
{
FILTER (!BOUND(?bidzone))
# When an EIC code does not exist, look for an EIC code in neighbouring nodes
{
SELECT (MAX(?related_bidzone) AS ?nearby_bidzone) WHERE {
# Collect bidzones from substations connected to the current substation via a ConductingEquipment
?con_node ^cim:Terminal.ConnectivityNode/cim:Terminal.ConductingEquipment/^cim:Terminal.ConductingEquipment/cim:Terminal.ConnectivityNode/cim:ConnectivityNode.ConnectivityNodeContainer/cim:VoltageLevel.Substation/SN:Substation.MarketDeliveryPoint/SN:MarketDeliveryPoint.BiddingArea/entsoeSecretariat:IdentifiedObject.energyIdentCodeEIC ?related_bidzone .
}
}
}
BIND ("Substation" AS ?container_type)
BIND (COALESCE(?direct_bidzone, ?nearby_bidzone) AS ?bidzone)
}
UNION {
?con_node_container cim:Line.Region/cim:SubGeographicalRegion.Region/cim:IdentifiedObject.name ?area ;
cim:IdentifiedObject.name ?container_name ;
cim:IdentifiedObject.mRID ?container_mrid
# Extract voltage levels connectivity nodes related via a conducting equipment (cim:Line has no cim:VoltageLeve.BaseVoltage)
{
SELECT ?base_voltage_mrid ?un {
?con_node ^cim:Terminal.ConnectivityNode/cim:Terminal.ConductingEquipment/^cim:Terminal.ConductingEquipment/cim:Terminal.ConnectivityNode/cim:ConnectivityNode.ConnectivityNodeContainer/cim:VoltageLevel.BaseVoltage ?base_voltage .
?base_voltage cim:IdentifiedObject.mRID ?base_voltage_mrid ;
cim:BaseVoltage.nominalVoltage ?un
}
ORDER BY DESC(xsd:double(STR(?un)))
LIMIT 1
}
BIND ("Line" AS ?container_type)
}
FILTER REGEX(?area,'.*')
}
Query Rationalization
- Replaced
GROUP BYandFILTER (?num_active > 0)withFILTER EXISTS - Fixed prop name from
SN:Equipment.networkAnalysisEnabletocim:Equipment.networkAnalysisEnabledand filter outfalseonly (treat missing astrue) - Removed the selection of
?area(which is not returned) and the vacuous filterFILTER REGEX(?area,'.*') - Nordic44 doesn't have
SN:Substation.MarketDeliveryPoint/SN:MarketDeliveryPoint.BiddingAreaso I removed these optional branches - Nordic44 doesn't have any
cim:ConnectivityNodeContainer.ConnectivityNodesrelations forcim:Line(see Nordic44#77, CIM4NoUtility#406) so the second branch "Line" of the query finds nothing. The first issue suggests how the missing relations can be added with a CONSTRUCT query: I added a similar clause below - Please note that some Telemark-120 voltages have values that look a bit strange: e.g.
"2.3E-1"^^xsd:floatmeans 230V.
Fixed SPARQL
PREFIX cim: <https://cim.ucaiug.io/ns#>
SELECT ?mrid ?container ?container_name ?un ?base_voltage_mrid ?container_type
WHERE {
?con_node a cim:ConnectivityNode; cim:IdentifiedObject.mRID ?mrid .
filter exists {
?con_node cim:ConnectivityNode.Terminals/cim:Terminal.ConductingEquipment ?equipment
filter not exists {?equipment cim:Equipment.networkAnalysisEnabled false}
}
{
# Extract properties of Substation, which is connectivity node container associated with the connectivity node
?con_node cim:ConnectivityNode.ConnectivityNodeContainer ?con_node_container.
?con_node_container cim:VoltageLevel.BaseVoltage ?base_voltage ;
cim:VoltageLevel.Substation ?_substation .
?base_voltage cim:BaseVoltage.nominalVoltage ?un ;
cim:IdentifiedObject.mRID ?base_voltage_mrid .
# Extract information about the substation associated with the connectivity node container
?_substation cim:IdentifiedObject.mRID ?container ;
cim:IdentifiedObject.name ?container_name .
BIND ("Substation" AS ?container_type)
}
UNION {
# Find ConnectivityNodes belonging to Line through ACLineSegment
?con_node_container a cim:Line;
cim:IdentifiedObject.name ?container_name ; cim:IdentifiedObject.mRID ?container ;
cim:EquipmentContainer.Equipments ?segment.
# Extract voltage levels from ACLineSegment
?segment a cim:ACLineSegment; cim:ConductingEquipment.Terminals/cim:Terminal.ConnectivityNode ?con_node;
cim:ConductingEquipment.BaseVoltage ?base_voltage.
?base_voltage cim:IdentifiedObject.mRID ?base_voltage_mrid ;
cim:BaseVoltage.nominalVoltage ?un
BIND ("Line" AS ?container_type)
}
}
converter_hvdc_bidzones
Question
For each HVDC converter, which two bidding zones (market codes) are connected by the DC line that starts at the converter’s associated market delivery point?
TLDR;
Find each converter’s pole, get its substation’s market delivery point and bidding zone (bidzone_1), then follow the DC line that departs from that delivery point to the opposite end’s bidding zone (bidzone_2), and return pairs where the zones differ.
Explanation
This query maps HVDC converters to the pair of bidding zones they bridge, using Statnett (SN) and Alstom (ALG) CIM extensions alongside the CIM core namespace (cim).
1) Namespaces
cim:— core IEC CIM (e.g.,IdentifiedObject,Equipment,EquipmentContainer).SN:— Statnett CIM extension (e.g.,Substation.MarketDeliveryPoint,BiddingArea.marketCode,Line.FromMarketDeliveryPoint).ALG:— Alstom CIM extension for DC converters (e.g.,DCConverter.DCPole,VoltageSourceConverter.DCPole).
2) Selecting converters and their poles
?converter ALG:DCConverter.DCPole | ALG:VoltageSourceConverter.DCPole ?pole ;
cim:IdentifiedObject.mRID ?mrid .
- Uses a property path union (
|) to cover two model variants: classical DC converters and voltage‑source converters, both linking a converter to its?pole. - Retrieves the converter’s external identifier
?mrid.
3) From the pole to its market delivery point and bidding zone
?pole cim:Equipment.EquipmentContainer/SN:Substation.MarketDeliveryPoint ?delivery_point .
?delivery_point SN:MarketDeliveryPoint.BiddingArea/SN:BiddingArea.marketCode ?bidzone_1 .
-
Uses a chained property path (
/) to traverse:cim:Equipment.EquipmentContainer→ the container (typically a Substation) that holds the pole.SN:Substation.MarketDeliveryPoint→ the substation’s MarketDeliveryPoint (?delivery_point).
-
From that delivery point, it reaches its BiddingArea and extracts the market code as
?bidzone_1.
4) Following the outgoing line to the opposite bidding zone
?line SN:Line.FromMarketDeliveryPoint ?delivery_point ;
SN:Line.ToMarketDeliveryPoint/SN:MarketDeliveryPoint.BiddingArea/SN:BiddingArea.marketCode ?bidzone_2
- Finds a Line where the FromMarketDeliveryPoint equals the converter’s
?delivery_point. - Traverses the ToMarketDeliveryPoint end to its BiddingArea and captures that end’s market code as
?bidzone_2.
5) Ensuring cross-zone connections and uniqueness
FILTER (?bidzone_1 != ?bidzone_2)
- Keeps only inter‑zone connections (i.e., the two ends are in different bidding zones).
SELECT DISTINCTremoves duplicates that could arise from multiple modelling paths, multiple poles per converter, or multiple lines starting from the same delivery point.
6) Output
SELECT DISTINCT ?mrid ?bidzone_1 ?bidzone_2
- Returns the converter’s identifier and the pair of market codes representing the two bidding zones bridged by the line originating at that converter’s market delivery point.
Notes & assumptions
- The pole’s
EquipmentContaineris a Substation that has exactly oneSN:Substation.MarketDeliveryPoint; if several exist,DISTINCTwill deduplicate results. - Directionality is taken from
SN:Line.FromMarketDeliveryPoint→SN:Line.ToMarketDeliveryPoint. If the dataset also models the reverse direction or multiple lines per delivery point, you may see multiple?bidzone_2values (still deduplicated). - The union on ALG properties makes the query resilient to different converter modelling styles (LCC vs VSC).
Original SPARQL
# Name: Converter HVDC bidzones
PREFIX cim: <http://iec.ch/TC57/2013/CIM-schema-cim16#>
PREFIX SN: <http://www.statnett.no/CIM-schema-cim15-extension#>
PREFIX ALG: <http://www.alstom.com/grid/CIM-schema-cim15-extension#>
SELECT DISTINCT ?mrid ?bidzone_1 ?bidzone_2 WHERE {
?converter ALG:DCConverter.DCPole | ALG:VoltageSourceConverter.DCPole ?pole ;
cim:IdentifiedObject.mRID ?mrid .
?pole cim:Equipment.EquipmentContainer/SN:Substation.MarketDeliveryPoint ?delivery_point .
?delivery_point SN:MarketDeliveryPoint.BiddingArea/SN:BiddingArea.marketCode ?bidzone_1 .
# Extract the destination point from the line that has one end matching bidzone_1
?line SN:Line.FromMarketDeliveryPoint ?delivery_point ;
SN:Line.ToMarketDeliveryPoint/SN:MarketDeliveryPoint.BiddingArea/SN:BiddingArea.marketCode ?bidzone_2
FILTER (?bidzone_1 != ?bidzone_2)
}
ALG:DCConverter.DCPoleis now standardized asnc:DCConverterUnit.DCPoleALG:VoltageSourceConverter.DCPoledoes not exist- Cannot refactor this query because we don't have any info about
MarketDeliveryPoint
converters
Question
Which converters exist in the system, along with their key electrical parameters, connectivity details, substation associations, control factors, and loss characteristics?
TLDR;
This SPARQL query retrieves detailed information about all converters in the network, including identifiers, names, alias names, power values (P, Q), substation details, status, connectivity nodes, controllers and participation factors, pole and converter losses, and voltage ratings.
Explanation
The query is structured to gather comprehensive converter-related data by combining multiple nested queries, optional patterns, and bindings. Here’s how it works step-by-step:
- Repository Setup
It starts by locating the relevant CIM equipment repository via:
?_eq_subject <http://entsoe.eu/CIM/EquipmentCore/3/1> ?eq_repo .
Then it uses a SERVICE call to query that repository for the actual converter data.
-
Core Converter Details Inside the service, it identifies converters by matching:
cim:IdentifiedObject.mRID→ unique ID (?mrid)cim:IdentifiedObject.name→ human-readable name (?name)- Associated poles via either
ALG:VoltageSourceConverter.DCPoleorALG:DCConverter.DCPole.
-
Controller & Participation Factor It fetches the pole’s controller mRID and calculates the average participation factor:
MAX(xsd:float(STR(?controller_factor))) / COUNT(*) AS ?controller_factorgrouped per pole.
-
Alias Name (Optional) If available,
cim:IdentifiedObject.aliasNameis retrieved. -
Terminal & Connectivity It finds the converter’s terminal with
sequenceNumber = 1and traces its connectivity node:- Node mRID (
?connectivity_node) - Container → VoltageLevel → Substation → Region (
?substation_mrid,?unvoltage level,?arearegion name).
- Node mRID (
-
Optional Network Analysis Enable Flag From
SN:Equipment.networkAnalysisEnable, defaults toTrueif missing. -
Loss Parameters (Optional) Retrieves converter loss coefficients (
loss0,loss1,loss2) and DC nominal voltage (vdcn) from poles, defaulting to 0.0 when absent. -
Filtering Only converters with
analysis_enabled = Trueare kept. -
Active & Reactive Power Retrieves
cim:ACDCConverter.p(active power) andcim:ACDCConverter.q(reactive power). -
Pole Loss & Status Optional
poleLossPis retrieved. Status is determined by coalescingSvStatus.inServicewith terminal connection status. -
Final Output Variables Returns:
- IDs:
mrid,substation_mrid,connectivity_node,controller - Names:
name,alias - Electrical:
p,q,un,vdcn - Losses:
pole_loss,loss0,loss1,loss2 - Control:
controller_factor - Status:
status
- IDs:
Original SPARQL
# Name: Converters
PREFIX cim: <http://iec.ch/TC57/2013/CIM-schema-cim16#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX SN: <http://www.statnett.no/CIM-schema-cim15-extension#>
PREFIX ALG: <http://www.alstom.com/grid/CIM-schema-cim15-extension#>
SELECT ?mrid ?name ?alias ?p ?q ?substation_mrid ?status ?connectivity_node ?controller ?controller_factor ?pole_loss ?loss0 ?loss1 ?loss2 ?vdcn ?un WHERE {
{
SELECT * WHERE {
?_eq_subject <http://entsoe.eu/CIM/EquipmentCore/3/1> ?eq_repo .
SERVICE ?eq_repo {
# Extract mrid, name, substation and optionally aliasName of the converter
?converter cim:IdentifiedObject.mRID ?mrid ;
cim:IdentifiedObject.name ?name ;
ALG:VoltageSourceConverter.DCPole | ALG:DCConverter.DCPole ?pole .
?pole ALG:DCPole.DCController/cim:IdentifiedObject.mRID ?controller .
{
SELECT ?pole (MAX(xsd:float(STR(?controller_factor))) / COUNT(*) AS ?controller_factor) {
?converter ALG:VoltageSourceConverter.DCPole | ALG:DCConverter.DCPole ?pole .
?pole ALG:DCPole.participationFactor ?controller_factor .
}
GROUP BY ?pole
}
OPTIONAL {
?converter cim:IdentifiedObject.aliasName ?alias .
}
# Extract properties for the terminals for the converter
?terminal cim:Terminal.ConductingEquipment ?converter ;
cim:Terminal.ConnectivityNode ?con_node ;
cim:Terminal.sequenceNumber | cim:ACDCTerminal.sequenceNumber 1 .
?con_node cim:IdentifiedObject.mRID ?connectivity_node ;
cim:ConnectivityNode.ConnectivityNodeContainer ?con_node_container .
?con_node_container cim:VoltageLevel.Substation ?substation ;
cim:VoltageLevel.BaseVoltage/cim:BaseVoltage.nominalVoltage ?un .
?substation cim:IdentifiedObject.mRID ?substation_mrid ;
cim:Substation.Region/cim:SubGeographicalRegion.Region/cim:IdentifiedObject.name ?area .
OPTIONAL {
?converter SN:Equipment.networkAnalysisEnable ?_analysis_enabled .
}
OPTIONAL {
?converter ALG:VoltageSourceConverter.loss0 ?_loss0 ;
ALG:VoltageSourceConverter.loss1 ?_loss1 ;
ALG:VoltageSourceConverter.loss2 ?_loss2 .
?pole cim:ConductingEquipment.BaseVoltage/cim:BaseVoltage.nominalVoltage ?_vdcn ;
}
BIND (COALESCE(?_analysis_enabled, True) AS ?analysis_enabled)
BIND (COALESCE(?_loss0, 0.0) AS ?loss0)
BIND (COALESCE(?_loss1, 0.0) AS ?loss1)
BIND (COALESCE(?_loss2, 0.0) AS ?loss2)
BIND (COALESCE(?_vdcn, 0.0) AS ?vdcn)
FILTER (?analysis_enabled)
}
}
}
# Extract active and reactive power for the converter
?converter cim:ACDCConverter.p ?p ;
cim:ACDCConverter.q ?q .
OPTIONAL {
?converter cim:ACDCConverter.poleLossP ?_pole_loss .
}
OPTIONAL {
?converter ^cim:SvStatus.ConductingEquipment/cim:SvStatus.inService ?in_service .
}
# Extract connected and optionally the mrid for the topological node associated with the terminal
?terminal cim:ACDCTerminal.connected ?connected .
BIND (COALESCE(?in_service, ?connected) AS ?status)
BIND (COALESCE(?_pole_loss, 0.0) AS ?pole_loss)
}
- Some of the terms are now standardized as
nc:DirectCurrentPoleController.DCPole, nc:DCConverterUnit.DCPoleetc - We don't have any data about DC Convertors, so cannot refactor the query
coordinates
Question
For each substation and AC line segment, what are the (x, y) coordinates of their position points, which EPSG code are those coordinates in, and what is the resource’s mRID and RDF type?
TLDR;
Returns every PositionPoint (x/y) tied to a Location that belongs to either a cim:Substation or a cim:ACLineSegment, along with the resource mRID, the parsed EPSG code from the coordinate system URN, and the string form of the resource’s RDF class.
Explanation
- Core pattern (position points):
?s cim:PositionPoint.Location ?location ; cim:PositionPoint.sequenceNumber ?nr ; cim:PositionPoint.xPosition ?x ; cim:PositionPoint.yPosition ?y .
This finds each cim:PositionPoint (?s) with its parent ?location, its ordinal ?nr, and its coordinates ?x/?y.
-
From location to the owning resource(s):
?location cim:Location.PowerSystemResources ?resource . VALUES ?resource_type { cim:Substation cim:ACLineSegment } ?resource a ?resource_type ; cim:IdentifiedObject.mRID ?mrid .Each
Locationmay be shared by multiple resources. TheVALUESclause restricts results to resources whose RDF type is eithercim:Substationorcim:ACLineSegment. For the chosen resource, the query retrieves itsmRID. -
Coordinate reference system → EPSG:
?location cim:Location.CoordinateSystem/cim:CoordinateSystem.crsUrn ?co . BIND (STRAFTER(?co,'EPSG::') AS ?epsg)The path
cim:Location.CoordinateSystem/cim:CoordinateSystem.crsUrngets a CRS URN likeurn:ogc:def:crs:EPSG::4326.STRAFTERextracts the EPSG code ("4326") as?epsg. -
Readable RDF type column:
(STR(?resource_type) AS ?rdf_type)Converts the class IRI (
cim:Substationorcim:ACLineSegment) to its lexical string (typically the full IRI) for display. -
Intended sequencing:
BIND (CONCAT(STR(?mrid), STR(?nr)) AS ?sequence) ORDER BY (?sequece)The query appears to create a sort key combining the resource
mRIDwith the position point’s sequence number, so points for the same resource sort by?nr. However, there are two issues:- Typo in ORDER BY — it uses
?sequeceinstead of?sequence, so ordering won’t apply. ?sequencenot selected — it’s only used for ordering; that’s fine, but if you want to inspect it you’d need to add it toSELECT.
Better approach: sort by the actual variables without concatenation:
ORDER BY ?mrid xsd:integer(?nr)(Cast
?nrif it’s a string to ensure numeric ordering.) - Typo in ORDER BY — it uses
-
What the result rows look like: Each row corresponds to one
PositionPointof a qualifying resource and contains:?mrid— the mRID of theSubstationorACLineSegment?x,?y— the point’s coordinates?epsg— EPSG code parsed from the CRS URN?rdf_type— string form of the resource’s RDF class
Quick fixed version (minimal changes):
PREFIX cim: <http://iec.ch/TC57/2013/CIM-schema-cim16#>
SELECT ?mrid ?x ?y ?epsg (STR(?resource_type) AS ?rdf_type) WHERE {
?s cim:PositionPoint.Location ?location ;
cim:PositionPoint.sequenceNumber ?nr ;
cim:PositionPoint.xPosition ?x ;
cim:PositionPoint.yPosition ?y .
?location cim:Location.PowerSystemResources ?resource ;
cim:Location.CoordinateSystem/cim:CoordinateSystem.crsUrn ?co .
VALUES ?resource_type { cim:Substation cim:ACLineSegment }
?resource a ?resource_type ;
cim:IdentifiedObject.mRID ?mrid .
BIND (STRAFTER(?co,'EPSG::') AS ?epsg)
}
ORDER BY ?mrid xsd:integer(?nr)
This preserves the intent, avoids the typo, and ensures a stable, numeric ordering of points per resource.
Original SPARQL
# Name: Coordinates
PREFIX cim: <http://iec.ch/TC57/2013/CIM-schema-cim16#>
SELECT ?mrid ?x ?y ?epsg (STR(?resource_type) AS ?rdf_type) WHERE {
?s cim:PositionPoint.Location ?location ;
cim:PositionPoint.sequenceNumber ?nr ;
cim:PositionPoint.xPosition ?x ;
cim:PositionPoint.yPosition ?y .
?location cim:Location.PowerSystemResources ?resource ;
cim:Location.CoordinateSystem/cim:CoordinateSystem.crsUrn ?co .
VALUES ?resource_type { cim:Substation cim:ACLineSegment }
?resource a ?resource_type ;
cim:IdentifiedObject.mRID ?mrid .
BIND (STRAFTER(?co,'EPSG::') AS ?epsg)
BIND (CONCAT(STR(?mrid), STR(?nr)) AS ?sequence)
}
ORDER BY (?sequece)
Query Rationalization
- We've converted coordinates to GeoSPARQL WKT:
- Every
cim:Locationis alsogeo:Geometrywithgeo:asWKT(POINTorLINESTRING) that carries all point coordinates in the appropriate order - Individual
cim:PositionPointare deleted since they are not needed anymore
- Every
- I added
strafterto return only the localname of?rdf_type; else I don't see whystr(?rdf_type)is needed - Note: the query hard-codes that only
cim:Substation cim:ACLineSegmenthave coordinates. An easy way to generalize this is to replace theVALUESclause with this:
?resource sesame:directType ?resource_type; cim:IdentifiedObject.mRID ?mrid .
filter(strstarts(str(?resource_type),str(cim:)))
Where:
sesame:directTypedoesn't return inferred types (abstract supertypes)filter(strstarts())ensures that only CIM types are returned.- Following the GeoSPARQL specification, we've added a secondary type
geo:Featureto every resource that has aGeometry
- Following the GeoSPARQL specification, we've added a secondary type
Fixed SPARQL
PREFIX sesame: <http://www.openrdf.org/schema/sesame#>
PREFIX geo: <http://www.opengis.net/ont/geosparql#>
PREFIX cim: <https://cim.ucaiug.io/ns#>
SELECT ?mrid ?wkt ?epsg ?rdf_type WHERE {
?location cim:Location.PowerSystemResources ?resource ;
geo:asWKT ?wkt;
cim:Location.CoordinateSystem/cim:CoordinateSystem.crsUrn ?co .
VALUES ?resource_type { cim:Substation cim:ACLineSegment }
?resource a ?resource_type; cim:IdentifiedObject.mRID ?mrid .
bind(strafter(str(?resource_type),str(cim:)) as ?rdf_type)
BIND (STRAFTER(?co,'EPSG::') AS ?epsg)
} ORDER BY ?mrid
dc_active_power_flow
Question
For each line segment, series compensator, and transformer end in a chosen region, what is the terminal active power (p) (from the state variables) and the implied flow direction based on the terminal’s sequence number?
TLDR;
Looks up terminals of selected equipment in a target region, joins them to SvPowerFlow.p, and returns the equipment mRID, the active power (p) at each terminal, and a direction flag +1 for terminal 1 and -1 for the opposite terminal.
Explanation
-
Prefixes & focus
- Uses the IEC CIM namespace (
cim:) and XML Schema datatypes (xsd:). - The query ultimately returns three bindings per row:
?mrid– the mRID of the equipment component,?p– the active power at the terminal fromSvPowerFlow,?direction– a sign (+1/-1) derived from the terminal sequence number.
- Uses the IEC CIM namespace (
-
Join to state variables (
SvPowerFlow)- Outside the
SERVICEblock:
The reverse path?terminal ^cim:SvPowerFlow.Terminal/cim:SvPowerFlow.p ?p .^cim:SvPowerFlow.Terminalfinds theSvPowerFlowrow whoseTerminalis?terminal, then extracts itspvalue. This ensures the power is per terminal (not per equipment).
- Outside the
-
Choosing the equipment repository
- The line:
binds?_eq_subject <http://entsoe.eu/CIM/EquipmentCore/3/1> ?eq_repo .?eq_repoto the dataset/endpoint IRI that hosts the EquipmentCore model. This is then used in:
to run the equipment/topology part of the query against that repository.SERVICE ?eq_repo { ... }
- The line:
-
Selecting components & their terminals (two cases) Inside the
SERVICE:-
Lines & series compensators
VALUES ?rdf_type { cim:ACLineSegment cim:SeriesCompensator } . ?component a ?rdf_type ; cim:Equipment.EquipmentContainer/(cim:Line.Region | cim:VoltageLevel.Substation/cim:Substation.Region) ?region . ?terminal cim:Terminal.ConductingEquipment ?component ; cim:Terminal.sequenceNumber | cim:ACDCTerminal.sequenceNumber ?nr .- Restricts to
ACLineSegmentandSeriesCompensator. - Resolves the geographical region via two alternative paths:
- directly from a line’s region (
Line.Region), or - via the VoltageLevel → Substation → Region chain for equipment contained in a substation.
- directly from a line’s region (
- Grabs the terminal linked to the component and its sequence number (
?nr). The alternationTerminal.sequenceNumber | ACDCTerminal.sequenceNumberallows either AC or DC-style terminals.
- Restricts to
-
Transformers (by ends)
?p_transformer cim:Equipment.EquipmentContainer/cim:Substation.Region ?region . ?component cim:PowerTransformerEnd.PowerTransformer ?p_transformer ; cim:TransformerEnd.Terminal ?terminal . BIND (1 AS ?nr)- First determine the region at the power transformer level (via its substation).
- Then treat each PowerTransformerEnd as the
?component, retrieving its associated?terminal. - Since transformer ends might not carry a meaningful
sequenceNumberin the same way, it forces?nr = 1for consistent handling downstream.
These two branches are combined with
UNION, so the result set contains terminals from line segments, series compensators, and transformer ends. -
-
Region naming & filtering
?region cim:SubGeographicalRegion.Region/cim:IdentifiedObject.name ?regionName . FILTER (REGEX(?regionName,'${region}'))
- Obtains a human-readable
?regionNameby traversingSubGeographicalRegion.Region → IdentifiedObject.name. - Applies a parameterized regex filter using the template variable
${region}(to be substituted by the caller) to restrict results to the desired region(s). The match is case-sensitive by default unless the template adds flags.
-
Equipment identity
?component cim:IdentifiedObject.mRID ?mrid .- Extracts the canonical identifier for the component tied to the terminal.
-
Direction sign from terminal ordering
BIND (IF(?nr = 1, 1, -1) AS ?direction)-
Interprets terminal sequence to produce a direction convention:
+1for terminal 1,-1for any other terminal (commonly terminal 2 for two-terminal devices).
-
For transformer ends (where
?nrwas bound to 1), the sign becomes+1by construction.
-
-
Result semantics
- Each row corresponds to a specific terminal of a selected component in the chosen region.
?pis the active power injection/flow at that terminal, as computed by the state variables (SvPowerFlow).?directionprovides a simple convention to orient flows consistently using terminal order; consumers can multiplyp * directionif they wish to align all flows to the “from-terminal-1” direction.- Multiple rows per equipment are expected (e.g., one per terminal on a line), allowing downstream aggregation if needed.
In summary, the query ties equipment geometry (region & container) to network terminals, joins those terminals to the state variable active power, and emits a signed terminal power based on a consistent terminal-order convention, restricted to a caller-provided region.
Original SPARQL
# Name: DC Active Power Flow
PREFIX cim: <http://iec.ch/TC57/2013/CIM-schema-cim16#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
SELECT ?mrid ?p ?direction WHERE {
?terminal ^cim:SvPowerFlow.Terminal/cim:SvPowerFlow.p ?p .
?_eq_subject <http://entsoe.eu/CIM/EquipmentCore/3/1> ?eq_repo .
SERVICE ?eq_repo {
{
{
# Declare components we are interested in
VALUES ?rdf_type { cim:ACLineSegment cim:SeriesCompensator } .
?component a ?rdf_type ;
cim:Equipment.EquipmentContainer/(cim:Line.Region | cim:VoltageLevel.Substation/cim:Substation.Region) ?region .
# Extract properties for the terminal associated with the component
?terminal cim:Terminal.ConductingEquipment ?component ;
cim:Terminal.sequenceNumber | cim:ACDCTerminal.sequenceNumber ?nr .
}
UNION {
# Extract the region for the transformer
?p_transformer cim:Equipment.EquipmentContainer/cim:Substation.Region ?region .
# For each power transformer extract all windngs and terminal
?component cim:PowerTransformerEnd.PowerTransformer ?p_transformer ;
cim:TransformerEnd.Terminal ?terminal .
BIND (1 AS ?nr)
}
} .
?region cim:SubGeographicalRegion.Region/cim:IdentifiedObject.name ?regionName .
# Extract the mRID for the component
?component cim:IdentifiedObject.mRID ?mrid .
FILTER (REGEX(?regionName,'${region}'))
BIND (IF(?nr = 1,1,-1) AS ?direction)
}
}
Query Rationalization
Not many changes here:
- Removed the federated SERVICE call
- Removed
cim:SubGeographicalRegion.Regionsince in our data all these are "NO"
Fixed SPARQL
PREFIX cim: <https://cim.ucaiug.io/ns#>
SELECT ?mrid ?p ?direction WHERE {
?terminal ^cim:SvPowerFlow.Terminal/cim:SvPowerFlow.p ?p .
{
# Declare components we are interested in
VALUES ?rdf_type { cim:ACLineSegment cim:SeriesCompensator } .
?component a ?rdf_type ;
cim:Equipment.EquipmentContainer/(cim:Line.Region | cim:VoltageLevel.Substation/cim:Substation.Region) ?region .
# Extract properties for the terminal associated with the component
?terminal cim:Terminal.ConductingEquipment ?component ;
cim:Terminal.sequenceNumber | cim:ACDCTerminal.sequenceNumber ?nr .
}
UNION {
# Extract the region for the transformer
?p_transformer cim:Equipment.EquipmentContainer/cim:Substation.Region ?region .
# For each power transformer extract all windings and terminal
?component cim:PowerTransformerEnd.PowerTransformer ?p_transformer ;
cim:TransformerEnd.Terminal ?terminal .
BIND (1 AS ?nr)
}
?region cim:IdentifiedObject.name ?regionName .
# Extract the mRID for the component
?component cim:IdentifiedObject.mRID ?mrid .
# FILTER (REGEX(?regionName,$REGION)
BIND (IF(?nr = 1,1,-1) AS ?direction)
}
disconnected
Question
Which disconnectors are open or terminals are disconnected in the CIM network?
TLDR;
This query retrieves the identifiers (?mrid) of all disconnectors that are currently open and all terminals that are not connected.
Explanation
The query uses the CIM ontology to check for two different disconnection scenarios and combines them with a UNION so that results from either scenario are included:
- First block
?mrid a cim:Disconnector ; cim:Switch.open True .
This matches all resources of type cim:Disconnector where the property cim:Switch.open has the value True. In CIM terms, this means the disconnector is physically in an open state, preventing current flow.
-
Second block
?mrid a cim:Terminal ; cim:Terminal.connected | cim:ACDCTerminal.connected False .This matches all resources of type
cim:Terminalwhere eithercim:Terminal.connectedorcim:ACDCTerminal.connectedisFalse. The vertical bar (|) acts as a property path “OR”, meaning it will check both possible connection properties in case the terminal is AC/DC specific. AFalsevalue means the terminal is not currently connected to the network.
The use of UNION means the final result set will include:
- All open disconnectors (from the first block)
- All disconnected terminals (from the second block)
This provides a combined view of components that break network continuity—either by open switching devices or by unconnected terminals.
Original SPARQL
# Name: Disconnected
PREFIX cim: <http://iec.ch/TC57/2013/CIM-schema-cim16#>
SELECT ?mrid WHERE {
{
?mrid a cim:Disconnector ;
cim:Switch.open True .
}
UNION {
?mrid a cim:Terminal ;
cim:Terminal.connected | cim:ACDCTerminal.connected False .
}
}
Fixed SPARQL
PREFIX cim: <https://cim.ucaiug.io/ns#>
SELECT ?mrid WHERE {
{
?mrid a cim:Disconnector ;
cim:Switch.open True .
}
UNION {
?mrid a cim:Terminal ;
cim:Terminal.connected | cim:ACDCTerminal.connected False .
}
}
exchange
Question
Which AC line segments export power from a chosen region to outside that region, and what are their names, terminal-1 active power flow (P), topological node mRID, equipment mRID, market code, and overall in-service/connected status?
TLDR;
Finds non‑HVDC ACLineSegments whose two terminals sit in different regions (one matching ${region}, the other not), then reports terminal‑1 power flow p, node ID, market code, and a computed status (prefer inService; otherwise both terminals must be connected).
Explanation
This query stitches together state variables, equipment data (via a federated SERVICE), and topology to list AC transmission lines that represent exchanges between a specified region and its neighbors.
-
State & connectivity at terminal level
?terminal1 ^cim:SvPowerFlow.Terminal/cim:SvPowerFlow.p ?p ; cim:ACDCTerminal.connected ?connected_1 .Uses a reverse property path to pull the active power flow?pfrom theSvPowerFlowstate tied to?terminal1and reads its connected flag.?terminal2 cim:ACDCTerminal.connected ?connected_2 .Reads the connected flag for the opposite terminal.
-
Topological node resolution (robust to model variants)
- Either take the ConnectivityNode → TopologicalNode mapping:
OR, if that mapping is absent, fall back to the Terminal → TopologicalNode link:?con_node cim:ConnectivityNode.TopologicalNode ?topological_node .FILTER NOT EXISTS { ?con_node cim:ConnectivityNode.TopologicalNode ?topological_node } ?terminal1 cim:Terminal.TopologicalNode ?topological_node . - Then fetch the node identifier:
?topological_node cim:IdentifiedObject.mRID ?node .
- Either take the ConnectivityNode → TopologicalNode mapping:
-
Optional computed equipment status
OPTIONAL { ?acline ^cim:SvStatus.ConductingEquipment/cim:SvStatus.inService ?in_service }If anSvStatus.inServiceexists for the?acline, capture it.
-
Federated access to the equipment repository
?_eq_subject <http://entsoe.eu/CIM/EquipmentCore/3/1> ?eq_repo .Supplies the endpoint/graph IRI for equipment data.SERVICE ?eq_repo { ... }wraps all equipment‑side lookups:- Identify non‑HVDC AC lines and basic IDs:
?acline a cim:ACLineSegment ; cim:IdentifiedObject.name ?name ; cim:IdentifiedObject.mRID ?mrid . FILTER (!REGEX(?name,'HVDC')) . - Optionally pull a market code via the equipment container chain:
OPTIONAL { ?acline cim:Equipment.EquipmentContainer/SN:Line.marketCode ?market_code . } - Bind each terminal to the line and its sequence numbers:
?terminal1 … sequenceNumber 1 ; Terminal.ConnectivityNode ?con_node .?terminal2 … sequenceNumber 2 ; Terminal.ConnectivityNode/(…)/IdentifiedObject.name ?area_2 .
- Resolve region names for each terminal by traversing:
producingConnectivityNode → ConnectivityNodeContainer → VoltageLevel → Substation → Region → SubGeographicalRegion.Region → IdentifiedObject.name?area_1(via?con_node) and?area_2(via?terminal2’s node). - Region boundary filter (intent): keep only lines where exactly one terminal is in
${region}:(REGEX(?area_1,'${region}') && !REGEX(?area_2,'${region}')) || (REGEX(?area_2,'${region}') && !REGEX(?area_1,'${region}'))Note: the code’s second disjunct repeats
?area_1; per the comment it should symmetrically test?area_2—adjust if needed. - Optionally read an analysis toggle and default it:
So equipment lacking the flag is included; explicitlyOPTIONAL { ?acline SN:Equipment.networkAnalysisEnable ?_analysis_enabled . } BIND (COALESCE(?_analysis_enabled, True) AS ?analysis_enabled) FILTER (?analysis_enabled)falseis excluded.
- Identify non‑HVDC AC lines and basic IDs:
-
Compute an overall status
BIND (COALESCE(?in_service, ?connected_1 && ?connected_2) AS ?status)Prefer the equipment’sinService; if absent, require both terminals connected.
-
Projection
- Returns:
?name— AC line name?node— mRID of the associated TopologicalNode?mrid— ACLineSegment mRID?status— overall availability (computed)?p— active power flow at terminal 1?market_code— optional market classification
- Returns:
Net effect: for a template variable ${region}, the query lists cross‑boundary AC lines (non‑HVDC) that connect the region to elsewhere, including their flow, IDs, market code, and a status derived from either explicit inService or both‑ends connectivity.
Original SPARQL
# Name: Exchange
PREFIX cim: <http://iec.ch/TC57/2013/CIM-schema-cim16#>
PREFIX SN: <http://www.statnett.no/CIM-schema-cim15-extension#>
SELECT ?name ?node ?mrid ?status ?p ?market_code WHERE {
?terminal1 ^cim:SvPowerFlow.Terminal/cim:SvPowerFlow.p ?p ;
cim:ACDCTerminal.connected ?connected_1 .
?terminal2 cim:ACDCTerminal.connected ?connected_2 .
{
?con_node cim:ConnectivityNode.TopologicalNode ?topological_node .
}
UNION {
FILTER NOT EXISTS {
?con_node cim:ConnectivityNode.TopologicalNode ?topological_node
}
?terminal1 cim:Terminal.TopologicalNode ?topological_node .
}
?topological_node cim:IdentifiedObject.mRID ?node .
# Extract a connection flag that is composed of the inService flag for all conducting equipment connected
# to an acline.
OPTIONAL {
?acline ^cim:SvStatus.ConductingEquipment/cim:SvStatus.inService ?in_service
} .
?_eq_subject <http://entsoe.eu/CIM/EquipmentCore/3/1> ?eq_repo .
SERVICE ?eq_repo {
# Extract name and mrid for aclines
?acline a cim:ACLineSegment ;
cim:IdentifiedObject.name ?name ;
cim:IdentifiedObject.mRID ?mrid .
FILTER (!REGEX(?name,'HVDC')) .
OPTIONAL {
?acline cim:Equipment.EquipmentContainer/SN:Line.marketCode ?market_code .
}
# Extract properties for the terminal at sequenceNumber 1 for the acline
?terminal1 cim:Terminal.ConductingEquipment ?acline ;
cim:ACDCTerminal.sequenceNumber 1 ;
cim:Terminal.ConnectivityNode ?con_node .
# Extract from the connectivity node of terminal1
?con_node cim:ConnectivityNode.ConnectivityNodeContainer/cim:VoltageLevel.Substation/cim:Substation.Region/cim:SubGeographicalRegion.Region/cim:IdentifiedObject.name ?area_1 .
# Extract propertoes for the terminal at squenceNumber 2 for the acline
?terminal2 cim:Terminal.ConductingEquipment ?acline ;
cim:ACDCTerminal.sequenceNumber 2 ;
cim:Terminal.ConnectivityNode/cim:ConnectivityNode.ConnectivityNodeContainer/cim:VoltageLevel.Substation/cim:Substation.Region/cim:SubGeographicalRegion.Region/cim:IdentifiedObject.name ?area_2 .
# When a region is provided: only keep results that satisfy either
# 1) area_1 = region and area_2 != region
# 2) area_2 = region and area_1 != region
FILTER ((REGEX(?area_1,'${region}') && !REGEX(?area_2,'${region}')) || (REGEX(?area_1,'${region}') && !REGEX(?area_2,'${region}')))
OPTIONAL {
?acline SN:Equipment.networkAnalysisEnable ?_analysis_enabled .
}
}
BIND (COALESCE(?_analysis_enabled, True) AS ?analysis_enabled)
FILTER (?analysis_enabled)
# Assign an overall status. The status is derived from the first existing entry of
# 1) The computed in_service flag for each acline
# 2) The connected status for the terminals. If one of the terminals is off, the status is False
BIND (COALESCE(?in_service, ?connected_1 && ?connected_2) AS ?status)
}
Query Rationalization
- This query is "written backwards": first some terminals and connectivityNodes are picked, then they are related to ACLineSegments. That makes it hard to read, and likely inefficient. Perhaps this was dictated by the need for federated SERVICE; we don't have such a requirement so we write it in a more logical order
- We simplify
FILTER (?analysis_enabled)toFILTER NOT EXISTS {?acline cim:Equipment.networkAnalysisEnabled false}taking into account that the default value istrue - Use the Double OPTIONAL trick to find
?topological_node
Fixed SPARQL
PREFIX cim: <https://cim.ucaiug.io/ns#>
SELECT ?name ?node ?mrid ?status ?p ?area_1 ?area_2 WHERE {
# Extract name and mrid for aclines
?acline a cim:ACLineSegment ;
cim:IdentifiedObject.name ?name ;
cim:IdentifiedObject.mRID ?mrid .
FILTER (!REGEX(?name,'HVDC'))
FILTER NOT EXISTS {?acline cim:Equipment.networkAnalysisEnabled false}
# Extract a connection flag that is composed of the inService flag for all conducting equipment connected to an acline.
OPTIONAL {?acline ^cim:SvStatus.ConductingEquipment/cim:SvStatus.inService ?in_service}
# Extract properties for the terminal at sequenceNumber 1 for the acline
?terminal1 cim:Terminal.ConductingEquipment ?acline ;
cim:ACDCTerminal.sequenceNumber 1 ;
cim:Terminal.ConnectivityNode ?con_node ;
^cim:SvPowerFlow.Terminal/cim:SvPowerFlow.p ?p ;
cim:ACDCTerminal.connected ?connected_1 .
# Extract from the connectivity node of terminal1
?con_node cim:ConnectivityNode.ConnectivityNodeContainer/cim:VoltageLevel.Substation/cim:Substation.Region/cim:IdentifiedObject.name ?area_1 .
# Extract properties for the terminal at sequenceNumber 2 for the acline
?terminal2 cim:Terminal.ConductingEquipment ?acline ;
cim:ACDCTerminal.sequenceNumber 2 ;
cim:ACDCTerminal.connected ?connected_2 ;
cim:Terminal.ConnectivityNode/cim:ConnectivityNode.ConnectivityNodeContainer/cim:VoltageLevel.Substation/cim:Substation.Region/cim:IdentifiedObject.name ?area_2 .
# Only keep results that are across areas
FILTER(?area_1 != ?area_2)
# Only keep results in the REGION of interest
# FILTER (REGEX(?area_1,$REGION) || REGEX(?area_2,$REGION))
# Find topological node from terminal1
OPTIONAL {?con_node cim:ConnectivityNode.TopologicalNode ?topological_node. ?topological_node cim:IdentifiedObject.mRID ?node}
OPTIONAL {?terminal1 cim:Terminal.TopologicalNode ?topological_node. ?topological_node cim:IdentifiedObject.mRID ?node}
# Assign an overall status. The status is derived from the first existing entry of
# 1) The computed in_service flag for each acline
# 2) The connected status for the terminals. If one of the terminals is off, the status is False
BIND (COALESCE(?in_service, ?connected_1 && ?connected_2) AS ?status)
}
full_model
Question
Which models are ready to use (i.e., all their dependencies are available), and if not locally, which equipment-profile models can we list directly from the equipment repository—showing each model’s time, profile, version, and description?
TLDR;
Return a unified list of models with their key metadata.
- From the local catalog: include only models whose
md:Model.DependentOnmodels can be found (locally or in the equipment repo). - From the external equipment repo: include all equipment models, filling in missing
profile/versionwith defaults.
Explanation
The query builds a single result set of ?model ?time ?profile ?version ?description using a UNION of two branches:
Branch A — Local models whose dependencies exist
{
?model md:Model.profile ?profile ;
md:Model.scenarioTime ?time ;
md:Model.version ?version ;
md:Model.description ?description .
{
SELECT ?model (MIN(?dependency_exists) AS ?all_dependencies_exist) {
?_eq_subject <http://entsoe.eu/CIM/EquipmentCore/3/1> ?eq_repo .
?model md:Model.DependentOn ?depend_on .
OPTIONAL {
{ ?depend_on md:Model.created ?created } # dependency found locally
UNION
{ SERVICE ?eq_repo { ?depend_on md:Model.created ?created } } # or in the equipment repo
}
BIND (BOUND(?created) AS ?dependency_exists)
}
GROUP BY ?model
}
FILTER (?all_dependencies_exist)
}
What it does:
-
It first binds the equipment repository endpoint/graph IRI to
?eq_repousing the mapping triple?_eq_subject <http://entsoe.eu/CIM/EquipmentCore/3/1> ?eq_repo. This is a pattern used in this dataset to look up the service for the ENTSO-E Equipment profile. -
For each local
?model, it enumerates its dependencies viamd:Model.DependentOn ?depend_on. -
It then tries to resolve each dependency’s creation timestamp (
md:Model.created ?created) either:- locally, or
- remotely via
SERVICE ?eq_repo { ... }to the equipment repository.
-
BOUND(?created)yieldstrueif that dependency can be found,falseotherwise. -
The subselect aggregates with
MIN(?dependency_exists):- In SPARQL,
MIN(false,true,...)isfalseif any dependency is missing; only if all are found does it becometrue.
- In SPARQL,
-
The outer
FILTER (?all_dependencies_exist)keeps only models whose every dependency was resolvable (locally or via the equipment repo). -
For such models, the metadata come from the local graph:
?time=md:Model.scenarioTime?profile,?version,?descriptionfrom the model itself.
Branch B — Equipment repository fallback (complete equipment models)
UNION {
?_eq_subject <http://entsoe.eu/CIM/EquipmentCore/3/1> ?eq_repo .
SERVICE ?eq_repo {
?model md:Model.description ?description ;
md:Model.created ?time .
OPTIONAL { ?model md:Model.profile ?nullable_profile }
OPTIONAL { ?model md:Model.version ?nullable_version }
BIND (COALESCE(?nullable_profile, "http://entsoe.eu/CIM/EquipmentCore/3/1") AS ?profile)
BIND (COALESCE(?nullable_version, "") AS ?version)
}
}
What it does:
-
Queries the external equipment repository directly (again located via the mapping triple).
-
Pulls
?modelalong with:-
?description(required) -
?timefrommd:Model.created(note: this differs from Branch A’sscenarioTime) -
Optional
profileandversion. If absent, they are defaulted:profile→ the Equipment profile IRI (http://entsoe.eu/CIM/EquipmentCore/3/1)version→ empty string""
-
-
This branch ensures you still get equipment models even if you don’t have a complete local roll-up with resolved dependencies.
Combined behavior
-
The
UNIONmerges:- Locally curated, dependency-complete models (with
scenarioTime) - Raw equipment models from the equipment repository (with
createdas the time)
- Locally curated, dependency-complete models (with
-
Output columns are harmonized as
?model ?time ?profile ?version ?description. -
Practical effect: you get a “full model list” view that prioritizes dependency integrity for local models, while still surfacing equipment-layer models directly from their source when needed.
Original SPARQL
# Name: Full model
PREFIX md: <http://iec.ch/TC57/61970-552/ModelDescription/1#>
SELECT ?model ?time ?profile ?version ?description WHERE {
{
?model md:Model.profile ?profile ;
md:Model.scenarioTime ?time ;
md:Model.version ?version ;
md:Model.description ?description .
{
SELECT ?model (MIN(?dependency_exists) AS ?all_dependencies_exist) {
?_eq_subject <http://entsoe.eu/CIM/EquipmentCore/3/1> ?eq_repo .
?model md:Model.DependentOn ?depend_on .
# Extract created time from both tp/sv/ssh profile and eq.
OPTIONAL {
{
?depend_on md:Model.created ?created
}
UNION {
SERVICE ?eq_repo {
?depend_on md:Model.created ?created
}
}
}
BIND (BOUND(?created) AS ?dependency_exists)
}
GROUP BY ?model
}
FILTER (?all_dependencies_exist)
}
UNION {
?_eq_subject <http://entsoe.eu/CIM/EquipmentCore/3/1> ?eq_repo .
SERVICE ?eq_repo {
?model md:Model.description ?description ;
md:Model.created ?time .
OPTIONAL {
?model md:Model.profile ?nullable_profile
}
OPTIONAL {
?model md:Model.version ?nullable_version
}
BIND (COALESCE(?nullable_profile, "http://entsoe.eu/CIM/EquipmentCore/3/1") AS ?profile)
BIND (COALESCE(?nullable_version, "") AS ?version)
}
}
}
Query Rationalization
We use a new representation of models:
- The old CIM represents models using custom namespaces
md, dm - The new CIM represents models using DCAT: specifically namespaces
dct, dcat, dcat-cim, prov - Inst4CIM-KG # Fix Model Representation describes the new representation in detail
- The SPARQL Update fix-model.ru implements the transformation
In addition to refactoring the query to the new representation, we do this:
- Simplify the complex
?all_dependencies_existwith a doublefilter not exists: the first one checks for a link to?depend_on, the second one checks for appropriate type of that node.- In other words, we check there are no dangling
dct:requireslinks that have no triples
- In other words, we check there are no dangling
- Remove the second clause that looks in the
?eq_repo"model registry" since we don't have such - Use DISTINCT on
dct:temporal/dcat:startDate: due to bug Talk2PowerSystem_PM#257, there are double blank nodes fordct:temporal - Only a quarter of models have
?version, so use OPTIONAL - A couple models have bilingual descriptions, so use
filter(lang(?description)!="no") - Note: some models have several values for
?profile, but that's fine
Fixed SPARQL
PREFIX dct: <http://purl.org/dc/terms/>
PREFIX dcat: <http://www.w3.org/ns/dcat#>
SELECT ?model ?time ?profile ?version ?description WHERE {
?model a dcat:Dataset; dct:conformsTo ?profile.
?model dct:description ?description filter(lang(?description)!="no")
optional {?model dcat:version ?version}
{select distinct * {?model a dcat:Dataset; dct:temporal/dcat:startDate ?time}}
filter not exists {
?model dct:requires ?depend_on.
filter not exists {?depend_on a dcat:Dataset}
}
}
gen_unit_and_sync_machine_mapping
Question
How can I retrieve the mapping between a generating unit's mRID and its corresponding synchronous machine's mRID?
TLDR;
This query returns pairs of mRIDs linking each synchronous machine to the generating unit it belongs to.
Explanation
The query uses the CIM ontology to connect a GeneratingUnit to its physical representation, a SynchronousMachine, via their mRID values.
-
Prefixes The
PREFIX cim: <http://iec.ch/TC57/2013/CIM-schema-cim16#>declares the CIM namespace, so CIM classes and properties can be referenced without the full URI. -
Variables Selected
?gen_unit_mrid: the mRID (unique identifier) of the generating unit.?sync_machine_mrid: the mRID of the synchronous machine (physical equipment) associated with that generating unit.
-
Triple Patterns
?s cim:SynchronousMachine.GeneratingUnit/cim:IdentifiedObject.mRID ?gen_unit_mridThis uses property path notation (/) to traverse from a synchronous machine (?s), through itsGeneratingUnitassociation, and then to the generating unit'smRID.?s cim:IdentifiedObject.mRID ?sync_machine_mridRetrieves the mRID of the synchronous machine itself.
-
How It Works The variable
?srepresents a synchronous machine.- First path: follow
cim:SynchronousMachine.GeneratingUnitto find the generating unit linked to?s, then get that generating unit'smRID. - Second triple: directly retrieve the synchronous machine's own
mRID. The result is a table where each row shows a generating unit mRID and the mRID of its associated synchronous machine.
- First path: follow
Effectively, this query creates a logical link between the conceptual generating unit and the physical synchronous machine it is implemented by, using their CIM-defined relationships.
Original SPARQL
# Name: GeneratingUnit mrid to physical equipment mrid
PREFIX cim: <http://iec.ch/TC57/2013/CIM-schema-cim16#>
SELECT ?gen_unit_mrid ?sync_machine_mrid WHERE {
?s cim:SynchronousMachine.GeneratingUnit/cim:IdentifiedObject.mRID ?gen_unit_mrid ;
cim:IdentifiedObject.mRID ?sync_machine_mrid
}
Fixed SPARQL
PREFIX cim: <https://cim.ucaiug.io/ns#>
SELECT ?gen_unit_mrid ?sync_machine_mrid WHERE {
?s a cim:SynchronousMachine; cim:IdentifiedObject.mRID ?sync_machine_mrid;
cim:RotatingMachine.GeneratingUnit/cim:IdentifiedObject.mRID ?gen_unit_mrid
}
hvdc
Question
Which pairs of Voltage Source Converters (VSCs) are connected by a DC line made of multiple segments, and what are the segment names and the total line resistance between them?
TLDR;
Finds VSC–VSC pairs linked by the same DC line segment(s) at terminal sequence ends 1 and 2, keeps only pairs with more than one matching segment, concatenates segment names, and sums their resistances.
Explanation
Prefixes
cim:andALG:provide access to CIM and an extension namespace (Alstom) used for DC equipment.xsd:is used to coerce numeric values.
Core resources
ALG:VoltageSourceConverter— the two end converters, bound as?converter_1and?converter_2.ALG:DCLineSegment— individual DC line segments forming the link between the converters, bound as?line.
SELECT clause
?converter_mrid_1,?converter_mrid_2— the mRIDs of the two VSCs.(GROUP_CONCAT(?name; SEPARATOR="--") AS ?name)— concatenates the names of all matching DC line segments between the pair, joined by--.(SUM(xsd:float(STR(?r))) AS ?r)— sums the (string-to-float coerced) resistances of those segments to get the total resistance.
How the topology match works
-
Two converters are identified:
?converter_1 a ALG:VoltageSourceConverter ; cim:IdentifiedObject.mRID ?converter_mrid_1 . ?converter_2 a ALG:VoltageSourceConverter ; cim:IdentifiedObject.mRID ?converter_mrid_2 . -
Two terminals on the same DC line segment
?lineare matched, each at a specific end by sequence number:?t_1is a terminal on?linewithcim:ACDCTerminal.sequenceNumber 1.?t_2is a terminal on the same?linewithcim:ACDCTerminal.sequenceNumber 2.
-
Each terminal is required to share a ConnectivityNode with a terminal of one of the converters:
?t_1 cim:Terminal.ConnectivityNode/^cim:Terminal.ConnectivityNode/cim:Terminal.ConductingEquipment ?converter_1 ; cim:Terminal.ConductingEquipment ?line ; cim:ACDCTerminal.sequenceNumber 1 . ?t_2 cim:Terminal.ConnectivityNode/^cim:Terminal.ConnectivityNode/cim:Terminal.ConductingEquipment ?converter_2 ; cim:Terminal.ConductingEquipment ?line ; cim:ACDCTerminal.sequenceNumber 2 .The path
cim:Terminal.ConnectivityNode/^cim:Terminal.ConnectivityNode/cim:Terminal.ConductingEquipment ?converter_Xmeans:- From the line terminal (
?t_1/?t_2), go to itsConnectivityNode. - Inverse (
^) back out to any terminal at that same node. - From that terminal, go to its
ConductingEquipmentand require that to be the respective converter. This ensures the line terminal is electrically connected to the converter via the same node (i.e., they meet at the node).
- From the line terminal (
-
The DC line segment resource itself is constrained and annotated:
?line a ALG:DCLineSegment ; ALG:DCLineSegment.dcSegmentResistance ?r ; cim:IdentifiedObject.name ?name .
Aggregation and filtering
GROUP BY ?converter_mrid_1 ?converter_mrid_2groups all segments that connect the same ordered converter pair (end 1 → end 2).HAVING (COUNT(*) > 1)keeps only those converter pairs that are connected by more than one matching line segment — i.e., multi‑segment DC connections.- Within each group,
GROUP_CONCATbuilds a readable list of segment names andSUMaccumulates the segment resistances to obtain the total line resistance between the two converters.
Result semantics
Each output row represents a pair of VSC endpoints (?converter_mrid_1, ?converter_mrid_2) connected through a DC line composed of at least two segments. The ?name field lists those segment names (joined by --), and ?r is the numeric sum of their resistances.
Original SPARQL
# Name: HVDC
PREFIX cim: <http://iec.ch/TC57/2013/CIM-schema-cim16#>
PREFIX ALG: <http://www.alstom.com/grid/CIM-schema-cim15-extension#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
SELECT ?converter_mrid_1 ?converter_mrid_2 (GROUP_CONCAT(?name; SEPARATOR="--") AS ?name) (SUM(xsd:float(STR(?r))) AS ?r) WHERE {
?converter_1 a ALG:VoltageSourceConverter ;
cim:IdentifiedObject.mRID ?converter_mrid_1 .
?converter_2 a ALG:VoltageSourceConverter ;
cim:IdentifiedObject.mRID ?converter_mrid_2 .
?t_1 cim:Terminal.ConnectivityNode/^cim:Terminal.ConnectivityNode/cim:Terminal.ConductingEquipment ?converter_1 ;
cim:Terminal.ConductingEquipment ?line ;
cim:ACDCTerminal.sequenceNumber 1 .
?t_2 cim:Terminal.ConnectivityNode/^cim:Terminal.ConnectivityNode/cim:Terminal.ConductingEquipment ?converter_2 ;
cim:Terminal.ConductingEquipment ?line ;
cim:ACDCTerminal.sequenceNumber 2 .
?line a ALG:DCLineSegment ;
ALG:DCLineSegment.dcSegmentResistance ?r ;
cim:IdentifiedObject.name ?name .
}
GROUP BY ?converter_mrid_1 ?converter_mrid_2
HAVING (COUNT(*) > 1)
We have no such data
loads
Question
Which loads (Conform, NonConform, and generic EnergyConsumers) in a given region are enabled for network analysis, what are their identifiers, names, substations, connectivity nodes, current status (in-service/connected), and their latest active/reactive power flows, along with any market station group?
TLDR;
Fetch all enabled loads in the specified ${region}, get their mRID, name, substation mRID, connectivity node mRID, status (in-service or, if missing, terminal-connected), real/reactive power (p/q) from SvPowerFlow, and optional market/station group.
Explanation
This query assembles per-load operational info by joining equipment, topology, status, and state-variable data—scoped to a specific region—while default-enforcing that loads must be network-analysis enabled.
1) Federated equipment lookup (subquery + SERVICE)
- The outer pattern wraps an inner
SELECT *subquery to speed execution. - It first finds an equipment repository graph IRI via:
?_eq_subject <http://entsoe.eu/CIM/EquipmentCore/3/1 ?eq_repo .
and then issues a federated SERVICE ?eq_repo { ... } call so that all equipment lookups run against that repository endpoint/graph.
2) Select load types and core load attributes
- Restricts to three load classes:
VALUES ?load_type { cim:ConformLoad cim:NonConformLoad cim:EnergyConsumer }
- For each
?load a ?load_type, it extracts: cim:IdentifiedObject.mRID→?mridcim:IdentifiedObject.name→?name- Its container substation via
cim:Equipment.EquipmentContainer / cim:VoltageLevel.Substation→?substation
3) Region scoping and substation identity
- From each
?substation, it walks up the geography:
cim\:Substation.Region / cim\:SubGeographicalRegion.Region / cim\:IdentifiedObject.name ?area
- Keeps only substations whose
?areamatches the${region}regex:
FILTER REGEX(?area,'\${region}')
- Captures the substation’s
mRIDas?substation_mrid.
4) Optional market/station grouping
- If present, pulls a market “station group” from a statnett extension path:
?load cim\:NonConformLoad.LoadGroup /
SN\:NonConformLoadGroup.ScheduleResource /
SN\:ScheduleResource.marketCode ?station\_group
(Optional: not all loads or load types will have it.)
5) Network-analysis enable flag with defaulting
- Optionally reads
SN:Equipment.networkAnalysisEnableinto?_network_analysis. - Uses
BIND (COALESCE(?_network_analysis, True) AS ?network_analysis)so the default isTruewhen the flag is absent. - Filters to only enabled loads:
FILTER (?network_analysis).
6) Terminal and connectivity mapping
- Still inside the SERVICE block, it maps each load to its terminals and connectivity nodes:
?terminal cim\:Terminal.ConductingEquipment ?load ;
cim\:Terminal.ConnectivityNode ?con\_node .
?con\_node cim\:IdentifiedObject.mRID ?connectivity\_node .
- The query returns one row per (load × terminal), preserving
?terminalfor later joins.
7) Outside SERVICE: operational status and power flows
- Gets the terminal’s switch-level connection flag:
?terminal cim\:ACDCTerminal.connected ?connected .
- Optionally retrieves equipment-level service status via
SvStatus:
OPTIONAL { ?load ^cim\:SvStatus.ConductingEquipment / cim\:SvStatus.inService ?in\_service }
- Pulls steady-state power flow linked to the terminal:
?sv\_power\_flow cim\:SvPowerFlow\.Terminal ?terminal ;
cim\:SvPowerFlow\.p ?p ;
cim\:SvPowerFlow\.q ?q .
8) Status resolution (in-service vs connected)
- Final status is chosen by precedence:
BIND (COALESCE(?in\_service, ?connected) AS ?status)
meaning: use in_service if available; otherwise fall back to the terminal’s connected flag.
9) Result set
- The
SELECTprojects: ?mrid,?name: load identity?substation_mrid: parent substation identifier?status: resolved operational status?p,?q: active/reactive power fromSvPowerFlow?station_group: optional market grouping?connectivity_node: terminal’s connectivity node mRID- Due to terminal joins, loads with multiple terminals will yield multiple rows (one per terminal).
Key behaviors & nuances
- Region filter:
${region}is a parameter placeholder; the regex allows partial or case-sensitive matches depending on the engine’s defaults. Adjust the pattern for anchoring or case-insensitivity if needed (e.g.,"(?i)^Nordics$"). - Enablement default: Missing
SN:Equipment.networkAnalysisEnableevaluates as enabled (True), ensuring broad inclusion unless explicitly disabled. - Status precedence:
in_serviceoverridesconnectedwhen both exist, offering a higher-level operational view if available.
Original SPARQL
# Name: Loads
PREFIX cim: <http://iec.ch/TC57/2013/CIM-schema-cim16#>
PREFIX SN: <http://www.statnett.no/CIM-schema-cim15-extension#>
SELECT ?mrid ?name ?substation_mrid ?status ?p ?q ?station_group ?connectivity_node WHERE {
{
# Appears to be significantly faster to run the query if the EQ part is executed within its own sub-query
SELECT * WHERE {
?_eq_subject <http://entsoe.eu/CIM/EquipmentCore/3/1> ?eq_repo .
SERVICE ?eq_repo {
# Extract mRID, name and substation for each load
VALUES ?load_type { cim:ConformLoad cim:NonConformLoad cim:EnergyConsumer }
?load a ?load_type ;
cim:IdentifiedObject.mRID ?mrid ;
cim:IdentifiedObject.name ?name ;
cim:Equipment.EquipmentContainer/cim:VoltageLevel.Substation ?substation .
# Extract area and mRID (referred to as 'station') for the substation of each load
?substation cim:Substation.Region/cim:SubGeographicalRegion.Region/cim:IdentifiedObject.name ?area ;
cim:IdentifiedObject.mRID ?substation_mrid .
FILTER REGEX(?area,'${region}')
OPTIONAL {
?load cim:NonConformLoad.LoadGroup/SN:NonConformLoadGroup.ScheduleResource/SN:ScheduleResource.marketCode ?station_group
} .
OPTIONAL {
?load SN:Equipment.networkAnalysisEnable ?_network_analysis
} .
BIND (COALESCE(?_network_analysis, True) AS ?network_analysis)
FILTER (?network_analysis)
# Extract mRID and connectivity node for each terminal associated with a load
?terminal cim:Terminal.ConductingEquipment ?load ;
cim:Terminal.ConnectivityNode ?con_node .
?con_node cim:IdentifiedObject.mRID ?connectivity_node .
} .
}
}
# Extrcact connected flag and optionally the mRID of the topological node associated with the terminal
?terminal cim:ACDCTerminal.connected ?connected .
# Optionally extract in_service flag and active and reactive energy consumption for each load
OPTIONAL {
?load ^cim:SvStatus.ConductingEquipment/cim:SvStatus.inService ?in_service
} .
?sv_power_flow cim:SvPowerFlow.Terminal ?terminal ;
cim:SvPowerFlow.p ?p ;
cim:SvPowerFlow.q ?q .
# Assign status flag for load. The status flag is set to the first existing of
# 1) in_service flag
# 2) connected flag the terminal
BIND (COALESCE(?in_service, ?connected) AS ?status)
}
Query Rationalization
- remove
cim:SubGeographicalRegion.Regionsince all are "NO" - simplified the filter
cim:Equipment.networkAnalysisEnabled false - there is prop
cim:NonConformLoadGroup.NonConformLoadSchedulesbut we don't have such data, and it doesn't havemarkeCode
Fixed SPARQL
PREFIX cim: <https://cim.ucaiug.io/ns#>
SELECT ?area ?mrid ?name ?substation_mrid ?status ?p ?q ?connectivity_node ?schedule WHERE {
# Extract mRID, name and substation for each load
VALUES ?load_type { cim:ConformLoad cim:NonConformLoad cim:EnergyConsumer }
?load a ?load_type ;
cim:IdentifiedObject.mRID ?mrid ;
cim:IdentifiedObject.name ?name ;
cim:Equipment.EquipmentContainer/cim:VoltageLevel.Substation ?substation .
filter not exists {?load cim:Equipment.networkAnalysisEnabled false}
# Extract area and mRID (referred to as 'station') for the substation of each load
?substation cim:Substation.Region/cim:IdentifiedObject.name ?area ;
cim:IdentifiedObject.mRID ?substation_mrid .
# FILTER REGEX(?area,$REGION)
OPTIONAL {?load cim:NonConformLoad.LoadGroup/cim:NonConformLoadGroup.NonConformLoadSchedules ?schedule}
# Extract mRID and connectivity node for each terminal associated with a load
?terminal cim:Terminal.ConductingEquipment ?load ;
cim:Terminal.ConnectivityNode ?con_node .
?con_node cim:IdentifiedObject.mRID ?connectivity_node .
# Extract connected flag and optionally the mRID of the topological node associated with the terminal
?terminal cim:ACDCTerminal.connected ?connected .
# Optionally extract in_service flag and active and reactive energy consumption for each load
OPTIONAL {?load ^cim:SvStatus.ConductingEquipment/cim:SvStatus.inService ?in_service}
?sv_power_flow cim:SvPowerFlow.Terminal ?terminal ;
cim:SvPowerFlow.p ?p ;
cim:SvPowerFlow.q ?q .
# Assign status flag for load. The status flag is set to the first existing of
# 1) in_service flag
# 2) connected flag the terminal
BIND (COALESCE(?in_service, ?connected) AS ?status)
}
market_dates
Question
What are the IDs, names, and activation dates of all market definition sets?
TLDR;
This query retrieves each market definition set’s unique identifier (mRID), its name, and the date it was activated.
Explanation
The query is written in SPARQL and uses two namespaces:
cim:for the standard CIM (Common Information Model) schema.SN:for Statnett’s CIM extension schema.
The WHERE clause specifies:
?_set a SN:MarketDefinitionSet— Finds all resources that are of typeSN:MarketDefinitionSet. This means the subject represents a market definition set entity.cim:IdentifiedObject.mRID ?mrid— Retrieves the unique identifier (mRID) for each market definition set.cim:IdentifiedObject.name ?name— Retrieves the human-readable name of the set.SN:MarketDefinitionSet.activationDate ?activation_date— Retrieves the date the set was activated.
The SELECT clause returns the three variables:
?mrid— unique identifier.?name— descriptive name.?activation_date— the activation date.
Effectively, this query lists all market definition sets along with their ID, name, and when they took effect.
Original SPARQL
# Name: Market dates
PREFIX cim: <http://iec.ch/TC57/2013/CIM-schema-cim16#>
PREFIX SN: <http://www.statnett.no/CIM-schema-cim15-extension#>
SELECT ?mrid ?name ?activation_date WHERE {
?_set a SN:MarketDefinitionSet ;
cim:IdentifiedObject.mRID ?mrid ;
cim:IdentifiedObject.name ?name ;
SN:MarketDefinitionSet.activationDate ?activation_date
}
phase_tap_changer
Question
Which phase tap changers (linear) are in the model, and for each, what are its phase‑shift increment, step limits (low/high/neutral), regulating control mode and target value, the monitored winding mRID, and whether the overall control is enabled?
TLDR;
Federates to the equipment repository, finds each PhaseTapChangerLinear, pulls its step settings and associated RegulatingControl, resolves the monitored winding, normalizes the control mode label, and reports a single enabled flag that is true only if both the tap changer and its regulating control are enabled.
Explanation
- Setup & inputs
The query uses
PREFIX cim:for the IEC CIM namespace. It expects a link to an equipment repository endpoint via:
?\_eq\_subject [http://entsoe.eu/CIM/EquipmentCore/3/1](http://entsoe.eu/CIM/EquipmentCore/3/1) ?eq\_repo .
The discovered IRI in ?eq_repo is then used as a SPARQL federation endpoint inside a SERVICE ?eq_repo { ... } clause.
- Top‑level control flags (outside SERVICE) Before federating, two booleans are read:
?tap_changer cim:TapChanger.controlEnabled ?enabled_1 .?tap_changer_control cim:RegulatingControl.enabled ?enabled_2 ; cim:RegulatingControl.targetValue ?target_value .
At the end, BIND (?enabled_1 && ?enabled_2 AS ?enabled) combines them so ?enabled is true only when both the physical tap changer and the regulating control are enabled.
-
Federated retrieval of device details (inside SERVICE) Within
SERVICE ?eq_repo { ... }, the query gathers the phase tap changer’s characteristics and relationships: -
?tap_changer cim:PhaseTapChangerLinear.stepPhaseShiftIncrement ?phase_shift_increment ;- Using the
PhaseTapChangerLinear.stepPhaseShiftIncrementproperty effectively scopes results to linear phase tap changers.
- Using the
-
cim:TapChanger.TapChangerControl ?tap_changer_control ;- Associates the device with its
RegulatingControl.
- Associates the device with its
-
Step limits:
cim:TapChanger.neutralStep ?neutral_step ;cim:TapChanger.highStep ?high_step ;cim:TapChanger.lowStep ?low_step ;
-
Related winding via inverse path:
^cim:TransformerEnd.PhaseTapChanger ?winding .- This walks from a
TransformerEndthat has this phase tap changer to the tap changer itself (the caret^means inverse), yielding the transformer end (?winding) the changer acts on.
-
The winding’s identifier:
?winding cim:IdentifiedObject.mRID ?mrid .
-
Regulating control metadata and the monitored winding:
?tap_changer_control cim:RegulatingControl.mode ?control_mode ;cim:RegulatingControl.Terminal/^cim:TransformerEnd.Terminal/cim:IdentifiedObject.mRID ?monitored_winding .- This path goes from the control’s
Terminalto theTransformerEndattached to that terminal (again using^for the inverse ofTransformerEnd.Terminal), then reads that end’smRID. This is the winding being monitored by the control loop (which may differ from the winding the tap changer is physically on).
- This path goes from the control’s
-
Post‑processing / normalization
-
BIND (replace(STR(?control_mode), STR(cim:), "") AS ?mode)strips the CIM namespace from theRegulatingControl.modeIRI, leaving just the local token (e.g.,voltage,activePower, etc.) in?mode. -
Projection The
SELECTreturns, per tap changer: -
?mrid— mRID of the transformer end the changer is on -
?phase_shift_increment— linear phase shift per step -
?enabled— combined enablement of device and control -
?neutral_step,?high_step,?low_step— step configuration -
?mode— normalized control mode (local name) -
?target_value— setpoint fromRegulatingControl.targetValue -
?monitored_winding— mRID of the transformer end the control monitors
In short, the query cross‑links equipment and control domains to present a compact, operational snapshot of each PhaseTapChangerLinear: how it steps, what it targets, which winding it monitors, and whether it’s actually active.
Original SPARQL
# Name: Phase tap changer
PREFIX cim: <http://iec.ch/TC57/2013/CIM-schema-cim16#>
SELECT ?mrid ?phase_shift_increment ?enabled ?neutral_step ?high_step ?low_step ?mode ?target_value ?monitored_winding WHERE {
?tap_changer cim:TapChanger.controlEnabled ?enabled_1 .
?tap_changer_control cim:RegulatingControl.enabled ?enabled_2 ;
cim:RegulatingControl.targetValue ?target_value .
?_eq_subject <http://entsoe.eu/CIM/EquipmentCore/3/1> ?eq_repo .
SERVICE ?eq_repo {
?tap_changer cim:PhaseTapChangerLinear.stepPhaseShiftIncrement ?phase_shift_increment ;
cim:TapChanger.TapChangerControl ?tap_changer_control ;
cim:TapChanger.neutralStep ?neutral_step ;
cim:TapChanger.highStep ?high_step ;
cim:TapChanger.lowStep ?low_step ;
^cim:TransformerEnd.PhaseTapChanger ?winding .
?winding cim:IdentifiedObject.mRID ?mrid .
?tap_changer_control cim:RegulatingControl.mode ?control_mode ;
cim:RegulatingControl.Terminal/^cim:TransformerEnd.Terminal/cim:IdentifiedObject.mRID ?monitored_winding .
}
BIND (replace(STR(?control_mode), STR(cim:), "") AS ?mode)
BIND (?enabled_1 && ?enabled_2 AS ?enabled)
}
power_flow
Question
What are the active (P) and reactive (Q) power flows at each terminal, along with the terminal’s mRID and whether its associated equipment is considered in service?
TLDR;
Pulls P and Q from SvPowerFlow per Terminal, fetches the terminal’s mRID from the equipment repository via a SERVICE call, and reports inService status (defaulting to true when missing).
Explanation
This query joins state variables with equipment metadata to present power flow by terminal, annotated with identity and service status.
1) Select state-variable power flows
?_s a cim:SvPowerFlow ;
cim:SvPowerFlow.Terminal ?terminal ;
cim:SvPowerFlow.p ?p ;
cim:SvPowerFlow.q ?q .
-
Restricts to resources of type
cim:SvPowerFlow. -
From each
SvPowerFlow, it extracts:- the associated
?terminal, - the active power
?p(typically MW), - the reactive power
?q(typically MVAr).
- the associated
This frames one row per terminal state-variable entry.
2) Discover the equipment repository and federate to get the terminal mRID
?_eq_subject <http://entsoe.eu/CIM/EquipmentCore/3/1> ?eq_repo .
SERVICE ?eq_repo {
?terminal cim:IdentifiedObject.mRID ?mrid .
}
-
The triple with predicate
<http://entsoe.eu/CIM/EquipmentCore/3/1>provides (or points to) the IRI of the equipment model endpoint in?eq_repo. -
SERVICE ?eq_repo { … }federates a subquery to that endpoint, retrieving thecim:IdentifiedObject.mRIDof each?terminal.- This decouples state (Sv* graphs) from equipment (EQ/core metadata), a common deployment pattern for CIM-based platforms.
3) Resolve the in-service status, defaulting to true
OPTIONAL {
?terminal
cim:Terminal.ConductingEquipment
/^cim:SvStatus.ConductingEquipment
/cim:SvStatus.inService ?_in_service
}
BIND (COALESCE(?_in_service, True) AS ?in_service)
-
The OPTIONAL pattern walks a path to find a corresponding
cim:SvStatusboolean:- From the
?terminalto itscim:Terminal.ConductingEquipment. - Then inverse of
cim:SvStatus.ConductingEquipment(^…) to reach anycim:SvStatuslinked to that equipment. - Finally reads
cim:SvStatus.inServiceinto?_in_service.
- From the
-
If such a status isn’t present,
COALESCEsets?in_servicetoTrue. This ensures every row reports a service flag without needing a separate filter or post-processing.
4) Output
SELECT ?mrid ?p ?q ?in_service
-
For each terminal with a state-variable power flow, returns:
?mrid— the terminal’s identifier from the equipment repository,?p,?q— active/reactive power fromSvPowerFlow,?in_service— boolean service state (true if missing).
Notes & implications
- If multiple
SvStatusinstances exist for the same equipment, the OPTIONAL path could yield multiple rows per terminal unless upstream data is constrained. The query intentionally doesn’t de-duplicate. - Sign conventions for
p/qfollow the CIMSvPowerFlowdefinition (typically positive from the terminal into the equipment/network, depending on the implementation). - The use of
SERVICEmeans execution depends on the availability and authorization of the remote equipment endpoint (?eq_repo).
Original SPARQL
# Name: Power flow
PREFIX cim: <http://iec.ch/TC57/2013/CIM-schema-cim16#>
SELECT ?mrid ?p ?q ?in_service WHERE {
?_s a cim:SvPowerFlow ;
cim:SvPowerFlow.Terminal ?terminal ;
cim:SvPowerFlow.p ?p ;
cim:SvPowerFlow.q ?q .
?_eq_subject <http://entsoe.eu/CIM/EquipmentCore/3/1> ?eq_repo .
SERVICE ?eq_repo {
?terminal cim:IdentifiedObject.mRID ?mrid .
}
OPTIONAL {
?terminal cim:Terminal.ConductingEquipment/^cim:SvStatus.ConductingEquipment/cim:SvStatus.inService ?_in_service
}
BIND (COALESCE(?_in_service, True) AS ?in_service)
}
ras_equipment
Question
Which RAS protective actions reference which pieces of equipment, and what are the mRIDs and names of those protective actions and the mRIDs of the referenced equipment?
TLDR;
For every RAS protective action (?rpact), follow any of three ALG extension properties to a referenced piece of equipment and return: the protective action’s mRID and name, plus the referenced equipment’s mRID.
Explanation
The query inspects relationships defined in the Alstom (ALG) CIM extension to find which equipment a RAS protective action is tied to. It does this with a SPARQL property path that unions three predicates and then drills down to the equipment’s identifier:
alg:ProtectiveActionEquipment.Equipmentalg:ProtectiveActionAdjustmentAC.ConductingEquipmentalg:ProtectiveActionAdjustmentDCController.DCController
The core of the pattern is:
?rpact (P1 | P2 | P3) / cim\:IdentifiedObject.mRID ?equipment\_mrid .
Where P1|P2|P3 is the union of the three ALG predicates above. This means:
- Start at a node
?rpact(a protective action instance, implicitly—because only such nodes will have these ALG properties in the data). - Follow any one of the three ALG properties to reach a target equipment resource (which may be a generic
Equipment, aConductingEquipment, or aDCController). - From that equipment resource, follow
cim:IdentifiedObject.mRIDto extract the equipment’s identifier into?equipment_mrid.
In parallel, the query also binds two attributes directly on the protective action node:
?rpact cim\:IdentifiedObject.mRID ?mrid ;
cim\:IdentifiedObject.name ?name .
So each solution row contains:
?mrid: the protective action’s mRID?name: the protective action’s human-readable name?equipment_mrid: the mRID of the equipment referenced by that protective action via any of the three allowed relationships
Behavioral notes:
- Because of the union, a single protective action that references equipment via multiple of these properties will produce multiple rows (one per referenced equipment).
- The query does not constrain
?rpactby explicit RDF type; the use of the ALG properties effectively scopes matches to protective action-like nodes, assuming predicate domains are respected in the data. - No
DISTINCTis used; if the data contains duplicate links or repeatedmRIDvalues, duplicates may appear in the results.
Original SPARQL
# Name: RAS Equipment
PREFIX cim: <http://iec.ch/TC57/2013/CIM-schema-cim16#>
PREFIX alg: <http://www.alstom.com/grid/CIM-schema-cim15-extension#>
SELECT ?mrid ?equipment_mrid ?name WHERE {
?rpact (alg:ProtectiveActionEquipment.Equipment | alg:ProtectiveActionAdjustmentAC.ConductingEquipment | alg:ProtectiveActionAdjustmentDCController.DCController)/cim:IdentifiedObject.mRID ?equipment_mrid ;
cim:IdentifiedObject.mRID ?mrid ;
cim:IdentifiedObject.name ?name .
}
regions
Question
Which SubGeographicalRegions exist, and what are their identifiers and names, along with (optionally) their short names and aliases, plus the name and alias of their parent GeographicalRegion?
TLDR;
Lists every cim:SubGeographicalRegion with its mRID, own name, optional short/alias names, and the name (and optional alias) of the cim:GeographicalRegion it belongs to.
Explanation
The query targets CIM geography classes using the cim and SN prefixes.
-
Core pattern (required):
?subGeoRegion a cim:SubGeographicalRegion ; ...Binds?subGeoRegionto each instance ofcim:SubGeographicalRegion.cim:IdentifiedObject.mRID ?mridRetrieves the unique identifier (mRID) for each sub‑region.cim:IdentifiedObject.name ?nameRetrieves the human‑readable name of the sub‑region.cim:SubGeographicalRegion.Region ?subgeoregFollows the object property linking a SubGeographicalRegion to its parentGeographicalRegion(bound to?subgeoreg).?subgeoreg cim:IdentifiedObject.name ?regionGets the parent region’s name (required).
-
Optional patterns (may be absent without filtering out the row):
OPTIONAL { ?subGeoRegion SN:IdentifiedObject.shortName ?short_name }If present in the Statnett extension, binds a short name for the sub‑region to?short_name.OPTIONAL { ?subGeoRegion cim:IdentifiedObject.aliasName ?alias_name }If the sub‑region has an alias, binds it to?alias_name.OPTIONAL { ?subgeoreg cim:IdentifiedObject.aliasName ?region_name }If the parent region has an alias, binds it to?region_name.
-
Projection: The
SELECTclause outputs:?mrid— the sub‑region’s unique identifier,?region— the parent region’s name,?short_name— the sub‑region’s optional short name (from the SN extension),?name— the sub‑region’s official name,?alias_name— the sub‑region’s optional alias,?region_name— the parent region’s optional alias.
Because the optional blocks are non‑binding when data is missing, each row is guaranteed to at least include the sub‑region’s mRID, its name, and its parent region’s name. Where alias/short names exist, the corresponding columns are filled; otherwise they remain unbound (typically shown as empty/null in results).
Original SPARQL
# Name: Regions
PREFIX cim: <http://iec.ch/TC57/2013/CIM-schema-cim16#>
PREFIX SN: <http://www.statnett.no/CIM-schema-cim15-extension#>
SELECT ?mrid ?region ?short_name ?name ?alias_name ?region_name WHERE {
?subGeoRegion a cim:SubGeographicalRegion ;
cim:IdentifiedObject.mRID ?mrid ;
cim:IdentifiedObject.name ?name ;
cim:SubGeographicalRegion.Region ?subgeoreg .
OPTIONAL {
?subGeoRegion SN:IdentifiedObject.shortName ?short_name
} .
OPTIONAL {
?subGeoRegion cim:IdentifiedObject.aliasName ?alias_name
} .
?subgeoreg cim:IdentifiedObject.name ?region .
OPTIONAL {
?subgeoreg cim:IdentifiedObject.aliasName ?region_name
}
}
series_compensators
Question
Which SeriesCompensator devices exist in the selected region, what are their key electrical parameters and connectivity, what (converted) current limits do they have, and what are their estimated active power losses at each terminal based on state-estimated terminal powers?
TLDR;
For each two‑terminal cim:SeriesCompensator in the chosen sub‑geographical region, the query gathers IDs, names, base voltage, R/X, terminal connectivity nodes, a boolean status, and an optional MVA rating converted from a named cim:CurrentLimit. It also derives per‑end “loss” values from terminal SvPowerFlow.p. Results are filtered to devices with two distinct connectivity nodes and (intended) network‑analysis enabled.
Explanation
This query is written against a CIM dataset and uses a federated SERVICE to the equipment repository for core equipment/terminal topology, while pulling state variables (Sv*) and limits from the outer graph.
1) Scope & federation
?_eq_subject <http://entsoe.eu/CIM/EquipmentCore/3/1> ?eq_repo .
SERVICE ?eq_repo { ... }
The SERVICE block points to the equipment model endpoint ?eq_repo. Inside it, we fetch series‑compensator master data and topology; outside it, we join state variables (status, power flows) and limits.
2) Selecting series compensators and core attributes
?compensator a cim:SeriesCompensator ;
cim:SeriesCompensator.r ?r ;
cim:SeriesCompensator.x ?x ;
cim:IdentifiedObject.mRID ?mrid ;
cim:IdentifiedObject.name ?name ;
cim:ConductingEquipment.BaseVoltage/cim:BaseVoltage.nominalVoltage ?un ;
^cim:Terminal.ConductingEquipment ?terminal .
This binds each cim:SeriesCompensator and its electrical parameters (r, x), identifiers (mRID, name), base voltage (un), and its terminals.
3) Terminals, connectivity, area filter
?terminal cim:Terminal.ConnectivityNode ?con_node ;
cim:ACDCTerminal.sequenceNumber ?nr .
?con_node cim:ConnectivityNode.ConnectivityNodeContainer/
cim:VoltageLevel.Substation ?substation ;
cim:IdentifiedObject.mRID ?connectivity_node .
?substation cim:Substation.Region/
cim:SubGeographicalRegion.Region/
cim:IdentifiedObject.name ?area .
FILTER (REGEX(?area,'${region}'))
Each terminal is tied to a ConnectivityNode and has a sequence number (nr) expected to be 1 or 2. The query walks up to the parent substation/region and keeps only compensators whose region name matches the ${region} regex parameter.
4) Optional “network analysis enabled”
OPTIONAL { ?compensator SN:Equipment.networkAnalysisEnable ?network_analysis }
This captures a vendor extension flag indicating if the device is enabled for network analysis.
Note: The HAVING clause later references ?analysis_enabled, which doesn’t exist. It should probably use MAX(?network_analysis) instead. As written, the COALESCE(MAX(?analysis_enabled), True) part will always fall back to True, unintentionally ignoring the flag.
5) Optional current limit → converted apparent power rating
OPTIONAL {
?_lim cim:OperationalLimit.OperationalLimitSet/cim:OperationalLimitSet.Equipment ?compensator ;
a cim:CurrentLimit ;
cim:IdentifiedObject.name '${rate}' ;
cim:CurrentLimit.value ?_rate .
BIND (1.7320508075688772 * xsd:double(xsd:string(?un))
* xsd:double(xsd:string(?_rate)) / 1000.0 AS ?rate)
}
If a cim:CurrentLimit exists on the device with the given name ${rate}, it is converted to an MVA‑style rating using √3·U[kV]·I[A]/1000.
6) In‑service status and connectivity
Outside the SERVICE, the query joins state variables and connectivity:
OPTIONAL { ?compensator ^cim:SvStatus.ConductingEquipment/cim:SvStatus.inService ?in_service } .
?terminal cim:ACDCTerminal.connected ?connected .
Later, status is computed as COALESCE(MAX(?in_service), MAX(?connected_1) && MAX(?connected_2)), i.e., use SvStatus.inService if available; otherwise require both terminals to be connected.
7) Terminal power flows and per‑end loss proxies
OPTIONAL { ?terminal ^cim:SvPowerFlow.Terminal/cim:SvPowerFlow.p ?p . }
BIND (IF(?nr = 1, STR(?p), '') AS ?p_1)
BIND (IF(?nr = 2, STR(?p), '') AS ?p_2)
Per terminal, the active power SvPowerFlow.p (in MW) is captured and routed into p_1 or p_2. In the SELECT, the query computes:
(IF(xsd:double(MAX(?p_1)) < xsd:double(MAX(?p_2)),
xsd:double(MAX(?p_1)) + xsd:double(MAX(?p_2)), 0.0) AS ?ploss_1)
(IF(xsd:double(MAX(?p_1)) > xsd:double(MAX(?p_2)),
xsd:double(MAX(?p_1)) + xsd:double(MAX(?p_2)), 0.0) AS ?ploss_2)
Idea: if power magnitudes imply flow from 2→1 (or 1→2), the sum p1 + p2 is treated as a positive “loss” on the receiving end, otherwise 0. This assumes p is signed by terminal orientation and that p1 + p2 ≈ losses.
Caveats:
p_1/p_2are bound as strings (STR(?p)) and aggregated withMAXbefore casting, which is lexicographic and can be brittle if multiplepvalues exist or empty strings appear. A safer pattern is to cast toxsd:doublebefore aggregating and useSUM/SAMPLE.- If either terminal lacks
SvPowerFlow.p, the casts can error; the currentOPTIONAL+ empty string plusMAXmay mask this but is fragile.
8) Per‑terminal routing of other fields
BIND (IF(?nr = 1, ?connected, False) AS ?connected_1)
BIND (IF(?nr = 2, ?connected, False) AS ?connected_2)
BIND (IF(?nr = 1, ?connectivity_node, '') AS ?connectivity_node_1)
BIND (IF(?nr = 2, ?connectivity_node, '') AS ?connectivity_node_2)
These create per‑end variables (connectivity flags and node mRIDs) so they can be aggregated later.
9) Aggregation & output columns
The SELECT uses MAX(...) to collapse per‑device fields:
?mrid,?name,?r,?x,?un,?rate— single‑valued by design,MAXjust picks one.?connectivity_node_1,?connectivity_node_2— per‑end node IDs.?status— as described above.?ploss_1,?ploss_2— derived “loss” proxies per end.
Grouping is by ?compensator:
GROUP BY ?compensator
10) Quality filters in HAVING
HAVING (
(COUNT(*) > 1) # at least two terminal rows
&& (MAX(?connectivity_node_1) != MAX(?connectivity_node_2)) # two distinct nodes
&& COALESCE(MAX(?analysis_enabled), True) # intended: network analysis enabled
)
- Ensures we only keep two‑terminal devices with distinct nodes.
- Bug alert:
?analysis_enabledisn’t defined; should be?network_analysis. As written, this condition always evaluates toTrue, so the flag is effectively ignored.
11) Practical notes / potential fixes
-
Fix the flag variable: change
?analysis_enabled→?network_analysisinHAVING. -
Safer power handling: bind numeric values directly, e.g.
OPTIONAL { ?terminal ^cim:SvPowerFlow.Terminal/cim:SvPowerFlow.p ?p . } BIND (IF(?nr=1, xsd:double(?p), 0.0) AS ?p1_num) BIND (IF(?nr=2, xsd:double(?p), 0.0) AS ?p2_num)then use
SUM(?p1_num)/SUM(?p2_num)orMAXon numeric variables, avoiding string casts and empty strings. -
Ratings by name: the limit is selected by
cim:IdentifiedObject.name '${rate}'. Ensure the${rate}parameter matches the naming convention in your data (e.g., “Continuous”, “Summer”, etc.).
Original SPARQL
# Name: Series compensators
PREFIX cim: <http://iec.ch/TC57/2013/CIM-schema-cim16#>
PREFIX SN: <http://www.statnett.no/CIM-schema-cim15-extension#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
SELECT (MAX(?mrid) AS ?mrid) (MAX(?name) AS ?name) (IF(xsd:double(MAX(?p_1)) < xsd:double(MAX(?p_2)),xsd:double(MAX(?p_1)) + xsd:double(MAX(?p_2)),xsd:double(0.0)) AS ?ploss_1) (IF(xsd:double(MAX(?p_1)) > xsd:double(MAX(?p_2)),xsd:double(MAX(?p_1)) + xsd:double(MAX(?p_2)),xsd:double(0.0)) AS ?ploss_2) (MAX(?r) AS ?r) (MAX(?rate) AS ?rate) (COALESCE(MAX(?in_service), MAX(?connected_1) && MAX(?connected_2)) AS ?status) (MAX(?un) AS ?un) (MAX(?x) AS ?x) (MAX(?connectivity_node_1) AS ?connectivity_node_1) (MAX(?connectivity_node_2) AS ?connectivity_node_2) WHERE {
# Assume π equivalent with at least r,x and b shunt.
# Extract properties for series compensator
?_eq_subject <http://entsoe.eu/CIM/EquipmentCore/3/1> ?eq_repo .
SERVICE ?eq_repo {
?compensator cim:SeriesCompensator.r ?r ;
cim:SeriesCompensator.x ?x ;
cim:IdentifiedObject.mRID ?mrid ;
cim:IdentifiedObject.name ?name ;
cim:ConductingEquipment.BaseVoltage/cim:BaseVoltage.nominalVoltage ?un ;
^cim:Terminal.ConductingEquipment ?terminal .
# Extract terminal properties
?terminal cim:Terminal.ConnectivityNode ?con_node ;
cim:ACDCTerminal.sequenceNumber ?nr .
?con_node cim:ConnectivityNode.ConnectivityNodeContainer/cim:VoltageLevel.Substation ?substation ;
cim:IdentifiedObject.mRID ?connectivity_node .
?substation cim:Substation.Region/cim:SubGeographicalRegion.Region/cim:IdentifiedObject.name ?area .
OPTIONAL {
?compensator SN:Equipment.networkAnalysisEnable ?network_analysis
}
FILTER (REGEX(?area,'${region}'))
# Optionally extract current limits
OPTIONAL {
?_lim cim:OperationalLimit.OperationalLimitSet/cim:OperationalLimitSet.Equipment ?compensator ;
a cim:CurrentLimit ;
cim:IdentifiedObject.name '${rate}' ;
cim:CurrentLimit.value ?_rate .
# Convert rate from current to power using √3 * U [kV] * I [A] / 1000.0 [MVA]
BIND (1.7320508075688772 * xsd:double(xsd:string(?un)) * xsd:double(xsd:string(?_rate)) / 1000.0 AS ?rate)
} .
}
# Optionally extract in_service associated with compensator
OPTIONAL {
?compensator ^cim:SvStatus.ConductingEquipment/cim:SvStatus.inService ?in_service
} .
?terminal cim:ACDCTerminal.connected ?connected .
OPTIONAL {
?terminal ^cim:SvPowerFlow.Terminal/cim:SvPowerFlow.p ?p .
}
# Create variables for node 1 and node 2
BIND (IF(?nr = 1,STR(?p),'') AS ?p_1)
BIND (IF(?nr = 1,?connected,False) AS ?connected_1)
BIND (IF(?nr = 2,STR(?p),'') AS ?p_2)
BIND (IF(?nr = 2,?connected,False) AS ?connected_2)
BIND (IF(?nr = 1,?connectivity_node,'') AS ?connectivity_node_1)
BIND (IF(?nr = 2,?connectivity_node,'') AS ?connectivity_node_2)
}
GROUP BY ?compensator
HAVING ((COUNT(*) > 1) && (MAX(?connectivity_node_1) != MAX(?connectivity_node_2)) && COALESCE(MAX(?analysis_enabled), True))
station_group_code_and_names
Question
Which ScheduleResource entries (in the Statnett CIM extension) exist in the dataset, and for each one, what are its marketCode (station group), name, and—if present—alias name?
TLDR;
Return all resources that have SN:ScheduleResource.marketCode and cim:IdentifiedObject.name; include cim:IdentifiedObject.aliasName when available.
Explanation
The query uses two prefixes:
cim:→ the IEC CIM namespace, to access common attributes likeIdentifiedObject.nameandIdentifiedObject.aliasName.SN:→ the Statnett CIM extension namespace, to accessScheduleResource.marketCode.
Projection
It selects three variables:
?station_group— bound fromSN:ScheduleResource.marketCode?name— bound fromcim:IdentifiedObject.name?alias_name— optionally bound fromcim:IdentifiedObject.aliasName
Pattern logic
?s SN\:ScheduleResource.marketCode ?station\_group ;
cim\:IdentifiedObject.name ?name .
OPTIONAL { ?s cim\:IdentifiedObject.aliasName ?alias\_name }
- The subject
?sis any resource that has aSN:ScheduleResource.marketCodeproperty and acim:IdentifiedObject.name. Because these two triples are not in anOPTIONAL, they act as a filter: only subjects with both properties are returned. - The
OPTIONALblock tries to bind?alias_namefromcim:IdentifiedObject.aliasName. If that property is missing for?s, the row is still returned with?alias_nameunbound.
Notes & implications
- Namespace-specific property: The query keys on
SN:ScheduleResource.marketCode. This effectively scopes results to the Statnett extension model; if the same concept exists under a different namespace in your data, those entries will not match. (This is why the inline comment asks whetherScheduleResourcemight exist in another namespace.) - No explicit rdf:type check: There’s no
?s a SN:ScheduleResourcetriple. Instead, the presence of themarketCodeproperty is used to identify schedule resources. This is often sufficient and slightly more flexible, but if you want stricter typing, add:
?s a SN\:ScheduleResource .
- Cardinality effects:
- If a subject has multiple
aliasNamevalues, you’ll get one row per alias (standard SPARQL multivalued join behavior). - Similarly, multiple
marketCodeornamevalues would create a row for each combination. - Semicolon syntax: The semicolons after
?ssimply chain predicates with the same subject, making the query more concise:
?s P1 O1 ;
P2 O2 .
is shorthand for
?s P1 O1 .
?s P2 O2 .
Overall, the query lists schedule-related resources defined via the Statnett extension, reporting their market grouping (station_group), canonical name, and an optional alias if present.
Original SPARQL
# Name: Station group code and names
PREFIX cim: <http://iec.ch/TC57/2013/CIM-schema-cim16#>
PREFIX SN: <http://www.statnett.no/CIM-schema-cim15-extension#>
SELECT ?station_group ?name ?alias_name WHERE {
# SN is not made optional here because then there is no filtering left.
# TODO: Is ScheduleResource available in a another namespace?
?s SN:ScheduleResource.marketCode ?station_group ;
cim:IdentifiedObject.name ?name ;
OPTIONAL {
?s cim:IdentifiedObject.aliasName ?alias_name
}
}
station_group_for_power_unit
Question
For each scheduling resource, which power system element (a SynchronousMachine tied to a GeneratingUnit or a NonConformLoad tied to a LoadGroup) is associated to it, and what are the identifiers, names, and market codes involved?
TLDR;
Finds the physical CIM object (either a SynchronousMachine’s GeneratingUnit or a NonConformLoad’s LoadGroup parent) connected to a given scheduling resource and returns the physical object’s mRID, the unit’s mRID and name, and the resource’s market code.
Explanation
Prefixes
SN:points to the Statnett CIM extension namespace, used here forSN:ScheduleResource.marketCode.cim:points to the IEC CIM v16 namespace for standard CIM classes and properties.
Selected outputs
?power_system_model_mrid— the mRID of the physical CIM object (either acim:SynchronousMachineor acim:NonConformLoad).?market_unit_mrid— the mRID of the unit associated with the resource (acim:GeneratingUnitor acim:LoadGroup).?resource_name— the name of that unit.?market_code— the market code of the scheduling resource.
Graph pattern walkthrough
-
?resource SN:ScheduleResource.marketCode ?market_code .Finds each scheduling resource and its market code in the Statnett extension. -
?unit ?p ?resource ; cim:IdentifiedObject.name ?resource_name ; cim:IdentifiedObject.mRID ?market_unit_mrid ;
Locates a unit (?unit) that links to the ?resource via some predicate ?p (left intentionally generic). From that unit, the query also retrieves the unit’s name and mRID. In practice, ?unit will be a cim:GeneratingUnit or a cim:LoadGroup.
-
VALUES ?physical_model_predicate { cim:SynchronousMachine.GeneratingUnit cim:NonConformLoad.LoadGroup }Restricts the relationship used to connect a physical object to the unit. Only two CIM properties are allowed:
cim:SynchronousMachine.GeneratingUnit(domain:SynchronousMachine, range:GeneratingUnit)cim:NonConformLoad.LoadGroup(domain:NonConformLoad, range:LoadGroup)
-
?physical_object ?physical_model_predicate ?unit ; cim:IdentifiedObject.mRID ?power_system_model_mrid .Uses the chosen predicate to find the physical object (
?physical_object) that owns/points to the?unit.- If
?physical_model_predicateiscim:SynchronousMachine.GeneratingUnit, then?physical_objectis acim:SynchronousMachinethat references the?unit(aGeneratingUnit). - If it is
cim:NonConformLoad.LoadGroup, then?physical_objectis acim:NonConformLoadthat references the?unit(aLoadGroup). The query then extracts that physical object’smRIDas?power_system_model_mrid.
- If
What this effectively returns For each scheduling resource with a market code, the query:
- Finds a related unit (either
GeneratingUnitorLoadGroup) that points to the resource. - Traverses back from that unit to the associated physical network element (
SynchronousMachineorNonConformLoad) via the appropriate CIM property. - Reports the physical object’s mRID (as the “power system model mRID”), plus the unit’s mRID and name, and the resource’s market code.
Notes & assumptions
- The generic
?unit ?p ?resourceallows any property to link a unit to the scheduling resource. In your data model, this should align with how resources are attached to their units; otherwise, consider constraining?pto a specific predicate. - The query uses only mandatory patterns. If a unit lacks a link to a resource or a physical object via the specified predicates, that record will not appear.
- Multiple physical objects tied to the same unit/resource will yield multiple rows (one per physical object).
Original SPARQL
# Name: station group for power resource
PREFIX SN: <http://www.statnett.no/CIM-schema-cim15-extension#>
PREFIX cim: <http://iec.ch/TC57/2013/CIM-schema-cim16#>
SELECT ?power_system_model_mrid ?market_unit_mrid ?resource_name ?market_code WHERE {
?resource SN:ScheduleResource.marketCode ?market_code .
?unit ?p ?resource ;
cim:IdentifiedObject.name ?resource_name ;
cim:IdentifiedObject.mRID ?market_unit_mrid ;
VALUES ?physical_model_predicate { cim:SynchronousMachine.GeneratingUnit cim:NonConformLoad.LoadGroup }
?physical_object ?physical_model_predicate ?unit ;
cim:IdentifiedObject.mRID ?power_system_model_mrid .
}
substation_voltage_level
Question
For each substation, what is the highest nominal voltage among its voltage levels, and which voltage level(s) achieve that value (returning their mRIDs alongside the substation mRID)?
TLDR;
Compute the maximum BaseVoltage.nominalVoltage per substation, then return the substation mRID, the max voltage value, and the mRID(s) of the VoltageLevel(s) in that substation that have that maximum.
Explanation
The query works in two layers:
- Inner subquery (aggregation per substation)
{ SELECT (MAX(?volt) AS ?v) ?_substation WHERE { ?volt_level a cim:VoltageLevel ; cim:VoltageLevel.BaseVoltage/cim:BaseVoltage.nominalVoltage ?volt ; cim:VoltageLevel.Substation ?_substation . } GROUP BY ?_substation }
- Scans all
cim:VoltageLevelinstances. - Via a property path, it retrieves each level’s nominal voltage:
cim:VoltageLevel.BaseVoltage / cim:BaseVoltage.nominalVoltage. - Groups by the containing substation (
?_substation) and computesMAX(?volt)for each group, binding the result to?v. - The subquery thus returns one row per substation with the maximum nominal voltage in that substation.
-
Outer query (join back to concrete voltage levels and IDs)
?volt_level a cim:VoltageLevel ; cim:IdentifiedObject.mRID ?container ; cim:VoltageLevel.BaseVoltage/cim:BaseVoltage.nominalVoltage ?v ; cim:VoltageLevel.Substation ?_substation . ?_substation cim:IdentifiedObject.mRID ?substation .-
Matches
VoltageLevelresources again, binding:?containerto themRIDof the voltage level (i.e., the voltage level’s own identifier).?vto the level’s nominal voltage (same property path as above).?_substationto the level’s parent substation resource.
-
Joins with the subquery on both
?_substationand?v. Because?vfrom the subquery is the maximum per substation, this join filters the outer solutions to only those voltage levels whose nominal voltage equals the per‑substation maximum. -
Finally, it resolves the substation’s external identifier by binding
?substationto the substation’scim:IdentifiedObject.mRID.
-
Result shape
SELECT ?container ?substation ?v yields:
?container: mRID of the voltage level(s) that have the maximum nominal voltage within their substation.?substation: mRID of the corresponding substation.?v: the maximum nominal voltage value for that substation.
Notes & behavior
- If multiple voltage levels in the same substation share the same maximum voltage, all of them are returned (one row per level).
- The use of the property path
cim:VoltageLevel.BaseVoltage/cim:BaseVoltage.nominalVoltagetraverses from aVoltageLevelto its associatedBaseVoltageresource and then to the numericnominalVoltageliteral. - Variable scoping ensures that
?vfrom the inner subquery is the aggregated maximum, and the outer pattern’s?v(the actual level’s voltage) must match it to survive the join.
Original SPARQL
# Name: Substation voltage level
PREFIX cim: <http://iec.ch/TC57/2013/CIM-schema-cim16#>
SELECT ?container ?substation ?v WHERE {
?volt_level a cim:VoltageLevel ;
cim:IdentifiedObject.mRID ?container ;
cim:VoltageLevel.BaseVoltage/cim:BaseVoltage.nominalVoltage ?v ;
cim:VoltageLevel.Substation ?_substation .
{
SELECT (MAX(?volt) AS ?v) ?_substation WHERE {
?volt_level a cim:VoltageLevel ;
cim:VoltageLevel.BaseVoltage/cim:BaseVoltage.nominalVoltage ?volt ;
cim:VoltageLevel.Substation ?_substation .
}
GROUP BY ?_substation
} .
?_substation cim:IdentifiedObject.mRID ?substation
}
sv_branch
Question
Which ACLineSegments (branches) have their equipment parameters, terminal connectivity, and state‑variable results (status, P/Q flows, voltages, angles) so we can verify a state estimator where both current and voltage are state variables?
TLDR;
Pulls one row per cim:ACLineSegment with r/x/bch/gch, IDs and base‑voltage, terminal‑1/2 connectivity, in‑service status, SvPowerFlow (p/q) per terminal, and SvVoltage (v/angle) per end’s topological node; status defaults to inService if present, otherwise to connected_1 && connected_2. Intended to include only equipment with SN:Equipment.networkAnalysisEnable true.
Explanation
The query stitches together data from the EQ (equipment), TP (topology), and SV (state variable) models around each cim:ACLineSegment (“branch”) to produce a verification‑ready view for state estimation results.
1) Scope to the Equipment repository and fetch static line data
?_eq_subject <http://entsoe.eu/CIM/EquipmentCore/3/1> ?eq_repo .
SERVICE ?eq_repo {
?acline cim:ACLineSegment.r ?r ;
cim:ACLineSegment.x ?x ;
cim:ACLineSegment.bch ?bch ;
cim:ACLineSegment.gch ?gch ;
cim:IdentifiedObject.mRID ?mrid ;
cim:IdentifiedObject.name ?name ;
cim:ConductingEquipment.BaseVoltage/cim:BaseVoltage.nominalVoltage ?un .
...
}
-
The
SERVICE ?eq_repoblock isolates the EQ graph. For each?acline, it returns series/shunt parameters (r,x,bch,gch), identifiers (mRID,name), and the nominal base voltage?unvia the attachedBaseVoltage. -
Inside the same
SERVICE, the two physical terminals are identified and ordered using sequence numbers:?terminal_1 a cim:Terminal ; ... ; (cim:Terminal.sequenceNumber | cim:ACDCTerminal.sequenceNumber) 1 . ?terminal_2 a cim:Terminal ; ... ; (cim:Terminal.sequenceNumber | cim:ACDCTerminal.sequenceNumber) 2 .This gives a consistent “end 1” and “end 2” for later joining.
2) Bring in SV status for the conducting equipment
?acline ^cim:SvStatus.ConductingEquipment/cim:SvStatus.inService ?in_service .
- Reads the state‑variable flag
SvStatus.inServicefor the line (if present).
3) Walk from ConnectivityNodes to TopologicalNodes, then attach SV node voltages
?con_node_1 cim:ConnectivityNode.TopologicalNode ?node_1 .
OPTIONAL {
?_sv_n_1 cim:SvVoltage.TopologicalNode ?node_1 ;
cim:SvVoltage.v ?v_1 ;
cim:SvVoltage.angle ?angle_1 .
}
?con_node_2 cim:ConnectivityNode.TopologicalNode ?node_2 .
OPTIONAL {
?_sv_n_2 cim:SvVoltage.TopologicalNode ?node_2 ;
cim:SvVoltage.v ?v_2 ;
cim:SvVoltage.angle ?angle_2 .
}
- Each terminal’s
ConnectivityNodeis mapped to itsTopologicalNode(TPlayer). SvVoltageon eachTopologicalNodeprovides per‑end voltage magnitudevand angle.
4) Terminal connectivity and SV power flows per terminal
?terminal_1 (cim:Terminal.connected | cim:ACDCTerminal.connected) ?connected_1 .
OPTIONAL {
?_sv_t_1 cim:SvPowerFlow.Terminal ?terminal_1 ;
cim:SvPowerFlow.p ?p_1 ;
cim:SvPowerFlow.q ?q_1 .
}
?terminal_2 (cim:Terminal.connected | cim:ACDCTerminal.connected) ?connected_2 .
OPTIONAL {
?_sv_t_2 cim:SvPowerFlow.Terminal ?terminal_2 ;
cim:SvPowerFlow.p ?p_2 ;
cim:SvPowerFlow.q ?q_2 .
}
- Reads the equipment‑model connectivity flags for both terminals (handles either
TerminalorACDCTerminalproperty). - Optionally attaches
SvPowerFlowactive/reactive power for each terminal, givingp_1/q_1andp_2/q_2.
5) Network‑analysis enable flag and intended filtering
OPTIONAL { ?acline SN:Equipment.networkAnalysisEnable ?_network_analysis }
FILTER (?network_analysis)
BIND (COALESCE(?_network_analysis, True) AS ?network_analysis)
-
Goal: return only equipment where
networkAnalysisEnableis true, defaulting toTruewhen the flag is missing. -
Important note on evaluation order: As written,
FILTER (?network_analysis)occurs beforeBINDdefines?network_analysis, so when the optional flag is absent the variable is unbound and the filter evaluates to error → the row is dropped. To implement the “default true” behavior, move the filter after theBIND, or fold the default into the filter:-
Fix A (reorder):
OPTIONAL { ?acline SN:Equipment.networkAnalysisEnable ?_network_analysis } BIND (COALESCE(?_network_analysis, true) AS ?network_analysis) FILTER (?network_analysis) -
Fix B (inline):
FILTER ( COALESCE(?_network_analysis, true) )
-
6) Derive the branch status
BIND (COALESCE(?in_service, ?connected_1 && ?connected_2) AS ?status) .
- Prioritizes
SvStatus.inServicewhen available; otherwise uses terminal connectivity and declares the branch “up” only if both ends are connected.
7) Output columns
SELECT
?mrid ?name ?r ?x ?bch ?gch ?status ?length ?un
?p_1 ?q_1 ?p_2 ?q_2
?v_1 ?angle_1 ?v_2 ?angle_2
-
Static parameters and identifiers from EQ (
mrid,name,r,x,bch,gch,un). -
Derived
status, per‑end P/Q (p_1/q_1,p_2/q_2), and per‑node volt/angle (v_1/angle_1,v_2/angle_2). -
Note:
?lengthappears inSELECTbut is never bound. If needed, add (likely inside theSERVICEblock):?acline cim:Conductor.length ?length .Otherwise
?lengthwill be unbound (NULL) for all rows.
8) Optional patterns and data sparsity
- All
SvVoltage/SvPowerFlowparts areOPTIONAL, so the query still returns the line with whatever SV data is available. - Using explicit terminal sequence numbers ensures
*_1and*_2fields are consistently associated with the same physical ends, which is critical when comparing state‑estimator results.
What you get per line segment
- Equipment:
mRID,name,r/x,bch/gch, base voltageun(andlengthif added). - Topology/SV per end:
v/angleon each end’sTopologicalNode. - Power flow per terminal:
p/qat end 1 and end 2. - Availability:
statusderived fromSvStatus.inServiceor terminal connectivity. - (Intended) network‑analysis gating via
SN:Equipment.networkAnalysisEnable.
This combined view is suitable for side‑by‑side checks of SE outputs (voltages/angles and terminal P/Q) against the modeled branch parameters and connectivity/state status.
Original SPARQL
# Name: SV branch
#
# Extract data from both EQ/TP/SV for ACLineSegment used to verify
# results from state estimator where both current and voltage has been
# defined as state variables.
#
PREFIX cim: <http://iec.ch/TC57/2013/CIM-schema-cim16#>
PREFIX SN: <http://www.statnett.no/CIM-schema-cim15-extension#>
SELECT ?mrid ?name ?r ?x ?bch ?gch ?status ?length ?un ?p_1 ?q_1 ?p_2 ?q_2 ?v_1 ?angle_1 ?v_2 ?angle_2 WHERE {
# Extract key properties for ACLineSegment
?_eq_subject <http://entsoe.eu/CIM/EquipmentCore/3/1> ?eq_repo .
SERVICE ?eq_repo {
?acline cim:ACLineSegment.r ?r ;
cim:ACLineSegment.x ?x ;
cim:ACLineSegment.bch ?bch ;
cim:ACLineSegment.gch ?gch ;
cim:IdentifiedObject.mRID ?mrid ;
cim:IdentifiedObject.name ?name ;
cim:ConductingEquipment.BaseVoltage/cim:BaseVoltage.nominalVoltage ?un .
?terminal_1 a cim:Terminal ;
cim:Terminal.ConductingEquipment ?acline ;
cim:Terminal.ConnectivityNode ?con_node_1 ;
cim:Terminal.sequenceNumber | cim:ACDCTerminal.sequenceNumber 1 .
?terminal_2 a cim:Terminal ;
cim:Terminal.ConductingEquipment ?acline ;
cim:Terminal.ConnectivityNode ?con_node_2 ;
cim:Terminal.sequenceNumber | cim:ACDCTerminal.sequenceNumber 2 .
}
# Extract in_service flag for each acline
?acline ^cim:SvStatus.ConductingEquipment/cim:SvStatus.inService ?in_service .
# Extract connectivity node, topological node, voltage ang angle
?con_node_1 cim:ConnectivityNode.TopologicalNode ?node_1 .
OPTIONAL {
?_sv_n_1 cim:SvVoltage.TopologicalNode ?node_1 ;
cim:SvVoltage.v ?v_1 ;
cim:SvVoltage.angle ?angle_1 .
}
# Extract conencted flag and active and reactive power for each terminal
?terminal_1 cim:Terminal.connected | cim:ACDCTerminal.connected ?connected_1 .
OPTIONAL {
?_sv_t_1 cim:SvPowerFlow.Terminal ?terminal_1 ;
cim:SvPowerFlow.p ?p_1 ;
cim:SvPowerFlow.q ?q_1 .
} .
?con_node_2 cim:ConnectivityNode.TopologicalNode ?node_2 .
OPTIONAL {
?_sv_n_2 cim:SvVoltage.TopologicalNode ?node_2 ;
cim:SvVoltage.v ?v_2 ;
cim:SvVoltage.angle ?angle_2 .
}
?terminal_2 cim:Terminal.connected | cim:ACDCTerminal.connected ?connected_2 .
OPTIONAL {
?_sv_t_2 cim:SvPowerFlow.Terminal ?terminal_2 ;
cim:SvPowerFlow.p ?p_2 ;
cim:SvPowerFlow.q ?q_2 .
}
OPTIONAL {
?acline SN:Equipment.networkAnalysisEnable ?_network_analysis
}
FILTER (?network_analysis)
BIND (COALESCE(?_network_analysis, True) AS ?network_analysis)
# Assign status flag for each branch. It is set to the first that exist of
# 1) in_service flag for each acline
# 2) Connected flags of the two terminals. Status is set to False if at least one of the terminals are disconnected
BIND (COALESCE(?in_service, ?connected_1 && ?connected_2) AS ?status) .
}
sv_injection
Question
Which topological nodes have steady-state real and reactive power injections, and what are their values?
TLDR;
The query retrieves the IDs of topological nodes along with their real (P) and reactive (Q) power injection values from SvInjection measurements.
Explanation
This SPARQL query is designed to extract information from the SvInjection class in the CIM model. The SvInjection class represents the steady-state injection of real and reactive power into the network at a given topological node.
Here's how the query works step-by-step:
-
PREFIX declaration The prefix
cim:is defined to point to the CIM RDF namespace:http://iec.ch/TC57/2013/CIM-schema-cim16#This makes it easier to refer to CIM classes and properties without typing the full URI. -
Triple pattern for node identification
?sv\_injection cim\:SvInjection.TopologicalNode/cim\:IdentifiedObject.mRID ?node ;
This line does two things:
- Finds instances of
SvInjectionand follows thecim:SvInjection.TopologicalNodeproperty to get the related topological node. - From the topological node, it navigates via
cim:IdentifiedObject.mRIDto retrieve the node's unique identifier (?node).
- Real power injection value
cim\:SvInjection.pInjection ?p ;
This fetches the real power (P) injection value associated with the SvInjection record, storing it in ?p.
- Reactive power injection value
cim\:SvInjection.qInjection ?q .
This fetches the reactive power (Q) injection value from the SvInjection record, storing it in ?q.
- Result The output will be a table with columns:
?node→ The mRID of the topological node.?p→ The real power injection value.?q→ The reactive power injection value.
Effectively, the query links steady-state injection records to their topological node IDs and retrieves both P and Q injection values for each.
Original SPARQL
# Name: SvInjection
PREFIX cim: <http://iec.ch/TC57/2013/CIM-schema-cim16#>
SELECT ?node ?p ?q WHERE {
?sv_injection cim:SvInjection.TopologicalNode/cim:IdentifiedObject.mRID ?node ;
cim:SvInjection.pInjection ?p ;
cim:SvInjection.qInjection ?q .
}
sv_power_deviation
Question
For each topological node, what is the summed active power from connected terminals (from SvPowerFlow or converter nameplate) and how does it compare to the reported SvInjection.pInjection at that node? Also, which connectivity nodes and terminals contribute to it?
TLDR;
Groups by TopologicalNode and:
- Sums terminal active power
p(preferSvPowerFlow; fallback toACDCConverter.pif no state value). - Retrieves the node’s reported
SvInjection.pInjection(takes the max if multiple). - Lists involved ConnectivityNode mRIDs and terminal names.
Explanation
This query rolls up power information from terminals to their TopologicalNode and aligns it with the node-level state variable injection. Key parts:
- Equipment/terminal context via a federated service
{ SELECT * { ?_eq_subject <http://entsoe.eu/CIM/EquipmentCore/3/1> ?eq_repo . SERVICE ?eq_repo { ?terminal cim:Terminal.ConnectivityNode ?con_node ; cim:Terminal.ConductingEquipment ?equipment ; cim:IdentifiedObject.name ?terminal_name . ?con_node cim:IdentifiedObject.mRID ?con_node_mrid } } }
- Finds an equipment repository endpoint (
?eq_repo) and usesSERVICEto federate into it. - Pulls terminals, their conducting equipment, and their connectivity nodes (plus IDs and terminal names).
- This establishes the list of terminals and how they attach to the network.
-
Terminal active power (
p) with fallback{ ?sv_power_flow cim:SvPowerFlow.Terminal ?terminal ; cim:SvPowerFlow.p ?p } UNION { ?equipment cim:ACDCConverter.p ?p FILTER NOT EXISTS { ?sv_power_flow cim:SvPowerFlow.Terminal ?terminal } }- Primary source:
SvPowerFlowbound to the?terminal, giving?p. - Fallback: If there is no
SvPowerFlowfor that terminal, use the equipment’sACDCConverter.pas?p. - This ensures each terminal contributes a power value even when state variables are missing.
- Primary source:
-
Map terminals to a TopologicalNode (two routes)
{ ?con_node cim:ConnectivityNode.TopologicalNode ?tp_node } UNION { FILTER NOT EXISTS { ?con_node cim:ConnectivityNode.TopologicalNode ?tp_node } ?terminal cim:Terminal.TopologicalNode ?tp_node }- Preferred mapping: from the
ConnectivityNodeto itsTopologicalNode. - Fallback mapping: if the connectivity node lacks a topo link, use the terminal’s direct
TopologicalNode. - This normalizes everything to the topology level.
- Preferred mapping: from the
-
Node identity and node-level injection
?tp_node cim:IdentifiedObject.mRID ?node ; cim:IdentifiedObject.name ?name ; ^cim:SvInjection.TopologicalNode/cim:SvInjection.pInjection ?p_inj- Captures the TopologicalNode’s mRID (
?node) and name. - Via an inverse path, finds any
SvInjectionon that node and binds itspInjectionas?p_inj.
- Captures the TopologicalNode’s mRID (
-
Aggregation by node
GROUP BY ?nodeWith the following outputs:
(SUM(xsd:double(STR(?p))) AS ?sum_terminal_flow)Sums all terminal power contributions on the node.STR()thenxsd:double()is used to robustly cast different literal forms of?pto a numeric for summation.(MAX(xsd:double(STR(?p_inj))) AS ?reported_sv_injection)If multipleSvInjectionvalues exist for the node, choose the maximum as a representative reported value.(GROUP_CONCAT(DISTINCT (?con_node_mrid); SEPARATOR=",") AS ?connectivity_nodes)Lists unique contributingConnectivityNodemRIDs for traceability.(GROUP_CONCAT(?terminal_name; SEPARATOR=",") AS ?terminal_names)Lists the terminal names aggregated into the node.
What the result means
Each result row corresponds to a TopologicalNode:
?sum_terminal_flow: The net active power from all terminals tied (directly or via connectivity nodes) to that node, using state values when available, otherwise converter power.?reported_sv_injection: The node-level injection reported inSvInjection.- Comparing the two highlights power deviations between bottom-up terminal sums and top-down node injection, useful for validation, estimation errors, or data gaps.
?connectivity_nodes/?terminal_namesgive provenance for auditing which parts of the network and which terminals contributed to the aggregate.
Original SPARQL
# Name: Sv power deviation
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX cim: <http://iec.ch/TC57/2013/CIM-schema-cim16#>
SELECT ?node (SUM(xsd:double(STR(?p))) AS ?sum_terminal_flow) (MAX(xsd:double(STR(?p_inj))) AS ?reported_sv_injection) (GROUP_CONCAT(DISTINCT (?con_node_mrid); SEPARATOR=",") AS ?connectivity_nodes) (GROUP_CONCAT(?terminal_name; SEPARATOR=",") AS ?terminal_names) WHERE {
{
SELECT * {
?_eq_subject <http://entsoe.eu/CIM/EquipmentCore/3/1> ?eq_repo .
SERVICE ?eq_repo {
?terminal cim:Terminal.ConnectivityNode ?con_node ;
cim:Terminal.ConductingEquipment ?equipment ;
cim:IdentifiedObject.name ?terminal_name .
?con_node cim:IdentifiedObject.mRID ?con_node_mrid
}
}
}
{
?sv_power_flow cim:SvPowerFlow.Terminal ?terminal ;
cim:SvPowerFlow.p ?p
}
UNION {
?equipment cim:ACDCConverter.p ?p
FILTER NOT EXISTS {
?sv_power_flow cim:SvPowerFlow.Terminal ?terminal
}
}
{
?con_node cim:ConnectivityNode.TopologicalNode ?tp_node
}
UNION {
FILTER NOT EXISTS {
?con_node cim:ConnectivityNode.TopologicalNode ?tp_node
}
?terminal cim:Terminal.TopologicalNode ?tp_node
}
?tp_node cim:IdentifiedObject.mRID ?node ;
cim:IdentifiedObject.name ?name ;
^cim:SvInjection.TopologicalNode/cim:SvInjection.pInjection ?p_inj
}
GROUP BY ?node
switches
Question
Which switches (breaker, disconnector, etc.) exist in the model, what is each switch’s effective open/closed state, and which two connectivity nodes (by mRID) does each switch connect between?
TLDR;
Returns one row per switch (from a set of switch-like equipment types) with: mRID, effective state (is_open, preferring SSH Switch.open over EQ normalOpen), equipment type (local name), terminal‑1 and terminal‑2 connectivity node mRIDs, and the switch name. If a switch has only one terminal defined, terminal‑2 collapses to terminal‑1.
Explanation
-
Repository selection & SERVICE scope
- The inner
SELECT *retrieves an equipment repository IRI?eq_repovia the triple:
The subsequent?_eq_subject <http://entsoe.eu/CIM/EquipmentCore/3/1> ?eq_repo .SERVICE ?eq_repo { ... }block executes the main pattern against that repository/graph.
- The inner
-
Handling switches with variable terminal counts
- A subquery inside the
SERVICEfinds, for each switch, the maximum terminal sequence number it has:SELECT (?internal_switch AS ?switch) (MAX(?nr) AS ?max_terminal_number) { ?internal_switch cim:Switch.normalOpen ?_unused_normal_open ; ^cim:Terminal.ConductingEquipment/cim:ACDCTerminal.sequenceNumber ?nr } GROUP BY ?internal_switch - This yields
?max_terminal_number(usually 2). If it’s 1 (a degenerate case), the query later binds both terminals using sequence number 1 so terminal‑2 effectively equals terminal‑1, representing a switch that cannot connect two distinct nodes.
- A subquery inside the
-
Limiting to switch-like equipment types
VALUES ?type { cim:Breaker cim:Disconnector cim:GroundDisconnector cim:LoadBreakSwitch cim:Recloser cim:MktSwitch cim:Fuse cim:Sectionaliser cim:Cut cim:Jumper }restricts results to common switch classes.
-
Core switch attributes
- The main switch pattern requires:
cim:IdentifiedObject.mRID→?mrid- RDF
a ?type→ later turned into a readable local name withSTRAFTER(STR(?type),"#") AS ?equipment_type cim:Switch.normalOpen→?normal_open(the EQ-profile default state)- Two terminals linked by inverse of
cim:Terminal.ConductingEquipment:?terminal1withcim:ACDCTerminal.sequenceNumber 1?terminal2withcim:ACDCTerminal.sequenceNumber ?max_terminal_number
- Each terminal is followed to its connectivity node mRID:
- Terminal‑1 →
?connectivity_node_1 - Terminal‑2 →
?connectivity_node_2
- Terminal‑1 →
cim:IdentifiedObject.name→?name
- The main switch pattern requires:
-
Effective state resolution (SSH overrides EQ)
- The operational state may be provided dynamically in SSH as
cim:Switch.open:OPTIONAL { ?switch cim:Switch.open ?ssh_is_open } BIND (COALESCE(?ssh_is_open, ?normal_open) AS ?is_open) COALESCEensures?is_openprefers the SSH state when present; otherwise it falls back to the equipment’snormalOpen.
- The operational state may be provided dynamically in SSH as
-
Final projection
- The outermost
SELECTreturns:?mrid?is_open(effective state)?equipment_type(local class name after#)?connectivity_node_1,?connectivity_node_2?name
- The outermost
-
Practical outcome
- Each row fully identifies a switch, its class, its readable name, where it sits in the network (via the two endpoint connectivity node mRIDs), and whether it is open or closed according to the most authoritative available profile (SSH > EQ). For single‑terminal anomalies, both endpoints resolve to the same node, reflecting no connective capability.
Original SPARQL
# Name: Switches
PREFIX cim: <http://iec.ch/TC57/2013/CIM-schema-cim16#>
SELECT ?mrid ?is_open (STRAFTER(STR(?type),"#") AS ?equipment_type) ?connectivity_node_1 ?connectivity_node_2 ?name WHERE {
{
SELECT * {
?_eq_subject <http://entsoe.eu/CIM/EquipmentCore/3/1> ?eq_repo .
SERVICE ?eq_repo {
{
# Extract the maximum terminal number per switch. This number is used to deduce the second terminal
# Normally this equals 2, but occasionally it can be one. In that case it means that the switch
# has only one termainal. A switch with only one terminal can not connect or disconnect anything
# which is equivalent of setting terminal 2 equal to terminal 1
SELECT (?internal_switch AS ?switch) (MAX(?nr) AS ?max_terminal_number) {
?internal_switch cim:Switch.normalOpen ?_unused_normal_open ;
^cim:Terminal.ConductingEquipment/cim:ACDCTerminal.sequenceNumber ?nr
}
GROUP BY ?internal_switch
}
VALUES ?type { cim:Breaker cim:Disconnector cim:GroundDisconnector cim:LoadBreakSwitch cim:Recloser cim:MktSwitch cim:Fuse cim:Sectionaliser cim:Cut cim:Jumper }
?switch cim:IdentifiedObject.mRID ?mrid ;
a ?type ;
cim:Switch.normalOpen ?normal_open ;
^cim:Terminal.ConductingEquipment ?terminal1 ;
^cim:Terminal.ConductingEquipment ?terminal2 ;
cim:IdentifiedObject.name ?name .
?terminal1 cim:ACDCTerminal.sequenceNumber 1 ;
cim:Terminal.ConnectivityNode/cim:IdentifiedObject.mRID ?connectivity_node_1 .
?terminal2 cim:ACDCTerminal.sequenceNumber ?max_terminal_number ;
cim:Terminal.ConnectivityNode/cim:IdentifiedObject.mRID ?connectivity_node_2 .
}
}
}
OPTIONAL {
?switch cim:Switch.open ?ssh_is_open
}
BIND (COALESCE(?ssh_is_open, ?normal_open) AS ?is_open)
}
synchronous_machines
Question
Which synchronous machines (and their associated generating units) are in a given region, what are their statuses and electrical values, and what market/scheduling metadata (limits, codes, grouping, type, and aFRR prequalification) are associated with them?
TLDR;
Federated query that lists synchronous machines in ${region}, deriving status and P/Q from state variables, defaulting and inferring limits/type when missing, and enriching with Statnett extension fields (market code, merit order, schedule resource, station group) plus an aFRR-prequalification flag.
Explanation
This query returns one row per synchronous machine (or its generating unit) that satisfies:
- It belongs to a substation within an area whose name matches
${region}. - It is enabled for network analysis (defaulting to
truewhen not explicitly disabled).
Federated source selection
?_eq_subject <http://entsoe.eu/CIM/EquipmentCore/3/1> ?eq_repo .followed bySERVICE ?eq_repo { ... }performs a federated subquery against the equipment repository endpoint discovered via that predicate.
Core equipment & topology
- Selects each
?machine a cim:SynchronousMachineand its basic identifiers:cim:IdentifiedObject.mRID ?machine_mridcim:IdentifiedObject.name ?name- Apparent power rating
cim:RotatingMachine.ratedS ?sn
- Topology binding:
- Inverse from
Terminalto the machine:^cim:Terminal.ConductingEquipment ?terminal - From terminal to connectivity node and its mRID:
?terminal cim:Terminal.ConnectivityNode ?con_node ; ?con_node cim:IdentifiedObject.mRID ?connectivity_node
- Inverse from
- Container → substation chain:
cim:Equipment.EquipmentContainer / cim:VoltageLevel.Substation ?substation- Region/area lookup:
?substation cim:Substation.Region / cim:SubGeographicalRegion.Region / cim:IdentifiedObject.name ?area - Substation identifier:
?substation cim:IdentifiedObject.mRID ?substation_mrid
- Region filter:
FILTER REGEX(?area,'${region}')
Generating Unit association & type
- Because of CIM15/16 modeling differences, it tries both properties:
cim:SynchronousMachine.GeneratingUnit | cim:RotatingMachine.GeneratingUnit ?nullable_gen_unit
- If a generating unit exists, its rdf:type is captured via
?nullable_gen_unit a ?gen_typeagainst a whitelist of unit classes:{ cim:NuclearGeneratingUnit cim:MktGeneratingUnit cim:HydroGeneratingUnit cim:WindGeneratingUnit cim:ThermalGeneratingUnit cim:SolarGeneratingUnit }
- A non-null
?gen_unitis guaranteed for later use:BIND (COALESCE(?nullable_gen_unit, URI("http://no-gen-unit")) AS ?gen_unit)
- Human-friendly generator type string:
BIND (IF(BOUND(?gen_type), replace(STR(?gen_type), STR(cim:), ""), "unknown") AS ?generator_type)
Operating limits & market metadata (SN extensions)
- If a generating unit exists, optional properties are pulled:
- Identifiers & limits:
cim:IdentifiedObject.mRID ?gen_unit_mridcim:GeneratingUnit.minOperatingP ?nullable_minPcim:GeneratingUnit.maxOperatingP ?nullable_maxP
- Statnett market fields:
SN:GeneratingUnit.marketCode ?market_codeSN:GeneratingUnit.groupAllocationWeight ?merit_orderSN:GeneratingUnit.ScheduleResource ?ScheduleResource- From the schedule resource:
SN:ScheduleResource.marketCode ?station_groupcim:IdentifiedObject.mRID ?schedule_resourcecim:IdentifiedObject.name ?station_group_name
- From the schedule resource:
- Identifiers & limits:
- Primary identifier preference:
BIND (COALESCE(?gen_unit_mrid, ?machine_mrid) AS ?mrid)— use the GU mRID when available, otherwise the machine’s.
aFRR prequalification
- Boolean flag computed via an existence check on the GU:
BIND (EXISTS { ?gen_unit SN:GeneratingUnit.ScheduleFRRResource [] } AS ?afrr_prequalified)
Status & network-analysis enablement
- Connectivity status from the terminal:
?terminal cim:ACDCTerminal.connected ?connected - Optional state variable status (if present):
?machine ^cim:SvStatus.ConductingEquipment / cim:SvStatus.inService ?in_service
- Effective status:
BIND (COALESCE(?in_service, ?connected) AS ?status)— prefer state variable; fallback to connectivity.
- Network-analysis toggle (SN extension), defaulting to true:
OPTIONAL { ?machine SN:Equipment.networkAnalysisEnable ?_network_analysis }BIND (COALESCE(?_network_analysis, True) AS ?network_analysis)- Final filter:
FILTER (?network_analysis)
Electrical state variables (Sv) & derived limits
- From
SvPowerFlowtied to the terminal:cim:SvPowerFlow.p ?p(active power)cim:SvPowerFlow.q ?q(reactive power)
- Computed limits when GU limits are missing:
?max_pdefaults to:?nullable_maxPif present, else?pwhenp ≥ 0, else0.0BIND (COALESCE(?nullable_maxP, IF(xsd:double(STR(?p)) >= 0.0, ?p, 0.0), 0.0) AS ?max_p)
?min_pdefaults to:?nullable_minPif present, else?pwhenp < 0, else0.0BIND (COALESCE(?nullable_minP, IF(xsd:double(STR(?p)) < 0.0, ?p, 0.0), 0.0) AS ?min_p)
- Note the explicit cast
xsd:double(STR(?p))to ensure numeric comparison robustness.
Result columns
- The outer
SELECTexposes:- Identifiers & names:
?mrid,?name,?substation_mrid,?connectivity_node,?schedule_resource - Status & configuration:
?status,?generator_type,?afrr_prequalified - Ratings & state variables:
?sn,?p,?q,?max_p,?min_p - Market metadata:
?market_code,?merit_order,?station_group,?station_group_name
- Identifiers & names:
Practical notes
- The query is resilient to partial data: pervasive
OPTIONAL,COALESCE, andEXISTSensure outputs even when GU links or limits are missing. - It accommodates CIM15/16 differences by trying both
SynchronousMachine.GeneratingUnitandRotatingMachine.GeneratingUnit. ${region}is a template parameter inserted into a regex filter against the substation’s area name.
Original SPARQL
# Name: Synchronous machines
PREFIX cim: <http://iec.ch/TC57/2013/CIM-schema-cim16#>
PREFIX SN: <http://www.statnett.no/CIM-schema-cim15-extension#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
SELECT ?mrid ?name ?market_code ?status ?station_group ?station_group_name ?substation_mrid ?max_p ?min_p ?merit_order ?sn ?p ?q ?connectivity_node ?generator_type ?schedule_resource ?afrr_prequalified WHERE {
# Extract properties for synchronous machines.
{
SELECT * WHERE {
?_eq_subject <http://entsoe.eu/CIM/EquipmentCore/3/1> ?eq_repo .
SERVICE ?eq_repo {
?machine a cim:SynchronousMachine ;
cim:IdentifiedObject.mRID ?machine_mrid ;
cim:IdentifiedObject.name ?name ;
cim:RotatingMachine.ratedS ?sn ;
^cim:Terminal.ConductingEquipment ?terminal ;
cim:Equipment.EquipmentContainer/cim:VoltageLevel.Substation ?substation .
# TODO: Seems like cim15 uses SynchronousMachine while cim16 uses RotatingMachine. Will fix this when we have a proper cim16 model
OPTIONAL {
VALUES ?gen_type { cim:NuclearGeneratingUnit cim:MktGeneratingUnit cim:HydroGeneratingUnit cim:WindGeneratingUnit cim:ThermalGeneratingUnit cim:SolarGeneratingUnit }
?machine cim:SynchronousMachine.GeneratingUnit | cim:RotatingMachine.GeneratingUnit ?nullable_gen_unit .
?nullable_gen_unit a ?gen_type
}
BIND (COALESCE(?nullable_gen_unit, URI("http://no-gen-unit")) AS ?gen_unit)
?terminal cim:Terminal.ConnectivityNode ?con_node .
?con_node cim:IdentifiedObject.mRID ?connectivity_node .
# Extract area and mrid for the substation associated with a sync machine
?substation cim:Substation.Region/cim:SubGeographicalRegion.Region/cim:IdentifiedObject.name ?area ;
cim:IdentifiedObject.mRID ?substation_mrid .
# Optionally extract min/max operating power for each machin
OPTIONAL {
?gen_unit cim:IdentifiedObject.mRID ?gen_unit_mrid ;
cim:GeneratingUnit.minOperatingP ?nullable_minP ;
cim:GeneratingUnit.maxOperatingP ?nullable_maxP .
OPTIONAL {
?gen_unit SN:GeneratingUnit.marketCode ?market_code ;
SN:GeneratingUnit.groupAllocationWeight ?merit_order ;
SN:GeneratingUnit.ScheduleResource ?ScheduleResource .
?ScheduleResource SN:ScheduleResource.marketCode ?station_group ;
cim:IdentifiedObject.mRID ?schedule_resource ;
cim:IdentifiedObject.name ?station_group_name .
}
}
FILTER REGEX(?area,'${region}')
# Opionally extract non-CIM standard properties generating units
OPTIONAL {
?machine SN:Equipment.networkAnalysisEnable ?_network_analysis
}
BIND (IF(BOUND(?gen_type),replace(STR(?gen_type), STR(cim:), ""),"unknown") AS ?generator_type)
BIND (COALESCE(?gen_unit_mrid, ?machine_mrid) AS ?mrid)
BIND (EXISTS {
?gen_unit SN:GeneratingUnit.ScheduleFRRResource []
} AS ?afrr_prequalified)
}
}
}
?terminal cim:ACDCTerminal.connected ?connected .
OPTIONAL {
?machine ^cim:SvStatus.ConductingEquipment/cim:SvStatus.inService ?in_service
} .
?sv_power_flow cim:SvPowerFlow.Terminal ?terminal ;
cim:SvPowerFlow.p ?p ;
cim:SvPowerFlow.q ?q .
BIND (COALESCE(?_network_analysis, True) AS ?network_analysis)
BIND (COALESCE(?in_service, ?connected) AS ?status)
BIND (COALESCE(?nullable_maxP, IF(xsd:double(STR(?p)) >= 0.0,?p,0.0), 0.0) AS ?max_p)
BIND (COALESCE(?nullable_minP, IF(xsd:double(STR(?p)) < 0.0,?p,0.0), 0.0) AS ?min_p)
FILTER (?network_analysis)
}
transformer_branches
Question
How can I list transformer-end “branches” (one per winding) in a given region, including their electrical parameters, connection status, tap-influenced ratio and angle, and the two “nodes” they connect?
TLDR;
For each transformer end in substations whose area name matches ${region}, this query returns a branch-like view: impedance/admittance (r, x, b, g), nominal voltage, an active-power limit named ${rate} (if any), service/connected status, and the two nodes—(1) the real connectivity node and (2) a dummy node equal to the transformer’s mRID. Tap-changer settings scale the voltage ratio and set the phase angle from the phase-angle clock.
Explanation
High-level idea.
Power transformer ends are treated as branch elements that connect a real network node to a “dummy” node representing the transformer unit. This makes each end look like a branch for network export/analysis. The inner SERVICE block gathers all equipment facts; the outer block adds status flags and derives tap-dependent quantities before selecting final columns.
1) Scoping to the equipment graph & region
?_eq_subject <http://entsoe.eu/CIM/EquipmentCore/3/1> ?eq_repo .Looks up the endpoint/graph for equipment data and binds it to?eq_repo.SERVICE ?eq_repo { ... }All core equipment facts are retrieved from that repository.- Region filter:
?p\_transformer cim\:Equipment.EquipmentContainer ?Substation .
?Substation cim\:Substation.Region/
cim\:SubGeographicalRegion.Region/
cim\:IdentifiedObject.name ?area .
FILTER (REGEX(?area,'\${region}'))
Keeps only transformers inside substations whose area name matches the ${region} regex.
2) Modeling a “branch” per transformer end
- “Dummy” node:
?p_transformer cim:IdentifiedObject.mRID ?node_2 .The transformer’s mRID is reused as a pseudo node (?node_2). In the final SELECT it’s exposed as?connectivity_node_2. - Select the transformer end (winding):
?winding cim\:TransformerEnd.Terminal ?terminal ;
cim\:IdentifiedObject.mRID ?mrid ;
cim\:IdentifiedObject.name ?name ;
cim\:PowerTransformerEnd.PowerTransformer ?p\_transformer ;
cim\:PowerTransformerEnd.ratedU ?ubase ;
cim\:PowerTransformerEnd.r ?r ;
cim\:PowerTransformerEnd.x ?x ;
cim\:PowerTransformerEnd.b ?b ;
cim\:PowerTransformerEnd.g ?g .
Each end contributes its series impedance (r,x) and shunt b,g, plus its rated voltage ?ubase.
3) Clock angle and real network node
- Phase-angle clock (vector group position) is optional:
OPTIONAL { ?winding cim\:PowerTransformerEnd.phaseAngleClock ?aclock . }
BIND (COALESCE(?aclock, 0.0) AS ?angleclock)
If absent, default is 0.
- Real connectivity node and nominal voltage:
?terminal cim\:Terminal.ConnectivityNode ?con\_node .
?con\_node cim\:ConnectivityNode.ConnectivityNodeContainer/
cim\:VoltageLevel.BaseVoltage/
cim\:BaseVoltage.nominalVoltage ?un ;
cim\:IdentifiedObject.mRID ?connectivity\_node\_1 .
This gives the actual node id (?connectivity_node_1) and its nominal voltage ?un.
4) Optional active power limit (rate)
- If there’s an
ActivePowerLimiton the same terminal with name exactly${rate}, its value is returned as?rate:
OPTIONAL {
?\_lim a cim\:ActivePowerLimit ;
cim\:OperationalLimit.OperationalLimitSet/cim\:OperationalLimitSet.Terminal ?terminal ;
cim\:IdentifiedObject.name '\${rate}' ;
cim\:ActivePowerLimit.value ?rate .
}
5) Network-analysis enable flag
- Some datasets gate equipment by
SN:Equipment.networkAnalysisEnable:
OPTIONAL { ?p\_transformer SN\:Equipment.networkAnalysisEnable ?\_network\_analysis } .
BIND (COALESCE(?\_network\_analysis, True) AS ?network\_analysis)
FILTER (?network\_analysis)
Only ends from equipment enabled for network analysis are kept (defaulting to enabled if the flag is missing).
6) Tap-changer handling and voltage ratio
- Optional ratio tap-changer facts per end:
OPTIONAL {
?tap\_changer cim\:RatioTapChanger.TransformerEnd ?winding ;
cim\:RatioTapChanger.stepVoltageIncrement ?inc ;
cim\:TapChanger.neutralStep ?neutral\_step ;
cim\:TapChanger.normalStep ?normal\_step
} .
BIND (COALESCE(?tap\_changer, [http://non-existing-tap-changer](http://non-existing-tap-changer)) AS ?ratio\_tap\_changer)
- Operating step:
OPTIONAL { ?ratio\_tap\_changer cim\:TapChanger.step ?ssh\_step } .
BIND (COALESCE(?ssh\_step, ?normal\_step) AS ?step)
Prefers an SSH (state) step; falls back to equipment normalStep.
- Tap ratio multiplier
?tau:
BIND (IF(BOUND(?inc),
1 + (xsd\:integer(STR(?step)) - xsd\:integer(STR(?neutral\_step)))
\* xsd\:double(STR(?inc)) / 100.0,
1.0) AS ?tau)
If stepVoltageIncrement (?inc, in %) exists, scale around neutralStep. Otherwise no scaling.
- Final per-end ratio (base adjustment by nominal/rated U):
BIND (xsd\:double(STR(?un)) \* ?tau / xsd\:double(STR(?ubase)) AS ?ratio)
Casts to numbers robustly via STR(...) then xsd:double(...).
7) Phase angle from clock
BIND (xsd\:double(30.0) \* ?angleclock AS ?angle)
Each clock position corresponds to 30 electrical degrees (e.g., clock 1 → 30°, 6 → 180°).
8) Status resolution (service vs. connected)
Outside the SERVICE block the query consults operational state:
?terminal cim\:ACDCTerminal.connected ?connected .
OPTIONAL { ?winding ^cim\:SvStatus.ConductingEquipment/cim\:SvStatus.inService ?in\_service } .
BIND (COALESCE(?in\_service, ?connected) AS ?status)
If a state variable (SvStatus.inService) exists, it wins; otherwise the terminal’s connected flag is used.
9) Final projection
The top-level SELECT returns:
?status— resolved in-service/connected flag.- Identification:
?name,?mrid. - Electrical:
?un,?r,?x,?b,?g,?rate(optional). - Tap-derived:
?angle,?ratio. - Topology:
?connectivity_node_1(real node) and?connectivity_node_2(the dummy node, i.e., the transformer’s mRID via(?node_2 AS ?connectivity_node_2)).
Result interpretation. Each row describes one transformer end as a branch from the real connectivity node to a per-transformer dummy node, carrying per-end impedance/admittance, status, and tap-influenced ratio/angle. This shape is convenient for building branch lists in power-flow tools, especially when transformers are modeled by their individual ends.
Original SPARQL
# Name: Transformer branches
PREFIX cim: <http://iec.ch/TC57/2013/CIM-schema-cim16#>
PREFIX SN: <http://www.statnett.no/CIM-schema-cim15-extension#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
# Name: Transformer branches
SELECT ?status ?name ?mrid ?un ?r ?x ?b ?g ?rate ?angle ?ratio ?connectivity_node_1 (?node_2 AS ?connectivity_node_2) WHERE {
{
SELECT * WHERE {
?_eq_subject <http://entsoe.eu/CIM/EquipmentCore/3/1> ?eq_repo .
SERVICE ?eq_repo {
# Use mrid of transformer as dummy node
?p_transformer cim:IdentifiedObject.mRID ?node_2 ;
cim:Equipment.EquipmentContainer ?Substation .
?Substation cim:Substation.Region/cim:SubGeographicalRegion.Region/cim:IdentifiedObject.name ?area .
FILTER (REGEX(?area,'${region}'))
# Extract properties for the windings associated with p_transformer
?winding cim:TransformerEnd.Terminal ?terminal ;
cim:IdentifiedObject.mRID ?mrid ;
cim:IdentifiedObject.name ?name ;
cim:PowerTransformerEnd.PowerTransformer ?p_transformer ;
cim:PowerTransformerEnd.ratedU ?ubase ;
cim:PowerTransformerEnd.r ?r ;
cim:PowerTransformerEnd.x ?x ;
cim:PowerTransformerEnd.b ?b ;
cim:PowerTransformerEnd.g ?g .
OPTIONAL {
?winding cim:PowerTransformerEnd.phaseAngleClock ?aclock .
}
BIND (COALESCE(?aclock, 0.0) AS ?angleclock)
# Extract the connectivity node for each termina, and find the nominal voltage from the connectivity node
?terminal cim:Terminal.ConnectivityNode ?con_node .
?con_node cim:ConnectivityNode.ConnectivityNodeContainer/cim:VoltageLevel.BaseVoltage/cim:BaseVoltage.nominalVoltage ?un ;
cim:IdentifiedObject.mRID ?connectivity_node_1 .
# Optionally extract active power limits
OPTIONAL {
?_lim a cim:ActivePowerLimit ;
cim:OperationalLimit.OperationalLimitSet/cim:OperationalLimitSet.Terminal ?terminal ;
cim:IdentifiedObject.name '${rate}' ;
cim:ActivePowerLimit.value ?rate .
}
OPTIONAL {
?p_transformer SN:Equipment.networkAnalysisEnable ?_network_analysis
} .
OPTIONAL {
?tap_changer cim:RatioTapChanger.TransformerEnd ?winding ;
cim:RatioTapChanger.stepVoltageIncrement ?inc ;
cim:TapChanger.neutralStep ?neutral_step ;
cim:TapChanger.normalStep ?normal_step
} .
BIND (COALESCE(?tap_changer, <http://non-existing-tap-changer>) AS ?ratio_tap_changer)
}
}
}
?terminal cim:ACDCTerminal.connected ?connected .
OPTIONAL {
?winding ^cim:SvStatus.ConductingEquipment/cim:SvStatus.inService ?in_service
} .
OPTIONAL {
?ratio_tap_changer cim:TapChanger.step ?ssh_step
} .
BIND (COALESCE(?ssh_step, ?normal_step) AS ?step)
BIND (IF(BOUND(?inc),1 + (xsd:integer(STR(?step)) - xsd:integer(STR(?neutral_step))) * xsd:double(STR(?inc)) / 100.0,1.0) AS ?tau)
BIND (COALESCE(?_network_analysis, True) AS ?network_analysis)
FILTER (?network_analysis)
# Assign status flag to the transformer. The first that exists is used
# 1) in_service flag on the transformer
# 2) Connected flag for the terminal
BIND (COALESCE(?in_service, ?connected) AS ?status)
BIND (xsd:double(STR(?un)) * ?tau / xsd:double(STR(?ubase)) AS ?ratio)
BIND (xsd:double(30.0) * ?angleclock AS ?angle)
}
transformer_center_nodes
Question
Which connectivity nodes (and their substations, voltages, bidding zones, and islands) are associated with the “end 1” side of power transformers that are enabled for network analysis?
TLDR;
Fetches the connectivity node on terminal end number 1 of each power transformer (from a remote equipment repository), along with substation info, base voltage, bidding zone EIC, and topological island name; defaults missing “networkAnalysisEnable” to true and excludes equipment where it’s false. (Note: as written, the FILTER(?network_analysis) occurs before the BIND that defines it, which can eliminate all results depending on the SPARQL engine.)
Explanation
This query stitches together equipment data from a remote repository with local/topological context to list “bus-like” nodes tied to the first end of each power transformer.
Prefixes
cim:: IEC CIM v16 core.SN:: Statnett CIM extensions.entsoeSecretariat:: ENTSO-E Secretariat profile extensions.
High-level flow
- Discover the remote equipment repository
?\_eq\_subject [http://entsoe.eu/CIM/EquipmentCore/3/1](http://entsoe.eu/CIM/EquipmentCore/3/1) ?eq\_repo .
The triple encodes a pointer to an equipment dataset/endpoint. That value is used in a federated SERVICE.
- (OPTIONAL) Island lookup from topology
OPTIONAL {
?con\_node cim\:ConnectivityNode.TopologicalNode ?top\_node .
?top\_node ^cim\:TopologicalIsland.TopologicalNodes/cim\:IdentifiedObject.name ?island\_name
} .
- From a
ConnectivityNodereach itsTopologicalNode. - Use a reverse path
^cim:TopologicalIsland.TopologicalNodesto find the containingTopologicalIslandand get its name. - This entire step is optional; if no island is found, a default will be applied later.
- Federated query to the equipment repository
SERVICE ?eq\_repo {
?p\_transformer cim\:IdentifiedObject.mRID ?node ;
cim\:IdentifiedObject.name ?busname ;
cim\:Equipment.EquipmentContainer ?container .
?winding cim:TransformerEnd.endNumber 1 ; cim:PowerTransformerEnd.PowerTransformer ?p_transformer ; cim:TransformerEnd.Terminal ?terminal .
?terminal cim:Terminal.ConnectivityNode ?con_node .
?con_node cim:IdentifiedObject.mRID ?connectivity_node ; cim:ConnectivityNode.ConnectivityNodeContainer/cim:VoltageLevel.BaseVoltage ?base_voltage .
?container cim:IdentifiedObject.mRID ?container_mrid ; cim:IdentifiedObject.name ?container_name . ?container SN:Substation.MarketDeliveryPoint/ SN:MarketDeliveryPoint.BiddingArea/ entsoeSecretariat:IdentifiedObject.energyIdentCodeEIC ?bidzone .
OPTIONAL { ?p_transformer SN:Equipment.networkAnalysisEnable ?_network_analysis }
?base_voltage cim:IdentifiedObject.mRID ?base_voltage_mrid ; cim:BaseVoltage.nominalVoltage ?un
}
- Transformer selection: grabs each
PowerTransformer(?p_transformer) and its mRID (?node) and name (?busname), plus its equipment container (aVoltageLevel’sSubstation). - End 1 only: picks the
TransformerEndwithendNumber 1, then follows to itsTerminaland on to theConnectivityNode(?con_node). This yields the “bus” on the transformer’s end 1 side. - Voltage & IDs: from the
ConnectivityNode, navigate to itsVoltageLevel.BaseVoltageand pull base-voltage mRID and nominal voltage (?un). - Substation & bidding zone: from the container, get both ID/name and the market delivery point → bidding area → EIC code (
?bidzone). - Network-analysis flag:
SN:Equipment.networkAnalysisEnableis optional; if missing, we will treat it as enabled.
- Enable/disable logic via COALESCE
BIND (COALESCE(?\_network\_analysis, True) AS ?network\_analysis)
- If the transformer lacks the
networkAnalysisEnableflag, assumeTrue.
- Filter to enabled equipment
FILTER (?network\_analysis)
- Keeps only equipment where the computed
?network_analysisis true.
Important caveat: In standard SPARQL evaluation, variables used in FILTER must be in scope at that point. Here, FILTER(?network_analysis) appears before the BIND that creates ?network_analysis. On many engines this makes the filter evaluate with ?network_analysis unbound (EBV error), effectively discarding all results. To ensure the intended behavior, move the FILTER after the BIND, or filter directly on COALESCE(?_network_analysis, true):
- Option A (reorder):
BIND(COALESCE(?_network_analysis, true) AS ?network_analysis) FILTER(?network_analysis) - Option B (inline):
FILTER(COALESCE(?_network_analysis, true))
- Island defaulting
BIND (COALESCE(?island\_name, "Unknown") AS ?island)
- If the optional island lookup failed, set island to
"Unknown".
- Projected variables / aliases
?node: transformer mRID (id).?busname: transformer name (used here as a “bus” label).?substation: alias of?container_name.?un: nominal base voltage.?base_voltage_mrid: base voltage ID.?substation_mrid: alias of?container_mrid.?bidzone: EIC of the bidding area.?island: island name (or"Unknown").?is_swing_bus: hard-codedFalse.?connectivity_node: the node mRID on the end-1 terminal.?sv_voltage: duplicate of?un(projected again for downstream compatibility).
What it returns conceptually One row per power transformer end-1 connectivity node that is “network-analysis enabled,” enriched with substation identifiers/names, base-voltage info, the market bidding zone, and the topological island label.
Suggested robustness tweaks
- Move the
FILTER(?network_analysis)after theBIND, or inline theCOALESCEin theFILTER. - Consider guarding the federated
SERVICEwith error handling (engine-specific) if?eq_repocan be missing. - Ensure the island OPTIONAL either runs after
?con_nodeis guaranteed bound (or rely on the engine’s join semantics as-is).
Original SPARQL
# Name: Transformer center nodes
PREFIX cim: <http://iec.ch/TC57/2013/CIM-schema-cim16#>
PREFIX SN: <http://www.statnett.no/CIM-schema-cim15-extension#>
PREFIX entsoeSecretariat: <http://entsoe.eu/Secretariat/ProfileExtension/1#>
SELECT ?node ?busname (?container_name AS ?substation) ?un ?base_voltage_mrid (?container_mrid AS ?substation_mrid) ?bidzone ?island ( False as ?is_swing_bus) ?connectivity_node (?un AS ?sv_voltage) WHERE {
OPTIONAL {
?con_node cim:ConnectivityNode.TopologicalNode ?top_node .
?top_node ^cim:TopologicalIsland.TopologicalNodes/cim:IdentifiedObject.name ?island_name
} .
?_eq_subject <http://entsoe.eu/CIM/EquipmentCore/3/1> ?eq_repo .
SERVICE ?eq_repo {
?p_transformer cim:IdentifiedObject.mRID ?node ;
cim:IdentifiedObject.name ?busname ;
cim:Equipment.EquipmentContainer ?container .
?winding cim:TransformerEnd.endNumber 1 ;
cim:PowerTransformerEnd.PowerTransformer ?p_transformer ;
cim:TransformerEnd.Terminal ?terminal .
?terminal cim:Terminal.ConnectivityNode ?con_node .
?con_node cim:IdentifiedObject.mRID ?connectivity_node ;
cim:ConnectivityNode.ConnectivityNodeContainer/cim:VoltageLevel.BaseVoltage ?base_voltage .
?container cim:IdentifiedObject.mRID ?container_mrid ;
cim:IdentifiedObject.name ?container_name .
?container SN:Substation.MarketDeliveryPoint/SN:MarketDeliveryPoint.BiddingArea/entsoeSecretariat:IdentifiedObject.energyIdentCodeEIC ?bidzone
OPTIONAL {
?p_transformer SN:Equipment.networkAnalysisEnable ?_network_analysis
}
?base_voltage cim:IdentifiedObject.mRID ?base_voltage_mrid ;
cim:BaseVoltage.nominalVoltage ?un
}
FILTER (?network_analysis)
BIND (COALESCE(?_network_analysis, True) AS ?network_analysis)
BIND (COALESCE(?island_name, "Unknown") AS ?island)
}
transformer_winding_angle
Question
What is the present phase-shift angle (in degrees) of each phase-shifting transformer winding, computed from its tap position relative to neutral, and what is the associated equipment mRID?
TLDR;
For each phase tap changer, pick the current tap position (prefer state variable SvTapStep if available, otherwise TapChanger.step from SSH), subtract the neutral step, multiply by the phase-shift increment per step, and report the resulting angle with the winding’s mRID.
Explanation
1) Inputs & namespaces
cim:is the IEC CIM v16 namespace;xsd:provides numeric casts.- The query works across profiles: SSH/SV for operational state, and EQ for static equipment data.
2) Getting a tap changer and its “best-known” position
?tap_changer cim:TapChanger.step ?ssh_position .
OPTIONAL {
?tap_changer ^cim:SvTapStep.TapChanger/cim:SvTapStep.position ?sv_position
}
BIND (COALESCE(?sv_position, ?ssh_position) AS ?position)
cim:TapChanger.stepis the steady‑state hypothesis (SSH) configured position.- The OPTIONAL block tries to read the live state variable
cim:SvTapStep.position(SV). COALESCEprefers?sv_position(if present) and falls back to?ssh_position, giving a single “effective”?position.
3) Federated hop into the Equipment profile (EQ)
?_eq_subject <http://entsoe.eu/CIM/EquipmentCore/3/1> ?eq_repo .
SERVICE ?eq_repo { ... }
- A data triple encodes (or references) the EQ SPARQL endpoint as
?eq_repo. SERVICE ?eq_repo { ... }runs a federated subquery against the EQ dataset to fetch static design data for each tap changer.
4) Equipment data required for angle computation and identification
Inside the SERVICE block:
?tap_changer
cim:PhaseTapChangerLinear.stepPhaseShiftIncrement ?inc ;
cim:TapChanger.neutralStep ?neutralstep ;
^cim:TransformerEnd.PhaseTapChanger/cim:IdentifiedObject.mRID ?mrid .
cim:PhaseTapChangerLinear.stepPhaseShiftIncrement (?inc)is the per‑step phase shift (typically degrees/step).cim:TapChanger.neutralStep (?neutralstep)is the position that yields zero phase shift.^cim:TransformerEnd.PhaseTapChangerwalks from the tap changer back to itsTransformerEnd; from there,cim:IdentifiedObject.mRIDgives the stable identifier?mridfor that end (the winding terminal in EQ).
5) Final numeric computation
BIND ((xsd:double(STR(?position)) - xsd:double(STR(?neutralstep))) * xsd:double(STR(?inc)) AS ?angle)
- Ensures numeric arithmetic by string‑casting then
xsd:double‑casting each term (guards against mixed literal types). - Formula:
angle = (position − neutralStep) × stepPhaseShiftIncrement - This yields the current phase‑shift angle in degrees for the winding associated with
?mrid.
6) Output
SELECT ?mrid ?angle
- For each applicable tap changer / transformer end, the query returns the equipment
mRIDand the computed angle.
Key SPARQL techniques used
- Inverse property paths (
^prop) to navigate from a tap changer to its transformer end. - Federated queries (
SERVICE ?eq_repo) to join runtime state with equipment design data stored in a separate endpoint. - OPTIONAL + COALESCE to prefer live state (
SV) over planned state (SSH) seamlessly. - Explicit numeric casting to ensure reliable arithmetic across differently typed literals.
Original SPARQL
# Name: Winding transformer angle
PREFIX cim: <http://iec.ch/TC57/2013/CIM-schema-cim16#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
SELECT ?mrid ?angle WHERE {
?tap_changer cim:TapChanger.step ?ssh_position .
OPTIONAL {
?tap_changer ^cim:SvTapStep.TapChanger/cim:SvTapStep.position ?sv_position
} .
?_eq_subject <http://entsoe.eu/CIM/EquipmentCore/3/1> ?eq_repo .
SERVICE ?eq_repo {
?tap_changer cim:PhaseTapChangerLinear.stepPhaseShiftIncrement ?inc ;
cim:TapChanger.neutralStep ?neutralstep ;
^cim:TransformerEnd.PhaseTapChanger/cim:IdentifiedObject.mRID ?mrid .
}
BIND (COALESCE(?sv_position, ?ssh_position) AS ?position)
BIND ((xsd:double(STR(?position)) - xsd:double(STR(?neutralstep))) * xsd:double(STR(?inc)) AS ?angle)
}
transformer_windings
Question
What are the windings of each power transformer, including the transformer's ID, the winding's ID, and the winding's end number?
TLDR;
This query lists all power transformers and their associated windings, showing the transformer's unique ID, each winding's unique ID, and the winding's connection end number.
Explanation
The query is structured to extract details about power transformers and their windings from a CIM dataset.
-
Prefixes
- The
cim:prefix points to the IEC CIM 16 schema, which defines all the classes and properties used.
- The
-
Main transformer selection
?power_transformer a cim:PowerTransformer ; cim:IdentifiedObject.mRID ?mrid .This line finds all instances ofcim:PowerTransformerand retrieves their unique identifier (mRID).
-
Winding association
?winding cim:IdentifiedObject.mRID ?w_mrid ; cim:PowerTransformerEnd.PowerTransformer ?power_transformer ; cim:TransformerEnd.endNumber ?end_numberThis line:- Finds winding objects (
?winding). - Gets their unique identifier (
?w_mrid). - Links them back to their parent transformer through
cim:PowerTransformerEnd.PowerTransformer. - Retrieves the
endNumberproperty, which indicates the winding's connection point in the transformer (e.g., primary, secondary).
- Finds winding objects (
-
Result columns
- The query outputs three pieces of information:
?mrid→ Power transformer’s ID.?end_number→ Winding end number.?w_mrid→ Winding’s ID.
- The query outputs three pieces of information:
Essentially, this query gives a mapping of each transformer to each winding, with enough data to identify both uniquely and understand their connection points.
Original SPARQL
# Name: Transformer Windings
PREFIX cim: <http://iec.ch/TC57/2013/CIM-schema-cim16#>
SELECT ?mrid ?end_number ?w_mrid WHERE {
?power_transformer a cim:PowerTransformer ;
cim:IdentifiedObject.mRID ?mrid .
?winding cim:IdentifiedObject.mRID ?w_mrid ;
cim:PowerTransformerEnd.PowerTransformer ?power_transformer ;
cim:TransformerEnd.endNumber ?end_number
}
transformers
Question
Which power transformers and their windings are in a sub-geographical region matching ${region}, what are their key electrical parameters (name, mRIDs, end number, rated voltage, r, x, terminal), and—if present—what is the value of the active power limit named ${rate}—but only for transformers that have network analysis enabled (or default to enabled when not specified)?
TLDR;
Return one row per transformer winding within the selected region, including winding/transformer identifiers and electrical parameters, optionally joining a named active power limit, and filtering to only equipment with networkAnalysisEnable true (defaulting to true when the flag is absent).
Explanation
-
Prefixes
- Uses the CIM 16 namespace (
cim:) and a Statnett-specific extension namespace (SN:).
- Uses the CIM 16 namespace (
-
Core transformer selection
?p_transformer a cim:PowerTransformer ; cim:IdentifiedObject.mRID ?p_mrid ; ...- From each PowerTransformer we extract its mRID (
?p_mrid) and navigate up its containment to derive the area name:
This property path walks: Transformer → its EquipmentContainer (e.g., substation) → the substation’s Region → the parent SubGeographicalRegion’s Region → that region’s name.cim:Equipment.EquipmentContainer / cim:Substation.Region / cim:SubGeographicalRegion.Region / cim:IdentifiedObject.name ?area
-
Winding join and electrical parameters
- Each PowerTransformerEnd (winding) linked to the transformer is bound as
?winding:?winding cim:PowerTransformerEnd.PowerTransformer ?p_transformer ; cim:PowerTransformerEnd.ratedU ?un ; cim:PowerTransformerEnd.r ?r ; cim:PowerTransformerEnd.x ?x ; cim:IdentifiedObject.mRID ?w_mrid ; cim:IdentifiedObject.name ?name ; cim:TransformerEnd.endNumber ?end_number ; cim:TransformerEnd.Terminal/cim:IdentifiedObject.mRID ?t_mrid . - This yields the winding’s rated voltage (
?un), series resistance/reactance (?r,?x), winding mRID (?w_mrid), winding name (?name), end number (?end_number), and the associated terminal mRID (?t_mrid).
- Each PowerTransformerEnd (winding) linked to the transformer is bound as
-
Region filtering
FILTER REGEX(?area,'${region}')- Keeps only transformers whose derived area name matches the (injected) regular expression
${region}. This allows partial matches; it’s case-sensitive by default unless your SPARQL endpoint treats it otherwise. If you need exact or case-insensitive matching, you’d typically adjust the pattern or use flags (e.g.,'(?i)^...$').
-
Optional active power limit lookup
- Optional block:
?p_lim a cim:ActivePowerLimit ; cim:OperationalLimit.OperationalLimitSet / cim:OperationalLimitSet.Equipment ?winding ; cim:IdentifiedObject.name '${rate}' ; cim:ActivePowerLimit.value ?rate . - If there exists an ActivePowerLimit whose OperationalLimitSet applies to this winding and whose name equals the injected literal
${rate}, its value is returned as?rate. If no such limit exists,?rateis unbound for that row. - Note: If multiple limits match (e.g., multiple sets or duplicate names), the query may produce duplicate rows—one per matching limit.
- Optional block:
-
Network analysis enable flag (Statnett extension)
- Optional read of a Statnett extension flag on the transformer:
OPTIONAL { ?p_transformer SN:Equipment.networkAnalysisEnable ?_analysis_enabled . } BIND (COALESCE(?_analysis_enabled, True) AS ?analysis_enabled) FILTER (?analysis_enabled) - Logic:
- If the flag exists, use its value.
- If it’s absent, default to
TrueviaCOALESCE, treating the transformer as enabled. - The
FILTERthen keeps only rows where?analysis_enabledis true.
- Implementation note: In SPARQL,
FILTERapplies to the bindings available at its position in the pattern. To be strictly safe across engines, place theFILTER (?analysis_enabled)after theBIND(as shown above). Some engines reorder, but relying on that can be brittle.
- Optional read of a Statnett extension flag on the transformer:
-
Projected variables
SELECT ?name ?p_mrid ?w_mrid ?end_number ?un ?t_mrid ?r ?x ?rate- Output includes key identifiers and parameters for each winding, plus the optional
?rate.
-
Cardinality & duplicates
- The query returns one row per winding (and per matching limit, if present). Because of optional joins (limits, terminals) and property paths, multiple rows can appear for the same winding if there are multiple terminals or multiple matching limits. Use
DISTINCTor further constraints if you need unique rows.
- The query returns one row per winding (and per matching limit, if present). Because of optional joins (limits, terminals) and property paths, multiple rows can appear for the same winding if there are multiple terminals or multiple matching limits. Use
-
Parameters and templating
${region}and${rate}appear to be template placeholders injected by the calling application. Ensure${region}is a safe regex (escape special characters when needed) and${rate}matches the exactIdentifiedObject.nameused for the active power limit you want.
Original SPARQL
# Name: Transformers
PREFIX cim: <http://iec.ch/TC57/2013/CIM-schema-cim16#>
PREFIX SN: <http://www.statnett.no/CIM-schema-cim15-extension#>
SELECT ?name ?p_mrid ?w_mrid ?end_number ?un ?t_mrid ?r ?x ?rate WHERE {
# Extract mRID for each power transformer
?p_transformer a cim:PowerTransformer ;
cim:IdentifiedObject.mRID ?p_mrid ;
cim:Equipment.EquipmentContainer/cim:Substation.Region/cim:SubGeographicalRegion.Region/cim:IdentifiedObject.name ?area .
?winding cim:PowerTransformerEnd.PowerTransformer ?p_transformer ;
cim:PowerTransformerEnd.ratedU ?un ;
cim:PowerTransformerEnd.r ?r ;
cim:PowerTransformerEnd.x ?x ;
cim:IdentifiedObject.mRID ?w_mrid ;
cim:IdentifiedObject.name ?name ;
cim:TransformerEnd.endNumber ?end_number ;
cim:TransformerEnd.Terminal/cim:IdentifiedObject.mRID ?t_mrid ;
FILTER REGEX(?area,'${region}') .
OPTIONAL {
?p_lim cim:OperationalLimit.OperationalLimitSet/cim:OperationalLimitSet.Equipment ?winding ;
a cim:ActivePowerLimit ;
cim:IdentifiedObject.name '${rate}' ;
cim:ActivePowerLimit.value ?rate
}
OPTIONAL {
?p_transformer SN:Equipment.networkAnalysisEnable ?_analysis_enabled .
}
FILTER (?analysis_enabled)
BIND (COALESCE(?_analysis_enabled, True) AS ?analysis_enabled)
}
transformers_connected_to_converter
Question
Which power transformers are connected to DC converters in a specified geographical region, and what are their associated mRIDs and terminal mRIDs?
TLDR;
The query finds all power transformers that are connected to certain types of DC converters (like voltage source or current source converters) within a specified region, retrieving their mRIDs, names, and the mRIDs of their first winding terminals, while ensuring both the transformer and converter are enabled for network analysis.
Explanation
This SPARQL query identifies power transformers connected to converters by:
-
Selecting Converter Types The query limits
?converterto specific CIM and vendor-specific converter classes:cim:VsConverter,cim:CsConverter,cim:DCConvertUnit(standard CIM types)ALG:VoltageSourceConverter,ALG:DCConverter(vendor extensions)
-
Retrieving Converter mRID Each converter must have a
cim:IdentifiedObject.mRIDvalue, which is stored as?mrid. -
Finding Connected Power Transformers A
cim:PowerTransformeris identified with:- Its own
mRIDas?p_mrid - Its alias name as
?name - A region name (
?area) determined through the equipment container → substation → sub-geographical region → geographical region hierarchy. - Connectivity is determined by traversing from the transformer’s terminals through
cim:ConnectivityNodelinks back to the converter's terminals.
- Its own
-
Identifying the First Winding Terminal Only the terminal for winding number 1 (
cim:TransformerEnd.endNumber 1) is retrieved, and its mRID is stored as?t_mrid. -
Filtering by Region The
FILTER REGEX(?area,'${region}')ensures results only come from the region of interest. -
Checking Network Analysis Enable Flags The query optionally retrieves
SN:Equipment.networkAnalysisEnablefor both transformers and converters. If the flag is missing, it defaults toTrueusingCOALESCE. Only equipment with the flag set toTrueis included. -
Ensuring Unique Results
SELECT DISTINCTremoves duplicates, which can occur if converters appear in both EQ and SSH profiles.
In essence, the query walks the network model to find transformers directly connected to specific types of DC converters, filters them by region and network-analysis-enabled status, and outputs both transformer and terminal identifiers.
Original SPARQL
# Name: Transforers connected to converter
PREFIX ALG: <http://www.alstom.com/grid/CIM-schema-cim15-extension#>
PREFIX SN: <http://www.statnett.no/CIM-schema-cim15-extension#>
PREFIX cim: <http://iec.ch/TC57/2013/CIM-schema-cim16#>
# TODO: We probably need distinct since we get a hit on cim:VsConverter in SSH-profile and ALG:VoltageSourceConverter
# in EQ-repo. This was caused by correcting the ALG-namespace which lacked # at the end
SELECT DISTINCT ?mrid ?name ?t_mrid ?p_mrid WHERE {
VALUES ?converter_type { cim:VsConverter cim:CsConverter cim:DCConvertUnit ALG:VoltageSourceConverter ALG:DCConverter }
# Extract mRID for the converters
?converter a ?converter_type ;
cim:IdentifiedObject.mRID ?mrid .
# Extract mRID name for the power transformer associated with the converter
?p_transformer a cim:PowerTransformer ;
cim:IdentifiedObject.mRID ?p_mrid ;
cim:IdentifiedObject.aliasName ?name ;
cim:Equipment.EquipmentContainer/cim:Substation.Region/cim:SubGeographicalRegion.Region/cim:IdentifiedObject.name ?area ;
^cim:Terminal.ConductingEquipment/cim:Terminal.ConnectivityNode/^cim:Terminal.ConnectivityNode/cim:Terminal.ConductingEquipment ?converter .
# Extract the mRID of the terminal associated with the first winding on each power transformer
?winding cim:PowerTransformerEnd.PowerTransformer ?p_transformer ;
cim:TransformerEnd.endNumber 1 ;
cim:TransformerEnd.Terminal/cim:IdentifiedObject.mRID ?t_mrid .
FILTER REGEX(?area,'${region}')
OPTIONAL {
?p_transformer SN:Equipment.networkAnalysisEnable ?_transformer_analysis_enabled .
}
OPTIONAL {
?converter SN:Equipment.networkAnalysisEnable ?_converter_analysis_enabled .
}
BIND (COALESCE(?_transformer_analysis_enabled, True) AS ?transformer_analysis_enabled)
BIND (COALESCE(?_converter_analysis_enabled, True) AS ?converter_analysis_enabled)
FILTER (?transformer_analysis_enabled)
FILTER (?converter_analysis_enabled)
}
type_mapper
Question
For each CIM attribute (SPARQL property), what is the underlying literal datatype it should map to, whether it is a Primitive or a CIMDatatype with a value?
TLDR;
Builds a lookup table from CIM attribute properties to their effective literal ranges by handling two cases: direct Primitive datatypes and CIMDatatype wrappers whose value points to the underlying primitive type.
Explanation
This query produces pairs of (?sparql_type, ?range) that tell you which literal datatype a given CIM attribute (expressed as an RDF/OWL property) should use.
It does this with two UNIONed patterns:
- Direct Primitive datatype
?sparql_type ^rdfs:domain/cims:dataType ?range . ?range cims:stereotype "Primitive"
^rdfs:domainwalks backwards from a class to the property whose domain is that class. In other words, it finds properties?sparql_typesuch that there exists some classXwith?sparql_type rdfs:domain X.cims:dataTypeon that classXpoints to a datatype resource?range.- The filter
?range cims:stereotype "Primitive"limits to plain primitive datatypes (e.g.,String,Integer,Boolean), so the mapping is direct: the attribute’s range is that primitive.
-
CIMDatatype wrapper with a
valueslot?sparql_type ^rdfs:domain/cims:dataType ?_dtype . ?_dtype cims:stereotype "CIMDatatype" . ?_dtype_value rdfs:domain ?_dtype ; rdfs:label "value"@en ; cims:dataType ?range-
Some attributes are typed not by a primitive directly, but by a CIMDatatype (a structured/value object such as
DateTime,UnitMultiplier, etc.). -
For such a datatype
?_dtype, the query finds its internal property (here bound as?_dtype_value) that:- has
rdfs:domain ?_dtype(i.e., belongs to that datatype), - is labeled
"value"@en, and - itself declares
cims:dataType ?range.
- has
-
This extracts the underlying primitive carried by the CIMDatatype’s
valuefield, yielding the effective literal range for the original attribute.
-
Finally, SELECT DISTINCT deduplicates results in case the same mapping is discoverable via multiple paths or model profiles.
Why this matters:
CIM profiles often model attributes via metaclasses where rdfs:domain and cims:dataType sit on a “slot” class rather than directly on the property. This query normalizes both modeling styles—direct primitives and wrapper CIMDatatypes—into a single, usable mapping from SPARQL attribute properties to concrete literal types.
Original SPARQL
# Name: Type mapper
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX cims: <http://iec.ch/TC57/1999/rdf-schema-extensions-19990926#>
SELECT DISTINCT ?sparql_type ?range WHERE {
{
?sparql_type ^rdfs:domain/cims:dataType ?range .
?range cims:stereotype "Primitive"
}
UNION {
?sparql_type ^rdfs:domain/cims:dataType ?_dtype .
?_dtype cims:stereotype "CIMDatatype" .
?_dtype_value rdfs:domain ?_dtype ;
rdfs:label "value"@en ;
cims:dataType ?range
}
}
wind_generating_units
Question
Which wind generating units (that are enabled for network analysis) exist in the model, and what are their IDs, names, min/max operating power, market code, station group, and associated wind power plant mRID?
TLDR;
Return all cim:WindGeneratingUnit instances with their mRID, name, min/max operating P, and (optionally) their market code, station group, and parent wind power plant mRID. The query intends to include only units where SN:Equipment.networkAnalysisEnable is true (defaulting to true when the flag is missing).
Explanation
Prefixes
cim:points to the IEC CIM v16 namespace.SN:points to Statnett’s CIM extension namespace.
Core pattern
?wind_gen_unit a cim:WindGeneratingUnit ;
cim:IdentifiedObject.mRID ?mrid ;
cim:IdentifiedObject.name ?name ;
cim:GeneratingUnit.maxOperatingP ?max_p ;
cim:GeneratingUnit.minOperatingP ?min_p .
This selects every resource typed as a cim:WindGeneratingUnit and extracts its:
- unique identifier (
?mrid) - human‑readable name (
?name) - operating limits (
?min_p,?max_p)
Optional commercial/plant context
OPTIONAL {
?wind_gen_unit
SN:WindGeneratingUnit.WindPowerPlant/cim:IdentifiedObject.mRID ?plant_mrid ;
SN:GeneratingUnit.marketCode ?market_code ;
SN:GeneratingUnit.ScheduleResource/SN:ScheduleResource.marketCode ?station_group .
}
SN:WindGeneratingUnit.WindPowerPlant/cim:IdentifiedObject.mRIDis a property path: from the wind unit, follow the Statnett link to itsWindPowerPlant, then read that plant’smRIDinto?plant_mrid.SN:GeneratingUnit.marketCodereads a market code directly associated with the generating unit.SN:GeneratingUnit.ScheduleResource/SN:ScheduleResource.marketCodeis another path: from the unit to itsScheduleResource, then read that resource’s market code into?station_group. All three are optional: if any link is missing, the respective variable is simply unbound (NULL in the result).
Optional network‑analysis flag & filtering
OPTIONAL { ?wind_gen_unit SN:Equipment.networkAnalysisEnable ?_network_analysis }
FILTER (?network_analysis)
BIND (COALESCE(?_network_analysis, True) AS ?network_analysis)
- The model may store a boolean flag
SN:Equipment.networkAnalysisEnableindicating whether the equipment should be considered in network analysis runs. It is read into the temporary variable?_network_analysis. BIND (COALESCE(..., True) AS ?network_analysis)is intended to default the flag totruewhen it is absent: if?_network_analysisis unbound,COALESCEyieldsTrue.FILTER (?network_analysis)then keeps only rows where the effective flag istrue.
Important execution‑order note
In SPARQL, solution modifiers are applied in the written order within the group pattern. As written, the FILTER (?network_analysis) appears before BIND (...), which means ?network_analysis is unbound at filter time. An unbound variable in a FILTER expression evaluates to an error, which filters the row out. This would unintentionally drop all rows where the flag is missing, defeating the “default to True” intent.
To achieve the intended behavior, put the BIND before the FILTER:
OPTIONAL { ?wind_gen_unit SN:Equipment.networkAnalysisEnable ?_network_analysis }
BIND (COALESCE(?_network_analysis, True) AS ?network_analysis)
FILTER (?network_analysis)
With this order:
- If the flag is present and
true, the row stays. - If the flag is present and
false, the row is removed. - If the flag is absent,
COALESCEsets it totrue, and the row stays.
Result set
The SELECT projects:
?mrid ?name ?market_code ?station_group ?min_p ?max_p ?plant_mrid
?market_code,?station_group, and?plant_mridmay be unbound (NULL) when the optional data is not present.- If a unit is linked to multiple schedule resources (or other multi‑valued properties), the query can produce multiple rows per unit (cartesian expansion). Add
SELECT DISTINCT ...if you want to de‑duplicate.
Practical tips
- Ensure boolean literals are actual booleans in the store (e.g.,
"true"^^xsd:boolean) soFILTER (?network_analysis)works as expected. - If you need to exclude units that lack the flag rather than defaulting to
true, drop theCOALESCEand filter directly on?_network_analysis.
OPTIONAL { ?wind_gen_unit SN:Equipment.networkAnalysisEnable ?_network_analysis }
FILTER (BOUND(?_network_analysis) && ?_network_analysis)
Original SPARQL
# Name: Wind generating units
PREFIX cim: <http://iec.ch/TC57/2013/CIM-schema-cim16#>
PREFIX SN: <http://www.statnett.no/CIM-schema-cim15-extension#>
SELECT ?mrid ?name ?market_code ?station_group ?min_p ?max_p ?plant_mrid WHERE {
?wind_gen_unit a cim:WindGeneratingUnit ;
cim:IdentifiedObject.mRID ?mrid ;
cim:IdentifiedObject.name ?name ;
cim:GeneratingUnit.maxOperatingP ?max_p ;
cim:GeneratingUnit.minOperatingP ?min_p .
OPTIONAL {
?wind_gen_unit SN:WindGeneratingUnit.WindPowerPlant/cim:IdentifiedObject.mRID ?plant_mrid ;
SN:GeneratingUnit.marketCode ?market_code ;
SN:GeneratingUnit.ScheduleResource/SN:ScheduleResource.marketCode ?station_group .
}
OPTIONAL {
?wind_gen_unit SN:Equipment.networkAnalysisEnable ?_network_analysis
}
FILTER (?network_analysis)
BIND (COALESCE(?_network_analysis, True) AS ?network_analysis)
}
winding
Question
For each power transformer, how many windings does it have, how many of those are “in service,” what’s the transformer’s name, and what is the summed active power flowing at the winding terminals?
TLDR;
Group transformer windings by their parent cim:PowerTransformer (via cim:PowerTransformerEnd.PowerTransformer). Count windings, sum a boolean “in‑service” flag into ?nr_on, and sum terminal active power ?sv_p into ?p. Fetch equipment model data through a federated SERVICE endpoint discovered at runtime.
Explanation
What the query returns (grouped per transformer ?p_transformer):
?count: number of windings (one percim:TransformerEnd).?name: the transformer's name (taken asMAX(?_name); acts like “any” when names are identical).?nr_on: how many windings are effectively considered “on/in service.”?p: sum of active power injections at the windings’ terminals.
How it finds and aggregates windings
- Each row starts from a winding (a
cim:TransformerEndthat is part of acim:PowerTransformer):?winding cim:PowerTransformerEnd.PowerTransformer ?p_transformer ; cim:TransformerEnd.Terminal ?terminal . ?p_transformer cim:IdentifiedObject.name ?_name .
* `?terminal` is the AC/DC terminal associated with that winding.
**Getting state & telemetry (optionally)**
* `SvStatus.inService` (boolean) per **conducting equipment** of the winding:
```sparql
OPTIONAL { ?winding ^cim:SvStatus.ConductingEquipment/cim:SvStatus.inService ?_in_service . }
-
Topology connection state on the terminal:
OPTIONAL { ?terminal cim:ACDCTerminal.connected ?_connected . } -
Steady‑state active power at the terminal:
OPTIONAL { ?terminal ^cim:SvPowerFlow.Terminal/cim:SvPowerFlow.p ?_sv_p . }
Federated access to the equipment repository
-
The line
?_eq_subject <http://entsoe.eu/CIM/EquipmentCore/3/1> ?eq_repo . SERVICE ?eq_repo { ... }discovers the equipment model endpoint IRI at runtime (
?eq_repo) and then runs the equipment‑side pattern inside that remote/service graph. This is a data‑driven federation: the local store holds a pointer to the remote equipment dataset.
Deriving the flags and numeric measures
-
Count each winding:
BIND (1 AS ?_count) -
Default terminal connection when missing, then derive an “in service” indicator:
BIND (COALESCE(?_connected, 1) AS ?connected) BIND (IF(COALESCE(?_in_service, ?connected), 1, 0) AS ?in_service)The intention is:
- If
SvStatus.inServiceexists, use it. - Otherwise fall back to
ACDCTerminal.connected. - If both are missing, default to “on”.
Spec nuance: In SPARQL,
IF()expects a boolean Effective Boolean Value (EBV). Using1(an integer) as a fallback inCOALESCEcan yield an EBV error on some engines. A safer, standards‑compliant variant is:BIND (COALESCE(?_connected, true) AS ?_is_connected) # boolean default BIND (COALESCE(?_in_service, ?_is_connected) AS ?_is_on) # boolean BIND (IF(?_is_on, 1, 0) AS ?in_service) # numeric for SUM() - If
-
Power defaulting and summation:
BIND (COALESCE(?_sv_p, xsd:double(0.0)) AS ?sv_p)Then
(SUM(xsd:double(STR(?sv_p))) AS ?p)converts to string and back to double before summing. If
?sv_pis alreadyxsd:double,SUM(?sv_p)suffices and is cleaner.
Grouping
GROUP BY ?p_transformer
Aggregates all winding rows per transformer.
Why MAX(?_name) for name?
- Within a group,
?p_transformershould have a single name. UsingMAXis a common trick to pick that single value without adding it toGROUP BY. If names could differ (data quality issue), you’d insteadGROUP_CONCAT(DISTINCT ?_name; separator=", ")or return the transformer name from a separate query.
Potential data‑shape pitfalls & tips
- Duplicate rows: If the model contains multiple
SvPowerFlowentries per terminal/time or multiple terminals/endings per winding, you might over‑count. UseSELECT DISTINCTinside theSERVICEblock or aggregate earlier to avoid duplication. - Type safety: Prefer boolean fallbacks (
true/false) when building EBV conditions; avoid numeric literals (1/0) inside boolean expressions. - Units & sign convention:
SvPowerFlow.poften uses MW and a sign convention (positive for injection, negative for consumption). Ensure your downstream interpretation matches your CIM profile. - Null‑tolerant sums: The
COALESCEon?sv_pensures missing flows don’t nullify the group sum.
Minimal, standards‑friendly rewrite (same output, safer booleans):
PREFIX cim: <http://iec.ch/TC57/2013/CIM-schema-cim16#>
PREFIX SN: <http://www.statnett.no/CIM-schema-cim15-extension#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
SELECT ?p_transformer
(SUM(?_count) AS ?count)
(MAX(?_name) AS ?name)
(SUM(?in_service) AS ?nr_on)
(SUM(?sv_p) AS ?p)
WHERE {
OPTIONAL { ?winding ^cim:SvStatus.ConductingEquipment/cim:SvStatus.inService ?_in_service . }
OPTIONAL { ?terminal cim:ACDCTerminal.connected ?_connected . }
OPTIONAL { ?terminal ^cim:SvPowerFlow.Terminal/cim:SvPowerFlow.p ?_sv_p . }
?_eq_subject <http://entsoe.eu/CIM/EquipmentCore/3/1> ?eq_repo .
SERVICE ?eq_repo {
?winding cim:PowerTransformerEnd.PowerTransformer ?p_transformer ;
cim:TransformerEnd.Terminal ?terminal .
?p_transformer cim:IdentifiedObject.name ?_name .
}
BIND (COALESCE(?_connected, true) AS ?_is_connected)
BIND (COALESCE(?_in_service, ?_is_connected) AS ?_is_on)
BIND (IF(?_is_on, 1, 0) AS ?in_service)
BIND (COALESCE(xsd:double(?_sv_p), 0.0) AS ?sv_p)
BIND (1 AS ?_count)
}
GROUP BY ?p_transformer
Original SPARQL
# Name: Windings
PREFIX cim: <http://iec.ch/TC57/2013/CIM-schema-cim16#>
PREFIX SN: <http://www.statnett.no/CIM-schema-cim15-extension#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
SELECT ?p_transformer (SUM(?_count) AS ?count) (MAX(?_name) AS ?name) (SUM(?in_service) AS ?nr_on) (SUM(xsd:double(STR(?sv_p))) AS ?p) WHERE {
OPTIONAL {
?winding ^cim:SvStatus.ConductingEquipment/cim:SvStatus.inService ?_in_service .
} .
OPTIONAL {
?terminal cim:ACDCTerminal.connected ?_connected .
}
OPTIONAL {
?terminal ^cim:SvPowerFlow.Terminal/cim:SvPowerFlow.p ?_sv_p .
}
?_eq_subject <http://entsoe.eu/CIM/EquipmentCore/3/1> ?eq_repo .
SERVICE ?eq_repo {
?winding cim:PowerTransformerEnd.PowerTransformer ?p_transformer ;
cim:TransformerEnd.Terminal ?terminal .
?p_transformer cim:IdentifiedObject.name ?_name .
}
BIND (COALESCE(?_connected, 1) AS ?connected)
BIND (IF(COALESCE(?_in_service, ?connected),1,0) AS ?in_service) .
BIND (COALESCE(?_sv_p, xsd:double(0.0)) AS ?sv_p)
BIND (1 AS ?_count)
}
GROUP BY ?p_transformer
winding_loss
Question
For each power transformer, what is the per‑branch (per in‑service winding/terminal) active‑power loss based on steady‑state terminal measurements, considering only transformers enabled for network analysis?
TLDR;
Group terminals by their parent transformer, sum terminal active power SvPowerFlow.p across the transformer's windings (proxy for transformer total losses), then divide by the number of in‑service windings to get a per‑branch loss value.
Explanation
What it returns (per transformer ?mrid):
?ploss_2— computed asSUM(sv_p) / SUM(in_service)where:sv_pis terminal active power (defaults to0.0if missing).in_serviceis1if the winding is effectively on, else0.
Core data paths
- Start from each terminal that has a connection state:
?terminal cim:ACDCTerminal.connected ?connected .
-
Optionally pull steady‑state power and equipment service flag:
OPTIONAL { ?terminal ^cim:SvPowerFlow.Terminal/cim:SvPowerFlow.p ?_sv_p . } OPTIONAL { ?winding ^cim:SvStatus.ConductingEquipment/cim:SvStatus.inService ?_in_service . } -
Federate into the equipment repository to relate windings/terminals to their transformer and fetch the transformer mRID (and area):
?_eq_subject <http://entsoe.eu/CIM/EquipmentCore/3/1> ?eq_repo . SERVICE ?eq_repo { ?winding cim:PowerTransformerEnd.PowerTransformer ?p_transformer ; cim:TransformerEnd.Terminal ?terminal . ?p_transformer cim:IdentifiedObject.mRID ?mrid ; cim:Equipment.EquipmentContainer/cim:Substation.Region/ cim:SubGeographicalRegion.Region/cim:IdentifiedObject.name ?area . OPTIONAL { ?p_transformer SN:Equipment.networkAnalysisEnable ?_network_analysis } FILTER (REGEX(?area, '.*')) # logically redundant; always true }
Flags and numeric bindings
-
Effective in‑service indicator uses
SvStatus.inServiceif present, else falls back to terminal connectivity:BIND (IF(COALESCE(?_in_service, ?connected), 1, 0) AS ?in_service) -
Default missing power to zero and coerce to numeric:
BIND (COALESCE(?_sv_p, xsd:double(0.0)) AS ?sv_p) -
Only keep transformers enabled for network analysis, defaulting missing flag to
true:BIND (COALESCE(?_network_analysis, True) AS ?network_analysis) FILTER (?network_analysis)
Aggregation
SELECT ?mrid
(SUM(xsd:double(STR(?sv_p))) / SUM(?in_service) AS ?ploss_2)
...
GROUP BY ?mrid
SUM(?sv_p)across all the transformer's terminals estimates total transformer losses (sum of terminal injections equals losses by convention).- Dividing by
SUM(?in_service)yields an average per in‑service branch loss (i.e., per winding/terminal).
Notes & caveats
- The
REGEX(?area, '.*')filter is a no‑op; it can be removed unless it’s deliberately used to force?areabinding or exploit an index hint on some engines. - Casting via
xsd:double(STR(?sv_p))is defensive; if?sv_pis already numeric you can simply useSUM(?sv_p). - Beware division by zero if all windings are out of service for a transformer (
SUM(?in_service) = 0); consider guarding withFILTER(SUM(?in_service) > 0)in a subquery or computing?ploss_2after aggregation. - Sign conventions for
SvPowerFlow.pmatter (positive injection vs. consumption). The sum should reflect the chosen convention where the transformer's net terminal sum approximates losses. - The mandatory
?terminal cim:ACDCTerminal.connected ?connectedtriple excludes terminals lacking an explicit connectivity value; if you want to include them as connected by default, make itOPTIONALand default withCOALESCE.
Original SPARQL
# Name: Transformer branches loss
PREFIX cim: <http://iec.ch/TC57/2013/CIM-schema-cim16#>
PREFIX SN: <http://www.statnett.no/CIM-schema-cim15-extension#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
SELECT ?mrid (SUM(xsd:double(STR(?sv_p))) / SUM(?in_service) AS ?ploss_2) WHERE {
?terminal cim:ACDCTerminal.connected ?connected .
OPTIONAL {
?terminal ^cim:SvPowerFlow.Terminal/cim:SvPowerFlow.p ?_sv_p .
}
OPTIONAL {
?winding ^cim:SvStatus.ConductingEquipment/cim:SvStatus.inService ?_in_service
} .
?_eq_subject <http://entsoe.eu/CIM/EquipmentCore/3/1> ?eq_repo .
SERVICE ?eq_repo {
# Extract mRID and area for each power transformer
?winding cim:PowerTransformerEnd.PowerTransformer ?p_transformer ;
cim:TransformerEnd.Terminal ?terminal .
?p_transformer cim:IdentifiedObject.mRID ?mrid ;
cim:Equipment.EquipmentContainer/cim:Substation.Region/cim:SubGeographicalRegion.Region/cim:IdentifiedObject.name ?area .
FILTER (REGEX(?area,'.*'))
OPTIONAL {
?p_transformer SN:Equipment.networkAnalysisEnable ?_network_analysis
}
}
BIND (IF(COALESCE(?_in_service, ?connected),1,0) AS ?in_service) .
BIND (COALESCE(?_sv_p, xsd:double(0.0)) AS ?sv_p)
BIND (COALESCE(?_network_analysis, True) AS ?network_analysis)
FILTER (?network_analysis)
}
GROUP BY ?mrid