How-Tos

These are short examples of how to do things in MASON you may have been wondering about. For more involved examples of extending MASON to use parameterization, use charts and graphs, etc., see the online Web Tutorials.

How to Create a Field Portrayal Inspector

Inspectors are primarily for objects and for the model proper. What if you want to make several inspectors for various fields? Create the Inspector as you see fit, as some subclass of sim.portrayal.Inspector. Then attach the Inspector to the Display2D (using Display2D.attach(...) ) with an appropriate name. This will put a menu for the inspector in the Display2D's layers menu.

The Social Networks package comes with an example about doing this with the Network field.

How to Draw Directly On the Display2D (or)
How to Create a Background Image for the Display2D

There are two different "kinds" of drawing on the Display2D you might want:
  1. Draw in a fashion that auto-scales and auto-scrolls like the rest of the portrayals (perhaps a background map of a country that the portrayals appear to move over).
  2. Draw something which retains its location and size regardless of how the Display2D is scaled or scrolled (perhaps an overlay of current statistics).

Auto-Scaling and Auto-Scrolling

The easiest way to draw in an auto-scaling fashion is to create a SimplePortrayal2D to draw the item; create a 2D Field (say, a Continuous2D); put a random object (say the String "object") into that Field; create a FieldPortrayal2D to draw the Field (say, a ContinuousPortrayal2D), and attach it to your display.

