EMlab-generation Documentation  1.0
Documentation of the EMLab-Generation model.
DetermineResidualLoadCurvesForTwoCountriesRole.java
1 package emlab.gen.role.market;
2 
3 import hep.aida.bin.DynamicBin1D;
4 
5 import java.util.HashMap;
6 import java.util.List;
7 import java.util.Map;
8 
9 import org.springframework.beans.factory.annotation.Autowired;
10 import org.springframework.transaction.annotation.Transactional;
11 
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;
31 
40 @RoleComponent
41 public class DetermineResidualLoadCurvesForTwoCountriesRole extends AbstractRole<DecarbonizationModel> implements
42 Role<DecarbonizationModel> {
43 
44  @Autowired
45  private Reps reps;
46 
52  @Override
53  @Transactional
54  public void act(DecarbonizationModel model) {
55 
56  long clearingTick = getCurrentTick();
57 
58  logger.warn("0. Determining the residual load duration curve");
59 
60  // 1. Create big matrix which contains columns for the information later
61  // used.
62  // Fill the columns with starting information (hour of year, initial
63  // maximum interconnector capacity
64 
65  // Create Matrix with following columns
66  // Hour of year | SegmentId | 2x Load | 2x intermittent Prod. | 2x Res.
67  // Load | Res.Load Total | Interc. Cap. | SegmentsAccordingToA |
68  // SegmentsAccordingtoB
69  // When creating views, and changes are made to the views, the
70  // original matrix is changed as well (see Colt package).
71 
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);
79  }
80 
81  int columnIterator = 0;
82 
83  // Naming of columns, since dynamically created cannot be done as an
84  // enum.
85  int HOUR = columnIterator;
86  columnIterator++;
87  int SEGMENT = columnIterator;
88  columnIterator++;
89  Map<Zone, Integer> LOADINZONE = new HashMap<Zone, Integer>();
90  for (Zone zone : zoneList) {
91  LOADINZONE.put(zone, columnIterator);
92  columnIterator++;
93  }
94 
95  Map<Zone, Integer> IPROD = new HashMap<Zone, Integer>();
96  for (Zone zone : zoneList) {
97  IPROD.put(zone, columnIterator);
98  columnIterator++;
99  }
100 
101  Map<Zone, Integer> RLOADINZONE = new HashMap<Zone, Integer>();
102  for (Zone zone : zoneList) {
103  RLOADINZONE.put(zone, columnIterator);
104  columnIterator++;
105  }
106 
107  int RLOADTOTAL = columnIterator;
108  columnIterator++;
109  int INTERCONNECTOR = columnIterator;
110  columnIterator++;
111 
112  Map<Zone, Integer> SEGMENTFORZONE = new HashMap<Zone, Integer>();
113  for (Zone zone : zoneList) {
114  SEGMENTFORZONE.put(zone, columnIterator);
115  columnIterator++;
116  }
117 
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>>();
121  for (PowerGridNode node : zoneToNodeList.get(zone)) {
122  Map<PowerGeneratingTechnology, Integer> technologyToColumn = new HashMap<PowerGeneratingTechnology, Integer>();
123  for (PowerGeneratingTechnology technology : technologyList) {
124  technologyToColumn.put(technology, columnIterator);
125  columnIterator++;
126  }
127  NODETOTECHNOLOGY.put(node, technologyToColumn);
128  }
129  TECHNOLOGYLOADFACTORSFORZONEANDNODE.put(zone, NODETOTECHNOLOGY);
130  }
131 
132  double interConnectorCapacity = reps.template.findAll(Interconnector.class).iterator().next()
133  .getCapacity(clearingTick);
134 
135  // Create globalResidualLoadMatrix and add hours.
136 
137  DoubleMatrix2D m = new DenseDoubleMatrix2D(8760, columnIterator);
138  m.assign(0d);
139 
140  for (int row = 0; row < 8760; row++) {
141  m.set(row, HOUR, row);
142  }
143 
144  // Create vector of 1:
145  DoubleMatrix1D oneVector = new DenseDoubleMatrix1D(m.rows());
146  oneVector.assign(1);
147 
148  // Is set to negative, since later on a max(-interconnector, Rload) is
149  // applied.
150  m.viewColumn(INTERCONNECTOR).assign(-interConnectorCapacity);
151 
152  logger.debug("First 10 values of matrix: \n " + m.viewPart(0, 0, 10, m.columns()).toString());
153 
154  // 2. Build national load curves, by adding up grid node load curves in
155  // each zone.
156  // also fill the residual load columns with the initial load curves.
157  // for now simply multiplied with the market wide growth factor
158  for (Zone zone : zoneList) {
159 
160  for (PowerGridNode node : zoneToNodeList.get(zone)) {
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);
169 
170  }
171 
172  }
173 
174  // 3. For each power grid node multiply the time series of each
175  // intermittent technology type with
176  // the installed capacity of that technology type. Substract
177  // intermittent production from the
178  // the residual load column (one column per zone). Calculate the total
179  // residual load (assuming
180  // no interconnector constraints). Reduce the load factors by obvious
181  // spill, that is RES production greater than demand + interconnector
182  // capacity.
183 
184  for (Zone zone : zoneList) {
185 
186  for (PowerGridNode node : zoneToNodeList.get(zone)) {
187 
188  for (PowerGeneratingTechnology technology : technologyList) {
189 
190  double intermittentCapacityOfTechnologyInNode = reps.powerPlantRepository
191  .calculateCapacityOfOperationalIntermittentPowerPlantsByPowerGridNodeAndTechnology(node, technology,
192  getCurrentTick());
193 
194  // logger.warn(technology.getName() + ": " +
195  // intermittentCapacityOfTechnologyInNode + " MW in Node "
196  // + node.getName() + " and Zone: " + zone.getName());
197 
198  IntermittentResourceProfile intermittentResourceProfile = reps.intermittentResourceProfileRepository
199  .findIntermittentResourceProfileByTechnologyAndNode(technology, node);
200 
201  // Calculates hourly production of intermittent renewable
202  // technology per 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);
209  // Add to zonal-technological RES column
210 
211  // Substracts the above from the residual load curve
212  m.viewColumn(RLOADINZONE.get(zone)).assign(hourlyProductionPerNode, Functions.minus);
213 
214  }
215 
216  }
217 
218  m.viewColumn(RLOADTOTAL).assign(m.viewColumn(RLOADINZONE.get(zone)), Functions.plus);
219  // Assign minimum of -interConnectorCapacity to national
220  // residual load
221  m.viewColumn(RLOADINZONE.get(zone)).assign(m.viewColumn(INTERCONNECTOR), Functions.max);
222 
223  // Assign a maximum production value of Load +
224  // interconnector capacity of INTPROD
225  DoubleMatrix1D loadPlusInterconnector = m.viewColumn(LOADINZONE.get(zone)).copy();
226  // Need to substract interconnector capacity, since defined
227  // negatively.
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);
233 
234  for (PowerGridNode node : zoneToNodeList.get(zone)) {
235 
236  for (PowerGeneratingTechnology technology : technologyList) {
237  m.viewColumn(TECHNOLOGYLOADFACTORSFORZONEANDNODE.get(zone).get(node).get(technology)).assign(spillVector,
238  Functions.mult);
239  }
240  }
241 
242  }
243 
244  // 4. Do a pre-market clearing of RES production: For each time step
245  // check if there's negative residual loads
246  // in each country. Export from one country to another country if
247  // interconnector constraints and residual
248  // and residual load in the other country allow for that. Reduce
249  // intermittent production if over supply.
250  // In the end calculate the total residual load curve over all
251  // countries.
252  // logger.warn("First 10 values of matrix: \n " + m.viewPart(0, 0, 10,
253  // m.columns()).toString());
254 
255  Zone zoneA = zoneList.get(0);
256  Zone zoneB = zoneList.get(1);
257 
258  Zone zoneSmallerResidual;
259  Zone zoneBiggerResidual;
260 
261  int numberOfHoursWereBothCountriesHaveNegativeResidualLoad = 0;
262  int numberOfHoursWhereOneCountryExportsREStoTheOther = 0;
263  int printAmount = 0;
264 
265  Map<Zone, DoubleMatrix1D> spillFactorMap = new HashMap<Zone, DoubleMatrix1D>();
266  // Get old values of IPROD to calculate spill factors later on.
267  for(Zone zone: zoneList){
268  spillFactorMap.put(zone, m.viewColumn(IPROD.get(zone)).copy());
269  }
270 
271  for (int row = 0; row < m.rows(); row++) {
272 
273  if (m.get(row, RLOADINZONE.get(zoneA)) < m.get(row, RLOADINZONE.get(zoneB))) {
274  zoneSmallerResidual = zoneA;
275  zoneBiggerResidual = zoneB;
276  } else {
277  zoneSmallerResidual = zoneB;
278  zoneBiggerResidual = zoneA;
279  }
280 
281  double smallerResidual = m.viewColumn(RLOADINZONE.get(zoneSmallerResidual)).get(row);
282  double biggerResidual = m.viewColumn(RLOADINZONE.get(zoneBiggerResidual)).get(row);
283  // In case both countries have negative residual load (more IPROD
284  // than load), set RLOAD to zero, and reduce IPROD to LOAD in
285  // countries. Calculate the spill factor of the two zones, and
286  // multiply it
287  // to the load factors of the technologies in the respective nodes.
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++;
296  // In case the country with the smaller residual can export and
297  // bigger residual can import, check what is the limiting
298  // factor.
299  double diffSandB = smallerResidual + biggerResidual;
300  // Country BiggerResidual can import more than Country
301  // SmallerResidual can export
302  if (diffSandB > 0) {
303  // Interconnector capacity is not limiting
304  if (Math.abs(smallerResidual) < Math.abs(m.get(row, INTERCONNECTOR))) {
305  // Substract export IPROD from interconnector capacity,
306  // reduce RLOAD in CountyrSmallerResidual to 0, in
307  // CountryBiggerResidual to
308  // biggerResidual+smallerResidual
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);
312  } else {
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));
316  }
317  } else {
318  // Country BiggerResidual can import less than Country
319  // SmallerResidual could export
320  // Interconnector capacity is not limiting
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));
326  } else {
327  // Interconnector capacity is limiting
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)));
333  }
334  }
335  }
336 
337  m.viewColumn(RLOADTOTAL).set(row,
338  m.get(row, RLOADINZONE.get(zoneSmallerResidual)) + m.get(row, RLOADINZONE.get(zoneBiggerResidual)));
339  }
340 
341  // First divide it by new value. Spilled values are than greater
342  // than 1, the other equal to 1.
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);
350  }
351 
352  oneVector.assign(spillFactorMap.get(zoneA), Functions.minus);
353 
354  DoubleMatrix1D differenceVector = m.viewColumn(12).copy();
355  differenceVector.assign(m.viewColumn(13), Functions.minus);
356  double result = differenceVector.aggregate(Functions.plus, Functions.identity);
357  // logger.warn("Result: " + result);
358  // Divide all the technology load factors in the zone by the spill
359  // factors above
360  for (Zone zone : zoneList) {
361  for (PowerGridNode node : zoneToNodeList.get(zone)) {
362  for (PowerGeneratingTechnology technology : technologyList) {
363  m.viewColumn(TECHNOLOGYLOADFACTORSFORZONEANDNODE.get(zone).get(node).get(technology)).assign(
364  spillFactorMap.get(zone), Functions.div);
365  }
366  }
367  }
368 
369  // Make the interconnector capacity postive
370  m.viewColumn(INTERCONNECTOR).assign(Functions.mult(-1));
371 
372  // logger.warn("Number of hours where both countries of negative residual load: "
373  // + numberOfHoursWereBothCountriesHaveNegativeResidualLoad);
374  // logger.warn("Number of hours where one country exports to the other: "
375  // + numberOfHoursWhereOneCountryExportsREStoTheOther);
376 
377  // 5. Order the hours in the global residual load curve. Peak load
378  // first, base load last.
379 
380  // Sorts matrix by the load curve in descending order
381 
382  m = m.viewSorted(RLOADTOTAL).viewRowFlip();
383 
384  // 6. Find values, so that each segments has approximately equal
385  // capacity
386  // needs.
387 
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++;
394  } else {
395  break;
396  }
397 
398  }
399 
400  int noSegments = (int) reps.segmentRepository.count();
401 
402  double[] upperBoundSplit = new double[noSegments];
403 
404  if (hoursWithoutZeroRLoad > 8750) {
405  for (int i = 0; i < noSegments; i++) {
406  upperBoundSplit[i] = max - (((double) (i)) / noSegments * (max - min));
407  }
408  } else {
409  for (int i = 0; i < (noSegments - 1); i++) {
410  upperBoundSplit[i] = max - (((double) (i)) / (noSegments - 1) * (max - min));
411  }
412  upperBoundSplit[noSegments - 1] = 0;
413  }
414  // 7. Create DynamicBins as representation for segments and for later
415  // calculation of means, no etc. Per bin one sort of information (e.g.
416  // residual
417  // load, interconnector capacity) and the corresponding hour of the yea
418  // can be stored.
419  // Thus connection to the matrix remains.
420 
421  DynamicBin1D[] segmentRloadBins = new DynamicBin1D[noSegments];
422  for (int i = 0; i < noSegments; i++) {
423  segmentRloadBins[i] = new DynamicBin1D();
424  }
425 
426  DynamicBin1D[] segmentInterConnectorBins = new DynamicBin1D[noSegments];
427  for (int i = 0; i < noSegments; i++) {
428  segmentInterConnectorBins[i] = new DynamicBin1D();
429  }
430 
431 
432  Map<Zone, DynamicBin1D[]> segmentRloadBinsByZone = new HashMap<Zone, DynamicBin1D[]>();
433  Map<Zone, DynamicBin1D[]> segmentLoadBinsByZone = new HashMap<Zone, DynamicBin1D[]>();
434 
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();
441  }
442  segmentRloadBinsByZone.put(zone, segmentRloadBinInZone);
443  segmentLoadBinsByZone.put(zone, segmentLoadBinInZone);
444  }
445 
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[]>>();
449  for (PowerGridNode node : zoneToNodeList.get(zone)) {
450  Map<PowerGeneratingTechnology, DynamicBin1D[]> technologyToBins = new HashMap<PowerGeneratingTechnology, DynamicBin1D[]>();
451  for (PowerGeneratingTechnology technology : technologyList) {
452  DynamicBin1D[] technologyLoadFactorInNode = new DynamicBin1D[noSegments];
453  for (int i = 0; i < noSegments; i++) {
454  technologyLoadFactorInNode[i] = new DynamicBin1D();
455  }
456  technologyToBins.put(technology, technologyLoadFactorInNode);
457  }
458  NODETOTECHNOLOGY.put(node, technologyToBins);
459  }
460  loadFactorBinMap.put(zone, NODETOTECHNOLOGY);
461  }
462 
463  // logger.warn("Max: " + max + "\n" + "Min: " + min);
464  // for (double value : upperBoundSplit) {
465  // logger.warn("Split-Value:" + value);
466  // }
467 
468  // Assign hours and load to bins and segments
469  int currentSegmentID = 1;
470  int hoursAssignedToCurrentSegment = 0;
471  for (int row = 0; row < m.rows() && currentSegmentID <= noSegments; row++) {
472  // IMPORTANT: since [] is zero-based index, it checks one index
473  // ahead of current segment.
474  while (currentSegmentID < noSegments && hoursAssignedToCurrentSegment > 0
475  && m.get(row, RLOADTOTAL) <= upperBoundSplit[currentSegmentID]) {
476  currentSegmentID++;
477  hoursAssignedToCurrentSegment = 0;
478  }
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)));
484  }
485  segmentInterConnectorBins[currentSegmentID - 1].add(m.get(row, INTERCONNECTOR));
486  hoursAssignedToCurrentSegment++;
487  }
488 
489  for (Zone zone : zoneList) {
490  for (PowerGridNode node : zoneToNodeList.get(zone)) {
491  for (PowerGeneratingTechnology technology : reps.powerGeneratingTechnologyRepository
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++) {
498  // IMPORTANT: since [] is zero-based index, it checks one index
499  // ahead of current segment.
500  while (currentSegmentID < noSegments && hoursAssignedToCurrentSegment > 0
501  && m.get(row, RLOADTOTAL) <= upperBoundSplit[currentSegmentID]) {
502  currentSegmentID++;
503  hoursAssignedToCurrentSegment = 0;
504  }
505  currentBinArray[currentSegmentID - 1].add(m.get(row,columnNumber));
506  hoursAssignedToCurrentSegment++;
507  }
508  loadFactorBinMap.get(zone).get(node).put(technology, currentBinArray);
509  }
510  }
511  }
512 
513 
514  // Assign hours to segments according to residual load in this country.
515  // Only for error estimation purposes
516 
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);
521 
522  double[] upperBoundSplitInZone = new double[noSegments];
523 
524  for (int i = 0; i < noSegments; i++) {
525  upperBoundSplitInZone[i] = maxInZone - (((double) (i)) / noSegments * (maxInZone - minInZone));
526  }
527 
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]) {
535  currentSegmentID++;
536  hoursAssignedToCurrentSegment = 0;
537  }
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));
542  }
543  hoursAssignedToCurrentSegment++;
544  }
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.");
553  } else {
554  logger.warn("For " + zone + ", all hours were in the same segment, as for combined sorting!");
555  }
556 
557  }
558 
559 
560  // m = m.viewSorted(RLOADTOTAL).viewRowFlip();
561  //
562  // logger.debug("First 30 values of matrix: \n " + m.viewPart(0, 0, 30,
563  // m.columns()).toString());
564 
565  // Printing of segments
566  int it = 1;
567  for (DynamicBin1D bin : segmentRloadBins) {
568  // logger.warn("Segment " + it + "\n Size: " + bin.size() +
569  // "\n Mean RLOAD~: " + Math.round(bin.mean())
570  // + "\n Max RLOAD~: " + Math.round(bin.max()) +
571  // "\n Min RLOAD~: " + Math.round(bin.min())
572  // + "\n Std RLOAD~: " + Math.round(bin.standardDeviation()));
573  it++;
574  }
575 
576  it = 1;
577  for (DynamicBin1D bin : segmentInterConnectorBins) {
578  // logger.warn("Segment " + it + "\n Size: " + bin.size() +
579  // "\n Mean IntCapacity~: "
580  // + Math.round(bin.mean()) + "\n Max IntCapacity~: " +
581  // Math.round(bin.max())
582  // + "\n Min IntCapacity~: " + Math.round(bin.min()) +
583  // "\n STD IntCapacity~: "
584  // + Math.round(bin.standardDeviation()));
585  it++;
586  }
587 
588  for (Zone zone : zoneList) {
589  // logger.warn("Bins for " + zone);
590  it = 1;
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)) {
595  // logger.warn("Segment " + it + "\n Size: " + bin.size() +
596  // "\n Mean RLOAD~: " + Math.round(bin.mean())
597  // + "\n Max RLOAD~: " + Math.round(bin.max()) +
598  // "\n Min RLOAD~: " + Math.round(bin.min())
599  // + "\n Std RLOAD~: " +
600  // Math.round(bin.standardDeviation()));
601  it++;
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());
607  }
608  it = 1;
609  for (DynamicBin1D bin : segmentLoadBinsByZone.get(zone)) {
610  // logger.warn("Segment " + it + "\n Size: " + bin.size() +
611  // "\n Mean LOAD~: "
612  // + Math.round(bin.mean()) + "\n Max LOAD~: " +
613  // Math.round(bin.max())
614  // + "\n Min LOAD~: " + Math.round(bin.min()) +
615  // "\n Std LOAD~: "
616  // + Math.round(bin.standardDeviation()));
617  it++;
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());
623  }
624  // logger.warn(meanRLoad);
625  // logger.warn(meanLoad);
626  // logger.warn(segmentLength);
627  }
628 
629  // 9. Store the load factors in the IntermittentTechnologyLoadFactors
630 
631  String loadFactors;
632  for (Zone zone : zoneList) {
633  for (PowerGridNode node : zoneToNodeList.get(zone)) {
634 
635  for (PowerGeneratingTechnology technology : technologyList) {
636  String loadFactorString = new String(technology.getName() + " LF in " + node.getName() + ":");
637  // logger.warn("Bins for " + zone + ", " + node + "and " +
638  // technology);
639  IntermittentTechnologyNodeLoadFactor intTechnologyNodeLoadFactor = reps.intermittentTechnologyNodeLoadFactorRepository
640  .findIntermittentTechnologyNodeLoadFactorForNodeAndTechnology(node, technology);
641  if (intTechnologyNodeLoadFactor == null) {
642  intTechnologyNodeLoadFactor = new IntermittentTechnologyNodeLoadFactor().persist();
643  intTechnologyNodeLoadFactor.setLoadFactors(new double[noSegments]);
644  intTechnologyNodeLoadFactor.setNode(node);
645  intTechnologyNodeLoadFactor.setTechnology(technology);
646  }
647  ;
648  it = 1;
649  for (DynamicBin1D bin : loadFactorBinMap.get(zone).get(node).get(technology)) {
650  // logger.warn("Segment " + it + "\n Size: " +
651  // bin.size() + "\n Mean RLOAD~: "
652  // + bin.mean() + "\n Max RLOAD~: " + bin.max() +
653  // "\n Min RLOAD~: " + bin.min()
654  // + "\n Std RLOAD~: " + bin.standardDeviation());
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);
660  it++;
661  }
662  logger.warn(loadFactorString);
663  }
664 
665  }
666  }
667 
668  // 8. Store the segment duration and the average load in that segment
669  // per country.
670 
671  Iterable<SegmentLoad> segmentLoads = reps.segmentLoadRepository.findAll();
672  for (SegmentLoad segmentLoad : segmentLoads) {
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);
679  // logger.warn("Segment " + segment.getSegmentID() + ": " +
680  // segmentLoad.getBaseLoad() + "MW");
681  }
682 
683  Iterable<Segment> segments = reps.segmentRepository.findAll();
684  for (Segment segment : segments) {
685  segment.setLengthInHours(segmentRloadBins[segment.getSegmentID() - 1].size());
686  }
687 
688  for (Zone zone : zoneList) {
689  double intermittentCapacityOfTechnologyInZone=0;
690 
691 
692 
693 
694  for (PowerGeneratingTechnology technology : technologyList) {
695  double productionOfTechInZone = 0;
696 
697  for (PowerGridNode node : zoneToNodeList.get(zone)) {
698 
699  intermittentCapacityOfTechnologyInZone += reps.powerPlantRepository
700  .calculateCapacityOfOperationalIntermittentPowerPlantsByPowerGridNodeAndTechnology(node, technology,
701  getCurrentTick());
702  productionOfTechInZone += m.viewColumn(
703  TECHNOLOGYLOADFACTORSFORZONEANDNODE.get(zone).get(node).get(technology)).zSum()
704  * intermittentCapacityOfTechnologyInZone;
705 
706 
707  }
708 
709  // logger.warn(technology.getName() + " is producing " +
710  // productionOfTechInZone + " MWh in "
711  // + zone.getName() + ".");
712 
713  }
714  }
715  }
716 
717  public Reps getReps() {
718  return reps;
719  }
720 
721 }