Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
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 @@ -118,6 +118,9 @@ public class ModificationInfos {
@Schema(description = "Modification activated (defaults to true at creation when not provided)")
private Boolean activated;

@Schema(description = "Modification applicability per root network tag (a tag without an entry is applicable)")
private Map<String, Boolean> applicabilityByRootNetworkTag;

@Schema(description = "User description")
private String description;

Expand All @@ -144,6 +147,20 @@ public Map<String, String> getMapMessageValues() {
return Map.of();
}

/**
* A modification is activated on a root network when it is not stashed, when it is globally activated and when
* its applicability for that root network tag is not explicitly set to false. A tag without any entry is
* applicable, and a null tag matches any root network.
*/
public boolean isActivatedOn(String rootNetworkTag) {
if (Boolean.TRUE.equals(stashed) || !Boolean.TRUE.equals(activated)) {
return false;
}
return rootNetworkTag == null
|| applicabilityByRootNetworkTag == null
|| !Boolean.FALSE.equals(applicabilityByRootNetworkTag.get(rootNetworkTag));
Comment thread
Mathieu-Deharbe marked this conversation as resolved.
}

@JsonIgnore
public void check() {
// To check input DTO before hypothesis creation. Nothing to check here
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/
package org.gridsuite.modification.modifications;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
Expand All @@ -16,6 +17,7 @@
import com.powsybl.iidm.network.Network;
import lombok.AccessLevel;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.gridsuite.modification.IFilterService;
import org.gridsuite.modification.ILoadFlowService;
Expand All @@ -33,7 +35,7 @@
* the {@code @JsonSubTypes} registry of this class.
*
* <p>The injected application context ({@code filterService}, {@code loadFlowService}) is not serialized.
* After deserialization, {@link #initApplicationContext(IFilterService, ILoadFlowService)} must be called
* After deserialization, {@link #initApplicationContext(IFilterService, ILoadFlowService, String)} must be called
* again with valid services before the modification can be applied.
*
* @author Slimane Amar <slimane.amar at rte-france.com>
Expand Down Expand Up @@ -96,6 +98,11 @@
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public abstract class AbstractModification extends AbstractNetworkModification {

@JsonIgnore
@EqualsAndHashCode.Exclude
@Getter
private String rootNetworkTag;

@Override
public void apply(Network network, NamingStrategy namingStrategy, boolean throwException, ComputationManager computationManager, ReportNode reportNode) {
apply(network, reportNode);
Expand All @@ -106,13 +113,18 @@ public void check(Network network) throws NetworkModificationException {
}

/**
* Injects the application context services ({@code filterService}, {@code loadFlowService}) required
* to {@link #apply(Network, ReportNode)}.
* Injects the application context required to {@link #apply(Network, ReportNode)}: the services, and the tag of
* the root network being applied on.
*
* <p>These services are not serialized with the modification: after deserialization, this method must
* be called again with valid services before the modification can be applied.
* <p>None of it is serialized with the modification: after deserialization, this method must be called again
* before the modification can be applied.
*/
public void initApplicationContext(IFilterService filterService, ILoadFlowService loadFlowService) {
public final void initApplicationContext(IFilterService filterService, ILoadFlowService loadFlowService, String rootNetworkTag) {
this.rootNetworkTag = rootNetworkTag;
initServices(filterService, loadFlowService);
}

protected void initServices(IFilterService filterService, ILoadFlowService loadFlowService) {
// To add some specific information
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ protected AbstractScaling(List<ScalingVariationInfos> variations, VariationType
}

@Override
public void initApplicationContext(IFilterService filterService, ILoadFlowService loadFlowService) {
protected void initServices(IFilterService filterService, ILoadFlowService loadFlowService) {
this.filterService = filterService;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public BalancesAdjustmentModification(List<BalancesAdjustmentAreaInfos> areas,
}

@Override
public void initApplicationContext(IFilterService filterService, ILoadFlowService loadFlowService) {
protected void initServices(IFilterService filterService, ILoadFlowService loadFlowService) {
this.loadFlowService = loadFlowService;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public ByFilterDeletion(IdentifiableType equipmentType, List<FilterInfos> filter
}

@Override
public void initApplicationContext(IFilterService filterService, ILoadFlowService loadFlowService) {
protected void initServices(IFilterService filterService, ILoadFlowService loadFlowService) {
this.filterService = filterService;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public CompositeModification(CompositeModificationInfos compositeModificationInf
}

@Override
public void initApplicationContext(IFilterService filterService, ILoadFlowService loadFlowService) {
protected void initServices(IFilterService filterService, ILoadFlowService loadFlowService) {
this.filterService = filterService;
this.loadFlowService = loadFlowService;
}
Expand All @@ -61,15 +61,14 @@ public void apply(Network network, ReportNode subReportNode) {
@Override
public void apply(Network network, NamingStrategy namingStrategy, ReportNode subReportNode) {
compositeModificationInfos.getModificationsInfos().stream()
.filter(modificationInfos -> Boolean.TRUE.equals(modificationInfos.getActivated())
&& Boolean.FALSE.equals(modificationInfos.getStashed()))
.filter(modificationInfos -> modificationInfos.isActivatedOn(getRootNetworkTag()))
.forEach(
modif -> {
ReportNode modifNode = modif.createSubReportNode(subReportNode);
AbstractModification modification = modif.toModification();
try {
modification.check(network);
modification.initApplicationContext(filterService, loadFlowService);
modification.initApplicationContext(filterService, loadFlowService, getRootNetworkTag());
modification.apply(network, namingStrategy, modifNode);
} catch (Exception e) {
// in case of error in a network modification, the composite modification doesn't interrupt its execution :
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ private static final class GeneratorsFrequencyReserve {
}

@Override
public void initApplicationContext(IFilterService filterService, ILoadFlowService loadFlowService) {
protected void initServices(IFilterService filterService, ILoadFlowService loadFlowService) {
this.filterService = filterService;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public ModificationReference(UUID referenceId,
}

@Override
public void initApplicationContext(IFilterService filterService, ILoadFlowService loadFlowService) {
protected void initServices(IFilterService filterService, ILoadFlowService loadFlowService) {
this.filterService = filterService;
this.loadFlowService = loadFlowService;
}
Expand All @@ -75,7 +75,7 @@ public void apply(Network network, ReportNode subReportNode) {
public void apply(Network network, NamingStrategy namingStrategy, ReportNode subReportNode) {
AbstractModification modification = referenceInfos.toModification();
modification.check(network);
modification.initApplicationContext(filterService, loadFlowService);
modification.initApplicationContext(filterService, loadFlowService, getRootNetworkTag());
modification.apply(network, namingStrategy, referenceInfos.createSubReportNode(subReportNode));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ protected String applyValue(Identifiable<?> equipment, AbstractAssignmentInfos a
}

@Override
public void initApplicationContext(IFilterService filterService, ILoadFlowService loadFlowService) {
protected void initServices(IFilterService filterService, ILoadFlowService loadFlowService) {
this.filterService = filterService;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
import com.powsybl.commons.report.ReportNode;
import org.junit.jupiter.api.Test;

import java.util.Collections;
import java.util.Map;

import static org.junit.jupiter.api.Assertions.*;

/**
Expand All @@ -17,11 +20,21 @@
*/
class ModificationInfosTest {

private static final String TAG = "PH1";
private static final String OTHER_TAG = "PH2";

private static final class TestModificationInfos extends ModificationInfos {
// Intentionally does not override createSubReportNode() or toModification()
// to test the UnsupportedOperationException throwing behavior
}

private static ModificationInfos modificationInfos(Boolean activated, Map<String, Boolean> applicabilityByRootNetworkTag) {
ModificationInfos modificationInfos = new TestModificationInfos();
modificationInfos.setActivated(activated);
modificationInfos.setApplicabilityByRootNetworkTag(applicabilityByRootNetworkTag);
return modificationInfos;
}

@Test
void testCreateSubReportNodeThrowsUnsupportedOperationException() {
ModificationInfos modificationInfos = new TestModificationInfos();
Expand Down Expand Up @@ -52,4 +65,71 @@ void testToModificationThrowsUnsupportedOperationException() {
assertEquals(expectedMessage, exception.getMessage(),
"Exception message should indicate which method and class need implementation");
}

@Test
void testNotActivatedWhenModificationIsStashed() {
ModificationInfos modificationInfos = modificationInfos(true, Map.of(TAG, true));
modificationInfos.setStashed(true);
assertFalse(modificationInfos.isActivatedOn(TAG),
"A stashed modification is activated on no root network, whatever its applicabilities");
Comment thread
Mathieu-Deharbe marked this conversation as resolved.
assertFalse(modificationInfos.isActivatedOn(null),
"A stashed modification is not activated without a root network context");
}

@Test
void testActivatedWhenStashedIsUndefined() {
ModificationInfos modificationInfos = modificationInfos(true, Map.of(TAG, true));
modificationInfos.setStashed(null);
assertTrue(modificationInfos.isActivatedOn(TAG),
"An undefined stash flag keeps the default of the field: the modification is not stashed");
}

@Test
void testNotActivatedWhenModificationIsDeactivated() {
assertFalse(modificationInfos(false, Map.of(TAG, true)).isActivatedOn(TAG),
"A deactivated modification is activated on no root network, whatever its applicabilities");
assertFalse(modificationInfos(null, Map.of(TAG, true)).isActivatedOn(TAG),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

As a side note this should'nt happen if we take the word of "activated" field description "Modification activated (defaults to true at creation when not provided)"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It's defaulted to true but it doesn't mean null value means activated.

"An undefined activation flag is not an activation");
}

@Test
void testActivatedWhenNoRootNetworkTagGiven() {
assertTrue(modificationInfos(true, Map.of(TAG, false)).isActivatedOn(null),
"A null tag means no root network context: the per root network applicabilities are then ignored");
}

@Test
void testActivatedWhenNoApplicabilityDefined() {
assertTrue(modificationInfos(true, null).isActivatedOn(TAG),
"A modification without any applicability is activated on every root network");
}

@Test
void testActivatedWhenTagHasNoEntry() {
assertTrue(modificationInfos(true, Map.of()).isActivatedOn(TAG),
"A modification without any applicability entry for a tag is activated on it");
assertTrue(modificationInfos(true, Map.of(OTHER_TAG, false)).isActivatedOn(TAG),
"An entry deactivating another tag leaves this one applicable");
}

@Test
void testActivatedWhenTagEntryIsNull() {
// singletonMap, not Map.of, which rejects a null value
assertTrue(modificationInfos(true, Collections.singletonMap(TAG, null)).isActivatedOn(TAG),
"A tag mapped to no value is applicable: only an explicit false deactivates it");
}

@Test
void testActivationFollowsTagEntry() {
assertTrue(modificationInfos(true, Map.of(TAG, true)).isActivatedOn(TAG));
assertFalse(modificationInfos(true, Map.of(TAG, false)).isActivatedOn(TAG));
}

@Test
void testTagsAreIndependent() {
ModificationInfos modificationInfos = modificationInfos(true, Map.of(TAG, false, OTHER_TAG, true));
assertFalse(modificationInfos.isActivatedOn(TAG));
assertTrue(modificationInfos.isActivatedOn(OTHER_TAG),
"Deactivating a tag must not affect the other ones");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ public void testRoundTripSerializationDeserialization() throws JsonProcessingExc
ILoadFlowService loadFlowServiceMock = mock(ILoadFlowService.class);
IFilterService filterServiceMock = mock(IFilterService.class);
AbstractModification expectedModification = buildModification().toModification();
expectedModification.initApplicationContext(filterServiceMock, loadFlowServiceMock);
expectedModification.initApplicationContext(filterServiceMock, loadFlowServiceMock, null);

String serializedModification = mapper.writeValueAsString(expectedModification);
AbstractModification deserializedModification = mapper.readValue(serializedModification, AbstractModification.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ void testApplyWithLoadFlow() {
)))
.build());
BalancesAdjustmentModification modification = (BalancesAdjustmentModification) infos.toModification();
modification.initApplicationContext(null, loadFlowService);
modification.initApplicationContext(null, loadFlowService, null);
modification.apply(getNetwork(), new DefaultNamingStrategy(), ReportNode.NO_OP);

assertEquals(-58d, getNetwork().getGenerator("GH1").getTerminal().getP(), PRECISION);
Expand Down Expand Up @@ -193,7 +193,7 @@ void testLoadFlowParametersNotFound() {
.thenReturn(null);

BalancesAdjustmentModification modification = (BalancesAdjustmentModification) infos.toModification();
modification.initApplicationContext(null, loadFlowService);
modification.initApplicationContext(null, loadFlowService, null);

Network network = getNetwork();
ReportNode reportNode = ReportNode.newRootReportNode()
Expand Down Expand Up @@ -236,7 +236,7 @@ void testLoadFlowProviderNotSpecified() {
.build());

BalancesAdjustmentModification modification = (BalancesAdjustmentModification) infos.toModification();
modification.initApplicationContext(null, loadFlowService);
modification.initApplicationContext(null, loadFlowService, null);

Network network = getNetwork();
ReportNode reportNode = ReportNode.newRootReportNode()
Expand Down Expand Up @@ -272,7 +272,7 @@ void testLoadFlowParametersIdNull() {
.build();

BalancesAdjustmentModification modification = (BalancesAdjustmentModification) infos.toModification();
modification.initApplicationContext(null, loadFlowService);
modification.initApplicationContext(null, loadFlowService, null);

Network network = getNetwork();
ReportNode reportNode = ReportNode.newRootReportNode()
Expand Down
Loading
Loading