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

Refactor PowerFactory object reference #2041

Merged
merged 7 commits into from
Mar 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -10,6 +10,8 @@
import com.powsybl.commons.PowsyblException;
import com.powsybl.iidm.network.util.ContainersMapping;
import com.powsybl.powerfactory.model.DataObject;
import com.powsybl.powerfactory.model.DataObjectIndex;
import com.powsybl.powerfactory.model.DataObjectRef;

import java.util.*;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -72,17 +74,17 @@ public double getX() {

private static final class BusesToVoltageLevelId {

private final Map<Long, DataObject> objsById;
private final DataObjectIndex index;

private int noNameVoltageLevelCount = 0;

private BusesToVoltageLevelId(Map<Long, DataObject> objsById) {
this.objsById = objsById;
private BusesToVoltageLevelId(DataObjectIndex index) {
this.index = index;
}

public String getVoltageLevelId(Set<Integer> ids) {
List<DataObject> objs = ids.stream()
.map(objsById::get)
.flatMap(id -> index.getDataObjectById(id).stream())
.filter(Objects::nonNull)
.collect(Collectors.toList());

Expand Down Expand Up @@ -137,7 +139,9 @@ private static void createNodes(List<DataObject> elmTerms, List<DataObject> node
for (DataObject elmTerm : elmTerms) {
nodes.add(elmTerm);
for (DataObject staCubic : elmTerm.getChildrenByClass("StaCubic")) {
DataObject connectedObj = staCubic.findObjectReferenceValue("obj_id").orElse(null);
DataObject connectedObj = staCubic.findObjectAttributeValue("obj_id")
.flatMap(DataObjectRef::resolve)
.orElse(null);
if (isBranch(connectedObj)) {
nodes.add(staCubic);
edges.add(new Edge(elmTerm, staCubic, null, false, 0, 0));
Expand All @@ -159,7 +163,7 @@ private static void createEdges(List<Edge> edges, Map<DataObject, List<DataObjec
break;
case "ElmLne":
float dline = connectedObj.getFloatAttributeValue("dline");
DataObject typLne = connectedObj.getObjectReferenceValue("typ_id");
DataObject typLne = connectedObj.getObjectAttributeValue("typ_id").resolve().orElseThrow();
float rline = typLne.getFloatAttributeValue("rline");
float xline = typLne.getFloatAttributeValue("xline");
double r = rline * dline;
Expand All @@ -184,15 +188,15 @@ private static void createEdges(List<Edge> edges, Map<DataObject, List<DataObjec
}
}

static ContainersMapping create(Map<Long, DataObject> objs, List<DataObject> elmTerms) {
static ContainersMapping create(DataObjectIndex index, List<DataObject> elmTerms) {
List<DataObject> nodes = new ArrayList<>();
List<Edge> edges = new ArrayList<>();
Map<DataObject, List<DataObject>> branchesByCubicleId = new HashMap<>();

createNodes(elmTerms, nodes, edges, branchesByCubicleId);
createEdges(edges, branchesByCubicleId);

BusesToVoltageLevelId busesToVoltageLevelId = new BusesToVoltageLevelId(objs);
BusesToVoltageLevelId busesToVoltageLevelId = new BusesToVoltageLevelId(index);

return ContainersMapping.create(nodes, edges,
obj -> Ints.checkedCast(obj.getId()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,7 @@
import com.powsybl.iidm.network.*;
import com.powsybl.iidm.network.util.ContainersMapping;
import com.powsybl.iidm.parameters.Parameter;
import com.powsybl.powerfactory.model.DataObject;
import com.powsybl.powerfactory.model.PowerFactoryException;
import com.powsybl.powerfactory.model.StudyCase;
import com.powsybl.powerfactory.model.StudyCaseLoader;
import com.powsybl.powerfactory.model.*;
import org.apache.commons.lang3.mutable.MutableInt;
import org.joda.time.DateTime;
import org.joda.time.Instant;
Expand Down Expand Up @@ -149,7 +146,7 @@ private static PowerFactoryException createNotYetSupportedException() {
private Network createNetwork(StudyCase studyCase, NetworkFactory networkFactory) {
Network network = networkFactory.createNetwork(studyCase.getName(), FORMAT);

List<DataObject> elmNets = studyCase.getElmNets();
List<DataObject> elmNets = studyCase.getIndex().getDataObjectsByClass("ElmNet");
if (elmNets.isEmpty()) {
throw new PowsyblException("No ElmNet object found");
}
Expand All @@ -159,19 +156,11 @@ private Network createNetwork(StudyCase studyCase, NetworkFactory networkFactory
DateTime caseDate = new Instant(studyCase.getTime().toEpochMilli()).toDateTime();
network.setCaseDate(caseDate);

// index objects by id
Map<Long, DataObject> objsById = new HashMap<>();
for (DataObject elmNet : elmNets) {
elmNet.traverse(obj -> objsById.put(obj.getId(), obj));
}

List<DataObject> elmTerms = objsById.values().stream()
.filter(obj -> obj.getDataClassName().equals("ElmTerm"))
.collect(Collectors.toList());
List<DataObject> elmTerms = studyCase.getIndex().getDataObjectsByClass("ElmTerm");

LOGGER.info("Creating containers...");

ContainersMapping containerMapping = ContainersMappingHelper.create(objsById, elmTerms);
ContainersMapping containerMapping = ContainersMappingHelper.create(studyCase.getIndex(), elmTerms);
ImportContext importContext = new ImportContext(containerMapping);

LOGGER.info("Creating topology graphs...");
Expand All @@ -190,7 +179,7 @@ private Network createNetwork(StudyCase studyCase, NetworkFactory networkFactory

LOGGER.info("Creating equipments...");

for (DataObject obj : objsById.values()) {
for (DataObject obj : studyCase.getIndex().getDataObjects()) {
switch (obj.getDataClassName()) {
case "ElmCoup":
createSwitch(network, importContext, obj);
Expand Down Expand Up @@ -327,12 +316,16 @@ private void createGenerator(Network network, ImportContext importContext, DataO
.setMinP(pMinUc)
.setMaxP(pMaxUc)
.add();
elmSym.findObjectReferenceValue(TYP_ID).ifPresent(typSym -> createReactiveLimits(elmSym, typSym, g));
elmSym.findObjectAttributeValue(TYP_ID)
.flatMap(DataObjectRef::resolve)
.ifPresent(typSym -> createReactiveLimits(elmSym, typSym, g));
}

private void createReactiveLimits(DataObject elmSym, DataObject typSym, Generator g) {
if (typSym.getDataClassName().equals("TypSym")) {
DataObject pQlimType = elmSym.findObjectReferenceValue("pQlimType").orElse(null);
DataObject pQlimType = elmSym.findObjectAttributeValue("pQlimType")
.flatMap(DataObjectRef::resolve)
.orElse(null);
if (pQlimType != null) {
throw new PowsyblException("Reactive capability curve not supported: '" + elmSym + "'");
} else {
Expand Down Expand Up @@ -366,7 +359,9 @@ private void createLine(Network network, ImportContext importContext, DataObject
NodeRef nodeRef1 = it.next();
NodeRef nodeRef2 = it.next();
float dline = elmLne.getFloatAttributeValue("dline");
DataObject typLne = elmLne.getObjectReferenceValue(TYP_ID);
DataObject typLne = elmLne.getObjectAttributeValue(TYP_ID)
.resolve()
.orElseThrow();
float rline = typLne.getFloatAttributeValue("rline");
float xline = typLne.getFloatAttributeValue("xline");
float bline = typLne.getFloatAttributeValue("bline");
Expand Down Expand Up @@ -403,7 +398,9 @@ private void create2wTransformer(Network network, ImportContext importContext, D
VoltageLevel vl1 = network.getVoltageLevel(nodeRef1.voltageLevelId);
VoltageLevel vl2 = network.getVoltageLevel(nodeRef2.voltageLevelId);
Substation s = vl1.getSubstation().orElseThrow();
DataObject typTr2 = elmTr2.getObjectReferenceValue(TYP_ID);
DataObject typTr2 = elmTr2.getObjectAttributeValue(TYP_ID)
.resolve()
.orElseThrow();
float strn = typTr2.getFloatAttributeValue("strn");
float utrnL = typTr2.getFloatAttributeValue("utrn_l");
float utrnH = typTr2.getFloatAttributeValue("utrn_h");
Expand Down Expand Up @@ -526,7 +523,9 @@ private void createNode(Network network, ImportContext importContext, DataObject
.add();
}
for (DataObject staCubic : elmTerm.getChildrenByClass("StaCubic")) {
DataObject connectedObj = staCubic.findObjectReferenceValue("obj_id").orElse(null);
DataObject connectedObj = staCubic.findObjectAttributeValue("obj_id")
.flatMap(DataObjectRef::resolve)
.orElse(null);
if (connectedObj == null) {
importContext.cubiclesObjectNotFound.add(staCubic);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Instant;
import java.util.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
Expand All @@ -29,16 +31,12 @@ public class DgsReader {

private static final Logger LOGGER = LoggerFactory.getLogger(DgsReader.class);

private final Map<Long, DataObject> objectsById = new HashMap<>();
private final DataObjectIndex index = new DataObjectIndex();

private final Map<String, DataClass> classesByName = new HashMap<>();

private final List<ToResolve> toResolveList = new ArrayList<>();

private final Map<String, String> general = new HashMap<>();

private List<DataObject> elmNets = new ArrayList<>();

public static StudyCase read(Path dgsFile) {
return read(dgsFile, StandardCharsets.ISO_8859_1);
}
Expand All @@ -51,21 +49,6 @@ public static StudyCase read(Path dgsFile, Charset charset) {
}
}

private static final class ToResolve {

private final DataObject obj;

private final String attributeName;

private final long id;

private ToResolve(DataObject obj, String attributeName, long id) {
this.obj = obj;
this.attributeName = attributeName;
this.id = id;
}
}

private static DataAttributeType getDataAttributeType(char attributeType) {
DataAttributeType type;
switch (attributeType) {
Expand All @@ -79,25 +62,19 @@ private static DataAttributeType getDataAttributeType(char attributeType) {
type = DataAttributeType.FLOAT;
break;
case 'p':
type = DataAttributeType.INTEGER64;
type = DataAttributeType.OBJECT;
break;
default:
throw new AssertionError("Unexpected attribute type: " + attributeType);
}
return type;
}

private void resolveLinksAndBuildObjectsTree() {
for (ToResolve toResolve : toResolveList) {
DataObject obj = objectsById.get(toResolve.id);
if (obj == null) {
throw new PowerFactoryException("Object '" + toResolve.id + "' not found");
}
if (toResolve.attributeName.equals(DataAttribute.FOLD_ID)) {
toResolve.obj.setParent(obj);
} else {
toResolve.obj.getReferenceValues().computeIfAbsent(toResolve.attributeName, k -> obj);
}
private void buildObjectTree() {
for (DataObject obj : index.getDataObjects()) {
obj.findObjectAttributeValue(DataAttribute.FOLD_ID)
.flatMap(DataObjectRef::resolve)
.ifPresent(obj::setParent);
}
}

Expand Down Expand Up @@ -126,24 +103,12 @@ public void onAttributeDescription(String attributeName, char attributeType) {
}
}

private DataObject createDataObject(long id, DataClass clazz) {
if (objectsById.containsKey(id)) {
throw new PowerFactoryException("Object '" + id + "' already exists");
}
DataObject newObj = new DataObject(id, clazz);
objectsById.put(id, newObj);
return newObj;
}

@Override
public void onStringValue(String attributeName, String value) {
if (clazz != null) {
if ("ID".equals(attributeName)) {
long id = Long.parseLong(value);
object = createDataObject(id, clazz);
if (clazz.getName().equals("ElmNet")) {
elmNets.add(object);
}
object = new DataObject(id, clazz, index);
} else {
object.setStringAttributeValue(attributeName, value);
}
Expand All @@ -168,8 +133,7 @@ public void onRealValue(String attributeName, float value) {

@Override
public void onObjectValue(String attributeName, long id) {
object.setLongAttributeValue(attributeName, id);
toResolveList.add(new ToResolve(object, attributeName, id));
object.setObjectAttributeValue(attributeName, id);
}
}

Expand All @@ -180,20 +144,12 @@ public StudyCase read(String studyCaseName, Reader reader) {

new DgsParser().read(reader, new DgsHandlerImpl());

if (elmNets.isEmpty()) {
throw new PowerFactoryException("ElmNet object is missing");
}

// resolve object attributes links
resolveLinksAndBuildObjectsTree();
// build object tree (so resolve parents / children links)
buildObjectTree();

stopwatch.stop();
LOGGER.info("DGS file read in {} ms: {} data objects", stopwatch.elapsed(TimeUnit.MILLISECONDS), objectsById.size());
LOGGER.info("DGS file read in {} ms: {} data objects", stopwatch.elapsed(TimeUnit.MILLISECONDS), index.getDataObjects().size());

StudyCase studyCase = new StudyCase(studyCaseName, Instant.now(), elmNets);
for (DataObject obj : objectsById.values()) {
obj.setStudyCase(studyCase);
}
return studyCase;
return new StudyCase(studyCaseName, Instant.now(), index);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import com.powsybl.commons.AbstractConverterTest;
import com.powsybl.commons.TestUtil;
import com.powsybl.powerfactory.model.StudyCase;

import org.junit.Test;

import java.io.IOException;
Expand All @@ -22,7 +21,8 @@
import java.nio.charset.StandardCharsets;
import java.util.Objects;

import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

/**
* @author Luma Zamarreño <zamarrenolm at aia.es>
Expand All @@ -41,9 +41,7 @@ private static StudyCase loadCase(String fileName) {
String studyName = Files.getNameWithoutExtension(fileName);
InputStream is = Objects.requireNonNull(DgsDataTest.class.getResourceAsStream(fileName));
DgsReader dgsReader = new DgsReader();
StudyCase s = dgsReader.read(studyName, new InputStreamReader(is));

return s;
return dgsReader.read(studyName, new InputStreamReader(is));
}

private static String loadReference(String path) {
Expand Down
Loading