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

Export buses voltage and update targets V #53

Merged
merged 31 commits into from
Feb 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
390cbcd
Refactor output classes.
p-arvy Jan 12, 2024
45f790d
refactor.
p-arvy Jan 12, 2024
ac2840c
refactor.
p-arvy Jan 12, 2024
bdf9067
Add TU for wrong number of columns.
p-arvy Jan 12, 2024
69d77c7
Merge branch 'main' into refactor_outputs
annetill Jan 15, 2024
e494e7b
Small renaming.
annetill Jan 17, 2024
9ba7d6a
Add export of voltage plan.
p-arvy Jan 10, 2024
b289f5a
remove useless id.
p-arvy Jan 10, 2024
6b12105
Add TU for VoltagePlanOutput.
p-arvy Jan 10, 2024
5115f1b
update/add TU.
p-arvy Jan 10, 2024
2ef091c
refactor.
p-arvy Jan 10, 2024
711d14c
Add warm-start and TU.
p-arvy Jan 11, 2024
295119b
refactor.
p-arvy Jan 17, 2024
023995c
add boolean for warm start update and refactor TUs.
p-arvy Jan 17, 2024
0cd5922
fix codesmell.
p-arvy Jan 17, 2024
3f98bca
Merge branch 'main' into export_buses_voltage
annetill Jan 18, 2024
b107540
refactor.
p-arvy Jan 18, 2024
f9d1851
Merge remote-tracking branch 'origin/export_buses_voltage' into expor…
p-arvy Jan 18, 2024
c117747
refactor.
p-arvy Jan 18, 2024
adea8ae
fix codesmell.
p-arvy Jan 18, 2024
c43485a
Refactor and add TUs.
p-arvy Jan 25, 2024
bace3c3
refactor mock files.
p-arvy Jan 25, 2024
c4d8012
add TU for missing regulated bus.
p-arvy Jan 25, 2024
504f6f5
wip.
p-arvy Jan 25, 2024
03eb0a2
Add log when bus/regulation terminal is null.
p-arvy Jan 31, 2024
ae63972
improve coverage.
p-arvy Jan 31, 2024
0bc0314
keep same changes but on modifiable tap changers/shunts.
p-arvy Feb 1, 2024
e49f9aa
refactor.
p-arvy Feb 1, 2024
810b10f
fix codesmell.
p-arvy Feb 1, 2024
4d192d2
remove restriction on target V update.
p-arvy Feb 1, 2024
24704ce
Rework to clarify.
annetill Feb 5, 2024
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 @@ -14,6 +14,7 @@
import com.powsybl.openreac.parameters.input.algo.AlgorithmInput;
import com.powsybl.openreac.parameters.output.OpenReacResult;
import com.powsybl.openreac.parameters.output.ReactiveSlackOutput;
import com.powsybl.openreac.parameters.output.VoltageProfileOutput;
import com.powsybl.openreac.parameters.output.network.NetworkModifications;

