SimuLaw Update – March 19

Working in RePast has not been terribly complex so long as I stay in the built-in environment (something very similar to remaining strictly in Processing). However, once I try to move RePast fully into Java, problems constantly arise.

The following is an overall summary of all my work to dates, together with notes on issues.

Research – I have completed a fairly exhaustive review of ABMS literature and feel comfortable with the principles, modeling approaches, etc. I have a strong bibliography and literature review and feel I could write a survey/intro paper without too much difficulty.

Model – I have completed what I believe is a conceptually sound model. I am starting far simpler than I had hoped, but have fleshed out a basic “jay-walking” model using shorthand logic and some predicate calculus.

Programming – This is problematic. Repast is apparently written using a Design Patterns approach. I was unaware of this and did not find any indication of this in any of the documentation. Fortunately, Heather Dewey-Hagborg was able to help me understand this.

“Design Patterns” are an approach to writing Java (and presumably other object-oriented) applications. It is not so much a framework as a design philosophy, perhaps like RESTful design for web applications. Design Patterns require development of object frameworks. The most common appear to be “Observers” and “Factories”.

It appears in Repast that an Observer pattern is the fundamental pattern to work with. That is, everything is built in a “context” within RePast — all agents reside in the context. The context gets built with a context “factory”. I *believe* that the context is the subject in the Observer pattern, and that it is then necessary to add an actual observer.

There are also a set of external XML files that contain parameters that are passed to the runtime. For example, a simple model would have a “grid” “projection” and a “space” “projection” — you create a “context” and then add projections. While these would be created using Factories, it is also necessary to identify them as “child” projections in an XML file. I’m not sure why this is, I believe it’s so that you can modify the runtime as it is used. This is not so much of a problem. The XML files are just in another folder and you need to label and format them correctly.

The developers have also built “launchers” in Eclipse that replace the “main” Java method. Instead of executing main, Eclipse looks for launcher files. The launcher files are also XML files that contain a pointer to the ultimate “repast.main” method. Very confusing to me and not too well documented, but I think I can live with that or try to replace. In looking at repast.main, it appears to just do some error trapping and then have a set of parameters to be passed.

The system also uses “schedulers” that run continuously and can be used to monitor and execute certain agents or their methods. So, some agents can be “scheduled” to run continuously, while some methods of an agent can be set to run only if a variable is changed in another agent — so, you can “schedule” zombies to run all the time, but “humans” to run only when a zombie has “moved” (a variable set in the zombie class).

I originally thought the Java scripting language “Groovy” was also required, but based on consultation with the developers, that  does not appear to be necessary.

The Problems I’m Facing - (1) I don’t really understand Design Patterns yet. I’m working my way through the book Head First Design Patterns, but the more serious issue is (2) I still need to “detach” the java code from the runtime and run it just as a standard java library that can hopefully pass things to the Processing canvas. In theory, I can ask any agent to report back what and where it is and I can also tell the system to continuously “check” every location on the grid or on the continuous space and instruct it to “run” a method for each agent that occupies that space. Unfortunately, I can’t get even the simplest “pure java” app to work. I have some guidance from Argonne, but it doesn’t really help (attached below).

Guidance from Argonne National Laboratory:

