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 47 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
47 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
242f781
use orElseGet; pretty code
zamarrenolm Jan 14, 2025
8eafb69
control areas must be compared in test; fix query for optional contro…
zamarrenolm Jan 14, 2025
b6cadb1
do not consider any extension when comparing EQ data
zamarrenolm Jan 14, 2025
b2f9f9b
remove unused code
zamarrenolm Jan 14, 2025
e50db9f
remove unneeded code
zamarrenolm Jan 14, 2025
b33d120
use constants
zamarrenolm Jan 14, 2025
71d8941
Merge branch 'main' into remove_cgmes_control_areas_extension
zamarrenolm Jan 14, 2025
5761066
Merge branch 'main' into remove_cgmes_control_areas_extension
zamarrenolm Jan 21, 2025
7ef0741
adjust unit test
zamarrenolm Jan 21, 2025
05b53ad
keep optional at SSH block level
zamarrenolm Jan 21, 2025
94a7a15
Merge branch 'main' into remove_cgmes_control_areas_extension
zamarrenolm Jan 23, 2025
9ca9e0a
areas can be compared now
zamarrenolm Jan 23, 2025
fda0105
check that the default control area is created before exporting
zamarrenolm Jan 23, 2025
4451325
write only EQ and check exported file contains control area
zamarrenolm Jan 23, 2025
720b652
write just the SSH file and check it contains the tolerance
zamarrenolm Jan 23, 2025
16e8fdc
write individual files and check contents instead of whole export
zamarrenolm Jan 23, 2025
58b07b8
Merge branch 'main' into remove_cgmes_control_areas_extension
zamarrenolm Jan 30, 2025
34e00ce
Update cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/convers…
zamarrenolm Jan 30, 2025
9bae92b
Update cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/convers…
zamarrenolm Jan 30, 2025
9d8a8bc
Update cgmes/cgmes-conversion/src/main/java/com/powsybl/cgmes/convers…
zamarrenolm Jan 30, 2025
39a64eb
considerations for CGMES 3 dc boundaries
zamarrenolm Jan 30, 2025
6e6843d
consistency with other classes in the package: do not catch XMLStream…
zamarrenolm Jan 30, 2025
1305696
add javadoc for default control area creation
zamarrenolm Jan 30, 2025
557b7df
Merge branch 'main' into remove_cgmes_control_areas_extension
zamarrenolm Jan 30, 2025
a1bb68d
Merge branch 'main' into remove_cgmes_control_areas_extension
zamarrenolm Feb 7, 2025
035bc84
Merge branch 'main' into remove_cgmes_control_areas_extension
olperr1 Feb 11, 2025
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 @@ -232,11 +232,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();
cgmes.controlAreas().forEach(ca -> createControlArea(context, ca));
cgmes.tieFlows().forEach(tf -> addTieFlow(context, tf));
context.popReportNode();
rcourtier marked this conversation as resolved.
Show resolved Hide resolved
}

Expand Down Expand Up @@ -401,31 +398,46 @@ 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()
private static void createControlArea(Context context, PropertyBag ca) {
rcourtier marked this conversation as resolved.
Show resolved Hide resolved
String controlAreaId = ca.getId(CgmesNames.CONTROL_AREA);
String type = ca.getLocal("controlAreaType");
Area area = context.network().newArea()
.setAreaType(type) // Copy the type defined by CGMES
.setId(controlAreaId)
.setName(ca.getLocal("name"))
.setEnergyIdentificationCodeEic(ca.getLocal("energyIdentCodeEic"))
.setNetInterchange(ca.asDouble("netInterchange", Double.NaN))
.setPTolerance(ca.asDouble("pTolerance", Double.NaN))
.setInterchangeTarget(ca.asDouble("netInterchange", Double.NaN))
.add();
String pTolerance = "0";
if (ca.containsKey(CgmesNames.P_TOLERANCE)) {
pTolerance = ca.get(CgmesNames.P_TOLERANCE);
}
area.setProperty(CgmesNames.P_TOLERANCE, pTolerance);
if (ca.containsKey(CgmesNames.ENERGY_IDENT_CODE_EIC)) {
area.addAlias(ca.get(CgmesNames.ENERGY_IDENT_CODE_EIC), CgmesNames.ENERGY_IDENT_CODE_EIC);
}
}

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) {
private static void addTieFlow(Context context, PropertyBag tf) {
String controlAreaId = tf.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", tf.getId("TieFlow")));
return;
}
String terminalId = tf.getId("terminal");
Boundary boundary = context.terminalMapping().findBoundary(terminalId, context.cgmes());
if (boundary != null) {
cgmesControlArea.add(boundary);
area.newAreaBoundary()
.setAc(true)
rcourtier marked this conversation as resolved.
Show resolved Hide resolved
.setBoundary(boundary)
.add();
return;
}
RegulatingTerminalMapper.mapForTieFlow(terminalId, context).ifPresent(cgmesControlArea::add);
RegulatingTerminalMapper.mapForTieFlow(terminalId, context)
.ifPresent(t -> area.newAreaBoundary()
.setAc(true)
rcourtier marked this conversation as resolved.
Show resolved Hide resolved
.setTerminal(t)
.add());
}

