Skip to content

Commit bae3dc5

Browse files
authored
Add JSON file content to ContingencyContainer (#959)
Signed-off-by: Naledi EL CHEIKH <naledi.elcheikh@rte-france.com>
1 parent 0c28385 commit bae3dc5

File tree

13 files changed

+173
-7
lines changed

13 files changed

+173
-7
lines changed

cpp/powsybl-cpp/powsybl-cpp.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -761,6 +761,10 @@ void addContingency(const JavaHandle& analysisContext, const std::string& contin
761761
PowsyblCaller::get()->callJava(::addContingency, analysisContext, (char*) contingencyId.data(), elementIdPtr.get(), elementsIds.size());
762762
}
763763

764+
void addContingencyFromJsonFile(const JavaHandle& analysisContext, const std::string& jsonFilePath) {
765+
PowsyblCaller::get()->callJava(::addContingencyFromJsonFile, analysisContext, (char*) jsonFilePath.data());
766+
}
767+
764768
JavaHandle runSecurityAnalysis(const JavaHandle& securityAnalysisContext, const JavaHandle& network, const SecurityAnalysisParameters& parameters,
765769
const std::string& provider, bool dc, JavaHandle* reportNode) {
766770
auto c_parameters = parameters.to_c_struct();

cpp/powsybl-cpp/powsybl-cpp.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,8 @@ JavaHandle createSecurityAnalysis();
594594

595595
void addContingency(const JavaHandle& analysisContext, const std::string& contingencyId, const std::vector<std::string>& elementsIds);
596596

597+
void addContingencyFromJsonFile(const JavaHandle& analysisContext, const std::string& jsonFilePath);
598+
597599
JavaHandle runSecurityAnalysis(const JavaHandle& securityAnalysisContext, const JavaHandle& network, const SecurityAnalysisParameters& parameters, const std::string& provider, bool dc, JavaHandle* reportNode);
598600

599601
JavaHandle createSensitivityAnalysis();

cpp/pypowsybl-cpp/bindings.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -705,6 +705,9 @@ PYBIND11_MODULE(_pypowsybl, m) {
705705
m.def("add_contingency", &pypowsybl::addContingency, "Add a contingency to a security analysis or sensitivity analysis",
706706
py::arg("analysis_context"), py::arg("contingency_id"), py::arg("elements_ids"));
707707

708+
m.def("add_contingency_from_json_file", &pypowsybl::addContingencyFromJsonFile, "Add contingencies from JSON file.",
709+
py::arg("analysis_context"), py::arg("path_to_json_file"));
710+
708711
m.def("add_load_active_power_action", &pypowsybl::addLoadActivePowerAction, "Add a load active power remedial action",
709712
py::arg("analysis_context"), py::arg("action_id"), py::arg("load_id"), py::arg("is_relative"), py::arg("active_power"));
710713

data/contingencies.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"type" : "default",
3+
"version" : "1.0",
4+
"name" : "list",
5+
"contingencies" : [ {
6+
"id" : "contingency",
7+
"elements" : [ {
8+
"id" : "NHV1_NHV2_1",
9+
"type" : "BRANCH"
10+
}, {
11+
"id" : "NHV1_NHV2_2",
12+
"type" : "BRANCH"
13+
} ]
14+
}, {
15+
"id" : "contingency2",
16+
"elements" : [ {
17+
"id" : "GEN",
18+
"type" : "GENERATOR"
19+
} ]
20+
} ]
21+
}

docs/user_guide/security.rst

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,4 +143,35 @@ The following operator strategy define the application of the switch action 'Swi
143143
>>> df.loc['Breaker contingency', 'OperatorStrategy1', 'LINE_S3S4']['p1'].item()
144144
240.00360040333226
145145

146-
Results for the post remedial action state are available in the branch results indexed with the operator strategy unique id.
146+
Results for the post remedial action state are available in the branch results indexed with the operator strategy unique id.
147+
148+
Adding input data from JSON files
149+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
150+
151+
It is possible to add the input data of a security analysis using JSON files.
152+
For now, only the contingencies can be added this way, using the `add_contingencies_from_json_file` method.
153+
An example of a valid JSON contingency file is the following :
154+
155+
.. code-block:: JSON
156+
157+
{
158+
"type" : "default",
159+
"version" : "1.0",
160+
"name" : "list",
161+
"contingencies" : [ {
162+
"id" : "contingency",
163+
"elements" : [ {
164+
"id" : "NHV1_NHV2_1",
165+
"type" : "BRANCH"
166+
}, {
167+
"id" : "NHV1_NHV2_2",
168+
"type" : "BRANCH"
169+
} ]
170+
}, {
171+
"id" : "contingency2",
172+
"elements" : [ {
173+
"id" : "GEN",
174+
"type" : "GENERATOR"
175+
} ]
176+
} ]
177+
}

java/pypowsybl/src/main/java/com/powsybl/python/contingency/ContingencyContainer.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*/
88
package com.powsybl.python.contingency;
99

10+
import java.nio.file.Path;
1011
import java.util.List;
1112

1213
/**
@@ -15,4 +16,6 @@
1516
public interface ContingencyContainer {
1617

1718
void addContingency(String contingencyId, List<String> elementIds);
19+
20+
void addContingencyFromJsonFile(Path pathToJsonFile);
1821
}

java/pypowsybl/src/main/java/com/powsybl/python/contingency/ContingencyContainerImpl.java

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@
99

1010
import com.powsybl.commons.PowsyblException;
1111
import com.powsybl.contingency.*;
12+
import com.powsybl.contingency.contingency.list.ContingencyList;
1213
import com.powsybl.iidm.network.*;
1314

14-
import java.util.ArrayList;
15-
import java.util.HashMap;
16-
import java.util.List;
17-
import java.util.Map;
15+
import java.nio.file.Files;
16+
import java.nio.file.Path;
17+
import java.util.*;
1818
import java.util.stream.Collectors;
1919

2020
/**
@@ -23,12 +23,18 @@
2323
public class ContingencyContainerImpl implements ContingencyContainer {
2424

2525
private final Map<String, List<String>> elementIdsByContingencyId = new HashMap<>();
26+
private Path pathToContingencyJsonFile = null;
2627

2728
@Override
2829
public void addContingency(String contingencyId, List<String> elementIds) {
2930
elementIdsByContingencyId.put(contingencyId, elementIds);
3031
}
3132

33+
@Override
34+
public void addContingencyFromJsonFile(Path pathToJsonFile) {
35+
pathToContingencyJsonFile = pathToJsonFile;
36+
}
37+
3238
private static ContingencyElement createContingencyElement(Network network, String elementId) {
3339
Identifiable<?> identifiable = network.getIdentifiable(elementId);
3440
if (identifiable == null) {
@@ -67,6 +73,21 @@ private static ContingencyElement createContingencyElement(Network network, Stri
6773

6874
protected List<Contingency> createContingencies(Network network) {
6975
List<Contingency> contingencies = new ArrayList<>(elementIdsByContingencyId.size());
76+
77+
if (pathToContingencyJsonFile != null) {
78+
if (Files.exists(pathToContingencyJsonFile)) {
79+
ContingencyList contingenciesList;
80+
contingenciesList = ContingencyList.load(pathToContingencyJsonFile);
81+
82+
for (Contingency contingency : contingenciesList.getContingencies(network)) {
83+
contingencies.add(new Contingency(contingency.getId(), contingency.getElements()));
84+
}
85+
} else {
86+
throw new PowsyblException("File not found: " + pathToContingencyJsonFile);
87+
}
88+
89+
}
90+
7091
for (Map.Entry<String, List<String>> e : elementIdsByContingencyId.entrySet()) {
7192
String contingencyId = e.getKey();
7293
List<String> elementIds = e.getValue();

java/pypowsybl/src/main/java/com/powsybl/python/security/SecurityAnalysisCFunctions.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
import org.slf4j.Logger;
3939
import org.slf4j.LoggerFactory;
4040

41+
import java.nio.file.Path;
42+
import java.nio.file.Paths;
4143
import java.util.List;
4244
import java.util.Objects;
4345
import java.util.Set;
@@ -136,6 +138,17 @@ public static void addContingency(IsolateThread thread, ObjectHandle contingency
136138
});
137139
}
138140

141+
@CEntryPoint(name = "addContingencyFromJsonFile")
142+
public static void addContingencyFromJsonFile(IsolateThread thread, ObjectHandle contingencyContainerHandle, CCharPointer jsonFilePath,
143+
PyPowsyblApiHeader.ExceptionHandlerPointer exceptionHandlerPtr) {
144+
doCatch(exceptionHandlerPtr, () -> {
145+
ContingencyContainer contingencyContainer = ObjectHandles.getGlobal().get(contingencyContainerHandle);
146+
String stringPath = CTypeUtil.toString(jsonFilePath);
147+
Path path = Paths.get(stringPath);
148+
contingencyContainer.addContingencyFromJsonFile(path);
149+
});
150+
}
151+
139152
private static void setPostContingencyResultInSecurityAnalysisResultPointer(PyPowsyblApiHeader.PostContingencyResultPointer contingencyPtr, PostContingencyResult postContingencyResult) {
140153
contingencyPtr.setContingencyId(CTypeUtil.toCharPtr(postContingencyResult.getContingency().getId()));
141154
contingencyPtr.setStatus(postContingencyResult.getStatus().ordinal());

java/pypowsybl/src/test/java/com/powsybl/python/contingency/ContingencyContainerTest.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,30 @@
77
*/
88
package com.powsybl.python.contingency;
99

10+
import com.google.common.jimfs.Configuration;
11+
import com.google.common.jimfs.Jimfs;
1012
import com.powsybl.contingency.*;
13+
import com.powsybl.iidm.network.Network;
1114
import com.powsybl.iidm.network.test.*;
15+
1216
import org.junit.jupiter.api.Test;
1317

18+
import java.io.IOException;
19+
import java.nio.file.FileSystem;
20+
import java.nio.file.Files;
1421
import java.util.List;
1522

1623
import static org.assertj.core.api.Assertions.assertThat;
1724
import static org.assertj.core.api.Assertions.assertThatThrownBy;
25+
import static org.junit.jupiter.api.Assertions.*;
1826

1927
/**
2028
* @author Yichen TANG {@literal <yichen.tang at rte-france.com>}
2129
*/
2230
class ContingencyContainerTest {
2331

32+
protected FileSystem fileSystem;
33+
2434
@Test
2535
void testContingencyConverter() {
2636
var container1 = new ContingencyContainerImpl();
@@ -89,4 +99,19 @@ void testContingencyConverter() {
8999
.hasOnlyOneElementSatisfying(c -> assertThat(c.getElements().get(0)).isInstanceOf(BatteryContingency.class));
90100
}
91101

102+
@Test
103+
void testToAddContingencyFromJsonFile() throws IOException {
104+
ContingencyContainerImpl container = new ContingencyContainerImpl();
105+
Network network = EurostagTutorialExample1Factory.createWithFixedCurrentLimits();
106+
fileSystem = Jimfs.newFileSystem(Configuration.unix());
107+
108+
Files.copy(getClass().getResourceAsStream("/contingencies.json"), fileSystem.getPath("/contingencies.json"));
109+
container.addContingencyFromJsonFile(fileSystem.getPath("/contingencies.json"));
110+
List<Contingency> contingencies = container.createContingencies(network);
111+
112+
assertFalse(contingencies.isEmpty());
113+
assertEquals(2, contingencies.size());
114+
assertEquals("contingency", contingencies.get(0).getId());
115+
assertEquals("contingency2", contingencies.get(1).getId());
116+
}
92117
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"type" : "default",
3+
"version" : "1.0",
4+
"name" : "list",
5+
"contingencies" : [ {
6+
"id" : "contingency",
7+
"elements" : [ {
8+
"id" : "NHV1_NHV2_1",
9+
"type" : "BRANCH"
10+
}, {
11+
"id" : "NHV1_NHV2_2",
12+
"type" : "BRANCH"
13+
} ]
14+
}, {
15+
"id" : "contingency2",
16+
"elements" : [ {
17+
"id" : "GEN",
18+
"type" : "GENERATOR"
19+
} ]
20+
} ]
21+
}

0 commit comments

Comments
 (0)