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

adds voltage-results parameters to the shortcircuit analysis APIs #650

Merged
merged 7 commits into from
Sep 22, 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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cpp/src/bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -809,5 +809,6 @@ PYBIND11_MODULE(_pypowsybl, m) {
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"));
m.def("get_short_circuit_bus_results", &pypowsybl::getShortCircuitBusResults, "gets the bus results of a short-circuit analysis", py::arg("result"));

}
6 changes: 5 additions & 1 deletion cpp/src/pypowsybl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1348,7 +1348,6 @@ void deleteShortCircuitAnalysisParameters(shortcircuit_analysis_parameters* ptr)

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);
Expand All @@ -1367,6 +1366,7 @@ std::shared_ptr<shortcircuit_analysis_parameters> ShortCircuitAnalysisParameters
res->with_limit_violations = (bool) with_limit_violations;
res->study_type = study_type;
res->with_fortescue_result = (bool) with_fortescue_result;
res->min_voltage_drop_proportional_threshold = min_voltage_drop_proportional_threshold;

res->provider_parameters_keys = pypowsybl::copyVectorStringToCharPtrPtr(provider_parameters_keys);
res->provider_parameters_keys_count = provider_parameters_keys.size();
Expand Down Expand Up @@ -1441,4 +1441,8 @@ SeriesArray* getShortCircuitLimitViolations(const JavaHandle& shortCircuitAnalys
return new SeriesArray(callJava<array*>(::getLimitViolationsResults, shortCircuitAnalysisResult));
}

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

}
1 change: 1 addition & 0 deletions cpp/src/pypowsybl.h
Original file line number Diff line number Diff line change
Expand Up @@ -604,6 +604,7 @@ void setFaults(pypowsybl::JavaHandle analysisContext, dataframe* dataframe, Shor
SeriesArray* getFaultResults(const JavaHandle& shortCircuitAnalysisResult);
SeriesArray* getFeederResults(const JavaHandle& shortCircuitAnalysisResult);
SeriesArray* getShortCircuitLimitViolations(const JavaHandle& shortCircuitAnalysisResult);
SeriesArray* getShortCircuitBusResults(const JavaHandle& shortCircuitAnalysisResult);

}
#endif //PYPOWSYBL_H
1 change: 1 addition & 0 deletions docs/reference/shortcircuit.rst
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,4 @@ When the short-circuit analysis is completed, you can inspect its results:
ShortCircuitAnalysisResult.fault_results
ShortCircuitAnalysisResult.feeder_results
ShortCircuitAnalysisResult.limit_violations
ShortCircuitAnalysisResult.voltage_bus_results
32 changes: 28 additions & 4 deletions java/src/main/java/com/powsybl/python/network/Dataframes.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,12 @@
import com.powsybl.python.security.LimitViolationContext;
import com.powsybl.python.security.ThreeWindingsTransformerResultContext;
import com.powsybl.python.shortcircuit.LimitViolationFaultContext;
import com.powsybl.python.shortcircuit.MagnitudeBusResultsContext;
import com.powsybl.python.shortcircuit.MagnitudeFeederResultContext;
import com.powsybl.security.LimitViolation;
import com.powsybl.security.LimitViolationType;
import com.powsybl.security.SecurityAnalysisResult;
import com.powsybl.shortcircuit.FaultResult;
import com.powsybl.shortcircuit.MagnitudeFaultResult;
import com.powsybl.shortcircuit.MagnitudeFeederResult;
import com.powsybl.shortcircuit.ShortCircuitAnalysisResult;
import com.powsybl.shortcircuit.*;
import org.apache.commons.collections4.IteratorUtils;
import org.apache.commons.lang3.tuple.Pair;

Expand Down Expand Up @@ -543,4 +541,30 @@ private static DataframeMapper<ShortCircuitAnalysisResult> createMagnitudeFeeder
.build();
}

public static DataframeMapper<ShortCircuitAnalysisResult> shortCircuitAnalysisMagnitudeBusResultsMapper() {
return SHORT_CIRCUIT_MAGNITUDE_BUS_RESULTS_MAPPER;
}

private static final DataframeMapper<ShortCircuitAnalysisResult> SHORT_CIRCUIT_MAGNITUDE_BUS_RESULTS_MAPPER = createMagnitudeBusResultsFaultMapper();