private void convert(PropertyBags elements, String elementType, Context context) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -530,21 +530,51 @@ 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")
// If no control area exists, create one for the whole network, containing the dangling lines as boundaries,
// but only if the network does not contain subnetworks
long numControlAreas = network.getAreaStream().filter(a -> a.getAreaType().equals("ControlAreaTypeKind.Interchange")).count();
long numSubnetworks = network.getSubnetworks().size();
rcourtier marked this conversation as resolved.
Show resolved Hide resolved
if (numControlAreas == 0 && numSubnetworks == 0) {
createDefaultControlArea(network);
}
}

private void createDefaultControlArea(Network network) {
String controlAreaId = namingStrategy.getCgmesId(refTyped(network), CONTROL_AREA);
Area area = network.newArea()
rcourtier marked this conversation as resolved.
Show resolved Hide resolved
.setAreaType("ControlAreaTypeKind.Interchange")
.setId(controlAreaId)
.setName("Network")
.add();
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();
for (DanglingLine danglingLine : CgmesExportUtil.getBoundaryDanglingLines(network)) {
// Our exchange should be referred the boundary
area.newAreaBoundary()
.setAc(isAcBoundary(danglingLine, boundaryDcNodes))
.setBoundary(danglingLine.getBoundary())
.add();
CgmesControlArea cgmesControlArea = cgmesControlAreas.getCgmesControlArea(cgmesControlAreaId);
for (DanglingLine danglingLine : CgmesExportUtil.getBoundaryDanglingLines(network)) {
cgmesControlArea.add(danglingLine.getTerminal());
}
currentInterchange += danglingLine.getBoundary().getP();
}
area.setInterchangeTarget(currentInterchange);
}

private Set<String> getBoundaryDcNodes() {
return referenceDataProvider.getBoundaryNodes().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;
}

public int getCimVersion() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1365,37 +1365,47 @@ private static void writeAcdcConverterDCTerminal(String id, String conductingEqu
}

