From f452b3a98a720223894016fbdc8b6f5404b5b13e Mon Sep 17 00:00:00 2001 From: Govert Buijs Date: Fri, 28 Feb 2014 13:31:54 +0100 Subject: [PATCH] Added prototype for PortFolioManager in MatLab --- lib/matlabcontrol-4.1.0.jar | Bin 0 -> 141637 bytes pom.xml | 7 +- .../samplebroker/PortfolioManagerProxy.java | 247 +++++++ .../samplebroker/PortfolioManagerService.java | 654 ------------------ .../samplebroker/core/BrokerMain.java | 28 +- .../core/BrokerPropertiesService.java | 15 +- .../samplebroker/core/BrokerRunner.java | 69 +- .../samplebroker/core/ClassPathHacker.java | 73 ++ .../matlab/portfoliomanager/CustomerRecord.m | 109 +++ src/main/matlab/portfoliomanager/activate.m | 15 + .../matlab/portfoliomanager/collectUsage.m | 14 + .../portfoliomanager/createInitialTariffs.m | 44 ++ .../getCustomerRecordByPowerType.m | 26 + .../getCustomerRecordByTariff.m | 27 + .../matlab/portfoliomanager/improveTariffs.m | 93 +++ src/main/matlab/portfoliomanager/mInit.m | 25 + .../msgBalancingControlEvent.m | 10 + .../msgCustomerBootstrapData.m | 23 + .../matlab/portfoliomanager/msgTariffRevoke.m | 37 + .../portfoliomanager/msgTariffSpecification.m | 40 ++ .../matlab/portfoliomanager/msgTariffStatus.m | 10 + .../portfoliomanager/msgTariffTransaction.m | 55 ++ .../matlab/portfoliomanager/testFunction.m | 3 + .../samplebroker/PortfolioManagerTest.java | 114 --- test.m | 6 + 25 files changed, 946 insertions(+), 798 deletions(-) create mode 100644 lib/matlabcontrol-4.1.0.jar create mode 100644 src/main/java/org/powertac/samplebroker/PortfolioManagerProxy.java delete mode 100644 src/main/java/org/powertac/samplebroker/PortfolioManagerService.java create mode 100644 src/main/java/org/powertac/samplebroker/core/ClassPathHacker.java create mode 100644 src/main/matlab/portfoliomanager/CustomerRecord.m create mode 100644 src/main/matlab/portfoliomanager/activate.m create mode 100644 src/main/matlab/portfoliomanager/collectUsage.m create mode 100644 src/main/matlab/portfoliomanager/createInitialTariffs.m create mode 100644 src/main/matlab/portfoliomanager/getCustomerRecordByPowerType.m create mode 100644 src/main/matlab/portfoliomanager/getCustomerRecordByTariff.m create mode 100644 src/main/matlab/portfoliomanager/improveTariffs.m create mode 100644 src/main/matlab/portfoliomanager/mInit.m create mode 100644 src/main/matlab/portfoliomanager/msgBalancingControlEvent.m create mode 100644 src/main/matlab/portfoliomanager/msgCustomerBootstrapData.m create mode 100644 src/main/matlab/portfoliomanager/msgTariffRevoke.m create mode 100644 src/main/matlab/portfoliomanager/msgTariffSpecification.m create mode 100644 src/main/matlab/portfoliomanager/msgTariffStatus.m create mode 100644 src/main/matlab/portfoliomanager/msgTariffTransaction.m create mode 100644 src/main/matlab/portfoliomanager/testFunction.m delete mode 100644 src/test/java/org/powertac/samplebroker/PortfolioManagerTest.java create mode 100644 test.m diff --git a/lib/matlabcontrol-4.1.0.jar b/lib/matlabcontrol-4.1.0.jar new file mode 100644 index 0000000000000000000000000000000000000000..93622af5a7febc2cb7a7c3a627aeadf5e33434c4 GIT binary patch literal 141637 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 z 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 literal 0 HcmV?d00001 diff --git a/pom.xml b/pom.xml index 558b08c..a27d4f5 100644 --- a/pom.xml +++ b/pom.xml @@ -37,7 +37,7 @@ spring-jms ${spring.version} - + org.apache.activemq @@ -94,6 +94,11 @@ commons-io 1.3.2 + + org.matlabcontrol + matlabcontrol + 4.1.0 + diff --git a/src/main/java/org/powertac/samplebroker/PortfolioManagerProxy.java b/src/main/java/org/powertac/samplebroker/PortfolioManagerProxy.java new file mode 100644 index 0000000..092b290 --- /dev/null +++ b/src/main/java/org/powertac/samplebroker/PortfolioManagerProxy.java @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2012-2013 by the original author + * + * 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.samplebroker; + +import matlabcontrol.MatlabConnectionException; +import matlabcontrol.MatlabInvocationException; +import matlabcontrol.MatlabProxy; +import matlabcontrol.MatlabProxyFactory; +import org.apache.log4j.Logger; +import org.joda.time.Instant; +import org.powertac.common.*; +import org.powertac.common.msg.*; +import org.powertac.common.repo.CustomerRepo; +import org.powertac.common.repo.TariffRepo; +import org.powertac.common.repo.TimeslotRepo; +import org.powertac.samplebroker.core.BrokerPropertiesService; +import org.powertac.samplebroker.interfaces.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.io.BufferedWriter; +import java.io.FileWriter; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.Arrays; + + +/** + * Handles portfolio-management responsibilities for the broker. This + * includes composing and offering tariffs, keeping track of customers and their + * usage, monitoring tariff offerings from competing brokers. + *

+ * A more complete broker implementation might split this class into two or + * more classes; the keys are to decide which messages each class handles, + * what each class does on the activate() method, and what data needs to be + * managed and shared. + * + * @author John Collins + */ +@Service // Spring creates a single instance at startup +public class PortfolioManagerProxy + implements PortfolioManager, Initializable, Activatable +{ + static private Logger log = Logger.getLogger(PortfolioManagerProxy.class); + + // Spring fills in Autowired dependencies through a naming convention + @Autowired + private BrokerPropertiesService propertiesService; + + @Autowired + private TimeslotRepo timeslotRepo; + + @Autowired + private TariffRepo tariffRepo; + + @Autowired + private CustomerRepo customerRepo; + + @Autowired + private MarketManager marketManager; + + @Autowired + private TimeService timeService; + + private MatlabProxy proxy; + + /** + * Default constructor registers for messages, must be called after + * message router is available. + */ + public PortfolioManagerProxy () + { + super(); + + try { + proxy = new MatlabProxyFactory().getProxy(); + proxy.eval("cd src/main/matlab/portfoliomanager;"); + } + catch (MatlabConnectionException e) { + e.printStackTrace(); + System.exit(1); + } + catch (MatlabInvocationException e) { + e.printStackTrace(); + System.exit(1); + } + } + + /** + * Per-game initialization. Configures parameters and registers + * message handlers. + */ + @Override // from Initializable + public void initialize (BrokerContext context) + { + propertiesService.configureMe(this); + + try { + proxy.feval("mInit", context, timeslotRepo, tariffRepo, + customerRepo, marketManager, timeService, log, null); + } + catch (MatlabInvocationException mie) { + mie.printStackTrace(); + } + } + + // -------------- data access ------------------ + /** + * Returns total usage for a given timeslot (represented as a simple index). + */ + @Override + public double collectUsage (int index) + { + double result = 0.0; + try { + Object[] returnArguments = proxy.returningFeval("collectUsage", 1, index); + result = ((double[]) returnArguments[0])[0]; + + if (Double.isNaN(result)) { + result = 0.0; + } + } + catch (MatlabInvocationException mie) { + mie.printStackTrace(); + } + + return -result; // convert to needed energy account balance + } + + // -------------- Message handlers ------------------- + + /** + * Handles CustomerBootstrapData by populating the customer model + * corresponding to the given customer and power type. This gives the + * broker a running start. + */ + public void handleMessage (CustomerBootstrapData cbd) + { + try { + proxy.feval("msgCustomerBootstrapData", cbd); + } + catch (MatlabInvocationException mie) { + mie.printStackTrace(); + } + } + + /** + * Handles a TariffSpecification. These are sent by the server when new tariffs are + * published. If it's not ours, then it's a competitor's tariff. We keep track of + * competing tariffs locally, and we also store them in the tariffRepo. + */ + public void handleMessage (TariffSpecification spec) + { + try { + proxy.feval("msgTariffSpecification", spec); + } + catch (MatlabInvocationException mie) { + mie.printStackTrace(); + } + } + + /** + * Handles a TariffStatus message. This should do something when the status + * is not SUCCESS. + */ + public void handleMessage (TariffStatus ts) + { + try { + proxy.feval("msgTariffStatus", ts); + } + catch (MatlabInvocationException mie) { + mie.printStackTrace(); + } + } + + /** + * Handles a TariffTransaction. We only care about certain types: PRODUCE, + * CONSUME, SIGNUP, and WITHDRAW. + */ + public void handleMessage (TariffTransaction ttx) + { + try { + proxy.feval("msgTariffTransaction", ttx); + } + catch (MatlabInvocationException mie) { + mie.printStackTrace(); + } + } + + /** + * Handles a TariffRevoke message from the server, indicating that some + * tariff has been revoked. + */ + public void handleMessage (TariffRevoke tr) + { + try { + proxy.feval("msgTariffRevoke", tr); + } + catch (MatlabInvocationException mie) { + mie.printStackTrace(); + } + } + + /** + * Handles a BalancingControlEvent, sent when a BalancingOrder is + * exercised by the DU. + */ + public void handleMessage (BalancingControlEvent bce) + { + try { + proxy.feval("msgBalancingControlEvent", bce); + } + catch (MatlabInvocationException mie) { + mie.printStackTrace(); + } + } + + // --------------- activation ----------------- + + /** + * Called after TimeslotComplete msg received. Note that activation order + * among modules is non-deterministic. + */ + @Override // from Activatable + public void activate (int timeslotIndex) + { + try { + proxy.feval("activate", timeslotIndex); + } + catch (MatlabInvocationException mie) { + mie.printStackTrace(); + } + } +} diff --git a/src/main/java/org/powertac/samplebroker/PortfolioManagerService.java b/src/main/java/org/powertac/samplebroker/PortfolioManagerService.java deleted file mode 100644 index 6b9bc10..0000000 --- a/src/main/java/org/powertac/samplebroker/PortfolioManagerService.java +++ /dev/null @@ -1,654 +0,0 @@ -/* - * Copyright (c) 2012-2013 by the original author - * - * 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.samplebroker; - -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; - -import org.apache.log4j.Logger; -import org.joda.time.Instant; -import org.powertac.common.Broker; -import org.powertac.common.Competition; -import org.powertac.common.CustomerInfo; -import org.powertac.common.IdGenerator; -import org.powertac.common.Rate; -import org.powertac.common.TariffSpecification; -import org.powertac.common.TariffTransaction; -import org.powertac.common.TimeService; -import org.powertac.common.config.ConfigurableValue; -import org.powertac.common.enumerations.PowerType; -import org.powertac.common.msg.BalancingControlEvent; -import org.powertac.common.msg.BalancingOrder; -import org.powertac.common.msg.CustomerBootstrapData; -import org.powertac.common.msg.TariffRevoke; -import org.powertac.common.msg.TariffStatus; -import org.powertac.common.repo.CustomerRepo; -import org.powertac.common.repo.TariffRepo; -import org.powertac.common.repo.TimeslotRepo; -import org.powertac.samplebroker.core.BrokerPropertiesService; -import org.powertac.samplebroker.interfaces.Activatable; -import org.powertac.samplebroker.interfaces.BrokerContext; -import org.powertac.samplebroker.interfaces.Initializable; -import org.powertac.samplebroker.interfaces.MarketManager; -import org.powertac.samplebroker.interfaces.PortfolioManager; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -/** - * Handles portfolio-management responsibilities for the broker. This - * includes composing and offering tariffs, keeping track of customers and their - * usage, monitoring tariff offerings from competing brokers. - * - * A more complete broker implementation might split this class into two or - * more classes; the keys are to decide which messages each class handles, - * what each class does on the activate() method, and what data needs to be - * managed and shared. - * - * @author John Collins - */ -@Service // Spring creates a single instance at startup -public class PortfolioManagerService -implements PortfolioManager, Initializable, Activatable -{ - static private Logger log = Logger.getLogger(PortfolioManagerService.class); - - private BrokerContext brokerContext; // master - - // Spring fills in Autowired dependencies through a naming convention - @Autowired - private BrokerPropertiesService propertiesService; - - @Autowired - private TimeslotRepo timeslotRepo; - - @Autowired - private TariffRepo tariffRepo; - - @Autowired - private CustomerRepo customerRepo; - - @Autowired - private MarketManager marketManager; - - @Autowired - private TimeService timeService; - - // ---- Portfolio records ----- - // Customer records indexed by power type and by tariff. Note that the - // CustomerRecord instances are NOT shared between these structures, because - // we need to keep track of subscriptions by tariff. - private HashMap> customerProfiles; - private HashMap> customerSubscriptions; - private HashMap> competingTariffs; - - // Configurable parameters for tariff composition - // Override defaults in src/main/resources/config/broker.config - // or in top-level config file - @ConfigurableValue(valueType = "Double", - description = "target profit margin") - private double defaultMargin = 0.5; - - @ConfigurableValue(valueType = "Double", - description = "Fixed cost/kWh") - private double fixedPerKwh = -0.06; - - @ConfigurableValue(valueType = "Double", - description = "Default daily meter charge") - private double defaultPeriodicPayment = -1.0; - - /** - * Default constructor registers for messages, must be called after - * message router is available. - */ - public PortfolioManagerService () - { - super(); - } - - /** - * Per-game initialization. Configures parameters and registers - * message handlers. - */ - @Override // from Initializable -// @SuppressWarnings("unchecked") - public void initialize (BrokerContext context) - { - this.brokerContext = context; - propertiesService.configureMe(this); - customerProfiles = new HashMap>(); - customerSubscriptions = new HashMap>(); - competingTariffs = new HashMap>(); - } - - // -------------- data access ------------------ - - /** - * Returns the CustomerRecord for the given type and customer, creating it - * if necessary. - */ - CustomerRecord getCustomerRecordByPowerType (PowerType type, - CustomerInfo customer) - { - HashMap customerMap = - customerProfiles.get(type); - if (customerMap == null) { - customerMap = new HashMap(); - customerProfiles.put(type, customerMap); - } - CustomerRecord record = customerMap.get(customer); - if (record == null) { - record = new CustomerRecord(customer); - customerMap.put(customer, record); - } - return record; - } - - /** - * Returns the customer record for the given tariff spec and customer, - * creating it if necessary. - */ - CustomerRecord getCustomerRecordByTariff (TariffSpecification spec, - CustomerInfo customer) - { - HashMap customerMap = - customerSubscriptions.get(spec); - if (customerMap == null) { - customerMap = new HashMap(); - customerSubscriptions.put(spec, customerMap); - } - CustomerRecord record = customerMap.get(customer); - if (record == null) { - // seed with the generic record for this customer - record = - new CustomerRecord(getCustomerRecordByPowerType(spec.getPowerType(), - customer)); - customerMap.put(customer, record); - } - return record; - } - - /** - * Finds the list of competing tariffs for the given PowerType. - */ - List getCompetingTariffs (PowerType powerType) - { - List result = competingTariffs.get(powerType); - if (result == null) { - result = new ArrayList(); - competingTariffs.put(powerType, result); - } - return result; - } - - /** - * Adds a new competing tariff to the list. - */ - private void addCompetingTariff (TariffSpecification spec) - { - getCompetingTariffs(spec.getPowerType()).add(spec); - } - - /** - * Returns total usage for a given timeslot (represented as a simple index). - */ - @Override - public double collectUsage (int index) - { - double result = 0.0; - for (HashMap customerMap : customerSubscriptions.values()) { - for (CustomerRecord record : customerMap.values()) { - result += record.getUsage(index); - } - } - return -result; // convert to needed energy account balance - } - - // -------------- Message handlers ------------------- - /** - * Handles CustomerBootstrapData by populating the customer model - * corresponding to the given customer and power type. This gives the - * broker a running start. - */ - public void handleMessage (CustomerBootstrapData cbd) - { - CustomerInfo customer = - customerRepo.findByNameAndPowerType(cbd.getCustomerName(), - cbd.getPowerType()); - CustomerRecord record = getCustomerRecordByPowerType(cbd.getPowerType(), customer); - int offset = (timeslotRepo.currentTimeslot().getSerialNumber() - - cbd.getNetUsage().length); - int subs = record.subscribedPopulation; - record.subscribedPopulation = customer.getPopulation(); - for (int i = 0; i < cbd.getNetUsage().length; i++) { - record.produceConsume(cbd.getNetUsage()[i], i); - } - record.subscribedPopulation = subs; - } - - /** - * Handles a TariffSpecification. These are sent by the server when new tariffs are - * published. If it's not ours, then it's a competitor's tariff. We keep track of - * competing tariffs locally, and we also store them in the tariffRepo. - */ - public void handleMessage (TariffSpecification spec) - { - Broker theBroker = spec.getBroker(); - if (brokerContext.getBrokerUsername().equals(theBroker.getUsername())) { - if (theBroker != brokerContext) - // strange bug, seems harmless for now - log.info("Resolution failed for broker " + theBroker.getUsername()); - // if it's ours, just log it, because we already put it in the repo - TariffSpecification original = - tariffRepo.findSpecificationById(spec.getId()); - if (null == original) - log.error("Spec " + spec.getId() + " not in local repo"); - log.info("published " + spec); - } - else { - // otherwise, keep track of competing tariffs, and record in the repo - addCompetingTariff(spec); - tariffRepo.addSpecification(spec); - } - } - - /** - * Handles a TariffStatus message. This should do something when the status - * is not SUCCESS. - */ - public void handleMessage (TariffStatus ts) - { - log.info("TariffStatus: " + ts.getStatus()); - } - - /** - * Handles a TariffTransaction. We only care about certain types: PRODUCE, - * CONSUME, SIGNUP, and WITHDRAW. - */ - public void handleMessage(TariffTransaction ttx) - { - // make sure we have this tariff - TariffSpecification newSpec = ttx.getTariffSpec(); - if (newSpec == null) { - log.error("TariffTransaction type=" + ttx.getTxType() - + " for unknown spec"); - } - else { - TariffSpecification oldSpec = - tariffRepo.findSpecificationById(newSpec.getId()); - if (oldSpec != newSpec) { - log.error("Incoming spec " + newSpec.getId() + " not matched in repo"); - } - } - TariffTransaction.Type txType = ttx.getTxType(); - CustomerRecord record = getCustomerRecordByTariff(ttx.getTariffSpec(), - ttx.getCustomerInfo()); - - if (TariffTransaction.Type.SIGNUP == txType) { - // keep track of customer counts - record.signup(ttx.getCustomerCount()); - } - else if (TariffTransaction.Type.WITHDRAW == txType) { - // customers presumably found a better deal - record.withdraw(ttx.getCustomerCount()); - } - else if (TariffTransaction.Type.PRODUCE == txType) { - // if ttx count and subscribe population don't match, it will be hard - // to estimate per-individual production - if (ttx.getCustomerCount() != record.subscribedPopulation) { - log.warn("production by subset " + ttx.getCustomerCount() + - " of subscribed population " + record.subscribedPopulation); - } - record.produceConsume(ttx.getKWh(), ttx.getPostedTime()); - } - else if (TariffTransaction.Type.CONSUME == txType) { - if (ttx.getCustomerCount() != record.subscribedPopulation) { - log.warn("consumption by subset " + ttx.getCustomerCount() + - " of subscribed population " + record.subscribedPopulation); - } - record.produceConsume(ttx.getKWh(), ttx.getPostedTime()); - } - } - - /** - * Handles a TariffRevoke message from the server, indicating that some - * tariff has been revoked. - */ - public void handleMessage (TariffRevoke tr) - { - Broker source = tr.getBroker(); - log.info("Revoke tariff " + tr.getTariffId() - + " from " + tr.getBroker().getUsername()); - // if it's from some other broker, we need to remove it from the - // tariffRepo, and from the competingTariffs list - if (!(source.getUsername().equals(brokerContext.getBrokerUsername()))) { - log.info("clear out competing tariff"); - TariffSpecification original = - tariffRepo.findSpecificationById(tr.getTariffId()); - if (null == original) { - log.warn("Original tariff " + tr.getTariffId() + " not found"); - return; - } - tariffRepo.removeSpecification(original.getId()); - List candidates = - competingTariffs.get(original.getPowerType()); - if (null == candidates) { - log.warn("Candidate list is null"); - return; - } - candidates.remove(original); - } - } - - /** - * Handles a BalancingControlEvent, sent when a BalancingOrder is - * exercised by the DU. - */ - public void handleMessage (BalancingControlEvent bce) - { - log.info("BalancingControlEvent " + bce.getKwh()); - } - - // --------------- activation ----------------- - /** - * Called after TimeslotComplete msg received. Note that activation order - * among modules is non-deterministic. - */ - @Override // from Activatable - public void activate (int timeslotIndex) - { - if (customerSubscriptions.size() == 0) { - // we (most likely) have no tariffs - createInitialTariffs(); - } - else { - // we have some, are they good enough? - improveTariffs(); - } - } - - // Creates initial tariffs for the main power types. These are simple - // fixed-rate two-part tariffs that give the broker a fixed margin. - private void createInitialTariffs () - { - // remember that market prices are per mwh, but tariffs are by kwh - double marketPrice = marketManager.getMeanMarketPrice() / 1000.0; - // for each power type representing a customer population, - // create a tariff that's better than what's available - for (PowerType pt : customerProfiles.keySet()) { - // we'll just do fixed-rate tariffs for now - double rateValue; - if (pt.isConsumption()) - rateValue = ((marketPrice + fixedPerKwh) * (1.0 + defaultMargin)); - else - //rateValue = (-1.0 * marketPrice / (1.0 + defaultMargin)); - rateValue = -2.0 * marketPrice; - if (pt.isInterruptible()) - rateValue *= 0.7; // Magic number!! price break for interruptible - TariffSpecification spec = - new TariffSpecification(brokerContext.getBroker(), pt) - .withPeriodicPayment(defaultPeriodicPayment); - Rate rate = new Rate().withValue(rateValue); - if (pt.isInterruptible()) { - // set max curtailment - rate.withMaxCurtailment(0.1); - } - spec.addRate(rate); - customerSubscriptions.put(spec, new HashMap()); - tariffRepo.addSpecification(spec); - brokerContext.sendMessage(spec); - } - } - - // Checks to see whether our tariffs need fine-tuning - private void improveTariffs() - { - // quick magic-number hack to inject a balancing order - int timeslotIndex = timeslotRepo.currentTimeslot().getSerialNumber(); - if (371 == timeslotIndex) { - for (TariffSpecification spec : - tariffRepo.findTariffSpecificationsByBroker(brokerContext.getBroker())) { - if (PowerType.INTERRUPTIBLE_CONSUMPTION == spec.getPowerType()) { - BalancingOrder order = new BalancingOrder(brokerContext.getBroker(), - spec, - 0.5, - spec.getRates().get(0).getMinValue() * 0.9); - brokerContext.sendMessage(order); - } - } - } - // magic-number hack to supersede a tariff - if (380 == timeslotIndex) { - // find the existing CONSUMPTION tariff - TariffSpecification oldc = null; - List candidates = - tariffRepo.findTariffSpecificationsByBroker(brokerContext.getBroker()); - if (null == candidates || 0 == candidates.size()) - log.error("No tariffs found for broker"); - else { - // oldc = candidates.get(0); - for (TariffSpecification candidate: candidates) { - if (candidate.getPowerType() == PowerType.CONSUMPTION) { - oldc = candidate; - break; - } - } - if (null == oldc) { - log.warn("No CONSUMPTION tariffs found"); - } - else { - double rateValue = oldc.getRates().get(0).getValue(); - // create a new CONSUMPTION tariff - TariffSpecification spec = - new TariffSpecification(brokerContext.getBroker(), - PowerType.CONSUMPTION) - .withPeriodicPayment(defaultPeriodicPayment * 1.1); - Rate rate = new Rate().withValue(rateValue); - spec.addRate(rate); - if (null != oldc) - spec.addSupersedes(oldc.getId()); - mungId(spec, 6); - tariffRepo.addSpecification(spec); - brokerContext.sendMessage(spec); - // revoke the old one - TariffRevoke revoke = - new TariffRevoke(brokerContext.getBroker(), oldc); - brokerContext.sendMessage(revoke); - } - } - } - } - - private void mungId (TariffSpecification spec, int i) - { - long id = spec.getId(); - long baseId = - id - IdGenerator.extractPrefix(id) * IdGenerator.getMultiplier(); - Field idField = findIdField(spec.getClass()); - try { - idField.setAccessible(true); - idField.setLong(spec, baseId + i * IdGenerator.getMultiplier()); - } - catch (Exception e) { - log.error(e.toString()); - } - } - - private Field findIdField (Class clazz) - { - try { - Field idField = clazz.getDeclaredField("id"); - return idField; - } - catch (NoSuchFieldException e) { - Class superclass = clazz.getSuperclass(); - if (null == superclass) { - return null; - } - return findIdField(superclass); - } - catch (SecurityException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return null; - } - } - - // ------------- test-support methods ---------------- - double getUsageForCustomer (CustomerInfo customer, - TariffSpecification tariffSpec, - int index) - { - CustomerRecord record = getCustomerRecordByTariff(tariffSpec, customer); - return record.getUsage(index); - } - - // test-support method - HashMap getRawUsageForCustomer (CustomerInfo customer) - { - HashMap result = new HashMap(); - for (PowerType type : customerProfiles.keySet()) { - CustomerRecord record = customerProfiles.get(type).get(customer); - if (record != null) { - result.put(type, record.usage); - } - } - return result; - } - - // test-support method - HashMap getCustomerCounts() - { - HashMap result = new HashMap(); - for (TariffSpecification spec : customerSubscriptions.keySet()) { - HashMap customerMap = customerSubscriptions.get(spec); - for (CustomerRecord record : customerMap.values()) { - result.put(record.customer.getName() + spec.getPowerType(), - record.subscribedPopulation); - } - } - return result; - } - - //-------------------- Customer-model recording --------------------- - /** - * Keeps track of customer status and usage. Usage is stored - * per-customer-unit, but reported as the product of the per-customer - * quantity and the subscribed population. This allows the broker to use - * historical usage data as the subscribed population shifts. - */ - class CustomerRecord - { - CustomerInfo customer; - int subscribedPopulation = 0; - double[] usage; - double alpha = 0.3; - - /** - * Creates an empty record - */ - CustomerRecord (CustomerInfo customer) - { - super(); - this.customer = customer; - this.usage = new double[brokerContext.getUsageRecordLength()]; - } - - CustomerRecord (CustomerRecord oldRecord) - { - super(); - this.customer = oldRecord.customer; - this.usage = Arrays.copyOf(oldRecord.usage, brokerContext.getUsageRecordLength()); - } - - // Returns the CustomerInfo for this record - CustomerInfo getCustomerInfo () - { - return customer; - } - - // Adds new individuals to the count - void signup (int population) - { - subscribedPopulation = Math.min(customer.getPopulation(), - subscribedPopulation + population); - } - - // Removes individuals from the count - void withdraw (int population) - { - subscribedPopulation -= population; - } - - // Customer produces or consumes power. We assume the kwh value is negative - // for production, positive for consumption - void produceConsume (double kwh, Instant when) - { - int index = getIndex(when); - produceConsume(kwh, index); - } - - // store profile data at the given index - void produceConsume (double kwh, int rawIndex) - { - int index = getIndex(rawIndex); - double kwhPerCustomer = 0.0; - if (subscribedPopulation > 0) { - kwhPerCustomer = kwh / (double)subscribedPopulation; - } - double oldUsage = usage[index]; - if (oldUsage == 0.0) { - // assume this is the first time - usage[index] = kwhPerCustomer; - } - else { - // exponential smoothing - usage[index] = alpha * kwhPerCustomer + (1.0 - alpha) * oldUsage; - } - log.debug("consume " + kwh + " at " + index + - ", customer " + customer.getName()); - } - - double getUsage (int index) - { - if (index < 0) { - log.warn("usage requested for negative index " + index); - index = 0; - } - return (usage[getIndex(index)] * (double)subscribedPopulation); - } - - // we assume here that timeslot index always matches the number of - // timeslots that have passed since the beginning of the simulation. - int getIndex (Instant when) - { - int result = (int)((when.getMillis() - timeService.getBase()) / - (Competition.currentCompetition().getTimeslotDuration())); - return result; - } - - private int getIndex (int rawIndex) - { - return rawIndex % usage.length; - } - } -} diff --git a/src/main/java/org/powertac/samplebroker/core/BrokerMain.java b/src/main/java/org/powertac/samplebroker/core/BrokerMain.java index 33fa26f..c344235 100644 --- a/src/main/java/org/powertac/samplebroker/core/BrokerMain.java +++ b/src/main/java/org/powertac/samplebroker/core/BrokerMain.java @@ -15,18 +15,12 @@ */ package org.powertac.samplebroker.core; -//import org.apache.log4j.Logger; -import org.springframework.context.support.AbstractApplicationContext; -import org.springframework.context.support.ClassPathXmlApplicationContext; - /** * This is the top level of the Power TAC server. * @author John Collins */ -public class BrokerMain +public class BrokerMain implements Runnable { - //static private Logger log = Logger.getLogger(BrokerMain.class); - /** * Sets up the broker. Single command-line arg is the username */ @@ -34,8 +28,26 @@ public static void main (String[] args) { BrokerRunner runner = new BrokerRunner(); runner.processCmdLine(args); - + // if we get here, it's time to exit System.exit(0); } + + private static String[] mainArgs; + + public static void mainMatlab (String[] args) + { + // This is some dirty hacking because Matlab doesn't load jars properly + ClassPathHacker.loadJarDynamically(); + + mainArgs = args; + Thread t = new Thread( new BrokerMain() ); + t.start(); + } + + public void run() + { + BrokerRunner runner = new BrokerRunner(); + runner.processCmdLine(mainArgs); + } } diff --git a/src/main/java/org/powertac/samplebroker/core/BrokerPropertiesService.java b/src/main/java/org/powertac/samplebroker/core/BrokerPropertiesService.java index fbaf988..0696a41 100644 --- a/src/main/java/org/powertac/samplebroker/core/BrokerPropertiesService.java +++ b/src/main/java/org/powertac/samplebroker/core/BrokerPropertiesService.java @@ -15,11 +15,6 @@ */ package org.powertac.samplebroker.core; -import java.io.File; -import java.io.IOException; -import java.net.URL; -import java.util.Collection; - import org.apache.commons.configuration.CompositeConfiguration; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; @@ -33,6 +28,10 @@ import org.springframework.core.io.Resource; import org.springframework.stereotype.Service; +import java.io.File; +import java.io.IOException; +import java.util.Collection; + /** * @author jcollins */ @@ -199,6 +198,11 @@ public void setProperty (String key, Object value) private boolean validXmlResource (Resource xml) { try { + xml.getInputStream(); + return true; + + /* TODO Doesn't seem to work with files inside a jar? + Jar is added to the classpath, and then the String path = xml.getFile().getPath(); for (String regex : excludedPaths) { if (path.matches(regex)) { @@ -206,6 +210,7 @@ private boolean validXmlResource (Resource xml) } } return true; + */ } catch (IOException e) { log.error("Should not happen: " + e.toString()); diff --git a/src/main/java/org/powertac/samplebroker/core/BrokerRunner.java b/src/main/java/org/powertac/samplebroker/core/BrokerRunner.java index 0179f6a..27143a2 100644 --- a/src/main/java/org/powertac/samplebroker/core/BrokerRunner.java +++ b/src/main/java/org/powertac/samplebroker/core/BrokerRunner.java @@ -15,21 +15,22 @@ */ package org.powertac.samplebroker.core; -import java.io.File; -import java.util.Date; -import java.util.Enumeration; - import joptsimple.OptionException; import joptsimple.OptionParser; import joptsimple.OptionSet; import joptsimple.OptionSpec; - import org.apache.log4j.Appender; import org.apache.log4j.FileAppender; +import org.apache.log4j.Level; import org.apache.log4j.Logger; +import org.apache.log4j.PatternLayout; import org.springframework.context.support.AbstractApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; +import java.io.File; +import java.util.Date; +import java.util.Enumeration; + /** * Multi-session broker runner. The Spring context is re-built for each * session. @@ -115,7 +116,7 @@ else if (options.has(repeatHoursOption)) { // Re-open the logfiles reopenLogs(counter); - + // initialize and run if (null == context) { context = new ClassPathXmlApplicationContext("broker.xml"); @@ -126,7 +127,7 @@ else if (options.has(repeatHoursOption)) { } // get the broker reference and delegate the rest context.registerShutdownHook(); - broker = (PowerTacBroker)context.getBeansOfType(PowerTacBroker.class).values().toArray()[0]; + broker = (PowerTacBroker) context.getBeansOfType(PowerTacBroker.class).values().toArray()[0]; System.out.println("Starting session " + counter); broker.startSession(configFile, jmsUrl, noNtp, queueName, serverQueue, end); if (null != repeatCount) @@ -144,17 +145,53 @@ private void reopenLogs(int counter) Logger root = Logger.getRootLogger(); @SuppressWarnings("unchecked") Enumeration rootAppenders = root.getAllAppenders(); - FileAppender logOutput = (FileAppender) rootAppenders.nextElement(); - // assume there's only the one, and that it's a file appender - logOutput.setFile("log/broker" + counter + ".trace"); - logOutput.activateOptions(); - + FileAppender logOutput; + + try { + logOutput = (FileAppender) rootAppenders.nextElement(); + // assume there's only the one, and that it's a file appender + logOutput.setFile("log/broker" + counter + ".trace"); + logOutput.activateOptions(); + } + catch (Exception ignored) { + try { + PatternLayout layout = new PatternLayout("%r %-5p %c{2}: %m%n"); + String fileName = "log/broker" + counter + ".trace"; + logOutput = new FileAppender(layout, fileName); + logOutput.activateOptions(); + root.addAppender(logOutput); + + root.setLevel(Level.WARN); + } + catch (Exception ignored2) { + // TODO What? + } + } + Logger state = Logger.getLogger("State"); @SuppressWarnings("unchecked") Enumeration stateAppenders = state.getAllAppenders(); - FileAppender stateOutput = (FileAppender) stateAppenders.nextElement(); - // assume there's only the one, and that it's a file appender - stateOutput.setFile("log/broker" + counter + ".state"); - stateOutput.activateOptions(); + FileAppender stateOutput; + + try { + stateOutput = (FileAppender) stateAppenders.nextElement(); + // assume there's only the one, and that it's a file appender + stateOutput.setFile("log/broker" + counter + ".state"); + stateOutput.activateOptions(); + } + catch (Exception ignored) { + try { + PatternLayout layout = new PatternLayout("%r::%m%n"); + String fileName = "log/broker" + counter + ".state"; + stateOutput = new FileAppender(layout, fileName); + stateOutput.activateOptions(); + state.addAppender(stateOutput); + + state.setLevel(Level.INFO); + } + catch (Exception ignored2) { + // TODO What? + } + } } } diff --git a/src/main/java/org/powertac/samplebroker/core/ClassPathHacker.java b/src/main/java/org/powertac/samplebroker/core/ClassPathHacker.java new file mode 100644 index 0000000..dcc9392 --- /dev/null +++ b/src/main/java/org/powertac/samplebroker/core/ClassPathHacker.java @@ -0,0 +1,73 @@ +package org.powertac.samplebroker.core; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Method; +import java.net.URL; +import java.net.URLClassLoader; + + +public class ClassPathHacker +{ + public static void loadJarDynamically () + { + String jarPath = BrokerMain.class.getProtectionDomain() + .getCodeSource().getLocation().getFile(); + URLClassLoader ucl = (URLClassLoader) ClassLoader.getSystemClassLoader(); + boolean found = false; + for (URL url : ucl.getURLs()) { + if (url.getFile().equals(jarPath)) { + found = true; + break; + } + } + + if (!found) { + ClassPathHacker.addFile(jarPath); + } + } + + private static void addFile (final String s) + { + try { + addURL((new File(s)).toURI().toURL()); + } + catch (IOException ignored) { + System.out.println(); + System.out.println("Unable to load " + s + "dynamically, exiting!"); + System.out.println(); + System.exit(1); + } + } + + private static void addURL (final URL u) throws IOException + { + final URLClassLoader urlClassLoader = getUrlClassLoader(); + + try { + final Method method = getAddUrlMethod(); + method.setAccessible(true); + method.invoke(urlClassLoader, u); + } + catch (final Exception e) { + throw new IOException("Error, could not add URL to system classloader"); + } + } + + private static Method getAddUrlMethod () throws NoSuchMethodException + { + final Class urlclassloader = URLClassLoader.class; + return urlclassloader.getDeclaredMethod("addURL", new Class[]{URL.class}); + } + + private static URLClassLoader getUrlClassLoader () + { + final ClassLoader sysloader = ClassLoader.getSystemClassLoader(); + if (sysloader instanceof URLClassLoader) { + return (URLClassLoader) sysloader; + } + else { + throw new IllegalStateException("Not an UrlClassLoader: " + sysloader); + } + } +} \ No newline at end of file diff --git a/src/main/matlab/portfoliomanager/CustomerRecord.m b/src/main/matlab/portfoliomanager/CustomerRecord.m new file mode 100644 index 0000000..f2a4bae --- /dev/null +++ b/src/main/matlab/portfoliomanager/CustomerRecord.m @@ -0,0 +1,109 @@ +classdef CustomerRecord < handle + % Keeps track of customer status and usage. Usage is stored + % per-customer-unit, but reported as the product of the per-customer + % quantity and the subscribed population. This allows the broker to use + % historical usage data as the subscribed population shifts. + + properties + customer = 'None'; + subscribedPopulation = 0; + usage = []; + alpha = 0.3; + end + + methods + function obj = CustomerRecord (inp) + global pmManager + + if strcmp(class(inp), 'org.powertac.common.CustomerInfo') + obj.customer = inp; + for i=1:pmManager.context.getUsageRecordLength() + obj.usage(i) = 0; + end + elseif strcmp(class(inp), 'CustomerRecord') + obj.customer = inp.customer; + obj.usage = repmat(inp.usage, 1); + elseif isnumeric(inp) && isempty(inp) + obj.customer = inp; + for i=1:pmManager.context.getUsageRecordLength() + obj.usage(i) = 0; + end + end + + while length(obj.usage) < pmManager.context.getUsageRecordLength() + obj.usage(length(obj.usage) + 1) = 0; + end + end + + % Adds new individuals to the count + function signup (obj, population) + obj.subscribedPopulation = min(obj.customer.getPopulation(), ... + obj.subscribedPopulation + population); + end + + % Removes individuals from the count + function withdraw (obj, population) + obj.subscribedPopulation = obj.subscribedPopulation - population; + end + + function produceConsume (obj, kwh, rawIndex) + % Customer produces or consumes power. We assume the kwh value is negative + % for production, positive for consumption + % store profile data at the given index + + global pmManager + + index = obj.getIndex(rawIndex); + if obj.subscribedPopulation == 0.0 + kwhPerCustomer = 0; + else + kwhPerCustomer = kwh / obj.subscribedPopulation; + end + oldUsage = obj.usage(index); + + if oldUsage == 0.0 + % assume this is the first time + obj.usage(index) = kwhPerCustomer; + else + % exponential smoothing + obj.usage(index) = obj.alpha * kwhPerCustomer + (1.0 - obj.alpha) * oldUsage; + end + + if isnumeric(obj.customer) && isempty(obj.customer) + name = 'null'; + else + name = char(obj.customer.getName()); + end + + msg = horzcat('consume ', num2str(kwh), ' at ', int2str(index), ... + ', customer ', name); + pmManager.log.debug(msg); + end + + function result = getUsage (obj, index) + global pmManager + + if index < 1 + msg = horzcat('usage requested for negative index ', int2str(index)); + pmManager.log.warn(msg); + index = 1; + end + + result = obj.usage(obj.getIndex(index)) * obj.subscribedPopulation; + end + + function index = getIndex (obj, rawIndex) + global pmManager + + if strcmp(class(rawIndex), 'double') + index = rawIndex; + elseif strcmp(class(rawIndex), 'org.joda.time.Instant') + diff = rawIndex.getMillis() - pmManager.timeService.getBase(); + duration = org.powertac.common.Competition.currentCompetition().getTimeslotDuration(); + index = floor(diff / duration) + 1; + end + + index = mod(index-1, pmManager.context.getUsageRecordLength()) + 1; + end + end +end \ No newline at end of file diff --git a/src/main/matlab/portfoliomanager/activate.m b/src/main/matlab/portfoliomanager/activate.m new file mode 100644 index 0000000..a178f4e --- /dev/null +++ b/src/main/matlab/portfoliomanager/activate.m @@ -0,0 +1,15 @@ +function activate (timeslotIndex) + % Called after TimeslotComplete msg received. Note that activation order + % among modules is non-deterministic. + + global pmManager + + if length(pmManager.customerSubscriptions) == 0 + % we (most likely) have no tariffs + createInitialTariffs(); + else + % we have some, are they good enough? + improveTariffs(); + end + +end diff --git a/src/main/matlab/portfoliomanager/collectUsage.m b/src/main/matlab/portfoliomanager/collectUsage.m new file mode 100644 index 0000000..5c5708b --- /dev/null +++ b/src/main/matlab/portfoliomanager/collectUsage.m @@ -0,0 +1,14 @@ +function result = collectUsage (index) + % Returns total usage for a given timeslot (represented as a simple index). + + global pmManager + + result = 0.0; + for k1 = keys(pmManager.customerSubscriptions) + customer_map = pmManager.customerSubscriptions(cell2mat(k1)); + for k2 = keys(customer_map) + record = customer_map(cell2mat(k2)); + result = result + record.getUsage(index); + end + end +end \ No newline at end of file diff --git a/src/main/matlab/portfoliomanager/createInitialTariffs.m b/src/main/matlab/portfoliomanager/createInitialTariffs.m new file mode 100644 index 0000000..4cc6e27 --- /dev/null +++ b/src/main/matlab/portfoliomanager/createInitialTariffs.m @@ -0,0 +1,44 @@ +function createInitialTariffs () + % Creates initial tariffs for the main power types. These are simple + % fixed-rate two-part tariffs that give the broker a fixed margin. + + global pmManager + + % remember that market prices are per mwh, but tariffs are by kwh + marketPrice = pmManager.marketManager.getMeanMarketPrice() / 1000; + + % for each power type representing a customer population, + % create a tariff that's better than what's available + for ptString = keys(pmManager.customerProfiles) + pt = org.powertac.common.enumerations.PowerType.valueOf(cell2mat(ptString)); + + % we'll just do fixed-rate tariffs for now + if pt.isConsumption() + rateValue = (marketPrice + pmManager.fixedPerKwh) * ... + (1.0 + pmManager.defaultMargin); + else + rateValue = -2.0 * marketPrice; + end + + if pt.isInterruptible() + % Magic number!! price break for interruptible + rateValue = rateValue * 0.7; + end + + broker = pmManager.context.getBroker(); + spec = org.powertac.common.TariffSpecification(broker, pt). ... + withPeriodicPayment(pmManager.defaultPeriodicPayment); + + rate = org.powertac.common.Rate().withValue(rateValue); + + if pt.isInterruptible() + % set max curtailment + rate.withMaxCurtailment(0.1); + end + + spec.addRate(rate); + pmManager.customerSubscriptions(char(spec)) = containers.Map; + pmManager.tariffRepo.addSpecification(spec); + pmManager.context.sendMessage(spec); + end +end \ No newline at end of file diff --git a/src/main/matlab/portfoliomanager/getCustomerRecordByPowerType.m b/src/main/matlab/portfoliomanager/getCustomerRecordByPowerType.m new file mode 100644 index 0000000..0c96ddf --- /dev/null +++ b/src/main/matlab/portfoliomanager/getCustomerRecordByPowerType.m @@ -0,0 +1,26 @@ +function record = getCustomerRecordByPowerType (powerType, customer) + global pmManager + + typeString = char(powerType); + % customerName = char(customer.getName()); + if isnumeric(customer) && isempty(customer) + % customer might be null (Java) == [] (MatLab) + customerName = 'null'; + else + customerName = char(customer.getName()); + end + + if ~pmManager.customerProfiles.isKey(typeString) + customerMap = containers.Map; + pmManager.customerProfiles(typeString) = customerMap; + else + customerMap = pmManager.customerProfiles(typeString); + end + + if ~customerMap.isKey(customerName) + record = CustomerRecord(customer); + customerMap(customerName) = record; + else + record = customerMap(customerName); + end +end diff --git a/src/main/matlab/portfoliomanager/getCustomerRecordByTariff.m b/src/main/matlab/portfoliomanager/getCustomerRecordByTariff.m new file mode 100644 index 0000000..75de397 --- /dev/null +++ b/src/main/matlab/portfoliomanager/getCustomerRecordByTariff.m @@ -0,0 +1,27 @@ +function record = getCustomerRecordByTariff (spec, customer) + global pmManager + + specString = char(spec); + if isnumeric(customer) && isempty(customer) + % customer might be null (Java) == [] (MatLab) + customerName = 'null'; + else + customerName = char(customer.getName()); + end + + if ~pmManager.customerSubscriptions.isKey(specString) + customerMap = containers.Map; + pmManager.customerSubscriptions(specString) = customerMap; + else + customerMap = pmManager.customerSubscriptions(specString); + end + + if ~customerMap.isKey(customerName) + % seed with the generic record for this customer + oldRecord = getCustomerRecordByPowerType(spec.getPowerType(), customer); + record = CustomerRecord(oldRecord); + customerMap(customerName) = record; + else + record = customerMap(customerName); + end +end \ No newline at end of file diff --git a/src/main/matlab/portfoliomanager/improveTariffs.m b/src/main/matlab/portfoliomanager/improveTariffs.m new file mode 100644 index 0000000..714fee2 --- /dev/null +++ b/src/main/matlab/portfoliomanager/improveTariffs.m @@ -0,0 +1,93 @@ +function improveTariffs () + % Checks to see whether our tariffs need fine-tuning + + global pmManager + + timeslotIndex = pmManager.timeslotRepo.currentTimeslot().getSerialNumber(); + + % quick magic-number hack to inject a balancing order + if timeslotIndex == 371 + broker = pmManager.context.getBroker(); + test = org.powertac.common.enumerations.PowerType.INTERRUPTIBLE_CONSUMPTION; + specs = pmManager.tariffRepo.findTariffSpecificationsByBroker(broker).toArray(); + for i = 1:length(specs) + spec = specs(i); + if spec.getPowerType() == test + order = org.powertac.common.msg.BalancingOrder(... + broker, spec, 0.5, spec.getRates().get(0).getMinValue() * 0.9); + pmManager.context.sendMessage(order); + end + end + end + + % magic-number hack to supersede a tariff + if timeslotIndex == 380 + broker = pmManager.context.getBroker(); + test = org.powertac.common.enumerations.PowerType.CONSUMPTION; + + % find the existing CONSUMPTION tariff + oldc = []; + candidates = pmManager.tariffRepo.findTariffSpecificationsByBroker(broker).toArray(); + if isnumeric(candidates) || isempty(candidates) % Test for null + pmManager.log.error('No tariffs found for broker'); + else + for i = 1:length(candidates) + candidate = candidates(i); + if candidate.getPowerType() == test + oldc = candidate; + break; + end + end + + if oldc == [] + pmManager.log.warn('No CONSUMPTION tariffs found'); + else + rateValue = oldc.getRates().get(0).getValue(); + % create a new CONSUMPTION tariff + spec = org.powertac.common.TariffSpecification(broker, test). ... + withPeriodicPayment(pmManager.defaultPeriodicPayment * 1.1); + rate = org.powertac.common.Rate().withValue(rateValue); + spec.addRate(rate); + spec.addSupersedes(oldc.getId()); + + pmManager.tariffRepo.addSpecification(spec); + pmManager.context.sendMessage(spec); + % revoke the old one + revoke = org.powertac.common.msg.TariffRevoke(broker, oldc); + pmManager.context.sendMessage(revoke); + end + end + end + +% % magic-number hack to supersede a tariff +% if timeslotIndex == 380 +% broker = pmManager.context.getBroker(); +% type = org.powertac.common.enumerations.PowerType.CONSUMPTION; +% +% % find the existing CONSUMPTION tariff +% oldc = []; +% candidates = pmManager.tariffRepo.findTariffSpecificationsByPowerType(type); +% if isnumeric(candidates) || isempty(candidates) % Test for null +% pmManager.log.error('No CONSUMPTION tariffs found'); +% end +% candidates = candidates.toArray(); +% oldc = candidates(1); +% +% rateValue = oldc.getRates().get(0).getValue(); +% +% % create a new CONSUMPTION tariff +% spec = org.powertac.common.TariffSpecification(broker, type). ... +% withPeriodicPayment(pmManager.defaultPeriodicPayment * 1.1); +% rate = org.powertac.common.Rate().withValue(rateValue); +% +% if ~isnumeric(oldc) && ~isempty(oldc) +% spec.addSupersedes(oldc.getId()); +% end +% +% pmManager.tariffRepo.addSpecification(spec); +% pmManager.context.sendMessage(spec); +% % revoke the old one +% revoke = org.powertac.common.msg.TariffRevoke(broker, oldc); +% pmManager.context.sendMessage(revoke); +% end +end diff --git a/src/main/matlab/portfoliomanager/mInit.m b/src/main/matlab/portfoliomanager/mInit.m new file mode 100644 index 0000000..3de6069 --- /dev/null +++ b/src/main/matlab/portfoliomanager/mInit.m @@ -0,0 +1,25 @@ +function mInit (var0, var1, var2, var3, var4, var5, var6, var7) + global pmManager + + pmManager.context = var0; + pmManager.timeslotRepo = var1; + pmManager.tariffRepo = var2; + pmManager.customerRepo = var3; + pmManager.marketManager = var4; + pmManager.timeService = var5; + pmManager.log = var6; + pmManager.null = var7; + + % Configurable parameters for tariff composition + pmManager.defaultMargin = 0.5; + pmManager.fixedPerKwh = -0.06; + pmManager.defaultPeriodicPayment = -1.0; + + % ---- Portfolio records ----- + % Customer records indexed by power type and by tariff. Note that the + % CustomerRecord instances are NOT shared between these structures, because + % we need to keep track of subscriptions by tariff. + pmManager.customerProfiles = containers.Map; + pmManager.customerSubscriptions = containers.Map; + pmManager.competingTariffs = containers.Map; +end \ No newline at end of file diff --git a/src/main/matlab/portfoliomanager/msgBalancingControlEvent.m b/src/main/matlab/portfoliomanager/msgBalancingControlEvent.m new file mode 100644 index 0000000..763cca3 --- /dev/null +++ b/src/main/matlab/portfoliomanager/msgBalancingControlEvent.m @@ -0,0 +1,10 @@ +function msgBalancingControlEvent (bce) + % Handles a BalancingControlEvent, sent when a BalancingOrder is + % exercised by the DU. + + global pmManager + + kwh = bce.getKwh(); + msg = horzcat('BalancingControlEvent ', num2str(kwh)); + pmManager.log.info(msg); +end \ No newline at end of file diff --git a/src/main/matlab/portfoliomanager/msgCustomerBootstrapData.m b/src/main/matlab/portfoliomanager/msgCustomerBootstrapData.m new file mode 100644 index 0000000..e1162bf --- /dev/null +++ b/src/main/matlab/portfoliomanager/msgCustomerBootstrapData.m @@ -0,0 +1,23 @@ +function msgCustomerBootstrapData (cbd) + % Handles CustomerBootstrapData by populating the customer model + % corresponding to the given customer and power type. This gives the + % broker a running start. + + global pmManager + + name = cbd.getCustomerName(); + type = cbd.getPowerType(); + usage = cbd.getNetUsage(); + + customer = pmManager.customerRepo.findByNameAndPowerType(name, type); + record = getCustomerRecordByPowerType(cbd.getPowerType(), customer); + + check1 = record.subscribedPopulation; + + subs = record.subscribedPopulation; + record.subscribedPopulation = customer.getPopulation(); + for i=1:length(usage) + record.produceConsume(usage(i), i); + end + record.subscribedPopulation = subs; +end \ No newline at end of file diff --git a/src/main/matlab/portfoliomanager/msgTariffRevoke.m b/src/main/matlab/portfoliomanager/msgTariffRevoke.m new file mode 100644 index 0000000..0fbcd7e --- /dev/null +++ b/src/main/matlab/portfoliomanager/msgTariffRevoke.m @@ -0,0 +1,37 @@ +function msgTariffRevoke (tr) + % Handles a TariffRevoke message from the server, indicating that some + % tariff has been revoked. + + global pmManager + + source = tr.getBroker(); + name = char(source.getUsername()); + contextName = char(pmManager.context.getBrokerUsername()); + + % if it's from some other broker, we need to remove it from the + % tariffRepo, and from the competingTariffs list + if ~strcmp(name, contextName) + pmManager.log.info('clear out competing tariff'); + + original = pmManager.tariffRepo.findSpecificationById(tr.getTariffId()); + + if isnumeric(original) && isempty(original) + msg = horzcat('Original tariff ', int2str(tr.getTariffId()), 'not found'); + pmManager.log.warn(msg); + return; + end + + pmManager.tariffRepo.removeSpecification(original.getId()); + + typeString = char(original.getPowerType()); + if ~pmManager.competingTariffs.isKey(typeString) + pmManager.log.warn('Candidate list is null'); + return; + else + % candidates is an array with tariff specs, remove original + candidates = pmManager.competingTariffs(typeString); + candidates = candidates(candidates~=original); + pmManager.competingTariffs(typeString) = candidates; + end + end +end \ No newline at end of file diff --git a/src/main/matlab/portfoliomanager/msgTariffSpecification.m b/src/main/matlab/portfoliomanager/msgTariffSpecification.m new file mode 100644 index 0000000..87c752a --- /dev/null +++ b/src/main/matlab/portfoliomanager/msgTariffSpecification.m @@ -0,0 +1,40 @@ +function msgTariffSpecification (spec) + % Handles a TariffSpecification. These are sent by the server when new tariffs + % are published. If it's not ours, then it's a competitor's tariff. We keep + % track of competing tariffs locally, and we also store them in the tariffRepo. + + global pmManager + + theBroker = spec.getBroker(); + theBrokerName = char(theBroker.getUsername()); + contextBrokerName = char(pmManager.context.getBrokerUsername()); + + if strcmp(theBrokerName, contextBrokerName) + % if it's ours, just log it, because we already put it in the repo + original = pmManager.tariffRepo.findSpecificationById(spec.getId()); + if ~isa(original, 'org.powertac.common.TariffSpecification') + pmManager.log.error(horzcat('Spec ', int2str(spec.getId()), ' not in local repo')); + end + pmManager.log.info(horzcat('published ', char(spec.toString()))); + else + % otherwise, keep track of competing tariffs, and record in the repo + addCompetingTariff(spec); + pmManager.tariffRepo.addSpecification(spec); + end +end + +function addCompetingTariff (spec) + % Finds the list of competing tariffs for the given PowerType, add tariff + global pmManager + + typeString = char(spec.getPowerType()); + + if ~pmManager.competingTariffs.isKey(typeString) + tariffs = []; + else + tariffs = pmManager.competingTariffs(typeString); + end + + tariffs = [tariffs spec]; + pmManager.competingTariffs(typeString) = tariffs; +end \ No newline at end of file diff --git a/src/main/matlab/portfoliomanager/msgTariffStatus.m b/src/main/matlab/portfoliomanager/msgTariffStatus.m new file mode 100644 index 0000000..e019e92 --- /dev/null +++ b/src/main/matlab/portfoliomanager/msgTariffStatus.m @@ -0,0 +1,10 @@ +function msgTariffStatus (ts) + % Handles a TariffStatus message. This should do something when the status + % is not SUCCESS. + + global pmManager + + status = ts.getStatus(); + msg = horzcat('TariffStatus: ', char(status)); + pmManager.log.info(msg); +end \ No newline at end of file diff --git a/src/main/matlab/portfoliomanager/msgTariffTransaction.m b/src/main/matlab/portfoliomanager/msgTariffTransaction.m new file mode 100644 index 0000000..7273e07 --- /dev/null +++ b/src/main/matlab/portfoliomanager/msgTariffTransaction.m @@ -0,0 +1,55 @@ +function msgTariffTransaction (ttx) + % Handles a TariffTransaction. We only care about certain types: + % PRODUCE, CONSUME, SIGNUP, and WITHDRAW. + + global pmManager + + txTypeString = char(ttx.getTxType()); + newSpec = ttx.getTariffSpec(); + + % make sure we have this tariff + if ~isa(newSpec, 'org.powertac.common.TariffSpecification') + msg = horzcat('TariffTransaction type=', txTypeString, ' for unknown spec'); + pmManager.log.error(msg); + else + oldSpec = pmManager.tariffRepo.findSpecificationById(newSpec.getId()); + if oldSpec.getId() ~= newSpec.getId() + msg = horzcat('Incoming spec ', num2str(newSpec.getId()), ... + ' not matched in repo'); + pmManager.log.error(msg); + end + end + + % ttx.getCustomerInfo() might return null => [] in MatLab + record = getCustomerRecordByTariff(newSpec, ttx.getCustomerInfo()); + + enumType = 'org.powertac.common.TariffTransaction$Type'; + SIGNUP = javaMethod('valueOf', enumType, 'SIGNUP'); + WITHDRAW = javaMethod('valueOf', enumType, 'WITHDRAW'); + PRODUCE = javaMethod('valueOf', enumType, 'PRODUCE'); + PUBLISH = javaMethod('valueOf', enumType, 'PUBLISH'); + + if strcmp(txTypeString, char(SIGNUP)) + % keep track of customer counts + record.signup(ttx.getCustomerCount()); + elseif strcmp(txTypeString, char(WITHDRAW)) + % customers presumably found a better deal + record.withdraw(ttx.getCustomerCount()); + elseif strcmp(txTypeString, char(PRODUCE)) + % if ttx count and subscribe population don't match, it will be hard + % to estimate per-individual production + if ttx.getCustomerCount() ~= record.subscribedPopulation + msg = horzcat('production by subset ', num2str(ttx.getCustomerCount()),... + ' of subscribed population ', int2str(record.subscribedPopulation)); + pmManager.log.warn(msg); + end + record.produceConsume(ttx.getKWh(), ttx.getPostedTime()); + elseif strcmp(txTypeString, char(PUBLISH)) + if ttx.getCustomerCount() ~= record.subscribedPopulation + msg = horzcat('production by subset ', num2str(ttx.getCustomerCount()),... + ' of subscribed population ', int2str(record.subscribedPopulation)); + pmManager.log.warn(msg); + end + record.produceConsume(ttx.getKWh(), ttx.getPostedTime()); + end +end diff --git a/src/main/matlab/portfoliomanager/testFunction.m b/src/main/matlab/portfoliomanager/testFunction.m new file mode 100644 index 0000000..d618b5d --- /dev/null +++ b/src/main/matlab/portfoliomanager/testFunction.m @@ -0,0 +1,3 @@ +function result = testFunction (var0) + result = 10 * var0; +end diff --git a/src/test/java/org/powertac/samplebroker/PortfolioManagerTest.java b/src/test/java/org/powertac/samplebroker/PortfolioManagerTest.java deleted file mode 100644 index 7f6ae7e..0000000 --- a/src/test/java/org/powertac/samplebroker/PortfolioManagerTest.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) 2012 by the original author - * - * 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.samplebroker; - -import static org.junit.Assert.*; -import static org.mockito.Mockito.*; - -import java.util.Arrays; - -import org.joda.time.DateTime; -import org.joda.time.DateTimeZone; -import org.joda.time.Instant; -import org.junit.Before; -import org.junit.Test; -import org.powertac.common.CustomerInfo; -import org.powertac.common.TimeService; -import org.powertac.common.Timeslot; -import org.powertac.common.enumerations.PowerType; -import org.powertac.common.msg.CustomerBootstrapData; -import org.powertac.common.repo.CustomerRepo; -import org.powertac.common.repo.TimeslotRepo; -import org.powertac.samplebroker.core.BrokerPropertiesService; -import org.powertac.samplebroker.core.PowerTacBroker; -import org.springframework.test.util.ReflectionTestUtils; - -/** - * @author jcollins - */ -public class PortfolioManagerTest -{ - private TimeslotRepo timeslotRepo; - private CustomerRepo customerRepo; - - private PortfolioManagerService portfolioManagerService; - private PowerTacBroker broker; - private Instant baseTime; - - /** - * - */ - @Before - public void setUp () throws Exception - { - broker = mock(PowerTacBroker.class); - timeslotRepo = mock(TimeslotRepo.class); - customerRepo = new CustomerRepo(); - BrokerPropertiesService bps = mock(BrokerPropertiesService.class); - when(broker.getUsageRecordLength()).thenReturn(7*24); - portfolioManagerService = new PortfolioManagerService(); - ReflectionTestUtils.setField(portfolioManagerService, - "timeslotRepo", - timeslotRepo); - ReflectionTestUtils.setField(portfolioManagerService, - "customerRepo", - customerRepo); - ReflectionTestUtils.setField(portfolioManagerService, - "propertiesService", - bps); - portfolioManagerService.initialize(broker); - - // set the time - baseTime = - new DateTime(2011, 2, 1, 0, 0, 0, 0, DateTimeZone.UTC).toInstant(); - } - - /** - * Test customer boot data - */ - @Test - public void testCustomerBootstrap () - { - // set up a competition - CustomerInfo podunk = new CustomerInfo("Podunk", 3); - customerRepo.add(podunk); - CustomerInfo midvale = new CustomerInfo("Midvale", 1000); - customerRepo.add(midvale); - // create a Timeslot for use by the bootstrap data - Timeslot ts0 = new Timeslot(8*24, baseTime.plus(TimeService.DAY * 8)); - when(timeslotRepo.currentTimeslot()).thenReturn(ts0); - // send to broker and check - double[] podunkData = new double[7*24]; - Arrays.fill(podunkData, 3.6); - double[] midvaleData = new double[7*24]; - Arrays.fill(midvaleData, 1600.0); - CustomerBootstrapData boot = - new CustomerBootstrapData(podunk, PowerType.CONSUMPTION, podunkData); - portfolioManagerService.handleMessage(boot); - boot = new CustomerBootstrapData(midvale, PowerType.CONSUMPTION, midvaleData); - portfolioManagerService.handleMessage(boot); - double[] podunkUsage = - portfolioManagerService.getRawUsageForCustomer(podunk).get(PowerType.CONSUMPTION); - assertNotNull("podunk usage is recorded", podunkUsage); - assertEquals("correct usage value for podunk", 1.2, podunkUsage[23], 1e-6); - double[] midvaleUsage = - portfolioManagerService.getRawUsageForCustomer(midvale).get(PowerType.CONSUMPTION); - assertNotNull("midvale usage is recorded", midvaleUsage); - assertEquals("correct usage value for midvale", 1.6, midvaleUsage[27], 1e-6); - } - - // other tests needed... -} diff --git a/test.m b/test.m new file mode 100644 index 0000000..655b93e --- /dev/null +++ b/test.m @@ -0,0 +1,6 @@ +% Run this with : matlab -nodisplay -nosplash -nodesktop -r test + +javaaddpath('target/sample-broker.jar'); + +o = org.powertac.samplebroker.core.BrokerMain; +javaMethod('mainMatlab', o, '--jms-url=tcp://130.115.197.116:61616');