info.raack.appliancedetection.evaluation.service.DefaultSimulationService.java Source code

Java tutorial

Introduction

Here is the source code for info.raack.appliancedetection.evaluation.service.DefaultSimulationService.java

Source

/*******************************************************************************
 * This file is part of the Appliance Energy Detector, a free household appliance energy disaggregation intelligence engine and webapp.
 * 
 * Copyright (C) 2011,2012 Taylor Raack <traack@raack.info>
 * 
 * The Appliance Energy Detector is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
 * 
 * The Appliance Energy Detector 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 Affero General Public License for more details.
 * 
 * You should have received a copy of the GNU Affero General Public License along with the Appliance Energy Detector.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * According to sec. 7 of the GNU Affero General Public License, version 3, the terms of the AGPL are supplemented with the following terms:
 * 
 * If you modify this Program, or any covered work, by linking or combining it with any of the following programs (or modified versions of those libraries), containing parts covered by the terms of those libraries licenses, the licensors of this Program grant you additional permission to convey the resulting work:
 * 
 * Javabeans(TM) Activation Framework 1.1 (activation) - Common Development and Distribution License Version 1.0
 * AspectJ 1.6.9 (aspectjrt and aspectjweaver) - Eclipse Public License 1.0
 * EMMA 2.0.5312 (emma and emma_ant) - Common Public License Version 1.0
 * JAXB Project Libraries 2.2.2 (jaxb-api, jaxb-impl, jaxb-xjc) - Common Development and Distribution License Version 1.0
 * Java Standard Template Library 1.2 (jstl) - Common Development and Distribution License Version 1.0
 * Java Servlet Pages API 2.1 (jsp-api) - Common Development and Distribution License Version 1.0
 * Java Transaction API 1.1 (jta) - Common Development and Distribution License Version 1.0
 * JavaMail(TM) 1.4.1 (mail) - Common Development and Distribution License Version 1.0
 * XML Pull Parser 3 (xpp3) - Indiana University Extreme! Lab Software License Version 1.1.1
 * 
 * The interactive user interface of the software display an attribution notice containing the phrase "Appliance Energy Detector". Interactive user interfaces of unmodified and modified versions must display Appropriate Legal Notices according to sec. 5 of the GNU Affero General Public License, version 3, when you propagate an unmodified or modified version of the Program. In accordance with sec. 7 b) of the GNU Affero General Public License, version 3, these Appropriate Legal Notices must prominently display either a) "Initial Development by <a href='http://www.linkedin.com/in/taylorraack'>Taylor Raack</a>" if displayed in a web browser or b) "Initial Development by Taylor Raack (http://www.linkedin.com/in/taylorraack)" if displayed otherwise.
 ******************************************************************************/
package info.raack.appliancedetection.evaluation.service;

