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

Support for operator strategies in security analysis API #621

Merged
merged 28 commits into from
Jan 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
b316029
Support first actions and operator strategy.
obrix Jun 28, 2023
d1ca2a4
Support for operator strategy results.
obrix Jun 28, 2023
baf4119
Remove duplicated test.
obrix Jun 28, 2023
8314622
Add condition support and some tests for Load Action with conditions.
obrix Jul 21, 2023
13412e9
Fix type check.
obrix Aug 2, 2023
4ada531
Handle operator strategy branch result and add a switch action test.
obrix Aug 3, 2023
d94b871
Operator strategy result also for bus.
obrix Aug 3, 2023
bcab580
Try updating doc test.
obrix Aug 3, 2023
e0913ab
Merge branch 'main' into sa_operator_strategies
EtienneLt Aug 29, 2023
35d2a81
Merge branch 'main' into sa_operator_strategies
obrix Nov 14, 2023
c1e7caa
Add missing import.
obrix Nov 14, 2023
839cc9b
Clean.
obrix Nov 14, 2023
d0300fd
Clean.
obrix Nov 14, 2023
e562549
Import missing.
obrix Nov 14, 2023
4fd2da1
Merge branch 'main' into sa_operator_strategies
obrix Jan 12, 2024
69d691b
Fix action description.
obrix Jan 12, 2024
acaee26
Basic user guide.
obrix Jan 15, 2024
3e8a01e
Merge branch 'main' into sa_operator_strategies
obrix Jan 15, 2024
5f588e6
Import conditiontype.
obrix Jan 15, 2024
1219ae3
Remove assert.
obrix Jan 15, 2024
70de010
P result.
obrix Jan 15, 2024
ab118bb
Actually use _operator_strategy_result_repr.
obrix Jan 17, 2024
64296ee
Operator strategy in get_table.
obrix Jan 17, 2024
9998f95
Fix broken limit type conversion.
obrix Jan 17, 2024
7ae2bef
Implement getitem for array indexing.
obrix Jan 18, 2024
a61ede9
Get item for all arrays.
obrix Jan 18, 2024
ef6b107
Add assert on get_table.
obrix Jan 18, 2024
96edeef
Dereference return getitem element.
obrix Jan 18, 2024
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
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