public static List<MagnitudeBusResultsContext> getMagnitudeBusResultsContexts(ShortCircuitAnalysisResult result) {
List<MagnitudeBusResultsContext> busResults = result.getFaultResults().stream()
.flatMap(a -> a.getShortCircuitBusResults()
.stream()
.map(ss -> new MagnitudeBusResultsContext(a.getFault().getId(), (MagnitudeShortCircuitBusResults) ss)))
.collect(Collectors.toList());
return busResults;
}

private static DataframeMapper<ShortCircuitAnalysisResult> createMagnitudeBusResultsFaultMapper() {
return new DataframeMapperBuilder<ShortCircuitAnalysisResult, MagnitudeBusResultsContext>()
.itemsProvider(Dataframes::getMagnitudeBusResultsContexts)
.stringsIndex("id", MagnitudeBusResultsContext::getFaultId)
.stringsIndex("voltage_level_id", MagnitudeBusResultsContext::getVoltageLevelId)
.stringsIndex("bus_id", MagnitudeBusResultsContext::getBusId)
.doubles("initial_voltage_magnitude", MagnitudeBusResultsContext::getInitialVoltageMagnitude)
.doubles("voltage_drop_proportional", MagnitudeBusResultsContext::getVoltageDropProportional)
.doubles("voltage", MagnitudeBusResultsContext::getVoltage)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* Copyright (c) 2023, RTE (http://www.rte-france.com)
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
* SPDX-License-Identifier: MPL-2.0
*/
package com.powsybl.python.shortcircuit;

import com.powsybl.shortcircuit.MagnitudeShortCircuitBusResults;

import java.util.Objects;

/**
* @author Christian Biasuzzi <christian.biasuzzi@soft.it>
*/
public class MagnitudeBusResultsContext extends MagnitudeShortCircuitBusResults {

private final String faultId;

public MagnitudeBusResultsContext(String faultId, MagnitudeShortCircuitBusResults busResults) {
super(busResults.getVoltageLevelId(), busResults.getBusId(), busResults.getInitialVoltageMagnitude(), busResults.getVoltage(), busResults.getVoltageDropProportional());
this.faultId = Objects.requireNonNull(faultId);
}

public String getFaultId() {
return faultId;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -188,4 +188,12 @@ public static PyPowsyblApiHeader.ArrayPointer<PyPowsyblApiHeader.SeriesPointer>
return Dataframes.createCDataframe(Dataframes.shortCircuitAnalysisLimitViolationsResultsMapper(), result);
});
}

@CEntryPoint(name = "getMagnitudeBusResults")
public static PyPowsyblApiHeader.ArrayPointer<PyPowsyblApiHeader.SeriesPointer> getMagnitudeBusResults(IsolateThread thread, ObjectHandle shortCircuitAnalysisResult, PyPowsyblApiHeader.ExceptionHandlerPointer exceptionHandlerPtr) {
return doCatch(exceptionHandlerPtr, () -> {
ShortCircuitAnalysisResult result = ObjectHandles.getGlobal().get(shortCircuitAnalysisResult);
return Dataframes.createCDataframe(Dataframes.shortCircuitAnalysisMagnitudeBusResultsMapper(), result);
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,11 @@ void testShortCircuitAnalysisResults() {
MagnitudeFeederResult mfr1 = new MagnitudeFeederResult("connect1", 1.1);
MagnitudeFeederResult mfr2 = new MagnitudeFeederResult("connect2", 1.2);

FaultResult fr1 = new MagnitudeFaultResult(f1, 1.0, List.of(mfr1, mfr2), List.of(lv1, lv2), 5.0, FaultResult.Status.SUCCESS);
FaultResult fr2 = new MagnitudeFaultResult(f2, 2.0, Collections.emptyList(), List.of(lv3, lv4, lv5), 6.0, FaultResult.Status.SUCCESS);
MagnitudeShortCircuitBusResults mbr1 = new MagnitudeShortCircuitBusResults("VL1", "bus1", 10.0, 8.0, 20.0);
MagnitudeShortCircuitBusResults mbr2 = new MagnitudeShortCircuitBusResults("VL2", "bus2", 15.0, 13.5, 10.0);

FaultResult fr1 = new MagnitudeFaultResult(f1, 1.0, List.of(mfr1, mfr2), List.of(lv1, lv2), 5.0, List.of(mbr1), null, FaultResult.Status.SUCCESS);
FaultResult fr2 = new MagnitudeFaultResult(f2, 2.0, Collections.emptyList(), List.of(lv3, lv4, lv5), 6.0, List.of(mbr2), null, FaultResult.Status.SUCCESS);

ShortCircuitAnalysisResult fakeResults = new ShortCircuitAnalysisResult(List.of(fr1, fr2));

Expand Down Expand Up @@ -105,5 +108,22 @@ void testShortCircuitAnalysisResults() {
.containsExactly("f1", "f1", "f2", "f2", "f2");
Assertions.assertThat(limitViolationsSeries.get(1).getStrings())
.containsExactly("subj1", "subj2", "subj3", "subj4", "subj5");

List<Series> busResultsSeries = Dataframes.createSeries(Dataframes.shortCircuitAnalysisMagnitudeBusResultsMapper(), fakeResults);
Assertions.assertThat(busResultsSeries)
.extracting(Series::getName)
.containsExactly("id", "voltage_level_id", "bus_id", "initial_voltage_magnitude", "voltage_drop_proportional", "voltage");
Assertions.assertThat(busResultsSeries.get(0).getStrings())
.containsExactly("f1", "f2");
Assertions.assertThat(busResultsSeries.get(1).getStrings())
.containsExactly("VL1", "VL2");
Assertions.assertThat(busResultsSeries.get(2).getStrings())
.containsExactly("bus1", "bus2");
Assertions.assertThat(busResultsSeries.get(3).getDoubles())
.containsExactly(10.0, 15.0);
Assertions.assertThat(busResultsSeries.get(4).getDoubles())
.containsExactly(20.0, 10.0);
Assertions.assertThat(busResultsSeries.get(5).getDoubles())
.containsExactly(8.0, 13.5);
}
}
1 change: 1 addition & 0 deletions pypowsybl/_pypowsybl.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,7 @@ def set_faults(short_circuit_analysis: JavaHandle, dfs: Optional[Dataframe], fau
def get_fault_results(result: JavaHandle) -> SeriesArray: ...
def get_feeder_results(result: JavaHandle) -> SeriesArray: ...
def get_short_circuit_limit_violations(result: JavaHandle) -> SeriesArray: ...
def get_short_circuit_bus_results(result: JavaHandle) -> SeriesArray: ...
def get_faults_dataframes_metadata(faultType: ShortCircuitFaultType) -> List[SeriesMetadata]: ...
def run_shortcircuit_analysis(context: JavaHandle, network: JavaHandle, parameters: ShortCircuitAnalysisParameters, provider: str, reporter: Optional[JavaHandle]) -> JavaHandle: ...
def create_shortcircuit_analysis() -> JavaHandle: ...
Expand Down
18 changes: 16 additions & 2 deletions pypowsybl/shortcircuit/impl/parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,27 @@ class Parameters: # pylint: disable=too-few-public-methods
Args:
with_feeder_result: indicates if the contributions of each feeder to the short circuit current at the fault node should be computed
with_limit_violations: indicates whether limit violations should be returned after the computation
with_voltage_result: indicates if the voltage profile should be computed on every node of the network
min_voltage_drop_proportional_threshold: indicates a threshold to filter the voltage results. Only nodes where the voltage drop due to the short circuit is greater than this property are retained
study_type: indicates the type of short circuit study. It can be SUB_TRANSIENT, TRANSIENT or STEADY_STATE
"""

def __init__(self,
with_feeder_result: bool = None,
with_limit_violations: bool = None,
with_voltage_result: bool = None,
min_voltage_drop_proportional_threshold: float = None,
study_type: ShortCircuitStudyType = None,
provider_parameters: Dict[str, str] = None):
self._init_with_default_values()
if with_feeder_result is not None:
self.with_feeder_result = with_feeder_result
if with_limit_violations is not None:
self.with_limit_violations = with_limit_violations
if with_voltage_result is not None:
self.with_voltage_result = with_voltage_result
if min_voltage_drop_proportional_threshold is not None:
self.min_voltage_drop_proportional_threshold = min_voltage_drop_proportional_threshold
if study_type is not None:
self.study_type = study_type
if provider_parameters is not None:
Expand All @@ -45,6 +53,8 @@ def __init__(self,
def _init_from_c(self, c_parameters: _pypowsybl.ShortCircuitAnalysisParameters) -> None:
self.with_feeder_result = c_parameters.with_feeder_result
self.with_limit_violations = c_parameters.with_limit_violations
self.with_voltage_result = c_parameters.with_voltage_result
self.min_voltage_drop_proportional_threshold = c_parameters.min_voltage_drop_proportional_threshold
self.study_type = c_parameters.study_type
self.provider_parameters = dict(
zip(c_parameters.provider_parameters_keys, c_parameters.provider_parameters_values))
Expand All @@ -53,16 +63,18 @@ def _init_with_default_values(self) -> None:
self._init_from_c(_pypowsybl.ShortCircuitAnalysisParameters())
self.with_feeder_result = False
self.with_limit_violations = False
self.with_voltage_result = False
self.min_voltage_drop_proportional_threshold = 0
self.study_type = ShortCircuitStudyType.TRANSIENT

def _to_c_parameters(self) -> _pypowsybl.ShortCircuitAnalysisParameters:
c_parameters = _pypowsybl.ShortCircuitAnalysisParameters()
c_parameters.with_voltage_result = False
c_parameters.with_voltage_result = self.with_voltage_result
c_parameters.with_feeder_result = self.with_feeder_result
c_parameters.with_limit_violations = self.with_limit_violations
c_parameters.study_type = self.study_type
c_parameters.with_fortescue_result = False
c_parameters.min_voltage_drop_proportional_threshold = 0
c_parameters.min_voltage_drop_proportional_threshold = self.min_voltage_drop_proportional_threshold
c_parameters.provider_parameters_keys = []
c_parameters.provider_parameters_values = []
return c_parameters
Expand All @@ -71,5 +83,7 @@ def __repr__(self) -> str:
return f"{self.__class__.__name__}(" \
f"with_feeder_result={self.with_feeder_result!r}" \
f", with_limit_violations={self.with_limit_violations!r}" \
f", with_voltage_result={self.with_voltage_result!r}" \
f", min_voltage_drop_proportional_threshold={self.min_voltage_drop_proportional_threshold!r}" \
f", study_type={self.study_type!r}" \
f")"
4 changes: 1 addition & 3 deletions pypowsybl/shortcircuit/impl/short_circuit_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,5 @@ def run(self, network: Network, parameters: Parameters = None,

return ShortCircuitAnalysisResult(
_pypowsybl.run_shortcircuit_analysis(self._handle, network._handle, p, provider,
None if reporter is None else reporter._reporter_model)
# pylint: disable=protected-access
# pylint: disable=protected-access
None if reporter is None else reporter._reporter_model) # pylint: disable=protected-access
)
8 changes: 8 additions & 0 deletions pypowsybl/shortcircuit/impl/short_circuit_analysis_result.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,11 @@ def limit_violations(self) -> pd.DataFrame:
contains a list of all the violations after the fault, in a dataframe representation.
"""
return create_data_frame_from_series_array(_pypowsybl.get_short_circuit_limit_violations(self._handle))

@property
def voltage_bus_results(self) -> pd.DataFrame:
"""
contains a list of all the short circuit voltage bus results, in a dataframe representation.
It should be empty when the parameter with_voltage_result is set to false
"""
return create_data_frame_from_series_array(_pypowsybl.get_short_circuit_bus_results(self._handle))
3 changes: 3 additions & 0 deletions tests/test_shortcircuit_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,13 @@ def test_run_analysis():

# sets some short-circuit parameters
pars = pp.shortcircuit.Parameters(with_feeder_result = False, with_limit_violations = False,
with_voltage_result = False, min_voltage_drop_proportional_threshold = 0,
study_type = pp.shortcircuit.ShortCircuitStudyType.TRANSIENT)
assert pars is not None
assert pars.with_feeder_result == False
assert pars.with_limit_violations == False
assert pars.with_voltage_result == False
assert pars.min_voltage_drop_proportional_threshold == 0
assert pars.study_type == pp.shortcircuit.ShortCircuitStudyType.TRANSIENT

# create a short-circuit analysis context
Expand Down