Skip to content

Changed SubgridContainer to represent galvanically seperated grids #1365

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

Closed
Closed
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- Updated dependabot workflow and added CODEOWNERS [#1328](https://github.com/ie3-institute/PowerSystemDataModel/issues/1328)
- Extend azimuth angle range to [-180°, 180°] for PV inputs [#1330](https://github.com/ie3-institute/PowerSystemDataModel/issues/1330)
- Changed `SubgridContainer` to represent galvanically seperated grids [#1226](https://github.com/ie3-institute/PowerSystemDataModel/issues/1226)

## [7.0.0] - 2025-05-08

Expand Down
13 changes: 0 additions & 13 deletions docs/readthedocs/models/input/grid/gridcontainer.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,6 @@ Why predominant?
As of convention, the `SubGridContainers` hold also reference to the transformers leading to higher sub grids
and their higher voltage coupling point.

![Sub grid boundary definition for transformers with upstream switchgear](../../../_static/figures/transformerWithSwitchGear.png)

Let's shed a more detailed light on the boundaries of a sub grid as of our definition.
This especially is important, if the switchgear of the transformer is modeled in detail.
We defined, that all nodes in upstream direction of the transformer, that are connected by switches *only* (therefore
are within the switchgear) are counted towards the inferior sub grid structure (here "2"), although they belong to a
different voltage level.
This decision is taken, because we assume, that the interest to operate on the given switchgear will most likely be
placed in the inferior grid structure.

The "real" coupling node A is not comprised in the sub grids node collection, but obviously has reference through the
switch between nodes A and B.

A synoptic overview of both classes' attributes is given here:

## Attributes, Units and Remarks
Expand Down
121 changes: 5 additions & 116 deletions src/main/java/edu/ie3/datamodel/utils/ContainerUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -426,41 +426,11 @@ public static GraphicElements filterForSubnet(GraphicElements input, int subnet)
*/
public static VoltageLevel determinePredominantVoltLvl(RawGridElements rawGrid, int subnet)
throws InvalidGridException {
/* Exclude all nodes, that are at the high voltage side of the transformer */
Set<NodeInput> gridNodes = new HashSet<>(rawGrid.getNodes());
gridNodes.removeAll(
/* Remove all nodes, that are upstream of transformers, this comprises all those, that are connected by
* switches */
rawGrid.getTransformer2Ws().stream()
.flatMap(
transformer ->
ContainerUtils.traverseAlongSwitchChain(transformer.getNodeA(), rawGrid)
.stream())
.collect(Collectors.toSet()));
gridNodes.removeAll(
rawGrid.getTransformer3Ws().stream()
.flatMap(
transformer -> {
if (transformer.getNodeA().getSubnet() == subnet)
return Stream.of(transformer.getNodeB(), transformer.getNodeC());
else if (transformer.getNodeB().getSubnet() == subnet)
return Stream.concat(
ContainerUtils.traverseAlongSwitchChain(transformer.getNodeA(), rawGrid)
.stream(),
Stream.of(transformer.getNodeC(), transformer.getNodeInternal()));
else
return Stream.concat(
ContainerUtils.traverseAlongSwitchChain(transformer.getNodeA(), rawGrid)
.stream(),
Stream.of(transformer.getNodeB(), transformer.getNodeInternal()));
})
.collect(Collectors.toSet()));

/* Build a mapping, which voltage level appears how often */
Map<VoltageLevel, Long> voltageLevelCount =
gridNodes.stream()
.map(NodeInput::getVoltLvl)
.collect(Collectors.groupingBy(voltLvl -> voltLvl, Collectors.counting()));
rawGrid.getNodes().stream()
.filter(n -> n.getSubnet() == subnet)
.collect(Collectors.groupingBy(NodeInput::getVoltLvl, Collectors.counting()));

/* At this point only one voltage level should be apparent */
int amountOfVoltLvl = voltageLevelCount.size();
Expand Down Expand Up @@ -677,14 +647,8 @@ private static TransformerSubGridContainers getSubGridContainers(
RawGridElements rawGridElements,
Map<Integer, SubGridContainer> subGrids)
throws TopologyException {
/* Get the sub grid container at port A - travel upstream as long as nodes are connected
* _only_ by switches */
NodeInput topNode = traverseAlongSwitchChain(transformer.getNodeA(), rawGridElements).getLast();
if (Objects.isNull(topNode))
throw new TopologyException(
"Cannot find most upstream node of transformer '" + transformer + "'");

SubGridContainer containerA = subGrids.get(topNode.getSubnet());
/* Get the sub grid container at port A */
SubGridContainer containerA = subGrids.get(transformer.getNodeA().getSubnet());

/* Get the sub grid container at port B */
SubGridContainer containerB = subGrids.get(transformer.getNodeB().getSubnet());
Expand All @@ -696,81 +660,6 @@ private static TransformerSubGridContainers getSubGridContainers(
} else return new TransformerSubGridContainers(containerA, containerB);
}

/**
* Traversing along a chain of switches and return the traveled nodes. The end thereby is defined
* by a node, that either is a dead end or is connected to any other type of connector (e.g.
* lines, transformers) and therefore leads to other parts of a "real" grid. If the starting node
* is not part of any switch, the starting node is returned.
*
* @param startNode Node that is meant to be the start of the switch chain
* @param rawGridElements Elements of the pure grid structure.
* @return The end node of the switch chain
*/
public static LinkedList<NodeInput> traverseAlongSwitchChain(
NodeInput startNode, RawGridElements rawGridElements) {
Set<NodeInput> possibleJunctions =
Stream.concat(
Stream.concat(
rawGridElements.getLines().parallelStream(),
rawGridElements.getTransformer2Ws().parallelStream()),
rawGridElements.getTransformer3Ws().parallelStream())
.flatMap(connector -> connector.allNodes().parallelStream())
.collect(Collectors.toSet());
return traverseAlongSwitchChain(startNode, rawGridElements.getSwitches(), possibleJunctions);
}

/**
* Traversing along a chain of switches and return the traveled nodes. The end thereby is defined
* by a node, that either is a dead end or part of the provided node set. If the starting node is
* not part of any switch, the starting node is returned.
*
* @param startNode Node that is meant to be the start of the switch chain
* @param switches Set of available switches
* @param possibleJunctions Set of nodes that denote possible junctions to "real" grid
* @return The end node of the switch chain
*/
private static LinkedList<NodeInput> traverseAlongSwitchChain(
NodeInput startNode, Set<SwitchInput> switches, Set<NodeInput> possibleJunctions) {
LinkedList<NodeInput> traveledNodes = new LinkedList<>();
traveledNodes.addFirst(startNode);

/* Get the switch, that is connected to the starting node and determine the next node */
List<SwitchInput> nextSwitches =
switches.stream().filter(switcher -> switcher.allNodes().contains(startNode)).toList();
switch (nextSwitches.size()) {
case 0:
/* No further switch found -> Return the starting node */
break;
case 1:
/* One next switch has been found -> Travel in this direction */
SwitchInput nextSwitch = nextSwitches.get(0);
Optional<NodeInput> candidateNodes =
nextSwitch.allNodes().stream().filter(node -> node != startNode).findFirst();
NodeInput nextNode =
candidateNodes.orElseThrow(
() ->
new IllegalArgumentException(
"There is no further node available at switch " + nextSwitch));
if (possibleJunctions.contains(nextNode)) {
/* This is a junction, leading to another Connector than a switch */
traveledNodes.addLast(nextNode);
} else {
/* Add the traveled nodes to the nodes to be excluded, to avoid endless loops in cyclic switch topologies */
HashSet<NodeInput> newNodesToExclude = new HashSet<>(possibleJunctions);
newNodesToExclude.add(nextNode);
HashSet<SwitchInput> newSwitches = new HashSet<>(switches);
newSwitches.remove(nextSwitch);
traveledNodes.addAll(traverseAlongSwitchChain(nextNode, newSwitches, newNodesToExclude));
}
break;
default:
throw new IllegalArgumentException(
"Cannot traverse along switch chain, as there is a junction included at node "
+ startNode);
}
return traveledNodes;
}

/**
* Combines a given collection of sub grid containers to a joint model. If the single models do
* not fit together, exceptions are thrown.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,13 @@
import edu.ie3.datamodel.models.input.container.*;
import edu.ie3.datamodel.models.input.graphics.GraphicInput;
import edu.ie3.datamodel.models.input.system.SystemParticipantInput;
import edu.ie3.datamodel.utils.ContainerUtils;
import edu.ie3.datamodel.utils.Try;
import edu.ie3.datamodel.utils.Try.Failure;
import edu.ie3.datamodel.utils.Try.Success;
import java.time.ZonedDateTime;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.jgrapht.Graph;
import org.jgrapht.alg.connectivity.ConnectivityInspector;
import org.jgrapht.graph.DefaultEdge;
Expand Down Expand Up @@ -135,26 +133,12 @@ private GridContainerValidationUtils() {
exceptions.addAll(ConnectorValidationUtils.check(transformer));
});

/* Checking switches
* Because of the fact, that a transformer with switch gear in "upstream" direction has its corresponding node in
* upper grid connected to a switch, instead of to the transformer directly: Collect all nodes at the end of the
* upstream switch chain and add them to the set of allowed nodes */
HashSet<NodeInput> validSwitchNodes = new HashSet<>(nodes);
validSwitchNodes.addAll(
Stream.of(rawGridElements.getTransformer2Ws(), rawGridElements.getTransformer2Ws())
.flatMap(Set::stream)
.parallel()
.map(
transformer ->
ContainerUtils.traverseAlongSwitchChain(transformer.getNodeA(), rawGridElements)
.getLast())
.toList());

/* Checking switches */
rawGridElements
.getSwitches()
.forEach(
switcher -> {
exceptions.add(checkNodeAvailability(switcher, validSwitchNodes));
exceptions.add(checkNodeAvailability(switcher, nodes));
exceptions.addAll(ConnectorValidationUtils.check(switcher));
});

Expand Down
Loading
Loading