Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CGMES: remove extension for Control Areas, use IIDM Area #3149

Open
wants to merge 21 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
9bc3e5c
CGMES: remove extension for Control Areas, use iidm Area
zamarrenolm Sep 20, 2024
f164ae5
add energy identification code EIC as alias
zamarrenolm Sep 20, 2024
8831363
do not delete existing cgmes extension
zamarrenolm Sep 20, 2024
38c02c9
copy the cgmes control area type to the iidm area type
zamarrenolm Sep 20, 2024
df99a96
use iidm area for cgmes export of control areas, adjust unit tests
zamarrenolm Sep 25, 2024
9387a35
always set pTolerance; adjust unit tests
zamarrenolm Sep 26, 2024
5019069
Merge branch 'main' into remove_cgmes_control_areas_extension
zamarrenolm Oct 2, 2024
c67ca0c
Merge branch 'main' into remove_cgmes_control_areas_extension
zamarrenolm Oct 23, 2024
69026ac
EIC code and target for default control area created for export
zamarrenolm Oct 24, 2024
e946c3f
Merge branch 'main' into remove_cgmes_control_areas_extension
zamarrenolm Oct 24, 2024
20cd5e5
p tolerance positive, by default 1% of net interchange
zamarrenolm Oct 24, 2024
ee15e39
refactor writing of tie flows in equipment export
zamarrenolm Oct 25, 2024
0af40d1
determine if a boundary should be ac or dc based on the reference data
zamarrenolm Nov 4, 2024
f51309f
move control area conversion to specific class
zamarrenolm Nov 14, 2024
53cb10d
int for size of list
zamarrenolm Nov 14, 2024
81b63e3
import tie flow sets the ac/dc type
zamarrenolm Nov 14, 2024
f2a31ac
Merge branch 'main' into remove_cgmes_control_areas_extension
zamarrenolm Dec 12, 2024
c081ba2
remove legacy extension, adapt unit tests
zamarrenolm Dec 13, 2024
cc60a53
remove local directory
zamarrenolm Dec 13, 2024
4f9d471
explicit creation of default control area of type interchange
zamarrenolm Dec 16, 2024
d264397
control area net interchange tolerance is optional, no default value …
zamarrenolm Dec 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@
import com.powsybl.cgmes.conversion.naming.NamingStrategy;
import com.powsybl.cgmes.conversion.naming.NamingStrategyFactory;
import com.powsybl.cgmes.extensions.CgmesMetadataModels;
import com.powsybl.cgmes.model.CgmesMetadataModel;
import com.powsybl.cgmes.model.CgmesMetadataModelImpl;
import com.powsybl.cgmes.model.CgmesNamespace;
import com.powsybl.cgmes.model.CgmesSubset;
import com.powsybl.cgmes.model.*;
import com.powsybl.commons.config.PlatformConfig;
import com.powsybl.commons.datasource.DataSource;
import com.powsybl.commons.exceptions.UncheckedXmlStreamException;
Expand All @@ -28,6 +25,7 @@
import com.powsybl.commons.xml.XmlUtil;
import com.powsybl.iidm.network.*;
import com.powsybl.triplestore.api.PropertyBag;
import com.powsybl.triplestore.api.PropertyBags;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -42,6 +40,8 @@
import java.util.stream.Collectors;

import static com.powsybl.cgmes.conversion.CgmesReports.inconsistentProfilesTPRequiredReport;
import static com.powsybl.cgmes.conversion.naming.CgmesObjectReference.Part.CONTROL_AREA;
import static com.powsybl.cgmes.conversion.naming.CgmesObjectReference.refTyped;

