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

Connect transformers during generator connection #2989

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,30 @@
import com.powsybl.computation.ComputationManager;
import com.powsybl.iidm.modification.topology.NamingStrategy;
import com.powsybl.iidm.modification.util.VoltageRegulationUtils;
import com.powsybl.iidm.network.Bus;
import com.powsybl.iidm.network.Generator;
import com.powsybl.iidm.network.IdentifiableType;
import com.powsybl.iidm.network.Network;
import com.powsybl.iidm.network.Terminal;
import com.powsybl.iidm.network.TwoWindingsTransformer;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import org.jgrapht.alg.util.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* @author Olivier Perrin {@literal <olivier.perrin at rte-france.com>}
*/
public final class ConnectGenerator extends AbstractNetworkModification {

private static final Logger LOGGER = LoggerFactory.getLogger(ConnectGenerator.class);

private final String generatorId;

public ConnectGenerator(String generatorId) {
Expand Down Expand Up @@ -54,5 +66,50 @@ static void connect(Generator g) {
VoltageRegulationUtils.getTargetVForRegulatingElement(g.getNetwork(), g.getRegulatingTerminal().getBusView().getBus(), g.getId(), IdentifiableType.GENERATOR)
.ifPresent(g::setTargetV);
}
connectTransformersOfGenerator(g);
}

/**
* Checks if the generator is connected to the network through transformers and, if it is the case, connect them too.
* If it is not the case, nothing is modified
*/
private static void connectTransformersOfGenerator(Generator generator) {
Bus genBus = getBus(generator.getTerminal());
Set<TwoWindingsTransformer> transformers = generator.getTerminal().getVoltageLevel().getTwoWindingsTransformerStream()
Copy link
Contributor

Choose a reason for hiding this comment

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

You don't fully check that the generator is connected to the network through transformers. Indeed,

  • the generator might be connected to the network through a line AND also through one or several two-winding transformers; in that case you might be connecting the transformers whereas the generator is already connected to the main connected component
  • the generator might be connected to the network through a two-winding transformer but with a retained breaker between the generator and the transformer

.filter(twt -> genBus.equals(getBus(twt.getTerminal1())) || genBus.equals(getBus(twt.getTerminal2())))
.collect(Collectors.toSet());
Map<String, Pair<Boolean, Boolean>> twtConnectionInitialState = new HashMap<>();
transformers.forEach(twt -> {
LOGGER.info("Connecting twoWindingsTransformer {} linked to generator {}", twt.getId(), generator.getId());
twtConnectionInitialState.put(twt.getId(), Pair.of(twt.getTerminal1().isConnected(), twt.getTerminal2().isConnected()));
twt.getTerminals().forEach(Terminal::connect);
Copy link
Contributor

Choose a reason for hiding this comment

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

Why connecting all transformers? one of them should be enough. Maybe we could add a parameter to the network modification to let the user decide.

});
// If, even after connecting the transformer, the generator remains disconnected from the main component, we remove the unnecessary transformer connection.
if (!generator.getTerminal().getBusBreakerView().getConnectableBus().isInMainConnectedComponent()) {
revertInitialState(generator, transformers, twtConnectionInitialState);
Comment on lines +88 to +89
Copy link
Contributor

Choose a reason for hiding this comment

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

We should avoid doing something and then revert it. In order to do so you could check beforehand if the two-winding transformers are connected to the main connected component.

}
}

private static void revertInitialState(Generator generator, Set<TwoWindingsTransformer> transformers, Map<String, Pair<Boolean, Boolean>> twtConnectionInitialState) {
transformers.forEach(twt -> {
LOGGER.info("Generator {} could not be connected to the main component, reset initial status for twoWindingsTransformer {}", generator.getId(), twt.getId());
Pair<Boolean, Boolean> initialTerminalStatus = twtConnectionInitialState.get(twt.getId());
applyTerminalStatus(twt.getTerminal1(), initialTerminalStatus.getFirst());
applyTerminalStatus(twt.getTerminal2(), initialTerminalStatus.getSecond());
});
}

private static void applyTerminalStatus(Terminal terminal, boolean connect) {
if (connect) {
terminal.connect();
} else {
terminal.disconnect();
}

}

private static Bus getBus(Terminal terminal) {
return terminal.getBusBreakerView().getConnectableBus();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,12 @@ public double scale(Network n, double asked, ScalingParameters parameters) {
Terminal t = g.getTerminal();
if (!t.isConnected()) {
if (parameters.isReconnect()) {
new ConnectGenerator(g.getId()).apply(n);
LOGGER.info("Connecting {}", g.getId());
if (!connectGeneratorToMainComponent(n, g)) {
Copy link
Member

Choose a reason for hiding this comment

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

You have to extract more lines in order to reduce the method complexity, it is still at 18 (with a maximum allowed fixed at 15)

// If the generator is still disconnected from main component, we should not change the active power setPoint
LOGGER.info("Generator {} could not be connected, discarded from scaling", g.getId());
return 0.;
}

} else {
LOGGER.info("Generator {} is not connected, discarded from scaling", g.getId());
return 0.;
Expand All @@ -139,6 +143,7 @@ public double scale(Network n, double asked, ScalingParameters parameters) {
double oldTargetP = g.getTargetP();
double minimumTargetP = minimumTargetP(g);
double maximumTargetP = maximumTargetP(g);

if (!parameters.isAllowsGeneratorOutOfActivePowerLimits() && (oldTargetP < minimumTargetP || oldTargetP > maximumTargetP)) {
LOGGER.error("Error scaling GeneratorScalable {}: Initial P is not in the range [Pmin, Pmax], skipped", id);
return 0.;
Expand All @@ -163,6 +168,12 @@ public double scale(Network n, double asked, ScalingParameters parameters) {
return done;
}

private static boolean connectGeneratorToMainComponent(Network n, Generator g) {
LOGGER.info("Connecting {}", g.getId());
new ConnectGenerator(g.getId()).apply(n);
return g.getTerminal().isConnected() && g.getTerminal().getBusBreakerView().getConnectableBus().isInMainConnectedComponent();
}

/**
* Compute the percentage of asked power available for the scale. It takes into account the scaling convention
* specified by the user and the sign of the asked power.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

Expand Down Expand Up @@ -101,4 +105,41 @@ void testConnectGeneratorWithNoNetworkInformation() {
assertTrue(g2.getTerminal().isConnected());
assertEquals(g2.getRegulatingTerminal().getBusView().getBus().getV(), g2.getTargetV(), 0.01);
}

@Test
void testConnectGeneratorWithTransformers() {
Network networkWithTransformers = Network.read("/testCase_with_transformers.xiidm", getClass().getResourceAsStream("/testCase_with_transformers.xiidm"));

// These generators are directly connected to main grid: it should remain that way
List<String> generatorsInitiallyConnected = List.of("ESDCGU1 _generator", "ESDCGN1 _generator", "ESCTGU1 _generator", "ESCTGN1 _generator");
checkTerminalStatus(networkWithTransformers, generatorsInitiallyConnected, true, true);

// These generators are directly connected to grid but its terminal is disconnected: they should be reconnected
List<String> generatorsToConnectTerminal = List.of("ESDDGU1 _generator", "ESDDGN1 _generator");
checkTerminalStatus(networkWithTransformers, generatorsToConnectTerminal, false, true);

// These generators are linked to grid through a line that is disconnected: it should remain that way
List<String> generatorsRemainsDisconnectedToTheMainComponent = List.of("ESCDGU1 _generator", "ESCDGN1 _generator");

// These generators are connected to grid through 2 transformers that are disconnected: they should be reconnected
List<String> generatorsToConnectToTheMainComponent = List.of("ESD2GU1 _generator", "ESDTGU1 _generator", "ESD2GN1 _generator", "ESDTGN1 _generator");
checkTerminalStatus(networkWithTransformers, Stream.concat(generatorsToConnectToTheMainComponent.stream(), generatorsRemainsDisconnectedToTheMainComponent.stream()).collect(Collectors.toList()), false, false);

for (List<String> generatorsId : List.of(generatorsInitiallyConnected, generatorsToConnectTerminal, generatorsToConnectToTheMainComponent, generatorsRemainsDisconnectedToTheMainComponent)) {
generatorsId.forEach(generatorId -> new ConnectGenerator(generatorId).apply(networkWithTransformers));
}
checkTerminalStatus(networkWithTransformers, generatorsRemainsDisconnectedToTheMainComponent, true, false);
checkTerminalStatus(networkWithTransformers, generatorsInitiallyConnected, true, true);
checkTerminalStatus(networkWithTransformers, Stream.concat(generatorsToConnectToTheMainComponent.stream(), generatorsToConnectTerminal.stream()).collect(Collectors.toList()), true, true);

}

private void checkTerminalStatus(Network network, List<String> ids, boolean shouldBeConnected, boolean shouldBeInMainSynchronousComponent) {
ids.forEach(id -> {
Generator gen = network.getGenerator(id);
assertEquals(shouldBeConnected, gen.getTerminal().isConnected());
assertEquals(shouldBeInMainSynchronousComponent, gen.getTerminal().getBusBreakerView().getConnectableBus().isInMainSynchronousComponent());
});
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class GeneratorScalableTest {
private Scalable g3;
private Scalable g4;
private Scalable g5;
private Scalable g6;
private Scalable unknownGeneratorScalable;

@BeforeEach
Expand All @@ -45,6 +46,8 @@ void setUp() {

g4 = Scalable.onGenerator("g2", 0., 80);
g5 = Scalable.onGenerator("g2", 20., 100);

g6 = Scalable.onGenerator("g4");
}

@Test
Expand Down Expand Up @@ -288,5 +291,22 @@ void testReconnect() {
assertFalse(generator.getTerminal().isConnected());
assertEquals(0.0, g1.scale(network, 10));
assertEquals(20.0, generator.getTargetP(), 1e-3);

}

@Test
void testForGeneratorDisconnectedFromMainComponent() {
//reconnect true and generator remains disconnected
Generator generator = network.getGenerator("g4");
generator.getTerminal().disconnect();
assertFalse(generator.getTerminal().isConnected());
assertFalse(generator.getTerminal().getBusBreakerView().getConnectableBus().isInMainConnectedComponent());
assertEquals(0.0, generator.getTargetP(), 1e-3);

ScalingParameters parameters = new ScalingParameters().setReconnect(true);
assertEquals(0., g6.scale(network, 20.0, parameters), 1e-3);
assertEquals(0., generator.getTargetP(), 1e-3);
assertTrue(generator.getTerminal().isConnected());
assertFalse(generator.getTerminal().getBusBreakerView().getConnectableBus().isInMainConnectedComponent());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,25 @@ static Network createNetwork() {
.setB1(0)
.setB2(0)
.add();
VoltageLevel vl3 = s.newVoltageLevel()
.setId("vl3")
.setTopologyKind(TopologyKind.BUS_BREAKER)
.setNominalV(380)
.add();
vl3.getBusBreakerView().newBus()
.setId("bus3")
.add();
vl3.newGenerator()
.setId("g4")
.setBus("bus3")
.setConnectableBus("bus3")
.setMinP(0.0)
.setMaxP(100.0)
.setTargetP(0.0)
.setVoltageRegulatorOn(false)
.setTargetQ(0.0)
.add();

return network;
}

Expand Down
Loading