Skip to content

Commit

Permalink
Accelerate state tree init (#979)
Browse files Browse the repository at this point in the history
* precompute usage methods per state and instant in abstractRemedialAction

Signed-off-by: Philippe Edwards <[email protected]>

* cleaned up code

Signed-off-by: Philippe Edwards <[email protected]>

* revert changes to pom

Signed-off-by: Philippe Edwards <[email protected]>

* added tests

Signed-off-by: Philippe Edwards <[email protected]>

* fix tests

Signed-off-by: Philippe Edwards <[email protected]>

---------

Signed-off-by: Philippe Edwards <[email protected]>
Co-authored-by: Philippe Edwards <[email protected]>
  • Loading branch information
phiedw and phiedw authored Apr 24, 2024
1 parent d1e5196 commit bcd6403
Show file tree
Hide file tree
Showing 2 changed files with 163 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
package com.powsybl.openrao.data.cracimpl;

import com.powsybl.openrao.commons.OpenRaoException;
import com.powsybl.openrao.data.cracapi.Instant;
import com.powsybl.openrao.data.cracapi.RemedialAction;
import com.powsybl.openrao.data.cracapi.State;
import com.powsybl.openrao.data.cracapi.cnec.Cnec;
Expand All @@ -16,10 +17,7 @@
import com.powsybl.iidm.network.Country;
import com.powsybl.iidm.network.Network;

import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.*;
import java.util.stream.Collectors;

/**
Expand All @@ -31,6 +29,9 @@ public abstract class AbstractRemedialAction<I extends RemedialAction<I>> extend
protected String operator;
protected Set<UsageRule> usageRules;
protected Integer speed;
private boolean computedUsageMethods = false;
private Map<State, UsageMethod> usageMethodPerState;
private Map<Instant, UsageMethod> usageMethodPerInstant;

protected AbstractRemedialAction(String id, String name, String operator, Set<UsageRule> usageRules, Integer speed) {
super(id, name);
Expand All @@ -40,6 +41,7 @@ protected AbstractRemedialAction(String id, String name, String operator, Set<Us
}

void addUsageRule(UsageRule usageRule) {
computedUsageMethods = false;
this.usageRules.add(usageRule);
}

Expand All @@ -65,10 +67,59 @@ public Optional<Integer> getSpeed() {

@Override
public UsageMethod getUsageMethod(State state) {
Set<UsageMethod> usageMethods = usageRules.stream()
.map(usageRule -> usageRule.getUsageMethod(state))
.collect(Collectors.toSet());
return UsageMethod.getStrongestUsageMethod(usageMethods);
if (!computedUsageMethods) {
computeUsageMethodPerStateAndInstant();
computedUsageMethods = true;
}
if (usageMethodPerState.getOrDefault(state, UsageMethod.UNDEFINED).equals(usageMethodPerInstant.getOrDefault(state.getInstant(), UsageMethod.UNDEFINED))) {
return usageMethodPerInstant.getOrDefault(state.getInstant(), UsageMethod.UNDEFINED);
}
return UsageMethod.getStrongestUsageMethod(Set.of(
usageMethodPerState.getOrDefault(state, UsageMethod.UNDEFINED),
usageMethodPerInstant.getOrDefault(state.getInstant(), UsageMethod.UNDEFINED)));
}

private void computeUsageMethodPerStateAndInstant() {
usageMethodPerState = new HashMap<>();
usageMethodPerInstant = new HashMap<>();

for (UsageRule usageRule : usageRules) {
if (usageRule.getInstant().isPreventive()) {
updateMapWithValue(usageMethodPerInstant, usageRule.getInstant(), usageRule.getUsageMethod());
} else if (usageRule instanceof OnFlowConstraint ofc) {
State state = ofc.getFlowCnec().getState();
updateMapWithValue(usageMethodPerState, state, usageRule.getUsageMethod());
} else if (usageRule instanceof OnAngleConstraint oac) {
State state = oac.getAngleCnec().getState();
updateMapWithValue(usageMethodPerState, state, usageRule.getUsageMethod());
} else if (usageRule instanceof OnVoltageConstraint ovc) {
State state = ovc.getVoltageCnec().getState();
updateMapWithValue(usageMethodPerState, state, usageRule.getUsageMethod());
} else if (usageRule instanceof OnContingencyState ocs) {
State state = ocs.getState();
updateMapWithValue(usageMethodPerState, state, usageRule.getUsageMethod());
} else if (usageRule instanceof OnFlowConstraintInCountry || usageRule instanceof OnInstant) {
updateMapWithValue(usageMethodPerInstant, usageRule.getInstant(), usageRule.getUsageMethod());
} else {
throw new OpenRaoException(String.format("Usage rule of type %s is not implemented yet.", usageRule.getClass().getName()));
}
}
}

private void updateMapWithValue(Map<Instant, UsageMethod> map, Instant key, UsageMethod value) {
if (!map.containsKey(key)) {
map.put(key, value);
} else if (!value.equals(map.get(key))) {
map.put(key, UsageMethod.getStrongestUsageMethod(Set.of(map.get(key), value)));
}
}

private void updateMapWithValue(Map<State, UsageMethod> map, State key, UsageMethod value) {
if (!map.containsKey(key)) {
map.put(key, value);
} else if (!value.equals(map.get(key))) {
map.put(key, UsageMethod.getStrongestUsageMethod(Set.of(map.get(key), value)));
}
}

/**
Expand Down Expand Up @@ -107,9 +158,9 @@ private <T extends UsageRule> List<T> getUsageRules(Class<T> usageRuleClass, Sta

private static boolean isCnecInCountry(Cnec<?> cnec, Country country, Network network) {
return cnec.getLocation(network).stream()
.filter(Optional::isPresent)
.map(Optional::get)
.anyMatch(cnecCountry -> cnecCountry.equals(country));
.filter(Optional::isPresent)
.map(Optional::get)
.anyMatch(cnecCountry -> cnecCountry.equals(country));
}

@Override
Expand All @@ -122,8 +173,8 @@ public boolean equals(Object o) {
}
AbstractRemedialAction<?> remedialAction = (AbstractRemedialAction<?>) o;
return super.equals(remedialAction)
&& new HashSet<>(usageRules).equals(new HashSet<>(remedialAction.getUsageRules()))
&& (operator != null && operator.equals(remedialAction.operator) || operator == null && remedialAction.operator == null);
&& new HashSet<>(usageRules).equals(new HashSet<>(remedialAction.getUsageRules()))
&& (operator != null && operator.equals(remedialAction.operator) || operator == null && remedialAction.operator == null);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* Copyright (c) 2024, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/

package com.powsybl.openrao.data.cracimpl;

import com.powsybl.iidm.network.Country;
import com.powsybl.openrao.data.cracapi.Instant;
import com.powsybl.openrao.data.cracapi.State;
import com.powsybl.openrao.data.cracapi.cnec.FlowCnec;
import com.powsybl.openrao.data.cracapi.usagerule.UsageMethod;
import com.powsybl.openrao.data.cracapi.usagerule.UsageRule;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

import java.util.Collections;
import java.util.Set;

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

/**
* @author Philippe Edwards {@literal <philippe.edwards at rte-france.com>}
*/
class RemedialActionTest {
@Test
void testNoUsageRulesShouldReturnUndefined() {
State state = Mockito.mock(State.class);
Set<UsageRule> usageRules = Collections.emptySet();
AbstractRemedialAction<?> ra = new NetworkActionImpl("id", "name", "operator", usageRules, Collections.emptySet(), 0);
assertEquals(UsageMethod.UNDEFINED, ra.getUsageMethod(state));
}

@Test
void testOnlyOneOnInstantUsageRule() {
State state = Mockito.mock(State.class);
Instant instant = Mockito.mock(Instant.class);
Mockito.doReturn(instant).when(state).getInstant();
Set<UsageRule> usageRules = Set.of(new OnInstantImpl(UsageMethod.AVAILABLE, instant));
AbstractRemedialAction<?> ra = new NetworkActionImpl("id", "name", "operator", usageRules, Collections.emptySet(), 0);
assertEquals(UsageMethod.AVAILABLE, ra.getUsageMethod(state));
}

@Test
void testStrongestInstantUsageRule() {
State state = Mockito.mock(State.class);
Instant instant = Mockito.mock(Instant.class);
Mockito.doReturn(instant).when(state).getInstant();
Set<UsageRule> usageRules = Set.of(
new OnInstantImpl(UsageMethod.AVAILABLE, instant),
new OnFlowConstraintInCountryImpl(UsageMethod.FORCED, instant, Country.FR));
AbstractRemedialAction<?> ra = new NetworkActionImpl("id", "name", "operator", usageRules, Collections.emptySet(), 0);
assertEquals(UsageMethod.FORCED, ra.getUsageMethod(state));
}

@Test
void testOnlyOneOnContingencyStateUsageRule() {
State state = Mockito.mock(State.class);
Instant instant = Mockito.mock(Instant.class);
Mockito.doReturn(false).when(instant).isPreventive();
Mockito.doReturn(instant).when(state).getInstant();
Set<UsageRule> usageRules = Set.of(new OnContingencyStateImpl(UsageMethod.AVAILABLE, state));
AbstractRemedialAction<?> ra = new NetworkActionImpl("id", "name", "operator", usageRules, Collections.emptySet(), 0);
assertEquals(UsageMethod.AVAILABLE, ra.getUsageMethod(state));
}

@Test
void testOnlyStrongestStateUsageRule() {
State state = Mockito.mock(State.class);
Instant instant = Mockito.mock(Instant.class);
Mockito.doReturn(false).when(instant).isPreventive();
Mockito.doReturn(instant).when(state).getInstant();

FlowCnec flowCnec = Mockito.mock(FlowCnec.class);
Mockito.doReturn(state).when(flowCnec).getState();

Set<UsageRule> usageRules = Set.of(
new OnContingencyStateImpl(UsageMethod.AVAILABLE, state),
new OnFlowConstraintImpl(UsageMethod.FORCED, instant, flowCnec));
AbstractRemedialAction<?> ra = new NetworkActionImpl("id", "name", "operator", usageRules, Collections.emptySet(), 0);
assertEquals(UsageMethod.FORCED, ra.getUsageMethod(state));
}

@Test
void testStrongestStateAndInstantUsageRule() {
State state = Mockito.mock(State.class);
Instant instant = Mockito.mock(Instant.class);
Mockito.doReturn(false).when(instant).isPreventive();
Mockito.doReturn(instant).when(state).getInstant();

Set<UsageRule> usageRules = Set.of(
new OnContingencyStateImpl(UsageMethod.AVAILABLE, state),
new OnInstantImpl(UsageMethod.FORCED, instant));
AbstractRemedialAction<?> ra = new NetworkActionImpl("id", "name", "operator", usageRules, Collections.emptySet(), 0);
assertEquals(UsageMethod.FORCED, ra.getUsageMethod(state));
}
}

0 comments on commit bcd6403

Please sign in to comment.