/**
* @author Luma Zamarreño {@literal <zamarrenolm at aia.es>}
Expand Down Expand Up @@ -78,6 +78,49 @@ public List<Parameter> getParameters() {
public void export(Network network, Properties parameters, DataSource dataSource, ReportNode reportNode) {
Objects.requireNonNull(network);

CgmesExportContext context = createContext(network, parameters, reportNode);

// Export the network
if (Parameter.readBoolean(getFormat(), parameters, CGM_EXPORT_PARAMETER, defaultValueConfig)) {
exportCGM(network, dataSource, context);
} else {
exportIGM(network, dataSource, context);
}
}

public void createDefaultControlAreaInterchange(Network network) {
createDefaultControlAreaInterchange(network, null);
}

public void createDefaultControlAreaInterchange(Network network, Properties parameters) {
Objects.requireNonNull(network);

CgmesExportContext context = createContext(network, parameters, ReportNode.NO_OP);

String controlAreaId = context.getNamingStrategy().getCgmesId(refTyped(network), CONTROL_AREA);
Area area = network.newArea()
.setAreaType("ControlAreaTypeKind.Interchange")
Copy link
Member

@rcourtier rcourtier Dec 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ControlAreaTypeKind.Interchange enum value is used here as well as in:

  • EquipmentExport
  • SteadyStateHypothesisExport
  • ControlAreaEq
  • CgmesConformity1ModifiedConversionTest
  • EquipmentExportTest
  • SteadyStateHypothesisExportTest

I think it would be worth creating a constant in CgmesNames.

.setId(controlAreaId)
.setName("Network")
.add();
ReferenceDataProvider referenceDataProvider = context.getReferenceDataProvider();
if (referenceDataProvider != null && referenceDataProvider.getSourcingActor().containsKey(CgmesNames.ENERGY_IDENT_CODE_EIC)) {
area.addAlias(referenceDataProvider.getSourcingActor().get(CgmesNames.ENERGY_IDENT_CODE_EIC), CgmesNames.ENERGY_IDENT_CODE_EIC);
}
double currentInterchange = 0;
Set<String> boundaryDcNodes = getBoundaryDcNodes(referenceDataProvider);
for (DanglingLine danglingLine : CgmesExportUtil.getBoundaryDanglingLines(network)) {
// Our exchange should be referred the boundary
area.newAreaBoundary()
.setAc(isAcBoundary(danglingLine, boundaryDcNodes))
.setBoundary(danglingLine.getBoundary())
.add();
currentInterchange += danglingLine.getBoundary().getP();
}
area.setInterchangeTarget(currentInterchange);
}

private CgmesExportContext createContext(Network network, Properties parameters, ReportNode reportNode) {
// Determine reference data (boundaries, base voltages and other sourcing references) for the export
String sourcingActorName = Parameter.readString(getFormat(), parameters, SOURCING_ACTOR_PARAMETER, defaultValueConfig);
String countryName = getCountry(network);
Expand All @@ -90,12 +133,30 @@ public void export(Network network, Properties parameters, DataSource dataSource
CgmesExportContext context = new CgmesExportContext(network, referenceDataProvider, namingStrategy);
addParametersToContext(context, parameters, reportNode, referenceDataProvider);

// Export the network
if (Parameter.readBoolean(getFormat(), parameters, CGM_EXPORT_PARAMETER, defaultValueConfig)) {
exportCGM(network, dataSource, context);
return context;
}

private Set<String> getBoundaryDcNodes(ReferenceDataProvider referenceDataProvider) {
if (referenceDataProvider == null) {
return Collections.emptySet();
}
PropertyBags boundaryNodes = referenceDataProvider.getBoundaryNodes();
if (boundaryNodes == null) {
return Collections.emptySet();
} else {
exportIGM(network, dataSource, context);
return boundaryNodes.stream()
.filter(node -> node.containsKey("topologicalNodeDescription") && node.get("topologicalNodeDescription").startsWith("HVDC"))
.map(node -> node.getId(CgmesNames.TOPOLOGICAL_NODE))
.collect(Collectors.toSet());
}
}

private boolean isAcBoundary(DanglingLine danglingLine, Set<String> boundaryDcNodes) {
String dlBoundaryNode = danglingLine.getProperty(Conversion.CGMES_PREFIX_ALIAS_PROPERTIES + CgmesNames.TOPOLOGICAL_NODE_BOUNDARY);
if (dlBoundaryNode != null) {
return !boundaryDcNodes.contains(dlBoundaryNode);
}
return true;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,13 +231,8 @@ public Network convert(ReportNode reportNode) {
}

if (config.importControlAreas()) {
context.pushReportNode(CgmesReports.convertingElementTypeReport(reportNode, CgmesNames.CONTROL_AREA));
network.newExtension(CgmesControlAreasAdder.class).add();
CgmesControlAreas cgmesControlAreas = network.getExtension(CgmesControlAreas.class);
cgmes.controlAreas().forEach(ca -> createControlArea(cgmesControlAreas, ca));
cgmes.tieFlows().forEach(tf -> addTieFlow(context, cgmesControlAreas, tf));
cgmesControlAreas.cleanIfEmpty();
context.popReportNode();
convert(cgmes.controlAreas(), CgmesNames.CONTROL_AREA, context);
convert(cgmes.tieFlows(), CgmesNames.TIE_FLOW, context);
}

context.pushReportNode(CgmesReports.convertingElementTypeReport(reportNode, CgmesNames.REGULATING_CONTROL));
Expand Down Expand Up @@ -401,33 +396,6 @@ private static void completeVoltagesAndAngles(Network network) {
network.getTieLines().forEach(tieLine -> AbstractConductingEquipmentConversion.calculateVoltageAndAngleInBoundaryBus(tieLine.getDanglingLine1(), tieLine.getDanglingLine2()));
}

private static void createControlArea(CgmesControlAreas cgmesControlAreas, PropertyBag ca) {
String controlAreaId = ca.getId("ControlArea");
cgmesControlAreas.newCgmesControlArea()
.setId(controlAreaId)
.setName(ca.getLocal("name"))
.setEnergyIdentificationCodeEic(ca.getLocal("energyIdentCodeEic"))
.setNetInterchange(ca.asDouble("netInterchange", Double.NaN))
.setPTolerance(ca.asDouble("pTolerance", Double.NaN))
.add();
}

private static void addTieFlow(Context context, CgmesControlAreas cgmesControlAreas, PropertyBag tf) {
rcourtier marked this conversation as resolved.
Show resolved Hide resolved
String controlAreaId = tf.getId("ControlArea");
CgmesControlArea cgmesControlArea = cgmesControlAreas.getCgmesControlArea(controlAreaId);
if (cgmesControlArea == null) {
context.ignored("Tie Flow", String.format("Tie Flow %s refers to a non-existing control area", tf.getId("TieFlow")));
return;
}
String terminalId = tf.getId("terminal");
Boundary boundary = context.terminalMapping().findBoundary(terminalId, context.cgmes());
if (boundary != null) {
cgmesControlArea.add(boundary);
return;
}
RegulatingTerminalMapper.mapForTieFlow(terminalId, context).ifPresent(cgmesControlArea::add);
}

private void convert(PropertyBags elements, String elementType, Context context) {
context.pushReportNode(CgmesReports.convertingElementTypeReport(context.getReportNode(), elementType));
for (PropertyBag element : elements) {
Expand All @@ -452,6 +420,8 @@ private void convert(PropertyBags elements, String elementType, Context context)
case CgmesNames.SERIES_COMPENSATOR -> new SeriesCompensatorConversion(element, context);
case CgmesNames.OPERATIONAL_LIMIT -> new OperationalLimitConversion(element, context);
case CgmesNames.SV_INJECTION -> new SvInjectionConversion(element, context);
case CgmesNames.CONTROL_AREA -> new ControlAreaConversion(element, context);
case CgmesNames.TIE_FLOW -> new TieFlowConversion(element, context);
default -> throw new IllegalArgumentException("Invalid elementType.");
};
if (c.insideBoundary()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
* @author Luma Zamarreño {@literal <zamarrenolm at aia.es>}
* @author José Antonio Marqués {@literal <marquesja at aia.es>}
*/
final class RegulatingTerminalMapper {
public final class RegulatingTerminalMapper {

private RegulatingTerminalMapper() {
// Empty constructor for utility class
Expand Down Expand Up @@ -105,7 +105,7 @@ private static <T> Stream<? extends Terminal> allTerminals(VoltageLevel vl, Set<
.filter(terminal -> vertices.contains(terminalToVertex.apply(terminal)));
}

static class TerminalAndSign {
public static class TerminalAndSign {
private final Terminal terminal;
private final int sign;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
Copyright (c) 2024, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
* SPDX-License-Identifier: MPL-2.0
*/
package com.powsybl.cgmes.conversion.elements;

import com.powsybl.cgmes.conversion.Context;
import com.powsybl.cgmes.model.CgmesNames;
import com.powsybl.iidm.network.Area;
import com.powsybl.triplestore.api.PropertyBag;

/**
* @author Luma Zamarreño {@literal <zamarrenolm at aia.es>}
*/
public class ControlAreaConversion extends AbstractIdentifiedObjectConversion {

public ControlAreaConversion(PropertyBag area, Context context) {
super(CgmesNames.CONTROL_AREA, area, context);
}

@Override
public boolean valid() {
return true;
}

@Override
public void convert() {
String controlAreaId = p.getId(CgmesNames.CONTROL_AREA);
String type = p.getLocal("controlAreaType");
Area area = context.network().newArea()
.setAreaType(type) // Copy the type defined by CGMES
.setId(controlAreaId)
.setName(p.getLocal("name"))
.setInterchangeTarget(p.asDouble("netInterchange", Double.NaN))
.add();
if (p.containsKey(CgmesNames.P_TOLERANCE)) {
String pTolerance = p.get(CgmesNames.P_TOLERANCE);
area.setProperty(CgmesNames.P_TOLERANCE, pTolerance);
}
if (p.containsKey(CgmesNames.ENERGY_IDENT_CODE_EIC)) {
area.addAlias(p.get(CgmesNames.ENERGY_IDENT_CODE_EIC), CgmesNames.ENERGY_IDENT_CODE_EIC);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/**
Copyright (c) 2024, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
* SPDX-License-Identifier: MPL-2.0
*/
package com.powsybl.cgmes.conversion.elements;

import com.powsybl.cgmes.conversion.Context;
import com.powsybl.cgmes.conversion.RegulatingTerminalMapper;
import com.powsybl.cgmes.model.CgmesNames;
import com.powsybl.cgmes.model.CgmesTerminal;
import com.powsybl.iidm.network.Area;
import com.powsybl.iidm.network.Boundary;
import com.powsybl.triplestore.api.PropertyBag;

/**
* @author Luma Zamarreño {@literal <zamarrenolm at aia.es>}
*/
public class TieFlowConversion extends AbstractIdentifiedObjectConversion {

public TieFlowConversion(PropertyBag tieFlow, Context context) {
super(CgmesNames.TIE_FLOW, tieFlow, context);
}

@Override
public boolean valid() {
return true;
}

@Override
public void convert() {
String controlAreaId = p.getId(CgmesNames.CONTROL_AREA);
Area area = context.network().getArea(controlAreaId);
if (area == null) {
context.ignored("Tie Flow", String.format("Tie Flow %s refers to a non-existing control area", p.getId("TieFlow")));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could use the constant from CgmesNames for more consistency:

p.getId(CgmesNames.TIE_FLOW)

return;
}
String terminalId = p.getId("terminal");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could use the constant from CgmesNames for more consistency:

p.getId(CgmesNames.TERMINAL)

boolean isAc = isConsideredAcTieFlow(terminalId);
Boundary boundary = context.terminalMapping().findBoundary(terminalId, context.cgmes());
if (boundary != null) {
area.newAreaBoundary()
.setAc(isAc)
.setBoundary(boundary)
.add();
return;
}
RegulatingTerminalMapper.mapForTieFlow(terminalId, context)
.ifPresent(t -> area.newAreaBoundary()
.setAc(isAc)
.setTerminal(t)
.add());
}

private boolean isConsideredAcTieFlow(String terminalId) {
CgmesTerminal cgmesTerminal = context.cgmes().terminal(terminalId);
String node = cgmesTerminal.topologicalNode() == null ? cgmesTerminal.connectivityNode() : cgmesTerminal.topologicalNode();
boolean isDc = context.boundary().isHvdc(node);
return !isDc;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,10 @@ public CgmesExportContext(Network network, ReferenceDataProvider referenceDataPr
}
}

public ReferenceDataProvider getReferenceDataProvider() {
return referenceDataProvider;
}

private CgmesTopologyKind networkTopologyKind(Network network) {
for (VoltageLevel vl : network.getVoltageLevels()) {
if (vl.getTopologyKind().equals(TopologyKind.NODE_BREAKER)) {
Expand All @@ -180,7 +184,6 @@ public void addIidmMappings(Network network) {
addIidmMappingsStaticVarCompensators(network);
addIidmMappingsEndsAndTapChangers(network);
addIidmMappingsEquivalentInjection(network);
addIidmMappingsControlArea(network);
}

private void addIidmMappingsSubstations(Network network) {
Expand Down Expand Up @@ -531,24 +534,6 @@ private void addIidmMappingsEquivalentInjection(Network network) {
}
}

private void addIidmMappingsControlArea(Network network) {
CgmesControlAreas cgmesControlAreas = network.getExtension(CgmesControlAreas.class);
if (cgmesControlAreas == null) {
network.newExtension(CgmesControlAreasAdder.class).add();
cgmesControlAreas = network.getExtension(CgmesControlAreas.class);
String cgmesControlAreaId = namingStrategy.getCgmesId(refTyped(network), CONTROL_AREA);
cgmesControlAreas.newCgmesControlArea()
.setId(cgmesControlAreaId)
.setName("Network")
.setEnergyIdentificationCodeEic("Network--1")
.add();
CgmesControlArea cgmesControlArea = cgmesControlAreas.getCgmesControlArea(cgmesControlAreaId);
for (DanglingLine danglingLine : CgmesExportUtil.getBoundaryDanglingLines(network)) {
cgmesControlArea.add(danglingLine.getTerminal());
}
}
}

public int getCimVersion() {
return cim.getVersion();
}
Expand Down
Loading
Loading