Skip to content

Commit ac70f34

Browse files
authored
Merge branch 'dev' into dependabot/gradle/dev/net.bytebuddy-byte-buddy-1.14.17
2 parents 47dd4e6 + d2bca6b commit ac70f34

File tree

4 files changed

+221
-3
lines changed

4 files changed

+221
-3
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99
### Added
1010
- Enhancing `VoltageLevel` with `equals` method [#1063](https://github.com/ie3-institute/PowerSystemDataModel/issues/1063)
1111
- `ConnectorValidationUtils` checks if parallel devices is > 0 [#1077](https://github.com/ie3-institute/PowerSystemDataModel/issues/1077)
12+
- `GridContainerValidationUtils` checks the connectivity for all defined operation time intervals [#1091](https://github.com/ie3-institute/PowerSystemDataModel/issues/1091)
1213

1314
### Fixed
1415
- Fixed `MappingEntryies` not getting processed by adding `Getter` methods for record fields [#1084](https://github.com/ie3-institute/PowerSystemDataModel/issues/1084)

docs/readthedocs/io/ValidationUtils.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ The methods in ValidationUtils and subclasses can be used to check that objects
1111
The general validation checks:
1212
- if assigned values are valid, e.g. lines are not allowed to have negative lengths or the rated power factor of any unit must be between 0 and 1
1313
- furthermore, several connections are checked, e.g. that lines only connect nodes of the same voltage level or that the voltage levels indicated for the transformer sides match the voltage levels of the nodes they are connected to.
14+
- the connectivity of the given grid for all defined operation intervals
1415

1516
The uniqueness validation checks if a collection of given objects are unique in either:
1617
- a specific field

src/main/java/edu/ie3/datamodel/utils/validation/GridContainerValidationUtils.java

Lines changed: 113 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,33 @@
88
import static edu.ie3.datamodel.utils.validation.UniquenessValidationUtils.checkAssetUniqueness;
99
import static edu.ie3.datamodel.utils.validation.UniquenessValidationUtils.checkUniqueEntities;
1010

11-
import edu.ie3.datamodel.exceptions.*;
11+
import edu.ie3.datamodel.exceptions.DuplicateEntitiesException;
12+
import edu.ie3.datamodel.exceptions.InvalidEntityException;
13+
import edu.ie3.datamodel.exceptions.InvalidGridException;
14+
import edu.ie3.datamodel.exceptions.ValidationException;
15+
import edu.ie3.datamodel.models.OperationTime;
1216
import edu.ie3.datamodel.models.input.AssetInput;
1317
import edu.ie3.datamodel.models.input.MeasurementUnitInput;
1418
import edu.ie3.datamodel.models.input.NodeInput;
15-
import edu.ie3.datamodel.models.input.connector.*;
19+
import edu.ie3.datamodel.models.input.connector.ConnectorInput;
20+
import edu.ie3.datamodel.models.input.connector.LineInput;
21+
import edu.ie3.datamodel.models.input.connector.Transformer3WInput;
1622
import edu.ie3.datamodel.models.input.container.*;
1723
import edu.ie3.datamodel.models.input.graphics.GraphicInput;
1824
import edu.ie3.datamodel.models.input.system.SystemParticipantInput;
1925
import edu.ie3.datamodel.utils.ContainerUtils;
2026
import edu.ie3.datamodel.utils.Try;
21-
import edu.ie3.datamodel.utils.Try.*;
27+
import edu.ie3.datamodel.utils.Try.Failure;
28+
import edu.ie3.datamodel.utils.Try.Success;
29+
import java.time.ZonedDateTime;
2230
import java.util.*;
31+
import java.util.function.Predicate;
32+
import java.util.stream.Collectors;
2333
import java.util.stream.Stream;
34+
import org.jgrapht.Graph;
35+
import org.jgrapht.alg.connectivity.ConnectivityInspector;
36+
import org.jgrapht.graph.DefaultEdge;
37+
import org.jgrapht.graph.SimpleGraph;
2438

2539
public class GridContainerValidationUtils extends ValidationUtils {
2640

@@ -155,9 +169,105 @@ private GridContainerValidationUtils() {
155169
exceptions.add(MeasurementUnitValidationUtils.check(measurement));
156170
});
157171

172+
exceptions.addAll(checkConnectivity(rawGridElements));
173+
158174
return exceptions;
159175
}
160176

177+
/**
178+
* Checks the connectivity of the given grid for all defined {@link OperationTime}s. If every
179+
* {@link AssetInput} is set to {@link OperationTime#notLimited()}, the connectivity is only
180+
* checked once.
181+
*
182+
* @param rawGridElements to check
183+
* @return a try
184+
*/
185+
protected static List<Try<Void, InvalidGridException>> checkConnectivity(
186+
RawGridElements rawGridElements) {
187+
Set<ZonedDateTime> times =
188+
rawGridElements.allEntitiesAsList().stream()
189+
.map(AssetInput::getOperationTime)
190+
.filter(OperationTime::isLimited)
191+
.map(OperationTime::getOperationLimit)
192+
.filter(Optional::isPresent)
193+
.map(Optional::get)
194+
.map(interval -> Set.of(interval.getLower(), interval.getUpper()))
195+
.flatMap(Collection::stream)
196+
.collect(Collectors.toSet());
197+
198+
if (times.isEmpty()) {
199+
return List.of(checkConnectivity(rawGridElements, Optional.empty()));
200+
} else {
201+
return times.stream()
202+
.sorted()
203+
.map(time -> checkConnectivity(rawGridElements, Optional.of(time)))
204+
.toList();
205+
}
206+
}
207+
208+
/**
209+
* Checks if the given {@link RawGridElements} from a connected grid.
210+
*
211+
* @param rawGridElements to check
212+
* @param time for operation filtering
213+
* @return a try
214+
*/
215+
protected static Try<Void, InvalidGridException> checkConnectivity(
216+
RawGridElements rawGridElements, Optional<ZonedDateTime> time) {
217+
218+
Predicate<AssetInput> isInOperation =
219+
assetInput -> time.map(assetInput::inOperationOn).orElse(true);
220+
221+
// build graph
222+
Graph<UUID, DefaultEdge> graph = new SimpleGraph<>(DefaultEdge.class);
223+
224+
rawGridElements.getNodes().stream()
225+
.filter(isInOperation)
226+
.forEach(node -> graph.addVertex(node.getUuid()));
227+
rawGridElements.getLines().stream()
228+
.filter(isInOperation)
229+
.forEach(
230+
connector ->
231+
graph.addEdge(connector.getNodeA().getUuid(), connector.getNodeB().getUuid()));
232+
rawGridElements.getTransformer2Ws().stream()
233+
.filter(isInOperation)
234+
.forEach(
235+
connector ->
236+
graph.addEdge(connector.getNodeA().getUuid(), connector.getNodeB().getUuid()));
237+
rawGridElements.getTransformer3Ws().stream()
238+
.filter(isInOperation)
239+
.forEach(
240+
connector ->
241+
graph.addEdge(connector.getNodeA().getUuid(), connector.getNodeB().getUuid()));
242+
rawGridElements.getSwitches().stream()
243+
.filter(isInOperation)
244+
.forEach(
245+
connector ->
246+
graph.addEdge(connector.getNodeA().getUuid(), connector.getNodeB().getUuid()));
247+
248+
ConnectivityInspector<UUID, DefaultEdge> inspector = new ConnectivityInspector<>(graph);
249+
250+
if (inspector.isConnected()) {
251+
return Success.empty();
252+
} else {
253+
List<Set<UUID>> sets = inspector.connectedSets();
254+
255+
List<UUID> unconnected =
256+
sets.stream()
257+
.max(Comparator.comparing(Set::size))
258+
.map(set -> graph.vertexSet().stream().filter(v -> !set.contains(v)).toList())
259+
.orElse(List.of());
260+
261+
String message = "The grid contains unconnected elements";
262+
263+
if (time.isPresent()) {
264+
message += " for time " + time.get();
265+
}
266+
267+
return Failure.of(new InvalidGridException(message + ": " + unconnected));
268+
}
269+
}
270+
161271
/**
162272
* Checks the validity of each and every system participant. Moreover, it checks, if the systems
163273
* are connected to a node that is not in the provided set
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
/*
2+
* © 2024. TU Dortmund University,
3+
* Institute of Energy Systems, Energy Efficiency and Energy Economics,
4+
* Research group Distribution grid planning and operation
5+
*/
6+
package edu.ie3.datamodel.utils.validation
7+
8+
import edu.ie3.datamodel.exceptions.InvalidGridException
9+
import edu.ie3.datamodel.models.OperationTime
10+
import edu.ie3.datamodel.models.input.container.RawGridElements
11+
import edu.ie3.datamodel.utils.Try
12+
import edu.ie3.test.common.GridTestData as GTD
13+
import spock.lang.Shared
14+
import spock.lang.Specification
15+
16+
import java.time.ZonedDateTime
17+
18+
class GridContainerValidationUtilsTest extends Specification {
19+
@Shared
20+
private ZonedDateTime start
21+
22+
@Shared
23+
private RawGridElements limitedElements
24+
25+
def setupSpec() {
26+
start = ZonedDateTime.now()
27+
28+
def operationTimeFrame1 = OperationTime.builder().withStart(start).withEnd(start.plusHours(2)).build()
29+
def operationTimeFrame2 = OperationTime.builder().withStart(start.plusHours(1)).withEnd(start.plusHours(3)).build()
30+
31+
def nodes = [
32+
GTD.nodeC,
33+
GTD.nodeD,
34+
GTD.nodeE,
35+
GTD.nodeF,
36+
GTD.nodeG
37+
] as Set
38+
39+
def lines = [
40+
GTD.lineCtoD.copy().operationTime(operationTimeFrame1).build(),
41+
GTD.lineFtoG.copy().operationTime(operationTimeFrame2).build()
42+
] as Set
43+
44+
def transformers = [
45+
GTD.transformerCtoF.copy().operationTime(operationTimeFrame1).build(),
46+
GTD.transformerCtoE.copy().operationTime(operationTimeFrame2).build()
47+
] as Set
48+
49+
limitedElements = new RawGridElements(nodes, lines, transformers, [] as Set, [] as Set, [] as Set)
50+
}
51+
52+
def "The GridContainerValidationUtils should check the connectivity for all operation intervals correctly"() {
53+
when:
54+
def actual = GridContainerValidationUtils.checkConnectivity(limitedElements)
55+
56+
then:
57+
actual.size() == 4
58+
actual.get(0).failure
59+
actual.get(1).success
60+
actual.get(2).success
61+
actual.get(3).failure
62+
63+
actual.get(0).exception.get().message == "The grid contains unconnected elements for time " + start + ": " + [
64+
GTD.nodeE.uuid,
65+
GTD.nodeG.uuid
66+
]
67+
actual.get(3).exception.get().message == "The grid contains unconnected elements for time " + start.plusHours(3) + ": " + [
68+
GTD.nodeD.uuid,
69+
GTD.nodeF.uuid,
70+
GTD.nodeG.uuid
71+
]
72+
}
73+
74+
def "The GridContainerValidationUtils should check the connectivity correctly"() {
75+
when:
76+
def actual = GridContainerValidationUtils.checkConnectivity(limitedElements, time as Optional<ZonedDateTime>)
77+
78+
then:
79+
actual == expectedResult
80+
81+
where:
82+
time || expectedResult
83+
Optional.empty() || Try.Success.empty()
84+
Optional.of(start.plusHours(1)) || Try.Success.empty()
85+
}
86+
87+
def "The GridContainerValidationUtils should return an exception if the grid is not properly connected"() {
88+
when:
89+
def actual = GridContainerValidationUtils.checkConnectivity(limitedElements, time as Optional<ZonedDateTime>)
90+
91+
then:
92+
actual.exception.get().message == expectedException.message
93+
94+
where:
95+
time || expectedException
96+
Optional.of(start) || new InvalidGridException("The grid contains unconnected elements for time " + start + ": " + [
97+
GTD.nodeE.uuid,
98+
GTD.nodeG.uuid
99+
])
100+
Optional.of(start.plusHours(3)) || new InvalidGridException("The grid contains unconnected elements for time " + start.plusHours(3) + ": " + [
101+
GTD.nodeD.uuid,
102+
GTD.nodeF.uuid,
103+
GTD.nodeG.uuid
104+
])
105+
}
106+
}

0 commit comments

Comments
 (0)