Skip to content

Commit 7014908

Browse files
Merge branch 'main' into connectivity-loss-in-connectivity-break-analysis
2 parents 4f92d7c + 71db750 commit 7014908

38 files changed

Lines changed: 1999 additions & 943 deletions

File tree

docs/sensitivity/sensitivity.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ $$
5858
s_{b,kl}^c = s_{b,kl} - \sum_{g \in U} r^c_g s_{g,kl}
5959
$$
6060

61-
We only support for the moment balance type `PROPORTIONAL_TO_GENERATION_P_MAX` and `PROPORTIONAL_TO_LOAD`.
61+
We only support for the moment balance type `PROPORTIONAL_TO_GENERATION_P_MAX`, `PROPORTIONAL_TO_GENERATION_P` and `PROPORTIONAL_TO_LOAD`.
6262

6363
### Contingency management
6464

src/main/java/com/powsybl/openloadflow/ac/outerloop/ReactiveLimitsOuterLoop.java

Lines changed: 64 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,7 @@
1111
import com.powsybl.openloadflow.ac.AcOuterLoopContext;
1212
import com.powsybl.openloadflow.lf.outerloop.OuterLoopResult;
1313
import com.powsybl.openloadflow.lf.outerloop.OuterLoopStatus;
14-
import com.powsybl.openloadflow.network.GeneratorVoltageControl;
15-
import com.powsybl.openloadflow.network.LfBus;
16-
import com.powsybl.openloadflow.network.LfNetwork;
17-
import com.powsybl.openloadflow.network.VoltageControl;
14+
import com.powsybl.openloadflow.network.*;
1815
import com.powsybl.openloadflow.util.PerUnit;
1916
import com.powsybl.openloadflow.util.Reports;
2017
import org.apache.commons.lang3.mutable.MutableInt;
@@ -136,6 +133,10 @@ private boolean switchPvPq(List<ControllerBusToPqBus> pvToPqBuses, int remaining
136133
if (!pvToPqBuses.isEmpty()) {
137134
done = true;
138135

136+
ReportNode summary = Reports.reportPvToPqBuses(reportNode, pvToPqBuses.size(), modifiedRemainingPvBusCount);
137+
138+
boolean log = LOGGER.isTraceEnabled();
139+
139140
for (ControllerBusToPqBus pvToPqBus : pvToPqBuses) {
140141
LfBus controllerBus = pvToPqBus.controllerBus;
141142

@@ -146,30 +147,23 @@ private boolean switchPvPq(List<ControllerBusToPqBus> pvToPqBuses, int remaining
146147
// increment PV -> PQ switch counter
147148
contextData.incrementPvPqSwitchCount(controllerBus.getId());
148149

149-
if (LOGGER.isTraceEnabled()) {
150-
switch (pvToPqBus.limitType) {
151-
case MAX_Q :
152-
LOGGER.trace("Switch bus '{}' PV -> PQ, q={} > maxQ={}", controllerBus.getId(), pvToPqBus.q * PerUnit.SB,
153-
pvToPqBus.qLimit * PerUnit.SB);
154-
break;
155-
case MIN_Q:
156-
LOGGER.trace("Switch bus '{}' PV -> PQ, q={} < minQ={}", controllerBus.getId(), pvToPqBus.q * PerUnit.SB,
157-
pvToPqBus.qLimit * PerUnit.SB);
158-
break;
159-
case MIN_REALISTIC_V:
160-
LOGGER.trace("Switch bus '{}' PV -> PQ, q set to {} = targetQ - v is below realistic voltage limit ({}pu) when remote voltage target is maintained",
161-
controllerBus.getId(), pvToPqBus.qLimit * PerUnit.SB, minRealisticVoltage);
162-
break;
163-
case MAX_REALISTIC_V:
164-
LOGGER.trace("Switch bus '{}' PV -> PQ, q set to {} = targetQ - v is above realistic voltage limits ({}pu) when remote voltage target is maintained",
165-
controllerBus.getId(), pvToPqBus.qLimit * PerUnit.SB, maxRealisticVoltage);
166-
break;
167-
}
150+
switch (pvToPqBus.limitType) {
151+
case MAX_Q :
152+
Reports.reportPvToPqMaxQ(summary, controllerBus, pvToPqBus.q, pvToPqBus.qLimit, log, LOGGER);
153+
break;
154+
case MIN_Q:
155+
Reports.reportPvToPqMinQ(summary, controllerBus, pvToPqBus.q, pvToPqBus.qLimit, log, LOGGER);
156+
break;
157+
case MIN_REALISTIC_V:
158+
Reports.reportPvToPqMinRealisticV(summary, controllerBus, pvToPqBus.qLimit, minRealisticVoltage, log, LOGGER);
159+
break;
160+
case MAX_REALISTIC_V:
161+
Reports.reportPvToPqMaxRealisticV(summary, controllerBus, pvToPqBus.qLimit, maxRealisticVoltage, log, LOGGER);
162+
break;
168163
}
169164
}
170-
}
171165

172-
Reports.reportPvToPqBuses(reportNode, pvToPqBuses.size(), modifiedRemainingPvBusCount);
166+
}
173167

174168
LOGGER.info("{} buses switched PV -> PQ ({} bus remains PV)", pvToPqBuses.size(), modifiedRemainingPvBusCount);
175169

@@ -184,30 +178,43 @@ public void initialize(AcOuterLoopContext context) {
184178
private static boolean switchPqPv(List<PqToPvBus> pqToPvBuses, ContextData contextData, ReportNode reportNode, int maxPqPvSwitch) {
185179
int pqPvSwitchCount = 0;
186180

181+
boolean log = LOGGER.isTraceEnabled();
182+
183+
List<ReportNode> pqPvNodes = new ArrayList<>();
184+
187185
for (PqToPvBus pqToPvBus : pqToPvBuses) {
188186
LfBus controllerBus = pqToPvBus.controllerBus;
189187

190188
int pvPqSwitchCount = contextData.getPvPqSwitchCount(controllerBus.getId());
191189
if (pvPqSwitchCount >= maxPqPvSwitch) {
192-
LOGGER.trace("Bus '{}' blocked PQ as it has reach its max number of PQ -> PV switch ({})",
193-
controllerBus.getId(), pvPqSwitchCount);
190+
pqPvNodes.add(Reports.reportPvPqSwitchLimit(controllerBus, pvPqSwitchCount, log, LOGGER));
194191
} else {
195192
controllerBus.setGeneratorVoltageControlEnabled(true);
196193
controllerBus.setGenerationTargetQ(0);
197194
controllerBus.setQLimitType(null);
198195
pqPvSwitchCount++;
199196

200-
if (LOGGER.isTraceEnabled()) {
201-
if (pqToPvBus.limitType.isMaxLimit()) {
202-
LOGGER.trace("Switch bus '{}' PQ -> PV, q=maxQ and v={} > targetV={}", controllerBus.getId(), getBusV(controllerBus), getBusTargetV(controllerBus));
203-
} else {
204-
LOGGER.trace("Switch bus '{}' PQ -> PV, q=minQ and v={} < targetV={}", controllerBus.getId(), getBusV(controllerBus), getBusTargetV(controllerBus));
205-
}
197+
if (pqToPvBus.limitType.isMaxLimit()) {
198+
pqPvNodes.add(Reports.reportPqToPvBusMaxLimit(controllerBus,
199+
controllerBus.getGeneratorVoltageControl().map(VoltageControl::getControlledBus).orElseThrow(),
200+
getBusTargetV(controllerBus),
201+
log,
202+
LOGGER));
203+
} else {
204+
pqPvNodes.add(Reports.reportPqToPvBusMinLimit(controllerBus,
205+
controllerBus.getGeneratorVoltageControl().map(VoltageControl::getControlledBus).orElseThrow(),
206+
getBusTargetV(controllerBus),
207+
log,
208+
LOGGER));
206209
}
207210
}
211+
208212
}
209213

210-
Reports.reportPqToPvBuses(reportNode, pqPvSwitchCount, pqToPvBuses.size() - pqPvSwitchCount);
214+
if (!pqPvNodes.isEmpty()) {
215+
ReportNode summary = Reports.reportPqToPvBuses(reportNode, pqPvSwitchCount, pqToPvBuses.size() - pqPvSwitchCount);
216+
pqPvNodes.forEach(summary::include);
217+
}
211218

212219
LOGGER.info("{} buses switched PQ -> PV ({} buses blocked PQ because have reach max number of switch)",
213220
pqPvSwitchCount, pqToPvBuses.size() - pqPvSwitchCount);
@@ -269,7 +276,7 @@ private void checkControllerBus(LfBus controllerBus,
269276
}
270277

271278
private double getInitialGenerationTargetQ(LfBus controllerBus) {
272-
return controllerBus.getGenerators().stream().mapToDouble(g -> g.getTargetQ()).sum();
279+
return controllerBus.getGenerators().stream().mapToDouble(LfGenerator::getTargetQ).sum();
273280
}
274281

275282
private boolean isGeneratorRemoteController(LfBus controllerBus) {
@@ -321,33 +328,38 @@ private void checkPqBus(LfBus controllerCapableBus, List<PqToPvBus> pqToPvBuses,
321328
private boolean switchReactiveControllerBusPq(List<ControllerBusToPqBus> reactiveControllerBusesToPqBuses, ReportNode reportNode) {
322329
int switchCount = 0;
323330

331+
List<ReportNode> switchedNodes = new ArrayList<>();
332+
333+
boolean log = LOGGER.isTraceEnabled();
334+
324335
for (ControllerBusToPqBus bus : reactiveControllerBusesToPqBuses) {
325336
LfBus controllerBus = bus.controllerBus;
326337

327338
controllerBus.setGeneratorReactivePowerControlEnabled(false);
328339
controllerBus.setGenerationTargetQ(bus.qLimit);
329340
switchCount++;
330341

331-
if (LOGGER.isTraceEnabled()) {
332-
switch (bus.limitType) {
333-
case MAX_Q:
334-
LOGGER.trace("Remote reactive power controller bus '{}' -> PQ, q={} > maxQ={}", controllerBus.getId(), bus.q * PerUnit.SB,
335-
bus.qLimit * PerUnit.SB);
336-
break;
337-
case MIN_Q:
338-
LOGGER.trace("Remote reactive power controller bus '{}' -> PQ, q={} < minQ={}", controllerBus.getId(), bus.q * PerUnit.SB,
339-
bus.qLimit * PerUnit.SB);
340-
break;
341-
case MIN_REALISTIC_V, MAX_REALISTIC_V:
342-
LOGGER.trace("Switch bus '{}' PV -> PQ, q set to {} = targetQ - v is outside realistic voltage limits [{}pu,{}pu] when remote voltage is maintained",
343-
controllerBus.getId(), bus.qLimit * PerUnit.SB, minRealisticVoltage, maxRealisticVoltage);
344-
345-
break;
346-
}
342+
switch (bus.limitType) {
343+
case MAX_Q:
344+
switchedNodes.add(Reports.reportReactiveControllerBusesToPqMaxQ(controllerBus, bus.q, bus.qLimit, log, LOGGER));
345+
break;
346+
case MIN_Q:
347+
switchedNodes.add(Reports.reportReactiveControllerBusesToPqMinQ(controllerBus, bus.q, bus.qLimit, log, LOGGER));
348+
break;
349+
case MIN_REALISTIC_V, MAX_REALISTIC_V:
350+
// Note: never happens for now. Robust mode applies only to remote voltage control generators
351+
LOGGER.trace("Switch bus '{}' PV -> PQ, q set to {} = targetQ - v is outside realistic voltage limits [{}pu,{}pu] when remote voltage is maintained",
352+
controllerBus.getId(), bus.qLimit * PerUnit.SB, minRealisticVoltage, maxRealisticVoltage);
353+
354+
break;
347355
}
356+
348357
}
349358

350-
Reports.reportReactiveControllerBusesToPqBuses(reportNode, switchCount);
359+
if (!switchedNodes.isEmpty()) {
360+
ReportNode node = Reports.reportReactiveControllerBusesToPqBuses(reportNode, switchCount);
361+
switchedNodes.forEach(node::include);
362+
}
351363

352364
LOGGER.info("{} remote reactive power controller buses switched PQ", switchCount);
353365

src/main/java/com/powsybl/openloadflow/network/action/LfActionUtils.java

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/**
22
* Copyright (c) 2025, Coreso SA (https://www.coreso.eu/) and TSCNET Services GmbH (https://www.tscnet.eu/)
3-
* Copyright (c) 2022, RTE (http://www.rte-france.com)
3+
* Copyright (c) 2022-2025, RTE (http://www.rte-france.com)
44
* This Source Code Form is subject to the terms of the Mozilla Public
55
* License, v. 2.0. If a copy of the MPL was not distributed with this
66
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
@@ -9,10 +9,10 @@
99
package com.powsybl.openloadflow.network.action;
1010

1111
import com.powsybl.action.*;
12-
import com.powsybl.commons.report.ReportNode;
1312
import com.powsybl.iidm.network.Network;
1413
import com.powsybl.openloadflow.graph.GraphConnectivity;
1514
import com.powsybl.openloadflow.network.*;
15+
import com.powsybl.openloadflow.util.Reports;
1616

1717
import java.util.*;
1818

@@ -25,10 +25,6 @@
2525
*/
2626
public final class LfActionUtils {
2727

28-
private static final String ACTION_ID = "actionId";
29-
30-
private static final String CONTINGENCY_ID = "contingencyId";
31-
3228
private LfActionUtils() {
3329
}
3430

@@ -55,27 +51,27 @@ public static LfAction createLfAction(Action action, Network network, boolean br
5551
};
5652
}
5753

58-
public static void applyListOfActions(List<LfAction> actions, LfNetwork network, LfContingency contingency, LfNetworkParameters networkParameters, ReportNode node) {
54+
public static void applyListOfActions(List<LfAction> actions, LfNetwork network, LfContingency contingency, LfNetworkParameters networkParameters) {
5955
Objects.requireNonNull(actions);
6056
Objects.requireNonNull(network);
6157

6258
// first apply action modifying connectivity
6359
List<LfAction> branchActions = actions.stream()
6460
.filter(action -> action instanceof AbstractLfBranchAction<?>)
6561
.toList();
66-
updateConnectivity(branchActions, network, contingency, node);
62+
updateConnectivity(branchActions, network, contingency);
6763

6864
// then process remaining changes of actions
6965
actions.stream()
7066
.filter(action -> !(action instanceof AbstractLfBranchAction<?>))
7167
.forEach(action -> {
7268
if (!action.apply(network, contingency, networkParameters)) {
73-
reportActionApplicationFailure(action.getId(), contingency.getId(), node);
69+
Reports.reportActionApplicationFailure(action.getId(), contingency.getId(), network.getReportNode());
7470
}
7571
});
7672
}
7773

78-
private static void updateConnectivity(List<LfAction> branchActions, LfNetwork network, LfContingency contingency, ReportNode node) {
74+
private static void updateConnectivity(List<LfAction> branchActions, LfNetwork network, LfContingency contingency) {
7975
GraphConnectivity<LfBus, LfBranch> connectivity = network.getConnectivity();
8076

8177
// re-update connectivity according to post contingency state (revert after LfContingency apply)
@@ -87,7 +83,7 @@ private static void updateConnectivity(List<LfAction> branchActions, LfNetwork n
8783

8884
branchActions.forEach(action -> {
8985
if (!((AbstractLfBranchAction<?>) action).applyOnConnectivity(network, connectivity)) {
90-
reportActionApplicationFailure(action.getId(), contingency.getId(), node);
86+
Reports.reportActionApplicationFailure(action.getId(), contingency.getId(), network.getReportNode());
9187
}
9288
});
9389

@@ -98,12 +94,4 @@ private static void updateConnectivity(List<LfAction> branchActions, LfNetwork n
9894
connectivity.undoTemporaryChanges();
9995
}
10096

101-
private static void reportActionApplicationFailure(String actionId, String contingencyId, ReportNode node) {
102-
node.newReportNode()
103-
.withMessageTemplate("LfActionUtils", "Action '${actionId}': may not have been applied successfully on contingency '${contingencyId}'")
104-
.withUntypedValue(ACTION_ID, actionId)
105-
.withUntypedValue(CONTINGENCY_ID, contingencyId)
106-
.add();
107-
}
108-
10997
}

0 commit comments

Comments
 (0)