All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.powertac.distributionutility.DistributionUtilityService Maven / Gradle / Ivy

/*
 * Copyright 2009-2014 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 org.powertac.distributionutility;

import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.joda.time.Instant;
import org.powertac.common.config.ConfigurableValue;
import org.powertac.common.interfaces.Accounting;
import org.powertac.common.interfaces.BalancingMarket;
import org.powertac.common.interfaces.InitializationService;
import org.powertac.common.interfaces.ServerConfiguration;
import org.powertac.common.Broker;
import org.powertac.common.Competition;
import org.powertac.common.RandomSeed;
import org.powertac.common.TariffTransaction;
import org.powertac.common.interfaces.TimeslotPhaseProcessor;
import org.powertac.common.repo.BrokerRepo;
import org.powertac.common.repo.OrderbookRepo;
import org.powertac.common.repo.RandomSeedRepo;
import org.powertac.common.repo.TariffRepo;
import org.powertac.common.repo.TimeslotRepo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * Implementation of the Distribution Utility function. Levies a per-timeslot
 * charge based on the total energy transferred to and from customers in each
 * broker's portfolio.
 * 
 * @author John Collins
 */
@Service
public class DistributionUtilityService
extends TimeslotPhaseProcessor
implements InitializationService
{
  Logger log = Logger.getLogger(this.getClass().getSimpleName());

  @Autowired
  private BrokerRepo brokerRepo;

  @Autowired
  private TimeslotRepo timeslotRepo;

  @Autowired
  private OrderbookRepo orderbookRepo;
  
  @Autowired
  private TariffRepo tariffRepo;

  @Autowired
  private Accounting accounting;

  @Autowired
  private BalancingMarket balancingMarket;
  
  @Autowired
  private ServerConfiguration serverProps;

  @Autowired
  private RandomSeedRepo randomSeedService;
  private RandomSeed randomGen;

  // fees and prices should be negative, because they are debits against brokers
  @ConfigurableValue(valueType = "Double",
      description = "Low end of distribution fee range")
  private double distributionFeeMin = -0.005;

  @ConfigurableValue(valueType = "Double",
      description = "High end of distribution fee range")
  private double distributionFeeMax = -0.15;

  @ConfigurableValue(valueType = "Double",
      publish = true,
      description = "Distribution fee: overrides random value selection")
  private Double distributionFee = null;

  @Override
  public void setDefaults ()
  {
  }

  /**
   * Computes actual distribution and balancing costs by random selection
   */
  @Override
  public String initialize (Competition competition, List completedInits)
  {
    int index = completedInits.indexOf("BalancingMarket");
    if (index == -1) {
      return null;
    }

    super.init();
    distributionFee = null;

    serverProps.configureMe(this);
    
    // compute randomly-generated values if not overridden
    randomGen = randomSeedService.getRandomSeed("DistributionUtilityService",
                                                0, "model");
    if (null == distributionFee)
      distributionFee = (distributionFeeMin + randomGen.nextDouble()
                         * (distributionFeeMax - distributionFeeMin));
    log.info("Configured DU: distro fee = " + distributionFee);
    
    serverProps.publishConfiguration(this);
    return "DistributionUtility";
  }

  @Override
  public void activate (Instant time, int phaseNumber)
  {
    log.info("Activate");
    List brokerList = brokerRepo.findRetailBrokers();
    if (brokerList == null) {
      log.error("Failed to retrieve retail broker list");
      return;
    }

    // Add distribution transactions
    // should be total production + total consumption
    //    + final imbalance - balancing transactions
    Map> totals =
            accounting.getCurrentSupplyDemandByBroker();
    for (Broker broker : brokerList) {
      Map brokerTotals = totals.get(broker);
      if (null == brokerTotals)
        continue;
      double consumption = brokerTotals.get(TariffTransaction.Type.CONSUME);
      double production = brokerTotals.get(TariffTransaction.Type.PRODUCE);
      double imports = accounting.getCurrentMarketPosition(broker) * 1000.0;
      // balancing adjusts imports
      double imbalance = balancingMarket.getMarketBalance(broker); // >0 if oversupply
      double balanceAdj = balancingMarket.getRegulation(broker);
      log.info("Distribution tx for "
               + broker.getUsername() + "(c,p,m,i,b) = ("
               + consumption + ","
               + production + ","
               + imports + ","
               + imbalance + ","
               + balanceAdj + ")");
      double transport = (production - consumption - balanceAdj
                          + Math.abs(imports - imbalance)) / 2.0;
      accounting.addDistributionTransaction(broker, transport,
                                                   transport * distributionFee);
    }
  }

  // ---------- parameter getters ---------

  double getDistributionFeeMin ()
  {
    return distributionFeeMin;
  }

  double getDistributionFeeMax ()
  {
    return distributionFeeMax;
  }

  Double getDistributionFee ()
  {
    return distributionFee;
  }

  // -------- Delegation methods for backward compatibility -------
  // The only purpose of these methods is to produce configuration data for
  // older brokers. Should not be called by server code.

  /**
   * @deprecated
   * For backward-compatibility only - should not be called.
   */
  @ConfigurableValue(valueType = "Double",
      name = "balancingCost",
      publish = true,
      description = "Low end of distribution fee range")
  public double getBalancingCost ()
  {
    return balancingMarket.getBalancingCost();
  }


  /**
   * @deprecated
   * For backward-compatibility only - should not be called.
   */
  @ConfigurableValue(valueType = "Double",
      name = "pPlusPrime",
      publish = true,
      description = "Slope of up-regulation cost function")
  public double getPPlusPrime ()
  {
    return balancingMarket.getPPlusPrime();
  }


  /**
   * @deprecated
   * For backward-compatibility only - should not be called.
   */
  @ConfigurableValue(valueType = "Double",
      name = "pMinusPrime",
      publish = true,
      description = "slope of down-regulation cost function")
  public double getPMinusPrime()
  {
    return balancingMarket.getPMinusPrime();
  }


  /**
   * @deprecated
   * For backward-compatibility only - should not be called.
   */
  @ConfigurableValue(valueType = "Double",
      name = "defaultSpotPrice",
      publish = true,
      description = "value used for spot price/MWh if unavailable from market")
  public double getDefaultSpotPrice()
  {
    return balancingMarket.getDefaultSpotPrice();
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy