Skip to content
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

Populate ConnectivityResult in SA post contingency results #701

Merged
merged 16 commits into from
Jan 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
48 changes: 42 additions & 6 deletions src/main/java/com/powsybl/openloadflow/network/LfContingency.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ public class LfContingency {

private final int index;

private final int createdSynchronousComponentsCount;

private final Set<LfBus> disabledBuses;

private final Set<LfBranch> disabledBranches;
Expand All @@ -43,28 +45,46 @@ public class LfContingency {

private final Set<LfGenerator> lostGenerators;

private double activePowerLoss = 0;
private double disconnectedLoadActivePower;

private double disconnectedGenerationActivePower;

private Set<String> disconnectedElementIds;

public LfContingency(String id, int index, Set<LfBus> disabledBuses, Set<LfBranch> disabledBranches, Map<LfShunt, AdmittanceShift> shuntsShift,
public LfContingency(String id, int index, int createdSynchronousComponentsCount, Set<LfBus> disabledBuses, Set<LfBranch> disabledBranches, Map<LfShunt, AdmittanceShift> shuntsShift,
Map<LfBus, PowerShift> busesLoadShift, Set<LfGenerator> lostGenerators, Set<LfHvdc> disabledHvdcs, Set<String> originalPowerShiftIds) {
this.id = Objects.requireNonNull(id);
this.index = index;
this.createdSynchronousComponentsCount = createdSynchronousComponentsCount;
this.disabledBuses = Objects.requireNonNull(disabledBuses);
this.disabledBranches = Objects.requireNonNull(disabledBranches);
this.disabledHvdcs = Objects.requireNonNull(disabledHvdcs);
this.shuntsShift = Objects.requireNonNull(shuntsShift);
this.busesLoadShift = Objects.requireNonNull(busesLoadShift);
this.lostGenerators = Objects.requireNonNull(lostGenerators);
this.originalPowerShiftIds = Objects.requireNonNull(originalPowerShiftIds);
this.disconnectedLoadActivePower = 0.0;
this.disconnectedGenerationActivePower = 0.0;
this.disconnectedElementIds = new HashSet<>();

for (LfBus bus : disabledBuses) {
activePowerLoss += bus.getGenerationTargetP() - bus.getLoadTargetP();
disconnectedLoadActivePower += bus.getLoadTargetP();
disconnectedGenerationActivePower += bus.getGenerationTargetP();
disconnectedElementIds.addAll(bus.getGenerators().stream().map(LfGenerator::getId).collect(Collectors.toList()));
disconnectedElementIds.addAll(bus.getAggregatedLoads().getOriginalIds());
bus.getControllerShunt().ifPresent(shunt -> disconnectedElementIds.addAll(shunt.getOriginalIds()));
bus.getShunt().ifPresent(shunt -> disconnectedElementIds.addAll(shunt.getOriginalIds()));
}
for (Map.Entry<LfBus, PowerShift> e : busesLoadShift.entrySet()) {
activePowerLoss -= e.getValue().getActive();
disconnectedLoadActivePower += e.getValue().getActive();
}
for (LfGenerator generator : lostGenerators) {
activePowerLoss += generator.getTargetP();
disconnectedGenerationActivePower += generator.getTargetP();
disconnectedElementIds.add(generator.getId());
}
disconnectedElementIds.addAll(originalPowerShiftIds);
disconnectedElementIds.addAll(disabledBranches.stream().map(LfBranch::getId).collect(Collectors.toList()));
// FIXME: shuntsShift has to be included in the disconnected elements.
}

public String getId() {
Expand All @@ -75,6 +95,10 @@ public int getIndex() {
return index;
}

public int getCreatedSynchronousComponentsCount() {
return createdSynchronousComponentsCount;
}

public Set<LfBus> getDisabledBuses() {
return disabledBuses;
}
Expand All @@ -95,8 +119,20 @@ public Set<LfGenerator> getLostGenerators() {
return lostGenerators;
}

public Set<String> getDisconnectedElementIds() {
return disconnectedElementIds;
}

public double getActivePowerLoss() {
return activePowerLoss;
return disconnectedGenerationActivePower - disconnectedLoadActivePower;
}

public double getDisconnectedLoadActivePower() {
return disconnectedLoadActivePower;
}

public double getDisconnectedGenerationActivePower() {
return disconnectedGenerationActivePower;
}

public void apply(LoadFlowParameters.BalanceType balanceType) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@ public Optional<LfContingency> toLfContingency(LfNetwork network) {

// add to contingency description buses and branches that won't be part of the main connected
// component in post contingency state
int createdSynchronousComponents = connectivity.getNbConnectedComponents() - 1;
Set<LfBus> buses = connectivity.getVerticesRemovedFromMainComponent();
Set<LfBranch> branches = new HashSet<>(connectivity.getEdgesRemovedFromMainComponent());

Expand Down Expand Up @@ -352,6 +353,6 @@ public Optional<LfContingency> toLfContingency(LfNetwork network) {
return Optional.empty();
}

return Optional.of(new LfContingency(contingency.getId(), index, buses, branches, shunts, busesLoadShift, generators, hvdcs, originalPowerShiftIds));
return Optional.of(new LfContingency(contingency.getId(), index, createdSynchronousComponents, buses, branches, shunts, busesLoadShift, generators, hvdcs, originalPowerShiftIds));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import com.powsybl.openloadflow.network.impl.PropagatedContingency;
import com.powsybl.openloadflow.network.util.ActivePowerDistribution;
import com.powsybl.openloadflow.network.util.PreviousValueVoltageInitializer;
import com.powsybl.openloadflow.util.PerUnit;
import com.powsybl.openloadflow.util.Reports;
import com.powsybl.security.*;
import com.powsybl.security.action.Action;
Expand Down Expand Up @@ -247,12 +248,17 @@ private PostContingencyResult runPostContingencySimulation(LfNetwork network, Ac
LOGGER.info("Post contingency '{}' simulation done on network {} in {} ms", lfContingency.getId(),
network, stopwatch.elapsed(TimeUnit.MILLISECONDS));

var connectivityResult = new ConnectivityResult(lfContingency.getCreatedSynchronousComponentsCount(), 0,
lfContingency.getDisconnectedLoadActivePower() * PerUnit.SB,
lfContingency.getDisconnectedGenerationActivePower() * PerUnit.SB,
lfContingency.getDisconnectedElementIds());

return new PostContingencyResult(contingency, status,
new LimitViolationsResult(postContingencyLimitViolationManager.getLimitViolations()),
postContingencyNetworkResult.getBranchResults(),
postContingencyNetworkResult.getBusResults(),
postContingencyNetworkResult.getThreeWindingsTransformerResults(),
new ConnectivityResult(0, 0, 0, 0, Collections.emptySet()));
connectivityResult);
}

private Optional<OperatorStrategyResult> runActionSimulation(LfNetwork network, AcLoadFlowContext context, OperatorStrategy operatorStrategy,
Expand Down
71 changes: 57 additions & 14 deletions src/main/java/com/powsybl/openloadflow/sa/DcSecurityAnalysis.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import com.powsybl.openloadflow.network.impl.Networks;
import com.powsybl.openloadflow.network.impl.PropagatedContingency;
import com.powsybl.openloadflow.sensi.OpenSensitivityAnalysisProvider;
import com.powsybl.openloadflow.util.PerUnit;
import com.powsybl.security.*;
import com.powsybl.security.action.Action;
import com.powsybl.security.detectors.DefaultLimitViolationDetector;
Expand All @@ -51,7 +52,9 @@ private static class DcSecurityAnalysisContext {
private final List<Contingency> contingencies;
private final DefaultLimitViolationDetector detector;
private final double dcPowerFactor;
private final Map<String, PostContingencyResult> postContingencyResultPerContingencyId = new HashMap<>();
private final Map<String, LimitViolationsResult> limitViolationsPerContingencyId = new LinkedHashMap<>();
private final Map<String, List<BranchResult>> branchResultsPerContingencyId = new LinkedHashMap<>();
private final Map<String, ConnectivityResult> connectivityResultPerContingencyId = new LinkedHashMap<>();

public DcSecurityAnalysisContext(SecurityAnalysisParameters saParameters,
List<Contingency> contingencyList,
Expand Down Expand Up @@ -94,8 +97,16 @@ DefaultLimitViolationDetector getDetector() {
return dcPowerFactor;
}

Map<String, PostContingencyResult> getPostContingencyResultPerContingencyId() {
return postContingencyResultPerContingencyId;
Map<String, LimitViolationsResult> getLimitViolationsPerContingencyId() {
return limitViolationsPerContingencyId;
}

Map<String, List<BranchResult>> getBranchResultsPerContingencyId() {
return branchResultsPerContingencyId;
}

Map<String, ConnectivityResult> getConnectivityResultPerContingencyId() {
return connectivityResultPerContingencyId;
}
}

Expand Down Expand Up @@ -134,10 +145,17 @@ SecurityAnalysisReport runSync(String workingVariantId, SecurityAnalysisParamete

PreContingencyResult preContingencyResult = createPreContingencyResults(context, result);

List<PostContingencyResult> postContingencyResults = createPostContingencyResults(context, result);
preparePostContingencyResults(context, result);

List<OperatorStrategyResult> operatorStrategyResult = createOperatorStrategyResults(context, operatorStrategies, actions);

List<PostContingencyResult> postContingencyResults = new ArrayList<>();
for (Contingency contingency : contingencies) {
postContingencyResults.add(new PostContingencyResult(contingency, PostContingencyComputationStatus.CONVERGED,
context.getLimitViolationsPerContingencyId().get(contingency.getId()), context.getBranchResultsPerContingencyId().get(contingency.getId()),
Collections.emptyList(), Collections.emptyList(), context.getConnectivityResultPerContingencyId().get(contingency.getId())));
}

return new SecurityAnalysisReport(new SecurityAnalysisResult(preContingencyResult, postContingencyResults, operatorStrategyResult));
}

Expand All @@ -164,9 +182,8 @@ private PreContingencyResult createPreContingencyResults(DcSecurityAnalysisConte
return new PreContingencyResult(LoadFlowResult.ComponentResult.Status.CONVERGED, limitViolations, branchResults, Collections.emptyList(), Collections.emptyList());
}

private List<PostContingencyResult> createPostContingencyResults(DcSecurityAnalysisContext context, SensitivityAnalysisResult res) {
private void preparePostContingencyResults(DcSecurityAnalysisContext context, SensitivityAnalysisResult res) {

List<PostContingencyResult> postContingencyResults = new ArrayList<>();
for (Contingency contingency : context.getContingencies()) {
Map<String, BranchResult> postContingencyBranchResults = new HashMap<>();
List<SensitivityValue> values = res.getValues(contingency.getId());
Expand Down Expand Up @@ -198,12 +215,9 @@ private List<PostContingencyResult> createPostContingencyResults(DcSecurityAnaly
}
});

PostContingencyResult pcResult = new PostContingencyResult(contingency, PostContingencyComputationStatus.CONVERGED, new ArrayList<>(violations.values()),
new ArrayList<>(postContingencyBranchResults.values()), Collections.emptyList(), Collections.emptyList(), new ConnectivityResult(0, 0, 0, 0, Collections.emptySet()));
context.getPostContingencyResultPerContingencyId().put(contingency.getId(), pcResult);
postContingencyResults.add(pcResult);
context.getLimitViolationsPerContingencyId().put(contingency.getId(), new LimitViolationsResult(new ArrayList<>(violations.values()), Collections.emptyList()));
context.getBranchResultsPerContingencyId().put(contingency.getId(), new ArrayList<>(postContingencyBranchResults.values()));
}
return postContingencyResults;
}

private List<OperatorStrategyResult> createOperatorStrategyResults(DcSecurityAnalysisContext context, List<OperatorStrategy> operatorStrategies, List<Action> actions) {
Expand Down Expand Up @@ -231,7 +245,7 @@ private List<OperatorStrategyResult> createOperatorStrategyResults(DcSecurityAna
try (LfNetworkList lfNetworks = Networks.load(network, dcParameters.getNetworkParameters(), allSwitchesToOpen, allSwitchesToClose, Reporter.NO_OP)) {
return lfNetworks.getLargest().filter(LfNetwork::isValid)
.map(largestNetwork -> runActionSimulations(context, largestNetwork, dcParameters, propagatedContingencies,
operatorStrategies, actionsById, neededActions))
operatorStrategies, actionsById, neededActions))
.orElse(Collections.emptyList());
}
}
Expand Down Expand Up @@ -281,8 +295,7 @@ private List<OperatorStrategyResult> runActionSimulations(DcSecurityAnalysisCont
break;
}
for (OperatorStrategy operatorStrategy : operatorStrategiesForThisContingency) {
var postContingencyResult = context.getPostContingencyResultPerContingencyId().get(propagatedContingency.getContingency().getId());
if (checkCondition(operatorStrategy, postContingencyResult.getLimitViolationsResult())) {
if (checkCondition(operatorStrategy, context.getLimitViolationsPerContingencyId().get(propagatedContingency.getContingency().getId()))) {
propagatedContingency.toLfContingency(lfNetwork)
.ifPresent(lfContingency -> {
lfContingency.apply(context.getParameters().getLoadFlowParameters().getBalanceType());
Expand All @@ -294,9 +307,39 @@ private List<OperatorStrategyResult> runActionSimulations(DcSecurityAnalysisCont
}
}
}

completeConnectivityResults(context, lfNetwork, propagatedContingencies, networkState);

return operatorStrategyResults;
}

private void completeConnectivityResults(DcSecurityAnalysisContext context, LfNetwork lfNetwork,
List<PropagatedContingency> propagatedContingencies,
NetworkState networkState) {

// some connectivity results have not been built yet and we have to.
// after some contingencies, no operator strategies have been applied.
// we apply the contingency on the network just to complete the connectivity results.
Iterator<PropagatedContingency> contingencyIt = propagatedContingencies.iterator();
while (contingencyIt.hasNext() && !Thread.currentThread().isInterrupted()) {
PropagatedContingency propagatedContingency = contingencyIt.next();
context.getConnectivityResultPerContingencyId().computeIfAbsent(propagatedContingency.getContingency().getId(), id ->
propagatedContingency.toLfContingency(lfNetwork)
.map(lfContingency -> {
lfContingency.apply(context.getParameters().getLoadFlowParameters().getBalanceType());
// we build the connectivity result linked to this contingency by opportunity.
ConnectivityResult connectivityResult = new ConnectivityResult(lfContingency.getCreatedSynchronousComponentsCount(), 0,
lfContingency.getDisconnectedLoadActivePower() * PerUnit.SB,
lfContingency.getDisconnectedGenerationActivePower() * PerUnit.SB,
lfContingency.getDisconnectedElementIds());
networkState.restore();
return connectivityResult;
})
.orElse(new ConnectivityResult(0, 0, 0, 0, Collections.emptySet()))
Copy link
Member

Choose a reason for hiding this comment

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

We have a API design issue, maybe we should have done this ConnectivityResult optional.

Copy link
Member

Choose a reason for hiding this comment

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

If you have a PostContingencyResult, you have a ConnectivityResult, no?

Copy link
Member

@geofjamg geofjamg Jan 27, 2023

Choose a reason for hiding this comment

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

Bu if you don't have any loss of connectivity for you contingency, you should not provide this object?

Copy link
Member

Choose a reason for hiding this comment

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

No... right...

);
}
}

@Override
protected PostContingencyComputationStatus runActionLoadFlow(DcLoadFlowContext context) {
DcLoadFlowResult dcLoadFlowResult = new DcLoadFlowEngine(context).run();
Expand Down
Loading