A RePast Tutorial by John T. Murphy, University of Arizona & Arizona State University (contact)
The ‘Model’ object will extend RePast’s SimModelImpl object. You never see a lot of the code that is built into the SimModelImpl object, but in fact it’s the most important code because it manages the entire RePast environment and the simulation. Moreover, it expects to find certain things in the Model object you create- this is, unfortunately, less formal than a true Interface, but the idea is similar.
The Model object that you create will be designed, in part, to react to the buttons on the RePast control toolbar.
We can dispense with a few of these buttons easily: the ‘folder’ button opens a new model; the X closes the RePast model. The light bulb opens the window in which parameters can be set.
More significant are the three active buttons to the right of the folder. The curved arrow is ‘Initialize.’ This button assumes the model is uninitialized and initializes it. The leftmost of the three is ‘play,’ which starts the model running. In between is ‘step,’ which is exactly like play except that it advances the model only one time step and pauses it. The two buttons (grey in the image above) to the right of these also act on the VCR analogy- they are ‘stop’ and ‘pause.’ The remaining button, with the two curved arrows is ‘setup.’ This button is poorly named: it, in fact, ‘tears down’ the simulation back to the uninitialized state that ‘Initialize’ expects.
Your Model object must certain methods in it. It must, for example, have a ‘getName’ method that returns the name of the simulation model being run. This name appears in some of the RePast toolbars (though not the one shown).
If you are unfamiliar with Java, it may help to focus on the above statement, even though it is something of a distraction from the main point. If you have followed the requirements so far your Model class would look like:
import uchicago.src.sim.engine.SimModelImpl;
public class MyFirstRePastModel extends SimModelImpl {
public String getName(){
return "My First RePast Model";
}
}
However, there are more requirements. When the ‘Initialize’ button is clicked on the toolbar, RePast will invoke a method in your model object called ‘begin.’ This method is responsible for initializing the simulation. Note: Beginning here, each new line of code is indicated by being highlighted in bold.
import uchicago.src.sim.engine.SimModelImpl;
public class MyFirstRePastModel extends SimModelImpl {
public String getName(){
return "My First RePast Model";
}
public void begin(){
}
}
In technical terms, the SimModelImpl class is an abstract class that implements an interface; the interface requires certain methods- we have seen two of these, getName() and begin(), and there are a few others to come. However, there is an additional structure to RePast models that is not enforced by any requirement of Java or the RePast package; it is simply a customary and useful way to organize the program. RePast models traditionally have a consistent ‘map’ to their model classes. In this case, the traditional ‘map’ dictates that the ‘begin’ method should actually divide its responsibilities into three other methods: buildModel, buildSchedule, and buildDisplay. Hence:
import uchicago.src.sim.engine.SimModelImpl;
public class MyFirstRePastModel extends SimModelImpl {
public String getName(){
return "My First RePast Model";
}
public void begin(){
buildModel();
buildSchedule();
buildDisplay();
}
public void buildModel(){
}
public void buildSchedule(){
}
public void buildDisplay(){
}
}
This structure is not required- you can do it any other way you’d like. But you will find that many RePast models do it this way, and there are certain advantages to it that make it a good procedure to follow.
No explicit methods are needed for the ‘play’, ‘pause’, ‘stop’, and ‘step’ functions, although they rely on things that are essential ingredients in the Model. However, three other functions are required.
The first is the ‘setup’ function, which is called when the button with the two curved arrows is pressed. I usually place the setup function before the begin function, but this is preference.
import uchicago.src.sim.engine.SimModelImpl;
public class MyFirstRePastModel extends SimModelImpl {
public String getName(){
return "My First RePast Model";
}
public void setup(){
}
public void begin(){
buildModel();
buildSchedule();
buildDisplay();
}
public void buildModel(){
}
public void buildSchedule(){
}
public void buildDisplay(){
}
}
The second is a getSchedule function, which must return an object of type ‘Schedule.’ Every RePast model will have at least one schedule object. Typically this is created by adding a schedule object as a class variable (note: capital Schedule is the object, lower-case schedule is the variable, per Java conventions). Hence:
import uchicago.src.sim.engine.SimModelImpl;
import uchicago.src.sim.engine.Schedule;
public class MyFirstRePastModel extends SimModelImpl {
private Schedule schedule;
public String getName(){
return "My First RePast Model";
}
public void setup(){
}
public void begin(){
buildModel();
buildSchedule();
buildDisplay();
}
public void buildModel(){
}
public void buildSchedule(){
}
public void buildDisplay(){
}
public Schedule getSchedule(){
return schedule;
}
}
Notice that to add the schedule, the schedule object is imported at the top of the file, a schedule variable is declared in the variable declarations section, and the function itself is added below
There is a bit of oddness here in that the 'schedule' object that is internal to the model is declared as 'private', which would ordinarily mean that it is not accessible directly by outside programs or other objects. Then the 'getSchedule' method is provided as a public method, and what it does is pass the 'schedule' object directly to the outside program or other object. Effectively this provides direct access to the schedule object. It might seem like a good alternative would be to just have the 'schedule' object be public, but this would be a poor choice. Right now the RePast engine, which has to have access to the model's schedule, gets this access by calling a method 'getSchedule', and this method is required by the SimModelImpl interface, so the compiler enforces this. The alternative would be to have the 'schedule' object be public, which would mean that the RePast engine would just look for it directly, but there's no way to enforce this elegantly. More importantly, by following the standard format where the internal variable is private and one of the object's methods provides the access, the programmer is left free to implement the internal 'schedule' any way desired. In this example, I named my schedule 'schedule', but I didn't have to, and another name might have been clearer. Even more important, I could create a child of the Schedule class that adds more functionality, or done any number of other things to suit my needs; as long as the 'getSchedule' method returns an object of the appropriate type, RePast's engine will be happy. Finally, we note that public/private is less important here than it might be; we could make our schedule object 'public' without too much concern, because we will have a more complete knowledge of how our model will be used than we would if we were creating a production API to be distributed to and used by other programmers.
The last necessary ingredient is rather complicated. It is the getInitParam function, which returns an array of String variables, each one listing the name of a particular parameter that you want to be available to vary using the RePast control panel.
Suppose you want to have a simulation in which N agents are implemented, but you want to be able to run the simulation with different Ns simply by clicking the ‘setup’ and ‘initialize’ buttons (without changing code). RePast permits this by requiring the following:
So, assume we want to have a variable called ‘numAgents’ (watch capitalization closely here- it’s tricky and it matters!):
import uchicago.src.sim.engine.SimModelImpl;
import uchicago.src.sim.engine.Schedule;
public class MyFirstRePastModel extends SimModelImpl {
private Schedule schedule;
private int numAgents;
public String getName(){
return "My First RePast Model";
}
public void setup(){
}
public void begin(){
buildModel();
buildSchedule();
buildDisplay();
}
public void buildModel(){
}
public void buildSchedule(){
}
public void buildDisplay(){
}
public Schedule getSchedule(){
return schedule;
}
}
Typical programming practice and the specific RePast structure require us to provide get and set methods as follows:
import uchicago.src.sim.engine.SimModelImpl;
import uchicago.src.sim.engine.Schedule;
public class MyFirstRePastModel extends SimModelImpl {
private Schedule schedule;
private int numAgents;
public String getName(){
return "My First RePast Model";
}
public void setup(){
}
public void begin(){
buildModel();
buildSchedule();
buildDisplay();
}
public void buildModel(){
}
public void buildSchedule(){
}
public void buildDisplay(){
}
public Schedule getSchedule(){
return schedule;
}
public int getNumAgents(){
return numAgents;
}
public void setNumAgents(int na){
numAgents = na;
}
}
Finally, inform RePast that you want to be able to vary this in the control panel by creating the getInitParam method as follows:
import uchicago.src.sim.engine.SimModelImpl;
import uchicago.src.sim.engine.Schedule;
public class MyFirstRePastModel extends SimModelImpl {
private Schedule schedule;
private int numAgents;
public String getName(){
return "My First RePast Model";
}
public void setup(){
}
public void begin(){
buildModel();
buildSchedule();
buildDisplay();
}
public void buildModel(){
}
public void buildSchedule(){
}
public void buildDisplay(){
}
public Schedule getSchedule(){
return schedule;
}
public String[] getInitParam(){
String[] initParams = { "NumAgents" };
return initParams;
}
public int getNumAgents(){
return numAgents;
}
public void setNumAgents(int na){
numAgents = na;
}
}
Capitalization is tricky because the variable is ‘numAgents’ but the ‘get’ and ‘set’ methods become getNumAgents (capital N) and setNumAgents. The string that tells RePast that the method can be used is thus ‘NumAgents’ because RePast will look (automatically) for methods named "get" + the string and "set" + the string, hence "getNumAgents" and "setNumAgents."
[Note: getInitParams returns an array of strings; so far in our example we have only one String to be returned; the syntax if there were more is, for example:
String[] initParams = { "NumAgents", "AgentStrength" };
Even if there is only one parameter name to be returned, the return type must be an array. The square brackets in 'String[]' indicate that what is being returned is not a String object but a pointer to an array of String objects, and hence must be used both in the declaration of the method and in the creation of the variable 'initParams' within the method.]
Go to Table of Contents
A RePast Tutorial by John T. Murphy, University of Arizona & Arizona State University (contact)