private static void writeControlAreas(String energyAreaId, Network network, String cimNamespace, String euNamespace, XMLStreamWriter writer, CgmesExportContext context) throws XMLStreamException {
CgmesControlAreas cgmesControlAreas = network.getExtension(CgmesControlAreas.class);
for (CgmesControlArea cgmesControlArea : cgmesControlAreas.getCgmesControlAreas()) {
writeControlArea(cgmesControlArea, energyAreaId, cimNamespace, euNamespace, writer, context, network);
for (Area area : network.getAreas()) {
if (area.getAreaType().equals("ControlAreaTypeKind.Interchange")) {
writeControlArea(area, energyAreaId, cimNamespace, euNamespace, writer, context, network);
}
}
}

private static void writeControlArea(CgmesControlArea cgmesControlArea, String energyAreaId, String cimNamespace, String euNamespace,
private static void writeControlArea(Area controlArea, String energyAreaId, String cimNamespace, String euNamespace,
XMLStreamWriter writer, CgmesExportContext context, Network network) throws XMLStreamException {
// Original control area identifiers may not respect mRID rules, so we pass it through naming strategy
// to obtain always valid mRID identifiers
String controlAreaCgmesId = context.getNamingStrategy().getCgmesId(cgmesControlArea.getId());
ControlAreaEq.write(controlAreaCgmesId, cgmesControlArea.getName(), cgmesControlArea.getEnergyIdentificationCodeEIC(), energyAreaId, cimNamespace, euNamespace, writer, context);
for (Terminal terminal : cgmesControlArea.getTerminals()) {
Connectable<?> c = terminal.getConnectable();
if (c instanceof DanglingLine dl) {
if (network.isBoundaryElement(dl)) {
String tieFlowId = context.getNamingStrategy().getCgmesId(refTyped(c), TIE_FLOW);
String terminalId = context.getNamingStrategy().getCgmesIdFromAlias(dl, Conversion.CGMES_PREFIX_ALIAS_PROPERTIES + TERMINAL_BOUNDARY);
TieFlowEq.write(tieFlowId, controlAreaCgmesId, terminalId, cimNamespace, writer, context);
} else {
LOG.error("Unsupported tie flow at TieLine boundary {}", dl.getId());
}
} else {
LOG.warn("Ignored tie flow at {}: should be a dangling line to retrieve boundary terminal", terminal.getConnectable().getId());
}
String controlAreaCgmesId = context.getNamingStrategy().getCgmesId(controlArea.getId());
String energyIdentCodeEic = controlArea.getAliasFromType(CgmesNames.ENERGY_IDENT_CODE_EIC).orElse("");
ControlAreaEq.write(controlAreaCgmesId, controlArea.getNameOrId(), energyIdentCodeEic, energyAreaId, cimNamespace, euNamespace, writer, context);
for (AreaBoundary areaBoundary : controlArea.getAreaBoundaries()) {
TieFlow.from(areaBoundary, context, network).ifPresent(tieFlow ->
TieFlowEq.write(tieFlow.id(), controlAreaCgmesId, tieFlow.terminalId(), cimNamespace, writer, context)
);
}
}

private record TieFlow(String id, String terminalId) {
static Optional<TieFlow> from(AreaBoundary areaBoundary, CgmesExportContext context, Network network) {
return areaBoundary.getTerminal().map(terminal -> from(terminal, context))
.orElse(areaBoundary.getBoundary().flatMap(boundary -> from(boundary, context, network)));
rcourtier marked this conversation as resolved.
Show resolved Hide resolved
}

static Optional<TieFlow> from(Terminal terminal, CgmesExportContext context) {
return Optional.of(new TieFlow(
context.getNamingStrategy().getCgmesId(refTyped(terminal.getConnectable()), TIE_FLOW),
CgmesExportUtil.getTerminalId(terminal, context)));
}
for (Boundary boundary : cgmesControlArea.getBoundaries()) {

static Optional<TieFlow> from(Boundary boundary, CgmesExportContext context, Network network) {
String terminalId = getTieFlowBoundaryTerminal(boundary, context, network);
if (terminalId != null) {
String tieFlowId = context.getNamingStrategy().getCgmesId(ref(terminalId), TIE_FLOW);
TieFlowEq.write(tieFlowId, controlAreaCgmesId, terminalId, cimNamespace, writer, context);
return Optional.of(new TieFlow(
context.getNamingStrategy().getCgmesId(ref(terminalId), TIE_FLOW),
terminalId));
} else {
return Optional.empty();
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public class ReferenceDataProvider {
private final Map<Double, String> baseVoltagesByNominalVoltage = new HashMap<>();
private String equipmentBoundaryId = null;
private String topologyBoundaryId = null;
private PropertyBags boundaryNodes = null;

private boolean loaded = false;

Expand All @@ -58,6 +59,10 @@ public String getBaseVoltage(double nominalV) {
return baseVoltagesByNominalVoltage.get(nominalV);
}

public PropertyBags getBoundaryNodes() {
return boundaryNodes;
}

public PropertyBag getSourcingActor() {
ensureReferenceDataIsLoaded();
return sourcingActor;
Expand Down Expand Up @@ -89,6 +94,7 @@ private void ensureReferenceDataIsLoaded() {
loadBoundaryModelIds();
loadBaseVoltages();
loadSourcingActor();
loadBoundaryNodes();
loaded = true;
}

Expand Down Expand Up @@ -138,6 +144,13 @@ private void loadBaseVoltages() {
)));
}

private void loadBoundaryNodes() {
if (referenceData == null) {
return;
}
boundaryNodes = referenceData.boundaryNodes();
}

private void loadSourcingActor() {
if (referenceData != null) {
if (sourcingActorName == null || sourcingActorName.isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@
import com.powsybl.cgmes.conversion.CgmesExport;
import com.powsybl.cgmes.conversion.Conversion;
import com.powsybl.cgmes.conversion.export.elements.RegulatingControlEq;
import com.powsybl.cgmes.extensions.CgmesControlArea;
import com.powsybl.cgmes.extensions.CgmesControlAreas;
import com.powsybl.cgmes.extensions.CgmesTapChanger;
import com.powsybl.cgmes.extensions.CgmesTapChangers;
import com.powsybl.cgmes.model.CgmesMetadataModel;
Expand Down Expand Up @@ -843,20 +841,28 @@ private static String generatingUnitClassname(Injection<?> i) {
}

private static void writeControlAreas(Network network, String cimNamespace, XMLStreamWriter writer, CgmesExportContext context) throws XMLStreamException {
CgmesControlAreas areas = network.getExtension(CgmesControlAreas.class);
for (CgmesControlArea area : areas.getCgmesControlAreas()) {
writeControlArea(area, cimNamespace, writer, context);
for (Area area : network.getAreas()) {
if (area.getAreaType().equals("ControlAreaTypeKind.Interchange")) {
writeControlArea(area, cimNamespace, writer, context);
}
}
}

private static void writeControlArea(CgmesControlArea area, String cimNamespace, XMLStreamWriter writer, CgmesExportContext context) throws XMLStreamException {
String areaId = context.getNamingStrategy().getCgmesId(area.getId());
private static void writeControlArea(Area controlArea, String cimNamespace, XMLStreamWriter writer, CgmesExportContext context) throws XMLStreamException {
String areaId = context.getNamingStrategy().getCgmesId(controlArea.getId());
CgmesExportUtil.writeStartAbout("ControlArea", areaId, cimNamespace, writer, context);
writer.writeStartElement(cimNamespace, "ControlArea.netInterchange");
writer.writeCharacters(CgmesExportUtil.format(area.getNetInterchange()));
double netInterchange = controlArea.getInterchangeTarget().orElse(Double.NaN);
writer.writeCharacters(CgmesExportUtil.format(netInterchange));
writer.writeEndElement();
double pTolerance;
if (controlArea.hasProperty("pTolerance")) {
pTolerance = Double.parseDouble(controlArea.getProperty("pTolerance"));
rcourtier marked this conversation as resolved.
Show resolved Hide resolved
} else {
pTolerance = Math.abs(0.01 * netInterchange);
}
writer.writeStartElement(cimNamespace, "ControlArea.pTolerance");
writer.writeCharacters(CgmesExportUtil.format(area.getPTolerance()));
writer.writeCharacters(CgmesExportUtil.format(pTolerance));
writer.writeEndElement();
rcourtier marked this conversation as resolved.
Show resolved Hide resolved
writer.writeEndElement();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@
public final class ControlAreaEq {
private static final String CONTROL_AREA_TYPE = "ControlAreaTypeKind.Interchange";

public static void write(String id, String controlAreaName, String energyIdentificationCodeEIC, String energyAreaId, String cimNamespace, String euNamespace, XMLStreamWriter writer, CgmesExportContext context) throws XMLStreamException {
public static void write(String id, String controlAreaName, String energyIdentCodeEIC, String energyAreaId, String cimNamespace, String euNamespace, XMLStreamWriter writer, CgmesExportContext context) throws XMLStreamException {
CgmesExportUtil.writeStartIdName("ControlArea", id, controlAreaName, cimNamespace, writer, context);
writer.writeStartElement(euNamespace, "IdentifiedObject.energyIdentCodeEic");
writer.writeCharacters(energyIdentificationCodeEIC);
writer.writeCharacters(energyIdentCodeEIC);
writer.writeEndElement();
writer.writeEmptyElement(cimNamespace, "ControlArea.type");
writer.writeAttribute(RDF_NAMESPACE, CgmesNames.RESOURCE, cimNamespace + CONTROL_AREA_TYPE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import com.powsybl.cgmes.conversion.export.CgmesExportContext;
import com.powsybl.cgmes.conversion.export.CgmesExportUtil;
import com.powsybl.commons.PowsyblException;

import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
Expand All @@ -18,14 +19,18 @@
*/
public final class TieFlowEq {

public static void write(String id, String controlAreaId, String terminalId, String cimNamespace, XMLStreamWriter writer, CgmesExportContext context) throws XMLStreamException {
CgmesExportUtil.writeStartId("TieFlow", id, false, cimNamespace, writer, context);
CgmesExportUtil.writeReference("TieFlow.ControlArea", controlAreaId, cimNamespace, writer, context);
CgmesExportUtil.writeReference("TieFlow.Terminal", terminalId, cimNamespace, writer, context);
writer.writeStartElement(cimNamespace, "TieFlow.positiveFlowIn");
writer.writeCharacters("true"); // always true
writer.writeEndElement();
writer.writeEndElement();
public static void write(String id, String controlAreaId, String terminalId, String cimNamespace, XMLStreamWriter writer, CgmesExportContext context) {
olperr1 marked this conversation as resolved.
Show resolved Hide resolved
try {
CgmesExportUtil.writeStartId("TieFlow", id, false, cimNamespace, writer, context);
CgmesExportUtil.writeReference("TieFlow.ControlArea", controlAreaId, cimNamespace, writer, context);
CgmesExportUtil.writeReference("TieFlow.Terminal", terminalId, cimNamespace, writer, context);
writer.writeStartElement(cimNamespace, "TieFlow.positiveFlowIn");
writer.writeCharacters("true"); // always true
writer.writeEndElement();
writer.writeEndElement();
} catch (XMLStreamException x) {
throw new PowsyblException(x);
}
}

private TieFlowEq() {
Expand Down
Loading
Loading