EMlab-generation Documentation  1.0
Documentation of the EMLab-Generation model.
AbstractMarketRole.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.data.neo4j.support.Neo4jTemplate;
20 import org.springframework.transaction.annotation.Transactional;
21 
22 import agentspring.role.AbstractRole;
28 
37 public abstract class AbstractMarketRole<T extends DecarbonizationMarket> extends AbstractRole<T> {
38 
39  @Autowired
40  Neo4jTemplate template;
41 
42  @Autowired
43  Reps reps;
44 
45  @Transactional
46  public ClearingPoint calculateClearingPoint(DecarbonizationMarket market, long time) {
47  double clearedVolume = 0d;
48  double clearedPrice = 0d;
49  double totalSupplyPrice = calculateTotalSupplyPriceForMarketForTime(market, time);
50  double totalSupply = calculateTotalSupplyForMarketForTime(market, time);
51  logger.info("total supply {} total price {}", totalSupply, totalSupplyPrice);
52  double totalDemandForPrice = calculateTotalDemandForMarketForTimeForPrice(market, time, totalSupplyPrice);
53  logger.info("total demand {} for price {}", totalDemandForPrice, totalSupplyPrice);
54 
55  double minimumSupplyPrice = calculateMinimumSupplyPriceForMarketForTime(market, time);
56  double demandAtMinimumSupplyPrice = calculateTotalDemandForMarketForTimeForPrice(market, time, totalSupplyPrice);
57 
58  if (demandAtMinimumSupplyPrice <= 0) {
59  clearedPrice = minimumSupplyPrice;
60  clearedVolume = 0;
61  } else if (totalDemandForPrice > totalSupply) {
62  // Not enough to meet demand
63  clearedVolume = totalSupply;
64  if (market.isAuction()) {
65  clearedPrice = calculateTotalDemandForMarketForTimeForPrice(market, time, 0d);
66  } else {
67  clearedPrice = market instanceof ElectricitySpotMarket ? ((ElectricitySpotMarket) market).getValueOfLostLoad()
68  : totalSupplyPrice;
69  }
70  } else { // Supply exceeds demand
71  double totalOfferAmount = 0d;
72  double previousPrice = 0d;
73  for (Bid offer : reps.bidRepository.findOffersForMarketForTime(market, time)) {
74  double price = offer.getPrice();
75  double amount = offer.getAmount();
76  double demand = calculateTotalDemandForMarketForTimeForPrice(market, time, price);
77  if (demand < totalOfferAmount + amount) {
78  if (demand == 0) {
79  if (getCurrentTick() > 0) {
80  ClearingPoint cp = reps.clearingPointRepository.findClearingPointForMarketAndTime(market,
81  getCurrentTick() - 1, false);
82  if (cp != null)
83  previousPrice = cp.getPrice();
84  }
85  clearedPrice = previousPrice;
86  clearedVolume = totalOfferAmount;
87  } else if (totalOfferAmount >= demand) {
88  clearedPrice = previousPrice;
89  clearedVolume = totalOfferAmount;
90  } else {
91  clearedPrice = price;
92  clearedVolume = demand;
93  }
94  break;
95  }
96  totalOfferAmount += amount;
97  previousPrice = price;
98  }
99  }
100  ClearingPoint point = new ClearingPoint().persist();
101  point.setAbstractMarket(market);
102  point.setTime(time);
103  point.setPrice(Math.max(0, clearedPrice));
104  point.setVolume(clearedVolume);
105  point.setForecast(false);
106 
107  // set bids to accepted and check for partial acceptance
108  // DEMAND
109  double previousPrice = markAcceptedBids(point, false);
110  // if auction - last accepted demand bid sets the price
111  if (market.isAuction()) {
112  point.setPrice(Math.max(0, previousPrice));
113  }
114  // SUPPLY
115  markAcceptedBids(point, true);
116  return point;
117  }
118 
119  private double markAcceptedBids(ClearingPoint point, boolean isSupply) {
120  long time = point.getTime();
121  DecarbonizationMarket market = point.getAbstractMarket();
122  double clearedPrice = point.getPrice();
123  double clearedVolume = point.getVolume();
124  double totalBidVolume = 0d;
125  double previousPrice = Double.NEGATIVE_INFINITY;
126  double accpetedSamePriceVolume = 0d;
127 
128  Iterable<Bid> bids = isSupply ? reps.bidRepository.findOffersForMarketForTimeBelowPrice(market, time, clearedPrice) : market
129  .isAuction() ? reps.bidRepository.findDemandBidsForMarketForTime(market, time) : reps.bidRepository
130  .findDemandBidsForMarketForTimeAbovePrice(market, time, clearedPrice);
131 
132  for (Bid bid : bids) {
133  double amount = bid.getAmount();
134  totalBidVolume += amount;
135  accpetedSamePriceVolume = bid.getPrice() == previousPrice ? accpetedSamePriceVolume + amount : amount;
136  if (totalBidVolume < clearedVolume) {
137  bid.setStatus(Bid.ACCEPTED);
138  bid.setAcceptedAmount(bid.getAmount());
139  } else {
140  double lastAvailableBidSize = clearedVolume - (totalBidVolume - accpetedSamePriceVolume);
141  double samePriceVolume = calculateBidsForMarketForTimeForPrice(market, time, bid.getPrice(), isSupply);
142  double adjustRatio = lastAvailableBidSize / samePriceVolume;
143  for (Bid partBid : isSupply ? reps.bidRepository.findOffersForMarketForTimeForPrice(market, time, bid.getPrice())
144  : reps.bidRepository.findDemandBidsForMarketForTimeForPrice(market, time, bid.getPrice())) {
145  partBid.setStatus(Bid.PARTLY_ACCEPTED);
146  partBid.setAcceptedAmount(partBid.getAmount() * adjustRatio);
147  }
148  break;
149  }
150  previousPrice = bid.getPrice();
151  }
152  return previousPrice;
153  }
154 
155  private double calculateBidsForMarketForTimeForPrice(DecarbonizationMarket market, long time, double price, boolean isSupply) {
156  try {
157  return isSupply ? reps.bidRepository.calculateOffersForMarketForTimeForPrice(market, time, price) : reps.bidRepository
158  .calculateDemandBidsForMarketForTimeForPrice(market, time, price);
159  } catch (NullPointerException npe) {
160  }
161  return 0d;
162  }
163 
164  private double calculateTotalDemandForMarketForTimeForPrice(DecarbonizationMarket market, long time, double price) {
165  try {
166  return market.isAuction() ? reps.bidRepository.calculateTotalDemandForMarketForTime(market, time) : reps.bidRepository
167  .calculateTotalDemandForMarketForTimeForPrice(market, time, price);
168  } catch (NullPointerException npe) {
169  }
170  return 0d;
171  }
172 
173  private double calculateTotalSupplyPriceForMarketForTime(DecarbonizationMarket market, long time) {
174  try {
175  return reps.bidRepository.calculateTotalSupplyPriceForMarketForTime(market, time);
176  } catch (NullPointerException e) {
177  }
178  return 0d;
179  }
180 
181  private double calculateTotalSupplyForMarketForTime(DecarbonizationMarket market, long time) {
182  try {
183  return reps.bidRepository.calculateTotalSupplyForMarketForTime(market, time);
184  } catch (NullPointerException e) {
185  }
186  return 0d;
187  }
188 
189  private double calculateMinimumSupplyPriceForMarketForTime(DecarbonizationMarket market, long time) {
190  try {
191  return reps.bidRepository.calculateMinimumSupplyPriceForMarketForTime(market, time);
192  } catch (NullPointerException e) {
193  }
194  return 0d;
195  }
196 
197  public abstract Reps getReps();
198 }