# 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
- How to Draw Directly on the Display2D (or)
  How to Create a Background Image for the Display2D
- How to Make an Applet
- How to Parallelize a MASON application
- How to Schedule Things Weakly
- How to Delete Things from the Schedule
- How to Delete Things from a Field

## 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.

- Go into the sim/app/tutorial1and2 directory and compile all the java files.
- Go outside the mason directory. Construct a jar file out of the sim directory by typing the following at the command line

    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:

- The class files (*.class)
- Any images the class files load (*.jpg, *.png)
- Any HTML files displayed in the console's "About" tab (index.html)
- The sim/display/simulation.classes file

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:

- Any given step can be broken into parallel substeps each performed simultaneously. This is particularly helpful for expensive steps which can be readily parallelized on a multi-processor computer.
- A step can run asynchronously in the background independent of the simulation. This is for the rare occasions when you need to fire off things to run on their own.

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 kinds 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.

## How to Delete Things from the Schedule

Answer: just wait until their time has come up.

Schedule doesn't at present have a way to delete things except when their time is called. The reason is because Schedule uses a data structure called a binary heap to work efficiently. Heaps are good for inserting arbitrary objects and then extracting them in sorted order (in our case, sorted order means order of scheduled time). However, other arbitrary deletion of objects from binary heaps is highly inefficient. Instead, the better way to "delete" an object is to "stop" it and forget about it. It'll drop out of the Schedule in due time. How you "stop" an agent depends on whether or not it's a one-shot agent or a repeating agent, which we discuss next.

One-shot agents. Agents can be scheduled on the Schedule in two ways: one-shot agents and repeating agents. When an agent is scheduled just once, it sits in the Schedule until its time has come. At that point the agent is deleted from the Schedule and its step() method is called. If you're writing a one-shot agent, and you want your agent out of the Schedule, all you have to do is tell your agent to ignore its sole step() method and wait.

But perhaps this is inconvenient: you might want to reuse the agent and its step() method -- perhaps to reschedule it at a future time instead. Having it ignore future step() calls isn't feasible in that case. Then instead you can wrap it in another Steppable which can be stopped. We provide such an object: `sim.engine.TentativeStep`. When its step() is called, this object will in turn call step() on its subsidiary Steppable unless stop() has been called, at which time it just forgets about the subsidiary object (sets it to null). You can wrap your Steppable in various TentativeSteps and schedule each of them independently on the Schedule, then stop() various ones at your leisure.

Repeating agents. A repeating-scheduled agent has actually just been wrapped in a private 'Repeat' Steppable. When the step() method is called on the 'repeat' object, it simply calls step() on its subsidiary Steppable (your agent), then it reschedules itself in the Schedule for a later date. This 'repeat' object is also a Stoppable: when its stop() method is called, then the subsidiary Steppable is set to null and the 'Repeat' object ceases to function -- no later subsidiar step(), no later rescheduling.

This Stoppable is handed to you when you call scheduleRepeating(...): to delete a repeating object from the Schedule, you merely need to call stop() on the Stoppable and forget about the agent.

## How to Delete Things from a Field

We occasionally get questions about deleting objects from fields. All fields are designed to have objects removed very efficiently. Specifically:

SparseGrid2D, SparseGrid3D, Continuous2D, Continuous3D. Use the `remove(obj)` method declared in these classes' superclass, `SparseField`. Under no circumstances should you manually remove objects from the Bags of these classes -- there's a lot of unhooking that must be done in different places. Let `remove(obj)` do the job for you. You can also call `removeObjectsAtLocation(location)` (and variations thereof) which removes and returns all objects at a given location. And you can call `clear()` to delete all objects in the entire field.

ObjectGrid2D, ObjectGrid3D. You remove elements from these objects by simply deleting the elements from their underlying arrays. The `clear()` function will delete all elements for you.

Network. Use `removeEdge(edge)` to delete an edge from the graph, and `removeNode(node)` to delete a node from the graph. Once an edge has been removed from the graph, you can reuse it by adding it to another graph, but you cannot change the nodes it is connected to (they will be added to the other graph as well if not already present). You can also delete all nodes and edges from the graph with `clear()`.

IntGrid2D, IntGrid3D, DoubleGrid2D, DoubleGrid3D. There are no removal functions in these fields as there is nothing to "remove".