-
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
base: main
Are you sure you want to change the base?
fix syncv #460
Changes from all commits
a43f002
8492ef9
3afafdd
9ce5cb7
6661c1f
3b26409
98bf508
4c2dffb
d09854e
ed42836
54ef522
d59aada
ebe387e
16edded
15df0fa
6853516
9c17fe0
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 |
---|---|---|
|
@@ -9,6 +9,8 @@ | |
import com.powsybl.commons.config.PlatformConfig; | ||
import com.powsybl.iidm.network.*; | ||
import com.powsybl.network.store.model.*; | ||
import org.apache.commons.collections4.CollectionUtils; | ||
import org.apache.commons.collections4.MapUtils; | ||
import org.jgrapht.Graph; | ||
import org.jgrapht.alg.connectivity.ConnectivityInspector; | ||
import org.jgrapht.graph.DirectedPseudograph; | ||
|
@@ -358,6 +360,52 @@ private void setCalculatedBuses(Resource<VoltageLevelAttributes> voltageLevelRes | |
} | ||
} | ||
|
||
private CalculatedBusAttributes findFirstMatchingNodeBreakerCalculatedBusAttributes(Resource<VoltageLevelAttributes> voltageLevelResource, | ||
ConnectedSetResult<T> connectedSet, boolean isBusView) { | ||
// TODO Some day we may decide to start preserving values in nodebreaker topology after invalidating the views, | ||
// so we could remove this check for isCalculatedBusesValid. Here it controls preserving | ||
// the value accross the other view, we have it to be consistent with preserving values | ||
// from the same view (currently not preserved) | ||
if (voltageLevelResource.getAttributes().isCalculatedBusesValid()) { | ||
List<CalculatedBusAttributes> calculatedBusAttributes = isBusView ? voltageLevelResource.getAttributes().getCalculatedBusesForBusBreakerView() : voltageLevelResource.getAttributes().getCalculatedBusesForBusView(); | ||
if (!CollectionUtils.isEmpty(calculatedBusAttributes)) { | ||
Map<Integer, Integer> nodesToCalculatedBuses = isBusView ? voltageLevelResource.getAttributes().getNodeToCalculatedBusForBusBreakerView() : voltageLevelResource.getAttributes().getNodeToCalculatedBusForBusView(); | ||
if (!MapUtils.isEmpty(nodesToCalculatedBuses)) { | ||
Integer node = (Integer) connectedSet.getConnectedNodesOrBuses().iterator().next(); // non deterministic | ||
Integer busNum = nodesToCalculatedBuses.get(node); | ||
if (busNum != null) { | ||
return calculatedBusAttributes.get(busNum); | ||
} | ||
} | ||
} | ||
} | ||
return null; | ||
} | ||
|
||
private CalculatedBusAttributes createCalculatedBusAttributesWithVAndAngle(NetworkObjectIndex index, | ||
Resource<VoltageLevelAttributes> voltageLevelResource, | ||
ConnectedSetResult<T> connectedSet, | ||
boolean isBusView) { | ||
double v = Double.NaN; | ||
double angle = Double.NaN; | ||
if (voltageLevelResource.getAttributes().getTopologyKind() == TopologyKind.NODE_BREAKER) { | ||
CalculatedBusAttributes busAttributes = findFirstMatchingNodeBreakerCalculatedBusAttributes(voltageLevelResource, connectedSet, isBusView); | ||
if (busAttributes != null) { | ||
v = busAttributes.getV(); | ||
angle = busAttributes.getAngle(); | ||
} | ||
} else { // BUS_BREAKER | ||
// currently for busbreakertopology the values are always preserved | ||
// when using only the busbreakerview. So mimic the behavior and always preserve them | ||
// when using the busview: get V and Angle values from configured buses | ||
String configuredBusId = ((ConnectedSetResult<String>) connectedSet).getConnectedNodesOrBuses().iterator().next(); // nondeterministic | ||
Bus b = index.getConfiguredBus(configuredBusId).orElseThrow(); | ||
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. Maybe customize the exception, in order to have a more accurate message ... |
||
v = b.getV(); | ||
angle = b.getAngle(); | ||
} | ||
return new CalculatedBusAttributes(connectedSet.getConnectedVertices(), null, null, v, angle); | ||
Comment on lines
+385
to
+406
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. This if/else makes me think that this should be implemented in BusBreakerTopology/NodeBreakerTopology classes ? Maybe an abstraction here |
||
} | ||
|
||
private CalculationResult<T> getCalculatedBusAttributesList(NetworkObjectIndex index, Resource<VoltageLevelAttributes> voltageLevelResource, boolean isBusView) { | ||
List<CalculatedBusAttributes> calculatedBusAttributesList; | ||
Map<T, Integer> nodeOrBusToCalculatedBusNum; | ||
|
@@ -369,7 +417,13 @@ private CalculationResult<T> getCalculatedBusAttributesList(NetworkObjectIndex i | |
List<ConnectedSetResult<T>> connectedSetList = findConnectedSetList(index, voltageLevelResource, isBusView); | ||
calculatedBusAttributesList = connectedSetList | ||
.stream() | ||
.map(connectedSet -> new CalculatedBusAttributes(connectedSet.getConnectedVertices(), null, null, Double.NaN, Double.NaN)) | ||
//TODO in this case in nodebreaker topology we currently don't preserve any values from | ||
//the same view if it was already computed but is invalidated. | ||
//we could do it some day (we need to define good heuristics to | ||
//match previous values to new buses). | ||
//NOTE: We chose to have the same behavior when getting the values from the other view | ||
// get V and Angle values from other view if available | ||
.map(connectedSet -> createCalculatedBusAttributesWithVAndAngle(index, voltageLevelResource, connectedSet, isBusView)) | ||
.collect(Collectors.toList()); | ||
setCalculatedBuses(voltageLevelResource, isBusView, calculatedBusAttributesList); | ||
|
||
|
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,43 @@ 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) { | ||
// busnum of this bus -> nodes in this bus -> busnums in the other view -> buses of the other view | ||
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. This comment is not clear |
||
VoltageLevelAttributes vlAttributes = ((VoltageLevelImpl) getVoltageLevel()).getResource().getAttributes(); | ||
Map<Integer, Integer> nodesToCalculatedBuses = isBusView | ||
? vlAttributes.getNodeToCalculatedBusForBusView() | ||
: vlAttributes.getNodeToCalculatedBusForBusBreakerView(); | ||
Map<Integer, Integer> nodesToCalculatedBusesInOtherView = isBusView | ||
? vlAttributes.getNodeToCalculatedBusForBusBreakerView() | ||
: vlAttributes.getNodeToCalculatedBusForBusView(); | ||
if (!MapUtils.isEmpty(nodesToCalculatedBuses) && !MapUtils.isEmpty(nodesToCalculatedBusesInOtherView)) { | ||
for (Entry<Integer, Integer> entry : nodesToCalculatedBuses.entrySet()) { | ||
if (getCalculatedBusNum() == entry.getValue()) { | ||
int node = entry.getKey(); | ||
if (nodesToCalculatedBusesInOtherView.containsKey(node)) { | ||
int busNumInOtherView = nodesToCalculatedBusesInOtherView.get(node); | ||
List<CalculatedBusAttributes> calculatedBusAttributes = isBusView | ||
? vlAttributes.getCalculatedBusesForBusBreakerView() | ||
: vlAttributes.getCalculatedBusesForBusView(); | ||
Comment on lines
+528
to
+530
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 is this inside the for loop? It looks like it's constant? Similarly to nodesToCalculatedBuses, etc |
||
if (!CollectionUtils.isEmpty(calculatedBusAttributes)) { | ||
setValue.accept(calculatedBusAttributes.get(busNumInOtherView), value); | ||
index.updateVoltageLevelResource(voltageLevelResource, AttributeFilter.SV); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
private void updateConfiguredBuses(double newValue, | ||
ObjDoubleConsumer<ConfiguredBusImpl> setValue) { | ||
VoltageLevelAttributes vlAttributes = ((VoltageLevelImpl) getVoltageLevel()).getResource().getAttributes(); | ||
for (Entry<String, Integer> entry : vlAttributes.getBusToCalculatedBusForBusView().entrySet()) { | ||
if (getCalculatedBusNum() == entry.getValue()) { | ||
Bus bus = getVoltageLevel().getBusBreakerView().getBus(entry.getKey()); | ||
setValue.accept((ConfiguredBusImpl) bus, newValue); | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,11 +25,16 @@ | |
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.Resource; | ||
import org.apache.commons.collections4.MapUtils; | ||
|
||
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 +82,94 @@ 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(); | ||
Map<String, Integer> calculatedBuses = voltageLevel.getResource().getAttributes().getBusToCalculatedBusForBusView(); | ||
// TODO, do we want to update the busview values if the view is invalid ? | ||
// if invalid, values will be restored from the configuredbuses on the next | ||
// busview computation anyway in the new bus objects and attributes, | ||
// but the previous bus objects and attributes may still be used somewhere | ||
// so there is a visible effect to choosing to update invalid views or not. | ||
if (!MapUtils.isEmpty(calculatedBuses)) { | ||
Integer busviewnum = calculatedBuses.get(getId()); | ||
if (busviewnum != null) { | ||
CalculatedBusAttributes busviewattributes = voltageLevel.getResource().getAttributes().getCalculatedBusesForBusView().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(busviewattributes, newValue); | ||
index.updateVoltageLevelResource(voltageLevel.getResource(), AttributeFilter.SV); | ||
} | ||
} | ||
} | ||
|
||
@Override | ||
public double getFictitiousP0() { | ||
return getResource().getAttributes().getFictitiousP0(); | ||
|
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.
Maybe check iterator with hasNext before calling next ...