com.powsybl.action.simulator.loadflow.LoadFlowActionSimulator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of powsybl-action-simulator Show documentation
Show all versions of powsybl-action-simulator Show documentation
A tool to run simulations with preventive or curative actions
/**
* Copyright (c) 2017-2018, 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.action.simulator.loadflow;
import com.powsybl.action.dsl.*;
import com.powsybl.action.dsl.ast.*;
import com.powsybl.action.simulator.ActionSimulator;
import com.powsybl.commons.PowsyblException;
import com.powsybl.commons.exceptions.UncheckedIllegalAccessException;
import com.powsybl.commons.exceptions.UncheckedInstantiationException;
import com.powsybl.computation.ComputationManager;
import com.powsybl.contingency.Contingency;
import com.powsybl.dsl.ast.ExpressionNode;
import com.powsybl.iidm.network.Network;
import com.powsybl.loadflow.LoadFlow;
import com.powsybl.loadflow.LoadFlowFactory;
import com.powsybl.loadflow.LoadFlowParameters;
import com.powsybl.loadflow.LoadFlowResult;
import com.powsybl.security.LimitViolation;
import com.powsybl.security.LimitViolationFilter;
import com.powsybl.security.LimitViolationType;
import com.powsybl.security.Security;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author Geoffroy Jamgotchian
* @author Teofil Calin BANC
*/
public class LoadFlowActionSimulator implements ActionSimulator {
private static final Logger LOGGER = LoggerFactory.getLogger(LoadFlowActionSimulator.class);
private static final LimitViolationFilter LIMIT_VIOLATION_FILTER = new LimitViolationFilter(EnumSet.of(LimitViolationType.CURRENT), 0.0);
static final LimitViolationFilter NO_FILTER = new LimitViolationFilter();
private final Network network;
private final ComputationManager computationManager;
private final LoadFlowActionSimulatorConfig config;
private final boolean applyIfSolvedViolations;
private final List observers;
public LoadFlowActionSimulator(Network network, ComputationManager computationManager) {
this(network, computationManager, LoadFlowActionSimulatorConfig.load(), false, Collections.emptyList());
}
public LoadFlowActionSimulator(Network network, ComputationManager computationManager, LoadFlowActionSimulatorConfig config,
boolean applyIfSolvedViolations, LoadFlowActionSimulatorObserver... observers) {
this(network, computationManager, config, applyIfSolvedViolations, Arrays.asList(observers));
}
public LoadFlowActionSimulator(Network network, ComputationManager computationManager, LoadFlowActionSimulatorConfig config,
boolean applyIfSolvedViolations, List observers) {
this.network = Objects.requireNonNull(network);
this.computationManager = Objects.requireNonNull(computationManager);
this.config = Objects.requireNonNull(config);
this.observers = Objects.requireNonNull(observers);
this.applyIfSolvedViolations = applyIfSolvedViolations;
}
@Override
public String getName() {
return "loadflow";
}
ComputationManager getComputationManager() {
return computationManager;
}
LoadFlowActionSimulatorConfig getConfig() {
return config;
}
protected Network getNetwork() {
return network;
}
protected boolean isApplyIfSolvedViolations() {
return applyIfSolvedViolations;
}
@Override
public void start(ActionDb actionDb, String... contingencyIds) {
start(actionDb, Arrays.asList(contingencyIds));
}
@Override
public void start(ActionDb actionDb, List contingencyIds) {
Objects.requireNonNull(actionDb);
LOGGER.info("Starting pre-contingency analysis");
RunningContext runningContext = new RunningContext(network);
observers.forEach(o -> o.beforePreContingencyAnalysis(runningContext));
boolean preContingencyAnalysisOk = next(actionDb, runningContext);
observers.forEach(LoadFlowActionSimulatorObserver::afterPreContingencyAnalysis);
NetworkCopyStrategy strategy = NetworkCopyStrategy.getInstance(config.getCopyStrategy(), runningContext.getNetwork());
if (preContingencyAnalysisOk || config.isIgnorePreContingencyViolations()) {
for (String contingencyId : contingencyIds) {
Contingency contingency = actionDb.getContingency(contingencyId);
Network network2 = strategy.createState(contingencyId);
RunningContext runningContext2 = new RunningContext(network2, contingency);
observers.forEach(o -> o.beforePostContingencyAnalysis(runningContext2));
LOGGER.info("Starting post-contingency analysis '{}'", contingency.getId());
contingency.toTask().modify(network2, computationManager);
observers.forEach(o -> o.postContingencyAnalysisNetworkLoaded(runningContext2));
next(actionDb, runningContext2);
strategy.removeState();
}
}
observers.forEach(LoadFlowActionSimulatorObserver::afterPostContingencyAnalysis);
}
protected LoadFlowFactory newLoadFlowFactory() {
try {
return config.getLoadFlowFactoryClass().newInstance();
} catch (InstantiationException e) {
throw new UncheckedInstantiationException(e);
} catch (IllegalAccessException e) {
throw new UncheckedIllegalAccessException(e);
}
}
private static final class RuleContext {
private final RuleEvaluationStatus status;
private final Map variables;
private final Map actions;
private RuleContext(RuleEvaluationStatus status, Map variables, Map actions) {
this.status = Objects.requireNonNull(status);
this.variables = Objects.requireNonNull(variables);
this.actions = Objects.requireNonNull(actions);
}
private RuleEvaluationStatus getStatus() {
return status;
}
private Map getVariables() {
return variables;
}
private Map getActions() {
return actions;
}
}
private RuleContext evaluateRule(Rule rule, RunningContext context) {
if (rule.getCondition().getType() != ConditionType.EXPRESSION) {
throw new AssertionError("TODO");
}
ExpressionNode conditionExpr = ((ExpressionCondition) rule.getCondition()).getNode();
EvaluationContext evalContext = new EvaluationContext() {
@Override
public Network getNetwork() {
return context.getNetwork();
}
@Override
public Contingency getContingency() {
return context.getContingency();
}
@Override
public boolean isActionTaken(String actionId) {
return context.getTimeLine().actionTaken(actionId);
}
};
boolean ok = ActionExpressionEvaluator.evaluate(conditionExpr, evalContext).equals(Boolean.TRUE);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Evaluating {} to {}", ActionExpressionPrinter.toString(conditionExpr), Boolean.toString(ok));
}
Map variables = ExpressionVariableLister.list(conditionExpr).stream()
.collect(Collectors.toMap(ActionExpressionPrinter::toString,
n -> ActionExpressionEvaluator.evaluate(n, evalContext),
(v1, v2) -> v1,
TreeMap::new));
LOGGER.debug("Variables values: {}", variables);
RuleEvaluationStatus status;
if (ok) {
status = RuleEvaluationStatus.TRUE;
context.incrementRuleMatchCount(rule.getId());
} else {
status = RuleEvaluationStatus.FALSE;
}
Map actions = ExpressionActionTakenLister.list(conditionExpr).stream()
.collect(Collectors.toMap(s -> s,
s -> context.getTimeLine().actionTaken(s),
(s1, s2) -> s1,
TreeMap::new));
return new RuleContext(status, variables, actions);
}
private void applyActions(ActionDb actionDb, RunningContext context, Rule rule, Set actionsTaken) {
for (String actionId : rule.getActions()) {
Action action = actionDb.getAction(actionId);
// apply action
LOGGER.info("Apply action '{}'", action.getId());
observers.forEach(o -> o.beforeAction(context, actionId));
action.run(context.getNetwork(), computationManager);
observers.forEach(o -> o.afterAction(context, actionId));
actionsTaken.add(actionId);
}
}
private boolean checkViolations(ActionDb actionDb, RunningContext context) {
List violations = LIMIT_VIOLATION_FILTER.apply(Security.checkLimits(context.getNetwork(), 1), context.getNetwork());
observers.forEach(o -> o.loadFlowConverged(context, violations));
// no more violations => work complete
if (violations.isEmpty()) {
LOGGER.info("No more violation");
observers.forEach(o -> o.noMoreViolations(context));
return true;
}
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Violations: \n{}", Security.printLimitsViolations(violations, network, NO_FILTER));
}
if (context.getRound() + 1 == config.getMaxIterations()) {
LOGGER.info("Max number of iterations reached");
observers.forEach(o -> o.maxIterationsReached(context));
return false;
}
runTests(actionDb, context);
if (context.isTestWorks() && applyIfSolvedViolations) {
return true;
}
Set actionsTaken = new HashSet<>();
for (Rule rule : actionDb.getRules()) {
if (rule.getType().equals(RuleType.TEST)) {
continue;
}
RuleContext ruleContext;
if (context.getRuleMatchCount(rule.getId()) >= rule.getLife()) {
ruleContext = new RuleContext(RuleEvaluationStatus.DEAD, Collections.emptyMap(), Collections.emptyMap());
} else {
ruleContext = evaluateRule(rule, context);
}
observers.forEach(o -> o.ruleChecked(context, rule, ruleContext.getStatus(), ruleContext.getVariables(), ruleContext.getActions()));
if (ruleContext.getStatus() == RuleEvaluationStatus.TRUE) {
applyActions(actionDb, context, rule, actionsTaken);
}
}
// record the action in the time line
context.getTimeLine().getActions().addAll(actionsTaken);
observers.forEach(o -> o.roundEnd(context));
if (!actionsTaken.isEmpty()) {
context.setRound(context.getRound() + 1);
return next(actionDb, context);
} else {
LOGGER.info("Still some violations and no rule match");
observers.forEach(o -> o.violationsAnymoreAndNoRulesMatch(context));
return false;
}
}
private boolean next(ActionDb actionDb, RunningContext context) {
observers.forEach(o -> o.roundBegin(context));
LoadFlowFactory loadFlowFactory = newLoadFlowFactory();
LoadFlow loadFlow = loadFlowFactory.create(context.getNetwork(), computationManager, 0);
LOGGER.info("Running loadflow ({})", loadFlow.getName());
LoadFlowResult result;
try {
result = loadFlow.run(context.getNetwork().getVariantManager().getWorkingVariantId(), LoadFlowParameters.load()).join();
} catch (Exception e) {
throw new PowsyblException(e);
}
if (result.isOk()) {
return checkViolations(actionDb, context);
} else {
LOGGER.warn("Loadflow diverged: {}", result.getMetrics());
observers.forEach(o -> o.loadFlowDiverged(context));
return false;
}
}
private void runTests(ActionDb actionDb, RunningContext context) {
// test actions
EvaluationContext evalContext = new EvaluationContext() {
@Override
public Network getNetwork() {
return context.getNetwork();
}
@Override
public Contingency getContingency() {
return context.getContingency();
}
@Override
public boolean isActionTaken(String actionId) {
return context.getTimeLine().actionTaken(actionId);
}
};
List activedRules = actionDb.getRules().stream()
.filter(rule -> rule.getType().equals(RuleType.TEST))
.filter(rule -> {
ExpressionNode conditionExpr = ((ExpressionCondition) rule.getCondition()).getNode();
return ActionExpressionEvaluator.evaluate(conditionExpr, evalContext).equals(Boolean.TRUE);
})
.collect(Collectors.toList());
List testActionIds = activedRules.stream()
.flatMap(r -> r.getActions().stream())
.distinct()
.filter(id -> !context.isTested(id))
.collect(Collectors.toList());
if (testActionIds.isEmpty()) {
return;
}
NetworkCopyStrategy strategy = NetworkCopyStrategy.getInstance(config.getCopyStrategy(), context.getNetwork());
for (String actionId : testActionIds) {
Action action = actionDb.getAction(actionId);
Network networkForTest = strategy.createState(actionId);
LoadFlowResult testResult = runTest(context, networkForTest, action);
context.addTested(actionId);
if (testResult.isOk()) {
List violationsInTest =
LIMIT_VIOLATION_FILTER.apply(Security.checkLimits(networkForTest, 1), networkForTest);
if (violationsInTest.isEmpty()) {
context.addWorkedTest(action.getId());
if (applyIfSolvedViolations) {
LOGGER.info("Loadflow with test '{}' works already and exits simulation", action.getId());
observers.forEach(o -> o.noMoreViolationsAfterTest(context, action.getId()));
observers.forEach(o -> o.beforeApplyTest(context, action.getId()));
action.run(context.getNetwork(), computationManager);
context.getTimeLine().getActions().add(actionId);
observers.forEach(o -> o.loadFlowConverged(context, violationsInTest));
observers.forEach(o -> o.noMoreViolations(context));
observers.forEach(o -> o.afterApplyTest(context, action.getId()));
return;
} else {
LOGGER.info("Loadflow with test '{}' works already and continues simulation", action.getId());
observers.forEach(o -> o.noMoreViolationsAfterTest(context, action.getId()));
}
} else {
LOGGER.info("Loadflow with test '{}' exits with violations", action.getId());
observers.forEach(o -> o.violationsAfterTest(action.getId(), violationsInTest));
}
} else {
LOGGER.info("Loadflow with test '{}' diverged", action.getId());
observers.forEach(o -> o.divergedAfterTest(action.getId()));
}
strategy.removeState();
}
}
private LoadFlowResult runTest(RunningContext context, Network networkForTry, Action action) {
String actionId = action.getId();
LOGGER.info("Test action '{}'", actionId);
action.run(networkForTry, computationManager);
LoadFlowFactory loadFlowFactory = newLoadFlowFactory();
LoadFlow testLoadFlow = loadFlowFactory.create(networkForTry, computationManager, 0);
try {
observers.forEach(o -> o.beforeTest(context, actionId));
LoadFlowResult testResult = testLoadFlow.run(networkForTry.getVariantManager().getWorkingVariantId(), LoadFlowParameters.load()).join();
observers.forEach(o -> o.afterTest(context, actionId));
return testResult;
} catch (Exception e) {
throw new PowsyblException(e);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy