com.powsybl.metrix.mapping.NetworkPointWriter Maven / Gradle / Ivy
/*
* Copyright (c) 2020, 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/.
* SPDX-License-Identifier: MPL-2.0
*/
package com.powsybl.metrix.mapping;
import com.powsybl.commons.datasource.DataSource;
import com.powsybl.commons.datasource.MemDataSource;
import com.powsybl.iidm.network.*;
import com.powsybl.iidm.network.extensions.HvdcAngleDroopActivePowerControl;
import com.powsybl.iidm.network.extensions.HvdcOperatorActivePowerRange;
import com.powsybl.iidm.network.extensions.LoadDetail;
import com.powsybl.iidm.network.extensions.LoadDetailAdder;
import com.powsybl.iidm.serde.ExportOptions;
import com.powsybl.iidm.serde.NetworkSerDe;
import com.powsybl.metrix.mapping.common.MetrixIidmConfiguration;
import com.powsybl.timeseries.TimeSeriesIndex;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UncheckedIOException;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import static com.powsybl.metrix.mapping.TimeSeriesMapper.*;
/**
* @author Paul Bui-Quang {@literal }
*/
public class NetworkPointWriter extends DefaultTimeSeriesMapperObserver {
public static final int OFF_VALUE = 0;
private static final class GeneratorInitialValues {
private final double minP;
private final double maxP;
private GeneratorInitialValues(double minP, double maxP) {
this.minP = minP;
this.maxP = maxP;
}
}
static final class HvdcLineInitialValues {
private final double maxP;
private final boolean isActivePowerRange;
private final float oprFromCS1toCS2;
private final float oprFromCS2toCS1;
private HvdcLineInitialValues(double maxP, boolean isActivePowerRange, float oprFromCS1toCS2, float oprFromCS2toCS1) {
this.maxP = maxP;
this.isActivePowerRange = isActivePowerRange;
this.oprFromCS1toCS2 = oprFromCS1toCS2;
this.oprFromCS2toCS1 = oprFromCS2toCS1;
}
}
private final Map generatorToInitialValues = new HashMap<>();
private final Map hvdcLineToInitialValues = new HashMap<>();
private static final DateTimeFormatter FMT = DateTimeFormatter.ofPattern("yyyyMMdd_HHmm");
private final Network network;
private final DataSource dataSource;
private int version = -1;
public NetworkPointWriter(Network network, DataSource dataSource) {
this.network = Objects.requireNonNull(network);
this.dataSource = Objects.requireNonNull(dataSource);
}
private static String getStateId(int point, TimeSeriesIndex index) {
return "point-" + index.getInstantAt(point);
}
private void mapToEquipmentVariable(Identifiable> identifiable, EquipmentVariable variable, double equipmentValue) {
if (Double.isNaN(equipmentValue)) {
return;
}
if (identifiable instanceof Generator) {
mapToGeneratorVariable(identifiable, variable, equipmentValue);
} else if (identifiable instanceof Load) {
mapToLoadVariable(identifiable, variable, equipmentValue);
} else if (identifiable instanceof HvdcLine) {
mapToHvdcLineVariable(identifiable, variable, equipmentValue);
} else if (identifiable instanceof Switch) {
mapToSwitchVariable(identifiable, equipmentValue);
} else if (identifiable instanceof TwoWindingsTransformer) {
mapToTwoWindingsTransformerVariable(identifiable, variable, equipmentValue);
} else if (identifiable instanceof LccConverterStation) {
mapToLccConverterStationVariable(identifiable, variable, (float) equipmentValue);
} else if (identifiable instanceof VscConverterStation) {
mapToVscConverterStationVariable(identifiable, variable, equipmentValue);
} else if (identifiable instanceof Line) {
mapToLineVariable(identifiable, variable, equipmentValue);
} else {
throw new AssertionError(String.format("Unknown equipment type %s", identifiable.getClass().getName()));
}
}
private void mapToLineVariable(Identifiable> identifiable, EquipmentVariable variable, double equipmentValue) {
Line line = network.getLine(identifiable.getId());
if (variable == EquipmentVariable.DISCONNECTED && Math.abs(equipmentValue - DISCONNECTED_VALUE) > EPSILON_COMPARISON) {
line.getTerminal1().disconnect();
line.getTerminal2().disconnect();
}
}
private void mapToSwitchVariable(Identifiable> identifiable, double equipmentValue) {
Switch breaker = network.getSwitch(identifiable.getId());
breaker.setOpen(Math.abs(equipmentValue - TimeSeriesMapper.SWITCH_OPEN) < EPSILON_COMPARISON);
}
private void mapToLccConverterStationVariable(Identifiable> identifiable, EquipmentVariable variable, float equipmentValue) {
LccConverterStation converter = network.getLccConverterStation(identifiable.getId());
if (variable == EquipmentVariable.POWER_FACTOR) {
converter.setPowerFactor(equipmentValue);
}
}
private void mapToVscConverterStationVariable(Identifiable> identifiable, EquipmentVariable variable, double equipmentValue) {
VscConverterStation converter = network.getVscConverterStation(identifiable.getId());
switch (variable) {
case VOLTAGE_REGULATOR_ON -> converter.setVoltageRegulatorOn(Math.abs(equipmentValue - OFF_VALUE) > EPSILON_COMPARISON);
case VOLTAGE_SETPOINT -> converter.setVoltageSetpoint(equipmentValue);
case REACTIVE_POWER_SETPOINT -> converter.setReactivePowerSetpoint(equipmentValue);
default -> {
// Do nothing
}
}
}
private void mapToTwoWindingsTransformerVariable(Identifiable> identifiable, EquipmentVariable variable, double equipmentValue) {
TwoWindingsTransformer transformer = network.getTwoWindingsTransformer(identifiable.getId());
// mapToTransformers variables
switch (variable) {
case RATED_U1 -> transformer.setRatedU1(equipmentValue);
case RATED_U2 -> transformer.setRatedU2(equipmentValue);
// mapToPhaseTapChangers variables
case PHASE_TAP_POSITION -> transformer.getPhaseTapChanger().setTapPosition((int) equipmentValue);
case PHASE_REGULATING -> transformer.getPhaseTapChanger().setRegulating(Math.abs(equipmentValue - OFF_VALUE) > EPSILON_COMPARISON);
case TARGET_DEADBAND -> transformer.getPhaseTapChanger().setTargetDeadband(equipmentValue);
case REGULATION_MODE -> selectRegulationMode(equipmentValue, transformer);
// mapToRatioTapChanger variables
case RATIO_TAP_POSITION -> transformer.getRatioTapChanger().setTapPosition((int) equipmentValue);
case TARGET_V -> transformer.getRatioTapChanger().setTargetV(equipmentValue);
case LOAD_TAP_CHANGING_CAPABILITIES -> transformer.getRatioTapChanger().setLoadTapChangingCapabilities(Math.abs(equipmentValue - OFF_VALUE) > EPSILON_COMPARISON);
case RATIO_REGULATING -> transformer.getRatioTapChanger().setRegulating(Math.abs(equipmentValue - OFF_VALUE) > EPSILON_COMPARISON);
case DISCONNECTED -> {
if (Math.abs(equipmentValue - DISCONNECTED_VALUE) > EPSILON_COMPARISON) {
transformer.getTerminal1().disconnect();
transformer.getTerminal2().disconnect();
}
}
default -> {
// Do nothing
}
}
}
private void selectRegulationMode(double equipmentValue, TwoWindingsTransformer transformer) {
PhaseTapChanger.RegulationMode mode = switch ((int) equipmentValue) {
case 0 -> PhaseTapChanger.RegulationMode.CURRENT_LIMITER;
case 1 -> PhaseTapChanger.RegulationMode.ACTIVE_POWER_CONTROL;
case 2 -> PhaseTapChanger.RegulationMode.FIXED_TAP;
default -> throw new AssertionError("Unsupported regulation mode " + equipmentValue);
};
transformer.getPhaseTapChanger().setRegulationMode(mode);
}
private void mapToHvdcLineVariable(Identifiable> identifiable, EquipmentVariable variable, double equipmentValue) {
HvdcLine hvdcLine = network.getHvdcLine(identifiable.getId());
HvdcOperatorActivePowerRange hvdcRange = addActivePowerRangeExtension(hvdcLine);
switch (variable) {
case ACTIVE_POWER_SETPOINT -> {
HvdcAngleDroopActivePowerControl activePowerControl = TimeSeriesMapper.getActivePowerControl(hvdcLine);
if (activePowerControl != null) {
activePowerControl.setP0((float) equipmentValue);
} else if (equipmentValue >= 0) {
hvdcLine.setConvertersMode(HvdcLine.ConvertersMode.SIDE_1_RECTIFIER_SIDE_2_INVERTER);
hvdcLine.setActivePowerSetpoint((float) equipmentValue);
} else {
hvdcLine.setConvertersMode(HvdcLine.ConvertersMode.SIDE_1_INVERTER_SIDE_2_RECTIFIER);
hvdcLine.setActivePowerSetpoint((float) -equipmentValue);
}
}
case MIN_P -> {
hvdcRange.setOprFromCS2toCS1((float) Math.abs(equipmentValue));
calculateMaxP(equipmentValue, hvdcLine, hvdcRange.getOprFromCS1toCS2());
}
case MAX_P -> {
hvdcRange.setOprFromCS1toCS2((float) Math.abs(equipmentValue));
calculateMaxP(equipmentValue, hvdcLine, hvdcRange.getOprFromCS2toCS1());
}
case NOMINAL_V -> hvdcLine.setNominalV(equipmentValue);
default -> {
// Do nothing
}
}
}
private void calculateMaxP(double equipmentValue, HvdcLine hvdcLine, float hvdcRange) {
double maxP = Math.max(Math.abs(equipmentValue), hvdcRange);
if (hvdcLine.getMaxP() < maxP) {
hvdcLine.setMaxP(maxP);
}
}
private void mapToLoadVariable(Identifiable> identifiable, EquipmentVariable variable, double equipmentValue) {
Load load = network.getLoad(identifiable.getId());
LoadDetail loadDetail = load.getExtension(LoadDetail.class);
switch (variable) {
case P0 -> {
if (loadDetail != null) {
loadDetail.setFixedActivePower(0);
loadDetail.setVariableActivePower(equipmentValue);
}
load.setP0(equipmentValue);
}
case Q0 -> {
if (loadDetail != null) {
loadDetail.setFixedReactivePower(0);
loadDetail.setVariableReactivePower(equipmentValue);
}
load.setQ0(equipmentValue);
}
case FIXED_ACTIVE_POWER -> {
loadDetail = newLoadDetailExtension(load, loadDetail);
loadDetail.setFixedActivePower(equipmentValue);
load.setP0(loadDetail.getFixedActivePower() + loadDetail.getVariableActivePower());
}
case VARIABLE_ACTIVE_POWER -> {
loadDetail = newLoadDetailExtension(load, loadDetail);
loadDetail.setVariableActivePower(equipmentValue);
load.setP0(loadDetail.getFixedActivePower() + loadDetail.getVariableActivePower());
}
case FIXED_REACTIVE_POWER -> {
loadDetail = newLoadDetailExtension(load, loadDetail);
loadDetail.setFixedReactivePower(equipmentValue);
load.setQ0(loadDetail.getFixedReactivePower() + loadDetail.getVariableReactivePower());
}
case VARIABLE_REACTIVE_POWER -> {
loadDetail = newLoadDetailExtension(load, loadDetail);
loadDetail.setVariableReactivePower(equipmentValue);
load.setQ0(loadDetail.getFixedReactivePower() + loadDetail.getVariableReactivePower());
}
default -> {
// Do nothing
}
}
}
private LoadDetail newLoadDetailExtension(Load load, LoadDetail loadDetail) {
if (loadDetail == null) {
load.newExtension(LoadDetailAdder.class)
.withFixedActivePower(0d)
.withFixedReactivePower(0d)
.withVariableActivePower(0d)
.withVariableReactivePower(0d)
.add();
return load.getExtension(LoadDetail.class);
}
return loadDetail;
}
private void mapToGeneratorVariable(Identifiable> identifiable, EquipmentVariable variable, double equipmentValue) {
Generator generator = network.getGenerator(identifiable.getId());
switch (variable) {
case TARGET_P -> generator.setTargetP(equipmentValue);
case TARGET_Q -> generator.setTargetQ(equipmentValue);
case MIN_P -> generator.setMinP(equipmentValue);
case MAX_P -> generator.setMaxP(equipmentValue);
case VOLTAGE_REGULATOR_ON -> generator.setVoltageRegulatorOn(Math.abs(equipmentValue - OFF_VALUE) > EPSILON_COMPARISON);
case TARGET_V -> generator.setTargetV(equipmentValue);
case DISCONNECTED -> {
if (Math.abs(equipmentValue - OFF_VALUE) > EPSILON_COMPARISON) {
generator.getTerminal().disconnect();
}
}
default -> {
// Do nothing
}
}
}
public static String getFileName(Network network, int version, int point, TimeSeriesIndex index) {
return network.getId() + "_" + version + "_" + FMT.format(index.getInstantAt(point).atZone(ZoneId.of("UTC")));
}
private String getSuffix(int point, TimeSeriesIndex index) {
return getSuffix(version, point, index);
}
public static String getSuffix(int version, int point, TimeSeriesIndex index) {
return "_" + version + "_" + FMT.format(index.getInstantAt(point).atZone(ZoneId.of("UTC")));
}
private void storeInitialStateValues() {
network.getGenerators().forEach(g -> generatorToInitialValues.put(g.getId(),
new GeneratorInitialValues(
g.getMinP(),
g.getMaxP())));
network.getHvdcLines().forEach(l -> hvdcLineToInitialValues.put(l.getId(),
new HvdcLineInitialValues(
l.getMaxP(),
l.getExtension(HvdcOperatorActivePowerRange.class) != null,
l.getExtension(HvdcOperatorActivePowerRange.class) != null ? l.getExtension(HvdcOperatorActivePowerRange.class).getOprFromCS1toCS2() : (float) l.getMaxP(),
l.getExtension(HvdcOperatorActivePowerRange.class) != null ? l.getExtension(HvdcOperatorActivePowerRange.class).getOprFromCS2toCS1() : (float) l.getMaxP()
)));
}
private void restoreInitialStateValues() {
for (Map.Entry e : generatorToInitialValues.entrySet()) {
Generator g = network.getGenerator(e.getKey());
GeneratorInitialValues initialValues = e.getValue();
g.setMinP(initialValues.minP);
g.setMaxP(initialValues.maxP);
}
for (Map.Entry e : hvdcLineToInitialValues.entrySet()) {
HvdcLine l = network.getHvdcLine(e.getKey());
HvdcLineInitialValues initialValues = e.getValue();
l.setMaxP(initialValues.maxP);
if (initialValues.isActivePowerRange) {
HvdcOperatorActivePowerRange activePowerRange = l.getExtension(HvdcOperatorActivePowerRange.class);
activePowerRange.setOprFromCS1toCS2(initialValues.oprFromCS1toCS2);
activePowerRange.setOprFromCS2toCS1(initialValues.oprFromCS2toCS1);
} else {
l.removeExtension(HvdcOperatorActivePowerRange.class);
}
}
}
@Override
public void start() {
//Nothing to do
}
@Override
public void versionStart(int version) {
this.version = version;
network.getVariantManager().setWorkingVariant(VariantManagerConstants.INITIAL_VARIANT_ID);
}
@Override
public void timeSeriesMappingStart(int point, TimeSeriesIndex index) {
if (point != TimeSeriesMapper.CONSTANT_VARIANT_ID) {
String stateId = getStateId(point, index);
network.getVariantManager().cloneVariant(VariantManagerConstants.INITIAL_VARIANT_ID, stateId);
network.getVariantManager().setWorkingVariant(stateId);
}
}
@Override
public void timeSeriesMappingEnd(int point, TimeSeriesIndex index, double balance) {
if (point == TimeSeriesMapper.CONSTANT_VARIANT_ID) {
storeInitialStateValues();
return;
}
// Write variant
String suffix = getSuffix(point, index);
if (dataSource instanceof MemDataSource) {
// for the moment, it is not possible with PowSyBl to import with a suffix different from null ...
suffix = null;
}
try (OutputStream os = new BufferedOutputStream(dataSource.newOutputStream(suffix, "xiidm", false))) {
ExportOptions exportOptions = new ExportOptions();
exportOptions.setVersion(MetrixIidmConfiguration.load().getNetworkExportVersion());
NetworkSerDe.write(network, exportOptions, os);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
// Remove variant
network.getVariantManager().removeVariant(getStateId(point, index));
network.getVariantManager().setWorkingVariant(VariantManagerConstants.INITIAL_VARIANT_ID);
// Return to initial values for attributes not depending on the variant
restoreInitialStateValues();
}
@Override
public void timeSeriesMappedToEquipment(int point, String timeSeriesName, Identifiable> identifiable, MappingVariable variable, double equipmentValue) {
if (variable instanceof EquipmentVariable equipmentVariable) {
mapToEquipmentVariable(identifiable, equipmentVariable, equipmentValue);
}
}
@Override
public void versionEnd(int version) {
this.version = -1;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy