emlab.role.market.SubmitLongTermElectricityContractsRole.java Source code

Java tutorial

Introduction

Here is the source code for emlab.role.market.SubmitLongTermElectricityContractsRole.java

Source

/*******************************************************************************
 * 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.role.market;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import agentspring.role.Role;
import agentspring.role.RoleComponent;
import emlab.domain.agent.EnergyProducer;
import emlab.domain.contract.LongTermContractDuration;
import emlab.domain.contract.LongTermContractOffer;
import emlab.domain.contract.LongTermContractType;
import emlab.domain.gis.Zone;
import emlab.domain.market.Bid;
import emlab.domain.market.electricity.ElectricitySpotMarket;
import emlab.domain.market.electricity.Segment;
import emlab.domain.market.electricity.SegmentClearingPoint;
import emlab.domain.technology.PowerPlant;
import emlab.domain.technology.Substance;
import emlab.repository.Reps;
import emlab.role.AbstractEnergyProducerRole;

/**
 * {@link EnergyProducer} submits offers to the {@link ElectricitySpotMarket}.
 * One {@link Bid} per {@link PowerPlant}.
 * 
 * @author <a href="mailto:A.Chmieliauskas@tudelft.nl">Alfredas
 *         Chmieliauskas</a> @author <a
 *         href="mailto:E.J.L.Chappin@tudelft.nl">Emile Chappin</a>
 * 
 */