(1) The /bin and lib/*.jar from repast.simphony.core and the same from repast.simphony.relogo.runtime and repast.simphony.runtime, although for the latter the lib jars are probably sufficient.

(2) You might also need repast.simphony.relogo.ide. With respect to the core /lib jars you won’t need the geotools ones if you are not doing any geographical work which you won’t if you are focusing on ReLogo. These are the jars prefixed with gt2-.

(3) You’ll also need the groovy-all.jar for ReLogo. There’s probably a version of this as an eclipse plugin if you are using the same eclipse that runs Repast, but you can get a stand alone version from the groovy website. You’ll want version 1.8.  [NOTE – THIS DOES NOT APPEAR TO BE NECESSARY]

(4) Lastly, I’d recommend you use the code from our git repository on sourceforge. This will give you the latest and greatest and we hope to release with that very soon. git://repast.git.sourceforge.net/gitroot/repast/repast.simphony

(5) NOTE – THE LAST RELEASE OF REPAST IS NOW OUT.

(6) There are some additional steps you’ll need to take to initialize an observer. These are pretty much what you find in the SimBuilder.groovy code that is part of every ReLogo project. I have attached a sample one to this email. The relevant code is:

int minPxcor = p.getValue("default_observer_minPxcor");
int maxPxcor = p.getValue("default_observer_maxPxcor");
int minPycor = p.getValue("default_observer_minPycor");
int maxPycor = p.getValue("default_observer_maxPycor");
RLWorldDimensions rLWorldDimensions = new RLWorldDimensions(minPxcor, maxPxcor, minPycor, maxPycor);
LinkFactory lf = new LinkFactory(UserLink);
TurtleFactory tf = new TurtleFactory(UserTurtle);
PatchFactory pf = new PatchFactory(UserPatch);
ReLogoWorldFactory wf = new ReLogoWorldFactory(context,"default_observer_context", rLWorldDimensions, tf, pf, lf);

ObserverFactory oF = new ObserverFactory(“default_observer”,UserObserver,wf);

            Observer dO = oF.createObserver();

For the world dimensions (i.e. the minPxcor etc.) you should substitute your own hardcoded values, for now. I believe the defaults are -16,-16 and 16, 16. For the various Factories, add “.class” on to the arguments (i.e., new TurtleFactory(UserTurtle.class). That you don’t see it in the above is a groovy artifact — it will be necessary in Java. You’ll need to do the same with the UserObserver in the ObserverFactory. Then use that factory to create your observer. When you’ve done that, methods like createObserver should work

In addition, the single argument constructors for LinkFactory and TurtleFactory below are convenience constructors, which make use of some assumptions on the structure and loading of regular Repast Simphony projects. They automatically find all the necessary link and turtle types. You would likely need to use the non-automated version, which simply require you to explicitly specify any additional link and turtle types (if any) you’d like to use.

So this could be as simple as:

 LinkFactory lf = new LinkFactory(UserLink.class, new ArrayList<Class<? extends BaseLink>>());
TurtleFactory tf = new TurtleFactory(UserTurtle.class, new ArrayList<Class<? extends BaseTurtle>>());

This would for specifying no additional custom link or turtle classes.

To something like:

List<Class<? extends BaseTurtle>> customTurtles = new ArrayList<Class<? extends BaseTurtle>>();
customTurtles.add(MyCustomTurtle1.class);
customTurtles.add(MyCustomTurtle2.class);
TurtleFactory tf = new TurtleFactory(UserTurtle.class, customTurtles);

For specifying MyCustomTurtle1 and MyCustomTurtle2 as additional custom turtle classes (I’ve omitted the link bit).

(8) The ContextBuilder’s build method, as used in a regular Repast Simphony simulation workflow, expects a non-null (i.e., instantiated) Context object. That looks like what’s going wrong here. In this “stripped down” approach, you’d need to instantiate your own.

(9) Given the use of the ContextBuilder, I’m not sure what level of integration with Repast you want. If its just using Repast classes (i.e. create a context, and run the schedule), then something like the following should work.

 //-- Initialization --  Create the context
 DefaultContext<MyAgent> context = new DefaultContext<MyAgent>();
 // Add any projections to it
 GridFactory gridFactory = GridFactoryFinder.createGridFactory(null);
Grid<MyAgent> grid = gridFactory.createGrid("grid", context, new GridBuilderParameters<MyAgent>(
        new WrapAroundBorders(), new SimpleGridAdder<MyAgent>(), true, 50, 50));
 // Add agents
 for (int i = 0; i < count; i++) {
      int energy = RandomHelper.nextIntFromTo(4, 10);
      context.add(new MyAgent(energy));
}
 // Create a schedule
 ISchedule schedule = new Schedule();
 // Add actions to the schedule
 private static class MyAction implements IAction {
     Context<MyAgent> context;
     public MyAction(Context<MyAgent> context) {
      this.context = context;
    }
     @Override
    public void execute() {
      // probably want to use the random iterator here
        for (MyAgent agent : context) {
            // do something with the agent
            // e.g. move it in the grid etc.
        }
   }
schedule.schedule(ScheduleParameters.createRepeating(1, 1), new MyAction(context));
  // -- Running -- Call execute on the schedule during Processing's event loop
 schedule.execute()

(10) You could also use a ScheduleRunner to run the schedule, but that would integrate less well with Processing. See ScheduleRunner and its implementations in the repast source for more details.

(11) ReLogo in Java. Just to clarify — you should be able to use the various primitives in Java — BaseTurtles etc. provided the world is set up as we described in a previous email. These are just Java classes so they should work.

Leave a Comment