/* Domestic Lighting Model - Simulation Example Code
Copyright (C) 2008 Ian Richardson, Murray Thomson
CREST (Centre for Renewable Energy Systems Technology),
Department of Electronic and Electrical Engineering
Loughborough University, Leicestershire LE11 3TU, UK
Tel. +44 1509 635326. Email address: I.W.Richardson@lboro.ac.uk
Java implementation (c) 2014 James Keirstead
Imperial College London
j.keirstead@imperial.ac.uk
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package uk.ac.imperial.simelec;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import au.com.bytecode.opencsv.CSVReader;
import cern.jet.random.Normal;
import cern.jet.random.Uniform;
import cern.jet.random.engine.MersenneTwister;
import cern.jet.random.engine.RandomEngine;
/**
* Simulates electricity demand for lighting in a household at one-minute
* intervals during the day.
*
* @author James Keirstead
*
*/
public class LightingModel extends LoadModel<Bulb> {
private float mean_irradiance = 60f;
private float sd_irradiance = 10f;
// Data files
private static String irradiance_file = "/data/irradiance.csv";
private static String bulbs_file = "/data/bulbs.csv";
/**
* Create a LightingModel for a specified month and output directory
*
* @param month
* an int giving the month to simulate (1-12)
* @param dir
* a String giving the output directory
* @param model
* an OccupancyModel to provide data on occupancy within the home
*/
public LightingModel(int month, String dir, OccupancyModel model) {
super(month, true, dir, new File(dir, "lighting_output.csv"), model);
}
/**
*
* Simulates the electricity demand for lighting in a household for a single
* day at one-minute intervals.
*
* @param args
* takes four arguments, plus three options. The first is an int
* giving the number of residents in the home, the second an int
* giving the month to simulate (1-12), the third is a two-letter
* code indicating weekend (<code>we</code>) or weekday (
* <code>wd</code>), and the fourth is a String giving the output
* directory. The optional arguments five and six are floats
* giving the mean and standard deviation of the irradiance in
* W/m2. Optional argument seven is an int giving a random number
* seed.
*
* If these are not specified, the default is to simulate two
* occupants for a weekday with results saved in the current
* directory.
*
* @throws IOException
*/
public static void main(String[] args) throws IOException {
int month = 1;
int residents = 2;
boolean weekend = false;
String dir = ".";
OccupancyModel occ = new OccupancyModel(residents, weekend, dir);
if (args.length == 4 || args.length == 6 || args.length == 7) {
residents = Integer.valueOf(args[0]);
month = Integer.valueOf(args[1]);
weekend = args[2].equals("we") ? true : false;
dir = args[3];
occ = new OccupancyModel(residents, weekend, dir);
if (args.length == 7)
LightingModel.setSeed(Integer.valueOf(args[4]));
} else {
System.out.printf(
"%d arguments detected. Using default arguments.%n",
args.length);
}
LightingModel model = new LightingModel(month, dir, occ);
if (args.length == 6) {
model.mean_irradiance = Float.valueOf(args[2]);
model.sd_irradiance = Float.valueOf(args[3]);
}
model.run();
}
/**
*
* Runs the LightingModel.
*
* @throws IOException
*
*/
public void runModel() throws IOException {
// Ensure the output directory exists
File dir = new File(this.out_dir);
if (!dir.isDirectory())
dir.mkdirs();
// Calculation the irradiance threshold for the house
float iThreshold = (float) Normal.staticNextDouble(
this.mean_irradiance, this.sd_irradiance);
// Calculate the number of bulbs in the household
loads = getBulbs();
int[] irradiance = getIrradianceData(month);
int[] occupancy = model.getOccupancy();
// Main simulation loop
// for each bulb in the household
for (Bulb b : loads) {
// for each minute of the day
int t = 0;
while (t < 1440) {
// Get the irradiance at that moment
int ir = irradiance[t];
// Get the number of active occupants, adjusting for 10 minute
// intervals
int occ = occupancy[(int) Math.floor(t / 10f)];
// if at least one active occupant and insufficient irradiance,
// turn on a bulb
boolean low_light = (ir < iThreshold)
|| (Uniform.staticNextDouble() < 0.05);
// Get effective occupant to account for sharing
float effective_occupancy = getEffectiveOccupancy(occ);
// if bulb switched on:
if (low_light
&& Uniform.staticNextDouble() < (effective_occupancy * b.weight)) {
int duration = getLightDuration();
for (int j = 0; j < duration; j++) {
if (t >= 1440)
break;
if (occ != 0) {
b.on(t);
t++;
}
}
} else {
t++;
}
}
}
}
/**
* Effective occupancy represents the sharing of light use.
*
* Derived from: U.S. Department of Energy, Energy Information
* Administration, 1993 Residential Energy Consumption Survey, Mean Annual
* Electricity Consumption for Lighting, by Family Income by Number of
* Household Members
*
* @param occ
* an int giving the active number of household occupants
* @return a float giving the effective occupant factor
*/
private float getEffectiveOccupancy(int occ) {
switch (occ) {
case 0:
return (0f);
case 1:
return (1.000f);
case 2:
return (1.528f);
case 3:
return (1.694f);
case 4:
return (1.983f);
case 5:
return (2.094f);
}
return (0f);
}
/**
* Gets the bulbs in the household based on 100 sample bulb configurations.
* The data has been generated stochastically, based upon statistics
* available from: (1) The Lighting Association, In Home Lighting Audit
* Report, Domestic Lighting Report 2008. (2) Market Transformation
* Programme, Assumptions for energy scenarios in the domestic lighting
* sector, version 4.0, 2008.
*
* @return a List of Bulb objects
* @throws IOException
*/
private List<Bulb> getBulbs() throws IOException {
// Load in the raw data
InputStream is = this.getClass().getResourceAsStream(bulbs_file);
CSVReader reader = new CSVReader(new InputStreamReader(is), ',', '\'',
10);
List<String[]> myEntries = reader.readAll();
reader.close();
// Choose a random house
int house = Uniform.staticNextIntFromTo(0, myEntries.size() - 1);
// Create a set of bulbs corresponding to that line.
String[] data = myEntries.get(house);
int nBulbs = Integer.valueOf(data[1]);
List<Bulb> bulbs = new ArrayList<Bulb>(nBulbs);
// Note that the input data file is a ragged array. To get CSVReader
// to work, it has been padded with 0 values for bulb ratings. However
// the first column "nBulbs" specifies how many valid values to read.
for (int i = 0; i < nBulbs; i++) {
// Read in the power rating of the bulb
int rating = Integer.valueOf(data[2 + i]);
Bulb b = new Bulb(i, rating);
bulbs.add(b);
}
return (bulbs);
}
/**
* Gets irradiance data
*
* @param month
* an integer giving the month of the year (1-12)
* @return an array of irradiance values in W/m2 at one-minute intervals
* @throws IOException
*/
private int[] getIrradianceData(int month) throws IOException {
InputStream is = this.getClass().getResourceAsStream(irradiance_file);
CSVReader reader = new CSVReader(new InputStreamReader(is), ',', '\'',
8);
List<String[]> myEntries = reader.readAll();
reader.close();
int[] answer = new int[myEntries.size()];
for (int i = 0; i < myEntries.size(); i++) {
answer[i] = Integer.valueOf(myEntries.get(i)[1 + month]);
}
return (answer);
}
/**
*
* Gets the duration of a lighting event (i.e. how long will a bulb will
* stay on for once switched on?).
*
* Source: M. Stokes, M. Rylatt, K. Lomas, A simple model of domestic
* lighting demand, Energy and Buildings 36 (2004) 103-116
*
* @return
*/
private int getLightDuration() {
int interval = Uniform.staticNextIntFromTo(0, 8);
int low = 0;
int up = 0;
switch (interval) {
case 0:
low = 1;
up = 1;
break;
case 1:
low = 2;
up = 2;
break;
case 2:
low = 3;
up = 4;
break;
case 3:
low = 5;
up = 8;
break;
case 4:
low = 9;
up = 16;
break;
case 5:
low = 17;
up = 27;
break;
case 6:
low = 28;
up = 49;
break;
case 7:
low = 50;
up = 91;
break;
case 8:
low = 92;
up = 259;
break;
}
float rnd = (float) Uniform.staticNextDouble();
return (int) (low + rnd * (up - low));
}
/**
* Sets the seed for the random number generator.
*
* @param seed
* an int giving the seed
*/
public static void setSeed(int seed) {
// TODO verify that this works for the Normal draws as well
RandomEngine engine = new MersenneTwister(seed);
Uniform.staticSetRandomEngine(engine);
}
}