From d6d13fbf067964ed5ab960d9fe32f36cda8c5c13 Mon Sep 17 00:00:00 2001 From: Leif Warland Date: Thu, 2 Nov 2023 14:43:16 +0100 Subject: [PATCH] WIP --- cimsparql/data_models.py | 18 ++-- cimsparql/model.py | 7 +- cimsparql/sparql/ac_lines.sparql | 16 +-- cimsparql/sparql/branch_node_withdraw.sparql | 8 +- cimsparql/sparql/bus.sparql | 6 +- .../sparql/converter_hvdc_bidzones.sparql | 33 +++--- cimsparql/sparql/converters.sparql | 42 ++++---- cimsparql/sparql/dc_active_power_flow.sparql | 102 +++++++++--------- cimsparql/sparql/loads.sparql | 17 ++- cimsparql/sparql/ras_equipment.sparql | 4 +- cimsparql/sparql/series_compensators.sparql | 58 +++++----- .../station_group_code_and_names.sparql | 10 +- cimsparql/sparql/synchronous_machines.sparql | 56 ++++------ cimsparql/sparql/three_winding.sparql | 15 ++- .../sparql/three_winding_dummy_nodes.sparql | 12 ++- .../sparql/two_winding_transformer.sparql | 17 ++- tests/test_graphdb.py | 6 +- 17 files changed, 200 insertions(+), 227 deletions(-) diff --git a/cimsparql/data_models.py b/cimsparql/data_models.py index b215d5d8..f2395cde 100644 --- a/cimsparql/data_models.py +++ b/cimsparql/data_models.py @@ -22,7 +22,8 @@ class FullModelSchema(JsonSchemaOut): @pa.dataframe_check def unique_time(cls, df: DataFrame) -> bool: - return len(df["time"].unique()) == 1 + n = len(df["time"].unique()) + return n == 1 or n == 0 FullModelDataFrame = DataFrame[FullModelSchema] @@ -76,8 +77,6 @@ class BusDataSchema(JsonSchemaOut): class LoadsSchema(NamedResourceSchema): node: Series[str] = pa.Field() - substation_mrid: Series[str] = pa.Field() - bidzone: Series[str] = pa.Field(nullable=True) status: Series[bool] = pa.Field() p: Series[float] = pa.Field(nullable=True) q: Series[float] = pa.Field(nullable=True) @@ -88,7 +87,7 @@ class LoadsSchema(NamedResourceSchema): LoadsDataFrame = DataFrame[LoadsSchema] -class WindGeneratingUnitsSchema(NamedMarketResourceSchema): +class WindGeneratingUnitsSchema(NamedResourceSchema): station_group: Series[str] = pa.Field(nullable=True) min_p: Series[float] = pa.Field() max_p: Series[float] = pa.Field() @@ -98,7 +97,7 @@ class WindGeneratingUnitsSchema(NamedMarketResourceSchema): WindGeneratingUnitsDataFrame = DataFrame[WindGeneratingUnitsSchema] -class SynchronousMachinesSchema(NamedMarketResourceSchema): +class SynchronousMachinesSchema(NamedResourceSchema): node: Series[str] = pa.Field() status: Series[bool] = pa.Field() station_group: Series[str] = pa.Field(nullable=True) @@ -107,7 +106,6 @@ class SynchronousMachinesSchema(NamedMarketResourceSchema): maxP: Series[float] = pa.Field(nullable=True) # noqa N815 minP: Series[float] = pa.Field(nullable=True) # noqa N815 MO: Series[float] = pa.Field(nullable=True) - bidzone: Series[str] = pa.Field(nullable=True) sn: Series[float] = pa.Field() p: Series[float] = pa.Field(nullable=True) q: Series[float] = pa.Field(nullable=True) @@ -177,8 +175,6 @@ class CoordinatesSchema(JsonSchemaOut): class BranchComponentSchema(NamedResourceSchema): - bidzone_1: Series[str] = pa.Field(nullable=True) - bidzone_2: Series[str] = pa.Field(nullable=True) node_1: Series[str] = pa.Field() node_2: Series[str] = pa.Field() ploss_1: Series[float] = pa.Field(nullable=True) @@ -295,9 +291,13 @@ class StationGroupCodeNameSchema(JsonSchemaOut): StationGroupCodeNameDataFrame = DataFrame[StationGroupCodeNameSchema] -class HVDCBidzonesSchema(MridResourceSchema): +class HVDCBidzonesSchema(JsonSchemaOut): bidzone_1: Series[str] = pa.Field() bidzone_2: Series[str] = pa.Field() + converter_1: Series[str] = pa.Field() + converter_2: Series[str] = pa.Field() + name_1: Series[str] = pa.Field() + name_2: Series[str] = pa.Field() HVDCBidzonesDataFrame = DataFrame[HVDCBidzonesSchema] diff --git a/cimsparql/model.py b/cimsparql/model.py index 9b641947..c3b1cdfd 100644 --- a/cimsparql/model.py +++ b/cimsparql/model.py @@ -528,9 +528,8 @@ async def dc_active_flow(self, region: str | None = None) -> DcActiveFlowDataFra query = self.dc_active_flow_query(region) df = await self.get_table_and_convert(query) # Unable to group on max within the sparql query so we do it here. - df = df.iloc[df.groupby("mrid")["p"].idxmax()].set_index("mrid") - df["p"] *= df["direction"] - return DcActiveFlowDataFrame(df.drop(columns="direction")) + df = df.iloc[df.eval("p_abs = abs(p)").groupby("mrid")["p_abs"].idxmax()].set_index("mrid") + return DcActiveFlowDataFrame(df) @property def sv_injection_query(self) -> str: @@ -570,7 +569,7 @@ async def hvdc_converter_bidzones(self) -> HVDCBidzonesDataFrame: Fetching mrid of converters placed on HVDC exchange corridors together with to/from bidzone """ - df = await self.get_table_and_convert(self.hvdc_converter_bidzone_query, index="mrid") + df = await self.get_table_and_convert(self.hvdc_converter_bidzone_query) return HVDCBidzonesDataFrame(df) @property diff --git a/cimsparql/sparql/ac_lines.sparql b/cimsparql/sparql/ac_lines.sparql index b19b2f13..e448ded2 100644 --- a/cimsparql/sparql/ac_lines.sparql +++ b/cimsparql/sparql/ac_lines.sparql @@ -1,7 +1,7 @@ # Name: AC Lines PREFIX cim: <${cim}> -PREFIX SN: <${SN}> PREFIX xsd: <${xsd}> +PREFIX pti:<${pti}> 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 @@ -11,8 +11,6 @@ select # thus max-aggregation will pick True if it exists in the group (max(?mrid) as ?mrid) (max(?name) as ?name) -(max(?bidzone_1) as ?bidzone_1) -(max(?bidzone_2) as ?bidzone_2) (max(?node_1) as ?node_1) (max(?node_2) as ?node_2) @@ -45,19 +43,16 @@ where { ?terminal cim:Terminal.ConductingEquipment ?acline; cim:Terminal.ConnectivityNode ?con_node; - cim:Terminal.sequenceNumber|cim:ACDCTerminal.sequenceNumber ?nr . + cim:ACDCTerminal.sequenceNumber ?nr . # Find substation of each connectivity node of the terminals above ?con_node cim:ConnectivityNode.ConnectivityNodeContainer/cim:VoltageLevel.Substation ?substation . # Find area and optionally bidzone for each substation ?substation cim:Substation.Region/cim:SubGeographicalRegion.Region/cim:IdentifiedObject.name ?area . - optional { - ?substation SN:Substation.MarketDeliveryPoint/SN:MarketDeliveryPoint.BiddingArea/SN:BiddingArea.marketCode ?bidzone . - } optional {?acline cim:ACLineSegment.gch ?g .} - optional {?acline SN:Equipment.networkAnalysisEnable ?analysis_enabled .} + optional {?acline pti:Equipment.excludeFromCase ?exclude_from_case} . # If exists, extract active power limit for acline optional { @@ -86,11 +81,9 @@ where { 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, ?bidzone, '') as ?bidzone_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, ?bidzone, '') as ?bidzone_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}')) @@ -98,5 +91,4 @@ where { # 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(?node_1) != max(?node_2)) && (max(?node_1) != "") && (max(?node_2) != "") && (count(*) > 1) && coalesce(max(?analysis_enabled), True)) +having((max(?node_1) != max(?node_2)) && (max(?node_1) != "") && (max(?node_2) != "") && (count(*) > 1) && coalesce(max(!?exclude_from_case), true)) diff --git a/cimsparql/sparql/branch_node_withdraw.sparql b/cimsparql/sparql/branch_node_withdraw.sparql index 230ddd3d..389733fb 100644 --- a/cimsparql/sparql/branch_node_withdraw.sparql +++ b/cimsparql/sparql/branch_node_withdraw.sparql @@ -1,6 +1,6 @@ # Name: Branch node withdraw PREFIX cim:<${cim}> -PREFIX SN:<${SN}> +PREFIX pti:<${pti}> select ?mrid ?node ?p ?q where { # Extract properties of each terminal from the SV/TP/SSH profile. @@ -18,7 +18,7 @@ where { # 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 .} + optional {?component pti:Equipment.excludeFromCase ?_exclude_from_case} . ?terminal cim:Terminal.ConductingEquipment ?component; cim:IdentifiedObject.mRID ?mrid; cim:Terminal.ConnectivityNode ?con_node. @@ -29,13 +29,13 @@ where { } # Assign analysis enabled (all True if not exist) - bind(coalesce(?_analysis_enabled, True) as ?analysis_enabled) + bind(coalesce(?_exclude_from_case, false) as ?exclude_from_case) # Assign an mRID to the ?node variable. The first that exists is used # 1) mRID of the topological node associated with the connectivity node the terminal # 2) mrID of the topoligical node associated with the terminel # 3) mRID of the terminal bind(coalesce(?con_top_node_mrid, ?term_top_node_mrid, ?mrid) as ?node) - filter(?analysis_enabled) + filter(!?exclude_from_case) filter(?connected) } diff --git a/cimsparql/sparql/bus.sparql b/cimsparql/sparql/bus.sparql index 056b7cc7..29b5f418 100644 --- a/cimsparql/sparql/bus.sparql +++ b/cimsparql/sparql/bus.sparql @@ -1,6 +1,8 @@ # Name: Bus PREFIX cim:<${cim}> -PREFIX SN:<${SN}> +PREFIX entsoe:<${entsoe}> +PREFIX entsoe2:<${entsoe2}> +PREFIX pti:<${pti}> select (?mrid as ?node) ?busname (?substation_name as ?substation) ?un ?substation_mrid ?bidzone ?sv_voltage ?island ?is_swing_bus where { # Extract propertoes from the TP/SV/SSH profile for each topological node @@ -28,6 +30,6 @@ where { 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/SN:BiddingArea.marketCode ?bidzone} . + optional {?_substation pti:Substation.EnergySchedulingArea/entsoe2:EnergySchedulingArea.EnergyCongestionZone/entsoe:IdentifiedObject.energyIdentCodeEic ?bidzone} . FILTER regex(?area, '${region}') } diff --git a/cimsparql/sparql/converter_hvdc_bidzones.sparql b/cimsparql/sparql/converter_hvdc_bidzones.sparql index b41f216c..85a73168 100644 --- a/cimsparql/sparql/converter_hvdc_bidzones.sparql +++ b/cimsparql/sparql/converter_hvdc_bidzones.sparql @@ -1,19 +1,26 @@ # Name: Converter HVDC bidzones PREFIX cim:<${cim}> -PREFIX SN:<${SN}> -PREFIX ALG:<${ALG}> +PREFIX pti:<${pti}> +PREFIX entsoe2:<${entsoe2}> +PREFIX entsoe:<${entsoe}> +select distinct ?bidzone_1 ?bidzone_2 ?converter_1 ?converter_2 ?name_1 ?name_2 +where { + ?line a cim:DCLineSegment; + cim:IdentifiedObject.name ?name. -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. + ?terminal_1 cim:DCTerminal.DCConductingEquipment ?line; + cim:Terminal.sequenceNumber 1; + cim:DCBaseTerminal.DCNode/^cim:DCBaseTerminal.DCNode/cim:ACDCConverterDCTerminal.DCConductingEquipment ?conducting_equipment_1. + ?conducting_equipment_1 ^cim:Terminal.ConductingEquipment/cim:Terminal.ConnectivityNode/cim:ConnectivityNode.ConnectivityNodeContainer/cim:VoltageLevel.Substation/pti:Substation.EnergySchedulingArea/entsoe2:EnergySchedulingArea.EnergyCongestionZone/entsoe:IdentifiedObject.energyIdentCodeEic ?bidzone_1; + cim:IdentifiedObject.mRID ?converter_1; + cim:IdentifiedObject.name ?name_1. - ?delivery_point SN:MarketDeliveryPoint.BiddingArea/SN:BiddingArea.marketCode ?bidzone_1 . + ?terminal_2 cim:DCTerminal.DCConductingEquipment ?line; + cim:Terminal.sequenceNumber 2; + cim:DCBaseTerminal.DCNode/^cim:DCBaseTerminal.DCNode/cim:ACDCConverterDCTerminal.DCConductingEquipment ?conducting_equipment_2. + ?conducting_equipment_2 ^cim:Terminal.ConductingEquipment/cim:Terminal.ConnectivityNode/cim:ConnectivityNode.ConnectivityNodeContainer/cim:VoltageLevel.Substation/pti:Substation.EnergySchedulingArea/entsoe2:EnergySchedulingArea.EnergyCongestionZone/entsoe:IdentifiedObject.energyIdentCodeEic ?bidzone_2; + cim:IdentifiedObject.mRID ?converter_2; + cim:IdentifiedObject.name ?name_2. - # 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) + filter (?bidzone_1 != ?bidzone_2) } diff --git a/cimsparql/sparql/converters.sparql b/cimsparql/sparql/converters.sparql index 7ca5aff4..c9cc97fc 100644 --- a/cimsparql/sparql/converters.sparql +++ b/cimsparql/sparql/converters.sparql @@ -1,8 +1,8 @@ # Name: Converters PREFIX cim:<${cim}> +PREFIX pti:<${pti}> PREFIX xsd:<${xsd}> -PREFIX SN:<${SN}> -select ?mrid ?name ?alias ?p ?q ?substation_mrid ?status ?node ?connectivity_node +select ?mrid ?name ?alias ?p ?q ?substation_mrid ?status ?node ?connectivity_node ?area where { # Extract active and reactive power for the converter ?converter cim:ACDCConverter.p ?p; @@ -18,26 +18,26 @@ where { optional {?con_node cim:ConnectivityNode.TopologicalNode/cim:IdentifiedObject.mRID ?con_top_node_mrid .} service <${eq_repo}> { - # Extract mrid, name, substation and optionally aliasName of the converter - ?converter cim:IdentifiedObject.mRID ?mrid; - cim:IdentifiedObject.name ?name; - cim:Equipment.EquipmentContainer/cim:VoltageLevel.Substation ?substation . - optional {?converter cim:IdentifiedObject.aliasName ?alias .} - - # Find area and mRID for the substation - ?substation cim:Substation.Region/cim:SubGeographicalRegion.Region/cim:IdentifiedObject.name ?area; - cim:IdentifiedObject.mRID ?substation_mrid . - - # 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 . - optional {?converter SN:Equipment.networkAnalysisEnable ?_analysis_enabled .} - filter regex(?area, '${region}') - bind(coalesce(?_analysis_enabled, True) as ?analysis_enabled) - filter(?analysis_enabled) + # Extract mrid, name, substation and optionally aliasName of the converter + ?converter cim:IdentifiedObject.mRID ?mrid; + cim:IdentifiedObject.name ?name; + cim:Equipment.EquipmentContainer/cim:DCConverterUnit.Substation ?substation . + optional {?converter cim:IdentifiedObject.aliasName ?alias} + + # Find area and mRID for the substation + ?substation cim:Substation.Region/cim:SubGeographicalRegion.Region/cim:IdentifiedObject.name ?area; + cim:IdentifiedObject.mRID ?substation_mrid . + + # Extract properties for the terminals for the converter + ?terminal cim:Terminal.ConductingEquipment ?converter; + cim:Terminal.ConnectivityNode ?con_node . + ?con_node cim:IdentifiedObject.mRID ?connectivity_node . + filter regex(?area, '${region}') } + optional {?converter pti:Equipment.excludeFromCase ?_exclude_from_case} . + bind(coalesce(?_exclude_from_case, false) as ?exclude_from_case) + filter (!?exclude_from_case) + # Asiign an mrid to the ?node variable. The first that exists is choden # 1) mRID of the topological node associated with the connectivity node diff --git a/cimsparql/sparql/dc_active_power_flow.sparql b/cimsparql/sparql/dc_active_power_flow.sparql index f7c5c1cd..c48c14d0 100644 --- a/cimsparql/sparql/dc_active_power_flow.sparql +++ b/cimsparql/sparql/dc_active_power_flow.sparql @@ -1,69 +1,65 @@ # Name: DC Active Power Flow PREFIX cim:<${cim}> -PREFIX xsd:<${xsd}> -select ?mrid ?p ?direction +select ?mrid (?direction * xsd:double(str(?_p)) as ?p) where { - ?terminal ^cim:SvPowerFlow.Terminal/cim:SvPowerFlow.p ?p . + ?terminal ^cim:SvPowerFlow.Terminal/cim:SvPowerFlow.p ?_p . service <${eq_repo}> { - {{ - # Declare components we are interested in - values ?rdf_type {cim:ACLineSegment cim:SeriesCompensator} . - ?component a ?rdf_type; + { + { + # 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 properties for the terminal associated with the component + ?terminal cim:Terminal.ConductingEquipment ?component; + cim:ACDCTerminal.sequenceNumber ?nr . + } + union { - select ?p_transformer - where { - ?p_transformer ^cim:PowerTransformerEnd.PowerTransformer/cim:TransformerEnd.endNumber ?nr . - } - group by ?p_transformer - having (count(*) = 2) - } . + { + select ?p_transformer + where {?p_transformer ^cim:PowerTransformerEnd.PowerTransformer/cim:TransformerEnd.endNumber ?nr} + group by ?p_transformer + having (count(*) = 2) + } . - # Extract region pf the power trasnformer - ?p_transformer cim:Equipment.EquipmentContainer/cim:Substation.Region ?region . + # Extract region pf the power trasnformer + ?p_transformer cim:Equipment.EquipmentContainer/cim:Substation.Region ?region . - # Extract information from the windings associated with the power transformer - ?winding cim:PowerTransformerEnd.PowerTransformer ?p_transformer; - cim:TransformerEnd.Terminal ?terminal; - cim:TransformerEnd.endNumber ?nr . + # Extract information from the windings associated with the power transformer + ?winding cim:PowerTransformerEnd.PowerTransformer ?p_transformer; + cim:TransformerEnd.Terminal ?terminal; + cim:TransformerEnd.endNumber ?nr . - # For power transformer extract the winding corresponding to endNumber 1 - ?component cim:PowerTransformerEnd.PowerTransformer ?p_transformer; - cim:TransformerEnd.endNumber 1 . - } - union - { - # Extract all three winding transformers + # For power transformer extract the winding corresponding to endNumber 1 + ?component cim:PowerTransformerEnd.PowerTransformer ?p_transformer; + cim:TransformerEnd.endNumber 1 . + } + union { - select ?p_transformer - where { - ?p_transformer ^cim:PowerTransformerEnd.PowerTransformer/cim:TransformerEnd.endNumber ?nr; - } - group by ?p_transformer - having (count(*) = 3) - } . + # Extract all three winding transformers + { + select ?p_transformer + where {?p_transformer ^cim:PowerTransformerEnd.PowerTransformer/cim:TransformerEnd.endNumber ?nr} + group by ?p_transformer + having (count(*) = 3) + } . - # Extract the region for the transformer - ?p_transformer cim:Equipment.EquipmentContainer/cim:Substation.Region ?region . + # 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 . + # 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) + # Extract the mRID for the component + ?component cim:IdentifiedObject.mRID ?mrid . + filter(regex(?regionName, '${region}')) + bind(if (?nr = 1, 1, -1) as ?direction) } } diff --git a/cimsparql/sparql/loads.sparql b/cimsparql/sparql/loads.sparql index 064ce859..a510d9ec 100644 --- a/cimsparql/sparql/loads.sparql +++ b/cimsparql/sparql/loads.sparql @@ -1,7 +1,7 @@ # Name: Loads PREFIX cim: <${cim}> -PREFIX SN: <${SN}> -select ?mrid ?name ?node ?substation_mrid ?bidzone ?status ?p ?q ?station_group ?connectivity_node +PREFIX pti:<${pti}> +select ?mrid ?name ?node ?status ?p ?q ?station_group ?connectivity_node where { # Extrcact connected flag and optionally the mRID of the topological node associated with the terminal @@ -27,16 +27,15 @@ where { 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 . + ?substation cim:Substation.Region/cim:SubGeographicalRegion.Region/cim:IdentifiedObject.name ?area. + filter regex(?area, '${region}') # Optionally extract bidzone for each substation and station_group for each load - optional {?substation SN:Substation.MarketDeliveryPoint/SN:MarketDeliveryPoint.BiddingArea/SN:BiddingArea.marketCode ?bidzone} . - 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) + optional {?load pti:Equipment.excludeFromCase ?_exclude_from_case} . + bind(coalesce(?_exclude_from_case, false) as ?exclude_from_case) + filter (!?exclude_from_case) + optional {?load cim:NonConformLoad.LoadGroup/pti:NonConformLoadGroup.ScheduleResource/pti:ScheduleResource.marketCode ?station_group} . # Extract mRID and connectivity node for each terminal associated with a load ?terminal cim:Terminal.ConductingEquipment ?load; diff --git a/cimsparql/sparql/ras_equipment.sparql b/cimsparql/sparql/ras_equipment.sparql index f1849638..c16263f3 100644 --- a/cimsparql/sparql/ras_equipment.sparql +++ b/cimsparql/sparql/ras_equipment.sparql @@ -1,10 +1,10 @@ # Name: RAS Equipment PREFIX cim: <${cim}> -PREFIX alg: <${ALG}> +PREFIX icim: <${icim}> select ?mrid ?equipment_mrid ?name where { - ?rpact (alg:ProtectiveActionEquipment.Equipment|alg:ProtectiveActionAdjustmentAC.ConductingEquipment|alg:ProtectiveActionAdjustmentDCController.DCController)/cim:IdentifiedObject.mRID ?equipment_mrid; + ?rpact (icim:ProtectiveActionEquipment.Equipment|icim:ProtectiveActionAdjustment.ConductingEquipment)/cim:IdentifiedObject.mRID ?equipment_mrid; cim:IdentifiedObject.mRID ?mrid; cim:IdentifiedObject.name ?name . } diff --git a/cimsparql/sparql/series_compensators.sparql b/cimsparql/sparql/series_compensators.sparql index 322c1e3e..55c0a402 100644 --- a/cimsparql/sparql/series_compensators.sparql +++ b/cimsparql/sparql/series_compensators.sparql @@ -1,12 +1,10 @@ # Name: Series compensators PREFIX cim: <${cim}> -PREFIX SN: <${SN}> +PREFIX pti: <${pti}> PREFIX xsd: <${xsd}> select (max(?mrid) as ?mrid) (max(?name) as ?name) - (max(?bidzone_1) as ?bidzone_1) - (max(?bidzone_2) 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) @@ -22,38 +20,36 @@ where { # Assume π equivalent with at least r,x and b shunt. # Extract properties for series compensator 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 . + ?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 ; + # 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 { - ?substation SN:Substation.MarketDeliveryPoint/SN:MarketDeliveryPoint.BiddingArea/SN:BiddingArea.marketCode ?bidzone - } - optional {?compensator SN:Equipment.networkAnalysisEnable ?network_analysis} - filter(regex(?area, '${region}')) + ?substation cim:Substation.Region/cim:SubGeographicalRegion.Region/cim:IdentifiedObject.name ?area . + + optional {?compensator pti:Equipment.excludeFromCase ?exclude_from_case} . - # 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) - }.} + filter(regex(?area, '${region}')) + # Optionally extract current limits + optional { + ?_lim cim:OperationalLimit.OperationalLimitSet/cim:OperationalLimitSet.Equipment ?compensator; + 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) + }. + } - # Extract the mRID of the topological node of the connectivity node + # Extract the mRID of the topological node of the connectivity node ?con_node cim:ConnectivityNode.TopologicalNode/cim:IdentifiedObject.mRID ?node_mrid . # Optionally extract in_service associated with compensator optional {?compensator ^cim:SvStatus.ConductingEquipment/cim:SvStatus.inService ?in_service} . @@ -67,12 +63,10 @@ where { 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, ?bidzone, '') as ?bidzone_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, ?bidzone, '') as ?bidzone_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(?node_1) != max(?node_2)) && coalesce(max(?analysis_enabled), True)) +having ((count(*) > 1) && (max(?node_1) != max(?node_2)) && coalesce(max(!?exclude_from_case), True)) diff --git a/cimsparql/sparql/station_group_code_and_names.sparql b/cimsparql/sparql/station_group_code_and_names.sparql index d94003b3..4468b0f8 100644 --- a/cimsparql/sparql/station_group_code_and_names.sparql +++ b/cimsparql/sparql/station_group_code_and_names.sparql @@ -1,10 +1,8 @@ # Name: Station group code and names PREFIX cim: <${cim}> -PREFIX SN: <${SN}> +PREFIX pti: <${pti}> 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} + ?s pti:ScheduleResource.marketCode ?station_group; + cim:IdentifiedObject.name ?name. + optional{?s cim:IdentifiedObject.aliasName ?alias_name} } diff --git a/cimsparql/sparql/synchronous_machines.sparql b/cimsparql/sparql/synchronous_machines.sparql index ac105376..7faac720 100644 --- a/cimsparql/sparql/synchronous_machines.sparql +++ b/cimsparql/sparql/synchronous_machines.sparql @@ -1,49 +1,37 @@ # Name: Synchronous machines -PREFIX cim: <${cim}> PREFIX SN: <${SN}> +PREFIX cim: <${cim}> +PREFIX entsoe2:<${entsoe2}> +PREFIX pti:<${pti}> PREFIX xsd: <${xsd}> -select distinct ?mrid ?name ?market_code ?node ?status ?station_group ?station_group_name ?substation_mrid ?maxP ?minP ?MO ?bidzone ?sn ?p ?q ?connectivity_node +select distinct ?mrid ?name ?node ?status ?station_group ?station_group_name ?substation_mrid ?maxP ?minP ?MO ?sn ?p ?q ?connectivity_node where { # Extract properties for synchronous machines. ?machine a cim:SynchronousMachine; - cim:IdentifiedObject.name ?name; - cim:RotatingMachine.ratedS ?sn; - cim:IdentifiedObject.mRID ?mrid; - ^cim:Terminal.ConductingEquipment ?terminal; - cim:Equipment.EquipmentContainer/cim:VoltageLevel.Substation ?substation . + cim:IdentifiedObject.name ?name; + cim:RotatingMachine.ratedS ?sn; + cim:IdentifiedObject.mRID ?mrid; + ^cim:Terminal.ConductingEquipment ?terminal; + cim:Equipment.EquipmentContainer/cim:VoltageLevel.Substation ?substation . ?terminal cim:Terminal.ConnectivityNode ?con_node; cim:IdentifiedObject.mRID ?t_mrid . ?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 . + cim:IdentifiedObject.mRID ?substation_mrid . # Optionally extract min/max operating power for each machin - optional { - ?machine cim:SynchronousMachine.GeneratingUnit ?gen_unit. - ?gen_unit cim:GeneratingUnit.minOperatingP ?minP; - cim:GeneratingUnit.maxOperatingP ?maxP . - } + ?machine cim:RotatingMachine.GeneratingUnit ?gen_unit. + ?gen_unit cim:GeneratingUnit.minOperatingP ?minP; + cim:GeneratingUnit.maxOperatingP ?maxP . filter regex(?area, '${region}') - # Optionally extract bidzone for the substation associated with the sync machin - optional { - ?substation SN:Substation.MarketDeliveryPoint/SN:MarketDeliveryPoint.BiddingArea/SN:BiddingArea.marketCode ?bidzone - } . - # Opionally extract non-CIM standard properties generating units - optional { - select ?gen_unit ?market_code ?MO ?station_group ?station_group_name - where - { - ?gen_unit SN:GeneratingUnit.marketCode ?market_code; - SN:GeneratingUnit.groupAllocationWeight ?MO; - SN:GeneratingUnit.ScheduleResource ?ScheduleResource . - ?ScheduleResource SN:ScheduleResource.marketCode ?station_group; - cim:IdentifiedObject.name ?station_group_name . - } - } + ?gen_unit pti:GeneratingUnit.meritOrder ?MO; + pti:GeneratingUnit.ScheduleResource ?ScheduleResource. + ?ScheduleResource pti:ScheduleResource.marketCode ?station_group; + cim:IdentifiedObject.name ?station_group_name . # Extract connected flag and optionally mRID for the topological node associated with each terminal service <${repo}> { @@ -51,23 +39,23 @@ where { optional {?terminal cim:Terminal.TopologyNode/cim:IdentifiedObject.mRID ?term_top_node_mrid} } . - # Optionally extract the mRID of the topological node associated with the connectivity node for each sync machine - optional { service <${repo}> {?con_node cim:ConnectivityNode.TopologicalNode/cim:IdentifiedObject.mRID ?con_top_node_mrid .}} + # Optionally extract the mRID of the toplogical node associated with the connectivity node for each sync machine + optional {service <${repo}> {?con_node cim:ConnectivityNode.TopologicalNode/cim:IdentifiedObject.mRID ?con_top_node_mrid .}} # Optionally extract in_service flag for each machine, as well as active and reactive power service <${repo}> { optional {?machine ^cim:SvStatus.ConductingEquipment/cim:SvStatus.inService ?in_service} . optional {?machine cim:RotatingMachine.p ?p;cim:RotatingMachine.q ?q .} } - optional {?machine SN:Equipment.networkAnalysisEnable ?_network_analysis} - filter(?network_analysis) + optional {?machine pti:Equipment.excludeFromCase ?_exclude_from_case} . + bind(coalesce(?_exclude_from_case, false) as ?exclude_from_case) + filter (!?exclude_from_case) # Assign a node mRID for each sync machine. It is set as the first existing of # 1) mRID of the topological node associated with the connectivity node for the terminal associated # with the sync machine # 2) mRID of the topological node associated with the terminal for the sync machine bind(coalesce(?con_top_node_mrid, ?term_top_node_mrid, ?t_mrid) as ?node) - bind(coalesce(?_network_analysis, True) as ?network_analysis) # Assign a status flag. If exists, the in_service flag for the sync machine is used. Otherwise, # the connected flag of the terminal associated with the sync machine is used diff --git a/cimsparql/sparql/three_winding.sparql b/cimsparql/sparql/three_winding.sparql index df12a3d5..837ad031 100644 --- a/cimsparql/sparql/three_winding.sparql +++ b/cimsparql/sparql/three_winding.sparql @@ -1,8 +1,8 @@ # Name: Three winding PREFIX cim: <${cim}> -PREFIX SN: <${SN}> +PREFIX pti: <${pti}> PREFIX xsd: <${xsd}> -select ?node_1 ?node_2 ?status ?name ?mrid ?un ?r ?x ?b ?g ?rate (?bidzone as ?bidzone_1) (?bidzone as ?bidzone_2) ?angle ?ratio ?connectivity_node_1 (?node_2 as ?connectivity_node_2) +select ?node_1 ?node_2 ?status ?name ?mrid ?un ?r ?x ?b ?g ?rate ?angle ?ratio ?connectivity_node_1 (?node_2 as ?connectivity_node_2) where { # Use mrid of transformer as dummy node ?p_transformer cim:IdentifiedObject.mRID ?node_2; @@ -28,14 +28,11 @@ where { ?con_node cim:ConnectivityNode.ConnectivityNodeContainer/cim:VoltageLevel.BaseVoltage/cim:BaseVoltage.nominalVoltage ?un ; cim:IdentifiedObject.mRID ?connectivity_node_1 . - # Optionally extract bidzone for substations - optional {?Substation SN:Substation.MarketDeliveryPoint/SN:MarketDeliveryPoint.BiddingArea/SN:BiddingArea.marketCode ?bidzone} . - # Assign the mRID of the topological node for the connectivity nodes to node_1 service <${repo}> {?con_node cim:ConnectivityNode.TopologicalNode/cim:IdentifiedObject.mRID ?node_1 .} # Exxtract eonnected status for terminal and optionally in_service flag for windings - service <${repo}> {?terminal cim:Terminal.connected|cim:ACDCTerminal.connected ?connected .} + service <${repo}> {?terminal cim:ACDCTerminal.connected ?connected .} optional {service <${repo}> {?winding ^cim:SvStatus.ConductingEquipment/cim:SvStatus.inService ?in_service}} . # Extract three winding transformers @@ -55,9 +52,9 @@ where { cim:IdentifiedObject.name '${rate}'; cim:ActivePowerLimit.value ?rate . } - optional {?p_transformer SN:Equipment.networkAnalysisEnable ?_network_analysis} - filter(?network_analysis) - bind(coalesce(?_network_analysis, True) as ?network_analysis) + optional {?p_transformer pti:Equipment.excludeFromCase ?_exclude_from_case} . + bind(coalesce(?_exclude_from_case, false) as ?exclude_from_case) + filter (!?exclude_from_case) # Assign status flag to the transformer. The first that exists is used # 1) in_service flag on the transformer diff --git a/cimsparql/sparql/three_winding_dummy_nodes.sparql b/cimsparql/sparql/three_winding_dummy_nodes.sparql index 6c839acf..28266a74 100644 --- a/cimsparql/sparql/three_winding_dummy_nodes.sparql +++ b/cimsparql/sparql/three_winding_dummy_nodes.sparql @@ -1,6 +1,8 @@ # Name: Three winding with dummy nodes PREFIX cim:<${cim}> -PREFIX SN:<${SN}> +PREFIX entsoe:<${entsoe}> +PREFIX entsoe2:<${entsoe2}> +PREFIX pti:<${pti}> select ?node ?busname (?container_name as ?substation) ?un (?container_mrid as ?substation_mrid) ?bidzone ?island (False as ?is_swing_bus) ?connectivity_node where { @@ -33,8 +35,8 @@ where }. bind(coalesce(?island_name, "Unknown") as ?island) } - optional {?container SN:Substation.MarketDeliveryPoint/SN:MarketDeliveryPoint.BiddingArea/SN:BiddingArea.marketCode ?bidzone} - optional {?p_transformer SN:Equipment.networkAnalysisEnable ?_network_analysis} - filter(?network_analysis) - bind(coalesce(?_network_analysis, True) as ?network_analysis) + optional {?container pti:Substation.EnergySchedulingArea/entsoe2:EnergySchedulingArea.EnergyCongestionZone/entsoe:IdentifiedObject.energyIdentCodeEic ?bidzone}. + optional {?p_transformer pti:Equipment.excludeFromCase ?_exclude_from_case} . + bind(coalesce(?_exclude_from_case, false) as ?exclude_from_case) + filter (!?exclude_from_case) } diff --git a/cimsparql/sparql/two_winding_transformer.sparql b/cimsparql/sparql/two_winding_transformer.sparql index 4e5027c0..ef7d700e 100644 --- a/cimsparql/sparql/two_winding_transformer.sparql +++ b/cimsparql/sparql/two_winding_transformer.sparql @@ -1,9 +1,9 @@ # Name: Two winding transformer PREFIX cim: <${cim}> -PREFIX SN: <${SN}> +PREFIX pti: <${pti}> 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 ?connectivity_node_1 ?connectivity_node_2 +select ?mrid ?name ?node_1 ?node_2 ?ploss_1 ?ploss_2 ?r ?rate ?status (?un_1 as ?un) ?x ?b ?g ?angle ?ratio ?connectivity_node_1 ?connectivity_node_2 where { # Collect properties for terminal_1 @@ -20,8 +20,7 @@ where # Extract two winding transformers { select ?p_transformer where { - ?p_transformer a cim:PowerTransformer; - ^cim:PowerTransformerEnd.PowerTransformer ?power_transformer_end + ?power_transformer_end cim:PowerTransformerEnd.PowerTransformer ?p_transformer } group by ?p_transformer having (count(*) = 2) @@ -30,11 +29,9 @@ where 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 }. - optional { - ?p_transformer SN:Equipment.networkAnalysisEnable ?_network_analysis - } - bind(coalesce(?_network_analysis, True) as ?network_analysis) + optional {?p_transformer pti:Equipment.excludeFromCase ?_exclude_from_case} . + bind(coalesce(?_exclude_from_case, false) as ?exclude_from_case) + filter (!?exclude_from_case) # Extract for winding_1 ?winding_1 cim:PowerTransformerEnd.PowerTransformer ?p_transformer; cim:TransformerEnd.Terminal ?terminal_1; @@ -77,6 +74,4 @@ where 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) } diff --git a/tests/test_graphdb.py b/tests/test_graphdb.py index 91f401ec..4f3bec3f 100644 --- a/tests/test_graphdb.py +++ b/tests/test_graphdb.py @@ -92,15 +92,19 @@ async def test_regions(model: SingleClientModel): @pytest.mark.asyncio +@pytest.mark.xfail(reason="HVDC substations in wrong bidzone (e.g. HVDC_GB is placed in NO2)") async def test_hvdc_converters_bidzones(model: SingleClientModel): df = await model.hvdc_converter_bidzones() corridors = set(zip(df["bidzone_1"], df["bidzone_2"], strict=True)) # Check data quality in the models - expect_corridors = {("SE4", "SE3"), ("NO2", "DE"), ("NO2", "DK1"), ("NO2", "GB"), ("NO2", "NL")} + expect_corridors = {("NO2", "DE"), ("NO2", "DK1"), ("NO2", "GB"), ("NO2", "NL")} assert expect_corridors.issubset(corridors) + converter_df = await model.converters("NO") + assert set(converter_df.index).issubset(df.index) + @pytest.mark.asyncio async def test_windings(model: SingleClientModel):