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

Support of LoadAction in AC and DC security analysis #660

Merged
merged 15 commits into from
Jan 16, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@ public class BusDcState extends ElementState<LfBus> {
private final Map<String, Double> generatorsTargetP;
private final Map<String, Boolean> participatingGenerators;
private final double absVariableLoadTargetP;
private final Map<String, Boolean> loadsDisablingStatus;

public BusDcState(LfBus bus) {
super(bus);
this.loadTargetP = bus.getLoadTargetP();
this.generatorsTargetP = bus.getGenerators().stream().collect(Collectors.toMap(LfGenerator::getId, LfGenerator::getTargetP));
this.participatingGenerators = bus.getGenerators().stream().collect(Collectors.toMap(LfGenerator::getId, LfGenerator::isParticipating));
this.absVariableLoadTargetP = bus.getAggregatedLoads().getAbsVariableLoadTargetP();
this.loadsDisablingStatus = bus.getAggregatedLoads().getLoadsDisablingStatus();
}

@Override
Expand All @@ -34,6 +36,7 @@ public void restore() {
element.getGenerators().forEach(g -> g.setTargetP(generatorsTargetP.get(g.getId())));
element.getGenerators().forEach(g -> g.setParticipating(participatingGenerators.get(g.getId())));
element.getAggregatedLoads().setAbsVariableLoadTargetP(absVariableLoadTargetP);
element.getAggregatedLoads().setLoadsDisablingStatus(loadsDisablingStatus);
}

public static BusDcState save(LfBus bus) {
Expand Down
111 changes: 90 additions & 21 deletions src/main/java/com/powsybl/openloadflow/network/LfAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,15 @@
*/
package com.powsybl.openloadflow.network;

import com.powsybl.iidm.network.Bus;
import com.powsybl.iidm.network.Load;
import com.powsybl.iidm.network.Network;
import com.powsybl.iidm.network.Terminal;
import com.powsybl.loadflow.LoadFlowParameters;
import com.powsybl.openloadflow.graph.GraphConnectivity;
import com.powsybl.security.action.Action;
import com.powsybl.security.action.LineConnectionAction;
import com.powsybl.security.action.PhaseTapChangerTapPositionAction;
import com.powsybl.security.action.SwitchAction;
import com.powsybl.openloadflow.network.impl.Networks;
import com.powsybl.openloadflow.util.PerUnit;
import com.powsybl.security.action.*;

import java.util.*;

Expand Down Expand Up @@ -46,6 +50,24 @@ public boolean isRelative() {
}
}

private static final class LoadShift {

private final LfBus bus;

private final String loadId;

private final double p0;

private final PowerShift powerShift;

private LoadShift(LfBus bus, String loadId, double p0, PowerShift powerShift) {
this.bus = bus;
this.loadId = loadId;
this.p0 = p0;
this.powerShift = powerShift;
}
}

private final String id;

private final LfBranch disabledBranch; // switch to open
Expand All @@ -54,58 +76,90 @@ public boolean isRelative() {

private final TapPositionChange tapPositionChange;

private LfAction(String id, LfBranch disabledBranch, LfBranch enabledBranch, TapPositionChange tapPositionChange) {
private final LoadShift loadShift;

private LfAction(String id, LfBranch disabledBranch, LfBranch enabledBranch, TapPositionChange tapPositionChange,
LoadShift loadShift) {
this.id = Objects.requireNonNull(id);
this.disabledBranch = disabledBranch;
this.enabledBranch = enabledBranch;
this.tapPositionChange = tapPositionChange;
this.loadShift = loadShift;
}

public static Optional<LfAction> create(Action action, LfNetwork network) {
public static Optional<LfAction> create(Action action, LfNetwork lfNetwork, Network network, boolean breakers) {
Objects.requireNonNull(action);
Objects.requireNonNull(network);
switch (action.getType()) {
case SwitchAction.NAME:
return create((SwitchAction) action, network);
return create((SwitchAction) action, lfNetwork);

case LineConnectionAction.NAME:
return create((LineConnectionAction) action, network);
return create((LineConnectionAction) action, lfNetwork);

case PhaseTapChangerTapPositionAction.NAME:
return create((PhaseTapChangerTapPositionAction) action, network);
return create((PhaseTapChangerTapPositionAction) action, lfNetwork);

case LoadAction.NAME:
return create((LoadAction) action, lfNetwork, network, breakers);

default:
throw new UnsupportedOperationException("Unsupported action type: " + action.getType());
}
}

private static Optional<LfAction> create(PhaseTapChangerTapPositionAction action, LfNetwork network) {
LfBranch branch = network.getBranchById(action.getTransformerId()); // only two windings transformer for the moment.
private static Optional<LfAction> create(LoadAction action, LfNetwork lfNetwork, Network network, boolean breakers) {
Load load = network.getLoad(action.getLoadId());
Terminal terminal = load.getTerminal();
Bus bus = Networks.getBus(terminal, breakers);
if (bus != null) {
annetill marked this conversation as resolved.
Show resolved Hide resolved
LfBus lfBus = lfNetwork.getBusById(bus.getId());
double activePowerShift = 0;
double reactivePowerShift = 0;
Optional<Double> activePowerValue = action.getActivePowerValue();
Optional<Double> reactivePowerValue = action.getReactivePowerValue();
if (activePowerValue.isPresent()) {
activePowerShift = action.isRelativeValue() ? activePowerValue.get() : activePowerValue.get() - load.getP0();
}
if (reactivePowerValue.isPresent()) {
reactivePowerShift = action.isRelativeValue() ? reactivePowerValue.get() : reactivePowerValue.get() - load.getQ0();
}
// In case of a power shift, we suppose that the shift on a load P0 is exactly the same on the variable active power
// of P0 that could be described in a LoadDetail extension.
PowerShift powerShift = new PowerShift(activePowerShift / PerUnit.SB, activePowerShift / PerUnit.SB, reactivePowerShift / PerUnit.SB);
return Optional.of(new LfAction(action.getId(), null, null, null,
new LoadShift(lfBus, load.getId(), load.getP0(), powerShift)));
}
return Optional.empty(); // could be in another component or in contingency.
}

private static Optional<LfAction> create(PhaseTapChangerTapPositionAction action, LfNetwork lfNetwork) {
LfBranch branch = lfNetwork.getBranchById(action.getTransformerId()); // only two windings transformer for the moment.
if (branch != null) {
if (branch.getPiModel() instanceof SimplePiModel) {
throw new UnsupportedOperationException("Phase tap changer tap connection action: only one tap in the branch {" + action.getTransformerId() + "}");
} else {
var tapPositionChange = new TapPositionChange(branch, action.getValue(), action.isRelativeValue());
return Optional.of(new LfAction(action.getId(), null, null, tapPositionChange));
return Optional.of(new LfAction(action.getId(), null, null, tapPositionChange, null));
}
}
return Optional.empty(); // could be in another component
}

private static Optional<LfAction> create(LineConnectionAction action, LfNetwork network) {
LfBranch branch = network.getBranchById(action.getLineId());
private static Optional<LfAction> create(LineConnectionAction action, LfNetwork lfNetwork) {
LfBranch branch = lfNetwork.getBranchById(action.getLineId());
if (branch != null) {
if (action.isOpenSide1() && action.isOpenSide2()) {
return Optional.of(new LfAction(action.getId(), branch, null, null));
return Optional.of(new LfAction(action.getId(), branch, null, null, null));
} else {
throw new UnsupportedOperationException("Line connection action: only open line at both sides is supported yet.");
}
}
return Optional.empty(); // could be in another component
}

private static Optional<LfAction> create(SwitchAction action, LfNetwork network) {
LfBranch branch = network.getBranchById(action.getSwitchId());
private static Optional<LfAction> create(SwitchAction action, LfNetwork lfNetwork) {
LfBranch branch = lfNetwork.getBranchById(action.getSwitchId());
if (branch != null) {
LfBranch disabledBranch = null;
LfBranch enabledBranch = null;
Expand All @@ -114,7 +168,7 @@ private static Optional<LfAction> create(SwitchAction action, LfNetwork network)
} else {
enabledBranch = branch;
}
return Optional.of(new LfAction(action.getId(), disabledBranch, enabledBranch, null));
return Optional.of(new LfAction(action.getId(), disabledBranch, enabledBranch, null, null));
}
return Optional.empty(); // could be in another component
}
Expand All @@ -131,7 +185,7 @@ public LfBranch getEnabledBranch() {
return enabledBranch;
}

public static void apply(List<LfAction> actions, LfNetwork network, LfContingency contingency) {
public static void apply(List<LfAction> actions, LfNetwork network, LfContingency contingency, LoadFlowParameters.BalanceType balanceType) {
Objects.requireNonNull(actions);
Objects.requireNonNull(network);

Expand All @@ -140,7 +194,7 @@ public static void apply(List<LfAction> actions, LfNetwork network, LfContingenc

// then process remaining changes of actions
for (LfAction action : actions) {
action.apply();
action.apply(balanceType);
}
}

Expand Down Expand Up @@ -193,13 +247,28 @@ public void updateConnectivity(GraphConnectivity<LfBus, LfBranch> connectivity)
}
}

public void apply() {
public void apply(LoadFlowParameters.BalanceType balanceType) {
if (tapPositionChange != null) {
LfBranch branch = tapPositionChange.getBranch();
int tapPosition = branch.getPiModel().getTapPosition();
int value = tapPositionChange.getValue();
int newTapPosition = tapPositionChange.isRelative() ? tapPosition + value : value;
branch.getPiModel().setTapPosition(newTapPosition);
}
if (loadShift != null) {
LfBus bus = loadShift.bus;
String loadId = loadShift.loadId;
if (!bus.getAggregatedLoads().isDisabled(loadId)) {
Double loadP0 = loadShift.p0;
PowerShift shift = loadShift.powerShift;
double newP0 = loadP0 / PerUnit.SB + shift.getActive();
double oldUpdatedP0 = LfContingency.getUpdatedLoadP0(bus, balanceType, loadP0 / PerUnit.SB, loadP0 / PerUnit.SB);
double newUpdatedP0 = LfContingency.getUpdatedLoadP0(bus, balanceType, newP0, newP0);
bus.setLoadTargetP(bus.getLoadTargetP() + newUpdatedP0 - oldUpdatedP0);
bus.setLoadTargetQ(bus.getLoadTargetQ() + shift.getReactive());
bus.getAggregatedLoads().setAbsVariableLoadTargetP(bus.getAggregatedLoads().getAbsVariableLoadTargetP()
+ Math.signum(shift.getActive()) * Math.abs(shift.getVariableActive()) * PerUnit.SB);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
package com.powsybl.openloadflow.network;

import java.util.List;
import java.util.Map;

/**
* @author Anne Tilloy <anne.tilloy at rte-france.com>
Expand All @@ -22,4 +23,12 @@ public interface LfAggregatedLoads extends PropertyBag {
double getLoadCount();

double getLoadTargetQ(double diffLoadTargetP);

boolean isDisabled(String originalId);

void setDisabled(String originalId, boolean disabled);

Map<String, Boolean> getLoadsDisablingStatus();

void setLoadsDisablingStatus(Map<String, Boolean> loadsDisablingStatus);
}
15 changes: 13 additions & 2 deletions src/main/java/com/powsybl/openloadflow/network/LfContingency.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
* @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
Expand All @@ -38,12 +39,14 @@ public class LfContingency {

private final Map<LfBus, PowerShift> busesLoadShift;

private final Set<String> originalPowerShiftIds;
Copy link
Member

Choose a reason for hiding this comment

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

At first reading it was really not clear to me that this is load IDs.

Copy link
Member Author

Choose a reason for hiding this comment

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

It is not only load ids but also the other equipments converted as power shift as LCC converter stations.


private final Set<LfGenerator> lostGenerators;

private double activePowerLoss = 0;

public LfContingency(String id, int index, Set<LfBus> disabledBuses, Set<LfBranch> disabledBranches, Map<LfShunt, AdmittanceShift> shuntsShift,
Map<LfBus, PowerShift> busesLoadShift, Set<LfGenerator> lostGenerators, Set<LfHvdc> disabledHvdcs) {
Map<LfBus, PowerShift> busesLoadShift, Set<LfGenerator> lostGenerators, Set<LfHvdc> disabledHvdcs, Set<String> originalPowerShiftIds) {
this.id = Objects.requireNonNull(id);
this.index = index;
this.disabledBuses = Objects.requireNonNull(disabledBuses);
Expand All @@ -52,6 +55,7 @@ public LfContingency(String id, int index, Set<LfBus> disabledBuses, Set<LfBranc
this.shuntsShift = Objects.requireNonNull(shuntsShift);
this.busesLoadShift = Objects.requireNonNull(busesLoadShift);
this.lostGenerators = Objects.requireNonNull(lostGenerators);
this.originalPowerShiftIds = Objects.requireNonNull(originalPowerShiftIds);
for (LfBus bus : disabledBuses) {
activePowerLoss += bus.getGenerationTargetP() - bus.getLoadTargetP();
}
Expand Down Expand Up @@ -115,7 +119,14 @@ public void apply(LoadFlowParameters.BalanceType balanceType) {
PowerShift shift = e.getValue();
bus.setLoadTargetP(bus.getLoadTargetP() - getUpdatedLoadP0(bus, balanceType, shift.getActive(), shift.getVariableActive()));
bus.setLoadTargetQ(bus.getLoadTargetQ() - shift.getReactive());
bus.getAggregatedLoads().setAbsVariableLoadTargetP(bus.getAggregatedLoads().getAbsVariableLoadTargetP() - Math.abs(shift.getVariableActive()) * PerUnit.SB);
Set<String> loadsIdsInContingency = originalPowerShiftIds.stream()
.distinct()
.filter(bus.getAggregatedLoads().getOriginalIds()::contains) // maybe not optimized.
.collect(Collectors.toSet());
if (!loadsIdsInContingency.isEmpty()) { // it could be a LCC in contingency.
bus.getAggregatedLoads().setAbsVariableLoadTargetP(bus.getAggregatedLoads().getAbsVariableLoadTargetP() - Math.abs(shift.getVariableActive()) * PerUnit.SB);
loadsIdsInContingency.stream().forEach(loadId -> bus.getAggregatedLoads().setDisabled(loadId, true));
}
}
Set<LfBus> generatorBuses = new HashSet<>();
for (LfGenerator generator : lostGenerators) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@
import com.powsybl.openloadflow.network.LfAggregatedLoads;
import com.powsybl.openloadflow.util.PerUnit;

import java.util.ArrayList;
import java.util.List;
import java.util.*;
import java.util.stream.Collectors;

/**
Expand All @@ -31,6 +30,8 @@ class LfAggregatedLoadsImpl extends AbstractPropertyBag implements LfAggregatedL

private boolean initialized;

private Map<String, Boolean> loadsStatus = new LinkedHashMap<>();

LfAggregatedLoadsImpl(boolean distributedOnConformLoad) {
this.distributedOnConformLoad = distributedOnConformLoad;
}
Expand All @@ -42,6 +43,7 @@ public List<String> getOriginalIds() {

void add(Load load) {
loadsRefs.add(new Ref<>(load));
loadsStatus.put(load.getId(), false);
initialized = false;
}

Expand Down Expand Up @@ -112,6 +114,26 @@ public double getLoadTargetQ(double diffLoadTargetP) {
return newLoadTargetQ;
}

@Override
public boolean isDisabled(String originalId) {
return loadsStatus.get(originalId);
}

@Override
public void setDisabled(String originalId, boolean disabled) {
loadsStatus.put(originalId, disabled);
}

@Override
public Map<String, Boolean> getLoadsDisablingStatus() {
return loadsStatus;
}

@Override
public void setLoadsDisablingStatus(Map<String, Boolean> loadsStatus) {
this.loadsStatus = loadsStatus;
}

private static double getPowerFactor(Load load) {
return load.getP0() != 0 ? load.getQ0() / load.getP0() : 1;
}
Expand Down
Loading