If you use a Continuous2D, you'll want to make that your discretization significantly larger than the object you're storing. If you just have a single object, we suggest making the discretization as large or larger than the entire region of the field (so it's just one big cell).

The most common need is probably to put a map in the background of the screen. For this, your SimplePortrayal2D could be an ImagePortrayal2D. Make sure your field's width and height are of the proportions you want. Then add the object to the exact center of the field you've created. Now attach an ImagePortrayal2D along these lines:


myContinuousPortrayal2D.setField(theContinuousField);
myContinuousPortrayal2D.setPortrayalForAll(new ImagePortrayal2D(
    new ImageIcon(getClass().getResource("MyPicture.gif")).getImage()),theContinuousField.width);
myDisplay.attach(myContinuousPortrayal2D, "Overlay");

If the image is taller than wide, change theContinuousField.width to theContinuousField.height. If you're filling the entire background, remember to set Display2D's backdrop to null so it doesn't bother drawing it.

Scale-Independent

If you want to make an overlay, this is even easier. Create your own subclass of FieldPortrayal2D which overrides the draw method. The relevant coordinates are in the DrawInfo2D. Specifically, the field region is stored in the Rectangle called draw, and the displayed region on-screen is stored in the Rectangle called clip. Usually clip is what you want. For example, you might define the following FieldPortrayal2D to draw the current ticks in the top-left corner of the screen:

FieldPortrayal2D overlay = FieldPortrayal2D()
    {
    Font font = new Font("SansSerif", 0, 18);  // keep it around for efficiency
    public void draw(Object object, Graphics2D graphics, DrawInfo2D info)
        {
        String s = "";
        if (state !=null)
            s = state.schedule.getTimestamp("Before Simulation", "All Done!");
        graphics.setColor(Color.blue);
        graphics.drawString(s, (int)info.clip.x + 10, 
                (int)(info.clip.y + 10 + font.getStringBounds(s,graphics.getFontRenderContext()).getHeight()));

        }
    };
You don't need to set the field of this FieldPortrayal2D -- just leave it empty. All you need to do is attach it to your Display and you're on your way.

Note that this method locks to the top-left corner of the clip region. If you have scrolled out a lot, the clip region will be smaller than the window and located in the center of it. If you want to always draw in the top-left corner of the screen, you need to tell the Display2D to stop clipping. Then the clip region will always be the scroll rectangle. However if any of your portrayals spill outside of the clip region, their unclipped drawing will now be visible.

If you're filling the entire background with this method, remember to set Display2D's backdrop to null so it doesn't bother drawing it.

Another way to draw a scale-independent image in the background is to use a TexturePaint wrapped around your image, and use that as the "Paint" to draw the Display2D's backdrop. You could, for example, add this to your setupPortrayals method:


Image i = new ImageIcon(getClass().getResource("MyPicture.gif")).getImage();
BufferedImage b = display.getGraphicsConfiguration().createCompatibleImage(i.getWidth(null), i.getHeight(null));
Graphics g = b.getGraphics();
g.drawImage(i,0,0,i.getWidth(null),i.getHeight(null),null);
g.dispose();
display.setBackdrop(new TexturePaint(b, new Rectangle(0,0,i.getWidth(null),i.getHeight(null))));
This will tile the image into the scrolled space. Unfortunately, large tiled images are buggy on certain platforms (such as OS X java 1.3.x). So we don't recommend it.

How to Make an Applet

As an example, we will convert Conway's Game of Life from Tutorials 1 and 2 into an applet.

Modify the simulation.classes File

The simulation.classes file, located in the sim/display directory, specifies which files will appear in the pop-up list when the user chooses "New Simulation...". Edit this file to include only those simulations you wish the user to have access to. If you put the word 'ONLY' on a line all by itself, the user will not be able to type in a simulation classname by hand. If the file consists solely of the world 'ONLY', then the "New Simulation..." menu will be grayed out and the user won't be able to make a new simulation at all.

Build the Jar File

To make an applet you need two things: a web page which sets up the applet in HTML, and the applet code, typically embedded as a jar file. The jar file should contain all the non-standard classes that might be loaded during the course of running the applet, plus any pictures or auxillary data loaded by the applet. We begin by building a basic jar file.


jar cvf mason.jar mason
This dumps the entire mason directory, java files and all, into a jar file called mason.jar. You don't need all those files -- you just need:

To extract just these files and no others from the MASON directory and stuff them into a jar file, the easiest approach is (in UNIX or on a Mac) to go into the mason directory and type


make jar

This is still a big file for users to download. If you really want to shrink this, you'll need to identify which classes and related files have to be extracted. Generally speaking the only images that need to be extracted for MASON to operate are the PNG files in the display and util/gui directories. The HTML files you need are probably just those in the application directories you wish to make available. And you'll need the simulation.classes file. As to the class files: generally you're safe if you just grab all the class files in the mason directory EXCEPT for various sim/app/... applications you don't wish to include. Certain tutorials have big pictures, and you'll save a lot of space by tossing those tutorials out. If you're not doing Java3D, you can toss out the files in the portrayal3d and display3d directories as well.

Construct the HTML Page

Applets have changed over the years and certain web browsers <cough>IE</cough> have their own weird ways of doing things. We've constructed a sample web page that you should be able to modify. It's called SimApplet.html and is located in the sim/display/ directory.

Your mason.jar file should be located on the website right next to this HTML file. An example is shown on the MASON home page.

If you want to fire up MASON directly on the simulation of your choice, you'll need to change an applet parameter called Simulation in your HTML file. Its value is by default sim.display.Console, but you can change it to a simulation class, for example, sim.app.heatbugs.HeatBugsWithUI

You can also change what is placed on the button by changing the Name parameter. Note that these parameters have to be changed in several locations in our version of the file, because different web browsers handle HTML in subtly different ways.

How to Parallelize a MASON Application

MASON provides two kinds of parallelization:

Note that parallelization uses threads and is subject to race conditions. If your parallel actions perform writes or access the random number generator, you'll need to synchronize on the schedule. Remember not to hold the lock on the schedule for long!

Parallel Substeps

MASON provides a Steppable called ParallelSequence. If you load this Sequence with Steppables, when the Sequence is stepped, it will spawn independent threads to step each of its contained Steppables independently. It then waits for them to all finish their step() methods, then after they have it will clean up and finish its own step() method. Read the documentation for ParallelSequence carefully. Notably: be careful about putting a RandomSequence inside a ParallelSequence.

The MASON HeatBugs example shows a variety of approaches to improving the efficiency of the HeatBugs Diffuser, up to and including parallelizing it for multiple processors using ParallelSequence.

Asynchronous Steppables

The AsynchronousSteppable class allows you to fire off a Steppable from the Schedule which goes and runs in its own thread indefinitely. The Schedule does not wait for it to finish. The AsynchronousSteppable class is Stoppable, and also provides a "Stopper" (a Steppable which you can schedule to stop the AsynchronousSteppable at a future time if it has not already stopped).

Generally speaking there are two kings of Asynchronous Steppable operations: fast one-shot operations and slow or inifinite-loop operations. Fast one-shot operations can simply fire off in their own thread and do their thing, assuming they're fast enough that the user is willing to wait for them to finish after he has pressed the Stop or Pause buttons or is checkpointing out the simulation. Slow or infinite-loop operations must be able to respond to requests to be paused, resumed, and stopped (killed).

We expect that the use of Asynchronous Steppables should be exceedingly rare. Indeed, adding them to MASON required some retooling and we do not know if it works properly: it's essentially untested at this point. Read the AsynchronousSteppable documentation very closely.

How to Schedule Things Weakly

What if you want to schedule something to occur only if the object still exists? But you don't want the schedule to necessarily hold onto the object if you're low on memory?

MASON provides WeakSteppable, a wrapper for Steppables which holds onto them as WeakReferences. It also maintains weak Stoppables as well (though that may change). Keep in mind that just because the WeakReference is being held onto no one but the Schedule doesn't mean the Schedule will let go of it: this only occurs when Java needs to reclaim the WeakReference, perhaps during garbage collection.

When the WeakSteppable lets go of its weak reference, the WeakSteppable is still scheduled in the Schedule. It'll just do nothing when the Schedule gets around to stepping it. However, the time will advance to the scheduled point.