Skip to content

Reports i18n #1216

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Apr 18, 2025
Original file line number Diff line number Diff line change
Expand Up @@ -187,21 +187,25 @@ private static boolean switchPqPv(List<PqToPvBus> pqToPvBuses, ContextData conte

int pvPqSwitchCount = contextData.getPvPqSwitchCount(controllerBus.getId());
if (pvPqSwitchCount >= maxPqPvSwitch) {
pqPvNodes.add(Reports.reportPvPqSwitchLimit(controllerBus, pvPqSwitchCount, log, LOGGER));
pqPvNodes.add(Reports.reportPvPqSwitchLimit(reportNode, controllerBus, pvPqSwitchCount, log, LOGGER));
} else {
controllerBus.setGeneratorVoltageControlEnabled(true);
controllerBus.setGenerationTargetQ(0);
controllerBus.setQLimitType(null);
pqPvSwitchCount++;

if (pqToPvBus.limitType.isMaxLimit()) {
pqPvNodes.add(Reports.reportPqToPvBusMaxLimit(controllerBus,
pqPvNodes.add(Reports.reportPqToPvBusMaxLimit(
reportNode,
controllerBus,
controllerBus.getGeneratorVoltageControl().map(VoltageControl::getControlledBus).orElseThrow(),
getBusTargetV(controllerBus),
log,
LOGGER));
} else {
pqPvNodes.add(Reports.reportPqToPvBusMinLimit(controllerBus,
pqPvNodes.add(Reports.reportPqToPvBusMinLimit(
reportNode,
controllerBus,
controllerBus.getGeneratorVoltageControl().map(VoltageControl::getControlledBus).orElseThrow(),
getBusTargetV(controllerBus),
log,
Expand Down Expand Up @@ -341,10 +345,10 @@ private boolean switchReactiveControllerBusPq(List<ControllerBusToPqBus> reactiv

switch (bus.limitType) {
case MAX_Q:
switchedNodes.add(Reports.reportReactiveControllerBusesToPqMaxQ(controllerBus, bus.q, bus.qLimit, log, LOGGER));
switchedNodes.add(Reports.reportReactiveControllerBusesToPqMaxQ(reportNode, controllerBus, bus.q, bus.qLimit, log, LOGGER));
break;
case MIN_Q:
switchedNodes.add(Reports.reportReactiveControllerBusesToPqMinQ(controllerBus, bus.q, bus.qLimit, log, LOGGER));
switchedNodes.add(Reports.reportReactiveControllerBusesToPqMinQ(reportNode, controllerBus, bus.q, bus.qLimit, log, LOGGER));
break;
case MIN_REALISTIC_V, MAX_REALISTIC_V:
// Note: never happens for now. Robust mode applies only to remote voltage control generators
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1306,7 +1306,7 @@ public List<LfNetwork> load(Network network, LfTopoConfig topoConfig, LfNetworkP
int numSc = networkKey.getRight();
List<Bus> lfBuses = e.getValue();
return create(numCc, numSc, network, lfBuses, switchesByCc.get(networkKey), topoConfig,
parameters, Reports.createRootLfNetworkReportNode(numCc, numSc));
parameters, Reports.createRootLfNetworkReportNode(reportNode, numCc, numSc));
})
.collect(Collectors.toList());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,10 +217,7 @@ SecurityAnalysisReport runSync(SecurityAnalysisParameters securityAnalysisParame

parameters = createParameters(lfParameters, lfParametersExt, partitionTopoConfig.isBreaker(), isAreaInterchangeControl(lfParametersExt, contingencies));

ReportNode threadRootNode = partitionNum == 0 ? saReportNode :
ReportNode.newRootReportNode()
.withMessageTemplate("threadRoot", "threadRoot")
.build();
ReportNode threadRootNode = partitionNum == 0 ? saReportNode : Reports.createThreadRootReport(saReportNode);
reportNodes.set(partitionNum, threadRootNode);

// create networks including all necessary switches
Expand Down
255 changes: 135 additions & 120 deletions src/main/java/com/powsybl/openloadflow/util/Reports.java

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.powsybl.openloadflow.util.report;

/**
* Copyright (c) 2025, 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/.
* SPDX-License-Identifier: MPL-2.0
*/

import com.google.auto.service.AutoService;
import com.powsybl.commons.report.ReportResourceBundle;

/**
* @author Alice Caron {@literal <alice.caron at rte-france.com>}
*/

@AutoService(ReportResourceBundle.class)
public final class PowsyblOpenLoadFlowReportResourceBundle implements ReportResourceBundle {

public static final String BASE_NAME = "com.powsybl.openloadflow.reports";

public String getBaseName() {
return BASE_NAME;
}
}
87 changes: 87 additions & 0 deletions src/main/resources/com/powsybl/openloadflow/reports.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
olf.acEmulationDisabledInWoodburyDcSecurityAnalysis = AC emulation of HVDC lines is disabled with Woodbury DC Security Analysis. HVDC active power setpoint will be used instead.
olf.acLfComplete = AC load flow completed ${successText} (solverStatus=${solverStatus}, outerloopStatus=${outerloopStatus})
olf.acSecurityAnalysis = AC security analysis on network '${networkId}'
olf.activePowerControlPstsChangedTaps = ${numOfActivePowerControlPstsThatChangedTap} active power control PST(s) changed taps
olf.angleReferenceBusSelection = Angle reference bus: ${referenceBus}
olf.areaInterchangeControlAreaDistributionSuccess = Area ${area} interchange mismatch (${mismatch} MW) distributed in ${iterationCount} distribution iteration(s)
olf.areaInterchangeControlAreaMismatch = Remaining mismatch for Area ${area}: ${mismatch} MW
olf.areaInterchangeControlDistributionFailure = Failed to distribute interchange active power mismatch
olf.areaNoInterchangeControl = Area ${area} will not be considered in area interchange control, reason: ${reason}
olf.branchControlledAtBothSides = Controlled branch ${controlledBranchId} is controlled at both sides. Controlled side ${keptSide} (kept) side ${rejectedSide} (rejected).
olf.busAlreadyControlledWithDifferentTargetV = Bus ${controllerBusId} controls voltage of bus ${controlledBusId} which is already controlled by buses [${busesId}] with a different target voltage: ${keptTargetV} kV (kept) and ${ignoredTargetV} kV (ignored)
olf.busForcedToBePv = All PV buses should switch PQ, strongest one will stay PV: ${busId}
olf.busWithUpdatedQLimits = ${numBusesWithUpdatedQLimits} buses blocked at a reactive limit have been adjusted because the reactive limit changed
olf.componentsWithoutGenerators = No calculation will be done on ${deadComponentsCount} network(s) that have no generators
olf.contingencyActivePowerLossDistribution = Contingency caused the loss of ${mismatch} MW injection: ${distributed} MW distributed, ${remaining} MW remaining.
olf.controllerShuntAlreadyInVoltageControl = Controller shunt ${controllerShuntId} is already in a shunt voltage control. The second controlled bus ${controlledBusId} is ignored
olf.currentLimiterPstsChangedTaps = ${numOfCurrentLimiterPstsThatChangedTap} current limiter PST(s) changed taps
olf.dcLfComplete = DC load flow completed (solverSuccess=${succeeded}, outerloopStatus=${outerloopStatus})
olf.dcLfFailure = Failed to solve linear system for DC load flow: ${errorMessage}
olf.dcSecurityAnalysis = DC security analysis on network '${networkId}'
olf.generatorsDiscardedFromVoltageControlBecauseInconsistentControlledBus = ${impactedGeneratorCount} generators have been discarded from voltage control because connected to the same bus but controlling the voltage of different buses
olf.generatorsDiscardedFromVoltageControlBecauseInconsistentTargetVoltages = ${impactedGeneratorCount} generators have been discarded from voltage control because connected to the same bus but having different target voltages
olf.generatorsDiscardedFromVoltageControlBecauseNotStarted = ${impactedGeneratorCount} generators were discarded from voltage control because not started
olf.generatorsDiscardedFromVoltageControlBecauseReactiveRangeIsTooSmall = ${impactedGeneratorCount} generators have been discarded from voltage control because of a too small reactive range
olf.generatorsDiscardedFromVoltageControlBecauseTargetPIsOutsideActiveLimits = ${impactedGeneratorCount} generators have been discarded from voltage control because targetP is outside active power limits
olf.generatorsDiscardedFromVoltageControlBecauseTargetVIsImplausible = ${impactedGeneratorCount} generators have been discarded from voltage control because targetV is implausible
olf.LfActionUtils = Action '${actionId}': may not have been applied successfully on contingency '${contingencyId}'
olf.lineSearchStateVectorScaling = Step size: ${stepSize} (line search)
olf.loadFlow = Load flow on network '${networkId}'
olf.maxOuterLoopIterations = Maximum number of outerloop iterations reached: ${outerLoopIterationCount}
olf.maxVoltageChangeStateVectorScaling = Step size: ${stepSize} (max voltage change: ${vCutCount} Vmagnitude and ${phiCutCount} Vangle changes outside configured thresholds)
olf.mismatchDistributionFailure = Failed to distribute slack bus active power mismatch, ${mismatch} MW remains
olf.mismatchDistributionSuccess = Slack bus active power (${initialMismatch} MW) distributed in ${iterationCount} distribution iteration(s)
olf.mismatchInitial = Initial mismatch
olf.mismatchIteration = Iteration ${iteration} mismatch
olf.networkBalance = Network balance: active generation=${activeGeneration} MW, active load=${activeLoad} MW, reactive generation=${reactiveGeneration} MVar, reactive load=${reactiveLoad} MVar
olf.lfNetwork = Network CC${networkNumCc} SC${networkNumSc}
olf.networkInfo = Network info
olf.networkMustHaveAtLeastOneBusGeneratorVoltageControlEnabled = Network must have at least one bus with generator voltage control enabled
olf.networkSize = Network has ${busCount} buses and ${branchCount} branches
olf.newtonRaphsonBusesOutOfRealisticVoltageRange = ${busCountOutOfRealisticVoltageRange} buses have a voltage magnitude out of the configured realistic range [${minRealisticVoltage}, ${maxRealisticVoltage}] p.u.
olf.newtonRaphsonBusesOutOfRealisticVoltageRangeDetails = Bus ${busId} has an unrealistic voltage magnitude: ${voltage} p.u.
olf.notUniqueControlledBusDisablingControl = Generators [${generatorIds}] are connected to the same bus ${controllerBusId} but control the voltage of different buses (${controlledBusId} and ${controlledBusGenId}): disabling voltage control
olf.notUniqueControlledBusKeepingFirstControl = Generators [${generatorIds}] are connected to the same bus ${controllerBusId} but control the voltage of different buses: ${controlledBusId} (kept) and ${controlledBusGenId} (rejected)
olf.notUniqueTargetVControllerBusDisablingControl = Generators [${generatorIds}] are connected to the same bus ${controllerBusId} with different target voltages (${targetV1} kV and ${targetV2} kV): disabling voltage control
olf.notUniqueTargetVControllerBusKeepingFirstControl = Generators [${generatorIds}] are connected to the same bus ${controllerBusId} with different target voltages: ${keptTargetV} kV (kept) and ${rejectedTargetV} kV (rejected)
olf.NRError = Newton Raphson error: ${error}
olf.NRMismatch = Largest ${equationType} mismatch: ${mismatch} ${mismatchUnit}
olf.NRMismatchBusInfo = Bus Id: ${busId} (nominalVoltage=${busNominalV}kV)
olf.NRMismatchBusInjection = Bus injection: ${busP} MW, ${busQ} MVar
olf.NRMismatchBusV = Bus V: ${busV} pu, ${busPhi} rad
olf.NRNorm = Newton-Raphson norm |f(x)|=${norm}
olf.operatorStrategySimulation = Operator strategy simulation '${operatorStrategyId}'
olf.OuterLoop = Outer loop ${outerLoopType}
olf.OuterLoopIteration = Outer loop iteration ${outerLoopIteration}
olf.outerLoopStatus = Outer loop unsuccessful with status: ${outerLoopStatus}
olf.postContingencySimulation = Post-contingency simulation '${contingencyId}'
olf.PqToPvBuses = ${pqToPvBusCount} buses switched PQ -> PV (${blockedPqBusCount} buses blocked PQ due to the max number of switches)
olf.pqToPvBusMaxLimit = Switch bus '${busId}' PQ -> PV, q=maxQ and v=${busV}kV > targetV=${targetV}kV
olf.pqToPvBusMinLimit = Switch bus '${busId}' PQ -> PV, q=minQ and v=${busV}kV < targetV=${targetV}kV
olf.preContingencySimulation = Pre-contingency simulation
olf.pvPqSwitchLimit = Bus '${busId}' blocked PQ as it has reached its max number of PQ -> PV switch (${limit})
olf.pvToPqBuses = ${pvToPqBusCount} buses switched PV -> PQ (${remainingPvBusCount} buses remain PV)
olf.pvToPqMaxQ = Switch bus '${busId}' PV -> PQ, q=${busQ} > maxQ=${maxQ}
olf.PvToPqMaxRealisticV = Switch bus '${busId}' PV -> PQ, q set to ${targetQ} = targetQ - because V > ${maxRealisticV}kV when remote voltage target is maintained
olf.PvToPqMinQ = Switch bus '${busId}' PV -> PQ, q=${busQ} < minQ=${minQ}
olf.PvToPqMinRealisticV = Switch bus '${busId}' PV -> PQ, q set to ${targetQ} = targetQ - because V < ${minRealisticV}kV when remote voltage target is maintained
olf.reactiveControllerBusesToPqBuses = ${remoteReactivePowerControllerBusToPqCount} bus(es) with remote reactive power controller switched PQ
olf.reactiveControllerBusesToPqMaxQ = Remote reactive power controller bus '${busId}' -> PQ, q=${busQ} > maxQ=${maxQ}
olf.reactiveControllerBusesToPqMinQ = Remote reactive power controller bus '${busId}' -> PQ, q=${busQ} < minQ=${minQ}
olf.sensitivityAnalysis = Sensitivity analysis on network '${networkId}'
olf.shuntsDiscardedFromVoltageControlBecauseTargetVIsInconsistent = ${impactedShuntCount} shunt compensators have been discarded from voltage control because targetV is inconsistent
olf.shuntVoltageControlChangedSection = ${numShuntVoltageControlAdjusted} shunts changed section
olf.slackBusSelection = Slack bus: ${slackBus}
olf.solver = ${solverName} on Network CC${networkNumCc} SC${networkNumSc}
olf.solverNoOuterLoops = No outer loops have been launched
olf.solverOuterLoopCurrentType = Newton-Raphson of outer loop iteration ${outerLoopIteration} of type ${outerLoopType}
olf.standByAutomatonActivation = Activation of voltage control of static var compensator with stand by automaton: bus ${busId} switched PQ -> PV with targetV ${newTargetV}
olf.threadRoot = threadRoot
olf.transformerControlAlreadyExistsUpdateDeadband = Transformers ${firstControllerId} and ${newControllerId} control voltage at bus ${controlledBusId} with different deadbands, thinnest will be kept: ${newTargetDeadband}kV (kept) and ${oldTargetDeadband}kV (rejected)
olf.transformerControlAlreadyExistsWithDifferentTargetV = Transformers ${firstControllerId} and ${newControllerId} control voltage at bus ${controlledBusId} with different target voltages: ${vcTargetValue}kV (kept) and ${targetValue}kV (rejected)
olf.transformerControlBranchesOutsideDeadband = ${numTransformerControlBranchesOutsideDeadband} reactive power-controlled branches are outside of their target deadbands
olf.transformerControlBusesOutsideDeadband = ${numTransformerControlBusesOutsideDeadband} voltage-controlled buses are outside of their target deadbands
olf.transformerControlChangedTaps = ${numTransformerControlAdjusted} transformers changed tap position
olf.transformerControlTapLimit = ${numTransformerControlTapLimit} transformers reached their tap maximum position
olf.transformersDiscardedFromVoltageControlBecauseTargetVIsInconsistent = ${impactedTransformerCount} transformers have been discarded from voltage control because targetV is inconsistent
olf.woodburyDcSecurityAnalysis = Woodbury DC security analysis on network '${networkId}'
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
package com.powsybl.openloadflow.ac;

import com.powsybl.commons.report.ReportNode;
import com.powsybl.commons.test.PowsyblCoreTestReportResourceBundle;
import com.powsybl.computation.local.LocalComputationManager;
import com.powsybl.iidm.network.*;
import com.powsybl.iidm.network.extensions.SlackTerminal;
Expand All @@ -23,6 +24,7 @@
import com.powsybl.openloadflow.network.EurostagFactory;
import com.powsybl.openloadflow.network.SlackBusSelectionMode;
import com.powsybl.openloadflow.util.LoadFlowAssert;
import com.powsybl.openloadflow.util.report.PowsyblOpenLoadFlowReportResourceBundle;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

Expand Down Expand Up @@ -280,7 +282,8 @@ void noGeneratorPvTest() {
network.getGenerator("GEN").setVoltageRegulatorOn(false);

ReportNode reportNode = ReportNode.newRootReportNode()
.withMessageTemplate("unitTest", "")
.withResourceBundles(PowsyblOpenLoadFlowReportResourceBundle.BASE_NAME)
.withMessageTemplate("unitTest")
.build();
LoadFlowResult result = loadFlowRunner.run(network, VariantManagerConstants.INITIAL_VARIANT_ID, LocalComputationManager.getDefault(), parameters, reportNode);
assertFalse(result.isFullyConverged());
Expand All @@ -292,9 +295,9 @@ void noGeneratorPvTest() {
ReportNode lfReportNode = reportNode.getChildren().get(0);
assertEquals(1, lfReportNode.getChildren().size());
ReportNode networkReportNode = lfReportNode.getChildren().get(0);
assertEquals("lfNetwork", networkReportNode.getMessageKey());
assertEquals("olf.lfNetwork", networkReportNode.getMessageKey());
ReportNode networkInfoReportNode = networkReportNode.getChildren().get(0);
assertEquals("networkInfo", networkInfoReportNode.getMessageKey());
assertEquals("olf.networkInfo", networkInfoReportNode.getMessageKey());
assertEquals(1, networkInfoReportNode.getChildren().size());
assertEquals("Network must have at least one bus with generator voltage control enabled",
networkInfoReportNode.getChildren().get(0).getMessage());
Expand Down Expand Up @@ -460,7 +463,8 @@ void testGeneratorsConnectedToSameBusNotControllingSameBus() throws IOException
.setRegulatingTerminal(network.getLoad("LOAD").getTerminal())
.add();
ReportNode reportNode = ReportNode.newRootReportNode()
.withMessageTemplate("testReport", "Test Report")
.withResourceBundles(PowsyblOpenLoadFlowReportResourceBundle.BASE_NAME, PowsyblCoreTestReportResourceBundle.TEST_BASE_NAME)
.withMessageTemplate("testReport")
.build();
loadFlowRunner.run(network, VariantManagerConstants.INITIAL_VARIANT_ID, LocalComputationManager.getDefault(), parameters, reportNode);
assertVoltageEquals(24.5, network.getBusBreakerView().getBus("NGEN"));
Expand All @@ -471,7 +475,8 @@ void testGeneratorsConnectedToSameBusNotControllingSameBus() throws IOException
@Test
void maxOuterLoopIterationTest() throws IOException {
ReportNode report = ReportNode.newRootReportNode()
.withMessageTemplate("test", "test")
.withResourceBundles(PowsyblOpenLoadFlowReportResourceBundle.BASE_NAME, PowsyblCoreTestReportResourceBundle.TEST_BASE_NAME)
.withMessageTemplate("test")
.build();
gen.setTargetP(1000);
parameters.setDistributedSlack(true);
Expand Down
Loading