/* * Bee foraging simulation. Copyright by Joerg Hoehne. * For suggestions or questions email me at hoehne@thinktel.de */ package de.thinktel.foragingBee.masonGlue; import java.awt.Color; import java.util.ListIterator; import java.util.Vector; import javax.vecmath.Point3d; import sim.engine.SimState; import sim.engine.Steppable; import sim.engine.Stoppable; import sim.util.Interval; import de.thinktel.foragingBee.simulation.Bee; import de.thinktel.foragingBee.simulation.FoodSource; import de.thinktel.foragingBee.simulation.Hive; import de.thinktel.foragingBee.simulation.HiveEntrance; import de.thinktel.foragingBee.simulation.IAgentLocator; import de.thinktel.foragingBee.simulation.IMovingAgent; import de.thinktel.foragingBee.simulation.IVisualAgent; import de.thinktel.foragingBee.simulation.Obstacle; /** * This abstract class hold all information for the simulation. This class * implements the simulated world of a hive ({@link Hive}), bees ({@link Bee}) * and food sources ({@link FoodSource}). This class does not provide any user * interface. * <p> * This class implements {@link Steppable} and extends the type {@link SimState} * . Invoking the method {@link #step(SimState)} will provide an instance of * this class. * <p> * This class allows the access to certain simulation parameters by getter and * setter methods. These methods will be examined by an inspector to present the * access to these parameters in the GUI of the simulation. The parameters are: * * * <ul> * <li>Maximum number of bees {@link #maxBees},</li> * <li>control over the avoidance of obstacles {@link #avoidObstacles},</li> * <li>the maximum number of search steps when a bee a searching a food source * {@link #maxSearchSteps},</li> * <li>the communication noise {@link #comNoise} when bees exchanging * information,</li> * <li>the probability a bee forgets about its food source * {@link #pForgettingSource},</li> * <li>the probability a bee starts foraging again {@link #pForagingAgain},</li> * <li>the probability a bee starts scouting {@link #pStartScouting},</li> * <li>the colony nectar need {@link #colonyNectarNeed},</li> * <li>access to the hives in the simulation {@link #getHives()},</li> * <li>access to the food sources in the simulation {@link #getFoodSources()},</li> * <li>access to the obstacles in the simulation {@link #getObstacles()}.</li> * </ul> * <p> * Changes: * <ul> * <li>20090825: Added the {@link #bees} property to count the bee agents.</li> * <li>20090825: Modified the {@link #addAgent(IMovingAgent)} and * {@link #removeAgent(IMovingAgent)} methods to add bee to their properties.</li> * <li>20090827: Removed an error which causes no honey was drawn by this hive.</li> * <li>20090828: Made this class abstract for 2D and 3D computation.</li> * <li>20090829: Added the setter and getter methods.</li> * </ul> * <p> * Copyright 2009 Joerg Hoehne * * @author hoehne (<a href="mailto:hoehne@thinktel.de">Jörg Höhne</a>) * */ public abstract class ForagingHoneyBeeSimulation extends SimState implements Steppable, IAgentLocator { /** * */ private static final long serialVersionUID = -2187248402977949189L; /** * A flag indicating if this simulation shall run in a 3d simulation * environment. */ private boolean is3dMode = false; /** * The minimum x bounds. */ static public final int X_MIN = 0; /** * The maximum x bounds exclusive. */ static public final int X_MAX = 400; /** * The minimum y bounds. */ static public final int Y_MIN = 0; /** * The maximum y bounds exclusive. */ static public final int Y_MAX = 400; /** * The minimum z bounds. */ static public final int Z_MIN = 0; /** * The maximum z bounds exclusive. */ static public final int Z_MAX = 400; /** * The width (x-axis). */ static public final int WIDTH = X_MAX - X_MIN; /** * The middle of the x-axis. */ static public final int MIDDLE_WIDTH = X_MIN + (WIDTH / 2); // static public final int MIDDLE_WIDTH = 0; /** * The height (y-axis). */ static public final int HEIGHT = Y_MAX - Y_MIN; /** * The middle of the y-axis. */ static public final int MIDDLE_HEIGHT = Y_MIN + (HEIGHT / 2); // static public final int MIDDLE_HEIGHT = 0; /** * The length (z-axis). */ static public final int LENGTH = Z_MAX - Z_MIN; /** * The middle of the z-axis. */ static public final int MIDDLE_LENGTH = Z_MIN + (LENGTH / 2); // static public final int MIDDLE_LENGTH = 0; /** * The diameter of the hive. */ static public final double HIVE_DIAMETER = 80; /** * Set it to true if obstacles (other agents) are to be avoided. */ public boolean avoidObstacles = true; /** * The maximum number of bees in the simulation. This value is defined * protected only because a parametrizing subclass has to access this * property. */ public int maxBees = 800; /** * The communication problems between bees. It is noise when transferring * information. */ public double comNoise = 0.01; /** * A value describing the probability a bee forgets its source in every * iteration step. */ public double pForgettingSource = 30E-6; /** * A value describing the probability to start scouting. * */ public double pStartScouting = 39E-6; /** * A value describing the probability to forage again if the be returned * from foraging. * */ public double pForagingAgain = 500E-6; /** * The general urge the colony needs some nectar. This is a highly * aggregated variable including several aspects. */ public double colonyNectarNeed = 0.5; /** * A value describing the maximum steps for a bee searching a food source. */ public int maxSearchSteps = 100; /** * The maximum sphere radius of all objects in the simulation. */ double maxAgentSphereRadius = Double.MIN_VALUE; /** * All agents in the simulation. */ Vector<IMovingAgent> agents = new Vector<IMovingAgent>(); /** * All hives of type {@link Hive} in the simulation. */ Vector<Hive> hives = new Vector<Hive>(); /** * All food sources of type {@link FoodSource} in the simulation. */ Vector<FoodSource> foodSources = new Vector<FoodSource>(); /** * All obstacles of type {@link Obstacle} in the simulation. */ Vector<Obstacle> obstacles = new Vector<Obstacle>(); /** * All bees of type {@link Bee}. */ Vector<Bee> bees = new Vector<Bee>(); /** * The public constructor. Takes a seed for initializing the random number * generator and also a parameter set. * * @param seed */ public ForagingHoneyBeeSimulation(long seed, boolean is3dMode) { super(seed); this.is3dMode = is3dMode; } /** * Overwritten method for execution of this {@link SimState} object. */ public void start() { super.start(); // initialize the simulation initSimulation(); // add this simulation to the scheduler schedule.scheduleRepeating(this); } /** * This method is performed when the next step for the simulation is * computed. This simulation does nothing, so nothing is inside the body of * the method. * <p> * This method is used because this object is placed in the scheduler. * * * @param state * The {@link SimState} environment, in this simulation an * instance of type {@link ForagingHoneyBeeSimulation} or more * likely one of the subclasses. */ public void step(SimState state) { if (!is3dMode) { ListIterator<IMovingAgent> li = agents.listIterator(); while (li.hasNext()) { IMovingAgent a = li.next(); if (Math.abs(a.getLocation().z) > 0.000001) { System.err.println("Agent " + a + " z:" + a.getLocation().z); } } } } /** * This method prepares the simulation by creating all necessary objects. * This step is not really necessary because this can be done in the method * {@link #start()} that is called prior executing the simulation. But to * provide ready initialized objects for an user interface an even prior * call is a precondition so the objects are instantiated before even * {@link #start()} is called because the user interface and a model * inspector are created before calling {@link #start()}. */ public void prepareSimulation() { // create the hive Hive hive = new Hive(this, is3dMode, new Point3d(50, 50, MIDDLE_LENGTH), HIVE_DIAMETER, 2000); addAgent(hive); // create the entrance HiveEntrance entrance = new HiveEntrance(this, is3dMode, hive, 0); hive.setEntrance(entrance); addAgent(entrance); FoodSource f1 = new FoodSource(this, is3dMode, new Point3d(300, 100, MIDDLE_LENGTH), 20, new Color(0xd0, 0x00, 0x00), 100); addAgent(f1); FoodSource f2 = new FoodSource(this, is3dMode, new Point3d(50, 350, MIDDLE_LENGTH), 15, new Color(0xc0, 0xc0, 0x00), 200); addAgent(f2); FoodSource f3 = new FoodSource(this, is3dMode, new Point3d(200, 200, MIDDLE_LENGTH), 35, new Color(0xd0, 0x00, 0xd0), 300); addAgent(f3); FoodSource f4 = new FoodSource(this, is3dMode, new Point3d(180, 250, MIDDLE_LENGTH), 18, new Color(0x00, 0xd0, 0xd0), 300); addAgent(f4); Obstacle o; o = new Obstacle(this, is3dMode, new Point3d(155, 130, MIDDLE_LENGTH), 20); addAgent(o); o = new Obstacle(this, is3dMode, new Point3d(0, 0, MIDDLE_LENGTH), 20); addAgent(o); } /** * This method will be called by the {@link #start()} method that will start * the simulation. The agents are created and placed into the simulation. * The method {@link #prepareSimulation()} is called first to prepare the * simulation and provide the user interface with data. * <p> * This method places <b>every</b> agent in the scheduler, even those that * are created in {@link #prepareSimulation()}. */ private void initSimulation() { /* * If a hive exists create the maximum number of bees. */ Hive hive = hives.get(0); if (hive != null) { Point3d fsl = hive.getLocation(); int i; for (i = 0; i < maxBees; i++) { Bee b = new Bee(this, is3dMode, hive, new Point3d(fsl.x, fsl.y, MIDDLE_LENGTH)); addAgent(b); } } /* * Bee b = new Bee(this, hive, new Point3d(170, 135, MIDDLE_LENGTH)); * addAgent(b); b.setState(Bee.State.returnWithoutInfo); * b.headTo(hive.getEntrance()); */ /* * Place *every* agent in the scheduler. */ ListIterator<IMovingAgent> li; li = agents.listIterator(); while (li.hasNext()) { IIterationAgent agent = (IIterationAgent) li.next(); Object o = schedule.scheduleRepeating(agent); agent.setSchedulerInformation(o); } } /** * Check if the center of the agent is outside the simulation bounds. For * every bound on the axis it is checked if it is below the minimum or above * or equal the maximum: the maximum value is outside. * * @param agent * @return True if the agent is outside the boundaries. */ public boolean isOutside(IMovingAgent agent) { Point3d l = agent.getLocation(); return ((l.x < X_MIN) | (l.x >= X_MAX) | (l.y < Y_MIN) | (l.y >= Y_MAX) | (l.z < Z_MIN) | (l.z >= Z_MAX)); } /** * Check if the center of the agent is outside the xy-pane of the simulation * bounds. For every bound on the axis it is checked if it is below the * minimum or above or equal the maximum: the maximum value is outside. * * @param agent * @return True if the agent is outside the boundaries. */ public boolean isOutsideXY(IMovingAgent agent) { Point3d l = agent.getLocation(); return ((l.x < X_MIN) | (l.x >= X_MAX) | (l.y < Y_MIN) | (l.y >= Y_MAX)); } /** * Check if the center of the agent is outside the z-axis of the simulation * bounds. For every bound on the axis it is checked if it is below the * minimum or above or equal the maximum: the maximum value is outside. * * @param agent * @return True if the agent is outside the boundaries. */ public boolean isOutsideZ(IMovingAgent agent) { Point3d l = agent.getLocation(); return (l.z < Z_MIN) | (l.z >= Z_MAX); } /** * Add an agent to the simulation. The maximum sphere of all objects is * computed during successfully adding an agent. Some agent classes are * additionally stored in list to provide access in the user interface. * * @param agent * @return True, if the agent has successfully added; false otherwise. */ public boolean addAgent(IMovingAgent agent) { if (!agents.contains(agent)) { agents.add(agent); if (agent instanceof Bee) { bees.add((Bee) agent); } else { if (agent instanceof Hive) { hives.add((Hive) agent); } else { if (agent instanceof FoodSource) { foodSources.add((FoodSource) agent); } else { if (agent instanceof Obstacle) { obstacles.add((Obstacle) agent); } } } } double r = agent.getSphereRadius(); if (r > maxAgentSphereRadius) maxAgentSphereRadius = r; return true; } return false; } /** * Remove an agent from the simulation. If the agent has a sphere which * represents the maximum radius of all agents spheres the (possible) new * maximum sphere is computed. * <p> * The agents are also removed from the additional lists if necessary. * <p> * The agent is also removed from the simulation's scheduler. * * @param agent * @return True if the agent has been removed, false otherwise (because it * has never been stored). */ public boolean removeAgent(IMovingAgent agent) { boolean status = agents.remove(agent); if (agent instanceof Bee) { bees.remove(agent); } else { if (agent instanceof Hive) { hives.remove(agent); } else { if (agent instanceof FoodSource) { foodSources.remove(agent); } else { if (agent instanceof Obstacle) { obstacles.remove(agent); } } } } if (status) { double radius = agent.getSphereRadius(); if (radius >= maxAgentSphereRadius) { maxAgentSphereRadius = computeMaxAgentSphereRadius(); } } if (agent instanceof IIterationAgent) { IIterationAgent a = (IIterationAgent) agent; Stoppable stop = (Stoppable) a.getSchedulerInformation(); stop.stop(); } if (agent instanceof IVisualAgent) { Object o = removeFromVisualization((IVisualAgent) agent); System.out.println("removeFromVisualization: " + o); } return status; } /** * Compute the maximum radius of all agents inside this simulation. * * @return The computed maximum sphere currently in the simulation. */ private double computeMaxAgentSphereRadius() { double max = Double.MIN_VALUE; double r; ListIterator<IMovingAgent> li = agents.listIterator(); while (li.hasNext()) { r = li.next().getSphereRadius(); if (r > max) max = r; } return max; } /** * Compute every agent that is within a certain location from an agent. This * method assumes all objects are points so only the objects. Due to the * algorithm provided by MASON objects with a distance at least as provided * are included. * * @param agent * The agent where to start. * @param distance * The distance (radius) the returned agents should lie within. * @return All objects that are at least in the distance. */ public abstract Object[] getObjectsWithinDistance(IMovingAgent agent, double distance); /** * Return the maximum radius of all agents inside this simulation. * * @return The current maximum sphere. */ public double getMaxSphereRadius() { return this.maxAgentSphereRadius; } // ==================== Getter and Setter methods ==================== // ========== Number of Bees ========== /** * Get the maximum number of bees in the simulation. * * @return The current maximum number of bees. */ public int getNumberOfBees() { return maxBees; } /** * Set the maximum number of bees in the simulation. * * @param value * The current maximum number. */ public void setNumberOfBees(int value) { maxBees = value; } /** * The interval the number of bees lies in. * * @return The interval allowed for setting. */ public Interval domNumberOfBees() { return new Interval(1, 2000); } // ========== Avoid obstacles ========== /** * Get if obstacles (other agents) have to be avoided.. * * @return The current state, true if avoiding. */ public boolean getAvoidObstacles() { return avoidObstacles; } /** * Set if obstacles (other agents) have to be avoided.. * * @param value * The the current state, true if avoiding. */ public void setAvoidObstacles(boolean value) { avoidObstacles = value; } // ========== Maximum search time given in steps ========== /** * Get the maximum number of steps the bees is looking for a food source. * * @return The current maximum of search steps. */ public int getMaxSearchSteps() { return maxSearchSteps; } /** * Set the maximum number of steps the bees is looking for a food source. * * @param value * The current maximum number of search steps. */ public void setMaxSearchSteps(int value) { maxSearchSteps = value; } /** * The interval the number of maximum search steps lies in. * * @return The interval allowed for setting. */ public Interval domMaxSearchSteps() { return new Interval(1, 200); } // ========== Communication noise ========== /** * Get the communication noise between the bees. * * @return The current communication noise. */ public double getCommunicationNoise() { return comNoise; } /** * Set the communication noise between the bees. * * @param value * The current communication noise. */ public void setCommunicationNoise(double value) { comNoise = value; } /** * The interval the communication noise factor lies in. * * @return The interval allowed for setting. */ public Interval domCommunicationNoise() { return new Interval(0, .2); } // ========== The probability to forget the source ========== /** * Get the probability a bee forgets the source. * * @return The current probability. */ public double getpForgettingSource() { return pForgettingSource; } /** * Set the probability a bee forgets the source. * * @param value */ public void setpForgettingSource(double value) { pForgettingSource = value; } /** * The interval the probability the bee forgets the source lies in. * * @return The interval allowed for setting. */ public Interval dompForgettingSource() { return new Interval(1E-6, 100E-6); } // ========== The probability to forage again ========== /** * Get the probability a bee forgets the source. * * @return The current probability. */ public double getpForagingAgain() { return pForagingAgain; } /** * Set the probability a bee forgets the source. * * @param value */ public void setpForagingAgain(double value) { pForagingAgain = value; } /** * The interval the probability the bee forgets the source lies in. * * @return The interval allowed for setting. */ public Interval dompForagingAgain() { return new Interval(0, 500E-6); } // ========== The probability to forage again ========== /** * Get the probability a bee forgets the source. * * @return The current probability. */ public double getpStartScouting() { return pStartScouting; } /** * Set the probability a bee forgets the source. * * @param value */ public void setpStartScouting(double value) { pStartScouting = value; } /** * The interval the probability the bee forgets the source lies in. * * @return The interval allowed for setting. */ public Interval dompStartScouting() { return new Interval(0, 250E-6); } // ========== Colony nectar need ========== /** * Get the general urge to collect nectar. * * @return The current colony nectar need. */ public double getColonyNectarNeed() { return colonyNectarNeed; } /** * Set the general urge to collect nectar. * * @param value */ public void setColonyNectarNeed(double value) { colonyNectarNeed = value; } /** * The interval the colony nectar need factor lies in. * * @return The interval allowed for setting. */ public Interval domColonyNectarNeed() { return new Interval(0, 1.0); } // ========== Make the hives available in the GUI ========== /** * Return the food sources in the simulation. * * @return The {@link Vector} with the hives of type {@link Hive}. */ public Vector<Hive> getHives() { return hives; } // ========== Make the food sources available in the GUI ========== /** * Return the food sources in the simulation. * * @return The {@link Vector} with the food sources of type * {@link FoodSource}. */ public Vector<FoodSource> getFoodSources() { return foodSources; } // ========== Make the obstacles available in the GUI ========== /** * Return the food sources in the simulation. * * @return The {@link Vector} with the obstacles of type {@link Obstacle}. */ public Vector<Obstacle> getObstacles() { return obstacles; } }