/* * JABM - Java Agent-Based Modeling Toolkit * Copyright (C) 2013 Steve Phelps * * 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. */ package net.sourceforge.jabm; import java.io.Serializable; import java.util.ArrayList; import net.sourceforge.jabm.agent.Agent; import net.sourceforge.jabm.event.AbstractModel; import net.sourceforge.jabm.event.BatchFinishedEvent; import net.sourceforge.jabm.event.BatchStartingEvent; import net.sourceforge.jabm.event.SimEvent; import net.sourceforge.jabm.init.SimulationFactory; import net.sourceforge.jabm.report.Report; import org.apache.log4j.Logger; /** * The SimulationController is responsible for running a batch of one or more * independent Simulation runs. It is responsible for establishing the event * listening relationships between the different components of the simulation, * and is the container for all of the {@link Report} objects in the simulation. * * @author Steve Phelps */ public abstract class SimulationController extends AbstractModel implements Runnable, EventScheduler, Serializable { /** * The index of the current simulation. */ protected int batch = 0; /** * The total number of simulations to run. */ protected int numSimulations = 1; /** * The reports that will collect data on the simulations. */ protected ArrayList<Report> reports = new ArrayList<Report>(); /** * The underlying simulation. */ protected Simulation simulation; /** * The simulationFactory is responsible for initialising * the simulation at the beginning of each run. */ protected SimulationFactory simulationFactory; protected boolean listenersInitialised = false; protected boolean isRunning; protected int slowSleepInterval = 0; /** * A human-readable description of the model that can * be presented to the user of the model, e.g. in a GUI. */ protected String modelDescription; static Logger logger = Logger.getLogger(SimulationController.class); public SimulationController() { } /** * Run the batch of simulations in sequence. */ @Override public void run() { setListeners(); fireEvent(new BatchStartingEvent(this)); this.isRunning = true; for(batch = 0; batch<numSimulations && isRunning(); batch++) { if (logger.isInfoEnabled()) logger.info("Running simulation " + (batch+1) + " of " + numSimulations + ".."); runSingleSimulation(); if (logger.isInfoEnabled()) logger.info("simulation done."); } fireEvent(new BatchFinishedEvent(this)); this.isRunning = false; } /** * Run a single simulation. */ public void runSingleSimulation() { constructSimulation(); simulation.run(); } /** * Query the simulation time in the currently running simulation. */ @Override public SimulationTime getSimulationTime() { return simulation.getSimulationTime(); } @Override public void fireEvent(SimEvent event) { super.fireEvent(event); } /** * Terminate all simulations. */ public void terminate() { logger.info("Terminating simulation(s).. "); simulation.resume(); // resume if paused simulation.terminate(); isRunning = false; } /** * Fetch the Population of the current simulation. * @return */ public Population getPopulation() { return simulation.getPopulation(); } public ArrayList<Report> getReports() { return reports; } /** * Configure the reports for this simulation. * * @param reports * @see net.sourceforge.jabm.report.Report */ public void setReports(ArrayList<Report> reports) { this.reports = reports; } public void addReport(Report report) { reports.add(report); } /** * Fetch the total number of simulations to run in this batch. */ public int getNumSimulations() { return numSimulations; } /** * Configure the number of independent simulations to run as * part of a Monte-carlo experiment. * * @param numSimulations */ public void setNumSimulations(int numSimulations) { this.numSimulations = numSimulations; } public Simulation getSimulation() { return this.simulation; } public void setSimulation(Simulation simulation) { this.simulation = simulation; } public SimulationFactory getSimulationFactory() { return simulationFactory; } /** * Configure the initialiser for this simulation. * * @see net.sourceforge.jabm.init.SimulationFactory * @param simulationInitialiser */ public void setSimulationFactory( SimulationFactory simulationInitialiser) { this.simulationFactory = simulationInitialiser; } public int getSlowSleepInterval() { return slowSleepInterval; } public void setSlowSleepInterval(int slowSleepInterval) { this.slowSleepInterval = slowSleepInterval; } /** * Slow down the simulation by sleeping for the specified * interval in between simulation steps. * * @param slowSleepInterval */ public void slow(int slowSleepInterval) { setSlowSleepInterval(slowSleepInterval); if (simulation != null) { simulation.slow(slowSleepInterval); } } public boolean isRunning() { return isRunning; } /** * Establish any listening relationships that are required prior * to launching a new simulation. */ protected void setListeners() { logger.debug("Establishing listeners... "); wireReports(); wireSimulation(); logger.debug("done."); } /** * Establish the listening relationships for Report objects. */ protected void wireReports() { logger.debug("Wiring reports... "); for (Report report : reports) { logger.debug("Adding listener " + report); this.addListener(report); } logger.debug("genericListeners = " + genericListeners); logger.debug("done."); } /** * Configure the listener relationships for the simulation object. */ protected void wireSimulation() { logger.debug("Wiring simulation... "); this.addListener(simulation.getPopulation()); for(Agent agent : simulation.getPopulation().getAgents()) { agent.setScheduler(this); } if (logger.isDebugEnabled()) { logger.debug("genericListeners = " + this.genericListeners); logger.debug("specificListeners = " + this.specificListeners); } logger.debug("done."); } /** * Remove listeners prior to reconstructing the simulation object. */ protected void tearDownSimulation() { logger.debug("Tearing down simulation... "); clearListeners(); if (logger.isDebugEnabled()) { logger.debug("specificListeners = " + specificListeners); logger.debug("genericListeners = " + genericListeners); } logger.debug("done."); } public String getModelDescription() { return modelDescription; } public void setModelDescription(String modelDescription) { this.modelDescription = modelDescription; } protected abstract void constructSimulation(); }