import info.raack.appliancedetection.common.service.ErrorService;
import info.raack.appliancedetection.common.service.ErrorService.URGENCY;
import info.raack.appliancedetection.common.util.DateUtils;
import info.raack.appliancedetection.evaluation.data.Database;
import info.raack.appliancedetection.evaluation.model.Evaluation;
import info.raack.appliancedetection.evaluation.model.EvaluationGroup;
import info.raack.appliancedetection.evaluation.model.Simulation;
import info.raack.appliancedetection.evaluation.model.SimulationGroup;
import info.raack.appliancedetection.evaluation.model.appliance.SimulatedAppliance;
import info.raack.appliancelabeler.datacollector.SimulatedTED5000ConfigurationLoader;
import info.raack.appliancelabeler.machinelearning.ApplianceDetectionManager;
import info.raack.appliancelabeler.machinelearning.appliancedetection.algorithms.ApplianceEnergyConsumptionDetectionAlgorithm;
import info.raack.appliancelabeler.model.Appliance;
import info.raack.appliancelabeler.model.EnergyTimestep;
import info.raack.appliancelabeler.model.UserAppliance;
import info.raack.appliancelabeler.model.appliancestatetransition.ApplianceStateTransition;
import info.raack.appliancelabeler.model.energymonitor.EnergyMonitor;
import info.raack.appliancelabeler.model.energymonitor.SimulatedEnergyMonitor;
import info.raack.appliancelabeler.service.DataService;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class DefaultSimulationService implements SimulationService, Runnable {

    private Logger logger = LoggerFactory.getLogger(DefaultSimulationService.class);

    @Autowired
    private SimulatedTED5000ConfigurationLoader configurationLoader;

    @Autowired
    private List<SimulatedAppliance> possibleAppliances;

    @Autowired
    private Database evaluationDatabase;

    @Autowired
    private info.raack.appliancelabeler.data.Database engineDatabase;

    @Autowired
    private DataService dataService;

    @Autowired
    private ErrorService errorService;

    @Autowired
    private DateUtils dateUtils;

    @Autowired
    private ApplianceDetectionManager applianceDetectionManager;

    private ScheduledExecutorService scheduler;

    @Autowired
    private List<ApplianceEnergyConsumptionDetectionAlgorithm> algorithms;

    @PostConstruct
    public void init() {
        startRefreshTimer();
    }

    private void startRefreshTimer() {
        try {
            logger.info("Starting Simulation Service monitor...");

            scheduler = Executors.newScheduledThreadPool(1);
            scheduler.scheduleWithFixedDelay(this, 0, 1, TimeUnit.SECONDS);
        } catch (Exception e) {
            logger.error("Could not schedule TED data loader", e);
        }
    }

    @PreDestroy
    public void stop() {
        stopRefreshTimer();
    }

    private void stopRefreshTimer() {
        try {
            logger.info("Stopping Simulation Service monitor...");
            scheduler.shutdown();
        } catch (Exception e) {
            logger.warn("Could not shutdown cleanly", e);
        }
    }

    public String startNewSimulation(long durationInSeconds, int labelsPerOnOff, int onConcurrency,
            int numAppliances, SimulationGroup group) {
        // start the simulation off in the past by durationInSeconds seconds
        Calendar cal = new GregorianCalendar();
        cal.add(Calendar.SECOND, -1 * (int) durationInSeconds);

        Simulation simulation = new Simulation(dateUtils, cal.getTime(), durationInSeconds, numAppliances,
                labelsPerOnOff, onConcurrency, possibleAppliances, group);

        // create new simulated energy monitor
        SimulatedEnergyMonitor monitor = new SimulatedEnergyMonitor(simulation);

        // generate simulated training set with labels.
        generateAndStoreSimulatedTrainingDataSet(monitor);

        // activate energy monitor
        configurationLoader.activateEnergyMonitor(monitor);

        logger.debug("Creating new simulated energy monitor " + monitor.getMonitorId());

        return simulation.getId();
    }

    public void run() {
        // look for simulations whose data has already been captured
        for (final SimulatedEnergyMonitor monitor : configurationLoader.getActiveEnergyMonitors()) {
            if (monitor.isEnergyFinishedBeingRequested()) {
                try {
                    configurationLoader.deactivateEnergyMonitor(monitor);

                    // now train the system
                    logger.info("Forcing immediate training for simulation " + monitor.getSimulation().getId());
                    applianceDetectionManager.trainPredictionModelsForMonitors(new ArrayList<EnergyMonitor>() {
                        {
                            add(monitor);
                        }
                    });

                    if (monitor.isFinalRun() == false) {
                        // the last fill was sending testing data into the system

                        // now that the training data for this monitor has been inputted into the system, generate actual simulated data for testing

                        monitor.getSimulation().reset();
                        monitor.getSimulation().incrementTimeForTestDataSet();
                        monitor.getSimulation().run();

                        // save simulation info - save simulation
                        evaluationDatabase.saveSimulation(monitor.getSimulation());

                        monitor.setFinalRun(true);

                        // activate energy monitor
                        monitor.reset();

                        configurationLoader.activateEnergyMonitor(monitor);
                    } else {
                        logger.info("Simulation for " + monitor + " complete.");
                        evaluationDatabase.setDone(monitor.getSimulation());
                    }

                } catch (Exception e) {
                    logger.error("Could not close simulation", e);
                    errorService.reportError("Could not close simulation", URGENCY.REGULAR, e);
                }
            }
        }
    }

    private void generateAndStoreSimulatedTrainingDataSet(SimulatedEnergyMonitor energyMonitor) {

        Simulation simulation = energyMonitor.getSimulation();

        // run the simulation
        simulation.run();

        Map<SimulatedAppliance, List<ApplianceStateTransition>> applianceTransitions = simulation
                .getApplianceOnOffs();

        for (SimulatedAppliance simulatedAppliance : applianceTransitions.keySet()) {
            List<ApplianceStateTransition> transitions = applianceTransitions.get(simulatedAppliance);

            if (transitions != null && transitions.size() > 0) {
                logger.debug("Creating new appliance for " + simulatedAppliance.toString());

                Appliance appliance = engineDatabase.getAllAppliances().get(0);

                // TODO - don't just pick the first appliance, as the actual appliance type might become important to any algorithm later
                UserAppliance userAppliance = new UserAppliance(-1, appliance, simulatedAppliance.getName(), -1,
                        false);

                engineDatabase.addUserAppliance(energyMonitor, userAppliance);

                // link the labeled user appliance to the simulated appliance
                simulatedAppliance.setLabeledAppliance(userAppliance);

                logger.debug("Labeling transitions for " + appliance);

                // need to set the appliance for the state transitions - we didn't have them before, so they could not go into the ApplianceStateTransition constructor
                for (ApplianceStateTransition transition : transitions) {
                    transition.setUserAppliance(userAppliance);
                }

                engineDatabase.storeUserOnOffLabels(transitions);
            } else {
                logger.debug("No labels for " + simulatedAppliance);
            }
        }

    }

    public List<Simulation> getAllSimulationInformation() {
        return evaluationDatabase.getAllSimulationInformation();
    }

    public Evaluation getEvaluation(int algorithmId, String simulationId, Date start, Date end,
            boolean includeRawPowerMeasurements) {
        // get simulation

        Date queryStart = null;
        Date queryEnd = null;

        if (start != null && end != null && end.getTime() - start.getTime() < 5 * 60 * 1000) {
            // if less than a five minute increment is selected, just use it
            queryStart = start;
            queryEnd = end;
        } else {
            if (start != null) {
                Calendar cal = new GregorianCalendar();
                cal.setTime(start);
                queryStart = dateUtils.getPreviousFiveMinuteIncrement(cal).getTime();
            }

            if (end != null) {
                Calendar cal = new GregorianCalendar();
                cal.setTime(end);
                queryEnd = dateUtils.getNextFiveMinuteIncrement(cal).getTime();
            }
        }

        logger.debug("Time window for evaluation query: " + queryStart + " - " + queryEnd);
        Simulation simulation = evaluationDatabase.getSimulation(simulationId, queryStart, queryEnd,
                includeRawPowerMeasurements);

        EnergyMonitor databaseMonitor = evaluationDatabase.getSimulatedEnergyMonitor(simulation.getId());
        SimulatedEnergyMonitor em = new SimulatedEnergyMonitor(simulation);
        em.setId(databaseMonitor.getId());

        // get predicted energy measurements
        Map<UserAppliance, List<EnergyTimestep>> predictedEnergyUsage = dataService
                .getApplianceEnergyConsumptionForMonitor(em, algorithmId, simulation.getStartTime(),
                        simulation.getEndTime());

        // get predicted appliance state transitions
        Map<UserAppliance, List<ApplianceStateTransition>> predictedApplianceStateTransitions = dataService
                .getPredictedApplianceStateTransitionsForMonitor(em, algorithmId, simulation.getStartTime(),
                        simulation.getEndTime());

        return new Evaluation(simulation, predictedEnergyUsage, predictedApplianceStateTransitions);
    }

    @Override
    public int startNewSimulationGroup(final int numberOfSimulations, final int durationInSeconds,
            final int onOffLabelsPerAppliance, final int onConcurrency, final int numAppliances) {
        final SimulationGroup group = new SimulationGroup(numberOfSimulations, new Date(), durationInSeconds,
                numAppliances, onConcurrency, onOffLabelsPerAppliance);

        evaluationDatabase.saveSimulationGroup(group);

        Runnable simulationGroupRunner = new Runnable() {

            public void run() {
                try {
                    for (int i = 0; i < numberOfSimulations; i++) {
                        // start the simulation
                        String simulationId = startNewSimulation(durationInSeconds, onOffLabelsPerAppliance,
                                onConcurrency, numAppliances, group);

                        // wait until the simulation is done
                        while (true) {
                            // sleep for 10 seconds
                            try {
                                Thread.sleep(10000);
                            } catch (InterruptedException e) {
                                // don't care if this thread got interrupted
                            }

                            if (evaluationDatabase.isSimulationDone(simulationId)) {
                                break;
                            }
                        }
                    }
                    logger.info("Done with simulation group " + group);
                } catch (Exception e) {
                    logger.error("Could not finish simulation group", e);
                }
            }
        };

        // not going to try to stop this thread if we shut down the container, I might write that later for completeness
        new Thread(simulationGroupRunner).start();

        return group.getId();
    }

    @Override
    public EvaluationGroup getEvaluationGroup(int simulationGroupId) {
        // get all simulation info for simulation group
        List<Simulation> simulations = evaluationDatabase.getAllSimulationInformationForGroup(simulationGroupId);

        // get each evaluation, for all algorithms
        Map<ApplianceEnergyConsumptionDetectionAlgorithm, List<Evaluation>> evaluationInfo = new HashMap<ApplianceEnergyConsumptionDetectionAlgorithm, List<Evaluation>>();

        for (ApplianceEnergyConsumptionDetectionAlgorithm algorithm : algorithms) {
            List<Evaluation> evaluations = new ArrayList<Evaluation>();

            for (Simulation simulation : simulations) {
                Evaluation evaluation = getEvaluation(algorithm.getId(), simulation.getId(), null, null, true);
                evaluation.dumpInternalData();
                evaluation.getSimulation().reset();
                evaluations.add(evaluation);
            }

            evaluationInfo.put(algorithm, evaluations);
        }

        return new EvaluationGroup(evaluationDatabase.getSimulationGroup(simulationGroupId), evaluationInfo);
    }
}