/*******************************************************************************
* Copyright 2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package emlab.domain.factory;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.transaction.annotation.Transactional;
import emlab.domain.agent.EnergyProducer;
import emlab.domain.contract.Loan;
import emlab.domain.gis.Zone;
import emlab.domain.market.electricity.ElectricitySpotMarket;
import emlab.domain.market.electricity.SegmentLoad;
import emlab.domain.technology.PowerGeneratingTechnology;
import emlab.domain.technology.PowerGridNode;
import emlab.domain.technology.PowerPlant;
public class ElectricityProducerFactory implements InitializingBean {
private double capacityMargin;
private Map<PowerGeneratingTechnology, Double> portfolioShares = null;
private Set<PowerGridNode> nodes;
private ElectricitySpotMarket market;
private List<EnergyProducer> producers;
static final Logger logger = LoggerFactory.getLogger(ElectricityProducerFactory.class);
@Override
public void afterPropertiesSet() throws Exception {
createPowerPlantsForMarket(market);
}
@Transactional
private PowerPlant createPowerPlant(PowerGeneratingTechnology technology, EnergyProducer energyProducer, PowerGridNode location) {
PowerPlant plant = new PowerPlant().persist();
String label = energyProducer.getName() + " - " + technology.getName();
plant.setName(label);
plant.setTechnology(technology);
plant.setOwner(energyProducer);
plant.setLocation(location);
plant.setConstructionStartTime(-(technology.getExpectedLeadtime() + technology.getExpectedPermittime() + Math.round((Math.random() * technology
.getExpectedLifetime()))) + 2); // TODO: Why include expected lead
// time and permit time? Wouldn't it
// be realistic to have some PP in
// the pipeline at the start?
plant.setActualLeadtime(plant.getTechnology().getExpectedLeadtime());
plant.setActualPermittime(plant.getTechnology().getExpectedPermittime());
plant.setExpectedEndOfLife(plant.getConstructionStartTime() + plant.getActualPermittime() + plant.getActualLeadtime()
+ plant.getTechnology().getExpectedLifetime());
plant.calculateAndSetActualInvestedCapital(plant.getConstructionStartTime());
plant.calculateAndSetActualEfficiency(plant.getConstructionStartTime());
plant.setDismantleTime(1000);
Loan loan = new Loan().persist();
loan.setFrom(energyProducer);
loan.setTo(null);
double amountPerPayment = determineLoanAnnuities(plant.getActualInvestedCapital() * energyProducer.getDebtRatioOfInvestments(),
plant.getTechnology().getDepreciationTime(), energyProducer.getLoanInterestRate());
loan.setAmountPerPayment(amountPerPayment);
loan.setTotalNumberOfPayments(plant.getTechnology().getDepreciationTime());
loan.setLoanStartTime(plant.getConstructionStartTime());
loan.setNumberOfPaymentsDone(-plant.getConstructionStartTime());// Some
// payments
// are
// already
// made
plant.setLoan(loan);
return plant;
}
private void createPowerPlantsForMarket(ElectricitySpotMarket market) {
double maxLoad = Double.MIN_NORMAL;
// get max load
for (SegmentLoad segmentLoad : market.getLoadDurationCurve()) {
if (maxLoad < segmentLoad.getBaseLoad()) {
maxLoad = segmentLoad.getBaseLoad();
}
}
double requiredCapacity = maxLoad * (1 + capacityMargin);
logger.info("required capacity for market {} is {}", market, requiredCapacity);
for (PowerGeneratingTechnology technology : portfolioShares.keySet()) {
double pctValue = portfolioShares.get(technology);
double requiredCapacityForTechnology = pctValue * requiredCapacity;
logger.info("required capacity within this market for technology {} is {}", technology, requiredCapacityForTechnology);
// logger.info("required capacity: {} for technology {} before creating",
// requiredCapacityForTechnology, technology);
while (requiredCapacityForTechnology > 0) {
EnergyProducer energyProducer = getRandomProducer(producers);
PowerPlant plant = createPowerPlant(technology, energyProducer, getNodeForZone(market.getZone()));
requiredCapacityForTechnology -= plant.getAvailableCapacity(0);
}
// logger.info("required capacity: {} for technology {} after creating",
// requiredCapacityForTechnology, technology);
}
}
private EnergyProducer getRandomProducer(List<EnergyProducer> producers) {
if (producers.size() > 0) {
int size = producers.size();
int index = getRandomIndexFromList(size);
return producers.get(index);
}
return null;
}
private int getRandomIndexFromList(int size) {
return (int) Math.min(Math.floor(Math.random() * size), size - 1);
}
private PowerGridNode getNodeForZone(Zone zone) {
for (PowerGridNode node : nodes) {
if (node.getZone().equals(zone)) {
return node;
}
}
return null;
}
public double getCapacityMargin() {
return capacityMargin;
}
public void setCapacityMargin(double capacityMargin) {
this.capacityMargin = capacityMargin;
}
public Map<PowerGeneratingTechnology, Double> getPortfolioShares() {
return portfolioShares;
}
public void setPortfolioShares(Map<PowerGeneratingTechnology, Double> portfolioShares) {
this.portfolioShares = portfolioShares;
}
public Set<PowerGridNode> getNodes() {
return nodes;
}
public void setNodes(Set<PowerGridNode> nodes) {
this.nodes = nodes;
}
public ElectricitySpotMarket getMarket() {
return market;
}
public void setMarket(ElectricitySpotMarket market) {
logger.info("setting market {}", market);
this.market = market;
}
public List<EnergyProducer> getProducers() {
return producers;
}
public void setProducers(List<EnergyProducer> producers) {
this.producers = producers;
}
public double determineLoanAnnuities(double totalLoan, double payBackTime, double interestRate) {
double q = 1 + interestRate;
double annuity = totalLoan * (Math.pow(q, payBackTime) * (q - 1)) / (Math.pow(q, payBackTime) - 1);
return annuity;
}
}