Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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 @@ -24,7 +24,8 @@ public class LimitViolationDTO {
private String limitName;
private String nextLimitName;
private ThreeSides side;
private int acceptableDuration;
private Integer acceptableDuration;
private Integer upcomingAcceptableDuration;
private double limit;
private Double patlLimit;
private double limitReduction;
Expand All @@ -39,7 +40,8 @@ public static LimitViolationDTO toDto(AbstractLimitViolationEntity limitViolatio
.limitName(limitViolation.getLimitName())
.nextLimitName(limitViolation.getNextLimitName())
.side(limitViolation.getSide())
.acceptableDuration((int) limitViolation.getAcceptableDuration())
.acceptableDuration(limitViolation.getAcceptableDuration())
.upcomingAcceptableDuration(limitViolation.getUpcomingAcceptableDuration())
.limit(limitViolation.getLimit())
.patlLimit(limitViolation.getPatlLimit())
.limitReduction(limitViolation.getLimitReduction())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,7 @@
import lombok.experimental.FieldNameConstants;
import lombok.experimental.SuperBuilder;

import java.util.Collection;
import java.util.Iterator;
import java.util.Optional;
import java.util.UUID;
import java.util.*;

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

private long acceptableDuration;
private Integer acceptableDuration;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like we converted to long related sorting/filtering. I can't see why?
4f7a3f8

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After some tests, it's still working as expected, I can't find why it's ben done


private Integer upcomingAcceptableDuration;

private double limitReduction;

Expand Down Expand Up @@ -130,4 +129,47 @@ private static LoadingLimits.TemporaryLimit getNextTemporaryLimit(Branch<?> bran

return null;
}

protected static Integer calculateActualOverloadDuration(LimitViolation limitViolation, Network network) {
if (limitViolation.getValue() > limitViolation.getLimit()) {
return limitViolation.getAcceptableDuration();
} else {
String equipmentId = limitViolation.getSubjectId();
LoadingLimits.TemporaryLimit tempLimit = null;

Line line = network.getLine(equipmentId);
if (line != null) {
tempLimit = getBranchLimitViolationAboveCurrentValue(line, limitViolation);
} else {
TwoWindingsTransformer twoWindingsTransformer = network.getTwoWindingsTransformer(equipmentId);
if (twoWindingsTransformer != null) {
tempLimit = getBranchLimitViolationAboveCurrentValue(twoWindingsTransformer, limitViolation);
}
}
return (tempLimit != null) ? tempLimit.getAcceptableDuration() : Integer.MAX_VALUE;
}
}

protected static Integer calculateUpcomingOverloadDuration(LimitViolation limitViolation) {
if (limitViolation.getValue() < limitViolation.getLimit()) {
return limitViolation.getAcceptableDuration();
}
return null;
}

private static LoadingLimits.TemporaryLimit getBranchLimitViolationAboveCurrentValue(Branch<?> branch, LimitViolation limitViolation) {
// limits are returned from the store by DESC duration / ASC value
Optional<CurrentLimits> currentLimits = limitViolation.getSideAsTwoSides().equals(TwoSides.ONE) ? branch.getCurrentLimits1() : branch.getCurrentLimits2();
if (currentLimits.isEmpty() || limitViolation.getValue() < currentLimits.get().getPermanentLimit()) {
return null;
} else {
Optional<LoadingLimits.TemporaryLimit> nextTemporaryLimit = currentLimits.get().getTemporaryLimits().stream()
.filter(tl -> limitViolation.getValue() < tl.getValue())
.findFirst();
if (nextTemporaryLimit.isPresent()) {
return nextTemporaryLimit.get();
}
}
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ public static ContingencyLimitViolationEntity toEntity(Network network, LimitVio
.patlLimit(patlLimit)
.patlLoading(computeLoading(limitViolation, patlLimit))
.nextLimitName(getNextLimitName(limitViolation, network))
.acceptableDuration(limitViolation.getAcceptableDuration())
.acceptableDuration(calculateActualOverloadDuration(limitViolation, network))
.upcomingAcceptableDuration(calculateUpcomingOverloadDuration(limitViolation))
.build();

subjectLimitViolation.addContingencyLimitViolation(contingencyLimitViolationEntity);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?xml version="1.1" encoding="UTF-8" standalone="no"?>
<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">
<changeSet author="lesaulnierkev (generated)" id="1757342382341-1">
<addColumn tableName="contingency_limit_violation">
<column name="upcoming_acceptable_duration" type="integer"/>
</addColumn>
</changeSet>
<changeSet author="lesaulnierkev (generated)" id="1757342382341-2">
<addColumn tableName="pre_contingency_limit_violation">
<column name="upcoming_acceptable_duration" type="integer"/>
</addColumn>
</changeSet>
<changeSet author="lesaulnierkev (generated)" id="fix-overflowed-values-1">
<update tableName="pre_contingency_limit_violation">
<column name="acceptable_duration" value="NULL"/>
<where>acceptable_duration &lt; -2147483648 OR acceptable_duration &gt; 2147483647</where>
</update>
</changeSet>
<changeSet author="lesaulnierkev (generated)" id="1757342382341-3">
<modifyDataType
tableName="contingency_limit_violation"
columnName="acceptable_duration"
newDataType="INTEGER"/>
</changeSet>
<changeSet author="lesaulnierkev (generated)" id="fix-overflowed-values-2">
<update tableName="contingency_limit_violation">
<column name="acceptable_duration" value="NULL"/>
<where>acceptable_duration &lt; -2147483648 OR acceptable_duration &gt; 2147483647</where>
</update>
</changeSet>
<changeSet author="lesaulnierkev (generated)" id="1757342382341-4">
<modifyDataType
tableName="pre_contingency_limit_violation"
columnName="acceptable_duration"
newDataType="INTEGER"/>
</changeSet>
</databaseChangeLog>
3 changes: 3 additions & 0 deletions src/main/resources/db/changelog/db.changelog-master.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,6 @@ databaseChangeLog:
- include:
file: changesets/changelog_20250903T125946Z.xml
relativeToChangelogFile: true
- include:
file: changesets/changelog_20250908T143920Z.xml
relativeToChangelogFile: true
Original file line number Diff line number Diff line change
Expand Up @@ -17,44 +17,90 @@
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import static com.powsybl.iidm.network.test.EurostagTutorialExample1Factory.NGEN_NHV1;
import static com.powsybl.iidm.network.test.EurostagTutorialExample1Factory.NHV1_NHV2_1;
import static org.junit.jupiter.api.Assertions.assertEquals;

/**
* @author Kevin Le Saulnier <kevin.lesaulnier at rte-france.com>
*/
@SpringBootTest
class ContingencyLimitViolationTest {

@Test
void testContingencyLimitViolationEntityNewFields() {
testContingencyLimitViolationMapping("10'", 10 * 60, 1200, 1250, TwoSides.TWO, "1'", 1100);
testContingencyLimitViolationMapping("10'", 10 * 60, 1200, 1, 1250, TwoSides.TWO, "1'", 1100, 10 * 60, null);
}

@Test
void testContingencyLimitViolationEntityNewFieldsWithPermanentLimitReached() {
testContingencyLimitViolationMapping(LimitViolationUtils.PERMANENT_LIMIT_NAME, Integer.MAX_VALUE, 1100, 1150, TwoSides.TWO, "10'", 1100);
testContingencyLimitViolationMapping(LimitViolationUtils.PERMANENT_LIMIT_NAME, Integer.MAX_VALUE, 1100, 1, 1150, TwoSides.TWO, "10'", 1100, Integer.MAX_VALUE, null);
}

@Test
void testContingencyLimitViolationEntityNewFieldsWithPermanentLimitReachedAndNoTemporaryLimit() {
testContingencyLimitViolationMapping(LimitViolationUtils.PERMANENT_LIMIT_NAME, Integer.MAX_VALUE, 500, 1000, TwoSides.ONE, null, 500);
testContingencyLimitViolationMapping(LimitViolationUtils.PERMANENT_LIMIT_NAME, Integer.MAX_VALUE, 500, 1, 1000, TwoSides.ONE, null, 500, Integer.MAX_VALUE, null);
}

@Test
void testContingencyLimitViolationEntityNewFieldsWithLastLimitReached() {
testContingencyLimitViolationMapping("N/A", 0, 1100, 3000, TwoSides.TWO, null, 1100);
testContingencyLimitViolationMapping("N/A", 0, 1100, 1, 3000, TwoSides.TWO, null, 1100, 0, null);
}

@Test
void testContingencyLimitViolationEntityNewFieldsWithLimitReductionEffective() {
// for this test to be relevant, "value" needs to be less that "limit"
testContingencyLimitViolationMapping("10'", 60, 1200, 0.8, 1150, TwoSides.TWO, "1'", 1100, 10 * 60, 60);
}

@Test
void test2wtContingencyLimitViolationEntityNewFieldsWithLimitReductionEffective() {
// for this test to be relevant, "value" needs to be less that "limit"
Network network = EurostagTutorialExample1Factory.createWithFixedCurrentLimits();
// create limit set for two windings transformer
network.getTwoWindingsTransformer(NGEN_NHV1).getOrCreateSelectedOperationalLimitsGroup1().newCurrentLimits()
.setPermanentLimit(100)
.beginTemporaryLimit()
.setName("10'")
.setValue(200)
.setAcceptableDuration(60 * 10)
.endTemporaryLimit()
.beginTemporaryLimit()
.setName("1'")
.setValue(300)
.setAcceptableDuration(60)
.endTemporaryLimit()
.beginTemporaryLimit()
.setName("N/A")
.setValue(Double.MAX_VALUE)
.setAcceptableDuration(0)
.endTemporaryLimit()
.add();

LimitViolation limitViolation = new LimitViolation(NGEN_NHV1, "NGEN_NHV1_name", LimitViolationType.CURRENT, "10'", 60, 200, 0.8, 180, TwoSides.ONE);

SubjectLimitViolationEntity subjectLimitViolationEntity = new SubjectLimitViolationEntity(NGEN_NHV1, "NGEN_NHV1_name");

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

assertEquals("1'", contingencyLimitViolationEntity.getNextLimitName());
assertEquals(100, contingencyLimitViolationEntity.getPatlLimit());
assertEquals(60 * 10, contingencyLimitViolationEntity.getAcceptableDuration());
assertEquals(60, contingencyLimitViolationEntity.getUpcomingAcceptableDuration());
assertEquals(100 * limitViolation.getValue() / contingencyLimitViolationEntity.getPatlLimit(), contingencyLimitViolationEntity.getPatlLoading());
}

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

SubjectLimitViolationEntity subjectLimitViolationEntity = new SubjectLimitViolationEntity("NHV1_NHV2_1", "NHV1_NHV2_1_name");
SubjectLimitViolationEntity subjectLimitViolationEntity = new SubjectLimitViolationEntity(NHV1_NHV2_1, "NHV1_NHV2_1_name");

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

assertEquals(expectedNextLimitName, contingencyLimitViolationEntity.getNextLimitName());
assertEquals(expectedPatlLimit, contingencyLimitViolationEntity.getPatlLimit());
assertEquals(expectedAcceptableDuration, contingencyLimitViolationEntity.getAcceptableDuration());
assertEquals(expectedUpcomingAcceptableDuration, contingencyLimitViolationEntity.getUpcomingAcceptableDuration());
assertEquals(100 * limitViolation.getValue() / contingencyLimitViolationEntity.getPatlLimit(), contingencyLimitViolationEntity.getPatlLoading());
}
}