org.energy_home.jemma.ah.ebrain.algo.DailyTariff.java Source code

Java tutorial

Introduction

Here is the source code for org.energy_home.jemma.ah.ebrain.algo.DailyTariff.java

Source

/**
 * This file is part of JEMMA - http://jemma.energy-home.org
 * (C) Copyright 2013 Telecom Italia (http://www.telecomitalia.it)
 *
 * JEMMA is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License (LGPL) version 3
 * or later as published by the Free Software Foundation, which accompanies
 * this distribution and is available at http://www.gnu.org/licenses/lgpl.html
 *
 * JEMMA is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License (LGPL) for more details.
 *
 */
package org.energy_home.jemma.ah.ebrain.algo;

import java.util.*;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.energy_home.jemma.ah.ebrain.CalendarUtil;
import org.energy_home.jemma.ah.ebrain.EnergyCostInfo;
import org.energy_home.jemma.ah.ebrain.TwoTierDailyTariff;

/*
 * Daily Tariff for the week. It assumes that each profile is a segment that specifies a tariff
 * in KW/hour for a given start/end interval. Unit cost is expressed in hundredth-millesimals of euro,
 * Time units are 4-digit integer, the 2 highest are the hour and the 2 lowest are the minutes.
 * Each Daily profile will be an array of such interval profiles.
 */

public abstract class DailyTariff {
    private static final Log log = LogFactory.getLog(DailyTariff.class);

    private static DailyTariff instance;

    //private static List<DailyTariff> singletons = new ArrayList<DailyTariff>();
    /*
       static Reference<DailyTariff> getWeakInstance() {
          return new WeakReference<DailyTariff>(instance);
       }
    */
    public static DailyTariff getInstance() throws InstantiationException, IllegalAccessException {
        if (instance == null)
            return getInstance(TwoTierDailyTariff.class);
        return instance;
    }

    public static DailyTariff getInstance(Class<? extends DailyTariff> clazz)
            throws InstantiationException, IllegalAccessException {
        if (instance == null || instance.getClass() != clazz)
            instance = clazz.newInstance();
        return instance;
    }

    /*
       static <T extends DailyTariff> T getInstance2(Class<T> clazz) throws InstantiationException, IllegalAccessException {
          for (DailyTariff instance : singletons) {
     if (instance.getClass() == clazz) return clazz.cast(instance);
          }
          log.debug("new tariff " + clazz.getSimpleName());
          T instance = clazz.newInstance();
          singletons.add(instance);
          return instance;
       }
    */
    // this matrix is a 7 rows, each for every day of the week, and every column are the
    // tariff intervals for that day.
    protected TariffIntervals[][] weekTariffIntervals = new TariffIntervals[7][];
    protected float[][] slotsWeekTariffs = new float[7][];

    protected DailyTariff() {
    }

    protected void setDailyTariff(TariffIntervals[] tariffIntervals, int dayOfWeek) throws Exception {
        // Calendar.DAY_OF_WEEK goes from 1 to 7
        // 1st check to see if we already have a 'normalized' slot daily-tariff, else make a new one;
        for (int i = 0; i < 7; ++i) {
            if (tariffIntervals.equals(weekTariffIntervals[i])) {
                slotsWeekTariffs[dayOfWeek - 1] = slotsWeekTariffs[i];
                weekTariffIntervals[dayOfWeek - 1] = weekTariffIntervals[i];
                return;
            }
        }

        // not found, then create a new slot array
        float[] slotTariff = new float[CalendarUtil.SLOTS_IN_ONE_DAY];
        slotsWeekTariffs[dayOfWeek - 1] = slotTariff;
        weekTariffIntervals[dayOfWeek - 1] = tariffIntervals;

        for (TariffIntervals ti : tariffIntervals) {
            // the tariff is expressed 'per hour', so divide by the number of slots in one hour
            int[] slots = ti.getSlotIntervals();
            for (int i = 0; i < slots.length; i += 2) {
                for (int j = slots[i]; j < slots[i + 1]; slotTariff[j++] = ti.getTariff())
                    ;
            }
        }
    }

    // get the daily tariff array considering holydays as sundays
    private float[] getSlotDailyTariffProfile(Calendar calendar) {
        int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
        if (dayOfWeek != Calendar.SUNDAY && CalendarUtil.isHolyday(calendar))
            dayOfWeek = Calendar.SUNDAY;
        return slotsWeekTariffs[dayOfWeek - 1];
    }

    // compute the cost of a 'flat' energy value in the specified duration interval
    // and also the minimum & maximum costs in the specified time range
    public EnergyCostInfo computeMinMaxCosts(Calendar calendar, long duration, double deltaEnergy) {
        float[] slotTariff = getSlotDailyTariffProfile(calendar);

        // NOTE: the tariff is Kwatt/hour, while the 'energy' parameter is in watt/hour
        // therefore the necessary division by 1000
        double energy = deltaEnergy * 0.001;
        int slotDuration = CalendarUtil.slotsFromMillis(duration);
        double oneSlotEnergy = energy / slotDuration;

        int tariffSlot = CalendarUtil.getSlotOf(calendar);
        double cost = 0;
        float min = Float.POSITIVE_INFINITY;
        float max = 0;
        while (slotDuration-- > 0) {
            cost += slotTariff[tariffSlot] * oneSlotEnergy;
            if (min > slotTariff[tariffSlot])
                min = slotTariff[tariffSlot];
            if (max < slotTariff[tariffSlot])
                max = slotTariff[tariffSlot];
            if (++tariffSlot >= slotTariff.length) {
                // roll to the day after
                tariffSlot = 0;
                calendar.add(Calendar.DAY_OF_MONTH, 1);
                slotTariff = getSlotDailyTariffProfile(calendar);
            }
        }

        min *= energy;
        max *= energy;
        return new EnergyCostInfo((float) cost, min, max, deltaEnergy);
    }

    // compute the cost using the energy allocated in the buffer. The boolean flag specifies
    // whether the buffer is time relative to the Calendar object or absolute, i.e. if the
    // zero slot of the buffer is the calendar , or zero is the time 00:00
    public float computeCost(Calendar calendar, float[] energyAllocation) {
        // Initialize slotTariff to the current Daily Tariff Profile
        float[] slotTariff = getSlotDailyTariffProfile(calendar);
        int tariffSlot = CalendarUtil.getSlotOf(calendar);

        int startSlot = tariffSlot;
        int endSlot = energyAllocation.length;
        while (energyAllocation[--endSlot] == 0 && endSlot > startSlot)
            ;

        double cost = 0;
        int addedDays = 0;
        while (startSlot <= endSlot) {
            cost += slotTariff[tariffSlot++] * energyAllocation[startSlot++];
            if (tariffSlot >= slotTariff.length) {
                // roll to the next day
                tariffSlot = 0;
                calendar.add(Calendar.DAY_OF_MONTH, 1);
                ++addedDays;
                slotTariff = getSlotDailyTariffProfile(calendar);
            }
        }
        // before returning restore the calendar
        calendar.add(Calendar.DAY_OF_MONTH, -addedDays);
        // NOTE: the tariff is Kwatt/hour, while the 'energy' parameter is in watt/hour
        // therefore the necessary division by 1000
        return (float) (cost * 0.001);
    }

    /*
    public float computeCost1(Calendar calendar, float[] energyAllocation) {
       return computeCost1(calendar, energyAllocation, true);
    }
    public float computeCost1(Calendar calendar, float[] energyAllocation, boolean absoluteTimeAllocation) {
       int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK) -1;
       int tariffSlot = CalendarUtil.getSlotOf(calendar);
       int startSlot = absoluteTimeAllocation ? tariffSlot : 0;
       int endSlot = energyAllocation.length;
       while (energyAllocation[--endSlot] == 0);
        
       TariffIntervals[] tariffIntervals = weekTariffIntervals[dayOfWeek];
           
       double cost = 0;
       while (startSlot <= endSlot) {
      // find the tariff interval that includes this time slot
      for (int i = 0; i < tariffIntervals.length; ++i) {
         int[] slotBounds = tariffIntervals[i].getSlotIntervals();
         float tariff = tariffIntervals[i].getTariff();
         for (int t = 0; t < slotBounds.length; t += 2) {
            while (tariffSlot >= slotBounds[t] && tariffSlot < slotBounds[t+1]) {
               // interval found, now get the intersection
               cost += tariff * energyAllocation[startSlot++];
               if (++tariffSlot >= CalendarUtil.DAILY_TIME_SLOTS) {
                   // roll to the next day
                   tariffIntervals = weekTariffIntervals[++dayOfWeek %7];
                   tariffSlot -= CalendarUtil.DAILY_TIME_SLOTS;
                }
            }
         }      
      }
       }
       // the tariff is expressed 'per hour', so divide by the number of slots in one hour
       return (float)cost;// * CalendarUtil.SLOT_TARIFF_COEFFICIENT;
    }
    */

    public String toString() {
        StringBuilder sb = new StringBuilder();
        for (int day = 0; day < 7; ++day) {
            sb.append("\nDay ").append(day);
            for (int i = 0; i < weekTariffIntervals[day].length; ++i) {
                int[] bounds = weekTariffIntervals[day][i].getTimeIntervals();
                float cost = weekTariffIntervals[day][i].getTariff();
                sb.append("\n").append(cost).append(" @ ");
                for (int j = 0; j < bounds.length; j += 2) {
                    sb.append("[").append(bounds[j]).append(',');
                    sb.append(bounds[j + 1]).append(']');
                }
            }
        }
        return sb.toString();
    }

    public static class TariffIntervals {
        private float tariff;
        private int[] timeIntervals;
        private int[] slotIntervals;

        public TariffIntervals(float tariff, int[] intervals) {
            // make sure the time intervals are even (each start needs an end)
            if ((intervals.length % 2) != 0)
                throw new IllegalArgumentException("Uneven time intervals.");
            this.tariff = tariff;
            this.timeIntervals = intervals;
            slotIntervals = new int[intervals.length];

            for (int j = 0; j < intervals.length; ++j) {
                // get the hours from the coded time
                int hours = intervals[j] / 100;
                // get the minutes
                int minutes = intervals[j] % 100;
                slotIntervals[j] = CalendarUtil.getSlotOf(hours, minutes);
            }

        }

        public boolean equals(Object o) {
            if (o == this)
                return true;
            if (o == null || o.getClass() != this.getClass())
                return false;
            TariffIntervals other = (TariffIntervals) o;
            if (tariff != other.getTariff())
                return false;
            int[] otherIntervals = other.getTimeIntervals();
            if (timeIntervals.length != otherIntervals.length)
                return false;
            for (int i = 0; i < timeIntervals.length; ++i)
                if (timeIntervals[i] != otherIntervals[i])
                    return false;
            return true;
        }

        public float getTariff() {
            return tariff;
        }

        public int[] getSlotIntervals() {
            return slotIntervals;
        }

        public int[] getTimeIntervals() {
            return timeIntervals;
        }
    }
}