Skip to content

Commit

Permalink
Dataframe based network interface (#2)
Browse files Browse the repository at this point in the history
Explore network using julia dataframes and get network metadata.

Signed-off-by: Bertrand Rix <[email protected]>
  • Loading branch information
obrix authored Oct 9, 2024
1 parent b1f9ec7 commit f019cc3
Show file tree
Hide file tree
Showing 9 changed files with 417 additions and 16 deletions.
6 changes: 5 additions & 1 deletion .github/workflows/dev-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,8 @@ jobs:
- name: Test
run: |
julia test/print_version.jl
julia test/print_version.jl
- name: Test
run: |
julia test/print_network.jl
1 change: 1 addition & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ version = "0.1"
[deps]
CxxWrap = "1f15a43c-97ca-5a2a-ae31-89f07a497df4"
Powsybl_jll = "b8c81e45-bfcc-5af0-87df-fd7619bc5515"
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"

[compat]
julia = "1.6.7"
Expand Down
30 changes: 16 additions & 14 deletions build_local.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,25 @@ sources = [

julia_versions = [VERSION]

platform = HostPlatform()

@info string("Downloading pypowsybl java binaries for ", platform.tags["os"])
if platform.tags["os"] == "linux"
Base.download("https://github.com/powsybl/pypowsybl/releases/download/v1.7.0/binaries-v1.7.0-linux.zip", "cpp/powsybl-java.zip")
elseif platform.tags["os"] == "windows"
Base.download("https://github.com/powsybl/pypowsybl/releases/download/v1.7.0/binaries-v1.7.0-windows.zip", "cpp/powsybl-java.zip")
elseif platform.tags["os"] == "macos"
Base.download("https://github.com/powsybl/pypowsybl/releases/download/v1.7.0/binaries-v1.7.0-darwin.zip", "cpp/powsybl-java.zip")
else
throw("Unsupported platform with os " * platform.tags["os"])
end


script = raw"""
cd $WORKSPACE/srcdir
# Get binary for powsybl-java, generated with GraalVm
if [[ "${target}" == *-mingw* ]]; then
wget https://github.com/powsybl/pypowsybl/releases/download/vBinariesDeployment/binaries-vBinariesDeployment-windows.zip -O powsybl-java.zip
fi
if [[ "${target}" == *-linux-* ]]; then
wget https://github.com/powsybl/pypowsybl/releases/download/vBinariesDeployment/binaries-vBinariesDeployment-linux.zip -O powsybl-java.zip
fi
if [[ "${target}" == *-apple-* ]]; then
wget https://github.com/powsybl/pypowsybl/releases/download/vBinariesDeployment/binaries-vBinariesDeployment-darwin.zip -O powsybl-java.zip
fi
unzip powsybl-java.zip -d $prefix
unzip cpp/powsybl-java.zip -d $prefix
# Build powsybl-cpp API
cd $WORKSPACE/srcdir/cpp/ && mkdir build && cd build
Expand All @@ -34,9 +39,6 @@ cmake -DCMAKE_BUILD_TYPE=Release ../cpp/powsybljl-cpp -DJulia_PREFIX=$prefix -DJ
cmake --build . --target install --config Release
"""

platforms = [HostPlatform()]
@show platforms

products = [
LibraryProduct(["math", "libmath"], :libmath)
LibraryProduct(["pypowsybl-java", "libpypowsybl-java"], :libpypowsybl_java)
Expand All @@ -49,5 +51,5 @@ dependencies = [
Dependency("libjulia_jll")
]

build_tarballs(ARGS, name, version, sources, script, platforms, products, dependencies;
build_tarballs(ARGS, name, version, sources, script, [platform], products, dependencies;
preferred_gcc_version=v"12", julia_compat="1.6")
117 changes: 117 additions & 0 deletions cpp/powsybljl-cpp/powsybl_jl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,131 @@
#include "jlcxx/jlcxx.hpp"
#include "powsybl-cpp.h"

// Necessary to compile to map struct with no constructor ?
template <> struct jlcxx::IsMirroredType<series> : std::false_type {};
template <> struct jlcxx::IsMirroredType<network_metadata> : std::false_type {};

void logFromJava(int level, long timestamp, char* loggerName, char* message) {
//TODO Redirect log properly to julia logger
}

JLCXX_MODULE define_module_powsybl(jlcxx::Module& mod)
{
mod.add_type<pypowsybl::JavaHandle>("JavaHandle");

mod.add_bits<element_type>("ElementType", jlcxx::julia_type("CppEnum"));
mod.set_const("BUS", element_type::BUS);
mod.set_const("BUS_FROM_BUS_BREAKER_VIEW", element_type::BUS_FROM_BUS_BREAKER_VIEW);
mod.set_const("LINE", element_type::LINE);
mod.set_const("TWO_WINDINGS_TRANSFORMER", element_type::TWO_WINDINGS_TRANSFORMER);
mod.set_const("THREE_WINDINGS_TRANSFORMER", element_type::THREE_WINDINGS_TRANSFORMER);
mod.set_const("GENERATOR", element_type::GENERATOR);
mod.set_const("LOAD", element_type::LOAD);
mod.set_const("BATTERY", element_type::BATTERY);
mod.set_const("SHUNT_COMPENSATOR", element_type::SHUNT_COMPENSATOR);
mod.set_const("NON_LINEAR_SHUNT_COMPENSATOR_SECTION", element_type::NON_LINEAR_SHUNT_COMPENSATOR_SECTION);
mod.set_const("LINEAR_SHUNT_COMPENSATOR_SECTION", element_type::LINEAR_SHUNT_COMPENSATOR_SECTION);
mod.set_const("DANGLING_LINE", element_type::DANGLING_LINE);
mod.set_const("TIE_LINE", element_type::TIE_LINE);
mod.set_const("LCC_CONVERTER_STATION", element_type::LCC_CONVERTER_STATION);
mod.set_const("VSC_CONVERTER_STATION", element_type::VSC_CONVERTER_STATION);
mod.set_const("STATIC_VAR_COMPENSATOR", element_type::STATIC_VAR_COMPENSATOR);
mod.set_const("SWITCH", element_type::SWITCH);
mod.set_const("VOLTAGE_LEVEL", element_type::VOLTAGE_LEVEL);
mod.set_const("SUBSTATION", element_type::SUBSTATION);
mod.set_const("BUSBAR_SECTION", element_type::BUSBAR_SECTION);
mod.set_const("HVDC_LINE", element_type::HVDC_LINE);
mod.set_const("RATIO_TAP_CHANGER_STEP", element_type::RATIO_TAP_CHANGER_STEP);
mod.set_const("PHASE_TAP_CHANGER_STEP", element_type::PHASE_TAP_CHANGER_STEP);
mod.set_const("RATIO_TAP_CHANGER", element_type::RATIO_TAP_CHANGER);
mod.set_const("PHASE_TAP_CHANGER", element_type::PHASE_TAP_CHANGER);
mod.set_const("REACTIVE_CAPABILITY_CURVE_POINT", element_type::REACTIVE_CAPABILITY_CURVE_POINT);
mod.set_const("OPERATIONAL_LIMITS", element_type::OPERATIONAL_LIMITS);
mod.set_const("MINMAX_REACTIVE_LIMITS", element_type::MINMAX_REACTIVE_LIMITS);
mod.set_const("ALIAS", element_type::ALIAS);
mod.set_const("IDENTIFIABLE", element_type::IDENTIFIABLE);
mod.set_const("INJECTION", element_type::INJECTION);
mod.set_const("BRANCH", element_type::BRANCH);
mod.set_const("TERMINAL", element_type::TERMINAL);
mod.set_const("SUB_NETWORK", element_type::SUB_NETWORK);

mod.add_bits<filter_attributes_type>("FilterAttributes", jlcxx::julia_type("CppEnum"));
mod.set_const("ALL_ATTRIBUTES", filter_attributes_type::ALL_ATTRIBUTES);
mod.set_const("DEFAULT_ATTRIBUTES", filter_attributes_type::DEFAULT_ATTRIBUTES);
mod.set_const("SELECTION_ATTRIBUTES", filter_attributes_type::SELECTION_ATTRIBUTES);

auto preJavaCall = [](pypowsybl::GraalVmGuard* guard, exception_handler* exc){ };
auto postJavaCall = [](){ };
pypowsybl::init(preJavaCall, postJavaCall);
auto fptr = &::logFromJava;
pypowsybl::setupLoggerCallback(reinterpret_cast<void *&>(fptr));

mod.method("get_version_table", &pypowsybl::getVersionTable, "Get an ASCII table with all PowSybBl modules version");
mod.method("set_java_library_path", [] (std::string const& path) {
pypowsybl::setJavaLibraryPath(path);
}, "Set java.library.path JVM property");

mod.method("close_powsybl", [] () {
pypowsybl::closePypowsybl();
}, "Closes powsybl module");

mod.method("load", [] (std::string const& s) {
std::map<std::string, std::string> defaultParameters;
std::vector<std::string> postProcessors;
pypowsybl::JavaHandle network = pypowsybl::loadNetwork(s, defaultParameters, postProcessors, nullptr);
return network;
}, "Load a network from a file");

mod.method("create_network", [] (std::string const& name, std::string const& id) {
return pypowsybl::createNetwork(name, id);
}, "create an example network");

mod.method("get_network_import_formats", [] () {
return pypowsybl::getNetworkImportFormats();
}, "Get available import format");

mod.add_type<series>("SeriesType")
.method("name", [](series& s) { return std::string(s.name); })
.method("index", [](series& s) { return (bool) s.index; })
.method("type", [](series& s) { return s.type; })
.method("as_double_array", [](series& s) {
return jlcxx::ArrayRef<double,1>(static_cast<double*>(s.data.ptr), s.data.length);
})
.method("as_int_array", [](series& s) {
return jlcxx::ArrayRef<int,1>(static_cast<int*>(s.data.ptr), s.data.length);
})
.method("as_string_array", [](series& s) {
return pypowsybl::toVector<std::string>((array *) & s.data);
});

mod.add_type<network_metadata>("NetworkMetadata")
.method("id", [](pypowsybl::JavaHandle handle) {
return std::string(pypowsybl::getNetworkMetadata(handle)->id);
})
.method("name", [](pypowsybl::JavaHandle handle) {
return std::string(pypowsybl::getNetworkMetadata(handle)->name);
})
.method("source_format", [](pypowsybl::JavaHandle handle) {
return std::string(pypowsybl::getNetworkMetadata(handle)->source_format);
})
.method("forecast_distance", [](pypowsybl::JavaHandle handle) {
return pypowsybl::getNetworkMetadata(handle)->forecast_distance;
})
.method("case_date", [](pypowsybl::JavaHandle handle) {
return pypowsybl::getNetworkMetadata(handle)->case_date;
});

mod.add_type<pypowsybl::SeriesArray>("SeriesArray")
.method("as_array", [](pypowsybl::SeriesArray& seriesArray) {
jlcxx::Array<series> data{ };
for(int i=0; i < seriesArray.length(); ++i) {
data.push_back(seriesArray.begin()[i]);
}
return data;
});

mod.method("create_network_elements_series_array", [] (pypowsybl::JavaHandle handle, element_type type, std::vector<std::string> const& attributes, filter_attributes_type filter_attributes, bool nominal_apparent_power, double per_unit) {
return pypowsybl::createNetworkElementsSeriesArray(handle, type, filter_attributes, attributes, nullptr, nominal_apparent_power, per_unit);
}, "Get a series");

}
2 changes: 1 addition & 1 deletion cpp/pypowsybl
Submodule pypowsybl updated 57 files
+10 −2 .github/workflows/dev-ci.yml
+10 −2 .github/workflows/full-ci.yml
+3 −0 .github/workflows/release-ci.yml
+4 −0 cpp/CMakeLists.txt
+1 −3 cpp/powsybl-cpp/CMakeLists.txt
+16 −7 cpp/powsybl-cpp/powsybl-cpp.cpp
+11 −3 cpp/powsybl-cpp/powsybl-cpp.h
+2 −4 cpp/pypowsybl-cpp/CMakeLists.txt
+15 −9 cpp/pypowsybl-cpp/bindings.cpp
+1 −1 cpp/pypowsybl-java/powsybl-api.h
+25 −0 docs/_templates/sidebar/brand.html
+7 −1 docs/conf.py
+1 −0 docs/reference/network.rst
+73 −66 docs/user_guide/flowdecomposition.rst
+3 −3 docs/user_guide/loadflow.rst
+16 −2 docs/user_guide/network.rst
+6 −2 java/pom.xml
+44 −31 java/src/main/java/com/powsybl/dataframe/network/NetworkDataframes.java
+4 −4 java/src/main/java/com/powsybl/dataframe/network/adders/NetworkUtils.java
+13 −31 java/src/main/java/com/powsybl/dataframe/network/adders/OperationalLimitsDataframeAdder.java
+14 −2 java/src/main/java/com/powsybl/dataframe/network/extensions/ActivePowerControlDataframeAdder.java
+10 −2 java/src/main/java/com/powsybl/dataframe/network/extensions/ActivePowerControlDataframeProvider.java
+4 −4 java/src/main/java/com/powsybl/python/commons/PyPowsyblApiHeader.java
+5 −7 java/src/main/java/com/powsybl/python/dynamic/CurveMappingSupplier.java
+2 −6 java/src/main/java/com/powsybl/python/flow_decomposition/FlowDecompositionCFunctions.java
+1 −1 java/src/main/java/com/powsybl/python/flow_decomposition/FlowDecompositionCUtils.java
+13 −11 java/src/main/java/com/powsybl/python/flow_decomposition/XnecWithDecompositionContext.java
+4 −1 java/src/main/java/com/powsybl/python/network/Dataframes.java
+52 −24 java/src/main/java/com/powsybl/python/network/NetworkCFunctions.java
+1 −1 java/src/main/java/com/powsybl/python/network/Networks.java
+8 −16 java/src/main/java/com/powsybl/python/security/SecurityAnalysisContext.java
+1 −1 java/src/main/java/com/powsybl/python/shortcircuit/FortescueFeederResultContext.java
+1 −1 java/src/main/java/com/powsybl/python/shortcircuit/MagnitudeFeederResultContext.java
+29 −8 java/src/test/java/com/powsybl/dataframe/network/NetworkDataframesTest.java
+1 −1 java/src/test/java/com/powsybl/python/shortcircuit/ShortCircuitAnalysisTest.java
+80 −81 java/src/test/resources/nad.svg
+3 −1 java/src/test/resources/sld.svg
+1 −1 pypowsybl/__init__.py
+21 −4 pypowsybl/_pypowsybl.pyi
+1 −1 pypowsybl/flowdecomposition/__init__.py
+7 −7 pypowsybl/flowdecomposition/impl/parameters.py
+1 −0 pypowsybl/network/__init__.py
+45 −13 pypowsybl/network/impl/network.py
+21 −14 pypowsybl/network/impl/network_creation_util.py
+10 −0 pypowsybl/network/impl/util.py
+4 −3 pypowsybl/shortcircuit/impl/short_circuit_analysis_result.py
+2 −1 requirements.txt
+1 −1 setup.cfg
+1 −1 tests/battery.xiidm
+141 −141 tests/test_flow_decomposition.py
+4 −4 tests/test_java_perunit.py
+4 −2 tests/test_loadflow.py
+111 −10 tests/test_network.py
+18 −18 tests/test_network_elements_creation.py
+21 −4 tests/test_network_extensions.py
+4 −4 tests/test_per_unit.py
+2 −4 tests/test_security_analysis.py
188 changes: 188 additions & 0 deletions src/Network.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
module Network
using ..Powsybl
using CxxWrap
using DataFrames

const nominal_apparent_power = 100.0
const per_unit = false

mutable struct NetworkHandle
handle::Powsybl.JavaHandle
id::String
name::String
source_format::String
forecast_distance::Int32
case_date::Float64
end

function get_network_metadata(network::NetworkHandle)
return Powsybl.get_network_metadata(network.handle)
end

function get_elements(network::NetworkHandle, type::Powsybl.ElementType, all_attributes::Bool = false, attributes::Vector{String} = Vector{String}())
filter_attributes = Powsybl.DEFAULT_ATTRIBUTES
if all_attributes
filter_attributes = Powsybl.ALL_ATTRIBUTES
elseif !isempty(attributes)
filter_attributes = Powsybl.SELECTION_ATTRIBUTES
end

if all_attributes && !isempty(attributes)
throw("parameters \"all_attributes\" and \"attributes\" are mutually exclusive")
end
series_array = Powsybl.create_network_elements_series_array(network.handle, type, StdVector{StdString}(attributes), filter_attributes, per_unit, nominal_apparent_power)
return create_dataframe_from_series_array(series_array[])
end

function get_buses(network::NetworkHandle, all_attributes::Bool = false, attributes::Vector{String} = Vector{String}())
return get_elements(network, Powsybl.BUS, all_attributes, attributes)
end

function get_bus_breaker_view_buses(network::NetworkHandle, all_attributes::Bool = false, attributes::Vector{String} = Vector{String}())
return get_elements(network, Powsybl.BUS_FROM_BUS_BREAKER_VIEW, all_attributes, attributes)
end

function get_generators(network::NetworkHandle, all_attributes::Bool = false, attributes::Vector{String} = Vector{String}())
return get_elements(network, Powsybl.GENERATOR, all_attributes, attributes)
end

function get_batteries(network::NetworkHandle, all_attributes::Bool = false, attributes::Vector{String} = Vector{String}())
return get_elements(network, Powsybl.BATTERY, all_attributes, attributes)
end

function get_lines(network::NetworkHandle, all_attributes::Bool = false, attributes::Vector{String} = Vector{String}())
return get_elements(network, Powsybl.LINE, all_attributes, attributes)
end

function get_2_windings_transformers(network::NetworkHandle, all_attributes::Bool = false, attributes::Vector{String} = Vector{String}())
return get_elements(network, Powsybl.TWO_WINDINGS_TRANSFORMER, all_attributes, attributes)
end

function get_3_windings_transformers(network::NetworkHandle, all_attributes::Bool = false, attributes::Vector{String} = Vector{String}())
return get_elements(network, Powsybl.THREE_WINDINGS_TRANSFORMER, all_attributes, attributes)
end

function get_shunt_compensators(network::NetworkHandle, all_attributes::Bool = false, attributes::Vector{String} = Vector{String}())
return get_elements(network, Powsybl.SHUNT_COMPENSATOR, all_attributes, attributes)
end

function get_non_linear_shunt_compensator_sections(network::NetworkHandle, all_attributes::Bool = false, attributes::Vector{String} = Vector{String}())
return get_elements(network, Powsybl.NON_LINEAR_SHUNT_COMPENSATOR_SECTION, all_attributes, attributes)
end

function get_linear_shunt_compensator_sections(network::NetworkHandle, all_attributes::Bool = false, attributes::Vector{String} = Vector{String}())
return get_elements(network, Powsybl.LINEAR_SHUNT_COMPENSATOR_SECTION, all_attributes, attributes)
end

function get_dangling_lines(network::NetworkHandle, all_attributes::Bool = false, attributes::Vector{String} = Vector{String}())
return get_elements(network, Powsybl.DANGLING_LINE, all_attributes, attributes)
end

function get_tie_lines(network::NetworkHandle, all_attributes::Bool = false, attributes::Vector{String} = Vector{String}())
return get_elements(network, Powsybl.TIE_LINE, all_attributes, attributes)
end

function get_lcc_converter_stations(network::NetworkHandle, all_attributes::Bool = false, attributes::Vector{String} = Vector{String}())
return get_elements(network, Powsybl.LCC_CONVERTER_STATION, all_attributes, attributes)
end

function get_vsc_converter_stations(network::NetworkHandle, all_attributes::Bool = false, attributes::Vector{String} = Vector{String}())
return get_elements(network, Powsybl.VSC_CONVERTER_STATION, all_attributes, attributes)
end

function get_static_var_compensators(network::NetworkHandle, all_attributes::Bool = false, attributes::Vector{String} = Vector{String}())
return get_elements(network, Powsybl.STATIC_VAR_COMPENSATOR, all_attributes, attributes)
end

function get_voltage_levels(network::NetworkHandle, all_attributes::Bool = false, attributes::Vector{String} = Vector{String}())
return get_elements(network, Powsybl.VOLTAGE_LEVEL, all_attributes, attributes)
end

function get_busbar_sections(network::NetworkHandle, all_attributes::Bool = false, attributes::Vector{String} = Vector{String}())
return get_elements(network, Powsybl.BUSBAR_SECTION, all_attributes, attributes)
end

function get_substations(network::NetworkHandle, all_attributes::Bool = false, attributes::Vector{String} = Vector{String}())
return get_elements(network, Powsybl.SUBSTATION, all_attributes, attributes)
end

function get_hvdc_lines(network::NetworkHandle, all_attributes::Bool = false, attributes::Vector{String} = Vector{String}())
return get_elements(network, Powsybl.HVDC_LINE, all_attributes, attributes)
end

function get_switches(network::NetworkHandle, all_attributes::Bool = false, attributes::Vector{String} = Vector{String}())
return get_elements(network, Powsybl.SWITCH, all_attributes, attributes)
end

function get_ratio_tap_changer_steps(network::NetworkHandle, all_attributes::Bool = false, attributes::Vector{String} = Vector{String}())
return get_elements(network, Powsybl.RATIO_TAP_CHANGER_STEP, all_attributes, attributes)
end

function get_phase_tap_changer_steps(network::NetworkHandle, all_attributes::Bool = false, attributes::Vector{String} = Vector{String}())
return get_elements(network, Powsybl.PHASE_TAP_CHANGER_STEP, all_attributes, attributes)
end

function get_ratio_tap_changers(network::NetworkHandle, all_attributes::Bool = false, attributes::Vector{String} = Vector{String}())
return get_elements(network, Powsybl.RATIO_TAP_CHANGER, all_attributes, attributes)
end

function get_phase_tap_changers(network::NetworkHandle, all_attributes::Bool = false, attributes::Vector{String} = Vector{String}())
return get_elements(network, Powsybl.PHASE_TAP_CHANGER, all_attributes, attributes)
end

function get_reactive_capability_curve_points(network::NetworkHandle, all_attributes::Bool = false, attributes::Vector{String} = Vector{String}())
return get_elements(network, Powsybl.REACTIVE_CAPABILITY_CURVE_POINT, all_attributes, attributes)
end

function get_aliases(network::NetworkHandle, all_attributes::Bool = false, attributes::Vector{String} = Vector{String}())
return get_elements(network, Powsybl.ALIAS, all_attributes, attributes)
end

function get_identifiables(network::NetworkHandle, all_attributes::Bool = false, attributes::Vector{String} = Vector{String}())
return get_elements(network, Powsybl.IDENTIFIABLE, all_attributes, attributes)
end

function get_injections(network::NetworkHandle, all_attributes::Bool = false, attributes::Vector{String} = Vector{String}())
return get_elements(network, Powsybl.INJECTION, all_attributes, attributes)
end

function get_branches(network::NetworkHandle, all_attributes::Bool = false, attributes::Vector{String} = Vector{String}())
return get_elements(network, Powsybl.BRANCH, all_attributes, attributes)
end

function get_terminals(network::NetworkHandle, all_attributes::Bool = false, attributes::Vector{String} = Vector{String}())
return get_elements(network, Powsybl.TERMINAL, all_attributes, attributes)
end

function create_dataframe_from_series_array(array::Powsybl.SeriesArray)
myArray = Powsybl.as_array(array)
df = DataFrame()
for serie in myArray
type = Powsybl.type(serie)
name = Powsybl.name(serie)
if type == 0
data = Powsybl.as_string_array(serie)
elseif type == 1
data = Powsybl.as_double_array(serie)
elseif type == 2
data = Powsybl.as_int_array(serie)
else
continue
end
df[!, name]=data
end
return df
end

function load(network_file::String)::NetworkHandle
handle = Powsybl.load(network_file)
return NetworkHandle(Powsybl.load(network_file),
Powsybl.id(handle),
Powsybl.name(handle),
Powsybl.source_format(handle),
Powsybl.forecast_distance(handle),
Powsybl.case_date(handle))
end

include("NetworkCreationUtils.jl")
end
Loading

0 comments on commit f019cc3

Please sign in to comment.