Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ public void check(Network network) throws NetworkModificationException {
checkIsNotNegativeValue(errorMessage, modificationInfos.getTargetV(), CREATE_GENERATOR_ERROR, "Target Voltage");
checkIsPercentage(errorMessage, modificationInfos.getDroop(), CREATE_GENERATOR_ERROR, "Droop");
checkIsNotNegativeValue(errorMessage, modificationInfos.getRatedS(), CREATE_GENERATOR_ERROR, "Rated apparent power");
checkPowerValues(errorMessage, modificationInfos.getMinP(), modificationInfos.getMaxP(), modificationInfos.getTargetP(),
modificationInfos.getPlannedActivePowerSetPoint(), CREATE_GENERATOR_ERROR);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,28 @@ public void check(Network network) throws NetworkModificationException {
if (modificationInfos.getTargetV() != null) {
checkIsNotNegativeValue(errorMessage, modificationInfos.getTargetV().getValue(), MODIFY_GENERATOR_ERROR, TARGET_VOLTAGE);
}
checkPowerValues(errorMessage, generator);
}

private void checkPowerValues(String errorMessage, Generator generator) {
GeneratorStartup generatorStartup = generator.getExtension(GeneratorStartup.class);
Double oldValue = generatorStartup != null && !Double.isNaN(generatorStartup.getPlannedActivePowerSetpoint())
? generatorStartup.getPlannedActivePowerSetpoint() : null;
double minP = modificationInfos.getMinP() != null ? modificationInfos.getMinP().getValue() : generator.getMinP();
double maxP = modificationInfos.getMaxP() != null ? modificationInfos.getMaxP().getValue() : generator.getMaxP();
double targetP = modificationInfos.getTargetP() != null ? modificationInfos.getTargetP().getValue() : generator.getTargetP();
Double plannedActivePowerSetPoint = modificationInfos.getPlannedActivePowerSetPoint() != null ?
modificationInfos.getPlannedActivePowerSetPoint().applyModification(oldValue) : null;

if (modificationInfos.getPlannedActivePowerSetPoint() != null) {
checkActivePowerValue(errorMessage, FIELD_PLANNED_ACTIVE_POWER_SET_POINT, plannedActivePowerSetPoint, minP, maxP, MODIFY_GENERATOR_ERROR);
}
if (modificationInfos.getMaxP() != null) {
checkMaximumActivePower(errorMessage, minP, targetP, plannedActivePowerSetPoint, maxP, MODIFY_GENERATOR_ERROR);
}
if (modificationInfos.getMinP() != null) {
checkMinimumActivePower(errorMessage, maxP, targetP, plannedActivePowerSetPoint, minP, MODIFY_GENERATOR_ERROR);
}
}

private void checkActivePowerZeroOrBetweenMinAndMaxActivePowerGenerator(GeneratorModificationInfos modificationInfos, Generator generator, NetworkModificationException.Type exceptionType, String errorMessage) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import com.powsybl.commons.report.ReportNode;
import com.powsybl.commons.report.TypedValue;
import com.powsybl.iidm.network.Generator;
import com.powsybl.iidm.network.Identifiable;
import com.powsybl.iidm.network.IdentifiableType;
import com.powsybl.iidm.network.Network;
Expand All @@ -34,6 +35,7 @@

import static org.gridsuite.modification.dto.byfilter.equipmentfield.FieldUtils.getFieldValue;
import static org.gridsuite.modification.dto.byfilter.equipmentfield.FieldUtils.setFieldValue;
import static org.gridsuite.modification.dto.byfilter.equipmentfield.GeneratorField.*;
import static org.gridsuite.modification.utils.ModificationUtils.*;

/**
Expand All @@ -42,6 +44,10 @@
public abstract class AbstractModificationByAssignment extends AbstractModification {
public static final String VALUE_KEY_FILTER_NAME = "filterName";
public static final String VALUE_KEY_FIELD_NAME = "fieldName";
public static final String VALUE_KEY_FIELD_VALUE = "fieldValue";
public static final String VALUE_KEY_MIN_VALUE = "minValue";
public static final String VALUE_KEY_MAX_VALUE = "maxValue";
public static final String VALUE_KEY_TARGET_VALUE = "targetValue";
public static final String VALUE_KEY_EQUIPMENT_NAME = "equipmentName";
public static final String VALUE_KEY_EQUIPMENT_TYPE = "equipmentType";
public static final String VALUE_KEY_EQUIPMENT_COUNT = "equipmentCount";
Expand Down Expand Up @@ -103,6 +109,25 @@ protected abstract boolean preCheckValue(Identifiable<?> equipment,

protected abstract String getNewValue(Identifiable<?> equipment, AbstractAssignmentInfos abstractAssignmentInfos);

protected boolean checkGeneratorsPowerValues(Identifiable<?> equipment, AbstractAssignmentInfos abstractAssignmentInfos, List<ReportNode> reports) {
if (equipment.getType() == IdentifiableType.GENERATOR) {
Generator generator = (Generator) equipment;
if (abstractAssignmentInfos.getEditedField().equals(PLANNED_ACTIVE_POWER_SET_POINT.name())) {
return validateActivePowerValue(generator, FIELD_PLANNED_ACTIVE_POWER_SET_POINT, reports, Double.parseDouble(getNewValue(equipment, abstractAssignmentInfos)));
} else if (abstractAssignmentInfos.getEditedField().equals(MINIMUM_ACTIVE_POWER.name())) {
return validateMinimumActivePower(generator, reports, Double.parseDouble(getNewValue(equipment, abstractAssignmentInfos)));
} else if (abstractAssignmentInfos.getEditedField().equals(MAXIMUM_ACTIVE_POWER.name())) {
return validateMaximumActivePower(generator, reports, Double.parseDouble(getNewValue(equipment, abstractAssignmentInfos)));
} else if (abstractAssignmentInfos.getEditedField().equals(ACTIVE_POWER_SET_POINT.name())) {
double newValue = Double.parseDouble(getNewValue(equipment, abstractAssignmentInfos));
if (newValue != 0) { // 0 is an exception to the rule
return validateActivePowerValue(generator, FIELD_ACTIVE_POWER_TARGET, reports, newValue);
}
}
}
return true;
}

protected String getOldValue(Identifiable<?> equipment, AbstractAssignmentInfos abstractAssignmentInfos) {
return getFieldValue(equipment, abstractAssignmentInfos.getEditedField());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ protected boolean preCheckValue(Identifiable<?> equipment, AbstractAssignmentInf
.build());
return false;
}
if (equipment.getType() == IdentifiableType.GENERATOR) {
return checkGeneratorsPowerValues(equipment, abstractAssignmentInfos, reports);
}
return true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ protected boolean isEquipmentEditable(Identifiable<?> equipment, AbstractAssignm

@Override
protected boolean preCheckValue(Identifiable<?> equipment, AbstractAssignmentInfos abstractAssignmentInfos, List<ReportNode> reports, List<String> notEditableEquipments) {
if (equipment.getType() == IdentifiableType.GENERATOR) {
return checkGeneratorsPowerValues(equipment, abstractAssignmentInfos, reports);
}
return true;
}

Expand Down
109 changes: 109 additions & 0 deletions src/main/java/org/gridsuite/modification/utils/ModificationUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import static org.gridsuite.modification.dto.OperationalLimitsGroupInfos.Applicability.SIDE1;
import static org.gridsuite.modification.dto.OperationalLimitsGroupInfos.Applicability.SIDE2;
import static org.gridsuite.modification.modifications.AbstractBranchModification.*;
import static org.gridsuite.modification.modifications.byfilter.AbstractModificationByAssignment.*;

/**
* @author Slimane Amar <slimane.amar at rte-france.com>
Expand Down Expand Up @@ -71,6 +72,10 @@ public final class ModificationUtils {
private static final String COULD_NOT_ACTION_EQUIPMENT_ON_SIDE = COULD_NOT_ACTION_EQUIPMENT + " on side %s";
public static final String CONNECT = "connect";
public static final String DISCONNECT = "disconnect";
public static final String FIELD_MAX_ACTIVE_POWER = "Maximum active power";
public static final String FIELD_MIN_ACTIVE_POWER = "Minimum active power";
public static final String FIELD_PLANNED_ACTIVE_POWER_SET_POINT = "Planned active power set point";
public static final String FIELD_ACTIVE_POWER_TARGET = "Active power target";

public static String applicabilityToString(OperationalLimitsGroupInfos.Applicability applicability) {
return switch (applicability) {
Expand Down Expand Up @@ -1921,6 +1926,110 @@ public static void checkLimitsGroupExist(String errorMessage, String limitsGroup
}
}

public static void checkActivePowerValue(String errorMessage, String fieldName, double newValue, double minP, double maxP, NetworkModificationException.Type exceptionType) throws NetworkModificationException {
if (newValue > maxP || newValue < minP) {
String message = String.format("Invalid value %.2f field %s should be within interval [%.2f; %.2f]", newValue, fieldName, minP, maxP);
throw new NetworkModificationException(exceptionType, errorMessage + message);
}
}

public static void checkPowerValues(String errorMessage, double minP, double maxP, double targetP, Double plannedActivePowerSetPoint, NetworkModificationException.Type exceptionType) throws NetworkModificationException {
if (targetP != 0) { // exception for the rule minP <= targetP <= maxP
checkActivePowerValue(errorMessage, FIELD_ACTIVE_POWER_TARGET, targetP, minP, maxP, exceptionType);
}
if (plannedActivePowerSetPoint != null) {
checkActivePowerValue(errorMessage, FIELD_PLANNED_ACTIVE_POWER_SET_POINT, plannedActivePowerSetPoint, minP, maxP, exceptionType);
}
checkMinimumActivePower(errorMessage, maxP, targetP, plannedActivePowerSetPoint, minP, exceptionType);
checkMaximumActivePower(errorMessage, minP, targetP, plannedActivePowerSetPoint, maxP, exceptionType);
}

public static void checkMinimumActivePower(String errorMessage, double maxP, double targetP, Double pImp, double newValue, NetworkModificationException.Type exceptionType) throws NetworkModificationException {
// targetP = 0 is an exception to the rule
double pMin = targetP != 0 ? Math.min(targetP, maxP) : maxP;
if (pImp != null) {
pMin = Math.min(pMin, pImp);
}
if (pMin < newValue) {
throw new NetworkModificationException(exceptionType, errorMessage + String.format("Invalid value %.2f of field %s should be be smaller or equal to %.2f", newValue, FIELD_MIN_ACTIVE_POWER, pMin));
}
}

public static void checkMaximumActivePower(String errorMessage, double minP, double targetP, Double plannedActivePowerSetPoint, double newValue, NetworkModificationException.Type exceptionType) throws NetworkModificationException {
// targetP = 0 is an exception to the rule
double pMax = targetP != 0 ? Math.max(targetP, minP) : minP;
if (plannedActivePowerSetPoint != null) {
pMax = Math.max(pMax, plannedActivePowerSetPoint);
}
if (pMax > newValue) {
throw new NetworkModificationException(exceptionType, errorMessage + String.format("Invalid value %.2f of field %s should be be greater or equal to %.2f", newValue, FIELD_MAX_ACTIVE_POWER, pMax));
}
}

public static boolean validateMinimumActivePower(Generator generator, List<ReportNode> reports, double newValue) {
GeneratorStartup generatorStartup = generator.getExtension(GeneratorStartup.class);
Double plannedActivePowerSetPoint = generatorStartup != null && !Double.isNaN(generatorStartup.getPlannedActivePowerSetpoint()) ? generatorStartup.getPlannedActivePowerSetpoint() : null;

// targetP = 0 is an exception to the rule
double minP = generator.getTargetP() != 0 ? Math.min(generator.getTargetP(), generator.getMaxP()) : generator.getMaxP();
if (plannedActivePowerSetPoint != null) {
minP = Math.min(minP, plannedActivePowerSetPoint);
}

if (minP < newValue) {
reports.add(ReportNode.newRootReportNode()
.withMessageTemplate("network.modification.generator.ValueShouldBeSmallerThan")
.withUntypedValue(VALUE_KEY_EQUIPMENT_NAME, generator.getId())
.withUntypedValue(VALUE_KEY_FIELD_NAME, FIELD_MIN_ACTIVE_POWER)
.withUntypedValue(VALUE_KEY_FIELD_VALUE, newValue)
.withUntypedValue(VALUE_KEY_TARGET_VALUE, minP)
.withSeverity(TypedValue.WARN_SEVERITY)
.build());
return false;
}
return true;
}

public static boolean validateMaximumActivePower(Generator generator, List<ReportNode> reports, double newValue) {
GeneratorStartup generatorStartup = generator.getExtension(GeneratorStartup.class);
Double pImp = generatorStartup != null && !Double.isNaN(generatorStartup.getPlannedActivePowerSetpoint()) ? generatorStartup.getPlannedActivePowerSetpoint() : null;

// targetP = 0 is an exception to the rule
double maxP = generator.getTargetP() != 0 ? Math.max(generator.getTargetP(), generator.getMinP()) : generator.getMinP();
if (pImp != null) {
maxP = Math.min(maxP, pImp);
}

if (newValue < maxP) {
reports.add(ReportNode.newRootReportNode()
.withMessageTemplate("network.modification.generator.ValueShouldBeGreaterThan")
.withUntypedValue(VALUE_KEY_EQUIPMENT_NAME, generator.getId())
.withUntypedValue(VALUE_KEY_FIELD_NAME, FIELD_MAX_ACTIVE_POWER)
.withUntypedValue(VALUE_KEY_FIELD_VALUE, newValue)
.withUntypedValue(VALUE_KEY_TARGET_VALUE, maxP)
.withSeverity(TypedValue.WARN_SEVERITY)
.build());
return false;
}
return true;
}

public static boolean validateActivePowerValue(Generator generator, String fieldName, List<ReportNode> reports, double newValue) {
if (newValue > generator.getMaxP() || newValue < generator.getMinP()) {
reports.add(ReportNode.newRootReportNode()
.withMessageTemplate("network.modification.generator.ValueShouldBeWithinInterval")
.withUntypedValue(VALUE_KEY_EQUIPMENT_NAME, generator.getId())
.withUntypedValue(VALUE_KEY_FIELD_NAME, fieldName)
.withUntypedValue(VALUE_KEY_FIELD_VALUE, newValue)
.withUntypedValue(VALUE_KEY_MIN_VALUE, generator.getMinP())
.withUntypedValue(VALUE_KEY_MAX_VALUE, generator.getMaxP())
.withSeverity(TypedValue.WARN_SEVERITY)
.build());
return false;
}
return true;
}

public static List<OperationalLimitsGroupInfos> getOperationalLimitsGroupsOnSide(List<OperationalLimitsGroupInfos> operationalLimitsGroupInfos,
OperationalLimitsGroupInfos.Applicability applicability) {
if (operationalLimitsGroupInfos == null || operationalLimitsGroupInfos.isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,9 @@ network.modification.generatorNotFound.generatorsFrequencyReserve = Frequency re
network.modification.generatorNotFound.generatorsWithFixedSupply = Generators with fixed active power: Cannot find generator ${notFoundGeneratorId} in filter ${filterName}
network.modification.generatorNotFound.generatorsWithoutOutage = Generators without outage simulation: Cannot find generator ${notFoundGeneratorId} in filter ${filterName}
network.modification.generatorScaling = Generator scaling
network.modification.generator.ValueShouldBeGreaterThan = Generator ${equipmentName} : Invalid value ${fieldValue} for field ${fieldName}. Value should be greater or equal to ${targetValue}.
network.modification.generator.ValueShouldBeSmallerThan = Generator ${equipmentName} : Invalid value ${fieldValue} for field ${fieldName}. Value should be smaller or equal to ${targetValue}.
network.modification.generator.ValueShouldBeWithinInterval = Generator ${equipmentName} : Invalid value ${fieldValue} for field ${fieldName}. Value should be within interval [${minValue}; ${maxValue}].
network.modification.groovyScript = Apply groovy script
network.modification.groovyScriptApplied = Groovy script applied
network.modification.invalidFilters = ${errorType}: There is no valid equipment ID among the provided filter(s)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ protected void createEquipments() {
getNetwork().getGenerator(GENERATOR_ID_2)
.setTargetP(200)
.setMaxP(2000)
.setMinP(50)
.setMinP(10)
.setTargetV(10)
.setTargetQ(20)
.newExtension(GeneratorStartupAdder.class)
Expand Down Expand Up @@ -243,7 +243,7 @@ protected List<AssignmentInfos<?>> getAssignmentInfos() {

DoubleAssignmentInfos assignmentInfos10 = DoubleAssignmentInfos.builder()
.editedField(GeneratorField.MAXIMUM_ACTIVE_POWER.name())
.value(50.)
.value(300.)
.filters(List.of(filter1, filter2, filter3, filter4, filter5))
.build();

Expand Down Expand Up @@ -338,7 +338,7 @@ protected void assertAfterNetworkModificationApplication() {
assertEquals(0.1, generatorStartup1.getPlannedOutageRate(), 0);
assertEquals(0.05, generatorStartup1.getForcedOutageRate(), 0);
assertEquals(10, generatorStartup1.getPlannedActivePowerSetpoint(), 0);
assertEquals(50, generator1.getMaxP(), 0);
assertEquals(300., generator1.getMaxP(), 0);
assertEquals(2, generator1.getMinP(), 0);
assertTrue(generator1.isVoltageRegulatorOn());
ActivePowerControl<Generator> activePowerControl1 = generator1.getExtension(ActivePowerControl.class);
Expand All @@ -353,7 +353,7 @@ protected void assertAfterNetworkModificationApplication() {
assertEquals(0.1, generatorStartup2.getPlannedOutageRate(), 0);
assertEquals(0.05, generatorStartup2.getForcedOutageRate(), 0);
assertEquals(10, generatorStartup2.getPlannedActivePowerSetpoint(), 0);
assertEquals(50, generator2.getMaxP(), 0);
assertEquals(300., generator2.getMaxP(), 0);
assertEquals(2, generator2.getMinP(), 0);

Generator generator3 = getNetwork().getGenerator(GENERATOR_ID_3);
Expand All @@ -362,7 +362,7 @@ protected void assertAfterNetworkModificationApplication() {
assertEquals(300, generator3.getTargetP(), 0);
assertEquals(0.2, generatorShortCircuit3.getDirectTransX(), 0);
assertEquals(0.3, generatorShortCircuit3.getStepUpTransformerX(), 0);
assertEquals(50, generator3.getMaxP(), 0);
assertEquals(300., generator3.getMaxP(), 0);
assertEquals(2, generator3.getMinP(), 0);

Generator generator4 = getNetwork().getGenerator(GENERATOR_ID_4);
Expand All @@ -371,19 +371,20 @@ protected void assertAfterNetworkModificationApplication() {
assertEquals(0.2, generatorShortCircuit4.getDirectTransX(), 0);
assertEquals(0.3, generatorShortCircuit4.getStepUpTransformerX(), 0);
assertEquals(400, generator4.getTargetP(), 0);
assertEquals(50, generator4.getMaxP(), 0);
//targetP is 400 MaxP won't change
assertEquals(700.0, generator4.getMaxP(), 0);
assertEquals(2, generator4.getMinP(), 0);

Generator generator5 = getNetwork().getGenerator(GENERATOR_ID_5);
ActivePowerControl<Generator> activePowerControl5 = generator5.getExtension(ActivePowerControl.class);
assertNotNull(activePowerControl5);
assertEquals(50, generator5.getMaxP(), 0);
assertEquals(300., generator5.getMaxP(), 0);
assertEquals(2, activePowerControl5.getDroop(), 0);

Generator generator6 = getNetwork().getGenerator(GENERATOR_ID_6);
ActivePowerControl<Generator> activePowerControl6 = generator6.getExtension(ActivePowerControl.class);
assertNotNull(activePowerControl6);
assertEquals(50, generator6.getMaxP(), 0);
assertEquals(300., generator6.getMaxP(), 0);
assertEquals(2, activePowerControl6.getDroop(), 0);

Generator generator7 = getNetwork().getGenerator(GENERATOR_ID_7);
Expand Down
Loading