From 3892137c6a0705ceac9169d63a1b629603996633 Mon Sep 17 00:00:00 2001 From: David Kleiven Date: Tue, 28 Feb 2023 14:47:32 +0000 Subject: [PATCH] Refactor two_winding_transformer query such that we extract everything at once. Refactor to run from situation repo (reduce number of federated calls) --- .../sparql/two_winding_transformer.sparql | 143 ++++++++---------- tests/test_graphdb.py | 6 + 2 files changed, 72 insertions(+), 77 deletions(-) diff --git a/cimsparql/sparql/two_winding_transformer.sparql b/cimsparql/sparql/two_winding_transformer.sparql index 698f7565..ec9896a8 100644 --- a/cimsparql/sparql/two_winding_transformer.sparql +++ b/cimsparql/sparql/two_winding_transformer.sparql @@ -2,99 +2,88 @@ PREFIX cim: <${cim}> PREFIX SN: <${SN}> PREFIX xsd: <${xsd}> -select ?mrid ?name ?bidzone_1 ?bidzone_2 ?node_1 ?node_2 ?ploss_1 ?ploss_2 ?r ?rate ?status (?un_1 as ?un) ?x ?b ?g ?angle ?ratio +select + # max(?mrid) returns the mrid of the primary winding + (max(?mrid) as ?mrid) + (max(?name) as ?name) + (max(?bidzone) as ?bidzone_1) + (max(?bidzone) as ?bidzone_2) + (max(?node_1) as ?node_1) + (max(?node_2) as ?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) + (sum(xsd:double(str(?r))) as ?r) + (max(?rate) as ?rate) + (coalesce(max(?in_service), max(?connected_1) && max(?connected_2), True) as ?status) + + # Since the mrid is for winding 1, set un_1 as ?un + (xsd:double(max(?un_1)) as ?un) + (sum(xsd:double(str(?x))) as ?x) + (sum(xsd:double(str(?b))) as ?b) + (sum(xsd:double(str(?g))) as ?g) + (sum(?angle) as ?angle) + # ratio: n = Us / Up (secondary (2) / primary (1)) + ((xsd:double(max(?ubase_2)) / xsd:double(max(?un_2))) / (xsd:double(max(?ubase_1)) / xsd:double(max(?un_1))) as ?ratio) where { - # Extract two winding transformers - { - select ?p_transformer (count(distinct ?nr) as ?winding_count) - where { - ?p_transformer a cim:PowerTransformer; - ^cim:PowerTransformerEnd.PowerTransformer/cim:TransformerEnd.endNumber ?nr . - } - group by ?p_transformer - having (?winding_count = 2) - } . - ?p_transformer cim:IdentifiedObject.name ?name; - cim:Equipment.EquipmentContainer ?Substation; - cim:Equipment.EquipmentContainer/cim:Substation.Region/cim:SubGeographicalRegion.Region/cim:IdentifiedObject.name ?area . - filter(regex(?area, '${region}')) - optional {?Substation SN:Substation.MarketDeliveryPoint/SN:MarketDeliveryPoint.BiddingArea/SN:BiddingArea.marketCode ?bidzone} . - { # Search for winding 1 side - select ?p_transformer ?mrid (?un as ?un_1) (?ubase as ?ubase_1) ?r ?x ?b ?g ?connected_1 (?p as ?p_1) ?node_1 ?rate - where - { - ?winding cim:TransformerEnd.Terminal ?terminal; + service <${eq_repo}> { + ?winding cim:TransformerEnd.Terminal ?terminal; cim:PowerTransformerEnd.ratedU ?ubase; cim:PowerTransformerEnd.PowerTransformer ?p_transformer; cim:PowerTransformerEnd.r ?r; cim:PowerTransformerEnd.x ?x; cim:PowerTransformerEnd.b ?b; cim:PowerTransformerEnd.g ?g; - cim:IdentifiedObject.mRID ?mrid; - cim:TransformerEnd.endNumber 1 . + cim:IdentifiedObject.mRID ?w_mrid; + cim:TransformerEnd.endNumber ?nr . + optional{?winding cim:PowerTransformerEnd.phaseAngleClock ?aclock .} ?terminal cim:IdentifiedObject.mRID ?t_mrid; cim:Terminal.ConnectivityNode ?con_node . ?con_node cim:ConnectivityNode.ConnectivityNodeContainer/cim:VoltageLevel.BaseVoltage/cim:BaseVoltage.nominalVoltage ?un . + ?p_transformer cim:IdentifiedObject.name ?name; + cim:Equipment.EquipmentContainer ?substation; + cim:Equipment.EquipmentContainer/cim:Substation.Region/cim:SubGeographicalRegion.Region/cim:IdentifiedObject.name ?area . optional { ?p_lim cim:OperationalLimit.OperationalLimitSet/cim:OperationalLimitSet.Terminal ?terminal; a cim:ActivePowerLimit; cim:IdentifiedObject.name '${rate}'; - cim:ActivePowerLimit.value ?rate + cim:ActivePowerLimit.value ?w_rate } . + optional {?substation SN:Substation.MarketDeliveryPoint/SN:MarketDeliveryPoint.BiddingArea/SN:BiddingArea.marketCode ?bidzone} . + optional {?p_transformer SN:Equipment.networkAnalysisEnable ?network_analysis .} + filter(regex(?area, '${region}')) + } + ?terminal cim:ACDCTerminal.connected ?connected . + optional {?con_node cim:ConnectivityNode.TopologicalNode/cim:IdentifiedObject.mRID ?con_top_node_mrid .} + optional {?terminal cim:Terminal.TopologicalNode/cim:IdentifiedObject.mRID ?term_top_node_mrid .} + optional {?terminal ^cim:SvPowerFlow.Terminal/cim:SvPowerFlow.p ?p .} + optional {?p_transformer ^cim:SvStatus.ConductingEquipment/cim:SvStatus.inService ?in_service .} - # Extract mRID of the topological node associated with connectivity node - optional { service <${repo}> {?con_node cim:ConnectivityNode.TopologicalNode/cim:IdentifiedObject.mRID ?con_top_node_mrid .}} + # Assign mRID to ?node. Use the first existing + # 1) mRID of the topological node associated with the connectivity node for each terminal + # 2) mRID of the topological node associated with the terminal + bind(coalesce(?con_top_node_mrid, ?term_top_node_mrid) as ?node) - # Extract connected flag, opertionally power flow as well as optionally mRID of the topological node associated with the terminal - service <${repo}> { - ?terminal cim:Terminal.connected|cim:ACDCTerminal.connected ?connected_1; - optional {?terminal cim:Terminal.TopologicalNode/cim:IdentifiedObject.mRID ?term_top_node_mrid .} - optional {?terminal ^cim:SvPowerFlow.Terminal/cim:SvPowerFlow.p ?p .} - } + # Only include results where a connection to a topological node exists + filter(?node) - # Assign mRID to ?node_1. Use the first existing - # 1) mRID of the topological node associated with the connectivity node for each terminal - # 2) mRID of the topological node associated with the terminal - # 3) mRID of the terminal - bind(coalesce(?con_top_node_mrid, ?term_top_node_mrid, ?t_mrid) as ?node_1) - } - } . - { # Search for winding 2 side - select ?p_transformer (?un as ?un_2) (?ubase as ?ubase_2) ?connected_2 (?p as ?p_2) ?node_2 ?angle - where - { - ?winding cim:TransformerEnd.Terminal ?terminal; - cim:PowerTransformerEnd.ratedU ?ubase; - cim:PowerTransformerEnd.PowerTransformer ?p_transformer; - cim:TransformerEnd.endNumber 2 . - optional{?winding cim:PowerTransformerEnd.phaseAngleClock ?aclock .} - bind(coalesce(?aclock, 0.0) as ?angleclock) - ?terminal cim:IdentifiedObject.mRID ?t_mrid; - cim:Terminal.ConnectivityNode ?con_node. - ?con_node cim:ConnectivityNode.ConnectivityNodeContainer/cim:VoltageLevel.BaseVoltage/cim:BaseVoltage.nominalVoltage ?un . - optional { service <${repo}> {?con_node cim:ConnectivityNode.TopologicalNode/cim:IdentifiedObject.mRID ?con_top_node_mrid .}} - service <${repo}> { - ?terminal cim:Terminal.connected|cim:ACDCTerminal.connected ?connected_2 . - optional {?terminal cim:Terminal.TopologicalNode/cim:IdentifiedObject.mRID ?term_top_node_mrid .} - optional {?terminal ^cim:SvPowerFlow.Terminal/cim:SvPowerFlow.p ?p . } - } - bind(coalesce(?con_top_node_mrid, ?term_top_node_mrid, ?t_mrid) as ?node_2) - bind(xsd:double(30.0) * ?angleclock as ?angle) - } - } - optional { - bind((xsd:double(str(?p_1)) + xsd:double(str(?p_2))) as ?pl) - bind(if (xsd:double(str(?p_1)) > xsd:double(str(?p_2)), ?pl, xsd:double(0.0)) as ?ploss_2) - bind(if (xsd:double(str(?p_1)) < xsd:double(str(?p_2)), ?pl, xsd:double(0.0)) as ?ploss_1) - } - service <${repo}> {optional {?p_transformer ^cim:SvStatus.ConductingEquipment/cim:SvStatus.inService ?in_service}} - optional {?p_transformer SN:Equipment.networkAnalysisEnable ?_network_analysis} - bind(coalesce(?_network_analysis, True) as ?network_analysis) - filter(?network_analysis) - bind(coalesce(?in_service, ?connected_1 && ?connected_2) as ?status) - # ratio: n = Us / Up (secondary (2) / primary (1)) - bind((xsd:double(str(?ubase_2)) / xsd:double(str(?un_2))) / (xsd:double(str(?ubase_1)) / xsd:double(str(?un_1))) as ?ratio) - bind(?bidzone as ?bidzone_1) - bind(?bidzone as ?bidzone_2) -} + # Winding properties should be extracted only for winding 1. Set the value for winding 2 to 0.0, such that max + # aggregation will pick the value for winding 1 + bind(if(?nr = 1, ?w_mrid, '') as ?mrid) + + # Create variables for node 1 and node 2 + bind(if(?nr = 1, str(?p), '') as ?p_1) + bind(if(?nr = 1, ?node, '') as ?node_1) + bind(if(?nr = 1, ?connected, False) as ?connected_1) + bind(if(?nr = 1, str(?un), '') as ?un_1) + bind(if(?nr = 1, str(?ubase), '') as ?ubase_1) + bind(if(?nr = 2, str(?p), '') as ?p_2) + bind(if(?nr = 2, ?node, '') as ?node_2) + bind(if(?nr = 2, ?connected, False) as ?connected_2) + bind(if(?nr = 2, str(?un), '') as ?un_2) + bind(if(?nr = 2, str(?ubase), '') as ?ubase_2) + + # Extract only angle clock for winding 2 (set to 0 for winding 1) + bind(xsd:double(30.0) * coalesce(?angleclock, 0.0) as ?angle) +} group by ?p_transformer +having ((count(*) = 2) && coalesce(max(?analysis_enabled), True)) diff --git a/tests/test_graphdb.py b/tests/test_graphdb.py index 356ee7dd..90a98763 100644 --- a/tests/test_graphdb.py +++ b/tests/test_graphdb.py @@ -235,3 +235,9 @@ def test_custom_headers(graphdb_client: Callable): custom_headers = {"my_header": "my_header_value"} client = graphdb_client(ServiceConfig(server="some-server"), custom_headers) assert client.sparql.customHttpHeaders == custom_headers + + +@pytest.mark.asyncio +async def test_two_winding_transformers(model: CimModel): + df = await model.two_winding_transformers() + assert len(df) == 1326