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

add shortcircuit analysis api #640

Merged
merged 6 commits into from
Sep 13, 2023
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
41 changes: 41 additions & 0 deletions cpp/src/bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -766,4 +766,45 @@ PYBIND11_MODULE(_pypowsybl, m) {
m.def("get_network_modification_metadata_with_element_type", &pypowsybl::getModificationMetadataWithElementType, "Get network modification metadata with element type", py::arg("network_modification_type"), py::arg("element_type"));

m.def("create_network_modification", ::createNetworkModification, "Create and apply network modification", py::arg("network"), py::arg("dataframe"), py::arg("network_modification_type"), py::arg("raise_exception"), py::arg("reporter"));

py::enum_<pypowsybl::ShortCircuitStudyType>(m, "ShortCircuitStudyType", "Indicates the type of short circuit study")
.value("SUB_TRANSIENT", pypowsybl::ShortCircuitStudyType::SUB_TRANSIENT,
"It is the first stage of the short circuit, right when the fault happens. The subtransient reactance of generators will be used.")
.value("TRANSIENT", pypowsybl::ShortCircuitStudyType::TRANSIENT,
"The second stage of the short circuit, before the system stabilizes. The transient reactance of generators will be used.")
.value("STEADY_STATE", pypowsybl::ShortCircuitStudyType::STEADY_STATE,
"The last stage of the short circuit, once all transient effects are gone.");

py::class_<pypowsybl::ShortCircuitAnalysisParameters>(m, "ShortCircuitAnalysisParameters")
.def(py::init(&pypowsybl::createShortCircuitAnalysisParameters))
.def_readwrite("with_voltage_result", &pypowsybl::ShortCircuitAnalysisParameters::with_voltage_result)
.def_readwrite("with_feeder_result", &pypowsybl::ShortCircuitAnalysisParameters::with_feeder_result)
.def_readwrite("with_limit_violations", &pypowsybl::ShortCircuitAnalysisParameters::with_limit_violations)
.def_readwrite("study_type", &pypowsybl::ShortCircuitAnalysisParameters::study_type)
.def_readwrite("with_fortescue_result", &pypowsybl::ShortCircuitAnalysisParameters::with_fortescue_result)
.def_readwrite("min_voltage_drop_proportional_threshold", &pypowsybl::ShortCircuitAnalysisParameters::min_voltage_drop_proportional_threshold)
.def_readwrite("provider_parameters_keys", &pypowsybl::ShortCircuitAnalysisParameters::provider_parameters_keys)
.def_readwrite("provider_parameters_values", &pypowsybl::ShortCircuitAnalysisParameters::provider_parameters_values);

m.def("set_default_shortcircuit_analysis_provider", &pypowsybl::setDefaultShortCircuitAnalysisProvider, "Set default short-circuit analysis provider", py::arg("provider"));
m.def("get_default_shortcircuit_analysis_provider", &pypowsybl::getDefaultShortCircuitAnalysisProvider, "Get default short-circuit analysis provider");
m.def("get_shortcircuit_provider_names", &pypowsybl::getShortCircuitAnalysisProviderNames, "Get supported short-circuit analysis providers");
m.def("get_shortcircuit_provider_parameters_names", &pypowsybl::getShortCircuitAnalysisProviderParametersNames, "get provider parameters for a short-circuit analysis provider", py::arg("provider"));
m.def("create_shortcircuit_analysis", &pypowsybl::createShortCircuitAnalysis, "Create a short-circuit analysis");
m.def("run_shortcircuit_analysis", &pypowsybl::runShortCircuitAnalysis, "Run a short-circuit analysis", py::call_guard<py::gil_scoped_release>(),
py::arg("shortcircuit_analysis_context"), py::arg("network"), py::arg("parameters"),
py::arg("provider"), py::arg("reporter"));

py::enum_<ShortCircuitFaultType>(m, "ShortCircuitFaultType")
.value("BUS_FAULT", ShortCircuitFaultType::BUS_FAULT)
.value("BRANCH_FAULT", ShortCircuitFaultType::BRANCH_FAULT);

m.def("get_faults_dataframes_metadata", &pypowsybl::getFaultsMetaData, "Get faults metadata", py::arg("fault_type"));
m.def("set_faults", &pypowsybl::setFaults, "define faults for a short-circuit analysis", py::arg("analysisContext"), py::arg("dataframe"), py::arg("faultType"));
m.def("get_fault_results", &pypowsybl::getFaultResults, "gets the fault results computed after short-circuit analysis",
py::arg("result"));
m.def("get_feeder_results", &pypowsybl::getFeederResults, "gets the feeder results computed after short-circuit analysis",
py::arg("result"));
m.def("get_short_circuit_limit_violations", &pypowsybl::getShortCircuitLimitViolations, "gets the limit violations of a short-circuit analysis", py::arg("result"));

}
18 changes: 18 additions & 0 deletions cpp/src/pypowsybl-api.h
Original file line number Diff line number Diff line change
Expand Up @@ -291,3 +291,21 @@ typedef enum {
ONE = 0,
TWO,
} BranchSide;

