Skip to content

Commit

Permalink
Support for operator strategies in security analysis API (#621)
Browse files Browse the repository at this point in the history
Signed-off-by: Bertrand Rix <bertrand.rix@artelys.com>
  • Loading branch information
obrix committed Jan 18, 2024
1 parent 208ac11 commit 2fb7b5d
Show file tree
Hide file tree
Showing 18 changed files with 809 additions and 62 deletions.
69 changes: 68 additions & 1 deletion cpp/src/bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ void bindArray(py::module_& m, const std::string& className) {
})
.def("__iter__", [](T& a) {
return py::make_iterator(a.begin(), a.end());
}, py::keep_alive<0, 1>())
.def("__getitem__", [](T& a, size_t index) {
if (index >= a.length()) {
throw pypowsybl::PyPowsyblError("Index out of bounds.");
}
return *(a.begin() + index);
}, py::keep_alive<0, 1>());
}

Expand Down Expand Up @@ -509,16 +515,64 @@ PYBIND11_MODULE(_pypowsybl, m) {
m.def("add_contingency", &pypowsybl::addContingency, "Add a contingency to a security analysis or sensitivity analysis",
py::arg("analysis_context"), py::arg("contingency_id"), py::arg("elements_ids"));

m.def("add_load_active_power_action", &pypowsybl::addLoadActivePowerAction, "Add a load active power remedial action",
py::arg("analysis_context"), py::arg("action_id"), py::arg("load_id"), py::arg("is_relative"), py::arg("active_power"));

m.def("add_load_reactive_power_action", &pypowsybl::addLoadReactivePowerAction, "Add a load reactive power remedial action",
py::arg("analysis_context"), py::arg("action_id"), py::arg("load_id"), py::arg("is_relative"), py::arg("reactive_power"));

m.def("add_generator_active_power_action", &pypowsybl::addGeneratorActivePowerAction, "Add a generator active power remedial action",
py::arg("analysis_context"), py::arg("action_id"), py::arg("generator_id"), py::arg("is_relative"), py::arg("active_power"));

m.def("add_switch_action", &pypowsybl::addSwitchAction, "Add a switch action",
py::arg("analysis_context"), py::arg("action_id"), py::arg("switch_id"), py::arg("open"));

m.def("add_phase_tap_changer_position_action", &pypowsybl::addPhaseTapChangerPositionAction, "Add a phase tap changer position action",
py::arg("analysis_context"), py::arg("action_id"), py::arg("transformer_id"), py::arg("is_relative"), py::arg("tap_position"));

m.def("add_ratio_tap_changer_position_action", &pypowsybl::addRatioTapChangerPositionAction, "Add a ratio tap changer position action",
py::arg("analysis_context"), py::arg("action_id"), py::arg("transformer_id"), py::arg("is_relative"), py::arg("tap_position"));

m.def("add_shunt_compensator_position_action", &pypowsybl::addShuntCompensatorPositionAction, "Add a shunt compensator position action",
py::arg("analysis_context"), py::arg("action_id"), py::arg("shunt_id"), py::arg("section_count"));

m.def("add_operator_strategy", &pypowsybl::addOperatorStrategy, "Add an operator strategy",
py::arg("analysis_context"), py::arg("operator_strategy_id"), py::arg("contingency_id"), py::arg("action_ids"),
py::arg("condition_type"), py::arg("subject_ids"), py::arg("violation_types"));

py::enum_<pypowsybl::LimitType>(m, "LimitType")
.value("ACTIVE_POWER", pypowsybl::LimitType::ACTIVE_POWER)
.value("APPARENT_POWER", pypowsybl::LimitType::APPARENT_POWER)
.value("CURRENT", pypowsybl::LimitType::CURRENT)
.value("LOW_VOLTAGE", pypowsybl::LimitType::LOW_VOLTAGE)
.value("HIGH_VOLTAGE", pypowsybl::LimitType::HIGH_VOLTAGE);
.value("HIGH_VOLTAGE", pypowsybl::LimitType::HIGH_VOLTAGE)
.value("LOW_VOLTAGE_ANGLE", pypowsybl::LimitType::LOW_VOLTAGE_ANGLE)
.value("HIGH_VOLTAGE_ANGLE", pypowsybl::LimitType::HIGH_VOLTAGE_ANGLE)
.value("LOW_SHORT_CIRCUIT_CURRENT", pypowsybl::LimitType::LOW_SHORT_CIRCUIT_CURRENT)
.value("HIGH_SHORT_CIRCUIT_CURRENT", pypowsybl::LimitType::HIGH_SHORT_CIRCUIT_CURRENT)
.value("OTHER", pypowsybl::LimitType::OTHER);

py::enum_<pypowsybl::Side>(m, "Side")
.value("NONE", pypowsybl::Side::NONE)
.value("ONE", pypowsybl::Side::ONE)
.value("TWO", pypowsybl::Side::TWO);

py::enum_<violation_type>(m, "ViolationType")
.value("ACTIVE_POWER", violation_type::ACTIVE_POWER)
.value("APPARENT_POWER", violation_type::APPARENT_POWER)
.value("CURRENT", violation_type::CURRENT)
.value("LOW_VOLTAGE", violation_type::LOW_VOLTAGE)
.value("HIGH_VOLTAGE", violation_type::HIGH_VOLTAGE)
.value("LOW_SHORT_CIRCUIT_CURRENT", violation_type::LOW_SHORT_CIRCUIT_CURRENT)
.value("HIGH_SHORT_CIRCUIT_CURRENT", violation_type::HIGH_SHORT_CIRCUIT_CURRENT)
.value("OTHER", violation_type::OTHER);

py::enum_<condition_type>(m, "ConditionType")
.value("TRUE_CONDITION", condition_type::TRUE_CONDITION)
.value("ALL_VIOLATION_CONDITION", condition_type::ALL_VIOLATION_CONDITION)
.value("ANY_VIOLATION_CONDITION", condition_type::ANY_VIOLATION_CONDITION)
.value("AT_LEAST_ONE_VIOLATION_CONDITION", condition_type::AT_LEAST_ONE_VIOLATION_CONDITION);

py::class_<network_metadata, std::shared_ptr<network_metadata>>(m, "NetworkMetadata")
.def_property_readonly("id", [](const network_metadata& att) {
return att.id;
Expand Down Expand Up @@ -579,6 +633,18 @@ PYBIND11_MODULE(_pypowsybl, m) {
});
bindArray<pypowsybl::PostContingencyResultArray>(m, "PostContingencyResultArray");

py::class_<operator_strategy_result>(m, "OperatorStrategyResult")
.def_property_readonly("operator_strategy_id", [](const operator_strategy_result& r) {
return r.operator_strategy_id;
})
.def_property_readonly("status", [](const operator_strategy_result& r) {
return static_cast<pypowsybl::PostContingencyComputationStatus>(r.status);
})
.def_property_readonly("limit_violations", [](const operator_strategy_result& r) {
return pypowsybl::LimitViolationArray((array *) & r.limit_violations);
});
bindArray<pypowsybl::OperatorStrategyResultArray>(m, "OperatorStrategyResultArray");

py::class_<pre_contingency_result>(m, "PreContingencyResult")
.def_property_readonly("status", [](const pre_contingency_result& r) {
return static_cast<pypowsybl::LoadFlowComponentStatus>(r.status);
Expand Down Expand Up @@ -718,6 +784,7 @@ PYBIND11_MODULE(_pypowsybl, m) {

m.def("get_post_contingency_results", &pypowsybl::getPostContingencyResults, "get post contingency results of a security analysis", py::arg("result"));
m.def("get_pre_contingency_result", &pypowsybl::getPreContingencyResult, "get pre contingency result of a security analysis", py::arg("result"));
m.def("get_operator_strategy_results", &pypowsybl::getOperatorStrategyResults, "get operator strategy results of a security analysis", py::arg("result"));
m.def("get_node_breaker_view_nodes", &pypowsybl::getNodeBreakerViewNodes, "get all nodes for a voltage level", py::arg("network"), py::arg("voltage_level"));
m.def("get_node_breaker_view_internal_connections", &pypowsybl::getNodeBreakerViewInternalConnections,
"get all internal connections for a voltage level", py::arg("network"), py::arg("voltage_level"));
Expand Down
24 changes: 24 additions & 0 deletions cpp/src/pypowsybl-api.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,12 @@ typedef struct pre_contingency_result_struct {
array limit_violations;
} pre_contingency_result;

typedef struct operator_strategy_result_struct {
char* operator_strategy_id;
int status;
array limit_violations;
} operator_strategy_result;

typedef enum {
BUS = 0,
LINE,
Expand Down Expand Up @@ -166,6 +172,24 @@ typedef enum {
TWTS3W,
} validation_type;

typedef enum {
ACTIVE_POWER = 0,
APPARENT_POWER,
CURRENT,
LOW_VOLTAGE,
HIGH_VOLTAGE,
LOW_SHORT_CIRCUIT_CURRENT,
HIGH_SHORT_CIRCUIT_CURRENT,
OTHER,
} violation_type;

typedef enum {
TRUE_CONDITION = 0,
ALL_VIOLATION_CONDITION,
ANY_VIOLATION_CONDITION,
AT_LEAST_ONE_VIOLATION_CONDITION,
} condition_type;

typedef enum {
EQUIPMENT = 0,
STEADY_STATE_HYPOTHESIS,
Expand Down
53 changes: 53 additions & 0 deletions cpp/src/pypowsybl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,11 @@ Array<post_contingency_result>::~Array() {
callJava<>(::freeContingencyResultArrayPointer, delegate_);
}

template<>
Array<operator_strategy_result>::~Array() {
callJava<>(::freeOperatorStrategyResultArrayPointer, delegate_);
}

template<>
Array<limit_violation>::~Array() {
// already freed by contingency_result
Expand Down Expand Up @@ -843,6 +848,50 @@ JavaHandle createSensitivityAnalysis() {
return callJava<JavaHandle>(::createSensitivityAnalysis);
}

void addLoadActivePowerAction(const JavaHandle& analysisContext, const std::string& actionId, const std::string& loadId, bool relativeValue, double activePower) {
callJava(::addLoadActivePowerAction, analysisContext, (char*) actionId.data(), (char*) loadId.data(), relativeValue, activePower);
}

void addLoadReactivePowerAction(const JavaHandle& analysisContext, const std::string& actionId, const std::string& loadId, bool relativeValue, double reactivePower) {
callJava(::addLoadReactivePowerAction, analysisContext, (char*) actionId.data(), (char*) loadId.data(), relativeValue, reactivePower);
}

void addGeneratorActivePowerAction(const JavaHandle& analysisContext, const std::string& actionId, const std::string& generatorId, bool relativeValue, double activePower) {
callJava(::addGeneratorActivePowerAction, analysisContext, (char*) actionId.data(), (char*) generatorId.data(), relativeValue, activePower);
}

void addSwitchAction(const JavaHandle& analysisContext, const std::string& actionId, const std::string& switchId, bool open) {
callJava(::addSwitchAction, analysisContext, (char*) actionId.data(), (char*) switchId.data(), open);
}

void addPhaseTapChangerPositionAction(const JavaHandle& analysisContext, const std::string& actionId, const std::string& transformerId,
bool isRelative, int tapPosition) {
callJava(::addPhaseTapChangerPositionAction, analysisContext, (char*) actionId.data(), (char*) transformerId.data(), isRelative, tapPosition);
}

void addRatioTapChangerPositionAction(const JavaHandle& analysisContext, const std::string& actionId, const std::string& transformerId,
bool isRelative, int tapPosition) {
callJava(::addRatioTapChangerPositionAction, analysisContext, (char*) actionId.data(), (char*) transformerId.data(), isRelative, tapPosition);
}

void addShuntCompensatorPositionAction(const JavaHandle& analysisContext, const std::string& actionId, const std::string& shuntId,
int sectionCount) {
callJava(::addShuntCompensatorPositionAction, analysisContext, (char*) actionId.data(), (char*) shuntId.data(), sectionCount);
}

void addOperatorStrategy(const JavaHandle& analysisContext, std::string operatorStrategyId, std::string contingencyId, const std::vector<std::string>& actionsIds,
condition_type conditionType, const std::vector<std::string>& subjectIds, const std::vector<violation_type>& violationTypesFilters) {
ToCharPtrPtr actionsPtr(actionsIds);
ToCharPtrPtr subjectIdsPtr(subjectIds);
std::vector<int> violationTypes;
for(int i = 0; i < violationTypesFilters.size(); ++i) {
violationTypes.push_back(violationTypesFilters[i]);
}
ToIntPtr violationTypesPtr(violationTypes);
callJava(::addOperatorStrategy, analysisContext, (char*) operatorStrategyId.data(), (char*) contingencyId.data(), actionsPtr.get(), actionsIds.size(),
conditionType, subjectIdsPtr.get(), subjectIds.size(), violationTypesPtr.get(), violationTypesFilters.size());
}

::zone* createZone(const std::string& id, const std::vector<std::string>& injectionsIds, const std::vector<double>& injectionsShiftKeys) {
auto z = new ::zone;
z->id = copyStringToCharPtr(id);
Expand Down Expand Up @@ -975,6 +1024,10 @@ PostContingencyResultArray* getPostContingencyResults(const JavaHandle& security
return new PostContingencyResultArray(callJava<array*>(::getPostContingencyResults, securityAnalysisResult));
}

OperatorStrategyResultArray* getOperatorStrategyResults(const JavaHandle& securityAnalysisResult) {
return new OperatorStrategyResultArray(callJava<array*>(::getOperatorStrategyResults, securityAnalysisResult));
}

pre_contingency_result* getPreContingencyResult(const JavaHandle& securityAnalysisResult) {
return callJava<pre_contingency_result*>(::getPreContingencyResult, securityAnalysisResult);
}
Expand Down
29 changes: 28 additions & 1 deletion cpp/src/pypowsybl.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ class Array {

typedef Array<loadflow_component_result> LoadFlowComponentResultArray;
typedef Array<post_contingency_result> PostContingencyResultArray;
typedef Array<operator_strategy_result> OperatorStrategyResultArray;
typedef Array<limit_violation> LimitViolationArray;
typedef Array<series> SeriesArray;

Expand Down Expand Up @@ -111,9 +112,16 @@ enum class PostContingencyComputationStatus {
};

enum LimitType {
CURRENT = 0,
ACTIVE_POWER = 0,
APPARENT_POWER,
CURRENT,
LOW_VOLTAGE,
HIGH_VOLTAGE,
LOW_VOLTAGE_ANGLE,
HIGH_VOLTAGE_ANGLE,
LOW_SHORT_CIRCUIT_CURRENT,
HIGH_SHORT_CIRCUIT_CURRENT,
OTHER
};

enum Side {
Expand Down Expand Up @@ -414,6 +422,23 @@ JavaHandle runSecurityAnalysis(const JavaHandle& securityAnalysisContext, const

JavaHandle createSensitivityAnalysis();

void addLoadActivePowerAction(const JavaHandle& analysisContext, const std::string& actionId, const std::string& loadId, bool relativeValue, double activePower);

void addLoadReactivePowerAction(const JavaHandle& analysisContext, const std::string& actionId, const std::string& loadId, bool relativeValue, double reactivePower);

void addGeneratorActivePowerAction(const JavaHandle& analysisContext, const std::string& actionId, const std::string& generatorId, bool relativeValue, double activePower);

void addSwitchAction(const JavaHandle& analysisContext, const std::string& actionId, const std::string& switchId, bool open);

void addPhaseTapChangerPositionAction(const JavaHandle& analysisContext, const std::string& actionId, const std::string& transformerId, bool isRelative, int tapPosition);

void addRatioTapChangerPositionAction(const JavaHandle& analysisContext, const std::string& actionId, const std::string& transformerId, bool isRelative, int tapPosition);

void addShuntCompensatorPositionAction(const JavaHandle& analysisContext, const std::string& actionId, const std::string& shuntId, int sectionCount);

void addOperatorStrategy(const JavaHandle& analysisContext, std::string operatorStrategyId, std::string contingencyId, const std::vector<std::string>& actionsIds,
condition_type conditionType, const std::vector<std::string>& subjectIds, const std::vector<violation_type>& violationTypesFilters);

void setZones(const JavaHandle& sensitivityAnalysisContext, const std::vector<::zone*>& zones);

void addFactorMatrix(const JavaHandle& sensitivityAnalysisContext, std::string matrixId, const std::vector<std::string>& branchesIds,
Expand Down Expand Up @@ -456,6 +481,8 @@ SeriesArray* getLimitViolations(const JavaHandle& securityAnalysisResult);

PostContingencyResultArray* getPostContingencyResults(const JavaHandle& securityAnalysisResult);

OperatorStrategyResultArray* getOperatorStrategyResults(const JavaHandle& securityAnalysisResult);

pre_contingency_result* getPreContingencyResult(const JavaHandle& securityAnalysisResult);

SeriesArray* getBranchResults(const JavaHandle& securityAnalysisResult);
Expand Down

0 comments on commit 2fb7b5d

Please sign in to comment.