Skip to content

Commit

Permalink
Network elements creation (#259)
Browse files Browse the repository at this point in the history
Possibility to create network elements, either through dataframes
or keyword arguments.

C structures are slightly adapted to have stronger typing.

Design note: There is clearly some duplication between 
creation dataframes and get/update dataframes, but sharing
more is difficult because creation implies more complex
logics, sometimes with multiple objects created at once from
multiple dataframes.

Signed-off-by: Etienne LESOT <etienne.lesot@rte-france.com>
Signed-off-by: Sylvain Leclerc <sylvain.leclerc@rte-france.com>

Co-authored-by: Sylvain Leclerc <sylvain.leclerc@rte-france.com>
  • Loading branch information
EtienneLt and sylvlecl committed Feb 17, 2022
1 parent dc8c861 commit 23c7f8b
Show file tree
Hide file tree
Showing 47 changed files with 3,404 additions and 537 deletions.
74 changes: 48 additions & 26 deletions cpp/src/bindings.cpp
Expand Up @@ -22,24 +22,25 @@ void bindArray(py::module_& m, const std::string& className) {
}, py::keep_alive<0, 1>());
}

std::shared_ptr<array> createArray(py::list columnsValues, const std::vector<std::string>& columnsNames, const std::vector<int>& columnsTypes, const std::vector<bool>& isIndex) {
int columnsNumber = columnsNames.size();
std::shared_ptr<array> dataframe(new array(), [](array* dataframeToDestroy){
for (int indice = 0 ; indice < dataframeToDestroy->length; indice ++) {
series* column = ((series*) dataframeToDestroy->ptr) + indice;
if (column->type == 0) {
pypowsybl::deleteCharPtrPtr((char**) column->data.ptr, column->data.length);
} else if (column->type == 1) {
delete[] (double*) column->data.ptr;
} else if (column->type == 2 || column->type == 3) {
delete[] (int*) column->data.ptr;
}
delete[] column->name;
void deleteDataframe(dataframe* df) {
for (int indice = 0 ; indice < df->series_count; indice ++) {
series* column = df->series + indice;
if (column->type == 0) {
pypowsybl::deleteCharPtrPtr((char**) column->data.ptr, column->data.length);
} else if (column->type == 1) {
delete[] (double*) column->data.ptr;
} else if (column->type == 2 || column->type == 3) {
delete[] (int*) column->data.ptr;
}
delete[] (series*) dataframeToDestroy->ptr;
delete dataframeToDestroy;
});
dataframe->ptr = new series[columnsNumber];
delete[] column->name;
}
delete[] df->series;
delete df;
}

std::shared_ptr<dataframe> createDataframe(py::list columnsValues, const std::vector<std::string>& columnsNames, const std::vector<int>& columnsTypes, const std::vector<bool>& isIndex) {
int columnsNumber = columnsNames.size();
std::shared_ptr<dataframe> dataframe(new ::dataframe(), ::deleteDataframe);
series* columns = new series[columnsNumber];
for (int indice = 0 ; indice < columnsNumber ; indice ++ ) {
series* column = columns + indice;
Expand All @@ -62,13 +63,28 @@ std::shared_ptr<array> createArray(py::list columnsValues, const std::vector<std
column->data.ptr = pypowsybl::copyVectorInt(values);
}
}
dataframe->length = columnsNumber;
dataframe->ptr = columns;
dataframe->series_count = columnsNumber;
dataframe->series = columns;
return dataframe;
}

void updateNetworkElementsWithSeries(pypowsybl::JavaHandle network, array* dataframe, element_type elementType) {
pypowsybl::updateNetworkElementsWithSeries(network, dataframe, elementType);
std::shared_ptr<dataframe_array> createDataframeArray(const std::vector<dataframe*>& dataframes) {
std::shared_ptr<dataframe_array> dataframeArray(new dataframe_array(), [](dataframe_array* dataframeToDestroy){
delete[] dataframeToDestroy->dataframes;
delete dataframeToDestroy;
});
dataframe* dataframesFinal = new dataframe[dataframes.size()];
for (int indice = 0 ; indice < dataframes.size() ; indice ++) {
dataframesFinal[indice] = *dataframes[indice];
}
dataframeArray->dataframes = dataframesFinal;
dataframeArray->dataframes_count = dataframes.size();
return dataframeArray;
}

void createElement(pypowsybl::JavaHandle network, const std::vector<dataframe*>& dataframes, element_type elementType) {
std::shared_ptr<dataframe_array> dataframeArray = ::createDataframeArray(dataframes);
pypowsybl::createElement(network, dataframeArray.get(), elementType);
}

template<typename T>
Expand Down Expand Up @@ -254,10 +270,11 @@ PYBIND11_MODULE(_pypowsybl, m) {
.value("ALL", pypowsybl::ConnectedComponentMode::ALL, "Run on all connected components")
.value("MAIN", pypowsybl::ConnectedComponentMode::MAIN, "Run only on the main connected component")
.export_values();

py::class_<array_struct, std::shared_ptr<array_struct>>(m, "ArrayStruct")
.def(py::init());

py::class_<dataframe, std::shared_ptr<dataframe>>(m, "Dataframe");

py::class_<load_flow_parameters, std::shared_ptr<load_flow_parameters>>(m, "LoadFlowParameters")
.def(py::init(&initLoadFlowParameters))
Expand Down Expand Up @@ -500,15 +517,19 @@ PYBIND11_MODULE(_pypowsybl, m) {
.def_property_readonly("is_modifiable", &pypowsybl::SeriesMetadata::isModifiable)
.def_property_readonly("is_default", &pypowsybl::SeriesMetadata::isDefault);

m.def("get_series_metadata", &pypowsybl::getSeriesMetadata, "Get series metadata for a given element type", py::arg("element_type"));
m.def("get_network_elements_dataframe_metadata", &pypowsybl::getNetworkDataframeMetadata, "Get dataframe metadata for a given network element type",
py::arg("element_type"));

m.def("get_network_elements_creation_dataframes_metadata", &pypowsybl::getNetworkElementCreationDataframesMetadata, "Get network elements creation tables metadata",
py::arg("element_type"));

m.def("create_network_elements_series_array", &pypowsybl::createNetworkElementsSeriesArray, "Create a network elements series array for a given element type",
py::call_guard<py::gil_scoped_release>(), py::arg("network"), py::arg("element_type"), py::arg("filter_attributes_type"), py::arg("attributes"), py::arg("array"));

m.def("update_network_elements_with_series", ::updateNetworkElementsWithSeries, "Update network elements for a given element type with a series",
py::call_guard<py::gil_scoped_release>(), py::arg("network"), py::arg("array"), py::arg("element_type"));
m.def("update_network_elements_with_series", pypowsybl::updateNetworkElementsWithSeries, "Update network elements for a given element type with a series",
py::call_guard<py::gil_scoped_release>(), py::arg("network"), py::arg("dataframe"), py::arg("element_type"));

m.def("create_dataframe", ::createArray, "create dataframe to update or create new elements", py::arg("columns_values"), py::arg("columns_names"), py::arg("columns_types"),
m.def("create_dataframe", ::createDataframe, "create dataframe to update or create new elements", py::arg("columns_values"), py::arg("columns_names"), py::arg("columns_types"),
py::arg("is_index"));

m.def("get_network_metadata", &pypowsybl::getNetworkMetadata, "get attributes", py::arg("network"));
Expand Down Expand Up @@ -544,4 +565,5 @@ PYBIND11_MODULE(_pypowsybl, m) {
py::arg("result"));
m.def("get_three_windings_transformer_results", &pypowsybl::getThreeWindingsTransformerResults,
"create a table with all three windings transformer results computed after security analysis", py::arg("result"));
m.def("create_element", ::createElement, "create a new element on the network", py::arg("network"), py::arg("dataframes"), py::arg("elementType"));
}
38 changes: 38 additions & 0 deletions cpp/src/pypowsybl-api.h
Expand Up @@ -9,6 +9,9 @@ typedef struct exception_handler_struct {
char* message;
} exception_handler;

/**
* Weakly typed array of data.
*/
typedef struct array_struct {
void* ptr;
int length;
Expand Down Expand Up @@ -123,6 +126,25 @@ typedef struct series_struct {
array data;
} series;

/**
* A dataframe: simply an array of series.
*/
typedef struct dataframe_struct {
struct series_struct* series;
int series_count;
} dataframe;

/**
* An array of dataframes.
*/
typedef struct {
dataframe* dataframes;
int dataframes_count;
} dataframe_array;

/**
* Metadata about one attribute.
*/
typedef struct series_metadata_struct {
char* name;
int type;
Expand All @@ -131,6 +153,22 @@ typedef struct series_metadata_struct {
unsigned char is_default;
} series_metadata;

/**
* Metadata for one dataframe : simply a list of attributes metadata.
*/
typedef struct {
series_metadata* attributes_metadata;
int attributes_count;
} dataframe_metadata;

/**
* Metadata for a list of dataframes.
*/
typedef struct {
dataframe_metadata* dataframes_metadata;
int dataframes_count;
} dataframes_metadata;

typedef struct zone_struct {
char* id;
char** injections_ids;
Expand Down
39 changes: 28 additions & 11 deletions cpp/src/pypowsybl.cpp
Expand Up @@ -105,11 +105,6 @@ Array<series>::~Array() {
callJava<>(::freeSeriesArray, delegate_);
}

template<>
Array<series_metadata>::~Array() {
callJava<>(::freeSeriesMetadataArray, delegate_);
}

template<typename T>
class ToPtr {
public:
Expand Down Expand Up @@ -531,7 +526,7 @@ matrix* getReferenceVoltages(const JavaHandle& sensitivityAnalysisResultContext,
(char*) contingencyId.c_str());
}

SeriesArray* createNetworkElementsSeriesArray(const JavaHandle& network, element_type elementType, filter_attributes_type filterAttributesType, const std::vector<std::string>& attributes, array* dataframe) {
SeriesArray* createNetworkElementsSeriesArray(const JavaHandle& network, element_type elementType, filter_attributes_type filterAttributesType, const std::vector<std::string>& attributes, dataframe* dataframe) {
ToCharPtrPtr attributesPtr(attributes);
return new SeriesArray(callJava<array*>(::createNetworkElementsSeriesArray, network, elementType, filterAttributesType, attributesPtr.get(), attributes.size(), dataframe));
}
Expand Down Expand Up @@ -614,18 +609,40 @@ SeriesArray* getBusBreakerViewElements(const JavaHandle& network, std::string& v
return new SeriesArray(callJava<array*>(::getBusBreakerViewElements, network, (char*) voltageLevel.c_str()));
}

void updateNetworkElementsWithSeries(pypowsybl::JavaHandle network, array* dataframe, element_type elementType) {
void updateNetworkElementsWithSeries(pypowsybl::JavaHandle network, dataframe* dataframe, element_type elementType) {
pypowsybl::callJava<>(::updateNetworkElementsWithSeries, network, elementType, dataframe);
}

std::vector<SeriesMetadata> getSeriesMetadata(element_type elementType) {

Array<series_metadata> array(pypowsybl::callJava<array*>(::getSeriesMetadata, elementType));
std::vector<SeriesMetadata> convertDataframeMetadata(dataframe_metadata* dataframeMetadata) {
std::vector<SeriesMetadata> res;
for (const series_metadata& series: array) {
for (int i = 0; i < dataframeMetadata->attributes_count; i++) {
const series_metadata& series = dataframeMetadata->attributes_metadata[i];
res.push_back(SeriesMetadata(series.name, series.type, series.is_index, series.is_modifiable, series.is_default));
}
return res;
}

std::vector<SeriesMetadata> getNetworkDataframeMetadata(element_type elementType) {

dataframe_metadata* metadata = pypowsybl::callJava<dataframe_metadata*>(::getSeriesMetadata, elementType);
std::vector<SeriesMetadata> res = convertDataframeMetadata(metadata);
callJava(::freeDataframeMetadata, metadata);
return res;
}

std::vector<std::vector<SeriesMetadata>> getNetworkElementCreationDataframesMetadata(element_type elementType) {

dataframes_metadata* allDataframesMetadata = pypowsybl::callJava<dataframes_metadata*>(::getCreationMetadata, elementType);
std::vector<std::vector<SeriesMetadata>> res;
for (int i =0; i < allDataframesMetadata->dataframes_count; i++) {
res.push_back(convertDataframeMetadata(allDataframesMetadata->dataframes_metadata + i));
}
pypowsybl::callJava(::freeDataframesMetadata, allDataframesMetadata);
return res;
}

void createElement(pypowsybl::JavaHandle network, dataframe_array* dataframes, element_type elementType) {
pypowsybl::callJava<>(::createElement, network, elementType, dataframes);
}

}
16 changes: 13 additions & 3 deletions cpp/src/pypowsybl.h
Expand Up @@ -240,9 +240,9 @@ matrix* getReferenceFlows(const JavaHandle& sensitivityAnalysisResultContext, co

matrix* getReferenceVoltages(const JavaHandle& sensitivityAnalysisResultContext, const std::string& contingencyId);

SeriesArray* createNetworkElementsSeriesArray(const JavaHandle& network, element_type elementType, filter_attributes_type filterAttributesType, const std::vector<std::string>& attributes, array* dataframe);
SeriesArray* createNetworkElementsSeriesArray(const JavaHandle& network, element_type elementType, filter_attributes_type filterAttributesType, const std::vector<std::string>& attributes, dataframe* dataframe);

void updateNetworkElementsWithSeries(pypowsybl::JavaHandle network, array* dataframe, element_type elementType);
void updateNetworkElementsWithSeries(pypowsybl::JavaHandle network, dataframe* dataframe, element_type elementType);

std::string getWorkingVariantId(const JavaHandle& network);

Expand Down Expand Up @@ -280,7 +280,17 @@ SeriesArray* getBusBreakerViewBuses(const JavaHandle& network,std::string& volta

SeriesArray* getBusBreakerViewElements(const JavaHandle& network,std::string& voltageLevel);

std::vector<SeriesMetadata> getSeriesMetadata(element_type elementType);
/**
* Metadata of the dataframe of network elements data for a given element type.
*/
std::vector<SeriesMetadata> getNetworkDataframeMetadata(element_type elementType);

/**
* Metadata of the list of dataframes to create network elements of the given type.
*/
std::vector<std::vector<SeriesMetadata>> getNetworkElementCreationDataframesMetadata(element_type elementType);

void createElement(pypowsybl::JavaHandle network, dataframe_array* dataframes, element_type elementType);

}

Expand Down
Expand Up @@ -60,16 +60,22 @@ public void updateSeries(T object, UpdatingDataframe updatingDataframe) {
SeriesMapper<U> series = seriesMappers.get(seriesName);
switch (column.getType()) {
case STRING:
series.updateString(getItem(object, updatingDataframe, i),
updatingDataframe.getStringValue(seriesName, i));
if (updatingDataframe.getStringValue(seriesName, i).isPresent()) {
series.updateString(getItem(object, updatingDataframe, i),
updatingDataframe.getStringValue(seriesName, i).get());
}
break;
case DOUBLE:
series.updateDouble(getItem(object, updatingDataframe, i),
updatingDataframe.getDoubleValue(seriesName, i));
if (updatingDataframe.getDoubleValue(seriesName, i).isPresent()) {
series.updateDouble(getItem(object, updatingDataframe, i),
updatingDataframe.getDoubleValue(seriesName, i).getAsDouble());
}
break;
case INT:
series.updateInt(getItem(object, updatingDataframe, i),
updatingDataframe.getIntValue(seriesName, i));
if (updatingDataframe.getIntValue(seriesName, i).isPresent()) {
series.updateInt(getItem(object, updatingDataframe, i),
updatingDataframe.getIntValue(seriesName, i).getAsInt());
}
break;
default:
throw new IllegalStateException("Unexpected series type for update: " + column.getType());
Expand All @@ -79,6 +85,11 @@ public void updateSeries(T object, UpdatingDataframe updatingDataframe) {
}
}

@Override
public boolean isSeriesMetaDataExists(String seriesName) {
return seriesMappers.containsKey(seriesName);
}

public Collection<SeriesMapper<U>> getSeriesMappers(DataframeFilter dataframeFilter) {
Collection<SeriesMapper<U>> mappers = seriesMappers.values();
return mappers.stream()
Expand Down
Expand Up @@ -6,6 +6,7 @@
*/
package com.powsybl.dataframe;

import com.powsybl.commons.PowsyblException;
import com.powsybl.dataframe.update.UpdatingDataframe;

import java.util.ArrayList;
Expand Down Expand Up @@ -47,7 +48,8 @@ public B itemsStreamProvider(Function<T, Stream<U>> itemsProvider) {

public B itemGetter(BiFunction<T, String, U> itemGetter) {
this.itemMultiIndexGetter = (network, updatingDataframe, lineNumber) -> {
String id = updatingDataframe.getStringValue("id", 0, lineNumber);
String id = updatingDataframe.getStringValue("id", 0, lineNumber)
.orElseThrow(() -> new PowsyblException("id is missing"));
return itemGetter.apply(network, id);
};
return (B) this;
Expand Down
2 changes: 2 additions & 0 deletions java/src/main/java/com/powsybl/dataframe/DataframeMapper.java
Expand Up @@ -36,4 +36,6 @@ public interface DataframeMapper<T> {
* Updates object data with the provided series.
*/
void updateSeries(T object, UpdatingDataframe updatingDataframe);

boolean isSeriesMetaDataExists(String seriesName);
}
24 changes: 24 additions & 0 deletions java/src/main/java/com/powsybl/dataframe/SeriesMetadata.java
Expand Up @@ -41,6 +41,30 @@ public SeriesDataType getType() {
return type;
}

public static SeriesMetadata strings(String name) {
return new SeriesMetadata(false, name, false, SeriesDataType.STRING, false);
}

public static SeriesMetadata ints(String name) {
return new SeriesMetadata(false, name, false, SeriesDataType.INT, false);
}

public static SeriesMetadata booleans(String name) {
return new SeriesMetadata(false, name, false, SeriesDataType.BOOLEAN, false);
}

public static SeriesMetadata doubles(String name) {
return new SeriesMetadata(false, name, false, SeriesDataType.DOUBLE, false);
}

public static SeriesMetadata stringIndex(String name) {
return new SeriesMetadata(true, name, false, SeriesDataType.STRING, false);
}

public static SeriesMetadata intIndex(String name) {
return new SeriesMetadata(true, name, false, SeriesDataType.INT, false);
}

public boolean isDefaultAttribute() {
return defaultAttribute;
}
Expand Down

0 comments on commit 23c7f8b

Please sign in to comment.