import java.util.ArrayList;
Expand All @@ -40,6 +41,7 @@ public class OpenReacAmplIOFiles implements AmplParameters {
private final VoltageLevelLimitsOverrideInput voltageLimitsOverride;
private final ConfiguredBusesWithReactiveSlack configuredReactiveSlackBuses;
private final NetworkModifications networkModifications;
private final VoltageProfileOutput voltageProfileOutput;
private final boolean debug;

public OpenReacAmplIOFiles(OpenReacParameters params, Network network, boolean debug) {
Expand All @@ -54,6 +56,7 @@ public OpenReacAmplIOFiles(OpenReacParameters params, Network network, boolean d
//outputs
this.reactiveSlackOutput = new ReactiveSlackOutput();
this.networkModifications = new NetworkModifications(network);
this.voltageProfileOutput = new VoltageProfileOutput();

this.debug = debug;
}
Expand All @@ -66,6 +69,10 @@ public NetworkModifications getNetworkModifications() {
return networkModifications;
}

public VoltageProfileOutput getVoltageProfileOutput() {
return voltageProfileOutput;
}

@Override
public Collection<AmplInputFile> getInputParameters() {
return List.of(constantQGenerators, variableShuntCompensators, variableTwoWindingsTransformers,
Expand All @@ -76,9 +83,10 @@ public Collection<AmplInputFile> getInputParameters() {
public Collection<AmplOutputFile> getOutputParameters(boolean isConvergenceOk) {
if (isConvergenceOk) {
List<AmplOutputFile> networkModificationsOutputFiles = networkModifications.getOutputFiles();
List<AmplOutputFile> list = new ArrayList<>(networkModificationsOutputFiles.size() + 1);
List<AmplOutputFile> list = new ArrayList<>(networkModificationsOutputFiles.size() + 2);
list.addAll(networkModificationsOutputFiles);
list.add(reactiveSlackOutput);
list.add(voltageProfileOutput);
return list;
}
return List.of();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,16 @@
package com.powsybl.openreac.parameters.output;

import com.powsybl.iidm.modification.*;
import com.powsybl.iidm.modification.tapchanger.AbstractTapPositionModification;
import com.powsybl.iidm.modification.tapchanger.RatioTapPositionModification;
import com.powsybl.iidm.network.Network;
import com.powsybl.iidm.network.*;
import com.powsybl.openreac.parameters.OpenReacAmplIOFiles;
import com.powsybl.openreac.parameters.output.ReactiveSlackOutput.ReactiveSlack;
import org.jgrapht.alg.util.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.*;

/**
* OpenReac user interface to get results information.
Expand All @@ -24,6 +25,7 @@
*/
public class OpenReacResult {

private static final Logger LOGGER = LoggerFactory.getLogger(OpenReacResult.class);
private final OpenReacStatus status;
private final List<ReactiveSlack> reactiveSlacks;
private final Map<String, String> indicators;
Expand All @@ -32,6 +34,8 @@ public class OpenReacResult {
private final List<VscConverterStationModification> vscModifications;
private final List<StaticVarCompensatorModification> svcModifications;
private final List<RatioTapPositionModification> tapPositionModifications;
private final HashMap<String, Pair<Double, Double>> voltageProfile;
private boolean updateNetworkWithVoltages = true;

/**
* @param status the final status of the OpenReac run.
Expand All @@ -48,6 +52,7 @@ public OpenReacResult(OpenReacStatus status, OpenReacAmplIOFiles amplIOFiles, Ma
this.vscModifications = List.copyOf(amplIOFiles.getNetworkModifications().getVscModifications());
this.svcModifications = List.copyOf(amplIOFiles.getNetworkModifications().getSvcModifications());
this.tapPositionModifications = List.copyOf(amplIOFiles.getNetworkModifications().getTapPositionModifications());
this.voltageProfile = new HashMap<>(amplIOFiles.getVoltageProfileOutput().getVoltageProfile());
}

public OpenReacStatus getStatus() {
Expand Down Expand Up @@ -82,7 +87,19 @@ public List<VscConverterStationModification> getVscModifications() {
return vscModifications;
}

public List<NetworkModification> getAllModifs() {
public Map<String, Pair<Double, Double>> getVoltageProfile() {
return voltageProfile;
}

public boolean isUpdateNetworkWithVoltages() {
return updateNetworkWithVoltages;
}

public void setUpdateNetworkWithVoltages(boolean updateNetworkWithVoltages) {
this.updateNetworkWithVoltages = updateNetworkWithVoltages;
}

public List<NetworkModification> getAllNetworkModifications() {
List<NetworkModification> modifs = new ArrayList<>(getGeneratorModifications().size() +
getShuntsModifications().size() +
getSvcModifications().size() +
Expand All @@ -97,8 +114,71 @@ public List<NetworkModification> getAllModifs() {
}

public void applyAllModifications(Network network) {
for (NetworkModification modif : getAllModifs()) {
for (NetworkModification modif : getAllNetworkModifications()) {
modif.apply(network);
}

// update target of ratio tap changers specified as variable by user
getTapPositionModifications().stream()
So-Fras marked this conversation as resolved.
Show resolved Hide resolved
.map(AbstractTapPositionModification::getTransformerId)
.map(network::getTwoWindingsTransformer)
.forEach(transformer -> {
RatioTapChanger ratioTapChanger = transformer.getRatioTapChanger();
if (ratioTapChanger != null) {
Optional<Bus> bus = getRegulatingBus(ratioTapChanger.getRegulationTerminal(), transformer.getId());
bus.ifPresent(b -> {
Pair<Double, Double> busUpdate = voltageProfile.get(b.getId());
if (busUpdate != null) {
ratioTapChanger.setTargetV(busUpdate.getFirst() * b.getVoltageLevel().getNominalV());
} else {
throw new IllegalStateException("Voltage profile not found for bus " + b.getId());
}
});
}
});

// update target of shunts specified as variable by user
getShuntsModifications().stream()
.map(ShuntCompensatorModification::getShuntCompensatorId)
.map(network::getShuntCompensator)
.forEach(shunt -> {
Optional<Bus> bus = getRegulatingBus(shunt.getRegulatingTerminal(), shunt.getId());
bus.ifPresent(b -> {
Pair<Double, Double> busUpdate = voltageProfile.get(b.getId());
if (busUpdate != null) {
shunt.setTargetV(busUpdate.getFirst() * b.getVoltageLevel().getNominalV());
} else {
throw new IllegalStateException("Voltage profile not found for bus " + b.getId());
}
});
});

// update voltages of the buses
if (isUpdateNetworkWithVoltages()) {
for (var busUpdate : voltageProfile.entrySet()) {
Optional.ofNullable(network.getBusView().getBus(busUpdate.getKey())).ifPresentOrElse(
bus -> {
double v = busUpdate.getValue().getFirst();
double angle = busUpdate.getValue().getSecond();
bus.setV(v * bus.getVoltageLevel().getNominalV());
bus.setAngle(Math.toDegrees(angle));
}, () -> {
throw new IllegalStateException("Bus " + busUpdate.getKey() + " not found in network " + network.getId());
});
}
}
}

Optional<Bus> getRegulatingBus(Terminal terminal, String elementId) {
if (terminal == null) {
LOGGER.warn("Regulating terminal of element {} is null.", elementId);
return Optional.empty();
}
Bus bus = terminal.getBusView().getBus();
if (bus == null) {
LOGGER.warn("Bus of regulating terminal of element {} is null.", elementId);
return Optional.empty();
}
return Optional.ofNullable(bus);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/**
* Copyright (c) 2024, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package com.powsybl.openreac.parameters.output;

import com.powsybl.ampl.converter.AmplSubset;
import com.powsybl.commons.util.StringToIntMapper;
import com.powsybl.openreac.parameters.AmplIOUtils;
import org.jgrapht.alg.util.Pair;

import java.util.*;

/**
* @author Pierre Arvy <pierre.arvy at artelys.com>
*/
public class VoltageProfileOutput extends AbstractNoThrowOutput {

private static final String ELEMENT = "voltages";
public static final int EXPECTED_COLS = 5;
private static final int ID_COLUMN_INDEX = 4;
private static final int V_COLUMN_INDEX = 2;
private static final int ANGLE_COLUMN_INDEX = 3;

private final Map<String, Pair<Double, Double>> voltageProfile = new HashMap<>();

public Map<String, Pair<Double, Double>> getVoltageProfile() {
return voltageProfile;
}

@Override
public String getElement() {
return ELEMENT;
}

@Override
public int getExpectedColumns() {
return EXPECTED_COLS;
}

@Override
protected void readLine(String[] tokens, StringToIntMapper<AmplSubset> stringToIntMapper) {
String id = AmplIOUtils.removeQuotes(tokens[ID_COLUMN_INDEX]);
double v = readDouble(tokens[V_COLUMN_INDEX]);
double angle = readDouble(tokens[ANGLE_COLUMN_INDEX]);
voltageProfile.put(id, Pair.of(v, angle));
}

@Override
public boolean throwOnMissingFile() {
triggerErrorState();
return false;
}

}
18 changes: 18 additions & 0 deletions open-reac/src/main/resources/openreac/reactiveopfoutput.run
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,24 @@ close (fileOut);



###############################################################################
#
# Writing results for buses states
#
###############################################################################
if final_status == "OK" then {

let fileOut := "reactiveopf_results_voltages.csv";
printf "#variant;bus;V(pu);theta(rad);id;\n" > (fileOut);
printf {n in BUSCC} "%i;%i;%.3f;%.3f;%s;\n",
1, n, V[n], teta[n], '"' & bus_id[1,n] & '"'
> (fileOut);
close (fileOut);

}



###############################################################################
#
# Writing results for LCC converters
Expand Down
118 changes: 118 additions & 0 deletions open-reac/src/test/java/com/powsybl/openreac/OpenReacResultsTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package com.powsybl.openreac;

import com.powsybl.ieeecdf.converter.IeeeCdfNetworkFactory;
import com.powsybl.iidm.modification.ShuntCompensatorModification;
import com.powsybl.iidm.modification.tapchanger.RatioTapPositionModification;
import com.powsybl.iidm.network.Network;
import com.powsybl.iidm.network.RatioTapChanger;
import com.powsybl.iidm.network.ShuntCompensator;
import com.powsybl.openreac.network.ShuntNetworkFactory;
import com.powsybl.openreac.network.VoltageControlNetworkFactory;
import com.powsybl.openreac.parameters.OpenReacAmplIOFiles;
import com.powsybl.openreac.parameters.input.OpenReacParameters;
import com.powsybl.openreac.parameters.output.OpenReacResult;
import com.powsybl.openreac.parameters.output.OpenReacStatus;
import org.junit.jupiter.api.Test;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;

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

class OpenReacResultsTest {

@Test
void testTransformerTargetVUpdateWithoutVoltageResult() throws IOException {
Network network = VoltageControlNetworkFactory.createNetworkWithT2wt();
String t2wtId = "T2wT";
RatioTapChanger rtc = network.getTwoWindingsTransformer(t2wtId).getRatioTapChanger()
.setTargetDeadband(0)
.setRegulating(true);

// add transformer as variable for target V update
OpenReacAmplIOFiles io = getIOWithMockVoltageProfile(network);
io.getNetworkModifications().getTapPositionModifications().add(new RatioTapPositionModification(t2wtId, 0));

OpenReacResult results = new OpenReacResult(OpenReacStatus.OK, io, new HashMap<>());
IllegalStateException e = assertThrows(IllegalStateException.class, () -> results.applyAllModifications(network));
assertEquals("Voltage profile not found for bus " + rtc.getRegulationTerminal().getBusView().getBus().getId(), e.getMessage());
}

@Test
void testTransformerTargetVUpdateWithoutRegulationBus() throws IOException {
Network network = VoltageControlNetworkFactory.createNetworkWithT2wt();
String t2wtId = "T2wT";
RatioTapChanger rtc = network.getTwoWindingsTransformer(t2wtId).getRatioTapChanger()
.setTargetDeadband(0)
.setRegulating(true);
rtc.getRegulationTerminal().disconnect();

// add transformer as variable for target V update
OpenReacAmplIOFiles io = getIOWithMockVoltageProfile(network);
io.getNetworkModifications().getTapPositionModifications().add(new RatioTapPositionModification(t2wtId, 0));

// apply results without warm start (to avoid exception)
OpenReacResult results = new OpenReacResult(OpenReacStatus.OK, io, new HashMap<>());
results.setUpdateNetworkWithVoltages(false);
results.applyAllModifications(network);

// target V is not updated
assertEquals(33, rtc.getTargetV());
}

@Test
void testShuntTargetVUpdateWithoutVoltageResult() throws IOException {
Network network = ShuntNetworkFactory.create();
ShuntCompensator shunt = network.getShuntCompensator("SHUNT");
String regulatedBusId = shunt.getRegulatingTerminal().getBusView().getBus().getId();

OpenReacAmplIOFiles io = getIOWithMockVoltageProfile(network);
io.getNetworkModifications().getShuntModifications().add(new ShuntCompensatorModification("SHUNT", true, 0));

OpenReacResult results = new OpenReacResult(OpenReacStatus.OK, io, new HashMap<>());
IllegalStateException e = assertThrows(IllegalStateException.class, () -> results.applyAllModifications(network));
assertEquals("Voltage profile not found for bus " + regulatedBusId, e.getMessage());
}

@Test
void testShuntUpdateWithoutRegulationBus() throws IOException {
Network network = ShuntNetworkFactory.create();
ShuntCompensator shunt = network.getShuntCompensator("SHUNT");
shunt.getRegulatingTerminal().disconnect();

OpenReacAmplIOFiles io = getIOWithMockVoltageProfile(network);
io.getNetworkModifications().getShuntModifications().add(new ShuntCompensatorModification("SHUNT", null, 0));

// apply results without warm start
OpenReacResult results = new OpenReacResult(OpenReacStatus.OK, io, new HashMap<>());
results.setUpdateNetworkWithVoltages(false);
results.applyAllModifications(network);

// target V not updated
assertEquals(393, shunt.getTargetV());
}

@Test
void testWrongVoltageResult() throws IOException {
Network network = IeeeCdfNetworkFactory.create14();
OpenReacAmplIOFiles io = getIOWithMockVoltageProfile(network);
String idBusNotFound = io.getVoltageProfileOutput().getVoltageProfile().keySet().iterator().next();
OpenReacResult results = new OpenReacResult(OpenReacStatus.OK, io, new HashMap<>());
IllegalStateException e = assertThrows(IllegalStateException.class, () -> results.applyAllModifications(network));
assertEquals("Bus " + idBusNotFound + " not found in network " + network.getId(), e.getMessage());
}

private OpenReacAmplIOFiles getIOWithMockVoltageProfile(Network network) throws IOException {
OpenReacAmplIOFiles io = new OpenReacAmplIOFiles(new OpenReacParameters(), network, true);
try (InputStream input = getClass().getResourceAsStream("/mock_outputs/reactiveopf_results_voltages.csv");
InputStreamReader in = new InputStreamReader(input);
BufferedReader reader = new BufferedReader(in)) {
io.getVoltageProfileOutput().read(reader, null);
}
return io;
}
}
Loading
Loading