@RoleComponent
public class SubmitLongTermElectricityContractsRole extends AbstractEnergyProducerRole
        implements Role<EnergyProducer> {

    @Autowired
    Reps reps;

    @Override
    public Reps getReps() {
        return reps;
    }

    @Transactional
    public void act(EnergyProducer producer) {

        // TODO Contracts for checking assigned to power plants??
        // When dismantling, take over existing contract by new power plant?
        for (PowerPlant plant : reps.powerPlantRepository.findOperationalPowerPlantsByOwner(producer,
                getCurrentTick())) {

            // if it is not in the first tick,
            // and if the plant is within the technical lifetime
            // and if it is applicable for LTC's (i.e. not wind)
            // and if there is no contract yet
            if (getCurrentTick() > 0 && plant.isWithinTechnicalLifetime(getCurrentTick())
                    && plant.getTechnology().isApplicableForLongTermContract() && reps.contractRepository
                            .findLongTermContractForPowerPlantActiveAtTime(plant, getCurrentTick()) == null) {

                Zone zone = plant.getLocation().getZone();
                double capacity = plant.getAvailableCapacity(getCurrentTick());
                double fuelPriceStart = 0d;

                Substance mainFuel = null;
                if (!plant.getFuelMix().isEmpty()) {
                    mainFuel = plant.getFuelMix().iterator().next().getSubstance();
                    fuelPriceStart = findLastKnownPriceForSubstance(mainFuel);
                }

                double co2PriceStart = findLastKnownCO2Price();

                for (LongTermContractType type : reps.genericRepository.findAll(LongTermContractType.class)) {

                    double hours = 0d;
                    for (Segment s : type.getSegments()) {
                        hours += s.getLengthInHours();
                    }

                    double averageElectricityPrice = determineAverageElectricityPrice(hours,
                            (int) producer.getLongTermContractPastTimeHorizon(), type);

                    // Count the hours in this contract type.

                    logger.info("LTC type: {}, number of hours: {}", type, hours);
                    logger.info("Weighted average e-price: {}", averageElectricityPrice);

                    double passThroughCO2 = determineCO2Cost(plant) / determineTotalAverageCost(plant, hours);
                    double passThroughFuel = determineFuelCost(plant) / determineTotalAverageCost(plant, hours);

                    long minimumDuration = Long.MAX_VALUE;
                    long maximumDuration = Long.MIN_VALUE;
                    for (LongTermContractDuration duration : reps.genericRepository
                            .findAll(LongTermContractDuration.class)) {
                        if (duration.getDuration() < minimumDuration) {
                            minimumDuration = duration.getDuration();
                        }
                        if (duration.getDuration() > maximumDuration) {
                            maximumDuration = duration.getDuration();
                        }
                    }
                    logger.info("Minimum duration: {} and maximum: {}", minimumDuration, maximumDuration);

                    for (LongTermContractDuration duration : reps.genericRepository
                            .findAll(LongTermContractDuration.class)) {

                        double minimumPrice = (1 + producer.getLongTermContractMargin())
                                * determineTotalAverageCost(plant, hours);
                        double maximumPrice = averageElectricityPrice;
                        // TODO use risk double riskAversionFactor = 1;

                        // Check whether the maximum price is at
                        // least the minimum contract price. Otherwise,
                        // we'll use the minimum price.
                        double thisPrice = 0d;
                        if (maximumPrice < minimumPrice) {
                            thisPrice = minimumPrice;
                        } else {
                            thisPrice = minimumPrice
                                    + (((maximumDuration - duration.getDuration()) * (maximumPrice - minimumPrice))
                                            / (maximumDuration - minimumDuration));
                        }
                        // Skip the first tick for now. Otherwise the
                        // contracts in the
                        LongTermContractOffer offer = reps.contractRepository
                                .submitLongTermContractOfferForElectricity(producer, plant, zone, thisPrice,
                                        capacity, type, getCurrentTick(), duration, mainFuel, passThroughFuel,
                                        passThroughCO2, fuelPriceStart, co2PriceStart);
                        logger.info("Submitted offer for type {}. The offer: {}", type, offer);
                    }
                }
            }
        }
    }

    /**
     * Determines the average electricity price weighted by hours of segments of a previous number of years.
     * @param hours the total hours in these segments
     * @param type the contract type
     * @param the horizon to look back
     * @return the average price
     */
    private double determineAverageElectricityPrice(double hours, int horizon, LongTermContractType type) {

        // Keep track of the number of prices found and the averages
        int nrOfPrices = 0;
        double averageElectricityPrice = 0d;

        // For each of the previous years
        for (int i = -horizon; i <= -1; i++) {

            // Still valid
            boolean valid = true;
            double weightedElectricitySpotPrices = 0d;

            // For each of the segments in this type
            for (Segment s : type.getSegments()) {

                // Try to find a price for this year
                SegmentClearingPoint point = (SegmentClearingPoint) reps.clearingPointRepositoryOld
                        .findClearingPointForSegmentAndTime(s, getCurrentTick() + i);

                // If there is a price, add it multiplied to the number of hours to the total. 
                if (point != null) {
                    weightedElectricitySpotPrices += point.getPrice() * s.getLengthInHours();
                } else {
                    // Otherwise, no valid price is found for this year
                    valid = false;
                }
            }

            // If valid prices were found, we can use it.
            if (valid) {
                nrOfPrices++;
                averageElectricityPrice += weightedElectricitySpotPrices / hours;
            }
        }

        // Return the average
        return averageElectricityPrice / nrOfPrices;
    }

    /**
     * Determines the total average cost for a power plant, based on fixed and
     * variable cost, averaged out over a number of running hours.
     * 
     * @param plant
     * @param hours
     * @return
     */
    private double determineTotalAverageCost(PowerPlant plant, double hours) {
        double fixedOMCost = calculateFixedOperatingCost(plant) / plant.getAvailableCapacity(getCurrentTick());
        double fixedcapitalCost = plant.getActualInvestedCapital() //Doesn't consider the cost of capital, but just the overall invested capital
                / plant.getTechnology().getDepreciationTime() / plant.getAvailableCapacity(getCurrentTick());
        return determineFuelCost(plant) + determineCO2Cost(plant) + ((fixedOMCost + fixedcapitalCost) / hours);
    }

    private double determineCO2Cost(PowerPlant plant) {
        return calculateMarginalCO2Cost(plant);
    }

    private double determineFuelCost(PowerPlant plant) {
        return calculateMarginalFuelCost(plant);
    }
}