EMlab-generation Documentation  1.0
Documentation of the EMLab-Generation model.
SubmitLongTermElectricityContractsRole.java
1 /*******************************************************************************
2  * Copyright 2012 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  ******************************************************************************/
16 package emlab.gen.role.market;
17 
18 import org.springframework.beans.factory.annotation.Autowired;
19 import org.springframework.transaction.annotation.Transactional;
20 
21 import agentspring.role.Role;
22 import agentspring.role.RoleComponent;
35 import emlab.gen.role.AbstractEnergyProducerRole;
36 
46 @RoleComponent
48 AbstractEnergyProducerRole implements Role<EnergyProducer> {
49 
50  @Autowired
51  Reps reps;
52 
53  @Override
54  @Transactional
55  public void act(EnergyProducer producer) {
56 
57  // TODO Contracts for checking assigned to power plants??
58  // When dismantling, take over existing contract by new power plant?
59  for (PowerPlant plant : reps.powerPlantRepository
60  .findOperationalPowerPlantsByOwner(producer, getCurrentTick())) {
61 
62  // if it is not in the first tick,
63  // and if the plant is within the technical lifetime
64  // and if it is applicable for LTC's (i.e. not wind)
65  // and if there is no contract yet
66  if (getCurrentTick() > 0
67  && plant.isWithinTechnicalLifetime(getCurrentTick())
68  && plant.getTechnology().isApplicableForLongTermContract()
69  && reps.contractRepository
70  .findLongTermContractForPowerPlantActiveAtTime(
71  plant, getCurrentTick()) == null) {
72 
73  Zone zone = plant.getLocation().getZone();
74  double capacity = plant.getAvailableCapacity(getCurrentTick());
75  double fuelPriceStart = 0d;
76 
77  Substance mainFuel = null;
78  if (!plant.getFuelMix().isEmpty()) {
79  mainFuel = plant.getFuelMix().iterator().next()
80  .getSubstance();
81  fuelPriceStart = findLastKnownPriceForSubstance(mainFuel, getCurrentTick());
82  }
83 
84  double co2PriceStart = findLastKnownCO2Price(getCurrentTick());
85 
86  for (LongTermContractType type : reps.genericRepository
87  .findAll(LongTermContractType.class)) {
88 
89  double hours = 0d;
90  for (Segment s : type.getSegments()) {
91  hours += s.getLengthInHours();
92  }
93 
94  double averageElectricityPrice = determineAverageElectricityPrice(
95  hours, (int) producer.getLongTermContractPastTimeHorizon(), type);
96 
97  // Count the hours in this contract type.
98 
99  logger.info("LTC type: {}, number of hours: {}", type,
100  hours);
101  logger.info("Weighted average e-price: {}",
102  averageElectricityPrice);
103 
104  double passThroughCO2 = determineCO2Cost(plant)
105  / determineTotalAverageCost(plant, hours);
106  double passThroughFuel = determineFuelCost(plant)
107  / determineTotalAverageCost(plant, hours);
108 
109  long minimumDuration = Long.MAX_VALUE;
110  long maximumDuration = Long.MIN_VALUE;
111  for (LongTermContractDuration duration : reps.genericRepository
112  .findAll(LongTermContractDuration.class)) {
113  if (duration.getDuration() < minimumDuration) {
114  minimumDuration = duration.getDuration();
115  }
116  if (duration.getDuration() > maximumDuration) {
117  maximumDuration = duration.getDuration();
118  }
119  }
120  logger.info("Minimum duration: {} and maximum: {}",
121  minimumDuration, maximumDuration);
122 
123  for (LongTermContractDuration duration : reps.genericRepository
124  .findAll(LongTermContractDuration.class)) {
125 
126  double minimumPrice = (1 + producer
127  .getLongTermContractMargin())
128  * determineTotalAverageCost(plant, hours);
129  double maximumPrice = averageElectricityPrice;
130  // TODO use risk double riskAversionFactor = 1;
131 
132  // Check whether the maximum price is at
133  // least the minimum contract price. Otherwise,
134  // we'll use the minimum price.
135  double thisPrice = 0d;
136  if (maximumPrice < minimumPrice) {
137  thisPrice = minimumPrice;
138  } else {
139  thisPrice = minimumPrice
140  + (((maximumDuration - duration
141  .getDuration()) * (maximumPrice - minimumPrice)) / (maximumDuration - minimumDuration));
142  }
143  // Skip the first tick for now. Otherwise the
144  // contracts in the
145  LongTermContractOffer offer = reps.contractRepository
146  .submitLongTermContractOfferForElectricity(
147  producer, plant, zone, thisPrice,
148  capacity, type, getCurrentTick(),
149  duration, mainFuel, passThroughFuel,
150  passThroughCO2, fuelPriceStart,
151  co2PriceStart);
152  logger.info(
153  "Submitted offer for type {}. The offer: {}",
154  type, offer);
155  }
156  }
157  }
158  }
159  }
160 
168  private double determineAverageElectricityPrice(double hours, int horizon,
169  LongTermContractType type) {
170 
171  // Keep track of the number of prices found and the averages
172  int nrOfPrices = 0;
173  double averageElectricityPrice = 0d;
174 
175  // For each of the previous years
176  for (int i = -horizon; i <= -1; i++) {
177 
178  // Still valid
179  boolean valid = true;
180  double weightedElectricitySpotPrices = 0d;
181 
182  // For each of the segments in this type
183  for (Segment s : type.getSegments()) {
184 
185  // Try to find a price for this year
186  SegmentClearingPoint point = (SegmentClearingPoint) reps.clearingPointRepositoryOld
187  .findClearingPointForSegmentAndTime(s,
188  getCurrentTick() + i, false);
189 
190  // If there is a price, add it multiplied to the number of hours to the total.
191  if(point != null){
192  weightedElectricitySpotPrices += point.getPrice()
193  * s.getLengthInHours();
194  } else {
195  // Otherwise, no valid price is found for this year
196  valid = false;
197  }
198  }
199 
200  // If valid prices were found, we can use it.
201  if(valid){
202  nrOfPrices++;
203  averageElectricityPrice += weightedElectricitySpotPrices / hours;
204  }
205  }
206 
207  // Return the average
208  return averageElectricityPrice/nrOfPrices;
209  }
210 
219  private double determineTotalAverageCost(PowerPlant plant, double hours) {
220  double fixedOMCost = calculateFixedOperatingCost(plant, getCurrentTick())
221  / plant.getAvailableCapacity(getCurrentTick());
222  double fixedcapitalCost = plant.getActualInvestedCapital() //Doesn't consider the cost of capital, but just the overall invested capital
223  / plant.getTechnology().getDepreciationTime()/ plant.getAvailableCapacity(getCurrentTick());
224  return determineFuelCost(plant) + determineCO2Cost(plant)
225  + ((fixedOMCost + fixedcapitalCost) / hours);
226  }
227 
228  private double determineCO2Cost(PowerPlant plant) {
229  return calculateMarginalCO2Cost(plant, getCurrentTick(), false);
230  }
231 
232  private double determineFuelCost(PowerPlant plant) {
233  return calculateMarginalFuelCost(plant, getCurrentTick());
234  }
235 }
Iterable< PowerPlant > findOperationalPowerPlantsByOwner(@Param("owner") EnergyProducer owner,@Param("tick") long tick)