com.powsybl.psse.model.pf.PsseValidation Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of powsybl-psse-model Show documentation
Show all versions of powsybl-psse-model Show documentation
PSS/E raw format data model
/**
* 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.psse.model.pf;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.powsybl.psse.model.PsseVersion;
import static com.powsybl.psse.model.PsseVersion.Major.V35;
/**
* @author Luma Zamarreño {@literal }
* @author José Antonio Marqués {@literal }
*/
public class PsseValidation {
private final List warnings;
private boolean validCase;
private static final Logger LOGGER = LoggerFactory.getLogger(PsseValidation.class);
private static final String WARNING_TRANSFORMER_1_PARAMETER = "Transformer: %s Unexpected %s: %.5f";
private static final String WARNING_TRANSFORMER_2_PARAMETERS = "Transformer: %s Unexpected %s: %.5f %.5f";
public PsseValidation(PssePowerFlowModel model, PsseVersion psseVersion) {
Objects.requireNonNull(model);
warnings = new ArrayList<>();
validCase = true;
validate(model, psseVersion);
if (!validCase) {
writeWarnings();
}
}
public List getWarnings() {
return warnings;
}
public boolean isValidCase() {
return validCase;
}
private void writeWarnings() {
LOGGER.warn("PSS/E Validation ...");
warnings.forEach(LOGGER::warn);
LOGGER.warn("PSS/E Validation end. ValidCase {}", validCase);
}
private void validate(PssePowerFlowModel model, PsseVersion psseVersion) {
Map> buses = generateBuses(model.getBuses());
validateCaseIdentification(model.getCaseIdentification());
validateBuses(model.getBuses(), buses);
validateLoads(model.getLoads(), buses);
validateFixedShunts(model.getFixedShunts(), buses);
validateGenerators(model.getBuses(), model.getGenerators(), buses);
validateNonTransformerBranches(model.getNonTransformerBranches(), buses);
validateTransformers(model.getTransformers(), buses);
validateSwitchedShunts(model.getSwitchedShunts(), buses, psseVersion);
}
private static Map> generateBuses(List psseBuses) {
Map> buses = new HashMap<>();
for (int i = 0; i < psseBuses.size(); i++) {
buses.computeIfAbsent(psseBuses.get(i).getI(), k -> new ArrayList<>()).add(i);
}
return buses;
}
private void validateCaseIdentification(PsseCaseIdentification caseIdentification) {
if (caseIdentification.getSbase() <= 0.0) {
warnings.add(String.format(Locale.US, "CaseIdentification: Unexpected Sbase: %.2f", caseIdentification.getSbase()));
validCase = false;
}
if (caseIdentification.getBasfrq() <= 0.0) {
warnings.add(String.format(Locale.US, "CaseIdentification: Unexpected Basfrq: %.2f", caseIdentification.getBasfrq()));
validCase = false;
}
}
private void validateBuses(List psseBuses, Map> buses) {
for (Map.Entry> entry : buses.entrySet()) {
if (entry.getValue().size() != 1) {
warnings.add(String.format("Bus: %d defined multiple times (%d)", entry.getKey(), entry.getValue().size()));
validCase = false;
}
}
for (PsseBus psseBus : psseBuses) {
if (psseBus.getI() < 1 || psseBus.getI() > 999997) {
warnings.add(String.format("Bus: Unexpected I: %d", psseBus.getI()));
validCase = false;
}
if (psseBus.getBaskv() < 0.0) {
warnings.add(String.format(Locale.US, "Bus: %d Unexpected Baskv: %.2f", psseBus.getI(), psseBus.getBaskv()));
validCase = false;
}
}
}
private void validateLoads(List loads, Map> buses) {
Map> busesLoads = new HashMap<>();
for (PsseLoad load : loads) {
if (!buses.containsKey(load.getI())) {
warnings.add(String.format("Load: Unexpected I: %d", load.getI()));
validCase = false;
}
addBusesMap(busesLoads, load.getI(), load.getId());
}
checkDuplicates("Load", "loads", getDuplicates(busesLoads));
}
private void validateFixedShunts(List fixedShunts, Map> buses) {
Map> busesFixedShunts = new HashMap<>();
for (PsseFixedShunt fixedShunt : fixedShunts) {
if (!buses.containsKey(fixedShunt.getI())) {
warnings.add(String.format("FixedShunt: Unexpected I: %d", fixedShunt.getI()));
validCase = false;
}
addBusesMap(busesFixedShunts, fixedShunt.getI(), fixedShunt.getId());
}
checkDuplicates("FixedShunt", "fixed shunts", getDuplicates(busesFixedShunts));
}
private void validateGenerators(List psseBuses, List generators, Map> buses) {
Map> busesGenerators = new HashMap<>();
for (PsseGenerator generator : generators) {
if (!buses.containsKey(generator.getI())) {
warnings.add(String.format("Generator: Unexpected I: %d", generator.getI()));
validCase = false;
}
if (generator.getQt() < generator.getQb()) {
warnings.add(String.format(Locale.US, "Generator: %d %s Unexpected Qmin: %.2f Qmax: %.2f", generator.getI(), generator.getId(), generator.getQb(), generator.getQt()));
validCase = false;
}
if (generator.getIreg() != 0 && !buses.containsKey(generator.getIreg())) {
warnings.add(String.format("Generator: %d %s Unexpected IReg: %d", generator.getI(), generator.getId(), generator.getIreg()));
validCase = false;
}
if (generator.getPt() < generator.getPb()) {
warnings.add(String.format(Locale.US, "Generator: %d %s Unexpected Pmin: %.2f Pmax: %.2f", generator.getI(), generator.getId(), generator.getPb(), generator.getPt()));
validCase = false;
}
validateGeneratorRegulatingBus(psseBuses, buses, generator);
addBusesMap(busesGenerators, generator.getI(), generator.getId());
}
checkDuplicates("Generator", "generators", getDuplicates(busesGenerators));
}
private void validateGeneratorRegulatingBus(List psseBuses, Map> buses, PsseGenerator generator) {
PsseBus regulatingBus = getRegulatingBus(psseBuses, buses, generator.getIreg(), generator.getI());
if (regulatingBus != null
&& (regulatingBus.getIde() == 2 || regulatingBus.getIde() == 3)
&& generator.getVs() <= 0.0) {
warnings.add(String.format(Locale.US, "Generator: %d %s Unexpected Voltage setpoint: %.2f", generator.getI(), generator.getId(), generator.getVs()));
validCase = false;
}
}
private void validateNonTransformerBranches(List nonTransformerBranches, Map> buses) {
Map> busesNonTransformerBranches = new HashMap<>();
for (PsseNonTransformerBranch nonTransformerBranch : nonTransformerBranches) {
if (!buses.containsKey(nonTransformerBranch.getI())) {
warnings.add(String.format("NonTransformerBranch: Unexpected I: %d", nonTransformerBranch.getI()));
validCase = false;
}
if (!buses.containsKey(nonTransformerBranch.getJ())) {
warnings.add(String.format("NonTransformerBranch: Unexpected J: %d", nonTransformerBranch.getJ()));
validCase = false;
}
if (nonTransformerBranch.getX() == 0.0) {
warnings.add(String.format(Locale.US, "NonTransformerBranch: %d %d %s Unexpected X: %.5f", nonTransformerBranch.getI(), nonTransformerBranch.getJ(), nonTransformerBranch.getCkt(), nonTransformerBranch.getX()));
validCase = false;
}
addBusesMap(busesNonTransformerBranches, nonTransformerBranch.getI(), nonTransformerBranch.getJ(), nonTransformerBranch.getCkt());
}
checkDuplicatesLinks("NonTransformerBranch", "branches", getDuplicates(busesNonTransformerBranches));
}
private void validateTransformers(List transformers, Map> buses) {
List twoWindingsTransformers = transformers.parallelStream()
.filter(transformer -> transformer.getK() == 0).toList();
validateTwoWindingsTransformers(twoWindingsTransformers, buses);
List threeWindingsTransformers = transformers.parallelStream()
.filter(transformer -> transformer.getK() != 0).toList();
validateThreeWindingsTransformers(threeWindingsTransformers, buses);
}
private void validateTwoWindingsTransformers(List transformers, Map> buses) {
Map> busesTransformers = new HashMap<>();
for (PsseTransformer transformer : transformers) {
validateTransformerBus(buses, transformer.getI(), "I");
validateTransformerBus(buses, transformer.getJ(), "J");
String id = String.format("%d %d %s", transformer.getI(), transformer.getJ(), transformer.getCkt());
validateTransformerX(id, transformer.getX12(), "X12");
validateTransformerRatio(id, transformer.getWinding1().getWindv(), "ratio");
validateTransformerSbase(id, transformer.getCz(), transformer.getCm(), transformer.getSbase12(), "sbase12");
validateTransformerWindingVmiVma(id, transformer.getWinding1().getCod(), transformer.getWinding1().getVmi(), transformer.getWinding1().getVma(), "winding1 Vmi Vma");
validateTransformerWindingRmiRma(id, transformer.getWinding1().getCod(), transformer.getWinding1().getRmi(), transformer.getWinding1().getRma(), "winding1 Rmi Rma");
validateTransformerWindingCont(buses, id, transformer.getWinding1().getCod(), transformer.getWinding1().getCont(), "winding1 Cont");
addBusesMap(busesTransformers, transformer.getI(), transformer.getJ(), transformer.getCkt());
}
checkDuplicatesLinks("Transformer", "branches", getDuplicates(busesTransformers));
}
private void validateThreeWindingsTransformers(List transformers, Map> buses) {
Map> busesTransformers = new HashMap<>();
for (PsseTransformer transformer : transformers) {
validateTransformerBus(buses, transformer.getI(), "I");
validateTransformerBus(buses, transformer.getJ(), "J");
validateTransformerBus(buses, transformer.getK(), "K");
String id = String.format("%d %d %d %s", transformer.getI(), transformer.getJ(), transformer.getK(), transformer.getCkt());
validateTransformerX(id, transformer.getX12(), "X12");
validateTransformerX(id, transformer.getX31(), "X31");
validateTransformerX(id, transformer.getX23(), "X23");
validateTransformerRatio(id, transformer.getWinding1().getWindv(), "winding1 ratio");
validateTransformerRatio(id, transformer.getWinding2().getWindv(), "winding2 ratio");
validateTransformerRatio(id, transformer.getWinding3().getWindv(), "winding3 ratio");
validateTransformerSbase(id, transformer.getCz(), transformer.getCm(), transformer.getSbase12(), "sbase12");
validateTransformerSbase(id, transformer.getCz(), transformer.getCm(), transformer.getSbase23(), "sbase23");
validateTransformerSbase(id, transformer.getCz(), transformer.getCm(), transformer.getSbase31(), "sbase31");
validateTransformerWindingVmiVma(id, transformer.getWinding1().getCod(), transformer.getWinding1().getVmi(), transformer.getWinding1().getVma(), "winding1 Vmi Vma");
validateTransformerWindingVmiVma(id, transformer.getWinding2().getCod(), transformer.getWinding2().getVmi(), transformer.getWinding2().getVma(), "winding2 Vmi Vma");
validateTransformerWindingVmiVma(id, transformer.getWinding3().getCod(), transformer.getWinding3().getVmi(), transformer.getWinding3().getVma(), "winding3 Vmi Vma");
validateTransformerWindingRmiRma(id, transformer.getWinding1().getCod(), transformer.getWinding1().getRmi(), transformer.getWinding1().getRma(), "winding1 Rmi Rma");
validateTransformerWindingRmiRma(id, transformer.getWinding2().getCod(), transformer.getWinding2().getRmi(), transformer.getWinding2().getRma(), "winding2 Rmi Rma");
validateTransformerWindingRmiRma(id, transformer.getWinding3().getCod(), transformer.getWinding3().getRmi(), transformer.getWinding3().getRma(), "winding3 Rmi Rma");
validateTransformerWindingCont(buses, id, transformer.getWinding1().getCod(), transformer.getWinding1().getCont(), "winding1 Cont");
validateTransformerWindingCont(buses, id, transformer.getWinding2().getCod(), transformer.getWinding2().getCont(), "winding2 Cont");
validateTransformerWindingCont(buses, id, transformer.getWinding3().getCod(), transformer.getWinding3().getCont(), "winding3 Cont");
addBusesMap(busesTransformers, transformer.getI(), transformer.getJ(), transformer.getK(), transformer.getCkt());
}
Map> duplicatedBusesTransformers = getDuplicates(busesTransformers);
if (!duplicatedBusesTransformers.isEmpty()) {
duplicatedBusesTransformers.forEach((key,
value) -> warnings.add(String.format(
"Transformer: Multiple branches (%d) between buses %d, %d and %d with the same Id %s",
value.size(), firstBus(key), secondBus(key), thirdBus(key), value.get(0))));
validCase = false;
}
}
private void validateTransformerBus(Map> buses, int bus, String busTag) {
if (!buses.containsKey(bus)) {
warnings.add(String.format("Transformer: Unexpected %s: %d", busTag, bus));
validCase = false;
}
}
private void validateTransformerX(String id, double x, String xTag) {
if (x == 0.0) {
warnings.add(getWarningTransformer1Parameter(id, xTag, x));
validCase = false;
}
}
private void validateTransformerRatio(String id, double ratio, String ratioTag) {
if (ratio <= 0.0) {
warnings.add(getWarningTransformer1Parameter(id, ratioTag, ratio));
validCase = false;
}
}
private void validateTransformerSbase(String id, int cz, int cm, double sbase, String sbaseTag) {
if ((cz == 2 || cz == 3 || cm == 2) && sbase <= 0.0) {
warnings.add(getWarningTransformer1Parameter(id, sbaseTag, sbase));
validCase = false;
}
}
private void validateTransformerWindingVmiVma(String id, int cod, double windingVmi, double windingVma, String windingVmiVmaTag) {
if (Math.abs(cod) == 1 && (windingVmi <= 0.0 || windingVma <= 0.0 || windingVma < windingVmi)) {
warnings.add(getWarningTransformer2Parameters(id, windingVmiVmaTag, windingVmi, windingVma));
validCase = false;
}
if ((Math.abs(cod) == 2 || Math.abs(cod) == 3 || Math.abs(cod) == 5) && windingVma < windingVmi) {
warnings.add(getWarningTransformer2Parameters(id, windingVmiVmaTag, windingVmi, windingVma));
validCase = false;
}
}
private void validateTransformerWindingRmiRma(String id, int cod, double windingRmi, double windingRma, String windingRmiRmaTag) {
if ((Math.abs(cod) == 1 || Math.abs(cod) == 2) && (windingRmi <= 0.0 || windingRma <= 0.0 || windingRma < windingRmi)) {
warnings.add(getWarningTransformer2Parameters(id, windingRmiRmaTag, windingRmi, windingRma));
validCase = false;
}
if ((Math.abs(cod) == 3 || Math.abs(cod) == 5) && windingRma < windingRmi) {
warnings.add(getWarningTransformer2Parameters(id, windingRmiRmaTag, windingRmi, windingRma));
validCase = false;
}
}
private void validateTransformerWindingCont(Map> buses, String id, int cod, int windingCont, String windingContTag) {
if (Math.abs(cod) == 1 && (windingCont == 0 || !buses.containsKey(Math.abs(windingCont)))) {
warnings.add(String.format(Locale.US, "Transformer: %s Unexpected %s: %d", id, windingContTag, windingCont));
validCase = false;
}
}
private void validateSwitchedShunts(List switchedShunts, Map> buses, PsseVersion psseVersion) {
Map> busesSwitchedShunts = new HashMap<>();
for (PsseSwitchedShunt switchedShunt : switchedShunts) {
if (!buses.containsKey(switchedShunt.getI())) {
warnings.add(String.format("SwitchedShunt: Unexpected I: %d", switchedShunt.getI()));
validCase = false;
}
String id = switchedShuntId(switchedShunt, psseVersion);
int regulatingBus = switchedShuntRegulatingBus(switchedShunt, psseVersion);
if (switchedShunt.getModsw() != 0 && regulatingBus != 0 && !buses.containsKey(regulatingBus)) {
warnings.add(String.format("SwitchedShunt: %s Unexpected Swrem/Swreg: %d", id, regulatingBus));
validCase = false;
}
if (switchedShunt.getModsw() != 0 && switchedShunt.getVswhi() < switchedShunt.getVswlo()) {
warnings.add(String.format(Locale.US, "SwitchedShunt: %s Unexpected Vswlo Vswhi: %.5f %.5f", id, switchedShunt.getVswlo(), switchedShunt.getVswhi()));
validCase = false;
}
if ((switchedShunt.getModsw() == 1 || switchedShunt.getModsw() == 2) && (switchedShunt.getVswlo() <= 0.0 || switchedShunt.getVswhi() <= 0.0)) {
warnings.add(String.format(Locale.US, "SwitchedShunt: %s Unexpected Vswlo Vswhi: %.5f %.5f", id, switchedShunt.getVswlo(), switchedShunt.getVswhi()));
validCase = false;
}
addSwitchedShuntBusesMap(busesSwitchedShunts, switchedShunt, psseVersion);
}
Map> duplicatedBusesFixedShunts = getDuplicates(busesSwitchedShunts);
if (!duplicatedBusesFixedShunts.isEmpty()) {
duplicatedBusesFixedShunts.forEach((key, value) -> warnings.add(multipleSwitchedShuntString(key, value, psseVersion)));
validCase = false;
}
}
private static String switchedShuntId(PsseSwitchedShunt switchedShunt, PsseVersion psseVersion) {
if (psseVersion.major() == V35) {
return String.format("%d %s", switchedShunt.getI(), switchedShunt.getId());
} else {
return String.format("%d", switchedShunt.getI());
}
}
private static int switchedShuntRegulatingBus(PsseSwitchedShunt switchedShunt, PsseVersion psseVersion) {
if (psseVersion.major() == V35) {
return switchedShunt.getSwreg();
} else {
return switchedShunt.getSwrem();
}
}
private static void addSwitchedShuntBusesMap(Map> busesSwitchedShunts, PsseSwitchedShunt switchedShunt, PsseVersion psseVersion) {
if (psseVersion.major() == V35) {
addBusesMap(busesSwitchedShunts, switchedShunt.getI(), switchedShunt.getId());
} else {
addBusesMap(busesSwitchedShunts, switchedShunt.getI(), "1");
}
}
private static String multipleSwitchedShuntString(String key, List value, PsseVersion psseVersion) {
if (psseVersion.major() == V35) {
return String.format("SwitchedShunt: Multiple fixed shunts (%d) at bus %d with the same Id %s", value.size(), Integer.valueOf(key), value.get(0));
} else {
return String.format("SwitchedShunt: Multiple fixed shunts (%d) at bus %d", value.size(), Integer.valueOf(key));
}
}
private static PsseBus getRegulatingBus(List psseBuses, Map> buses, int ireg, int i) {
int regulatingId = i;
if (ireg != 0) {
regulatingId = ireg;
}
if (buses.containsKey(regulatingId)) {
return psseBuses.get(buses.get(regulatingId).get(0));
}
return null;
}
private static Map> getDuplicates(Map> busesMap) {
Map> duplicatedBusMap = new HashMap<>();
busesMap.forEach((key, value) -> value.stream().collect(Collectors.groupingBy(s -> s))
.entrySet()
.stream()
.filter(e -> e.getValue().size() > 1)
.forEach(e -> duplicatedBusMap.put(key, e.getValue())));
return duplicatedBusMap;
}
private static void addBusesMap(Map> busesMap, int busI, String id) {
String busString = String.format("%06d", busI);
busesMap.computeIfAbsent(busString, k -> new ArrayList<>()).add(id);
}
private static void addBusesMap(Map> busesMap, int busI, int busJ, String ckt) {
String busString;
if (busI < busJ) {
busString = String.format("%06d-%06d", busI, busJ);
} else {
busString = String.format("%06d-%06d", busJ, busI);
}
busesMap.computeIfAbsent(busString, k -> new ArrayList<>()).add(ckt);
}
private static void addBusesMap(Map> busesMap, int busI, int busJ, int busK, String ckt) {
String busString;
List buses = new ArrayList<>();
buses.add(busI);
buses.add(busJ);
buses.add(busK);
Collections.sort(buses);
busString = String.format("%06d-%06d-%06d", buses.get(0), buses.get(1), buses.get(2));
busesMap.computeIfAbsent(busString, k -> new ArrayList<>()).add(ckt);
}
private static int firstBus(String busKey) {
String[] tokens = busKey.split("-");
return Integer.parseInt(tokens[0]);
}
private static int secondBus(String busKey) {
String[] tokens = busKey.split("-");
return Integer.parseInt(tokens[1]);
}
private static int thirdBus(String busKey) {
String[] tokens = busKey.split("-");
return Integer.parseInt(tokens[2]);
}
private void checkDuplicates(String tag, String tagEquipments, Map> duplicatedBusesEquipments) {
if (!duplicatedBusesEquipments.isEmpty()) {
duplicatedBusesEquipments.forEach((key, value) -> warnings
.add(String.format("%s: Multiple %s (%d) at bus %d with the same Id %s", tag, tagEquipments,
value.size(), Integer.valueOf(key), value.get(0))));
validCase = false;
}
}
private void checkDuplicatesLinks(String tag, String tagLinks, Map> duplicatedBusesLinks) {
if (!duplicatedBusesLinks.isEmpty()) {
duplicatedBusesLinks.forEach((key, value) -> warnings
.add(String.format("%s: Multiple %s (%d) between buses %d and %d with the same Id %s", tag, tagLinks,
value.size(), firstBus(key), secondBus(key), value.get(0))));
validCase = false;
}
}
private String getWarningTransformer1Parameter(String id, String tag, double param) {
return String.format(Locale.US, WARNING_TRANSFORMER_1_PARAMETER, id, tag, param);
}
private String getWarningTransformer2Parameters(String id, String tag, double param1, double param2) {
return String.format(Locale.US, WARNING_TRANSFORMER_2_PARAMETERS, id, tag, param1, param2);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy