Java tutorial
/******************************************************************************* * 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); } }