com.powsybl.matpower.converter.MatpowerImporter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of powsybl-matpower-converter Show documentation
Show all versions of powsybl-matpower-converter Show documentation
MATPOWER Format to IIDM converter
/**
* 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.matpower.converter;
import com.google.auto.service.AutoService;
import com.google.common.io.ByteStreams;
import com.powsybl.commons.PowsyblException;
import com.powsybl.commons.datasource.DataSource;
import com.powsybl.commons.datasource.ReadOnlyDataSource;
import com.powsybl.commons.parameters.ConfiguredParameter;
import com.powsybl.commons.parameters.Parameter;
import com.powsybl.commons.parameters.ParameterDefaultValueConfig;
import com.powsybl.commons.parameters.ParameterType;
import com.powsybl.iidm.network.Importer;
import com.powsybl.iidm.network.*;
import com.powsybl.iidm.network.extensions.SlackTerminal;
import com.powsybl.iidm.network.util.ContainersMapping;
import com.powsybl.matpower.model.*;
import org.apache.commons.math3.complex.Complex;
import org.jgrapht.alg.util.Pair;
import java.time.ZonedDateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UncheckedIOException;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* @author Christian Biasuzzi {@literal }
*/
@AutoService(Importer.class)
public class MatpowerImporter implements Importer {
private static final Logger LOGGER = LoggerFactory.getLogger(MatpowerImporter.class);
private static final String BUS_PREFIX = "BUS";
private static final String GENERATOR_PREFIX = "GEN";
private static final String LINE_PREFIX = "LINE";
private static final String LOAD_PREFIX = "LOAD";
private static final String SHUNT_PREFIX = "SHUNT";
private static final String SUBSTATION_PREFIX = "SUB";
private static final String TRANSFORMER_PREFIX = "TWT";
private static final String VOLTAGE_LEVEL_PREFIX = "VL";
private static final String CONVERTER_STATION_1_PREFIX = "CS1";
private static final String CONVERTER_STATION_2_PREFIX = "CS2";
private static final String HVDC_LINE_PREFIX = "HL";
private static final Parameter IGNORE_BASE_VOLTAGE_PARAMETER = new Parameter("matpower.import.ignore-base-voltage",
ParameterType.BOOLEAN,
"Ignore base voltage specified in the file",
Boolean.TRUE);
private static final class Context {
private final double baseMva; // base apparent power
private final boolean ignoreBaseMva;
private final List slackBuses = new ArrayList<>();
private Context(double baseMva, boolean ignoreBaseMva) {
this.baseMva = baseMva;
this.ignoreBaseMva = ignoreBaseMva;
}
private boolean isIgnoreBaseMva() {
return ignoreBaseMva;
}
private double getBaseMva() {
return baseMva;
}
private List getSlackBuses() {
return slackBuses;
}
}
private static boolean isLine(MatpowerModel model, MBranch branch) {
if (branch.getPhaseShiftAngle() != 0) {
return false;
}
if (branch.getRatio() == 0) {
return true;
}
MBus from = model.getBusByNum(branch.getFrom());
MBus to = model.getBusByNum(branch.getTo());
return branch.getRatio() == 1 && from.getBaseVoltage() == to.getBaseVoltage();
}
private static boolean isTransformer(MatpowerModel model, MBranch branch) {
return !isLine(model, branch);
}
private static String getId(String prefix, int num) {
return prefix + "-" + num;
}
private static String getId(String prefix, int from, int to) {
return prefix + "-" + from + "-" + to;
}
private static void createBuses(MatpowerModel model, ContainersMapping containerMapping, Network network, Context context) {
Map> voltageLimitsByVoltageLevelId = new HashMap<>();
for (MBus mBus : model.getBuses()) {
String voltageLevelId = containerMapping.getVoltageLevelId(mBus.getNumber());
String substationId = containerMapping.getSubstationId(voltageLevelId);
// create substation
Substation substation = createSubstation(network, substationId);
// create voltage level
VoltageLevel voltageLevel = createVoltageLevel(mBus, voltageLevelId, substation, network, context);
// create bus
Bus bus = createBus(mBus, voltageLevel);
if (mBus.getType() == MBus.Type.REF) {
context.getSlackBuses().add(bus);
}
// create voltage limits
createVoltageLimits(mBus, voltageLevel, voltageLimitsByVoltageLevelId);
// create load
createLoad(mBus, voltageLevel);
// create shunt compensator
createShuntCompensator(mBus, voltageLevel, context);
//create generators
createGenerators(model, mBus, voltageLevel);
}
// set voltage limits
setVoltageLimits(voltageLimitsByVoltageLevelId, network);
}
private static void setVoltageLimits(Map> voltageLimitsByVoltageLevelId, Network network) {
for (var entry : voltageLimitsByVoltageLevelId.entrySet()) {
String voltageLevelId = entry.getKey();
double lowVoltageLimit = entry.getValue().getFirst();
double highVoltageLimit = entry.getValue().getSecond();
VoltageLevel voltageLevel = network.getVoltageLevel(voltageLevelId);
if (!Double.isNaN(lowVoltageLimit) && !Double.isNaN(highVoltageLimit)) {
if (highVoltageLimit >= lowVoltageLimit) {
voltageLevel.setLowVoltageLimit(lowVoltageLimit)
.setHighVoltageLimit(highVoltageLimit);
} else {
LOGGER.warn("Invalid voltage limits [{}, {}] for voltage level {}",
lowVoltageLimit, highVoltageLimit, voltageLevelId);
voltageLevel.setLowVoltageLimit(highVoltageLimit)
.setHighVoltageLimit(lowVoltageLimit);
}
} else {
if (!Double.isNaN(lowVoltageLimit)) {
voltageLevel.setLowVoltageLimit(lowVoltageLimit);
}
if (!Double.isNaN(highVoltageLimit)) {
voltageLevel.setHighVoltageLimit(highVoltageLimit);
}
}
}
}
private static void createVoltageLimits(MBus mBus, VoltageLevel voltageLevel, Map> voltageLimitsByVoltageLevelId) {
// as in IIDM, we only have one min and one max voltage level by voltage level we keep only the most severe ones
Pair voltageLimits = voltageLimitsByVoltageLevelId.computeIfAbsent(voltageLevel.getId(), k -> Pair.of(Double.NaN, Double.NaN));
if (mBus.getMinimumVoltageMagnitude() != 0) {
double lowVoltageLimit = mBus.getMinimumVoltageMagnitude() * voltageLevel.getNominalV();
if (Double.isNaN(voltageLimits.getFirst()) || lowVoltageLimit > voltageLimits.getFirst()) {
voltageLimits.setFirst(lowVoltageLimit);
}
}
if (mBus.getMaximumVoltageMagnitude() != 0) {
double highVoltageLimit = mBus.getMaximumVoltageMagnitude() * voltageLevel.getNominalV();
if (Double.isNaN(voltageLimits.getSecond()) || highVoltageLimit < voltageLimits.getSecond()) {
voltageLimits.setSecond(highVoltageLimit);
}
}
}
private static void createGenerators(MatpowerModel model, MBus mBus, VoltageLevel voltageLevel) {
for (MGen mGen : model.getGeneratorsByBusNum(mBus.getNumber())) {
String busId = getId(BUS_PREFIX, mGen.getNumber());
String genId = getId(GENERATOR_PREFIX, mGen.getNumber());
Generator generator = voltageLevel.newGenerator()
.setId(genId)
.setEnsureIdUnicity(true)
.setConnectableBus(busId)
.setBus(isInService(mGen) ? busId : null)
.setTargetV(mGen.getVoltageMagnitudeSetpoint() * voltageLevel.getNominalV())
.setTargetP(mGen.getRealPowerOutput())
.setTargetQ(mGen.getReactivePowerOutput())
.setVoltageRegulatorOn(mGen.getVoltageMagnitudeSetpoint() != 0)
.setMaxP(mGen.getMaximumRealPowerOutput())
.setMinP(mGen.getMinimumRealPowerOutput())
.setRatedS(mGen.getTotalMbase() != 0 ? mGen.getTotalMbase() : Double.NaN)
.add();
if (mGen.getPc1() != 0 || mGen.getPc2() != 0) {
generator.newReactiveCapabilityCurve()
.beginPoint()
.setP(mGen.getPc1())
.setMaxQ(mGen.getQc1Max())
.setMinQ(mGen.getQc1Min())
.endPoint()
.beginPoint()
.setP(mGen.getPc2())
.setMaxQ(mGen.getQc2Max())
.setMinQ(mGen.getQc2Min())
.endPoint()
.add();
} else {
generator.newMinMaxReactiveLimits()
.setMinQ(mGen.getMinimumReactivePowerOutput())
.setMaxQ(mGen.getMaximumReactivePowerOutput())
.add();
}
LOGGER.trace("Created generator {}", generator.getId());
}
}
private static Bus createBus(MBus mBus, VoltageLevel voltageLevel) {
String busId = getId(BUS_PREFIX, mBus.getNumber());
Bus bus = voltageLevel.getBusBreakerView().newBus()
.setId(busId)
.setName(mBus.getName())
.add();
bus.setV(mBus.getVoltageMagnitude() * voltageLevel.getNominalV())
.setAngle(mBus.getVoltageAngle());
LOGGER.trace("Created bus {}", bus.getId());
return bus;
}
private static Substation createSubstation(Network network, String substationId) {
Substation substation = network.getSubstation(substationId);
if (substation == null) {
substation = network.newSubstation()
.setId(substationId)
.add();
LOGGER.trace("Created substation {}", substation.getId());
}
return substation;
}
private static double getNominalV(MBus mBus, boolean ignoreBaseVoltage) {
return ignoreBaseVoltage || mBus.getBaseVoltage() == 0 ? 1 : mBus.getBaseVoltage();
}
private static VoltageLevel createVoltageLevel(MBus mBus, String voltageLevelId, Substation substation, Network network, Context context) {
double nominalV = getNominalV(mBus, context.isIgnoreBaseMva());
VoltageLevel voltageLevel = network.getVoltageLevel(voltageLevelId);
if (voltageLevel == null) {
voltageLevel = substation.newVoltageLevel()
.setId(voltageLevelId)
.setNominalV(nominalV)
.setTopologyKind(TopologyKind.BUS_BREAKER)
.add();
LOGGER.trace("Created voltagelevel {}", voltageLevel.getId());
}
return voltageLevel;
}
private static void createLoad(MBus mBus, VoltageLevel voltageLevel) {
if (mBus.getRealPowerDemand() != 0 || mBus.getReactivePowerDemand() != 0) {
String busId = getId(BUS_PREFIX, mBus.getNumber());
String loadId = getId(LOAD_PREFIX, mBus.getNumber());
Load newLoad = voltageLevel.newLoad()
.setId(loadId)
.setConnectableBus(busId)
.setBus(busId)
.setP0(mBus.getRealPowerDemand())
.setQ0(mBus.getReactivePowerDemand())
.add();
LOGGER.trace("Created load {}", newLoad.getId());
}
}
private static void createShuntCompensator(MBus mBus, VoltageLevel voltageLevel, Context context) {
if (mBus.getShuntSusceptance() != 0) {
String busId = getId(BUS_PREFIX, mBus.getNumber());
String shuntId = getId(SHUNT_PREFIX, mBus.getNumber());
double zb = voltageLevel.getNominalV() * voltageLevel.getNominalV() / context.getBaseMva();
ShuntCompensatorAdder adder = voltageLevel.newShuntCompensator()
.setId(shuntId)
.setConnectableBus(busId)
.setBus(busId)
.setVoltageRegulatorOn(false)
.setSectionCount(1);
adder.newLinearModel()
.setBPerSection(mBus.getShuntSusceptance() / context.getBaseMva() / zb)
.setMaximumSectionCount(1)
.add();
ShuntCompensator newShunt = adder.add();
LOGGER.trace("Created shunt {}", newShunt.getId());
}
}
private static boolean isInService(MBranch branch) {
return Math.abs(branch.getStatus()) > 0;
}
private static boolean isInService(MDcLine dcLine) {
return Math.abs(dcLine.getStatus()) > 0;
}
private static boolean isInService(MGen generator) {
return generator.getStatus() > 0;
}
private static void createApparentPowerLimits(MBranch mBranch, ApparentPowerLimitsAdder limitsAdder) {
limitsAdder.setPermanentLimit(mBranch.getRateA()); // long term rating
if (mBranch.getRateB() != 0) {
limitsAdder.beginTemporaryLimit()
.setName("RateB")
.setValue(mBranch.getRateB())
.setAcceptableDuration(60 * 20) // 20' for short term rating
.endTemporaryLimit();
}
if (mBranch.getRateC() != 0) {
limitsAdder.beginTemporaryLimit()
.setName("RateC")
.setValue(mBranch.getRateC())
.setAcceptableDuration(60) // 1' for emergency rating
.endTemporaryLimit();
}
limitsAdder.add();
}
private static void createBranches(MatpowerModel model, ContainersMapping containerMapping, Network network, Context context) {
for (MBranch mBranch : model.getBranches()) {
String bus1Id = getId(BUS_PREFIX, mBranch.getFrom());
String bus2Id = getId(BUS_PREFIX, mBranch.getTo());
String voltageLevel1Id = containerMapping.getVoltageLevelId(mBranch.getFrom());
String voltageLevel2Id = containerMapping.getVoltageLevelId(mBranch.getTo());
VoltageLevel voltageLevel1 = network.getVoltageLevel(voltageLevel1Id);
VoltageLevel voltageLevel2 = network.getVoltageLevel(voltageLevel2Id);
double zb = voltageLevel2.getNominalV() * voltageLevel2.getNominalV() / context.getBaseMva();
boolean isInService = isInService(mBranch);
String connectedBus1 = isInService ? bus1Id : null;
String connectedBus2 = isInService ? bus2Id : null;
Branch> branch;
if (isTransformer(model, mBranch)) {
TwoWindingsTransformer newTwt = voltageLevel2.getSubstation()
.orElseThrow(() -> new PowsyblException("Substation null! Transformer must be within a substation"))
.newTwoWindingsTransformer()
.setId(getId(TRANSFORMER_PREFIX, mBranch.getFrom(), mBranch.getTo()))
.setEnsureIdUnicity(true)
.setBus1(connectedBus1)
.setConnectableBus1(bus1Id)
.setVoltageLevel1(voltageLevel1Id)
.setBus2(connectedBus2)
.setConnectableBus2(bus2Id)
.setVoltageLevel2(voltageLevel2Id)
.setRatedU1(voltageLevel1.getNominalV() * mBranch.getRatio())
.setRatedU2(voltageLevel2.getNominalV())
.setR(mBranch.getR() * zb)
.setX(mBranch.getX() * zb)
.setG(0)
.setB(mBranch.getB() / zb)
.add();
if (mBranch.getPhaseShiftAngle() != 0) {
newTwt.newPhaseTapChanger()
.setTapPosition(0)
.beginStep()
.setRho(1)
.setAlpha(-mBranch.getPhaseShiftAngle())
.setR(0)
.setX(0)
.setG(0)
.setB(0)
.endStep()
.add();
}
branch = newTwt;
LOGGER.trace("Created TwoWindingsTransformer {} {} {}", newTwt.getId(), bus1Id, bus2Id);
} else {
double nominalV1 = voltageLevel1.getNominalV();
double nominalV2 = voltageLevel2.getNominalV();
double sBase = context.getBaseMva();
double r = impedanceToEngineeringUnitsForLine(mBranch.getR(), nominalV1, nominalV2, sBase);
double x = impedanceToEngineeringUnitsForLine(mBranch.getX(), nominalV1, nominalV2, sBase);
Complex ytr = impedanceToAdmittance(r, x);
double g1 = admittanceEndToEngineeringUnitsForLine(ytr.getReal(), 0.0, nominalV1, nominalV2, sBase);
double b1 = admittanceEndToEngineeringUnitsForLine(ytr.getImaginary(), mBranch.getB() * 0.5, nominalV1, nominalV2, sBase);
double g2 = admittanceEndToEngineeringUnitsForLine(ytr.getReal(), 0.0, nominalV2, nominalV1, sBase);
double b2 = admittanceEndToEngineeringUnitsForLine(ytr.getImaginary(), mBranch.getB() * 0.5, nominalV2, nominalV1, sBase);
branch = network.newLine()
.setId(getId(LINE_PREFIX, mBranch.getFrom(), mBranch.getTo()))
.setEnsureIdUnicity(true)
.setBus1(connectedBus1)
.setConnectableBus1(bus1Id)
.setVoltageLevel1(voltageLevel1Id)
.setBus2(connectedBus2)
.setConnectableBus2(bus2Id)
.setVoltageLevel2(voltageLevel2Id)
.setR(r)
.setX(x)
.setG1(g1)
.setB1(b1)
.setG2(g2)
.setB2(b2)
.add();
LOGGER.trace("Created line {} {} {}", branch.getId(), bus1Id, bus2Id);
}
if (mBranch.getRateA() != 0) {
// we create the apparent power limit arbitrary on both sides
// there is probably something to fix on IIDM API to not have sided apparent
// power limits. Apparent power does not depend on voltage so it does not make
// sens to associate the limit to a branch side.
createApparentPowerLimits(mBranch, branch.newApparentPowerLimits1());
createApparentPowerLimits(mBranch, branch.newApparentPowerLimits2());
}
}
}
// avoid NaN when r and x, both are 0.0
private static Complex impedanceToAdmittance(double r, double x) {
return r == 0.0 && x == 0.0 ? new Complex(0.0, 0.0) : new Complex(r, x).reciprocal();
}
private static double impedanceToEngineeringUnitsForLine(double impedance, double nominalVoltageAtEnd,
double nominalVoltageAtOtherEnd, double sBase) {
// this method handles also line with different nominal voltage at ends
return impedance * nominalVoltageAtEnd * nominalVoltageAtOtherEnd / sBase;
}
private static double admittanceEndToEngineeringUnitsForLine(double transmissionAdmittance, double shuntAdmittanceAtEnd,
double nominalVoltageAtEnd, double nominalVoltageAtOtherEnd, double sBase) {
// this method handles also line with different nominal voltage at ends
// note that ytr is already in engineering units
return shuntAdmittanceAtEnd * sBase / (nominalVoltageAtEnd * nominalVoltageAtEnd) - (1 - nominalVoltageAtOtherEnd / nominalVoltageAtEnd) * transmissionAdmittance;
}
private static void createDcLines(MatpowerModel model, ContainersMapping containerMapping, Network network) {
for (MDcLine mDcLine : model.getDcLines()) {
String id = getId(HVDC_LINE_PREFIX, mDcLine.getFrom(), mDcLine.getTo());
String bus1Id = getId(BUS_PREFIX, mDcLine.getFrom());
String bus2Id = getId(BUS_PREFIX, mDcLine.getTo());
String voltageLevel1Id = containerMapping.getVoltageLevelId(mDcLine.getFrom());
String voltageLevel2Id = containerMapping.getVoltageLevelId(mDcLine.getTo());
VoltageLevel voltageLevel1 = network.getVoltageLevel(voltageLevel1Id);
VoltageLevel voltageLevel2 = network.getVoltageLevel(voltageLevel2Id);
boolean isInService = isInService(mDcLine);
String connectedBus1Id = isInService ? bus1Id : null;
String connectedBus2Id = isInService ? bus2Id : null;
String csId1 = getId(CONVERTER_STATION_1_PREFIX, mDcLine.getFrom(), mDcLine.getTo());
String csId2 = getId(CONVERTER_STATION_2_PREFIX, mDcLine.getFrom(), mDcLine.getTo());
double losses = mDcLine.getLoss0() + mDcLine.getLoss1() * mDcLine.getPf();
VscConverterStation vsc1 = voltageLevel1.newVscConverterStation()
.setId(csId1)
.setBus(connectedBus1Id)
.setConnectableBus(bus1Id)
.setVoltageRegulatorOn(true)
.setVoltageSetpoint(mDcLine.getVf() * voltageLevel1.getNominalV())
.setLossFactor((float) computeLossFactor1(mDcLine.getPf(), mDcLine.getLoss0())) // To guarantee the round-trip
.add();
VscConverterStation vsc2 = voltageLevel2.newVscConverterStation()
.setId(csId2)
.setBus(connectedBus2Id)
.setConnectableBus(bus2Id)
.setVoltageRegulatorOn(true)
.setVoltageSetpoint(mDcLine.getVt() * voltageLevel2.getNominalV())
.setLossFactor((float) computeLossFactor2(mDcLine.getPf(), mDcLine.getLoss0(), losses - mDcLine.getLoss0()))
.add();
network.newHvdcLine()
.setId(id)
.setConverterStationId1(csId1)
.setConverterStationId2(csId2)
.setR(0)
.setConvertersMode(HvdcLine.ConvertersMode.SIDE_1_RECTIFIER_SIDE_2_INVERTER)
.setActivePowerSetpoint(mDcLine.getPf())
.setNominalV(voltageLevel1.getNominalV())
.setMaxP(mDcLine.getPmax())
.add();
if (reactiveLimitsAreOk(mDcLine.getQminf(), mDcLine.getQmaxf())) {
vsc1.newMinMaxReactiveLimits().setMinQ(mDcLine.getQminf()).setMaxQ(mDcLine.getQmaxf()).add();
}
if (reactiveLimitsAreOk(mDcLine.getQmint(), mDcLine.getQmaxt())) {
vsc2.newMinMaxReactiveLimits().setMinQ(mDcLine.getQmint()).setMaxQ(mDcLine.getQmaxt()).add();
}
}
}
// IIDM Rectifier PDC/PAC1 = 1 - lossFactor1/100
// IIDM Inverter PAC2/PDC = 1 - lossFactor2/100
// PAC1 = PDc + losses1
// PDc = PAC2 + losses2
// Matpower Pf = Pt + l0 + l1*Pf
private static double computeLossFactor1(double pac1, double losses1) {
return pac1 != 0.0 ? losses1 * 100.0 / pac1 : 0.0;
}
private static double computeLossFactor2(double pac1, double losses1, double losses2) {
return (pac1 - losses1) != 0.0 ? losses2 * 100.0 / (pac1 - losses1) : 0.0;
}
private static boolean reactiveLimitsAreOk(double minQ, double maxQ) {
return Double.isFinite(minQ) && Double.isFinite(maxQ) && minQ <= maxQ;
}
@Override
public boolean exists(ReadOnlyDataSource dataSource) {
try {
return dataSource.isDataExtension(MatpowerConstants.EXT) && dataSource.exists(null, MatpowerConstants.EXT);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
@Override
public String getComment() {
return "MATPOWER Format to IIDM converter";
}
@Override
public String getFormat() {
return MatpowerConstants.FORMAT;
}
@Override
public List getSupportedExtensions() {
return Collections.singletonList(MatpowerConstants.EXT);
}
@Override
public void copy(ReadOnlyDataSource fromDataSource, DataSource toDataSource) {
Objects.requireNonNull(fromDataSource);
Objects.requireNonNull(toDataSource);
try {
try (InputStream is = fromDataSource.newInputStream(null, MatpowerConstants.EXT);
OutputStream os = toDataSource.newOutputStream(null, MatpowerConstants.EXT, false)) {
ByteStreams.copy(is, os);
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
@Override
public List getParameters() {
return ConfiguredParameter.load(Collections.singletonList(IGNORE_BASE_VOLTAGE_PARAMETER), getFormat(), ParameterDefaultValueConfig.INSTANCE);
}
@Override
public Network importData(ReadOnlyDataSource dataSource, NetworkFactory networkFactory, Properties parameters) {
Objects.requireNonNull(dataSource);
Objects.requireNonNull(networkFactory);
Network network = networkFactory.createNetwork(dataSource.getBaseName(), MatpowerConstants.FORMAT);
//there is no time & date declared in the MATPOWER file: set a default now()
network.setCaseDate(ZonedDateTime.now());
try {
try (InputStream iStream = dataSource.newInputStream(null, MatpowerConstants.EXT)) {
MatpowerModel model = MatpowerReader.read(iStream, dataSource.getBaseName());
LOGGER.debug("MATPOWER model '{}'", model.getCaseName());
boolean ignoreBaseVoltage = Parameter.readBoolean(MatpowerConstants.FORMAT, parameters, IGNORE_BASE_VOLTAGE_PARAMETER,
ParameterDefaultValueConfig.INSTANCE);
Map busNumToMBus = model.getBuses().stream().collect(Collectors.toMap(MBus::getNumber, Function.identity()));
ContainersMapping containerMapping = ContainersMapping.create(model.getBuses(), model.getBranches(),
MBus::getNumber,
MBranch::getFrom,
MBranch::getTo,
branch -> branch.getR() == 0.0 && branch.getX() == 0.0,
branch -> isTransformer(model, branch),
busNumber -> getNominalVFromBusNumber(busNumToMBus, busNumber, ignoreBaseVoltage),
busNums -> getId(VOLTAGE_LEVEL_PREFIX, busNums.stream().sorted().findFirst().orElseThrow(() -> new PowsyblException("Unexpected empty busNums"))),
substationNums -> getId(SUBSTATION_PREFIX, substationNums.stream().sorted().findFirst().orElseThrow(() -> new PowsyblException("Unexpected empty substationNums"))));
Context context = new Context(model.getBaseMva(), ignoreBaseVoltage);
createBuses(model, containerMapping, network, context);
createBranches(model, containerMapping, network, context);
createDcLines(model, containerMapping, network);
for (Bus slackBus : context.getSlackBuses()) {
SlackTerminal.attach(slackBus);
}
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
return network;
}
private double getNominalVFromBusNumber(Map busNumToMBus, int busNumber, boolean ignoreBaseVoltage) {
if (!busNumToMBus.containsKey(busNumber)) { // never should happen
throw new PowsyblException("busId without MBus" + busNumber);
}
return getNominalV(busNumToMBus.get(busNumber), ignoreBaseVoltage);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy