Skip to content

Commit

Permalink
Synchronization between views for v and angle bus values.
Browse files Browse the repository at this point in the history
Signed-off-by: Franck LECUYER <[email protected]>
  • Loading branch information
FranckLecuyer committed Sep 16, 2024
1 parent 725ad63 commit a43f002
Show file tree
Hide file tree
Showing 7 changed files with 307 additions and 98 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,18 @@
*/
package com.powsybl.network.store.iidm.impl;

import com.google.common.util.concurrent.AtomicDouble;
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.jgrapht.Graph;
import org.jgrapht.alg.connectivity.ConnectivityInspector;
import org.jgrapht.graph.DirectedPseudograph;

import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
Expand Down Expand Up @@ -358,18 +362,80 @@ private void setCalculatedBuses(Resource<VoltageLevelAttributes> voltageLevelRes
}
}

private void getVAndAngleFromConfiguredBus(NetworkObjectIndex index,
Resource<VoltageLevelAttributes> voltageLevelResource,
ConnectedSetResult<T> connectedSet,
AtomicDouble v,
AtomicDouble angle) {
index.getConfiguredBuses(voltageLevelResource.getId()).forEach(bus -> {
ConfiguredBusImpl configuredBus = (ConfiguredBusImpl) bus;
AtomicReference<ConfiguredBusImpl> foundConfiguredBus = new AtomicReference<>();
configuredBus.getAllTerminals().stream()
.filter(Terminal::isConnected)
.forEach(t -> {
if (foundConfiguredBus.get() == null) {
connectedSet.getConnectedVertices().stream().filter(vertex ->
vertex.getId().equals(t.getConnectable().getId())
).findFirst().ifPresent(vertex -> foundConfiguredBus.set(configuredBus));
}
});
if (foundConfiguredBus.get() != null) {
v.set(foundConfiguredBus.get().getResource().getAttributes().getV());
angle.set(foundConfiguredBus.get().getResource().getAttributes().getAngle());
}
});
}

private void getVAndAngleFromOtherView(NetworkObjectIndex index,
Resource<VoltageLevelAttributes> voltageLevelResource,
ConnectedSetResult<T> connectedSet,
AtomicDouble v,
AtomicDouble angle,
boolean isBusView) {
AtomicBoolean foundInCalculatedBuses = new AtomicBoolean(false);
List<CalculatedBusAttributes> calculatedBusAttributes = isBusView ?
voltageLevelResource.getAttributes().getCalculatedBusesForBusBreakerView() :
voltageLevelResource.getAttributes().getCalculatedBusesForBusView();
if (!CollectionUtils.isEmpty(calculatedBusAttributes)) {
connectedSet.getConnectedVertices().forEach(vertex -> {
List<CalculatedBusAttributes> busesInOtherView = calculatedBusAttributes.stream().filter(attr -> attr.getVertices().contains(vertex)).toList();
if (!CollectionUtils.isEmpty(busesInOtherView)) {
busesInOtherView.forEach(b -> {
if (Double.isNaN(v.get()) && !Double.isNaN(b.getV())) {
v.set(b.getV());
foundInCalculatedBuses.set(true);
}
if (Double.isNaN(angle.get()) && !Double.isNaN(b.getAngle())) {
angle.set(b.getAngle());
foundInCalculatedBuses.set(true);
}
});
}
});
}
if (isBusView && !foundInCalculatedBuses.get()) {
// get V and Angle values from configured buses
getVAndAngleFromConfiguredBus(index, voltageLevelResource, connectedSet, v, angle);
}
}

private CalculationResult<T> getCalculatedBusAttributesList(NetworkObjectIndex index, Resource<VoltageLevelAttributes> voltageLevelResource, boolean isBusView) {
List<CalculatedBusAttributes> calculatedBusAttributesList;
Map<T, Integer> nodeOrBusToCalculatedBusNum;
if (isCalculatedBusesValid(voltageLevelResource, isBusView)) {
calculatedBusAttributesList = isBusView ? voltageLevelResource.getAttributes().getCalculatedBusesForBusView() : voltageLevelResource.getAttributes().getCalculatedBusesForBusBreakerView();
nodeOrBusToCalculatedBusNum = getNodeOrBusToCalculatedBusNum(voltageLevelResource, isBusView);
} else {
// calculate buses
List<ConnectedSetResult<T>> connectedSetList = findConnectedSetList(index, voltageLevelResource, isBusView);
AtomicDouble v = new AtomicDouble(Double.NaN);
AtomicDouble angle = new AtomicDouble(Double.NaN);
calculatedBusAttributesList = connectedSetList
.stream()
.map(connectedSet -> new CalculatedBusAttributes(connectedSet.getConnectedVertices(), null, null, Double.NaN, Double.NaN))
.map(connectedSet -> {
// get V and Angle values from other view if available
getVAndAngleFromOtherView(index, voltageLevelResource, connectedSet, v, angle, isBusView);
return new CalculatedBusAttributes(connectedSet.getConnectedVertices(), null, null, v.get(), angle.get());
})
.collect(Collectors.toList());
setCalculatedBuses(voltageLevelResource, isBusView, calculatedBusAttributesList);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +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 java.util.*;
import java.util.function.Function;
import java.util.function.ObjDoubleConsumer;
import java.util.function.Predicate;
import java.util.function.ToDoubleFunction;
import java.util.stream.Collectors;
import java.util.stream.Stream;

Expand Down Expand Up @@ -48,6 +51,9 @@ public final class CalculatedBus implements BaseBus {

private final Function<Terminal, Bus> getBusFromTerminal;

private static final String VOLTAGE = "v";
private static final String ANGLE = "angle";

CalculatedBus(NetworkObjectIndex index, String voltageLevelId, String id, String name, Resource<VoltageLevelAttributes> voltageLevelResource,
int calculatedBusNum, boolean isBusView) {
this.index = Objects.requireNonNull(index);
Expand Down Expand Up @@ -131,13 +137,94 @@ public double getV() {
return getAttributes().getV();
}

private void setVInCalculatedBus(CalculatedBusAttributes calculatedBusAttributes, double value) {
calculatedBusAttributes.setV(value);
}

private void setVInConfiguredBus(ConfiguredBusAttributes configuredBusAttributes, double value) {
configuredBusAttributes.setV(value);
}

private double getVInBus(Bus bus) {
return bus.getV();
}

private void setAngleInCalculatedBus(CalculatedBusAttributes calculatedBusAttributes, double value) {
calculatedBusAttributes.setAngle(value);
}

private void setAngleInConfiguredBus(ConfiguredBusAttributes configuredBusAttributes, double value) {
configuredBusAttributes.setAngle(value);
}

private double getAngleInBus(Bus bus) {
return bus.getAngle();
}

@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
updateConfiguredBuses(v, getAttributes(), VOLTAGE, this::getVInBus, this::setVInConfiguredBus);
} else {
if (isBusView) {
// update V for buses in BusBreakerView
updateBusesAttributes(v, voltageLevelResource.getAttributes().getCalculatedBusesForBusBreakerView(), getAttributes(), this::setVInCalculatedBus);
} else {
// update V for buses in BusView
updateBusesAttributes(v, voltageLevelResource.getAttributes().getCalculatedBusesForBusView(), getAttributes(), this::setVInCalculatedBus);
}
}
return this;
}

private void updateBusesAttributes(double value,
List<CalculatedBusAttributes> calculatedBusAttributesList,
CalculatedBusAttributes sourceBusAttributes,
ObjDoubleConsumer<CalculatedBusAttributes> setValue) {
if (!CollectionUtils.isEmpty(calculatedBusAttributesList)) {
calculatedBusAttributesList.forEach(busToUpdate -> busToUpdate.getVertices().forEach(vertex1 ->
sourceBusAttributes.getVertices().stream().filter(v -> v.getId().equals(vertex1.getId())).findFirst().ifPresent(vertex2 -> {
setValue.accept(busToUpdate, value);
index.updateVoltageLevelResource(voltageLevelResource, AttributeFilter.SV);
})
));
}
}

private void updateConfiguredBuses(double newValue,
CalculatedBusAttributes calculatedBusAttributesBus,
String attributeName,
ToDoubleFunction<Bus> getValue,
ObjDoubleConsumer<ConfiguredBusAttributes> setValue) {
List<String> busesIds = calculatedBusAttributesBus.getVertices().stream()
.map(Vertex::getBus)
.toList();

List<Bus> buses = index.getConfiguredBuses().stream()
.filter(bus -> busesIds.contains(bus.getId()) && !Objects.equals(getValue.applyAsDouble(bus), newValue))
.toList();

Map<Bus, Map.Entry<Double, Double>> oldNewValues = buses.stream()
.collect(Collectors.toMap(
bus -> bus,
bus -> new AbstractMap.SimpleEntry<>(getValue.applyAsDouble(bus), newValue)
));

buses.forEach(bus -> {
setValue.accept(((ConfiguredBusImpl) bus).getResource().getAttributes(), newValue);
index.updateConfiguredBusResource(((ConfiguredBusImpl) bus).getResource(), null);
});

String variantId = index.getNetwork().getVariantManager().getWorkingVariantId();
oldNewValues.forEach((bus, oldNewValue) ->
index.notifyUpdate(bus, attributeName, variantId, oldNewValue.getKey(), oldNewValue.getValue())
);
}

@Override
public double getAngle() {
return getAttributes().getAngle();
Expand All @@ -147,6 +234,19 @@ 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
updateConfiguredBuses(angle, getAttributes(), ANGLE, this::getAngleInBus, this::setAngleInConfiguredBus);
} else {
if (isBusView) {
// update angle for Bus in BusBreakerView
updateBusesAttributes(angle, voltageLevelResource.getAttributes().getCalculatedBusesForBusBreakerView(), getAttributes(), this::setAngleInCalculatedBus);
} else {
// update angle for Bus in BusView
updateBusesAttributes(angle, voltageLevelResource.getAttributes().getCalculatedBusesForBusView(), getAttributes(), this::setAngleInCalculatedBus);
}
}
return this;
}

Expand Down Expand Up @@ -423,6 +523,10 @@ public Stream<Terminal> getAllTerminalsStream() {
.filter(t -> t.getVoltageLevel().getId().equals(getVoltageLevel().getId()) && pred.test(t));
}

public int getCalculatedBusNum() {
return calculatedBusNum;
}

@Override
public <E extends Extension<Bus>> void addExtension(Class<? super E> aClass, E e) {
throw new UnsupportedOperationException("Adding an extension on calculated bus is not authorized");
Expand Down Expand Up @@ -467,8 +571,4 @@ public <E extends Extension<Bus>, B extends ExtensionAdder<Bus, E>> B newExtensi
ExtensionAdderProvider provider = ExtensionAdderProviders.findCachedProvider(getImplementationName(), type);
return (B) provider.newAdder(this);
}

public int getCalculatedBusNum() {
return calculatedBusNum;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +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.Resource;
import org.apache.commons.collections4.CollectionUtils;

import java.util.List;
import java.util.Optional;
import java.util.function.ObjDoubleConsumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
Expand Down Expand Up @@ -77,6 +82,40 @@ public double getAngle() {
return getResource().getAttributes().getAngle();
}

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) {
Optional<VoltageLevelImpl> voltageLevelOpt = index.getVoltageLevel(voltageLevelId);

voltageLevelOpt.ifPresent(voltageLevel -> {
List<CalculatedBusAttributes> calculatedBusAttributesList = voltageLevel.getResource()
.getAttributes()
.getCalculatedBusesForBusView();

if (CollectionUtils.isNotEmpty(calculatedBusAttributesList)) {
List<Integer> calculatedBusesNum = getAllTerminals().stream()
.filter(Terminal::isConnected)
.map(t -> ((CalculatedBus) t.getBusView().getBus()).getCalculatedBusNum()).distinct().toList();
List<CalculatedBusAttributes> busesToUpdateList = IntStream.range(0, calculatedBusAttributesList.size())
.filter(calculatedBusesNum::contains)
.mapToObj(calculatedBusAttributesList::get)
.toList();
if (CollectionUtils.isNotEmpty(busesToUpdateList)) {
busesToUpdateList.forEach(b -> setValue.accept(b, newValue));
index.updateVoltageLevelResource(voltageLevel.getResource(), AttributeFilter.SV);
}
}
});
}

@Override
public Bus setV(double v) {
if (v < 0) {
Expand All @@ -87,6 +126,9 @@ public Bus setV(double v) {
updateResource(res -> res.getAttributes().setV(v));
String variantId = index.getNetwork().getVariantManager().getWorkingVariantId();
index.notifyUpdate(this, "v", variantId, oldValue, v);

// update V for bus in BusView
updateCalculatedBusAttributes(v, getResource().getAttributes().getVoltageLevelId(), this::setVInCalculatedBus);
}
return this;
}
Expand All @@ -98,6 +140,9 @@ public Bus setAngle(double angle) {
updateResource(res -> res.getAttributes().setAngle(angle));
String variantId = index.getNetwork().getVariantManager().getWorkingVariantId();
index.notifyUpdate(this, "angle", variantId, oldValue, angle);

// update angle for bus in BusView
updateCalculatedBusAttributes(angle, getResource().getAttributes().getVoltageLevelId(), this::setAngleInCalculatedBus);
}
return this;
}
Expand Down
Loading

0 comments on commit a43f002

Please sign in to comment.