Skip to content

Commit

Permalink
add shortcircuit analysis api (#640)
Browse files Browse the repository at this point in the history
adds short-circuit analysis APIs

Signed-off-by: Christian Biasuzzi <christian.biasuzzi@soft.it>
  • Loading branch information
CBiasuzzi authored Sep 13, 2023
1 parent 14c522d commit bf7b7a3
Show file tree
Hide file tree
Showing 26 changed files with 1,458 additions and 7 deletions.
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;
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.

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
Loading

0 comments on commit bf7b7a3

Please sign in to comment.