-
Notifications
You must be signed in to change notification settings - Fork 8
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
Avoid slack distribution to fictitious loads #1028
Changes from all commits
caf81cb
b3c8530
9c471ef
2603c81
77629e8
a47906e
bae40cb
245c097
1a11956
5045ef7
4086b62
cf9268b
63c2e6c
64852e4
dd32089
4bb287c
0e2d9c2
9f63eae
97fc66f
c394912
b75cdb3
04d54b7
cf08e18
963db91
65dfe2f
ce3b1a2
ca1c237
53a73fc
9eda95b
380c90d
5cf6d41
712ab42
ec765b0
ff1cee1
dd5f96b
c449a9c
30452c1
411a27d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -147,7 +147,7 @@ public void apply(LoadFlowParameters.BalanceType balanceType) { | |
LfLoad load = e.getKey(); | ||
LfLostLoad lostLoad = e.getValue(); | ||
PowerShift shift = lostLoad.getPowerShift(); | ||
load.setTargetP(load.getTargetP() - getUpdatedLoadP0(load, balanceType, shift.getActive(), shift.getVariableActive())); | ||
load.setTargetP(load.getTargetP() - getUpdatedLoadP0(load, balanceType, shift.getActive(), shift.getVariableActive(), lostLoad.getNotParticipatingLoadP0())); | ||
load.setTargetQ(load.getTargetQ() - shift.getReactive()); | ||
load.setAbsVariableTargetP(load.getAbsVariableTargetP() - Math.abs(shift.getVariableActive())); | ||
lostLoad.getOriginalIds().forEach(loadId -> load.setOriginalLoadDisabled(loadId, true)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do you need to do somthing special for fictive load in setAbsVariableTargetP for fictive loads since the getAbsVariableTargetP is harcoded for fictive load , by this new code:: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ha, you are right. |
||
|
@@ -189,16 +189,17 @@ public void apply(LoadFlowParameters.BalanceType balanceType) { | |
} | ||
} | ||
|
||
private static double getUpdatedLoadP0(LfLoad load, LoadFlowParameters.BalanceType balanceType, double initialP0, double initialVariableActivePower) { | ||
private static double getUpdatedLoadP0(LfLoad lfLoad, LoadFlowParameters.BalanceType balanceType, double initialP0, double initialVariableActivePower, double notParticipatingLoadP0) { | ||
double factor = 0; | ||
if (load.getOriginalLoadCount() > 0) { | ||
double loadVariableTargetP = lfLoad.getAbsVariableTargetP(); | ||
if (loadVariableTargetP != 0 && lfLoad.getOriginalLoadCount() > 0) { | ||
if (balanceType == LoadFlowParameters.BalanceType.PROPORTIONAL_TO_LOAD) { | ||
factor = Math.abs(initialP0) / load.getAbsVariableTargetP(); | ||
factor = (Math.abs(initialP0) - Math.abs(notParticipatingLoadP0)) / loadVariableTargetP; | ||
} else if (balanceType == LoadFlowParameters.BalanceType.PROPORTIONAL_TO_CONFORM_LOAD) { | ||
factor = initialVariableActivePower / load.getAbsVariableTargetP(); | ||
factor = initialVariableActivePower / loadVariableTargetP; | ||
} | ||
} | ||
return initialP0 + (load.getTargetP() - load.getInitialTargetP()) * factor; | ||
return initialP0 + (lfLoad.getTargetP() - lfLoad.getInitialTargetP()) * factor; | ||
} | ||
|
||
public Set<LfBus> getLoadAndGeneratorBuses() { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,7 @@ | |
import com.powsybl.iidm.network.DanglingLine; | ||
import com.powsybl.iidm.network.LccConverterStation; | ||
import com.powsybl.iidm.network.Load; | ||
import com.powsybl.iidm.network.LoadType; | ||
import com.powsybl.iidm.network.extensions.LoadDetail; | ||
import com.powsybl.iidm.network.util.HvdcUtils; | ||
import com.powsybl.openloadflow.network.*; | ||
|
@@ -29,15 +30,15 @@ public class LfLoadImpl extends AbstractLfInjection implements LfLoad { | |
|
||
private final LfLoadModel loadModel; | ||
|
||
private final List<Ref<Load>> loadsRefs = new ArrayList<>(); | ||
private final Map<String, Ref<Load>> loadsRefs = new HashMap<>(); | ||
|
||
private final List<Ref<LccConverterStation>> lccCsRefs = new ArrayList<>(); | ||
|
||
private double targetQ = 0; | ||
|
||
private boolean ensurePowerFactorConstantByLoad = false; | ||
|
||
private final List<Double> loadsAbsVariableTargetP = new ArrayList<>(); | ||
private final HashMap<String, Double> loadsAbsVariableTargetP = new HashMap<>(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need to define the object as the implementation class? @vidaldid-rte
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You mean define it as a Map ? It avoids some pedantic discussions with Sonar lovers so why not, although it does not really matter in a private field definition. |
||
|
||
private double absVariableTargetP = 0; | ||
|
||
|
@@ -63,7 +64,7 @@ public String getId() { | |
|
||
@Override | ||
public List<String> getOriginalIds() { | ||
return Stream.concat(loadsRefs.stream().map(r -> r.get().getId()), | ||
return Stream.concat(loadsRefs.values().stream().map(r -> r.get().getId()), | ||
lccCsRefs.stream().map(r -> r.get().getId())) | ||
.toList(); | ||
} | ||
|
@@ -73,13 +74,21 @@ public LfBus getBus() { | |
return bus; | ||
} | ||
|
||
@Override | ||
public boolean isOriginalLoadNotParticipating(String originalLoadId) { | ||
if (loadsRefs.get(originalLoadId) == null) { | ||
return false; | ||
} | ||
return isLoadNotParticipating(loadsRefs.get(originalLoadId).get()); | ||
} | ||
|
||
@Override | ||
public Optional<LfLoadModel> getLoadModel() { | ||
return Optional.ofNullable(loadModel); | ||
} | ||
|
||
void add(Load load, LfNetworkParameters parameters) { | ||
loadsRefs.add(Ref.create(load, parameters.isCacheEnabled())); | ||
loadsRefs.put(load.getId(), Ref.create(load, parameters.isCacheEnabled())); | ||
loadsDisablingStatus.put(load.getId(), false); | ||
double p0 = load.getP0(); | ||
double q0 = load.getQ0(); | ||
|
@@ -97,8 +106,8 @@ void add(Load load, LfNetworkParameters parameters) { | |
if (p0 < 0 || hasVariableActivePower || reactiveOnlyLoad) { | ||
ensurePowerFactorConstantByLoad = true; | ||
} | ||
double absTargetP = getAbsVariableTargetP(load); | ||
loadsAbsVariableTargetP.add(absTargetP); | ||
double absTargetP = getAbsVariableTargetPPerUnit(load, distributedOnConformLoad); | ||
loadsAbsVariableTargetP.put(load.getId(), absTargetP); | ||
absVariableTargetP += absTargetP; | ||
} | ||
|
||
|
@@ -158,7 +167,10 @@ public void setAbsVariableTargetP(double absVariableTargetP) { | |
this.absVariableTargetP = absVariableTargetP; | ||
} | ||
|
||
private double getAbsVariableTargetP(Load load) { | ||
public static double getAbsVariableTargetPPerUnit(Load load, boolean distributedOnConformLoad) { | ||
if (isLoadNotParticipating(load)) { | ||
return 0.0; | ||
} | ||
double varP; | ||
if (distributedOnConformLoad) { | ||
varP = load.getExtension(LoadDetail.class) == null ? 0 : load.getExtension(LoadDetail.class).getVariableActivePower(); | ||
|
@@ -169,17 +181,17 @@ private double getAbsVariableTargetP(Load load) { | |
} | ||
|
||
@Override | ||
public double getOriginalLoadCount() { | ||
public int getOriginalLoadCount() { | ||
return loadsRefs.size(); | ||
} | ||
|
||
private double getParticipationFactor(int i) { | ||
private double getParticipationFactor(String originalLoadId) { | ||
// FIXME | ||
// After a load contingency or a load action, only the global variable targetP is updated. | ||
// The list loadsAbsVariableTargetP never changes. It is not an issue for security analysis as the network is | ||
// never updated. Excepted if loadPowerFactorConstant is true, the new targetQ could be wrong after a load contingency | ||
// or a load action. | ||
return absVariableTargetP != 0 ? loadsAbsVariableTargetP.get(i) / absVariableTargetP : 0; | ||
return absVariableTargetP != 0 ? loadsAbsVariableTargetP.get(originalLoadId) / absVariableTargetP : 0; | ||
} | ||
|
||
private double calculateP() { | ||
|
@@ -199,9 +211,9 @@ public void updateState(boolean loadPowerFactorConstant, boolean breakers) { | |
double pv = p == EvaluableConstants.NAN ? 1 : calculateP() / targetP; // extract part of p that is dependent to voltage | ||
double qv = q == EvaluableConstants.NAN ? 1 : calculateQ() / targetQ; | ||
double diffLoadTargetP = targetP - initialTargetP; | ||
for (int i = 0; i < loadsRefs.size(); i++) { | ||
Load load = loadsRefs.get(i).get(); | ||
double diffP0 = diffLoadTargetP * getParticipationFactor(i) * PerUnit.SB; | ||
for (Ref<Load> refLoad : loadsRefs.values()) { | ||
Load load = refLoad.get(); | ||
double diffP0 = diffLoadTargetP * getParticipationFactor(load.getId()) * PerUnit.SB; | ||
double updatedP0 = load.getP0() + diffP0; | ||
double updatedQ0 = load.getQ0() + (loadPowerFactorConstant ? getPowerFactor(load) * diffP0 : 0.0); | ||
load.getTerminal() | ||
|
@@ -223,9 +235,9 @@ public void updateState(boolean loadPowerFactorConstant, boolean breakers) { | |
@Override | ||
public double calculateNewTargetQ(double diffTargetP) { | ||
double newLoadTargetQ = 0; | ||
for (int i = 0; i < loadsRefs.size(); i++) { | ||
Load load = loadsRefs.get(i).get(); | ||
double updatedQ0 = load.getQ0() / PerUnit.SB + getPowerFactor(load) * diffTargetP * getParticipationFactor(i); | ||
for (Ref<Load> refLoad : loadsRefs.values()) { | ||
Load load = refLoad.get(); | ||
double updatedQ0 = load.getQ0() / PerUnit.SB + getPowerFactor(load) * diffTargetP * getParticipationFactor(load.getId()); | ||
newLoadTargetQ += updatedQ0; | ||
} | ||
return newLoadTargetQ; | ||
|
@@ -255,6 +267,14 @@ private static double getPowerFactor(Load load) { | |
return load.getP0() != 0 ? load.getQ0() / load.getP0() : 1; | ||
} | ||
|
||
/** | ||
* Returns true if the load does not participate to slack distribution | ||
*/ | ||
public static boolean isLoadNotParticipating(Load load) { | ||
// Fictitious loads that do not participate to slack distribution. | ||
return load.isFictitious() || LoadType.FICTITIOUS.equals(load.getLoadType()); | ||
} | ||
|
||
@Override | ||
public Evaluable getP() { | ||
return p; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should not keep directly iidm.network objects in memory since fast restart is implemented (#635)
If you need to keep the Load in a record, use a WeakRef instead.
Otherwise, this will prevent the GC from deleting a Network if the fast restart mode is on.
See LfBatteryImpl for an example.
Ref are created using com.powsybl.openloadflow.network.impl.Ref
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, thanks for the explanation
Since I don't need a lot of information about the load, only it's id and if it's fictitious or not, I kept only those informations instead of creating a Ref