Skip to content

Commit 2a0eff6

Browse files
phiedwGodelaine
andauthored
[WIP] IDCC - Fast MIP (#1313)
* run mips iteratively on bigger set of cnecs, import ics glsk Signed-off-by: Philippe Edwards <philippe.edwards@rte-france.com> * optimize a bit FastRAO for costly Signed-off-by: Philippe Edwards <philippe.edwards@rte-france.com> * added comments in Marmot Signed-off-by: Philippe Edwards <philippe.edwards@rte-france.com> * added a few more comments Signed-off-by: Philippe Edwards <philippe.edwards@rte-france.com> * removed system out println from fast rao Signed-off-by: Philippe Edwards <philippe.edwards@rte-france.com> * create postIcs directory Signed-off-by: Godelaine de Montmorillon <godelaine.demontmorillon@rte-france.com> * made some changes for setpoint results to get from postTopo rather than initial (which was failing) Signed-off-by: Philippe Edwards <philippe.edwards@rte-france.com> * fix copied Signed-off-by: Godelaine de Montmorillon <godelaine.demontmorillon@rte-france.com> * comments Signed-off-by: Godelaine de Montmorillon <godelaine.demontmorillon@rte-france.com> * adapt tests to parameter change Signed-off-by: Godelaine de Montmorillon <godelaine.demontmorillon@rte-france.com> --------- Signed-off-by: Philippe Edwards <philippe.edwards@rte-france.com> Signed-off-by: Godelaine de Montmorillon <godelaine.demontmorillon@rte-france.com> Co-authored-by: Godelaine de Montmorillon <godelaine.demontmorillon@rte-france.com>
1 parent 4d79e67 commit 2a0eff6

19 files changed

Lines changed: 563 additions & 242 deletions

File tree

ra-optimisation/rao-api/src/main/java/com/powsybl/openrao/raoapi/IcsImporter.java

Lines changed: 132 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,19 @@ public final class IcsImporter {
2424
private static final int OFFSET = 2;
2525
private static final double COST_UP = 10;
2626
private static final double COST_DOWN = 10;
27-
private static final double ACTIVATION_COST = 50;
27+
private static final String MAX_GRADIENT = "1000";
2828

29-
//TODO:QUALITY CHECK: do PO respect constraints?
29+
// TODO:QUALITY CHECK: do PO respect constraints?
30+
// TODO:QUALITY CHECK: consistency between gsks defined in static file + gsk file
31+
32+
// INFOS
33+
// Gradient constraints are defined for gsks à la maille parade, et pas par générateur : on applique donc le shift key au Pmax/Pmin
3034

3135
private IcsImporter() {
3236
//should only be used statically
3337
}
3438

35-
public static void populateInputWithICS(InterTemporalRaoInputWithNetworkPaths interTemporalRaoInput, InputStream staticInputStream, InputStream seriesInputStream) throws IOException {
39+
public static void populateInputWithICS(InterTemporalRaoInputWithNetworkPaths interTemporalRaoInput, InputStream staticInputStream, InputStream seriesInputStream, InputStream gskInputStream) throws IOException {
3640
TemporalData<Network> initialNetworks = new TemporalDataImpl<>();
3741
interTemporalRaoInput.getRaoInputs().getDataPerTimestamp().forEach((dateTime, raoInput) ->
3842
initialNetworks.add(dateTime, Network.read(raoInput.getInitialNetworkPath()))
@@ -51,54 +55,25 @@ public static void populateInputWithICS(InterTemporalRaoInputWithNetworkPaths in
5155
seriesPerIdAndType.get(record.get("RA RD ID")).put(record.get("Type of timeseries"), record);
5256
});
5357

58+
Map<String, Map<String, Double>> weightPerNodePerGsk = new HashMap<>();
59+
if (gskInputStream != null) {
60+
Iterable<CSVRecord> gskCsvRecords = csvFormat.parse(new InputStreamReader(gskInputStream));
61+
gskCsvRecords.forEach(record -> {
62+
weightPerNodePerGsk.putIfAbsent(record.get("GSK ID"), new HashMap<>());
63+
weightPerNodePerGsk.get(record.get("GSK ID")).put(record.get("Node"), Double.parseDouble(record.get("Weight")));
64+
});
65+
}
66+
5467
staticCsvRecords.forEach(staticRecord -> {
55-
if (shouldBeImported(staticRecord)) {
68+
if (shouldBeImported(staticRecord, weightPerNodePerGsk)) {
5669
String raId = staticRecord.get("RA RD ID");
5770
Map<String, CSVRecord> seriesPerType = seriesPerIdAndType.get(raId);
5871
if (seriesPerType != null && seriesPerType.containsKey("P0") && seriesPerType.containsKey("RDP-") && seriesPerType.containsKey("RDP+") && p0RespectsGradients(staticRecord, seriesPerType.get("P0"), interTemporalRaoInput.getTimestampsToRun())) {
59-
String networkElement = processNetworks(staticRecord.get("UCT Node or GSK ID"), initialNetworks, seriesPerType);
60-
if (networkElement == null) {
61-
return;
72+
if (staticRecord.get("RD description mode").equalsIgnoreCase("NODE")) {
73+
importNodeRedispatchingAction(interTemporalRaoInput, staticRecord, initialNetworks, seriesPerType, raId);
74+
} else {
75+
importGskRedispatchingAction(interTemporalRaoInput, staticRecord, initialNetworks, seriesPerType, raId, weightPerNodePerGsk.get(staticRecord.get("UCT Node or GSK ID")));
6276
}
63-
interTemporalRaoInput.getRaoInputs().getDataPerTimestamp().forEach((dateTime, raoInput) -> {
64-
Crac crac = raoInput.getCrac();
65-
double p0 = Double.parseDouble(seriesPerType.get("P0").get(dateTime.getHour() + OFFSET));
66-
InjectionRangeActionAdder injectionRangeActionAdder = crac.newInjectionRangeAction()
67-
.withId(raId + "_RD")
68-
.withName(staticRecord.get("Generator Name"))
69-
.withNetworkElement(networkElement)
70-
.withInitialSetpoint(p0)
71-
.withVariationCost(COST_UP, VariationDirection.UP)
72-
.withVariationCost(COST_DOWN, VariationDirection.DOWN)
73-
//.withActivationCost(ACTIVATION_COST)
74-
.newRange()
75-
.withMin(p0 - Double.parseDouble(seriesPerType.get("RDP-").get(dateTime.getHour() + OFFSET)))
76-
.withMax(p0 + Double.parseDouble(seriesPerType.get("RDP+").get(dateTime.getHour() + OFFSET)))
77-
.add();
78-
if (staticRecord.get("Preventive").equals("TRUE")) {
79-
injectionRangeActionAdder.newOnInstantUsageRule()
80-
.withInstant(crac.getPreventiveInstant().getId())
81-
.withUsageMethod(UsageMethod.AVAILABLE)
82-
.add();
83-
}
84-
/*if (staticRecord.get("Curative").equals("TRUE")) {
85-
injectionRangeActionAdder.newOnInstantUsageRule()
86-
.withInstant(crac.getLastInstant().getId())
87-
.withUsageMethod(UsageMethod.AVAILABLE)
88-
.add();
89-
}*/
90-
injectionRangeActionAdder.add();
91-
92-
});
93-
94-
PowerGradient powerGradient = PowerGradient.builder()
95-
.withNetworkElementId(networkElement)
96-
.withMaxValue(Double.parseDouble(
97-
staticRecord.get("Maximum positive power gradient [MW/h]").isEmpty() ? "1000" : staticRecord.get("Maximum positive power gradient [MW/h]")
98-
)).withMinValue(-Double.parseDouble(
99-
staticRecord.get("Maximum negative power gradient [MW/h]").isEmpty() ? "1000" : staticRecord.get("Maximum negative power gradient [MW/h]")
100-
)).build();
101-
interTemporalRaoInput.getPowerGradients().add(powerGradient);
10277
}
10378
}
10479
});
@@ -107,14 +82,117 @@ public static void populateInputWithICS(InterTemporalRaoInputWithNetworkPaths in
10782
initialNetwork.write("JIIDM", new Properties(), Path.of(interTemporalRaoInput.getRaoInputs().getData(dateTime).orElseThrow().getPostIcsImportNetworkPath())));
10883
}
10984

110-
private static String processNetworks(String uctNodeOrGskId, TemporalData<Network> initialNetworks, Map<String, CSVRecord> seriesPerType) {
111-
String generatorId = seriesPerType.get("P0").get("RA RD ID") + "_GENERATOR";
85+
private static void importGskRedispatchingAction(InterTemporalRaoInputWithNetworkPaths interTemporalRaoInput, CSVRecord staticRecord, TemporalData<Network> initialNetworks, Map<String, CSVRecord> seriesPerType, String raId, Map<String, Double> weightPerNode) {
86+
Map<String, String> networkElementPerGskElement = new HashMap<>();
87+
for (String nodeId : weightPerNode.keySet()) {
88+
String networkElementId = processNetworks(nodeId, initialNetworks, seriesPerType, weightPerNode.get(nodeId));
89+
if (networkElementId == null) {
90+
return;
91+
}
92+
networkElementPerGskElement.put(nodeId, networkElementId);
93+
}
94+
95+
interTemporalRaoInput.getRaoInputs().getDataPerTimestamp().forEach((dateTime, raoInput) -> {
96+
Crac crac = raoInput.getCrac();
97+
double p0 = Double.parseDouble(seriesPerType.get("P0").get(dateTime.getHour() + OFFSET));
98+
InjectionRangeActionAdder injectionRangeActionAdder = crac.newInjectionRangeAction()
99+
.withId(raId + "_RD")
100+
.withName(staticRecord.get("Generator Name"))
101+
.withInitialSetpoint(p0)
102+
.withVariationCost(COST_UP, VariationDirection.UP)
103+
.withVariationCost(COST_DOWN, VariationDirection.DOWN)
104+
//.withActivationCost(ACTIVATION_COST)
105+
.newRange()
106+
.withMin(p0 - Double.parseDouble(seriesPerType.get("RDP-").get(dateTime.getHour() + OFFSET)))
107+
.withMax(p0 + Double.parseDouble(seriesPerType.get("RDP+").get(dateTime.getHour() + OFFSET)))
108+
.add();
109+
110+
weightPerNode.forEach((nodeId, shiftKey) -> {
111+
injectionRangeActionAdder.withNetworkElementAndKey(shiftKey, networkElementPerGskElement.get(nodeId));
112+
});
113+
114+
if (staticRecord.get("Preventive").equals("TRUE")) {
115+
injectionRangeActionAdder.newOnInstantUsageRule()
116+
.withInstant(crac.getPreventiveInstant().getId())
117+
.withUsageMethod(UsageMethod.AVAILABLE)
118+
.add();
119+
}
120+
/*if (staticRecord.get("Curative").equals("TRUE")) {
121+
injectionRangeActionAdder.newOnInstantUsageRule()
122+
.withInstant(crac.getLastInstant().getId())
123+
.withUsageMethod(UsageMethod.AVAILABLE)
124+
.add();
125+
}*/
126+
injectionRangeActionAdder.add();
127+
128+
});
129+
130+
weightPerNode.forEach((nodeId, shiftKey) -> {
131+
PowerGradient powerGradient = PowerGradient.builder()
132+
.withNetworkElementId(networkElementPerGskElement.get(nodeId))
133+
.withMaxValue(shiftKey * Double.parseDouble(
134+
staticRecord.get("Maximum positive power gradient [MW/h]").isEmpty() ? MAX_GRADIENT : staticRecord.get("Maximum positive power gradient [MW/h]")
135+
)).withMinValue(-shiftKey * Double.parseDouble(
136+
staticRecord.get("Maximum negative power gradient [MW/h]").isEmpty() ? MAX_GRADIENT : staticRecord.get("Maximum negative power gradient [MW/h]")
137+
)).build();
138+
interTemporalRaoInput.getPowerGradients().add(powerGradient);
139+
});
140+
}
141+
142+
private static void importNodeRedispatchingAction(InterTemporalRaoInputWithNetworkPaths interTemporalRaoInput, CSVRecord staticRecord, TemporalData<Network> initialNetworks, Map<String, CSVRecord> seriesPerType, String raId) {
143+
String networkElementId = processNetworks(staticRecord.get("UCT Node or GSK ID"), initialNetworks, seriesPerType, 1.);
144+
if (networkElementId == null) {
145+
return;
146+
}
147+
interTemporalRaoInput.getRaoInputs().getDataPerTimestamp().forEach((dateTime, raoInput) -> {
148+
Crac crac = raoInput.getCrac();
149+
double p0 = Double.parseDouble(seriesPerType.get("P0").get(dateTime.getHour() + OFFSET));
150+
InjectionRangeActionAdder injectionRangeActionAdder = crac.newInjectionRangeAction()
151+
.withId(raId + "_RD")
152+
.withName(staticRecord.get("Generator Name"))
153+
.withNetworkElement(networkElementId)
154+
.withInitialSetpoint(p0)
155+
.withVariationCost(COST_UP, VariationDirection.UP)
156+
.withVariationCost(COST_DOWN, VariationDirection.DOWN)
157+
//.withActivationCost(ACTIVATION_COST)
158+
.newRange()
159+
.withMin(p0 - Double.parseDouble(seriesPerType.get("RDP-").get(dateTime.getHour() + OFFSET)))
160+
.withMax(p0 + Double.parseDouble(seriesPerType.get("RDP+").get(dateTime.getHour() + OFFSET)))
161+
.add();
162+
if (staticRecord.get("Preventive").equals("TRUE")) {
163+
injectionRangeActionAdder.newOnInstantUsageRule()
164+
.withInstant(crac.getPreventiveInstant().getId())
165+
.withUsageMethod(UsageMethod.AVAILABLE)
166+
.add();
167+
}
168+
/*if (staticRecord.get("Curative").equals("TRUE")) {
169+
injectionRangeActionAdder.newOnInstantUsageRule()
170+
.withInstant(crac.getLastInstant().getId())
171+
.withUsageMethod(UsageMethod.AVAILABLE)
172+
.add();
173+
}*/
174+
injectionRangeActionAdder.add();
175+
176+
});
177+
178+
PowerGradient powerGradient = PowerGradient.builder()
179+
.withNetworkElementId(networkElementId)
180+
.withMaxValue(Double.parseDouble(
181+
staticRecord.get("Maximum positive power gradient [MW/h]").isEmpty() ? MAX_GRADIENT : staticRecord.get("Maximum positive power gradient [MW/h]")
182+
)).withMinValue(-Double.parseDouble(
183+
staticRecord.get("Maximum negative power gradient [MW/h]").isEmpty() ? MAX_GRADIENT : staticRecord.get("Maximum negative power gradient [MW/h]")
184+
)).build();
185+
interTemporalRaoInput.getPowerGradients().add(powerGradient);
186+
}
187+
188+
private static String processNetworks(String nodeId, TemporalData<Network> initialNetworks, Map<String, CSVRecord> seriesPerType, double shiftKey) {
189+
String generatorId = seriesPerType.get("P0").get("RA RD ID") + "_" + nodeId + "_GENERATOR";
112190
for (Map.Entry<OffsetDateTime, Network> entry : initialNetworks.getDataPerTimestamp().entrySet()) {
113-
Bus bus = entry.getValue().getBusBreakerView().getBus(uctNodeOrGskId);
191+
Bus bus = entry.getValue().getBusBreakerView().getBus(nodeId);
114192
if (bus == null) {
115193
return null;
116194
}
117-
Double p0 = Double.parseDouble(seriesPerType.get("P0").get(entry.getKey().getHour() + OFFSET));
195+
Double p0 = Double.parseDouble(seriesPerType.get("P0").get(entry.getKey().getHour() + OFFSET)) * shiftKey;
118196
processBus(bus, generatorId, p0);
119197
}
120198
return generatorId;
@@ -144,16 +222,16 @@ private static void processBus(Bus bus, String generatorId, Double p0) {
144222
.add();
145223
}
146224

147-
private static boolean shouldBeImported(CSVRecord staticRecord) {
148-
return staticRecord.get("RD description mode").equals("NODE") &&
225+
private static boolean shouldBeImported(CSVRecord staticRecord, Map<String, Map<String, Double>> weightPerNodePerGsk) {
226+
return (staticRecord.get("RD description mode").equalsIgnoreCase("NODE") || weightPerNodePerGsk.containsKey(staticRecord.get("UCT Node or GSK ID"))) &&
149227
(staticRecord.get("Preventive").equals("TRUE") /*|| staticRecord.get("Curative").equals("TRUE")*/);
150228
}
151229

152230
private static boolean p0RespectsGradients(CSVRecord staticRecord, CSVRecord p0record, Set<OffsetDateTime> dateTimes) {
153231
double maxGradient = Double.parseDouble(staticRecord.get("Maximum positive power gradient [MW/h]").isEmpty() ?
154-
"1000" : staticRecord.get("Maximum positive power gradient [MW/h]"));
232+
MAX_GRADIENT : staticRecord.get("Maximum positive power gradient [MW/h]"));
155233
double minGradient = -Double.parseDouble(staticRecord.get("Maximum negative power gradient [MW/h]").isEmpty() ?
156-
"1000" : staticRecord.get("Maximum negative power gradient [MW/h]"));
234+
MAX_GRADIENT : staticRecord.get("Maximum negative power gradient [MW/h]"));
157235

158236
Iterator<OffsetDateTime> dateTimeIterator = dateTimes.iterator();
159237
OffsetDateTime currentDateTime = dateTimeIterator.next();

ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/MinMarginViolationEvaluator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
* @author Thomas Bouquet {@literal <thomas.bouquet at rte-france.com>}
2828
*/
2929
public class MinMarginViolationEvaluator extends MinMarginEvaluator implements CostEvaluator {
30-
private static final double OVERLOAD_PENALTY = 10000d; // TODO : set this in RAO parameters
30+
private static final double OVERLOAD_PENALTY = 1000d; // TODO : set this in RAO parameters
3131

3232
public MinMarginViolationEvaluator(Set<FlowCnec> flowCnecs, Unit unit, MarginEvaluator marginEvaluator) {
3333
super(flowCnecs, unit, marginEvaluator);

ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/commons/objectivefunctionevaluator/RemedialActionCostEvaluator.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,15 +51,16 @@ private double getTotalRangeActionsCost(RemedialActionActivationResult remedialA
5151

5252
private double computeRangeActionCost(RangeAction<?> rangeAction, State state, RemedialActionActivationResult remedialActionActivationResult) {
5353
double variation = rangeAction instanceof PstRangeAction pstRangeAction ? (double) remedialActionActivationResult.getTapVariation(pstRangeAction, state) : remedialActionActivationResult.getSetPointVariation(rangeAction, state);
54+
double after = rangeAction instanceof PstRangeAction pstRangeAction ? (double) remedialActionActivationResult.getOptimizedTap(pstRangeAction, state) : remedialActionActivationResult.getOptimizedSetpoint(rangeAction, state);
5455
if (variation == 0.0) {
5556
return 0.0;
5657
}
5758
double activationCost = rangeAction.getActivationCost().orElse(0.0);
5859
VariationDirection variationDirection = variation > 0 ? VariationDirection.UP : VariationDirection.DOWN;
5960
if (!(rangeAction instanceof PstRangeAction)) {
60-
TECHNICAL_LOGS.debug("{} variation of {} MW at state {}", rangeAction.getId(), variation, state);
61+
TECHNICAL_LOGS.debug("{} variation of {} MW at state {} ({} -> {})", rangeAction.getId(), variation, state, after - variation, after);
6162
} else {
62-
TECHNICAL_LOGS.debug("{} variation of {} taps at state {}", rangeAction.getId(), variation, state);
63+
TECHNICAL_LOGS.debug("{} variation of {} taps at state {} ({} -> {})", rangeAction.getId(), variation, state, after - variation, after);
6364
}
6465
return activationCost + Math.abs(variation) * rangeAction.getVariationCost(variationDirection).orElse(0.0);
6566
}

ra-optimisation/search-tree-rao/src/main/java/com/powsybl/openrao/searchtreerao/fastrao/FastRao.java

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -125,17 +125,15 @@ public static RaoResult launchFilteredRao(RaoInput raoInput, RaoParameters param
125125
int counter = 1;
126126
do {
127127
addWorstCnecs(consideredCnecs, NUMBER_OF_CNECS_TO_ADD, stepResult);
128-
System.out.println(consideredCnecs.size());
129128
if (ADD_UNSECURE_CNECS) {
130129
consideredCnecs.addAll(getUnsecureFunctionalCnecs(stepResult, parameters.getObjectiveFunctionParameters().getUnit()));
131130
}
132-
System.out.println(consideredCnecs.size());
133131
consideredCnecs.addAll(getCostlyVirtualCnecs(stepResult));
134-
System.out.println(consideredCnecs.size());
135132
consideredCnecs.add(getWorstPreventiveCnec(stepResult, crac));
136-
System.out.println(consideredCnecs.size());
137133
cleanVariants(raoInput.getNetwork(), initialNetworkVariants);
138134

135+
BUSINESS_LOGS.info("{} cnecs to be considered in filtered RAO", consideredCnecs.size());
136+
139137
raoResult = runFilteredRao(raoInput, parameters, targetEndInstant, consideredCnecs, toolProvider, initialResult, networkPool, counter);
140138
stepResult = raoResult.getAppropriateResult(lastInstant);
141139

@@ -207,8 +205,10 @@ private static Set<String> getUnsecureFunctionalCnecs(PrePerimeterResult prePeri
207205

208206
private static Set<String> getCostlyVirtualCnecs(ObjectiveFunctionResult ofResult) {
209207
Set<String> flowCnecs = new HashSet<>();
210-
ofResult.getVirtualCostNames().forEach(name -> ofResult.getCostlyElements(name, Integer.MAX_VALUE).forEach(
211-
flowCnec -> flowCnecs.add(flowCnec.getId())
208+
ofResult.getVirtualCostNames().stream()
209+
.filter(name -> !name.equals("min-margin-violation-evaluator"))
210+
.forEach(name -> ofResult.getCostlyElements(name, Integer.MAX_VALUE).forEach(
211+
flowCnec -> flowCnecs.add(flowCnec.getId())
212212
));
213213
return flowCnecs;
214214
}
@@ -217,12 +217,9 @@ private static FastRaoResultImpl runFilteredRao(RaoInput raoInput, RaoParameters
217217
Crac crac = raoInput.getCrac();
218218
// 4. Filter CRAC to only keep the worst CNECs
219219
Crac filteredCrac = copyCrac(crac, raoInput.getNetwork());
220-
System.out.println(filteredCrac.getFlowCnecs().size());
221220
removeFlowCnecsFromCrac(filteredCrac, flowCnecsToKeep);
222221

223222
BUSINESS_LOGS.info("***** Iteration {}: Run filtered RAO [start]", counter);
224-
System.out.println(filteredCrac.getFlowCnecs().size());
225-
System.out.println(flowCnecsToKeep.size());
226223

227224
RaoInput filteredRaoInput = createFilteredRaoInput(raoInput, filteredCrac);
228225
RaoResult raoResult;

0 commit comments

Comments
 (0)