typedef struct shortcircuit_analysis_parameters_struct {
unsigned char with_voltage_result;
unsigned char with_feeder_result;
unsigned char with_limit_violations;
int study_type;
unsigned char with_fortescue_result;
double min_voltage_drop_proportional_threshold;
char** provider_parameters_keys;
EtienneLt marked this conversation as resolved.
Show resolved Hide resolved
int provider_parameters_keys_count;
char** provider_parameters_values;
int provider_parameters_values_count;
} shortcircuit_analysis_parameters;

typedef enum {
BUS_FAULT = 0,
BRANCH_FAULT,
} ShortCircuitFaultType;
102 changes: 102 additions & 0 deletions cpp/src/pypowsybl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1339,4 +1339,106 @@ void createNetworkModification(pypowsybl::JavaHandle network, dataframe_array* d
pypowsybl::callJava(::createNetworkModification, network, dataframes, networkModificationType, throwException, (reporter == nullptr) ? nullptr : *reporter);
}

/*---------------------------------SHORT-CIRCUIT ANALYSIS---------------------------*/

void deleteShortCircuitAnalysisParameters(shortcircuit_analysis_parameters* ptr) {
pypowsybl::deleteCharPtrPtr(ptr->provider_parameters_keys, ptr->provider_parameters_keys_count);
pypowsybl::deleteCharPtrPtr(ptr->provider_parameters_values, ptr->provider_parameters_values_count);
}

ShortCircuitAnalysisParameters::ShortCircuitAnalysisParameters(shortcircuit_analysis_parameters* src)
{
with_voltage_result = (bool) src->with_voltage_result;
with_feeder_result = (bool) src->with_feeder_result;
with_limit_violations = (bool) src->with_limit_violations;
study_type = static_cast<ShortCircuitStudyType>(src->study_type);
with_fortescue_result = (bool) src->with_fortescue_result;
with_voltage_result = (bool) src->with_voltage_result;
min_voltage_drop_proportional_threshold = (double) src->min_voltage_drop_proportional_threshold;

copyCharPtrPtrToVector(src->provider_parameters_keys, src->provider_parameters_keys_count, provider_parameters_keys);
copyCharPtrPtrToVector(src->provider_parameters_values, src->provider_parameters_values_count, provider_parameters_values);
}

std::shared_ptr<shortcircuit_analysis_parameters> ShortCircuitAnalysisParameters::to_c_struct() const {
shortcircuit_analysis_parameters* res = new shortcircuit_analysis_parameters();
res->with_voltage_result = (bool) with_voltage_result;
res->with_feeder_result = (bool) with_feeder_result;
res->with_limit_violations = (bool) with_limit_violations;
res->study_type = study_type;
res->with_fortescue_result = (bool) with_fortescue_result;

res->provider_parameters_keys = pypowsybl::copyVectorStringToCharPtrPtr(provider_parameters_keys);
res->provider_parameters_keys_count = provider_parameters_keys.size();
res->provider_parameters_values = pypowsybl::copyVectorStringToCharPtrPtr(provider_parameters_values);
res->provider_parameters_values_count = provider_parameters_values.size();

//Memory has been allocated here on C side, we need to clean it up on C side (not java side)
return std::shared_ptr<shortcircuit_analysis_parameters>(res, [](shortcircuit_analysis_parameters* ptr){
deleteShortCircuitAnalysisParameters(ptr);
delete ptr;
});
}

void setDefaultShortCircuitAnalysisProvider(const std::string& shortCircuitAnalysisProvider) {
callJava<>(::setDefaultShortCircuitAnalysisProvider, (char*) shortCircuitAnalysisProvider.data());
}

std::string getDefaultShortCircuitAnalysisProvider() {
return toString(callJava<char*>(::getDefaultShortCircuitAnalysisProvider));
}

std::vector<std::string> getShortCircuitAnalysisProviderNames() {
auto formatsArrayPtr = callJava<array*>(::getShortCircuitAnalysisProviderNames);
ToStringVector formats(formatsArrayPtr);
return formats.get();
}

