Skip to content

Commit 01ef152

Browse files
authored
Add upcoming and current overload durations in result (#199)
Signed-off-by: LE SAULNIER Kevin <[email protected]>
1 parent 9ba47e7 commit 01ef152

File tree

6 files changed

+142
-16
lines changed

6 files changed

+142
-16
lines changed

src/main/java/org/gridsuite/securityanalysis/server/dto/LimitViolationDTO.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ public class LimitViolationDTO {
2424
private String limitName;
2525
private String nextLimitName;
2626
private ThreeSides side;
27-
private int acceptableDuration;
27+
private Integer acceptableDuration;
28+
private Integer upcomingAcceptableDuration;
2829
private double limit;
2930
private Double patlLimit;
3031
private double limitReduction;
@@ -39,7 +40,8 @@ public static LimitViolationDTO toDto(AbstractLimitViolationEntity limitViolatio
3940
.limitName(limitViolation.getLimitName())
4041
.nextLimitName(limitViolation.getNextLimitName())
4142
.side(limitViolation.getSide())
42-
.acceptableDuration((int) limitViolation.getAcceptableDuration())
43+
.acceptableDuration(limitViolation.getAcceptableDuration())
44+
.upcomingAcceptableDuration(limitViolation.getUpcomingAcceptableDuration())
4345
.limit(limitViolation.getLimit())
4446
.patlLimit(limitViolation.getPatlLimit())
4547
.limitReduction(limitViolation.getLimitReduction())

src/main/java/org/gridsuite/securityanalysis/server/entities/AbstractLimitViolationEntity.java

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,7 @@
1717
import lombok.experimental.FieldNameConstants;
1818
import lombok.experimental.SuperBuilder;
1919

20-
import java.util.Collection;
21-
import java.util.Iterator;
22-
import java.util.Optional;
23-
import java.util.UUID;
20+
import java.util.*;
2421

2522
/**
2623
* @author Kevin Le Saulnier <kevin.lesaulnier at rte-france.com>
@@ -53,7 +50,9 @@ public abstract class AbstractLimitViolationEntity {
5350
@Enumerated(EnumType.STRING)
5451
private LimitViolationType limitType;
5552

56-
private long acceptableDuration;
53+
private Integer acceptableDuration;
54+
55+
private Integer upcomingAcceptableDuration;
5756

5857
private double limitReduction;
5958

@@ -130,4 +129,42 @@ private static LoadingLimits.TemporaryLimit getNextTemporaryLimit(Branch<?> bran
130129

131130
return null;
132131
}
132+
133+
protected static Integer calculateActualOverloadDuration(LimitViolation limitViolation, Network network) {
134+
if (limitViolation.getValue() > limitViolation.getLimit()) {
135+
return limitViolation.getAcceptableDuration();
136+
} else {
137+
String equipmentId = limitViolation.getSubjectId();
138+
LoadingLimits.TemporaryLimit tempLimit = null;
139+
140+
Branch<?> branch = network.getBranch(equipmentId);
141+
if (branch != null) {
142+
tempLimit = getBranchLimitViolationAboveCurrentValue(branch, limitViolation);
143+
}
144+
return (tempLimit != null) ? tempLimit.getAcceptableDuration() : Integer.MAX_VALUE;
145+
}
146+
}
147+
148+
protected static Integer calculateUpcomingOverloadDuration(LimitViolation limitViolation) {
149+
if (limitViolation.getValue() < limitViolation.getLimit()) {
150+
return limitViolation.getAcceptableDuration();
151+
}
152+
return null;
153+
}
154+
155+
private static LoadingLimits.TemporaryLimit getBranchLimitViolationAboveCurrentValue(Branch<?> branch, LimitViolation limitViolation) {
156+
// limits are returned from the store by DESC duration / ASC value
157+
Optional<CurrentLimits> currentLimits = branch.getCurrentLimits(limitViolation.getSideAsTwoSides());
158+
if (currentLimits.isEmpty() || limitViolation.getValue() < currentLimits.get().getPermanentLimit()) {
159+
return null;
160+
} else {
161+
Optional<LoadingLimits.TemporaryLimit> nextTemporaryLimit = currentLimits.get().getTemporaryLimits().stream()
162+
.filter(tl -> limitViolation.getValue() < tl.getValue())
163+
.findFirst();
164+
if (nextTemporaryLimit.isPresent()) {
165+
return nextTemporaryLimit.get();
166+
}
167+
}
168+
return null;
169+
}
133170
}

src/main/java/org/gridsuite/securityanalysis/server/entities/ContingencyLimitViolationEntity.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ public static ContingencyLimitViolationEntity toEntity(Network network, LimitVio
4646
.patlLimit(patlLimit)
4747
.patlLoading(computeLoading(limitViolation, patlLimit))
4848
.nextLimitName(getNextLimitName(limitViolation, network))
49-
.acceptableDuration(limitViolation.getAcceptableDuration())
49+
.acceptableDuration(calculateActualOverloadDuration(limitViolation, network))
50+
.upcomingAcceptableDuration(calculateUpcomingOverloadDuration(limitViolation))
5051
.build();
5152

5253
subjectLimitViolation.addContingencyLimitViolation(contingencyLimitViolationEntity);
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
2+
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext" xmlns:pro="http://www.liquibase.org/xml/ns/pro" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd http://www.liquibase.org/xml/ns/pro http://www.liquibase.org/xml/ns/pro/liquibase-pro-latest.xsd http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-latest.xsd">
3+
<changeSet author="lesaulnierkev (generated)" id="1757342382341-1">
4+
<addColumn tableName="contingency_limit_violation">
5+
<column name="upcoming_acceptable_duration" type="integer"/>
6+
</addColumn>
7+
</changeSet>
8+
<changeSet author="lesaulnierkev (generated)" id="1757342382341-2">
9+
<addColumn tableName="pre_contingency_limit_violation">
10+
<column name="upcoming_acceptable_duration" type="integer"/>
11+
</addColumn>
12+
</changeSet>
13+
<changeSet author="lesaulnierkev (generated)" id="fix-overflowed-values-1">
14+
<update tableName="pre_contingency_limit_violation">
15+
<column name="acceptable_duration" value="NULL"/>
16+
<where>acceptable_duration &lt; -2147483648 OR acceptable_duration &gt; 2147483647</where>
17+
</update>
18+
</changeSet>
19+
<changeSet author="lesaulnierkev (generated)" id="1757342382341-3">
20+
<modifyDataType
21+
tableName="contingency_limit_violation"
22+
columnName="acceptable_duration"
23+
newDataType="INTEGER"/>
24+
</changeSet>
25+
<changeSet author="lesaulnierkev (generated)" id="fix-overflowed-values-2">
26+
<update tableName="contingency_limit_violation">
27+
<column name="acceptable_duration" value="NULL"/>
28+
<where>acceptable_duration &lt; -2147483648 OR acceptable_duration &gt; 2147483647</where>
29+
</update>
30+
</changeSet>
31+
<changeSet author="lesaulnierkev (generated)" id="1757342382341-4">
32+
<modifyDataType
33+
tableName="pre_contingency_limit_violation"
34+
columnName="acceptable_duration"
35+
newDataType="INTEGER"/>
36+
</changeSet>
37+
</databaseChangeLog>

src/main/resources/db/changelog/db.changelog-master.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,6 @@ databaseChangeLog:
4848
- include:
4949
file: changesets/changelog_20250903T125946Z.xml
5050
relativeToChangelogFile: true
51+
- include:
52+
file: changesets/changelog_20250908T143920Z.xml
53+
relativeToChangelogFile: true

src/test/java/org/gridsuite/securityanalysis/server/ContingencyLimitViolationTest.java

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,44 +17,90 @@
1717
import org.junit.jupiter.api.Test;
1818
import org.springframework.boot.test.context.SpringBootTest;
1919

20+
import static com.powsybl.iidm.network.test.EurostagTutorialExample1Factory.NGEN_NHV1;
21+
import static com.powsybl.iidm.network.test.EurostagTutorialExample1Factory.NHV1_NHV2_1;
2022
import static org.junit.jupiter.api.Assertions.assertEquals;
2123

2224
/**
2325
* @author Kevin Le Saulnier <kevin.lesaulnier at rte-france.com>
2426
*/
2527
@SpringBootTest
2628
class ContingencyLimitViolationTest {
27-
2829
@Test
2930
void testContingencyLimitViolationEntityNewFields() {
30-
testContingencyLimitViolationMapping("10'", 10 * 60, 1200, 1250, TwoSides.TWO, "1'", 1100);
31+
testContingencyLimitViolationMapping("10'", 10 * 60, 1200, 1, 1250, TwoSides.TWO, "1'", 1100, 10 * 60, null);
3132
}
3233

3334
@Test
3435
void testContingencyLimitViolationEntityNewFieldsWithPermanentLimitReached() {
35-
testContingencyLimitViolationMapping(LimitViolationUtils.PERMANENT_LIMIT_NAME, Integer.MAX_VALUE, 1100, 1150, TwoSides.TWO, "10'", 1100);
36+
testContingencyLimitViolationMapping(LimitViolationUtils.PERMANENT_LIMIT_NAME, Integer.MAX_VALUE, 1100, 1, 1150, TwoSides.TWO, "10'", 1100, Integer.MAX_VALUE, null);
3637
}
3738

3839
@Test
3940
void testContingencyLimitViolationEntityNewFieldsWithPermanentLimitReachedAndNoTemporaryLimit() {
40-
testContingencyLimitViolationMapping(LimitViolationUtils.PERMANENT_LIMIT_NAME, Integer.MAX_VALUE, 500, 1000, TwoSides.ONE, null, 500);
41+
testContingencyLimitViolationMapping(LimitViolationUtils.PERMANENT_LIMIT_NAME, Integer.MAX_VALUE, 500, 1, 1000, TwoSides.ONE, null, 500, Integer.MAX_VALUE, null);
4142
}
4243

4344
@Test
4445
void testContingencyLimitViolationEntityNewFieldsWithLastLimitReached() {
45-
testContingencyLimitViolationMapping("N/A", 0, 1100, 3000, TwoSides.TWO, null, 1100);
46+
testContingencyLimitViolationMapping("N/A", 0, 1100, 1, 3000, TwoSides.TWO, null, 1100, 0, null);
47+
}
48+
49+
@Test
50+
void testContingencyLimitViolationEntityNewFieldsWithLimitReductionEffective() {
51+
// for this test to be relevant, "value" needs to be less that "limit"
52+
testContingencyLimitViolationMapping("10'", 60, 1200, 0.8, 1150, TwoSides.TWO, "1'", 1100, 10 * 60, 60);
53+
}
54+
55+
@Test
56+
void test2wtContingencyLimitViolationEntityNewFieldsWithLimitReductionEffective() {
57+
// for this test to be relevant, "value" needs to be less that "limit"
58+
Network network = EurostagTutorialExample1Factory.createWithFixedCurrentLimits();
59+
// create limit set for two windings transformer
60+
network.getTwoWindingsTransformer(NGEN_NHV1).getOrCreateSelectedOperationalLimitsGroup1().newCurrentLimits()
61+
.setPermanentLimit(100)
62+
.beginTemporaryLimit()
63+
.setName("10'")
64+
.setValue(200)
65+
.setAcceptableDuration(60 * 10)
66+
.endTemporaryLimit()
67+
.beginTemporaryLimit()
68+
.setName("1'")
69+
.setValue(300)
70+
.setAcceptableDuration(60)
71+
.endTemporaryLimit()
72+
.beginTemporaryLimit()
73+
.setName("N/A")
74+
.setValue(Double.MAX_VALUE)
75+
.setAcceptableDuration(0)
76+
.endTemporaryLimit()
77+
.add();
78+
79+
LimitViolation limitViolation = new LimitViolation(NGEN_NHV1, "NGEN_NHV1_name", LimitViolationType.CURRENT, "10'", 60, 200, 0.8, 180, TwoSides.ONE);
80+
81+
SubjectLimitViolationEntity subjectLimitViolationEntity = new SubjectLimitViolationEntity(NGEN_NHV1, "NGEN_NHV1_name");
82+
83+
ContingencyLimitViolationEntity contingencyLimitViolationEntity = ContingencyLimitViolationEntity.toEntity(network, limitViolation, subjectLimitViolationEntity);
84+
85+
assertEquals("1'", contingencyLimitViolationEntity.getNextLimitName());
86+
assertEquals(100, contingencyLimitViolationEntity.getPatlLimit());
87+
assertEquals(60 * 10, contingencyLimitViolationEntity.getAcceptableDuration());
88+
assertEquals(60, contingencyLimitViolationEntity.getUpcomingAcceptableDuration());
89+
assertEquals(100 * limitViolation.getValue() / contingencyLimitViolationEntity.getPatlLimit(), contingencyLimitViolationEntity.getPatlLoading());
4690
}
4791

48-
private void testContingencyLimitViolationMapping(String limitName, int acceptableDuration, double limit, double value, TwoSides side, String expectedNextLimitName, long expectedPatlLimit) {
92+
private void testContingencyLimitViolationMapping(String limitName, int acceptableDuration, double limit, double limitReduction, double value, TwoSides side, String expectedNextLimitName, long expectedPatlLimit, Integer expectedAcceptableDuration, Integer expectedUpcomingAcceptableDuration) {
4993
Network network = EurostagTutorialExample1Factory.createWithFixedCurrentLimits();
50-
LimitViolation limitViolation = new LimitViolation("NHV1_NHV2_1", "NHV1_NHV2_1_name", LimitViolationType.CURRENT, limitName, acceptableDuration, limit, 1, value, side);
94+
LimitViolation limitViolation = new LimitViolation(NHV1_NHV2_1, "NHV1_NHV2_1_name", LimitViolationType.CURRENT, limitName, acceptableDuration, limit, limitReduction, value, side);
5195

52-
SubjectLimitViolationEntity subjectLimitViolationEntity = new SubjectLimitViolationEntity("NHV1_NHV2_1", "NHV1_NHV2_1_name");
96+
SubjectLimitViolationEntity subjectLimitViolationEntity = new SubjectLimitViolationEntity(NHV1_NHV2_1, "NHV1_NHV2_1_name");
5397

5498
ContingencyLimitViolationEntity contingencyLimitViolationEntity = ContingencyLimitViolationEntity.toEntity(network, limitViolation, subjectLimitViolationEntity);
5599

56100
assertEquals(expectedNextLimitName, contingencyLimitViolationEntity.getNextLimitName());
57101
assertEquals(expectedPatlLimit, contingencyLimitViolationEntity.getPatlLimit());
102+
assertEquals(expectedAcceptableDuration, contingencyLimitViolationEntity.getAcceptableDuration());
103+
assertEquals(expectedUpcomingAcceptableDuration, contingencyLimitViolationEntity.getUpcomingAcceptableDuration());
58104
assertEquals(100 * limitViolation.getValue() / contingencyLimitViolationEntity.getPatlLimit(), contingencyLimitViolationEntity.getPatlLoading());
59105
}
60106
}

0 commit comments

Comments
 (0)