-
Notifications
You must be signed in to change notification settings - Fork 6
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
fix syncv #460
Merged
fix syncv #460
Changes from all commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
a43f002
Synchronization between views for v and angle bus values.
FranckLecuyer 8492ef9
Merge branch 'main' into synchronize_set_v_angle_on_bus_between_views
FranckLecuyer 3afafdd
Merge branch 'main' into synchronize_set_v_angle_on_bus_between_views
FranckLecuyer 9ce5cb7
Merge branch 'main' into synchronize_set_v_angle_on_bus_between_views
FranckLecuyer 6661c1f
Changes after review
FranckLecuyer 3b26409
Fix sonar issue
FranckLecuyer 98bf508
Merge branch 'main' into synchronize_set_v_angle_on_bus_between_views
FranckLecuyer 4c2dffb
more exhaustive test
jonenst d09854e
wip fix syncv
jonenst ed42836
more fixes using busnum instead of vertex
jonenst 54ef522
Fix updateBusesAttributes method in CalculatedBus.java
FranckLecuyer d59aada
Cleaning and optimizing code
FranckLecuyer ebe387e
Move methods in another file
FranckLecuyer 16edded
Add configuration similar to the one in AbstractMainConnectedComponen…
FranckLecuyer 15df0fa
Clean code in getVAndAngleFromOtherView method
FranckLecuyer 6853516
VoltageLevelTest, Add more combinations to setV/setAngle for cache ex…
jonenst 9c17fe0
Improve exhaustive test, make nodebreaker consistent with invalid vie…
jonenst e9f18ad
add more checks for isCalculatedBusValid for updates and code improve…
jonenst 02033a4
remove useless cast as per sonar
jonenst 101cb6f
Merge branch 'main' into fixsyncv
jonenst a824b15
Merge branch 'main' into fixsyncv
jonenst File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,9 +15,13 @@ | |
import com.powsybl.iidm.network.util.Networks; | ||
import com.powsybl.network.store.model.*; | ||
import lombok.EqualsAndHashCode; | ||
import org.apache.commons.collections4.CollectionUtils; | ||
import org.apache.commons.collections4.MapUtils; | ||
|
||
import java.util.*; | ||
import java.util.Map.Entry; | ||
import java.util.function.Function; | ||
import java.util.function.ObjDoubleConsumer; | ||
import java.util.function.Predicate; | ||
import java.util.stream.Collectors; | ||
import java.util.stream.Stream; | ||
|
@@ -131,10 +135,35 @@ public double getV() { | |
return getAttributes().getV(); | ||
} | ||
|
||
private void setVInCalculatedBus(CalculatedBusAttributes calculatedBusAttributes, double value) { | ||
calculatedBusAttributes.setV(value); | ||
} | ||
|
||
private void setVInConfiguredBus(ConfiguredBusImpl configuredBus, double value) { | ||
configuredBus.setConfiguredBusV(value); | ||
} | ||
|
||
private void setAngleInCalculatedBus(CalculatedBusAttributes calculatedBusAttributes, double value) { | ||
calculatedBusAttributes.setAngle(value); | ||
} | ||
|
||
private void setAngleInConfiguredBus(ConfiguredBusImpl configuredBus, double value) { | ||
configuredBus.setConfiguredBusAngle(value); | ||
} | ||
Comment on lines
+138
to
+152
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. Can we have some consistency in naming? |
||
|
||
@Override | ||
public Bus setV(double v) { | ||
getAttributes().setV(v); | ||
index.updateVoltageLevelResource(voltageLevelResource, AttributeFilter.SV); | ||
|
||
if (getVoltageLevel().getTopologyKind() == TopologyKind.BUS_BREAKER) { | ||
// update V in configured buses | ||
// this triggers network notifications for 'v' for each configured bus | ||
updateConfiguredBuses(v, this::setVInConfiguredBus); | ||
} else { | ||
// update V for buses in the other view (busView/busBreakerView) | ||
updateBusesAttributes(v, this::setVInCalculatedBus); | ||
} | ||
return this; | ||
} | ||
|
||
|
@@ -147,6 +176,15 @@ public double getAngle() { | |
public Bus setAngle(double angle) { | ||
getAttributes().setAngle(angle); | ||
index.updateVoltageLevelResource(voltageLevelResource, AttributeFilter.SV); | ||
|
||
if (getVoltageLevel().getTopologyKind() == TopologyKind.BUS_BREAKER) { | ||
// update angle in configuredBus | ||
// this triggers network notifications for 'angle' for each configured bus | ||
updateConfiguredBuses(angle, this::setAngleInConfiguredBus); | ||
} else { | ||
// update angle for buses in the other view (busView/busBreakerView) | ||
updateBusesAttributes(angle, this::setAngleInCalculatedBus); | ||
} | ||
return this; | ||
} | ||
|
||
|
@@ -471,4 +509,62 @@ public <E extends Extension<Bus>, B extends ExtensionAdder<Bus, E>> B newExtensi | |
public int getCalculatedBusNum() { | ||
return calculatedBusNum; | ||
} | ||
|
||
private void updateBusesAttributes(double value, ObjDoubleConsumer<CalculatedBusAttributes> setValue) { | ||
// Use the busnum of this bus to get the nodes in this bus to get the | ||
// busnums in the other view to get the buses of the other view to | ||
// update them all. For the busbreakerview, there is only one matching bus in the busview so return early. | ||
// We only update when isCalculatedBusesValid is true, there is no point in updating stale bus objects and | ||
// in when isCalculatedBusesValid is not true, we may even update the wrong buses (but not much of a problem | ||
// because they are stale objects). | ||
// TODO add tests for updates with isCalculatedBusesValid=false | ||
// NOTE: we don't maintain a mapping from busnum to nodes so we iterate | ||
// all the nodes and filter but it should be ok, the number is small. TODO, is this really ok ? | ||
VoltageLevelAttributes vlAttributes = ((VoltageLevelImpl) getVoltageLevel()).getResource().getAttributes(); | ||
Map<Integer, Integer> nodesToCalculatedBuses = isBusView | ||
? vlAttributes.getNodeToCalculatedBusForBusView() | ||
: vlAttributes.getNodeToCalculatedBusForBusBreakerView(); | ||
Map<Integer, Integer> nodesToCalculatedBusesInOtherView = isBusView | ||
? vlAttributes.getNodeToCalculatedBusForBusBreakerView() | ||
: vlAttributes.getNodeToCalculatedBusForBusView(); | ||
List<CalculatedBusAttributes> calculatedBusAttributes = isBusView | ||
? vlAttributes.getCalculatedBusesForBusBreakerView() | ||
: vlAttributes.getCalculatedBusesForBusView(); | ||
if (vlAttributes.isCalculatedBusesValid() && !CollectionUtils.isEmpty(calculatedBusAttributes) | ||
&& !MapUtils.isEmpty(nodesToCalculatedBuses) && !MapUtils.isEmpty(nodesToCalculatedBusesInOtherView)) { | ||
Set<Integer> seen = new HashSet<>(); | ||
for (Entry<Integer, Integer> entry : nodesToCalculatedBuses.entrySet()) { | ||
if (getCalculatedBusNum() == entry.getValue()) { | ||
int node = entry.getKey(); | ||
Integer busNumInOtherView = nodesToCalculatedBusesInOtherView.get(node); | ||
if (busNumInOtherView != null && !seen.contains(busNumInOtherView)) { | ||
setValue.accept(calculatedBusAttributes.get(busNumInOtherView), value); | ||
index.updateVoltageLevelResource(voltageLevelResource, AttributeFilter.SV); | ||
seen.add(busNumInOtherView); | ||
} | ||
if (!isBusView) { | ||
return; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
private void updateConfiguredBuses(double newValue, | ||
ObjDoubleConsumer<ConfiguredBusImpl> setValue) { | ||
// update all the configured buses | ||
// NOTE: we don't maintain a mapping from busnum to bus so we iterate | ||
// all the buses and filter but it should be ok, the number is small. TODO, is this really ok ? | ||
// We only update when isCalculatedBusesValid is true, otherwise we may update the wrong configured bus | ||
// TODO add tests for updates with isCalculatedBusesValid=false | ||
VoltageLevelAttributes vlAttributes = ((VoltageLevelImpl) getVoltageLevel()).getResource().getAttributes(); | ||
if (vlAttributes.isCalculatedBusesValid()) { | ||
for (Entry<String, Integer> entry : vlAttributes.getBusToCalculatedBusForBusView().entrySet()) { | ||
if (getCalculatedBusNum() == entry.getValue()) { | ||
ConfiguredBusImpl bus = index.getConfiguredBus(entry.getKey()).orElseThrow(IllegalStateException::new); | ||
setValue.accept(bus, newValue); | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,11 +25,18 @@ | |
import com.powsybl.iidm.network.ValidationException; | ||
import com.powsybl.iidm.network.VoltageLevel; | ||
import com.powsybl.iidm.network.VscConverterStation; | ||
import com.powsybl.network.store.model.AttributeFilter; | ||
import com.powsybl.network.store.model.CalculatedBusAttributes; | ||
import com.powsybl.network.store.model.ConfiguredBusAttributes; | ||
import com.powsybl.network.store.model.VoltageLevelAttributes; | ||
import com.powsybl.network.store.model.Resource; | ||
import org.apache.commons.collections4.MapUtils; | ||
import org.apache.commons.collections4.CollectionUtils; | ||
|
||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Optional; | ||
import java.util.function.ObjDoubleConsumer; | ||
import java.util.function.Predicate; | ||
import java.util.stream.Collectors; | ||
import java.util.stream.Stream; | ||
|
@@ -77,31 +84,97 @@ public double getAngle() { | |
return getResource().getAttributes().getAngle(); | ||
} | ||
|
||
@Override | ||
public Bus setV(double v) { | ||
if (v < 0) { | ||
throw new ValidationException(this, "voltage cannot be < 0"); | ||
} | ||
private void setV(double v, boolean updateCalculatedBus) { | ||
double oldValue = getResource().getAttributes().getV(); | ||
if (v != oldValue) { | ||
updateResource(res -> res.getAttributes().setV(v)); | ||
String variantId = index.getNetwork().getVariantManager().getWorkingVariantId(); | ||
index.notifyUpdate(this, "v", variantId, oldValue, v); | ||
|
||
if (updateCalculatedBus) { | ||
// update V for bus in BusView | ||
updateCalculatedBusAttributes(v, getResource().getAttributes().getVoltageLevelId(), this::setVInCalculatedBus); | ||
} | ||
} | ||
return this; | ||
} | ||
|
||
// update without the part setting values in calculated buses otherwise it | ||
// leads to infinite loops because calculated buses also update configured buses | ||
void setConfiguredBusV(double v) { | ||
setV(v, false); | ||
} | ||
|
||
@Override | ||
public Bus setAngle(double angle) { | ||
public Bus setV(double v) { | ||
if (v < 0) { | ||
throw new ValidationException(this, "voltage cannot be < 0"); | ||
} | ||
setV(v, true); | ||
return this; | ||
} | ||
|
||
void setAngle(double angle, boolean updateCalculatedBus) { | ||
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. private? |
||
double oldValue = getResource().getAttributes().getAngle(); | ||
if (angle != oldValue) { | ||
updateResource(res -> res.getAttributes().setAngle(angle)); | ||
String variantId = index.getNetwork().getVariantManager().getWorkingVariantId(); | ||
index.notifyUpdate(this, "angle", variantId, oldValue, angle); | ||
|
||
if (updateCalculatedBus) { | ||
// update angle for bus in BusView | ||
updateCalculatedBusAttributes(angle, getResource().getAttributes().getVoltageLevelId(), this::setAngleInCalculatedBus); | ||
} | ||
} | ||
} | ||
|
||
// update without the part setting values in calculated buses otherwise | ||
// it leads to infinite loops because calculated buses also update configured buses | ||
void setConfiguredBusAngle(double angle) { | ||
setAngle(angle, false); | ||
} | ||
|
||
@Override | ||
public Bus setAngle(double angle) { | ||
setAngle(angle, true); | ||
return this; | ||
} | ||
|
||
private void setVInCalculatedBus(CalculatedBusAttributes calculatedBusAttributes, double value) { | ||
calculatedBusAttributes.setV(value); | ||
} | ||
|
||
private void setAngleInCalculatedBus(CalculatedBusAttributes calculatedBusAttributes, double value) { | ||
calculatedBusAttributes.setAngle(value); | ||
} | ||
|
||
private void updateCalculatedBusAttributes(double newValue, | ||
String voltageLevelId, | ||
ObjDoubleConsumer<CalculatedBusAttributes> setValue) { | ||
VoltageLevelImpl voltageLevel = index.getVoltageLevel(voltageLevelId).orElseThrow(IllegalArgumentException::new); | ||
VoltageLevelAttributes vlAttributes = voltageLevel.getResource().getAttributes(); | ||
Map<String, Integer> calculatedBuses = vlAttributes.getBusToCalculatedBusForBusView(); | ||
List<CalculatedBusAttributes> busViewCalculatedBusesAttributes = vlAttributes.getCalculatedBusesForBusView(); | ||
// We only update when isCalculatedBusesValid is true, there is no point in updating stale bus objects and | ||
// in when isCalculatedBusesValid is not true, we may even update the wrong buses (but not much of a problem | ||
// because they are stale objects). | ||
// TODO add tests for updates with isCalculatedBusesValid=false | ||
if (vlAttributes.isCalculatedBusesValid() | ||
&& !CollectionUtils.isEmpty(busViewCalculatedBusesAttributes) | ||
&& !MapUtils.isEmpty(calculatedBuses)) { | ||
Integer busviewnum = calculatedBuses.get(getId()); | ||
if (busviewnum != null) { | ||
CalculatedBusAttributes busViewCalculatedBusAttributes = busViewCalculatedBusesAttributes.get(busviewnum); | ||
// Same code as the iidm impl for CalculatedBus setV / setAngle | ||
// (without the part setting values in configured buses otherwise | ||
// it would be an infinite loop), but copy paste here | ||
// to avoid creating the object (calculated buses are created on when computing | ||
// the bus view, but we want to only update if the busview exist, not force its creation) | ||
setValue.accept(busViewCalculatedBusAttributes, newValue); | ||
index.updateVoltageLevelResource(voltageLevel.getResource(), AttributeFilter.SV); | ||
} | ||
} | ||
} | ||
|
||
@Override | ||
public double getFictitiousP0() { | ||
return getResource().getAttributes().getFictitiousP0(); | ||
|
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
should we use if (isCalculatedBusesValid(voltageLevelResource, !isBusView)) {
like in getCalculatedBusAttributesList ?