std::vector<std::string> getShortCircuitAnalysisProviderParametersNames(const std::string& shortCircuitAnalysisProvider) {
auto providerParametersArrayPtr = pypowsybl::callJava<array*>(::getShortCircuitAnalysisProviderParametersNames, (char*) shortCircuitAnalysisProvider.c_str());
ToStringVector providerParameters(providerParametersArrayPtr);
return providerParameters.get();
}

JavaHandle createShortCircuitAnalysis() {
return callJava<JavaHandle>(::createShortCircuitAnalysis);
}

JavaHandle runShortCircuitAnalysis(const JavaHandle& shortCircuitAnalysisContext, const JavaHandle& network, const ShortCircuitAnalysisParameters& parameters,
const std::string& provider, JavaHandle* reporter) {
auto c_parameters = parameters.to_c_struct();
return callJava<JavaHandle>(::runShortCircuitAnalysis, shortCircuitAnalysisContext, network, c_parameters.get(), (char *) provider.data(), (reporter == nullptr) ? nullptr : *reporter);
}

ShortCircuitAnalysisParameters* createShortCircuitAnalysisParameters() {
shortcircuit_analysis_parameters* parameters_ptr = callJava<shortcircuit_analysis_parameters*>(::createShortCircuitAnalysisParameters);
auto parameters = std::shared_ptr<shortcircuit_analysis_parameters>(parameters_ptr, [](shortcircuit_analysis_parameters* ptr){
callJava(::freeShortCircuitAnalysisParameters, ptr);
});
return new ShortCircuitAnalysisParameters(parameters.get());
}

std::vector<SeriesMetadata> getFaultsMetaData(ShortCircuitFaultType faultType) {
dataframe_metadata* metadata = pypowsybl::callJava<dataframe_metadata*>(::getFaultsDataframeMetaData, faultType);
std::vector<SeriesMetadata> res = convertDataframeMetadata(metadata);
callJava(::freeDataframeMetadata, metadata);
return res;
}

void setFaults(pypowsybl::JavaHandle analysisContext, dataframe* dataframe, ShortCircuitFaultType faultType) {
pypowsybl::callJava<>(::setFaults, analysisContext, faultType, dataframe);
}

SeriesArray* getFaultResults(const JavaHandle& shortCircuitAnalysisResult) {
return new SeriesArray(callJava<array*>(::getFaultResults, shortCircuitAnalysisResult));
}

SeriesArray* getFeederResults(const JavaHandle& shortCircuitAnalysisResult) {
return new SeriesArray(callJava<array*>(::getMagnitudeFeederResults, shortCircuitAnalysisResult));
}

SeriesArray* getShortCircuitLimitViolations(const JavaHandle& shortCircuitAnalysisResult) {
return new SeriesArray(callJava<array*>(::getLimitViolationsResults, shortCircuitAnalysisResult));
}

}
37 changes: 37 additions & 0 deletions cpp/src/pypowsybl.h
Original file line number Diff line number Diff line change
Expand Up @@ -568,5 +568,42 @@ std::vector<SeriesMetadata> getModificationMetadata(network_modification_type ne
std::vector<std::vector<SeriesMetadata>> getModificationMetadataWithElementType(network_modification_type networkModificationType, element_type elementType);

void createNetworkModification(pypowsybl::JavaHandle network, dataframe_array* dataframe, network_modification_type networkModificationType, bool throwException, JavaHandle* reporter);

//=======short-circuit analysis==========
enum ShortCircuitStudyType {
SUB_TRANSIENT = 0,
TRANSIENT,
STEADY_STATE
};

class ShortCircuitAnalysisParameters {
public:
ShortCircuitAnalysisParameters(shortcircuit_analysis_parameters* src);
std::shared_ptr<shortcircuit_analysis_parameters> to_c_struct() const;

bool with_voltage_result;
bool with_feeder_result;
bool with_limit_violations;
ShortCircuitStudyType study_type;
bool with_fortescue_result;
double min_voltage_drop_proportional_threshold;

std::vector<std::string> provider_parameters_keys;
std::vector<std::string> provider_parameters_values;
};

void setDefaultShortCircuitAnalysisProvider(const std::string& shortCircuitAnalysisProvider);
std::string getDefaultShortCircuitAnalysisProvider();
std::vector<std::string> getShortCircuitAnalysisProviderNames();
ShortCircuitAnalysisParameters* createShortCircuitAnalysisParameters();
std::vector<std::string> getShortCircuitAnalysisProviderParametersNames(const std::string& shortCircuitAnalysisProvider);
JavaHandle createShortCircuitAnalysis();
JavaHandle runShortCircuitAnalysis(const JavaHandle& shortCircuitAnalysisContext, const JavaHandle& network, const ShortCircuitAnalysisParameters& parameters, const std::string& provider, JavaHandle* reporter);
std::vector<SeriesMetadata> getFaultsMetaData(ShortCircuitFaultType faultType);
void setFaults(pypowsybl::JavaHandle analysisContext, dataframe* dataframe, ShortCircuitFaultType faultType);
SeriesArray* getFaultResults(const JavaHandle& shortCircuitAnalysisResult);
SeriesArray* getFeederResults(const JavaHandle& shortCircuitAnalysisResult);
SeriesArray* getShortCircuitLimitViolations(const JavaHandle& shortCircuitAnalysisResult);

}
#endif //PYPOWSYBL_H
1 change: 1 addition & 0 deletions docs/reference/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ of pypowsybl classes and methods.
sensitivity
flowdecomposition
dynamic
shortcircuit
59 changes: 59 additions & 0 deletions docs/reference/shortcircuit.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
Short-circuit analysis
======================

