Welcome to the provisional home page of the Heatbugs simulation model! The purpose of this page is to provide provisional access to the Java code of the heatbugs model until the regular VSEit home page is ready for use. Below you find the complete listings of all classes needed to get the Heatbugs model run within VSEit, version 0.97. Classes are:
The model was implemented using the Java based VSEit framework. For latest information about VSEit, please visit www.vse.de.
Name of Model: | Heatbugs |
---|---|
Author: | Kai-H. Brassel |
Date: | 01/07/01 |
VSEit Version: | 0.97 |
Start Simulation: | Netscape Navigator 4.x (on Windows 95/98/ME/NT4/2000, Linux, and Solaris) |
Microsoft Explorer 5.x (on Windows 95/98/ME/NT4/2000) | |
Other browsers and platforms (e.g. Netscape Navigator 6 on Windows 95/98/ME/NT4/2000 and Linux) |
By clicking at the appropriate link above the should simulation will automatically be downloaded and executed as an applet in your browser. If not already installed, your browser attempts to download and install a plug-in for the required Java version, too. If you encounter problems with the automatic installation performed by your browser, download the Java Runtime Environment (JRE) for Java 2, version 1.3.1, from http://java.sun.com/j2se/1.3/jre/index.html. Then close your browser, install the JRE, and try again.
If the applet starts up, choose File > New Simulation...
from
the main menu and provide any name for the new simulation run, you are
going to create. Then, issue command Simulation > Run
and
watch the show.
package de.vseit.heatbugs; import java.util.Date; import java.awt.Point; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import de.vseit.simulation.Simulation; import de.vseit.simulation.Clock; import de.vseit.simulation.SimulationTimeFormat; import de.vseit.simulation.InitializeModelException; import de.vseit.showit.DataCollection; import de.vseit.network.IntegerAttribute; import de.vseit.network.Multiplicity; import de.vseit.network.InputPane; public class Model extends Simulation { // ----- entity type definitions ----- static final String HEAT_RANGE = "0 to " + HeatSpace.MAX_TEMP; public static final IntegerAttribute NUM_BUGS = new IntegerAttribute( "Number of heatbugs: ",Multiplicity.MANDATORY,true,null,"> 0",null); public static final IntegerAttribute IDEAL_TEMP_MIN = new IntegerAttribute( "Minimal ideal temperature of bugs: ",Multiplicity.MANDATORY,true,null, HEAT_RANGE,null); public static final IntegerAttribute IDEAL_TEMP_MAX = new IntegerAttribute( "Maximal ideal temperature of bugs: ",Multiplicity.MANDATORY,true,null, HEAT_RANGE,null); public static final IntegerAttribute OUTPUT_HEAT_MIN = new IntegerAttribute( "Minimal output heat of bugs: ",Multiplicity.MANDATORY,true,null, HEAT_RANGE,null); public static final IntegerAttribute OUTPUT_HEAT_MAX = new IntegerAttribute( "Maximal output heat of bugs: ",Multiplicity.MANDATORY,true,null, HEAT_RANGE,null); public void initializeEntity() { super.initializeEntity(); entity().add(PAUSE_TIMES,new Date(500)); entity().set(NUM_BUGS,30); entity().set(IDEAL_TEMP_MIN,17000); entity().set(IDEAL_TEMP_MAX,31000); entity().set(OUTPUT_HEAT_MIN,3000); entity().set(OUTPUT_HEAT_MAX,10000); } public void acceptEntity(InputPane inputs) { super.acceptEntity(inputs); if (inputs.get(NUM_BUGS) <= 0) inputs.set(NUM_BUGS,1); if (inputs.get(IDEAL_TEMP_MIN) > inputs.get(IDEAL_TEMP_MAX)) { inputs.markError(IDEAL_TEMP_MIN); inputs.markError(IDEAL_TEMP_MAX); } if (inputs.get(OUTPUT_HEAT_MIN) > inputs.get(OUTPUT_HEAT_MAX)) { inputs.markError(OUTPUT_HEAT_MIN); inputs.markError(OUTPUT_HEAT_MAX); } int maxT = HeatSpace.MAX_TEMP; if (inputs.get(IDEAL_TEMP_MIN) < 0) inputs.set(IDEAL_TEMP_MIN,0); if (inputs.get(IDEAL_TEMP_MIN) > maxT) inputs.set(IDEAL_TEMP_MIN,maxT); if (inputs.get(IDEAL_TEMP_MAX) < 0) inputs.set(IDEAL_TEMP_MAX,0); if (inputs.get(IDEAL_TEMP_MAX) > maxT) inputs.set(IDEAL_TEMP_MAX,maxT); if (inputs.get(OUTPUT_HEAT_MIN) < 0) inputs.set(OUTPUT_HEAT_MIN,0); if (inputs.get(OUTPUT_HEAT_MIN) > maxT) inputs.set(OUTPUT_HEAT_MIN,maxT); if (inputs.get(OUTPUT_HEAT_MAX) < 0) inputs.set(OUTPUT_HEAT_MAX,0); if (inputs.get(OUTPUT_HEAT_MAX) > maxT) inputs.set(OUTPUT_HEAT_MAX,maxT); } // ----- end of entity type definitions ----- static { TIME_FORMAT = new SimulationTimeFormat(); INIT_TIME.initTimeFormat(TIME_FORMAT); STOP_TIME.initTimeFormat(TIME_FORMAT); PAUSE_TIMES.initTimeFormat(TIME_FORMAT); DataCollection.initializeDataClasses(new Class[]{MacroData.class}); } HeatSpace space; ArrayList bugs; Model(MainWindow mainWindow) { super(mainWindow); bugs = new ArrayList(); space = new HeatSpace(this); repository.insert(space,120,20,2); // insert heat space on level 2, so that it will always stay behind // the heat bugs "living" on level 1 (the default level) Clock clock = new Clock("Step",1,1000,1) { public void execute() { // simulate diffusion and evaporation in the heat space space.step(); // simulate one cycle of each heat bug's life Collections.shuffle(bugs,rnd0.getGenerator()); for (int i=0; i < bugs.size(); i++) ((Heatbug)bugs.get(i)).step(); // data sampling observations.addData(Model.this,new MacroData(Model.this)); } }; repository.insert(clock,10,120); } protected void initializeModel() throws InitializeModelException { observations.createDataSample(this,MacroData.class); // trim number of heatbugs int n = entity().get(NUM_BUGS) - bugs.size(); if (n > 0) for (int i=0; i < n; i++) { Heatbug bug = new Heatbug(this); bugs.add(bug); repository.insert(bug); } else if (n < 0) for (int i=0; i < -n; i++) repository.delete((Heatbug)bugs.remove(bugs.size()-1)); // initialize heat bugs randomly Point coords = new Point(); Iterator iter = bugs.iterator(); while (iter.hasNext()) { Heatbug bug = (Heatbug)iter.next(); do { coords.x = rnd0.nextUniform(0,space.width-1); coords.y = rnd0.nextUniform(0,space.height-1); } while (space.isOccupiedAt(coords)); bug.entity().set(bug.IDEAL_TEMP,rnd0.nextUniform( entity().get(IDEAL_TEMP_MIN),entity().get(IDEAL_TEMP_MAX))); bug.entity().set(bug.OUTPUT_HEAT,rnd0.nextUniform( entity().get(OUTPUT_HEAT_MIN),entity().get(OUTPUT_HEAT_MAX))); bug.placeAt(coords); } } protected void stopSimulationRun() { space.step(); super.stopSimulationRun(); } protected void resetSimulationRun() { space.resetSimulationRun(); } }
package de.vseit.heatbugs; import java.awt.geom.Ellipse2D; import java.awt.Color; import java.awt.Point; import java.util.Observable; import java.util.ArrayList; import de.vseit.network.*; public class Heatbug extends AbstractEntityClient { // provide the first HeatSpace.NUM_NEIGHBOURS integers as constants to // avoid repeating allocation of new integer objects in step private static final Integer[] INTEGERS = new Integer[HeatSpace.NUM_NEIGHBOURS]; { for (int d=0; d < HeatSpace.NUM_NEIGHBOURS; d++) INTEGERS[d] = new Integer(d); } // ----- entity type definitions ----- public static final Multiplicity MULTIPLICITY = Multiplicity.NONE; // attributes public static final IntegerAttribute IDEAL_TEMP = new IntegerAttribute( "Ideal Temperature: ",Multiplicity.MANDATORY,true,null,Model.HEAT_RANGE, null); public static final IntegerAttribute OUTPUT_HEAT = new IntegerAttribute( "Output Heat: ",Multiplicity.MANDATORY,true,null,Model.HEAT_RANGE,null); public static final DoubleAttribute UNHAPPINESS = new DoubleAttribute( "Unhappiness: ",Multiplicity.OPTIONAL,false,null,null,null); private static final EntityShape SHAPE = new EntityShape(new Ellipse2D.Float(1,1,10,10),1); static void setBugsSize(int cellSize) { SHAPE.setShape(new Ellipse2D.Float(0,0,cellSize-3,cellSize-1)); } public EntityShape shape() { SHAPE.setInnerColor(color); return SHAPE; } public void acceptEntity(InputPane inputs) { int maxT = HeatSpace.MAX_TEMP; if (inputs.get(IDEAL_TEMP) < 0) inputs.set(IDEAL_TEMP,0); if (inputs.get(IDEAL_TEMP) > maxT) inputs.set(IDEAL_TEMP,maxT); if (inputs.get(OUTPUT_HEAT) < 0) inputs.set(OUTPUT_HEAT,0); if (inputs.get(OUTPUT_HEAT) > maxT) inputs.set(OUTPUT_HEAT,maxT); } public void update(Observable sender, Object aspect) { if (aspect == IDEAL_TEMP) { float brightness = (float)entity().get(IDEAL_TEMP)/HeatSpace.MAX_TEMP; color = new Color(brightness,brightness,0); entity().changed("look"); } } // ----- end of entity type definitions ----- // instance variables private Model model; private HeatSpace myWorld; private Point gridPos; // may only modified via moveTo() and placeAt() private Color color; private ArrayList bestPlaces; Heatbug(Model m) { model = m; myWorld = model.space; gridPos = new Point(); bestPlaces = new ArrayList(HeatSpace.NUM_NEIGHBOURS); } void step() { Point coords = new Point(); // update unhappiness int ideal = entity().get(IDEAL_TEMP); int heatDiff = StrictMath.abs(ideal-myWorld.getHeatAt(gridPos)); entity().set(UNHAPPINESS,(double)heatDiff / HeatSpace.MAX_TEMP); // random moves would be implemented here // looking for a free and better place bestPlaces.clear(); for (int d=0; d < HeatSpace.NUM_NEIGHBOURS; d++) { coords.setLocation(gridPos); coords = myWorld.neighbour(coords,d); if (!myWorld.isOccupiedAt(coords)) { int diff = StrictMath.abs(ideal-myWorld.getHeatAt(coords)); if (diff < heatDiff) { heatDiff = diff; bestPlaces.clear(); bestPlaces.add(INTEGERS[d]); } else if (diff == heatDiff) bestPlaces.add(INTEGERS[d]); } } coords.setLocation(gridPos); if (!bestPlaces.isEmpty()) { int d = model.rnd0.nextUniform(0,bestPlaces.size()-1); d = ((Integer)bestPlaces.get(d)).intValue(); coords = myWorld.neighbour(coords,d); } // update position and heat moveTo(coords); myWorld.addHeat(coords,entity().get(OUTPUT_HEAT)); } // Assumes that the target cell is free void moveTo(Point coords) { myWorld.setOccupiedAt(gridPos,false); placeAt(coords); } // The bug to be placed was not in the world before. // Assumes that the target cell is not occupied void placeAt(Point coords) { // logical placement gridPos.setLocation(coords); myWorld.setOccupiedAt(gridPos,true); // graphical placement Point zero = model.repository.getPosition(myWorld); int cs = myWorld.cellSize; model.repository.setPosition( this,zero.x+1 + coords.x*cs,zero.y + coords.y*cs); } }
package de.vseit.heatbugs; import java.awt.Rectangle; import java.awt.Point; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Color; import java.awt.GridBagConstraints; import javax.swing.JComponent; import javax.swing.JPanel; import java.util.Observable; import java.util.ArrayList; import java.util.HashSet; import de.vseit.network.*; public class HeatSpace extends AbstractEntityClient { // ----- entity type definitions ----- public static final Multiplicity MULTIPLICITY = Multiplicity.MANDATORY; // attributes public static final IntegerAttribute DIMENSION = new IntegerAttribute( "Dimension: ",new Multiplicity(2,2),true,null,"width * height",null); public static final IntegerAttribute CELL_SIZE = new IntegerAttribute( "Size of a cell: ",Multiplicity.MANDATORY,true,null,"5 to 30 pixel",null); public static final DoubleAttribute DIFFUSION = new DoubleAttribute( "Diffusion constant: ",Multiplicity.MANDATORY,true,null, "0.0 to 1.0",null); public static final DoubleAttribute EVAPORATION = new DoubleAttribute( "Evaporation rate: ",Multiplicity.MANDATORY,true,null, "0.0 to 1.0",null); public static final EntityShape SHAPE = new EntityShape(new Rectangle(0,0,3,3),0); public EntityShape shape() { return SHAPE; } public void initializeEntity() { super.initializeEntity(); entity().set(DIMENSION, new int[]{40,40}); entity().set(CELL_SIZE,8); entity().set(DIFFUSION,1.0); entity().set(EVAPORATION,0.01); } public void installCustomComponent(JPanel panel) { JComponent ca = new JComponent() { public void paint(Graphics g) { super.paint(g); for (int y=0; y < height; y++) for (int x=0; x < width; x++) { g.setColor(colorOfHeat(space[x][y])); g.fillRect(x*cellSize,y*cellSize,cellSize,cellSize); } } }; GridBagConstraints gbc = new GridBagConstraints(); gbc.fill = GridBagConstraints.BOTH; gbc.weightx = 1.0; gbc.weighty = 1.0; panel.add(ca,gbc); } public double entityViewWidth() {return width*cellSize;} public double entityViewHeight() {return height*cellSize;} public void acceptEntity(InputPane inputs) { super.acceptEntity(inputs); // allow for changing dimensions of space only if simulation is not // initialized, active or ready (but new or resetted) if (inputs.isChanged(DIMENSION)) if (model.isNew()) { // prohibit a to small int w = inputs.get(DIMENSION,0); int h = inputs.get(DIMENSION,1); if (w < 3 || h < 3) inputs.set(DIMENSION,new int[] {StrictMath.max(3,w),StrictMath.max(3,h)}); } else inputs.reset(DIMENSION); if (inputs.get(CELL_SIZE) < 5) inputs.set(CELL_SIZE,5); if (inputs.get(CELL_SIZE) > 30) inputs.set(CELL_SIZE,30); if (inputs.get(DIFFUSION) < 0) inputs.set(DIFFUSION,0); if (inputs.get(DIFFUSION) > 1) inputs.set(DIFFUSION,1); if (inputs.get(EVAPORATION) < 0) inputs.set(EVAPORATION,0); if (inputs.get(EVAPORATION) > 1) inputs.set(EVAPORATION,1); } public void update(Observable sender, Object aspect) { super.update(sender,aspect); if (aspect == DIMENSION) { width = entity().get(DIMENSION,0); height = entity().get(DIMENSION,1); space = new short[width][height]; spaceNext = new short[width][height]; occupied = new boolean[width][height]; // These three arrays are initialized correctly by default with // zeros and false values (see ...) entity().changed("shape"); } if (aspect == CELL_SIZE) { cellSize = entity().get(CELL_SIZE); entity().changed("shape"); Heatbug.setBugsSize(cellSize); for (int i=0; i < model.bugs.size(); i++) ((Heatbug)model.bugs.get(i)).entity().changed("shape"); } } // ----- end of entity type definitions ----- static final int MAX_TEMP = Short.MAX_VALUE; private static final int NUM_COLORS = 64; // encoding of relative neighbour position in this sequence: // northwest, north, northeast, east, southeast, south, southwest, west private static final Point[] NEIGHBOURS = new Point[] { new Point(-1,-1), new Point( 0,-1), new Point( 1,-1), new Point( 1, 0), new Point( 1, 1), new Point( 0, 1), new Point(-1, 1), new Point(-1, 0) }; static final int NUM_NEIGHBOURS = NEIGHBOURS.length; private Model model; int width; int height; int cellSize; private short[][] space; private short[][] spaceNext; private boolean[][] occupied; private Color[] colorMap; public HeatSpace(Model m) { model = m; // colors for displaying different amounts of heat in the heat space colorMap = new Color[NUM_COLORS]; for (int i=0; i < NUM_COLORS; i++) { float c = i/(NUM_COLORS-1f); colorMap[i] = new Color(c,0,0); } } private Color colorOfHeat(int heat) { return colorMap[heat*(NUM_COLORS-1)/MAX_TEMP]; } int getHeatAt(Point coords) { return space[coords.x][coords.y]; } void addHeat(Point coords, int someHeat) { space[coords.x][coords.y] = (short)StrictMath.min(space[coords.x][coords.y]+someHeat,MAX_TEMP); } Point neighbour(Point coords, int direction) { coords.x = (coords.x + NEIGHBOURS[direction].x + width) % width; coords.y = (coords.y + NEIGHBOURS[direction].y + height) % height; return coords; } void setOccupiedAt(Point coords, boolean flag) { occupied[coords.x][coords.y] = flag; } boolean isOccupiedAt(Point coords) { return occupied[coords.x][coords.y]; } void resetSimulationRun() { for (int y=0; y < height; y++) for (int x=0; x < width; x++) { space[x][y] = 0; occupied[x][y] = false; } entity().changed("look"); } void step() { double diff = entity().get(DIFFUSION); double evap = 1-entity().get(EVAPORATION); Point coords = new Point(); for (int y=0; y < height; y++) for (int x=0; x < width; x++) { int heatAround = 0; for (int d=0; d < NUM_NEIGHBOURS; d++) { coords.x = x; coords.y = y; coords = neighbour(coords,d); heatAround += space[coords.x][coords.y]; } heatAround = heatAround / NUM_NEIGHBOURS; int oldHeat = space[x][y]; spaceNext[x][y] = (short)StrictMath.round( evap*(oldHeat + diff*(heatAround-oldHeat))); } short[][] tmp = space; space = spaceNext; spaceNext = tmp; entity().changed("look"); } }
package de.vseit.heatbugs; import java.util.Date; import java.util.Iterator; public class MacroData extends Object { public Date time; public double averageUnhappiness; protected MacroData(final Model model) { time = model.currentTime(); averageUnhappiness = 0; Iterator iter = model.bugs.iterator(); while (iter.hasNext()) { Heatbug bug = (Heatbug)iter.next(); averageUnhappiness += bug.entity().get(Heatbug.UNHAPPINESS); } averageUnhappiness = averageUnhappiness / model.bugs.size(); } }
package de.vseit.heatbugs; import de.vseit.simulation.MainPane; import de.vseit.simulation.Simulation; import javax.swing.JApplet; import javax.swing.JFrame; public class MainWindow extends MainPane { protected MainWindow(JFrame myFrame, String[] args) { super(myFrame,args); } protected MainWindow(JApplet callingApplet) { super(callingApplet); } protected Simulation getNewSimulation() { return new Model(this); } protected void installCustomWindowTypes() { } public String getModelName() { return "Heatbugs"; } public Class[] getRepositoryClasses() { return new Class[]{Heatbug.class,HeatSpace.class}; } }
package de.vseit.heatbugs; import de.vseit.simulation.MainPane; import javax.swing.JFrame; public class Application extends JFrame { static void main(String[] args) { new Application(args); } Application(String[] args) { this.setBounds(20,20,970,720); MainPane p = new MainWindow(this,args); this.setRootPane(p); this.setTitle(p.getModelName()); this.show(); } }
package de.vseit.heatbugs; import de.vseit.simulation.MainPane; import de.vseit.simulation.VSEitApplet; public class Applet extends VSEitApplet { public void init() { super.init(); this.setRootPane(new MainWindow(this)); } }