Skip to content

Commit 8f294c9

Browse files
committed
generate F711
Signed-off-by: Thomas Bouquet <[email protected]>
1 parent b454cf6 commit 8f294c9

File tree

18 files changed

+1082
-1
lines changed

18 files changed

+1082
-1
lines changed

ra-optimisation/search-tree-rao/pom.xml

+4
Original file line numberDiff line numberDiff line change
@@ -122,5 +122,9 @@
122122
<artifactId>mockito-core</artifactId>
123123
<scope>compile</scope>
124124
</dependency>
125+
<dependency>
126+
<groupId>com.powsybl</groupId>
127+
<artifactId>open-rao-crac-io-fb-constraint</artifactId>
128+
</dependency>
125129
</dependencies>
126130
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright (c) 2024, RTE (http://www.rte-france.com)
3+
* This Source Code Form is subject to the terms of the Mozilla Public
4+
* License, v. 2.0. If a copy of the MPL was not distributed with this
5+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
6+
*/
7+
package com.powsybl.openrao.searchtreerao.marmot.f711;
8+
9+
import com.powsybl.openrao.commons.OpenRaoException;
10+
import com.powsybl.openrao.data.crac.io.fbconstraint.xsd.FlowBasedConstraintDocument;
11+
import jakarta.xml.bind.JAXBContext;
12+
import jakarta.xml.bind.JAXBException;
13+
import jakarta.xml.bind.Unmarshaller;
14+
import org.apache.commons.io.IOUtils;
15+
16+
import java.io.ByteArrayInputStream;
17+
import java.io.ByteArrayOutputStream;
18+
import java.io.IOException;
19+
import java.io.InputStream;
20+
21+
/**
22+
* @author Amira Kahya {@literal <amira.kahya at rte-france.com>}
23+
*/
24+
public final class CracUtil {
25+
private CracUtil() {
26+
throw new AssertionError("Utility class should not be constructed");
27+
}
28+
29+
public static FlowBasedConstraintDocument importNativeCrac(InputStream inputStream) {
30+
try {
31+
byte[] bytes = getBytesFromInputStream(inputStream);
32+
JAXBContext jaxbContext = JAXBContext.newInstance(FlowBasedConstraintDocument.class);
33+
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
34+
return (FlowBasedConstraintDocument) jaxbUnmarshaller.unmarshal(new ByteArrayInputStream(bytes));
35+
} catch (JAXBException | IOException e) {
36+
throw new OpenRaoException("Exception occurred during import of native crac", e);
37+
}
38+
}
39+
40+
public static byte[] getBytesFromInputStream(InputStream inputStream) throws IOException {
41+
ByteArrayOutputStream baos = new ByteArrayOutputStream();
42+
IOUtils.copy(inputStream, baos);
43+
return baos.toByteArray();
44+
}
45+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
1+
/*
2+
* Copyright (c) 2023, RTE (http://www.rte-france.com)
3+
* This Source Code Form is subject to the terms of the Mozilla Public
4+
* License, v. 2.0. If a copy of the MPL was not distributed with this
5+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
6+
*/
7+
package com.powsybl.openrao.searchtreerao.marmot.f711;
8+
9+
import com.powsybl.openrao.data.crac.io.fbconstraint.xsd.ComplexVariantsType;
10+
import com.powsybl.openrao.data.crac.io.fbconstraint.xsd.CriticalBranchType;
11+
import com.powsybl.openrao.data.crac.io.fbconstraint.xsd.CriticalBranchesType;
12+
import com.powsybl.openrao.data.crac.io.fbconstraint.xsd.FlowBasedConstraintDocument;
13+
import com.powsybl.openrao.data.crac.io.fbconstraint.xsd.IndependantComplexVariant;
14+
import com.powsybl.openrao.data.crac.io.fbconstraint.xsd.etso.IdentificationType;
15+
import com.powsybl.openrao.data.crac.io.fbconstraint.xsd.etso.MessageDateTimeType;
16+
import com.powsybl.openrao.data.crac.io.fbconstraint.xsd.etso.MessageType;
17+
import com.powsybl.openrao.data.crac.io.fbconstraint.xsd.etso.MessageTypeList;
18+
import com.powsybl.openrao.data.crac.io.fbconstraint.xsd.etso.PartyType;
19+
import com.powsybl.openrao.data.crac.io.fbconstraint.xsd.etso.ProcessType;
20+
import com.powsybl.openrao.data.crac.io.fbconstraint.xsd.etso.ProcessTypeList;
21+
import com.powsybl.openrao.data.crac.io.fbconstraint.xsd.etso.RoleType;
22+
import com.powsybl.openrao.data.crac.io.fbconstraint.xsd.etso.TimeIntervalType;
23+
import com.powsybl.openrao.data.crac.io.fbconstraint.xsd.etso.VersionType;
24+
25+
import javax.xml.datatype.XMLGregorianCalendar;
26+
import java.time.OffsetDateTime;
27+
import java.util.ArrayList;
28+
import java.util.Comparator;
29+
import java.util.HashMap;
30+
import java.util.List;
31+
import java.util.Map;
32+
import java.util.Objects;
33+
34+
/**
35+
* @author Pengbo Wang {@literal <pengbo.wang at rte-international.com>}
36+
* @author Mohamed BenRejeb {@literal <mohamed.ben-rejeb at rte-france.com>}
37+
* @author Philippe Edwards {@literal <philippe.edwards at rte-france.com>}
38+
* @author Godelaine de Montmorillon {@literal <godelaine.demontmorillon at rte-france.com>}
39+
*/
40+
class DailyF711Clusterizer {
41+
42+
private final List<HourlyF711Info> hourlyF711Infos;
43+
private final FlowBasedConstraintDocument flowBasedConstraintDocument;
44+
private static final int DOCUMENT_VERSION = 1;
45+
private static final MessageTypeList DOCUMENT_TYPE = MessageTypeList.B_06;
46+
private static final ProcessTypeList PROCESS_TYPE = ProcessTypeList.A_02;
47+
48+
private static final Comparator<CriticalBranchType> CRITICAL_BRANCH_COMPARATOR =
49+
Comparator.comparing(DailyF711Clusterizer::getOriginalIdOrId)
50+
.thenComparing((CriticalBranchType cb) -> getStartTime(cb.getTimeInterval()))
51+
.thenComparing((CriticalBranchType cb) -> getEndTime(cb.getTimeInterval()));
52+
53+
private static final Comparator<IndependantComplexVariant> COMPLEX_VARIANT_COMPARATOR =
54+
Comparator.comparing(IndependantComplexVariant::getId)
55+
.thenComparing((IndependantComplexVariant icv) -> getStartTime(icv.getTimeInterval()))
56+
.thenComparing((IndependantComplexVariant icv) -> getEndTime(icv.getTimeInterval()));
57+
58+
DailyF711Clusterizer(List<HourlyF711Info> hourlyF711Infos, FlowBasedConstraintDocument flowBasedConstraintDocument) {
59+
this.hourlyF711Infos = hourlyF711Infos;
60+
this.flowBasedConstraintDocument = flowBasedConstraintDocument;
61+
}
62+
63+
FlowBasedConstraintDocument generateClusterizedDocument() {
64+
65+
/*
66+
possible improvement to optimize F303 size: cluster complexVariants with exactly the same RA
67+
*/
68+
69+
List<IndependantComplexVariant> complexVariantsList = getComplexVariants();
70+
List<CriticalBranchType> criticalBranchesList = clusterCriticalBranches();
71+
return generateDailyFbDocument(criticalBranchesList, complexVariantsList);
72+
}
73+
74+
private List<IndependantComplexVariant> getComplexVariants() {
75+
List<IndependantComplexVariant> independentComplexVariants = new ArrayList<>();
76+
for (HourlyF711Info hourlyInfos : hourlyF711Infos) {
77+
independentComplexVariants.addAll(hourlyInfos.getComplexVariants());
78+
}
79+
80+
independentComplexVariants.sort(COMPLEX_VARIANT_COMPARATOR);
81+
82+
return independentComplexVariants;
83+
}
84+
85+
private List<CriticalBranchType> clusterCriticalBranches() {
86+
87+
List<CriticalBranchType> criticalBranchTypeList = new ArrayList<>();
88+
89+
Map<String, List<CriticalBranchType>> criticalBranchesById = arrangeCriticalBranchesById();
90+
for (Map.Entry<String, List<CriticalBranchType>> entry : criticalBranchesById.entrySet()) {
91+
entry.getValue().sort(CRITICAL_BRANCH_COMPARATOR);
92+
}
93+
94+
criticalBranchesById.forEach((key, cbs) -> {
95+
List<CriticalBranchType> mergedCbs = mergeCriticalBranches(cbs);
96+
criticalBranchesById.put(key, mergedCbs);
97+
});
98+
for (List<CriticalBranchType> cbt : criticalBranchesById.values()) {
99+
criticalBranchTypeList.addAll(cbt);
100+
}
101+
102+
criticalBranchTypeList.sort(CRITICAL_BRANCH_COMPARATOR);
103+
return criticalBranchTypeList;
104+
}
105+
106+
private FlowBasedConstraintDocument generateDailyFbDocument(List<CriticalBranchType> criticalBranches, List<IndependantComplexVariant> independentComplexVariants) {
107+
108+
updateHeader(flowBasedConstraintDocument);
109+
flowBasedConstraintDocument.getCriticalBranches().getCriticalBranch().clear();
110+
flowBasedConstraintDocument.getComplexVariants().getComplexVariant().clear();
111+
CriticalBranchesType criticalBranchesType = new CriticalBranchesType();
112+
criticalBranchesType.getCriticalBranch().addAll(criticalBranches);
113+
flowBasedConstraintDocument.setCriticalBranches(criticalBranchesType);
114+
var complexVariantsType = new ComplexVariantsType();
115+
complexVariantsType.getComplexVariant().addAll(independentComplexVariants);
116+
flowBasedConstraintDocument.setComplexVariants(complexVariantsType);
117+
return flowBasedConstraintDocument;
118+
}
119+
120+
private static List<CriticalBranchType> mergeCriticalBranches(List<CriticalBranchType> cbs) {
121+
List<CriticalBranchType> mergedList = new ArrayList<>();
122+
int i = 0;
123+
int j;
124+
while (i < cbs.size()) {
125+
for (j = i + 1; j < cbs.size(); ++j) {
126+
if (canBeMerged(cbs.get(i), cbs.get(j))) {
127+
updateTimeInterval(cbs.get(i), cbs.get(j));
128+
} else {
129+
break;
130+
}
131+
}
132+
mergedList.add(cbs.get(i));
133+
i = j;
134+
}
135+
return mergedList;
136+
}
137+
138+
private static boolean canBeMerged(CriticalBranchType headBranch, CriticalBranchType tailBranch) {
139+
// If they have the same ID
140+
if (!headBranch.getId().equals(tailBranch.getId())) {
141+
return false;
142+
}
143+
144+
// Check that timestamps are consecutive
145+
if (!getEndTime(headBranch.getTimeInterval()).isEqual(getStartTime(tailBranch.getTimeInterval()))) {
146+
return false;
147+
}
148+
149+
// Check that the applied CRAs are the same between the two timestamps
150+
if (headBranch.getComplexVariantId() == null && tailBranch.getComplexVariantId() != null
151+
|| headBranch.getComplexVariantId() != null && tailBranch.getComplexVariantId() == null
152+
|| headBranch.getComplexVariantId() != null && tailBranch.getComplexVariantId() != null && !headBranch.getComplexVariantId().equals(tailBranch.getComplexVariantId())) {
153+
return false;
154+
}
155+
156+
// Check that the branch has not changed between the two timestamps (can occur if it was initially duplicated in the F301)
157+
return areCriticalBranchesEquivalent(headBranch, tailBranch);
158+
}
159+
160+
private Map<String, List<CriticalBranchType>> arrangeCriticalBranchesById() {
161+
Map<String, List<CriticalBranchType>> criticalBranchesById = new HashMap<>();
162+
for (HourlyF711Info hourlyInfos : hourlyF711Infos) {
163+
for (CriticalBranchType cb : hourlyInfos.getCriticalBranches()) {
164+
String cbId = cb.getId();
165+
if (criticalBranchesById.containsKey(cbId)) {
166+
criticalBranchesById.get(cbId).add(cb);
167+
} else {
168+
List<CriticalBranchType> cbs = new ArrayList<>();
169+
cbs.add(cb);
170+
criticalBranchesById.put(cbId, cbs);
171+
}
172+
}
173+
}
174+
return criticalBranchesById;
175+
}
176+
177+
private static void updateHeader(FlowBasedConstraintDocument fbDoc) {
178+
// Identification
179+
IdentificationType identificationType = fbDoc.getDocumentIdentification();
180+
String senderString = fbDoc.getReceiverIdentification().getV();
181+
String dateString = fbDoc.getConstraintTimeInterval().getV().split("/")[1].substring(0, 10).replace("-", "");
182+
String documentId = String.format("%s-%s-F711v%s", senderString, dateString, DOCUMENT_VERSION);
183+
identificationType.setV(documentId);
184+
fbDoc.setDocumentIdentification(identificationType);
185+
186+
// Version & co
187+
VersionType versionType = fbDoc.getDocumentVersion();
188+
versionType.setV(DOCUMENT_VERSION);
189+
fbDoc.setDocumentVersion(versionType);
190+
MessageType messageType = fbDoc.getDocumentType();
191+
messageType.setV(DOCUMENT_TYPE);
192+
fbDoc.setDocumentType(messageType);
193+
ProcessType processType = fbDoc.getProcessType();
194+
processType.setV(PROCESS_TYPE);
195+
fbDoc.setProcessType(processType);
196+
197+
// Invert sender & receiver
198+
PartyType rev = (PartyType) fbDoc.getSenderIdentification().clone();
199+
PartyType sender = (PartyType) fbDoc.getReceiverIdentification().clone();
200+
fbDoc.setReceiverIdentification(rev);
201+
fbDoc.setSenderIdentification(sender);
202+
RoleType revRoleType = (RoleType) fbDoc.getSenderRole().clone();
203+
RoleType senderRoleType = (RoleType) fbDoc.getReceiverRole().clone();
204+
fbDoc.setReceiverRole(revRoleType);
205+
fbDoc.setSenderRole(senderRoleType);
206+
207+
// DateTime
208+
MessageDateTimeType messageDateTimeType = new MessageDateTimeType();
209+
XMLGregorianCalendar xmlGregorianCalendar = XmlOutputsUtil.getXMLGregorianCurrentTime();
210+
messageDateTimeType.setV(xmlGregorianCalendar);
211+
fbDoc.setCreationDateTime(messageDateTimeType);
212+
fbDoc.setConstraintTimeInterval(fbDoc.getConstraintTimeInterval());
213+
fbDoc.setDomain(fbDoc.getDomain());
214+
}
215+
216+
private static void updateTimeInterval(CriticalBranchType headBranch, CriticalBranchType tailBranch) {
217+
OffsetDateTime start = getStartTime(headBranch.getTimeInterval());
218+
OffsetDateTime end = getEndTime(tailBranch.getTimeInterval());
219+
TimeIntervalType timeIntervalType = new TimeIntervalType();
220+
String timeIntervalString = start.toString() + "/" + end.toString();
221+
timeIntervalType.setV(timeIntervalString);
222+
headBranch.setTimeInterval(timeIntervalType);
223+
}
224+
225+
private static OffsetDateTime getStartTime(TimeIntervalType timeIntervalType) {
226+
String[] timeInterval = timeIntervalType.getV().split("/");
227+
return OffsetDateTime.parse(timeInterval[0]);
228+
}
229+
230+
private static OffsetDateTime getEndTime(TimeIntervalType timeIntervalType) {
231+
String[] timeInterval = timeIntervalType.getV().split("/");
232+
return OffsetDateTime.parse(timeInterval[1]);
233+
}
234+
235+
private static String getOriginalIdOrId(CriticalBranchType cb) {
236+
if (!Objects.isNull(cb.getOriginalId())) {
237+
return cb.getOriginalId();
238+
} else {
239+
return cb.getId();
240+
}
241+
}
242+
243+
private static boolean areCriticalBranchesEquivalent(CriticalBranchType cb1, CriticalBranchType cb2) {
244+
return cb1.getBranch().equals(cb2.getBranch())
245+
&& areImaxFactorsEqual(cb1, cb2)
246+
&& areImaxEqual(cb1, cb2)
247+
&& areMinRamFactorEqual(cb1, cb2)
248+
&& areOutageEqual(cb1, cb2)
249+
&& areDirectionEqual(cb1, cb2)
250+
&& areOriginEqual(cb1, cb2)
251+
&& Math.abs(cb1.getFrmMw() - cb2.getFrmMw()) < 1e-6
252+
&& areMnecEqual(cb1, cb2)
253+
&& areCnecEqual(cb1, cb2);
254+
}
255+
256+
private static boolean areCnecEqual(CriticalBranchType cb1, CriticalBranchType cb2) {
257+
return Objects.equals(cb1.isCNEC(), cb2.isCNEC());
258+
}
259+
260+
private static boolean areMnecEqual(CriticalBranchType cb1, CriticalBranchType cb2) {
261+
return Objects.equals(cb1.isMNEC(), cb2.isMNEC());
262+
}
263+
264+
private static boolean areOriginEqual(CriticalBranchType cb1, CriticalBranchType cb2) {
265+
return Objects.equals(cb1.getTsoOrigin(), cb2.getTsoOrigin());
266+
}
267+
268+
private static boolean areDirectionEqual(CriticalBranchType cb1, CriticalBranchType cb2) {
269+
return Objects.equals(cb1.getDirection(), cb2.getDirection());
270+
}
271+
272+
private static boolean areOutageEqual(CriticalBranchType cb1, CriticalBranchType cb2) {
273+
return Objects.equals(cb1.getOutage(), cb2.getOutage());
274+
}
275+
276+
private static boolean areMinRamFactorEqual(CriticalBranchType cb1, CriticalBranchType cb2) {
277+
return cb1.getMinRAMfactor() == null && cb2.getMinRAMfactor() == null || cb1.getMinRAMfactor() != null && cb2.getMinRAMfactor() != null && Math.abs(cb1.getMinRAMfactor().doubleValue() - cb2.getMinRAMfactor().doubleValue()) < 1e-6;
278+
}
279+
280+
private static boolean areImaxEqual(CriticalBranchType cb1, CriticalBranchType cb2) {
281+
return cb1.getImaxA() == null && cb2.getImaxA() == null || cb1.getImaxA() != null && cb2.getImaxA() != null && Math.abs(cb1.getImaxA().doubleValue() - cb2.getImaxA().doubleValue()) < 1e-6;
282+
}
283+
284+
private static boolean areImaxFactorsEqual(CriticalBranchType cb1, CriticalBranchType cb2) {
285+
return cb1.getImaxFactor() == null && cb2.getImaxFactor() == null || cb1.getImaxFactor() != null && cb2.getImaxFactor() != null && Math.abs(cb1.getImaxFactor().doubleValue() - cb2.getImaxFactor().doubleValue()) < 1e-6;
286+
}
287+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Copyright (c) 2023, RTE (http://www.rte-france.com)
3+
* This Source Code Form is subject to the terms of the Mozilla Public
4+
* License, v. 2.0. If a copy of the MPL was not distributed with this
5+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
6+
*/
7+
package com.powsybl.openrao.searchtreerao.marmot.f711;
8+
9+
import com.powsybl.openrao.data.crac.io.fbconstraint.xsd.FlowBasedConstraintDocument;
10+
import org.threeten.extra.Interval;
11+
12+
import java.util.ArrayList;
13+
import java.util.List;
14+
import java.util.Map;
15+
import java.util.Optional;
16+
17+
/**
18+
* @author Pengbo Wang {@literal <pengbo.wang at rte-international.com>}
19+
* @author Mohamed BenRejeb {@literal <mohamed.ben-rejeb at rte-france.com>}
20+
* @author Baptiste Seguinot {@literal <baptiste.seguinot at rte-france.com}
21+
* @author Philippe Edwards {@literal <philippe.edwards at rte-france.com>}
22+
* @author Godelaine de Montmorillon {@literal <godelaine.demontmorillon at rte-france.com>}
23+
* @author Sebastien Murgey {@literal <sebastien.murgey at rte-france.com>}
24+
*/
25+
public final class DailyF711Generator {
26+
27+
private DailyF711Generator() {
28+
throw new AssertionError("Static class. Should not be constructed");
29+
}
30+
31+
public static FlowBasedConstraintDocument generate(DailyF711GeneratorInputsProvider inputsProvider) {
32+
FlowBasedConstraintDocument flowBasedConstraintDocument = inputsProvider.referenceConstraintDocument();
33+
Map<Integer, Interval> positionMap = IntervalUtil.getPositionsMap(flowBasedConstraintDocument.getConstraintTimeInterval().getV());
34+
List<HourlyF711Info> hourlyF711Infos = new ArrayList<>();
35+
positionMap.values().forEach(interval -> {
36+
if (inputsProvider.shouldBeReported(interval)) {
37+
Optional<HourlyF711InfoGenerator.Inputs> optionalInputs = inputsProvider.hourlyF303InputsForInterval(interval);
38+
if (optionalInputs.isPresent()) {
39+
hourlyF711Infos.add(HourlyF711InfoGenerator.getInfoForSuccessfulInterval(flowBasedConstraintDocument, interval, optionalInputs.get()));
40+
} else {
41+
hourlyF711Infos.add(HourlyF711InfoGenerator.getInfoForNonRequestedOrFailedInterval(flowBasedConstraintDocument, interval));
42+
}
43+
}
44+
});
45+
46+
// gather hourly info in one common document, cluster the elements that can be clusterized
47+
return new DailyF711Clusterizer(hourlyF711Infos, flowBasedConstraintDocument).generateClusterizedDocument();
48+
}
49+
}

0 commit comments

Comments
 (0)