.. module:: pypowsybl.shortcircuit


Run a short-circuit analysis
----------------------------

You can run a short-circuit analysis using the following methods:

.. autosummary::
:nosignatures:
:toctree: api/

create_analysis
ShortCircuitAnalysis.run
set_default_provider
get_default_provider
get_provider_names


Parameters
----------

The execution of the short-circuit analysis can be customized using short-circuit analysis parameters.

.. autosummary::
:nosignatures:
:toctree: api/

Parameters


Define faults
-------------

You can define faults to be simulated with the following methods:

.. autosummary::
:nosignatures:
:toctree: api/

ShortCircuitAnalysis.set_faults


Results
-------

When the short-circuit analysis is completed, you can inspect its results:

.. autosummary::
:nosignatures:
:toctree: api/

ShortCircuitAnalysisResult
ShortCircuitAnalysisResult.fault_results
ShortCircuitAnalysisResult.feeder_results
ShortCircuitAnalysisResult.limit_violations
1 change: 1 addition & 0 deletions docs/user_guide/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,4 @@ relying as much as possible on practical examples.
logging
flowdecomposition
dynamic
shortcircuit
43 changes: 43 additions & 0 deletions docs/user_guide/shortcircuit.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
Running a short-circuit analysis
================================

You can use the module :mod:`pypowsybl.shortcircuit` in order to perform a shortcircuit analysis on a network.
Please check out the examples below.

For detailed documentation of involved classes and methods, please refer to the :mod:`API reference <pypowsybl.shortcircuit>`.

Note that, currently, no simulator is integrated in pypowsybl to perform the short-circuit analysis.

Short-circuit analysis
----------------------

The current APIs allow the simulation of three-phased bus faults, where the fault resistance and reactance, when specified, are connected to the ground in series.

colinepiloquet marked this conversation as resolved.
Show resolved Hide resolved
To perform a short-circuit analysis, you need a network and at least a fault to simulate on this network.
The results of the analysis contain the computed current and voltages on the network after the fault, in three-phased magnitude.
Optionally, depending on specific parameters for the simulation, the results contain also

- the contributions of each feeder to the short circuit current (parameter with_feeder_result)
- a list of all the violations after the fault (parameter with_limit_violations)


.. code-block::

>>> import pypowsybl as pp
>>> import pypowsybl.network as pn
>>> import pandas as pd
>>> # create a network
>>> n = pn.create_four_substations_node_breaker_network()
>>> # sets some short-circuit parameters
>>> pars = pp.shortcircuit.Parameters(with_feeder_result = False, with_limit_violations = False, study_type = pp.shortcircuit.ShortCircuitStudyType.TRANSIENT)
>>> # create a short-circuit analysis context
>>> sc = pp.shortcircuit.create_analysis()
>>> # create a bus fault on the first two buses
>>> buses = n.get_buses()
>>> sc.set_faults(id = ['fault_1', 'fault_2'], element_id = [buses.index[0], buses.index[1]], r = [1, 1], x = [2, 2])
>>> # perform the short-circuit analysis
>>> # results = sc.run(n, pars, 'sc_provider_1')
>>> # returns the analysis results
>>> # results.fault_results


4 changes: 4 additions & 0 deletions java/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,10 @@
<groupId>com.powsybl</groupId>
<artifactId>powsybl-flow-decomposition</artifactId>
</dependency>
<dependency>
<groupId>com.powsybl</groupId>
<artifactId>powsybl-shortcircuit-api</artifactId>
</dependency>

<!-- runtime -->
<dependency>
Expand Down