16 package emlab.gen.role.investment;
18 import java.util.HashMap;
20 import java.util.Map.Entry;
22 import java.util.TreeMap;
24 import org.springframework.beans.factory.annotation.Autowired;
25 import org.springframework.beans.factory.annotation.Configurable;
26 import org.springframework.data.annotation.Transient;
27 import org.springframework.data.neo4j.annotation.NodeEntity;
28 import org.springframework.data.neo4j.aspects.core.NodeBacked;
29 import org.springframework.data.neo4j.support.Neo4jTemplate;
30 import org.springframework.transaction.annotation.Transactional;
32 import agentspring.role.Role;
64 public class InvestInPowerGenerationTechnologiesRole<T
extends EnergyProducer> extends GenericInvestmentRole<T>
75 Neo4jTemplate
template;
83 Map<ElectricitySpotMarket, MarketInformation> marketInfoMap =
new HashMap<ElectricitySpotMarket, MarketInformation>();
86 public void act(T agent) {
88 long futureTimePoint = getCurrentTick() + agent.getInvestmentFutureTimeHorizon();
93 Map<Substance, Double> expectedFuelPrices = predictFuelPrices(agent, futureTimePoint);
96 Map<ElectricitySpotMarket, Double> expectedCO2Price = determineExpectedCO2PriceInclTax(futureTimePoint,
97 agent.getNumberOfYearsBacklookingForForecasting(), getCurrentTick());
102 Map<ElectricitySpotMarket, Double> expectedDemand =
new HashMap<ElectricitySpotMarket, Double>();
105 for(
long time = getCurrentTick(); time>getCurrentTick()-agent.getNumberOfYearsBacklookingForForecasting() && time>=0; time=time-1){
106 gtr.addData(time, elm.getDemandGrowthTrend().getValue(time));
108 expectedDemand.put(elm, gtr.predict(futureTimePoint));
118 MarketInformation marketInformation =
new MarketInformation(market, expectedDemand, expectedFuelPrices, expectedCO2Price.get(market)
119 .doubleValue(), futureTimePoint);
137 double highestValue = Double.MIN_VALUE;
143 plant.specifyNotPersist(getCurrentTick(), agent, getNodeForZone(market.getZone()), technology);
146 double expectedInstalledCapacityOfTechnology = reps.powerPlantRepository
147 .calculateCapacityOfExpectedOperationalPowerPlantsInMarketAndTechnology(market, technology, futureTimePoint);
149 if(technologyTarget!=null){
150 double technologyTargetCapacity = technologyTarget.getTrend().getValue(futureTimePoint);
151 expectedInstalledCapacityOfTechnology = (technologyTargetCapacity > expectedInstalledCapacityOfTechnology) ? technologyTargetCapacity : expectedInstalledCapacityOfTechnology;
153 double pgtNodeLimit = Double.MAX_VALUE;
155 .findOneByTechnologyAndNode(technology, plant.getLocation());
156 if (pgtLimit != null) {
157 pgtNodeLimit = pgtLimit.getUpperCapacityLimit(futureTimePoint);
159 double expectedInstalledCapacityOfTechnologyInNode = reps.powerPlantRepository
160 .calculateCapacityOfExpectedOperationalPowerPlantsByNodeAndTechnology(plant.getLocation(),
161 technology, futureTimePoint);
162 double expectedOwnedTotalCapacityInMarket = reps.powerPlantRepository
163 .calculateCapacityOfExpectedOperationalPowerPlantsInMarketByOwner(market, futureTimePoint, agent);
164 double expectedOwnedCapacityInMarketOfThisTechnology = reps.powerPlantRepository
165 .calculateCapacityOfExpectedOperationalPowerPlantsInMarketByOwnerAndTechnology(market, technology, futureTimePoint,
167 double capacityOfTechnologyInPipeline = reps.powerPlantRepository.calculateCapacityOfPowerPlantsByTechnologyInPipeline(
168 technology, getCurrentTick());
169 double operationalCapacityOfTechnology = reps.powerPlantRepository.calculateCapacityOfOperationalPowerPlantsByTechnology(
170 technology, getCurrentTick());
171 double capacityInPipelineInMarket = reps.powerPlantRepository
172 .calculateCapacityOfPowerPlantsByMarketInPipeline(market, getCurrentTick());
176 .getMaximumInstalledCapacityFractionInCountry()) {
182 }
else if (expectedOwnedCapacityInMarketOfThisTechnology > expectedOwnedTotalCapacityInMarket
183 * technology.getMaximumInstalledCapacityFractionPerAgent()) {
187 }
else if (capacityInPipelineInMarket > 0.2 * marketInformation.maxExpectedLoad) {
190 }
else if ((capacityOfTechnologyInPipeline > 2.0 * operationalCapacityOfTechnology)
191 && capacityOfTechnologyInPipeline > 9000) {
196 }
else if (plant.getActualInvestedCapital() * (1 - agent.getDebtRatioOfInvestments()) > agent
197 .getDownpaymentFractionOfCash() * agent.getCash()) {
203 Map<Substance, Double> myFuelPrices =
new HashMap<Substance, Double>();
204 for (
Substance fuel : technology.getFuels()) {
205 myFuelPrices.put(fuel, expectedFuelPrices.get(fuel));
207 Set<SubstanceShareInFuelMix> fuelMix = calculateFuelMix(plant, myFuelPrices, expectedCO2Price.get(market));
208 plant.setFuelMix(fuelMix);
210 double expectedMarginalCost = determineExpectedMarginalCost(plant, expectedFuelPrices, expectedCO2Price.get(market));
211 double runningHours = 0d;
212 double expectedGrossProfit = 0d;
214 long numberOfSegments = reps.segmentRepository.count();
219 for (
SegmentLoad segmentLoad : market.getLoadDurationCurve()) {
220 double expectedElectricityPrice = marketInformation.expectedElectricityPricesPerSegment.get(segmentLoad
222 double hours = segmentLoad.getSegment().getLengthInHours();
223 if (expectedMarginalCost <= expectedElectricityPrice) {
224 runningHours += hours;
225 expectedGrossProfit += (expectedElectricityPrice - expectedMarginalCost) * hours
226 * plant.getAvailableCapacity(futureTimePoint, segmentLoad.getSegment(), numberOfSegments);
234 if (runningHours < plant.getTechnology().getMinimumRunningHours()) {
240 double fixedOMCost = calculateFixedOperatingCost(plant, getCurrentTick());
243 double operatingProfit = expectedGrossProfit - fixedOMCost;
253 double wacc = (1 - agent.getDebtRatioOfInvestments()) * agent.getEquityInterestRate()
254 + agent.getDebtRatioOfInvestments() * agent.getLoanInterestRate();
258 TreeMap<Integer, Double> discountedProjectCapitalOutflow = calculateSimplePowerPlantInvestmentCashFlow(
259 technology.getDepreciationTime(), (int) plant.getActualLeadtime(),
260 plant.getActualInvestedCapital(), 0);
262 TreeMap<Integer, Double> discountedProjectCashInflow = calculateSimplePowerPlantInvestmentCashFlow(
263 technology.getDepreciationTime(), (int) plant.getActualLeadtime(), 0, operatingProfit);
265 double discountedCapitalCosts = npv(discountedProjectCapitalOutflow, wacc);
274 double discountedOpProfit = npv(discountedProjectCashInflow, wacc);
280 double projectValue = discountedOpProfit + discountedCapitalCosts;
301 highestValue = projectValue / plant.getActualNominalCapacity();
302 bestTechnology = plant.getTechnology();
309 if (bestTechnology != null) {
313 plant.specifyAndPersist(getCurrentTick(), agent, getNodeForZone(market.getZone()), bestTechnology);
315 BigBank bigbank = reps.genericRepository.findFirst(BigBank.class);
317 double investmentCostPayedByEquity = plant.getActualInvestedCapital() * (1 - agent.getDebtRatioOfInvestments());
318 double investmentCostPayedByDebt = plant.getActualInvestedCapital() * agent.getDebtRatioOfInvestments();
319 double downPayment = investmentCostPayedByEquity;
320 createSpreadOutDownPayments(agent, manufacturer, downPayment, plant);
322 double amount = determineLoanAnnuities(investmentCostPayedByDebt, plant.getTechnology().getDepreciationTime(),
323 agent.getLoanInterestRate());
325 Loan loan = reps.loanRepository.createLoan(agent, bigbank, amount, plant.getTechnology().getDepreciationTime(),
326 getCurrentTick(), plant);
328 plant.createOrUpdateLoan(loan);
335 setNotWillingToInvest(agent);
346 int buildingTime = (int) plant.getActualLeadtime();
347 reps.nonTransactionalCreateRepository.createCashFlow(agent, manufacturer, totalDownPayment / buildingTime,
348 CashFlow.DOWNPAYMENT, getCurrentTick(), plant);
349 Loan downpayment = reps.loanRepository.createLoan(agent, manufacturer, totalDownPayment / buildingTime,
350 buildingTime - 1, getCurrentTick(), plant);
351 plant.createOrUpdateDownPayment(downpayment);
356 agent.setWillingToInvest(
false);
368 Map<Substance, Double> expectedFuelPrices =
new HashMap<Substance, Double>();
369 for (
Substance substance : reps.substanceRepository.findAllSubstancesTradedOnCommodityMarkets()) {
371 Iterable<ClearingPoint> cps = reps.clearingPointRepository
372 .findAllClearingPointsForSubstanceTradedOnCommodityMarkesAndTimeRange(substance, getCurrentTick()
373 - (agent.getNumberOfYearsBacklookingForForecasting() - 1), getCurrentTick(),
false);
379 gtr.addData(clearingPoint.getTime(), clearingPoint.getPrice());
381 expectedFuelPrices.put(substance, gtr.predict(futureTimePoint));
384 return expectedFuelPrices;
390 private TreeMap<Integer, Double> calculateSimplePowerPlantInvestmentCashFlow(
int depriacationTime,
int buildingTime,
391 double totalInvestment,
double operatingProfit) {
392 TreeMap<Integer, Double> investmentCashFlow =
new TreeMap<Integer, Double>();
393 double equalTotalDownPaymentInstallement = totalInvestment / buildingTime;
394 for (
int i = 0; i < buildingTime; i++) {
395 investmentCashFlow.put(
new Integer(i), -equalTotalDownPaymentInstallement);
397 for (
int i = buildingTime; i < depriacationTime + buildingTime; i++) {
398 investmentCashFlow.put(
new Integer(i), operatingProfit);
401 return investmentCashFlow;
404 private double npv(TreeMap<Integer, Double> netCashFlow,
double wacc) {
406 for (Integer iterator : netCashFlow.keySet()) {
407 npv += netCashFlow.get(iterator).doubleValue() / Math.pow(1 + wacc, iterator.intValue());
412 public double determineExpectedMarginalCost(PowerPlant plant, Map<Substance, Double> expectedFuelPrices,
double expectedCO2Price) {
413 double mc = determineExpectedMarginalFuelCost(plant, expectedFuelPrices);
414 double co2Intensity = plant.calculateEmissionIntensity();
415 mc += co2Intensity * expectedCO2Price;
419 public double determineExpectedMarginalFuelCost(PowerPlant powerPlant, Map<Substance, Double> expectedFuelPrices) {
421 for (SubstanceShareInFuelMix mix : powerPlant.getFuelMix()) {
422 double amount = mix.getShare();
423 double fuelPrice = expectedFuelPrices.get(mix.getSubstance());
424 fc += amount * fuelPrice;
429 private PowerGridNode getNodeForZone(Zone zone) {
430 for (PowerGridNode node : reps.genericRepository.findAll(PowerGridNode.class)) {
431 if (node.getZone().equals(zone)) {
438 private class MarketInformation {
440 Map<Segment, Double> expectedElectricityPricesPerSegment;
441 double maxExpectedLoad = 0d;
442 Map<PowerPlant, Double> meritOrder;
445 MarketInformation(ElectricitySpotMarket market, Map<ElectricitySpotMarket, Double> expectedDemand, Map<Substance, Double> fuelPrices,
double co2price,
long time) {
447 expectedElectricityPricesPerSegment =
new HashMap<Segment, Double>();
448 Map<PowerPlant, Double> marginalCostMap =
new HashMap<PowerPlant, Double>();
452 for (PowerPlant plant : reps.powerPlantRepository.findExpectedOperationalPowerPlantsInMarket(market, time)) {
454 double plantMarginalCost = determineExpectedMarginalCost(plant, fuelPrices, co2price);
455 marginalCostMap.put(plant, plantMarginalCost);
456 capacitySum += plant.getActualNominalCapacity();
460 for(PowerGeneratingTechnologyTarget pggt : reps.powerGenerationTechnologyTargetRepository.findAllByMarket(market)){
461 double expectedTechnologyCapacity = reps.powerPlantRepository.calculateCapacityOfExpectedOperationalPowerPlantsInMarketAndTechnology(market, pggt.getPowerGeneratingTechnology(), time);
462 double targetDifference = pggt.getTrend().getValue(time) - expectedTechnologyCapacity;
463 if(targetDifference > 0){
464 PowerPlant plant =
new PowerPlant();
465 plant.specifyNotPersist(getCurrentTick(),
new EnergyProducer(), reps.powerGridNodeRepository.findFirstPowerGridNodeByElectricitySpotMarket(market), pggt.getPowerGeneratingTechnology());
466 plant.setActualNominalCapacity(targetDifference);
467 double plantMarginalCost = determineExpectedMarginalCost(plant, fuelPrices, co2price);
468 marginalCostMap.put(plant, plantMarginalCost);
469 capacitySum += targetDifference;
473 MapValueComparator comp =
new MapValueComparator(marginalCostMap);
474 meritOrder =
new TreeMap<PowerPlant, Double>(comp);
475 meritOrder.putAll(marginalCostMap);
477 long numberOfSegments = reps.segmentRepository.count();
479 double demandFactor = expectedDemand.get(market).doubleValue();
482 for (SegmentLoad segmentLoad : market.getLoadDurationCurve()) {
484 double expectedSegmentLoad = segmentLoad.getBaseLoad() * demandFactor;
486 if (expectedSegmentLoad > maxExpectedLoad) {
487 maxExpectedLoad = expectedSegmentLoad;
490 double segmentSupply = 0d;
491 double segmentPrice = 0d;
492 double totalCapacityAvailable = 0d;
494 for (Entry<PowerPlant, Double> plantCost : meritOrder.entrySet()) {
495 PowerPlant plant = plantCost.getKey();
496 double plantCapacity = 0d;
499 plantCapacity = plant.getExpectedAvailableCapacity(time, segmentLoad.getSegment(), numberOfSegments);
500 totalCapacityAvailable += plantCapacity;
504 if (segmentSupply < expectedSegmentLoad) {
505 segmentSupply += plantCapacity;
506 segmentPrice = plantCost.getValue();
517 double reservePrice = 0;
518 double reserveVolume = 0;
519 for (StrategicReserveOperator
operator : strategicReserveOperatorRepository.findAll()) {
520 ElectricitySpotMarket market1 = reps.marketRepository.findElectricitySpotMarketForZone(operator
522 if (market.getNodeId().intValue() == market1.getNodeId().intValue()) {
523 reservePrice = operator.getReservePriceSR();
524 reserveVolume = operator.getReserveVolume();
528 if (segmentSupply >= expectedSegmentLoad
529 && ((totalCapacityAvailable - expectedSegmentLoad) <= (reserveVolume))) {
530 expectedElectricityPricesPerSegment.put(segmentLoad.getSegment(), reservePrice);
533 }
else if (segmentSupply >= expectedSegmentLoad
534 && ((totalCapacityAvailable - expectedSegmentLoad) > (reserveVolume))) {
535 expectedElectricityPricesPerSegment.put(segmentLoad.getSegment(), segmentPrice);
539 expectedElectricityPricesPerSegment.put(segmentLoad.getSegment(), market.getValueOfLostLoad());
Map< Substance, Double > predictFuelPrices(EnergyProducer agent, long futureTimePoint)
double getActualNominalCapacity()