1 package emlab.gen.role.market;
3 import hep.aida.bin.DynamicBin1D;
5 import java.util.HashMap;
9 import org.springframework.beans.factory.annotation.Autowired;
10 import org.springframework.transaction.annotation.Transactional;
12 import agentspring.role.AbstractRole;
13 import agentspring.role.Role;
14 import agentspring.role.RoleComponent;
15 import cern.colt.matrix.DoubleMatrix1D;
16 import cern.colt.matrix.DoubleMatrix2D;
17 import cern.colt.matrix.impl.DenseDoubleMatrix1D;
18 import cern.colt.matrix.impl.DenseDoubleMatrix2D;
19 import cern.jet.math.Functions;
42 Role<DecarbonizationModel> {
56 long clearingTick = getCurrentTick();
58 logger.warn(
"0. Determining the residual load duration curve");
72 List<Zone> zoneList = Utils.asList(reps.template.findAll(Zone.class));
73 List<PowerGeneratingTechnology> technologyList = Utils.asList(reps.powerGeneratingTechnologyRepository
74 .findAllIntermittentPowerGeneratingTechnologies());
75 Map<Zone, List<PowerGridNode>> zoneToNodeList =
new HashMap<Zone, List<PowerGridNode>>();
76 for (
Zone zone : zoneList) {
77 List<PowerGridNode> nodeList = Utils.asList(reps.powerGridNodeRepository.findAllPowerGridNodesByZone(zone));
78 zoneToNodeList.put(zone, nodeList);
81 int columnIterator = 0;
85 int HOUR = columnIterator;
87 int SEGMENT = columnIterator;
89 Map<Zone, Integer> LOADINZONE =
new HashMap<Zone, Integer>();
90 for (
Zone zone : zoneList) {
91 LOADINZONE.put(zone, columnIterator);
95 Map<Zone, Integer> IPROD =
new HashMap<Zone, Integer>();
96 for (
Zone zone : zoneList) {
97 IPROD.put(zone, columnIterator);
101 Map<Zone, Integer> RLOADINZONE =
new HashMap<Zone, Integer>();
102 for (
Zone zone : zoneList) {
103 RLOADINZONE.put(zone, columnIterator);
107 int RLOADTOTAL = columnIterator;
109 int INTERCONNECTOR = columnIterator;
112 Map<Zone, Integer> SEGMENTFORZONE =
new HashMap<Zone, Integer>();
113 for (
Zone zone : zoneList) {
114 SEGMENTFORZONE.put(zone, columnIterator);
118 Map<Zone, Map<PowerGridNode, Map<PowerGeneratingTechnology, Integer>>> TECHNOLOGYLOADFACTORSFORZONEANDNODE =
new HashMap<Zone, Map<PowerGridNode, Map<PowerGeneratingTechnology, Integer>>>();
119 for (
Zone zone : zoneList) {
120 Map<PowerGridNode, Map<PowerGeneratingTechnology, Integer>> NODETOTECHNOLOGY =
new HashMap<PowerGridNode, Map<PowerGeneratingTechnology, Integer>>();
122 Map<PowerGeneratingTechnology, Integer> technologyToColumn =
new HashMap<PowerGeneratingTechnology, Integer>();
124 technologyToColumn.put(technology, columnIterator);
127 NODETOTECHNOLOGY.put(node, technologyToColumn);
129 TECHNOLOGYLOADFACTORSFORZONEANDNODE.put(zone, NODETOTECHNOLOGY);
132 double interConnectorCapacity = reps.template.findAll(Interconnector.class).iterator().next()
133 .getCapacity(clearingTick);
137 DoubleMatrix2D m =
new DenseDoubleMatrix2D(8760, columnIterator);
140 for (
int row = 0; row < 8760; row++) {
141 m.set(row, HOUR, row);
145 DoubleMatrix1D oneVector =
new DenseDoubleMatrix1D(m.rows());
150 m.viewColumn(INTERCONNECTOR).assign(-interConnectorCapacity);
152 logger.debug(
"First 10 values of matrix: \n " + m.viewPart(0, 0, 10, m.columns()).toString());
158 for (
Zone zone : zoneList) {
161 DoubleMatrix1D hourlyArray =
new DenseDoubleMatrix1D(node.getHourlyDemand().getHourlyArray(getCurrentTick()));
162 double growthRate = reps.marketRepository.findElectricitySpotMarketForZone(zone).getDemandGrowthTrend()
163 .getValue(clearingTick);
164 DoubleMatrix1D growthFactors = hourlyArray.copy();
165 growthFactors.assign(growthRate);
166 hourlyArray.assign(growthFactors, Functions.mult);
167 m.viewColumn(LOADINZONE.get(zone)).assign(hourlyArray, Functions.plus);
168 m.viewColumn(RLOADINZONE.get(zone)).assign(hourlyArray, Functions.plus);
184 for (
Zone zone : zoneList) {
190 double intermittentCapacityOfTechnologyInNode = reps.powerPlantRepository
191 .calculateCapacityOfOperationalIntermittentPowerPlantsByPowerGridNodeAndTechnology(node, technology,
199 .findIntermittentResourceProfileByTechnologyAndNode(technology, node);
203 DoubleMatrix1D hourlyProductionPerNode =
new DenseDoubleMatrix1D(
204 intermittentResourceProfile.getHourlyArray(getCurrentTick()));
205 m.viewColumn(TECHNOLOGYLOADFACTORSFORZONEANDNODE.get(zone).
get(node).get(technology)).assign(
206 hourlyProductionPerNode, Functions.plus);
207 hourlyProductionPerNode.assign(Functions.mult(intermittentCapacityOfTechnologyInNode));
208 m.viewColumn(IPROD.get(zone)).assign(hourlyProductionPerNode, Functions.plus);
212 m.viewColumn(RLOADINZONE.get(zone)).assign(hourlyProductionPerNode, Functions.minus);
218 m.viewColumn(RLOADTOTAL).assign(m.viewColumn(RLOADINZONE.get(zone)), Functions.plus);
221 m.viewColumn(RLOADINZONE.get(zone)).assign(m.viewColumn(INTERCONNECTOR), Functions.max);
225 DoubleMatrix1D loadPlusInterconnector = m.viewColumn(LOADINZONE.get(zone)).copy();
228 loadPlusInterconnector.assign(m.viewColumn(INTERCONNECTOR), Functions.minus);
229 DoubleMatrix1D spillVector = loadPlusInterconnector.copy();
230 spillVector.assign(m.viewColumn(IPROD.get(zone)), Functions.div);
231 spillVector.assign(oneVector, Functions.min);
232 m.viewColumn(IPROD.get(zone)).assign(loadPlusInterconnector, Functions.min);
237 m.viewColumn(TECHNOLOGYLOADFACTORSFORZONEANDNODE.get(zone).
get(node).get(technology)).assign(spillVector,
255 Zone zoneA = zoneList.get(0);
256 Zone zoneB = zoneList.get(1);
258 Zone zoneSmallerResidual;
259 Zone zoneBiggerResidual;
261 int numberOfHoursWereBothCountriesHaveNegativeResidualLoad = 0;
262 int numberOfHoursWhereOneCountryExportsREStoTheOther = 0;
265 Map<Zone, DoubleMatrix1D> spillFactorMap =
new HashMap<Zone, DoubleMatrix1D>();
267 for(
Zone zone: zoneList){
268 spillFactorMap.put(zone, m.viewColumn(IPROD.get(zone)).copy());
271 for (
int row = 0; row < m.rows(); row++) {
273 if (m.get(row, RLOADINZONE.get(zoneA)) < m.get(row, RLOADINZONE.get(zoneB))) {
274 zoneSmallerResidual = zoneA;
275 zoneBiggerResidual = zoneB;
277 zoneSmallerResidual = zoneB;
278 zoneBiggerResidual = zoneA;
281 double smallerResidual = m.viewColumn(RLOADINZONE.get(zoneSmallerResidual)).get(row);
282 double biggerResidual = m.viewColumn(RLOADINZONE.get(zoneBiggerResidual)).get(row);
288 if ((smallerResidual <= 0) && biggerResidual <= 0) {
289 numberOfHoursWereBothCountriesHaveNegativeResidualLoad++;
290 m.set(row, RLOADINZONE.get(zoneSmallerResidual), 0);
291 m.set(row, RLOADINZONE.get(zoneBiggerResidual), 0);
292 m.viewColumn(IPROD.get(zoneSmallerResidual)).set(row, m.get(row, LOADINZONE.get(zoneSmallerResidual)));
293 m.viewColumn(IPROD.get(zoneBiggerResidual)).set(row, m.get(row, LOADINZONE.get(zoneBiggerResidual)));
294 }
else if ((smallerResidual < 0) && (biggerResidual > 0)) {
295 numberOfHoursWhereOneCountryExportsREStoTheOther++;
299 double diffSandB = smallerResidual + biggerResidual;
304 if (Math.abs(smallerResidual) < Math.abs(m.get(row, INTERCONNECTOR))) {
309 m.set(row, INTERCONNECTOR, (m.get(row, INTERCONNECTOR) - smallerResidual));
310 m.viewColumn(RLOADINZONE.get(zoneSmallerResidual)).set(row, 0);
311 m.viewColumn(RLOADINZONE.get(zoneBiggerResidual)).set(row, biggerResidual + smallerResidual);
313 m.set(row, INTERCONNECTOR, 0);
314 m.viewColumn(RLOADINZONE.get(zoneSmallerResidual)).set(row, 0);
315 m.viewColumn(RLOADINZONE.get(zoneBiggerResidual)).set(row, biggerResidual + m.get(row, INTERCONNECTOR));
321 if (Math.abs(smallerResidual) < Math.abs(m.viewColumn(INTERCONNECTOR).
get(row))) {
322 m.set(row, INTERCONNECTOR, m.get(row, INTERCONNECTOR) + biggerResidual);
323 m.set(row, RLOADINZONE.get(zoneBiggerResidual), 0);
324 m.set(row, RLOADINZONE.get(zoneSmallerResidual), 0);
325 m.set(row, IPROD.get(zoneSmallerResidual), (m.get(row, IPROD.get(zoneSmallerResidual)) - biggerResidual));
328 m.set(row, INTERCONNECTOR, 0);
329 m.set(row, RLOADINZONE.get(zoneBiggerResidual), biggerResidual + m.viewColumn(INTERCONNECTOR).get(row));
330 m.set(row, RLOADINZONE.get(zoneSmallerResidual), 0);
331 m.set(row, IPROD.get(zoneSmallerResidual),
332 (m.get(row, IPROD.get(zoneSmallerResidual)) - m.get(row, INTERCONNECTOR)));
337 m.viewColumn(RLOADTOTAL).set(row,
338 m.get(row, RLOADINZONE.get(zoneSmallerResidual)) + m.get(row, RLOADINZONE.get(zoneBiggerResidual)));
343 for (
Zone zone : zoneList) {
344 DoubleMatrix1D minValuesVector = spillFactorMap.get(zone).like();
345 minValuesVector.assign(Double.MIN_NORMAL);
346 spillFactorMap.get(zone).assign(minValuesVector, Functions.plus);
347 m.viewColumn(IPROD.get(zone)).assign(minValuesVector, Functions.plus);
348 spillFactorMap.get(zone).assign(m.viewColumn(IPROD.get(zone)), Functions.div);
349 m.viewColumn(IPROD.get(zone)).assign(minValuesVector, Functions.minus);
352 oneVector.assign(spillFactorMap.get(zoneA), Functions.minus);
354 DoubleMatrix1D differenceVector = m.viewColumn(12).copy();
355 differenceVector.assign(m.viewColumn(13), Functions.minus);
356 double result = differenceVector.aggregate(Functions.plus, Functions.identity);
360 for (
Zone zone : zoneList) {
363 m.viewColumn(TECHNOLOGYLOADFACTORSFORZONEANDNODE.get(zone).
get(node).get(technology)).assign(
364 spillFactorMap.get(zone), Functions.div);
370 m.viewColumn(INTERCONNECTOR).assign(Functions.mult(-1));
382 m = m.viewSorted(RLOADTOTAL).viewRowFlip();
388 double min = m.viewColumn(RLOADTOTAL).aggregate(Functions.min, Functions.identity);
389 double max = m.viewColumn(RLOADTOTAL).aggregate(Functions.max, Functions.identity);
390 double hoursWithoutZeroRLoad = 0;
391 for (
int row = 0; row < m.rows(); row++) {
392 if (m.get(row, RLOADTOTAL) > 0) {
393 hoursWithoutZeroRLoad++;
400 int noSegments = (int) reps.segmentRepository.count();
402 double[] upperBoundSplit =
new double[noSegments];
404 if (hoursWithoutZeroRLoad > 8750) {
405 for (
int i = 0; i < noSegments; i++) {
406 upperBoundSplit[i] = max - (((double) (i)) / noSegments * (max - min));
409 for (
int i = 0; i < (noSegments - 1); i++) {
410 upperBoundSplit[i] = max - (((double) (i)) / (noSegments - 1) * (max - min));
412 upperBoundSplit[noSegments - 1] = 0;
421 DynamicBin1D[] segmentRloadBins =
new DynamicBin1D[noSegments];
422 for (
int i = 0; i < noSegments; i++) {
423 segmentRloadBins[i] =
new DynamicBin1D();
426 DynamicBin1D[] segmentInterConnectorBins =
new DynamicBin1D[noSegments];
427 for (
int i = 0; i < noSegments; i++) {
428 segmentInterConnectorBins[i] =
new DynamicBin1D();
432 Map<Zone, DynamicBin1D[]> segmentRloadBinsByZone =
new HashMap<Zone, DynamicBin1D[]>();
433 Map<Zone, DynamicBin1D[]> segmentLoadBinsByZone =
new HashMap<Zone, DynamicBin1D[]>();
435 for (
Zone zone : zoneList) {
436 DynamicBin1D[] segmentRloadBinInZone =
new DynamicBin1D[noSegments];
437 DynamicBin1D[] segmentLoadBinInZone =
new DynamicBin1D[noSegments];
438 for (
int i = 0; i < noSegments; i++) {
439 segmentRloadBinInZone[i] =
new DynamicBin1D();
440 segmentLoadBinInZone[i] =
new DynamicBin1D();
442 segmentRloadBinsByZone.put(zone, segmentRloadBinInZone);
443 segmentLoadBinsByZone.put(zone, segmentLoadBinInZone);
446 Map<Zone, Map<PowerGridNode, Map<PowerGeneratingTechnology, DynamicBin1D[]>>> loadFactorBinMap =
new HashMap<Zone, Map<PowerGridNode, Map<PowerGeneratingTechnology, DynamicBin1D[]>>>();
447 for (
Zone zone : zoneList) {
448 Map<PowerGridNode, Map<PowerGeneratingTechnology, DynamicBin1D[]>> NODETOTECHNOLOGY =
new HashMap<PowerGridNode, Map<PowerGeneratingTechnology, DynamicBin1D[]>>();
450 Map<PowerGeneratingTechnology, DynamicBin1D[]> technologyToBins =
new HashMap<PowerGeneratingTechnology, DynamicBin1D[]>();
452 DynamicBin1D[] technologyLoadFactorInNode =
new DynamicBin1D[noSegments];
453 for (
int i = 0; i < noSegments; i++) {
454 technologyLoadFactorInNode[i] =
new DynamicBin1D();
456 technologyToBins.put(technology, technologyLoadFactorInNode);
458 NODETOTECHNOLOGY.put(node, technologyToBins);
460 loadFactorBinMap.put(zone, NODETOTECHNOLOGY);
469 int currentSegmentID = 1;
470 int hoursAssignedToCurrentSegment = 0;
471 for (
int row = 0; row < m.rows() && currentSegmentID <= noSegments; row++) {
474 while (currentSegmentID < noSegments && hoursAssignedToCurrentSegment > 0
475 && m.get(row, RLOADTOTAL) <= upperBoundSplit[currentSegmentID]) {
477 hoursAssignedToCurrentSegment = 0;
479 m.set(row, SEGMENT, currentSegmentID);
480 segmentRloadBins[currentSegmentID - 1].add(m.get(row, RLOADTOTAL));
481 for (
Zone zone : zoneList) {
482 segmentRloadBinsByZone.get(zone)[currentSegmentID - 1].add(m.get(row, RLOADINZONE.get(zone)));
483 segmentLoadBinsByZone.get(zone)[currentSegmentID - 1].add(m.get(row, LOADINZONE.get(zone)));
485 segmentInterConnectorBins[currentSegmentID - 1].add(m.get(row, INTERCONNECTOR));
486 hoursAssignedToCurrentSegment++;
489 for (
Zone zone : zoneList) {
492 .findAllIntermittentPowerGeneratingTechnologies()) {
493 DynamicBin1D[] currentBinArray = loadFactorBinMap.get(zone).
get(node).get(technology);
494 int columnNumber = TECHNOLOGYLOADFACTORSFORZONEANDNODE.get(zone).
get(node).get(technology);
495 currentSegmentID = 1;
496 hoursAssignedToCurrentSegment = 0;
497 for (
int row = 0; row < m.rows() && currentSegmentID <= noSegments; row++) {
500 while (currentSegmentID < noSegments && hoursAssignedToCurrentSegment > 0
501 && m.get(row, RLOADTOTAL) <= upperBoundSplit[currentSegmentID]) {
503 hoursAssignedToCurrentSegment = 0;
505 currentBinArray[currentSegmentID - 1].add(m.get(row,columnNumber));
506 hoursAssignedToCurrentSegment++;
508 loadFactorBinMap.get(zone).
get(node).put(technology, currentBinArray);
517 for (
Zone zone : zoneList) {
518 currentSegmentID = 1;
519 double minInZone = m.viewColumn(RLOADINZONE.get(zone)).aggregate(Functions.min, Functions.identity);
520 double maxInZone = m.viewColumn(RLOADINZONE.get(zone)).aggregate(Functions.max, Functions.identity);
522 double[] upperBoundSplitInZone =
new double[noSegments];
524 for (
int i = 0; i < noSegments; i++) {
525 upperBoundSplitInZone[i] = maxInZone - (((double) (i)) / noSegments * (maxInZone - minInZone));
528 m = m.viewSorted(RLOADINZONE.get(zone)).viewRowFlip();
529 int hoursInDifferentSegment = 0;
530 double averageSegmentDeviation = 0;
531 hoursAssignedToCurrentSegment = 0;
532 for (
int row = 0; row < m.rows() && currentSegmentID <= noSegments; row++) {
533 while (currentSegmentID < noSegments && hoursAssignedToCurrentSegment > 0
534 && m.get(row, RLOADINZONE.get(zone)) <= upperBoundSplitInZone[currentSegmentID]) {
536 hoursAssignedToCurrentSegment = 0;
538 m.set(row, SEGMENTFORZONE.get(zone), currentSegmentID);
539 if (currentSegmentID != m.get(row, SEGMENT)) {
540 hoursInDifferentSegment++;
541 averageSegmentDeviation += Math.abs(currentSegmentID - m.get(row, SEGMENT));
543 hoursAssignedToCurrentSegment++;
545 if (hoursInDifferentSegment != 0) {
546 averageSegmentDeviation = averageSegmentDeviation / hoursInDifferentSegment;
547 averageSegmentDeviation = averageSegmentDeviation * 1000;
548 averageSegmentDeviation = Math.round(averageSegmentDeviation);
549 averageSegmentDeviation = averageSegmentDeviation / 1000;
550 logger.warn(
"For " + zone +
", " + hoursInDifferentSegment
551 +
" hours would have been in different segments, and on average " + averageSegmentDeviation
552 +
" Segments away from the segment they were in.");
554 logger.warn(
"For " + zone +
", all hours were in the same segment, as for combined sorting!");
567 for (DynamicBin1D bin : segmentRloadBins) {
577 for (DynamicBin1D bin : segmentInterConnectorBins) {
588 for (
Zone zone : zoneList) {
591 String meanRLoad =
new String(
"Residual load in " + zone.getName() +
":");
592 String meanLoad =
new String(
"Load in " + zone.getName() +
":");
593 String segmentLength =
new String(
"Segment length " + zone.getName() +
":");
594 for (DynamicBin1D bin : segmentRloadBinsByZone.get(zone)) {
602 double mean = bin.mean() * 1000;
603 mean = Math.round(mean);
604 mean = mean / 1000.0;
605 meanRLoad = meanRLoad.concat(
"," + mean);
606 segmentLength = segmentLength.concat(
"," + bin.size());
609 for (DynamicBin1D bin : segmentLoadBinsByZone.get(zone)) {
618 double mean = bin.mean() * 1000;
619 mean = Math.round(mean);
620 mean = mean / 1000.0;
621 meanLoad = meanLoad.concat(
"," + mean);
622 segmentLength = segmentLength.concat(
"," + bin.size());
632 for (
Zone zone : zoneList) {
636 String loadFactorString =
new String(technology.getName() +
" LF in " + node.getName() +
":");
640 .findIntermittentTechnologyNodeLoadFactorForNodeAndTechnology(node, technology);
641 if (intTechnologyNodeLoadFactor == null) {
643 intTechnologyNodeLoadFactor.setLoadFactors(
new double[noSegments]);
644 intTechnologyNodeLoadFactor.setNode(node);
645 intTechnologyNodeLoadFactor.setTechnology(technology);
649 for (DynamicBin1D bin : loadFactorBinMap.get(zone).get(node).
get(technology)) {
655 intTechnologyNodeLoadFactor.setLoadFactorForSegmentId(it, bin.mean());
656 double mean = bin.mean() * 1000000;
657 mean = Math.round(mean);
658 mean = mean / 1000000.0;
659 loadFactorString = loadFactorString.concat(
" " + mean);
662 logger.warn(loadFactorString);
671 Iterable<SegmentLoad> segmentLoads = reps.segmentLoadRepository.findAll();
673 Segment segment = segmentLoad.getSegment();
674 Zone zone = segmentLoad.getElectricitySpotMarket().getZone();
675 double demandGrowthFactor = reps.marketRepository.findElectricitySpotMarketForZone(zone)
676 .getDemandGrowthTrend().getValue(clearingTick);
677 segmentLoad.setBaseLoad(segmentLoadBinsByZone.get(zone)[segment.getSegmentID() - 1].mean()
678 / demandGrowthFactor);
683 Iterable<Segment> segments = reps.segmentRepository.findAll();
684 for (
Segment segment : segments) {
685 segment.setLengthInHours(segmentRloadBins[segment.getSegmentID() - 1].size());
688 for (
Zone zone : zoneList) {
689 double intermittentCapacityOfTechnologyInZone=0;
695 double productionOfTechInZone = 0;
699 intermittentCapacityOfTechnologyInZone += reps.powerPlantRepository
700 .calculateCapacityOfOperationalIntermittentPowerPlantsByPowerGridNodeAndTechnology(node, technology,
702 productionOfTechInZone += m.viewColumn(
703 TECHNOLOGYLOADFACTORSFORZONEANDNODE.get(zone).
get(node).get(technology)).zSum()
704 * intermittentCapacityOfTechnologyInZone;
717 public Reps getReps() {
void act(DecarbonizationModel model)