Skip to content

Commit

Permalink
Distinguish regulation depending on whether it is active
Browse files Browse the repository at this point in the history
Signed-off-by: Coline PILOQUET <coline.piloquet@rte-france.com>
  • Loading branch information
colinepiloquet committed Feb 28, 2025
1 parent 3d9beb3 commit 9b59035
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 15 deletions.
7 changes: 6 additions & 1 deletion docs/grid_exchange_formats/ucte/export.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,12 @@ the generators connected to the associated bus:
3 if the bus is the slack node and 0 (PQ node) by default.
- The voltage reference of the UCTE node is obtained from the `TargetV` of the generators connected to the bus.
If multiple generators are regulating voltage with a different `TargetV`, then the `TargetV` that is the closest to the
`nominalV` of the `VoltageLevel` is kept.
`nominalV` of the `VoltageLevel` is selected. If some generators are regulating remotely or have a `TargetV` without active regulation,
the `TargetV` is determined the following priority order:
1. TargetV of generators regulating locally
2. TargetV of generators regulating remotely
3. TargetV of generators with local deactivated regulation
4. TargetV of generators with remote deactivated regulation
- The active power generation of the UCTE node is the negated sum of the `TargetP` of every connected generator that are not `NaN`.
- The reactive power generation of the UCTE node is the negated sum of the `TargetQ` of every connected generator that are not `NaN`.
- The minimum permissible generation in active power of the UCTE node is the sum of the `minP` of every connected generator
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,12 @@ private GeneratorUcteExport() {
public static void convertGenerators(UcteNode ucteNode, Bus bus) {
double activePowerGeneration = 0;
double reactivePowerGeneration = 0;
List<Double> localVoltageReferences = new ArrayList<>();
List<Double> remoteVoltageReferences = new ArrayList<>();

List<Double> localActiveVoltageReferences = new ArrayList<>();
List<Double> remoteActiveVoltageReferences = new ArrayList<>();
List<Double> localInactiveVoltageReferences = new ArrayList<>();
List<Double> remoteInactiveVoltageReferences = new ArrayList<>();

List<Double> minPs = new ArrayList<>();
List<Double> maxPs = new ArrayList<>();
List<Double> minQs = new ArrayList<>();
Expand All @@ -54,24 +58,19 @@ public static void convertGenerators(UcteNode ucteNode, Bus bus) {
reactivePowerGeneration -= generator.getTargetQ();
}
if (!Double.isNaN(generator.getTargetV())) {
if (generator.getRegulatingTerminal().getConnectable().getId().equals(generator.getId())) {
localVoltageReferences.add(generator.getTargetV());
} else {
remoteVoltageReferences.add(getTargetV(generator));
categorizeVoltageReference(generator, localActiveVoltageReferences, remoteActiveVoltageReferences, localInactiveVoltageReferences, remoteInactiveVoltageReferences);
if (generator.isVoltageRegulatorOn()) {
nodeType = UcteNodeTypeCode.PU; // If one of the generators regulates voltage, then the node is a PU node.
}
}
if (generator.isVoltageRegulatorOn()) {
// If one of the generators regulates voltage, then the node is a PU node.
nodeType = UcteNodeTypeCode.PU;
}
minPs.add(generator.getMinP());
maxPs.add(generator.getMaxP());
powerPlantTypes.add(energySourceToUctePowerPlantType(generator));
}

ucteNode.setActivePowerGeneration(activePowerGeneration);
ucteNode.setReactivePowerGeneration(reactivePowerGeneration);
ucteNode.setVoltageReference(getVoltageReference(localVoltageReferences, remoteVoltageReferences, bus.getVoltageLevel().getNominalV()));
ucteNode.setVoltageReference(getVoltageReference(localActiveVoltageReferences, remoteActiveVoltageReferences, localInactiveVoltageReferences, remoteInactiveVoltageReferences, bus.getVoltageLevel().getNominalV()));
ucteNode.setPowerPlantType(getUctePowerPlantType(powerPlantTypes, bus));
ucteNode.setTypeCode(nodeType);
// for minP, maxP, minQ, maxQ, sum the values on each generator unless it is equal to Double.MAX_VALUE or DEFAULT_POWER_LIMIT (equivalent to undefined)
Expand All @@ -83,6 +82,25 @@ public static void convertGenerators(UcteNode ucteNode, Bus bus) {
ucteNode.setMaximumPermissibleReactivePowerGeneration(-computeMaxPower(maxQs));
}

private static void categorizeVoltageReference(Generator generator, List<Double> localActiveVoltageReferences, List<Double> remoteActiveVoltageReferences, List<Double> localInactiveVoltageReferences, List<Double> remoteInactiveVoltageReferences) {
double targetV = getTargetV(generator);
boolean isLocalRegulation = generator.getId().equals(generator.getRegulatingTerminal().getConnectable().getId());

if (isLocalRegulation) {
if (generator.isVoltageRegulatorOn()) {
localActiveVoltageReferences.add(targetV);
} else {
localInactiveVoltageReferences.add(targetV);
}
} else {
if (generator.isVoltageRegulatorOn()) {
remoteActiveVoltageReferences.add(targetV);
} else {
remoteInactiveVoltageReferences.add(targetV);
}
}
}

private static double computeMaxPower(List<Double> powers) {
return powers.isEmpty() || powers.contains(Double.MAX_VALUE) || powers.contains((double) DEFAULT_POWER_LIMIT) ? Double.NaN : powers.stream().reduce(Double::sum).orElse(Double.NaN);
}
Expand All @@ -106,9 +124,18 @@ private static UctePowerPlantType getUctePowerPlantType(Set<UctePowerPlantType>
return UctePowerPlantType.F;
}

private static double getVoltageReference(List<Double> localVoltageReferences, List<Double> remoteVoltageReferences, double nominalV) {
return findClosestVoltageToNominalV(localVoltageReferences, nominalV)
.orElseGet(() -> findClosestVoltageToNominalV(remoteVoltageReferences, nominalV).orElse(Double.NaN));
// Voltage reference depends on the generator connected to the bus, and if the regulation is remote or local
// Priority is given to:
// 1. TargetV of generators regulating locally
// 2. TargetV of generators regulating remotely
// 3. TargetV of generators with local deactivated regulation
// 4. TargetV of generators with remote deactivated regulation
// In any case, the value closest to the nominalV of the voltage level is kept.
private static double getVoltageReference(List<Double> localActiveVoltageReferences, List<Double> remoteActiveVoltageReferences, List<Double> localInactiveVoltageReferences, List<Double> remoteInactiveVoltageReferences, double nominalV) {
return findClosestVoltageToNominalV(localActiveVoltageReferences, nominalV)
.orElseGet(() -> findClosestVoltageToNominalV(remoteActiveVoltageReferences, nominalV)
.orElseGet(() -> findClosestVoltageToNominalV(localInactiveVoltageReferences, nominalV)
.orElseGet(() -> findClosestVoltageToNominalV(remoteInactiveVoltageReferences, nominalV).orElse(Double.NaN))));
}

private static Optional<Double> findClosestVoltageToNominalV(List<Double> voltageReferences, double nominalV) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,19 @@ void testRemoteAndLocalRegulatingGenerator() throws IOException {
testExporter(network, "/eurostag.uct", p);
}

@Test
void testActiveRemoteAndInactiveLocalRegulatingGenerator() throws IOException {
// Create a second generator and make it regulate remotely after the transformer with a different targetV
createGen2AndSplitGeneration();
network.getGenerator("GEN2").setRegulatingTerminal(network.getTwoWindingsTransformer("NGEN_NHV1").getTerminal2()).setTargetV(24.5*380/24);
// The local generator has inactive regulation
network.getGenerator("GEN").setVoltageRegulatorOn(false).setTargetV(25);
Properties p = new Properties();
p.put(UcteExporter.NAMING_STRATEGY, "Counter");
// TargetV exported will be the one of the local generator GEN and not the targetV of the remote generator
testExporter(network, "/eurostag.uct", p);
}

private void createGen2AndSplitGeneration() {
// Splits generation on two generators
network.getVoltageLevel("VLGEN").newGenerator()
Expand Down

0 comments on commit 9b59035

Please sign in to comment.