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 export: Add a parameter to export as bus branch #3315

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
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,6 +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.extensions.CgmesTopologyKind;
import com.powsybl.cgmes.model.*;
import com.powsybl.commons.config.PlatformConfig;
import com.powsybl.commons.datasource.DataSource;
Expand Down Expand Up @@ -164,6 +165,7 @@ private CgmesExportContext createContext(Network network, Properties parameters,
NamingStrategy namingStrategy = NamingStrategyFactory.create(namingStrategyImpl, uuidNamespace);
CgmesExportContext context = new CgmesExportContext(network, referenceDataProvider, namingStrategy);
addParametersToContext(context, parameters, reportNode, referenceDataProvider);
context.addIidmMappings(network);

return context;
}
Expand Down Expand Up @@ -538,18 +540,24 @@ private void addParametersToContext(CgmesExportContext context, Properties param
.setReportNode(reportNode)
.setUpdateDependencies(Parameter.readBoolean(getFormat(), params, UPDATE_DEPENDENCIES_PARAMETER, defaultValueConfig));

// If sourcing actor data has been found and the modeling authority set has not been specified explicitly, set it
PropertyBag sourcingActor = referenceDataProvider.getSourcingActor();
if (sourcingActor.containsKey("masUri") && context.getModelingAuthoritySet() == null) {
context.setModelingAuthoritySet(sourcingActor.get("masUri"));
}

// Set CIM version
String cimVersion = Parameter.readString(getFormat(), params, CIM_VERSION_PARAMETER, defaultValueConfig);
if (cimVersion != null) {
context.setCimVersion(Integer.parseInt(cimVersion));
}

// Set the topology kind
String topologyKind = Parameter.readString(getFormat(), params, TOPOLOGY_KIND_PARAMETER, defaultValueConfig);
if (topologyKind != null) {
context.setTopologyKind(Enum.valueOf(CgmesTopologyKind.class, topologyKind));
}

// If sourcing actor data has been found and the modeling authority set has not been specified explicitly, set it
PropertyBag sourcingActor = referenceDataProvider.getSourcingActor();
if (sourcingActor.containsKey("masUri") && context.getModelingAuthoritySet() == null) {
context.setModelingAuthoritySet(sourcingActor.get("masUri"));
}

// Set boundaries
String boundaryEqId = getBoundaryId(CgmesSubset.EQUIPMENT_BOUNDARY, params, BOUNDARY_EQ_ID_PARAMETER, referenceDataProvider);
if (boundaryEqId != null && context.getBoundaryEqId() == null) {
Expand Down Expand Up @@ -640,6 +648,7 @@ public String getFormat() {
public static final String EXPORT_POWER_FLOWS_FOR_SWITCHES = "iidm.export.cgmes.export-power-flows-for-switches";
public static final String NAMING_STRATEGY = "iidm.export.cgmes.naming-strategy";
public static final String PROFILES = "iidm.export.cgmes.profiles";
public static final String TOPOLOGY_KIND = "iidm.export.cgmes.topology-kind";
public static final String CGM_EXPORT = "iidm.export.cgmes.cgm_export";
public static final String MODELING_AUTHORITY_SET = "iidm.export.cgmes.modeling-authority-set";
public static final String MODEL_DESCRIPTION = "iidm.export.cgmes.model-description";
Expand Down Expand Up @@ -694,6 +703,12 @@ public String getFormat() {
"Profiles to export",
List.of("EQ", "TP", "SSH", "SV"),
List.of("EQ", "TP", "SSH", "SV"));
private static final Parameter TOPOLOGY_KIND_PARAMETER = new Parameter(
TOPOLOGY_KIND,
ParameterType.STRING,
"The topology kind of the export",
null,
List.of(CgmesTopologyKind.NODE_BREAKER.name(), CgmesTopologyKind.BUS_BRANCH.name()));
private static final Parameter CGM_EXPORT_PARAMETER = new Parameter(
CGM_EXPORT,
ParameterType.BOOLEAN,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public class CgmesExportContext {
private static final String BOUNDARY_TP_ID_PROPERTY = Conversion.CGMES_PREFIX_ALIAS_PROPERTIES + "TP_BD_ID";

private CgmesNamespace.Cim cim = CgmesNamespace.CIM_16;
private CgmesTopologyKind topologyKind = CgmesTopologyKind.BUS_BRANCH;
private CgmesTopologyKind topologyKind = CgmesTopologyKind.NODE_BREAKER;
private ZonedDateTime scenarioTime = ZonedDateTime.now();
private ReportNode reportNode = ReportNode.NO_OP;
private String businessProcess = DEFAULT_BUSINESS_PROCESS;
Expand Down Expand Up @@ -159,12 +159,25 @@ public ReferenceDataProvider getReferenceDataProvider() {
}

private CgmesTopologyKind networkTopologyKind(Network network) {
for (VoltageLevel vl : network.getVoltageLevels()) {
if (vl.getTopologyKind().equals(TopologyKind.NODE_BREAKER)) {
long nodeBreakerVoltageLevelsCount = network.getVoltageLevelStream()
.filter(vl -> vl.getTopologyKind() == TopologyKind.NODE_BREAKER)
.count();
long busBreakerVoltageLevelsCount = network.getVoltageLevelStream()
.filter(vl -> vl.getTopologyKind() == TopologyKind.BUS_BREAKER)
.count();

if (nodeBreakerVoltageLevelsCount > 0 && busBreakerVoltageLevelsCount == 0) {
return CgmesTopologyKind.NODE_BREAKER;
} else if (nodeBreakerVoltageLevelsCount == 0 && busBreakerVoltageLevelsCount > 0) {
return CgmesTopologyKind.BUS_BRANCH;
} else {
// For mixed-topology network, the topology kind is node/breaker for CIM 100 and bus/branch for CIM 16
if (getCimVersion() < 100) {
return CgmesTopologyKind.BUS_BRANCH;
} else {
return CgmesTopologyKind.NODE_BREAKER;
}
}
return CgmesTopologyKind.BUS_BRANCH;
}

public void addIidmMappings(Network network) {
Expand Down Expand Up @@ -285,11 +298,15 @@ public CgmesExportContext setExportEquipment(boolean exportEquipment) {
}

public boolean isExportedEquipment(Identifiable<?> c) {
// We ignore fictitious loads used to model CGMES SvInjection objects that represent calculation mismatches
// We also ignore fictitious switches used to model CGMES disconnected Terminals
boolean ignored = c.isFictitious() &&
(c instanceof Load
|| c instanceof Switch && "true".equals(c.getProperty(Conversion.PROPERTY_IS_CREATED_FOR_DISCONNECTED_TERMINAL)));
boolean ignored = false;
if (c instanceof Load load) {
ignored = load.isFictitious()
|| isCim16BusBranchExport() && CgmesNames.STATION_SUPPLY.equals(CgmesExportUtil.loadClassName(load));
} else if (c instanceof Switch sw) {
ignored = sw.isFictitious() && "true".equals(sw.getProperty(Conversion.PROPERTY_IS_CREATED_FOR_DISCONNECTED_TERMINAL))
|| isCim16BusBranchExport() && sw.getProperty(Conversion.PROPERTY_CGMES_ORIGINAL_CLASS, "").equals("GroundDisconnector")
|| isBusBranchExport() && !sw.isRetained();
}
return !ignored;
}

Expand Down Expand Up @@ -673,10 +690,6 @@ public BaseVoltageMapping.BaseVoltageSource getBaseVoltageByNominalVoltage(doubl
return baseVoltageByNominalVoltageMapping.get(nominalV);
}

public boolean writeConnectivityNodes() {
return getCimVersion() == 100 || topologyKind == CgmesTopologyKind.NODE_BREAKER;
}

public Collection<String> getRegionsIds() {
return Collections.unmodifiableSet(regionsIdsByRegionName.values());
}
Expand Down Expand Up @@ -779,6 +792,14 @@ public CgmesExportContext setProfiles(List<String> profiles) {
return this;
}

public boolean isCim16BusBranchExport() {
return getCimVersion() == 16 && isBusBranchExport();
}

public boolean isBusBranchExport() {
return getTopologyKind() == CgmesTopologyKind.BUS_BRANCH;
}

public String getBaseName() {
return baseName;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ public static void writeModelDescription(Network network, CgmesSubset subset, XM
writer.writeCharacters(profile);
writer.writeEndElement();
}
if (subset == CgmesSubset.EQUIPMENT && context.getTopologyKind().equals(CgmesTopologyKind.NODE_BREAKER) && context.getCimVersion() < 100) {
if (subset == CgmesSubset.EQUIPMENT && context.getTopologyKind() == CgmesTopologyKind.NODE_BREAKER && context.getCimVersion() < 100) {
// From CGMES 3 EquipmentOperation is not required to write operational limits, connectivity nodes
writer.writeStartElement(MD_NAMESPACE, CgmesNames.PROFILE);
writer.writeCharacters(context.getCim().getProfileUri("EQ_OP"));
Expand Down
Loading