2008年7月24日星期四

[网文随录]一些复杂性网站

By Nick Malleson

Introduction
This is a short tutorial which looks at some of the major differences between Repast 3 and Repast Simphony and goes over how to start building a simple model in Simphony. I've also made a pdf: Nick's Repast no-GUI Tutorial. For some reason the Java code on this site isn't being displayed properly but I'm working on this, in the meantime the pdf is easier to read. You'll still need this shapefile later though: people_shapefile.zip.

I’m still learning how to use repast myself so I make no promises that the information here is correct! Feel free to edit/comment or email me (my email address is on my University of Leeds School of Geography site: http://www.geog.leeds.ac.uk/people/n.malleson/). I hope that my experiences will help you overcome Simphony’s relatively steep learning curve. By the end of you should understand:

What Repast Simphony is / what it does.
How to build a simple model without using the new GUI interface,
How to use contexts and projections to organise agents,
How to read in agents from an ArcGIS Shapefile.
How to make some agents move around a geographical environment.
If you have Simphony already installed the tutorial shouldn’t take more than an hour. I assume you know how to program with Java (at a beginner level).

So what is Repast S?

A bit of history
Repast is a free and open-source set of tools which was originally based Swarm. Initially Repast was implemented exclusively in Java, although Repast version 3 is now fully object-oriented and consists of three core implementations: Repast for Java ( RepastJ); Repast for the Microsoft .Net framework ( Repast.Net); and Repast for Python Scripting ( RepastPy). However, Repast 3 has recently been superseded by a significant development named Repast Simphony ( RepastS).

Repast Simphony
The main improvements that Simphony has made over Repast3 are:

Adding a new GUI for developing models. The ``official'' Simphony tutorial ( http://repast.sourceforge.net/docs/tutorial/SIM/index.html) uses this method but I prefer to code models manually.


Improving the runtime GUI. Now you use the GUI to build displays or charts, output data, interrogate agents, and interface with other programs (like R for stats or Weka for data mining). This means that these tasks are done after the model has been built and compiled, they don't feature in the underlying code at all. This seems quite unusual at first but I now find it much quicker than the old method.


Contexts and Projections
Before we get coding, it's worth quickly describing the biggest change to the underbelly of Repast: the addition of contexts and projections.

A context is basically a bucket which we can use to hold agents. It's like a ``soup'': it holds a population of agents but doesn't give agents any concept of space or relationships (Howe et al., 2006). Contexts are arranged hierarchically and can contain sub-contexts. Agents who exist in a sub-context also exist in the parent context, but the reverse is not necessarily true. There are excellent descriptions of what contexts and projections are on the Simphony reference webpage ( http://repast.sourceforge.net/docs/reference/SIM/index.html) and the in some of the papers ( http://repast.sourceforge.net/papers/papers_main.html).

Once we have agents in a context, projections can give the agents a space and can define their relationships. For example, ``GIS'' projections gives each agent an spatial location and ``Network'' projections allow relationships between agents to be defined (e.g. a social network). Projections are created for specific contexts and will automatically contain every agent within the context (so if you add an agent to a context it is also added to any projections which have been created in that context).

An Example: SimTutorial
Ok, enough reading, lets start! Simphony has been integrated with Eclipse so we're pretty-much forced to use this development environment. If you like Eclipse then this is fine and if you don't you can edit your model code using a different text editor later anyway.

Step 1: Get Simphony
Repast Simphony is distributed as a collection of Eclipse plug-ins. You can download Eclipse with the plugins already installed (recommended) or download the plugins separately from the Repast website.

Step 2: Start Eclipse
This one is fairly straightforward.

Step 3: Build a new Simphony Project
Go to File -> New -> Other
Select Repast Simphony -> Repast Simphony Project from the box which appears.
Give the project a name (we'll call it ``SimTutorial'').
Press next a few times and then finish, the default values should all be ok.
When Eclipse has finished creating the project you should see something a bit like this:



The model.score will be open automatically (if you need to re-open the model.score file it is in the simtutorial.rs folder). This is an xml file (displayed nicely in Eclipse) which describes the model components (agents, contexts, projections and attributes). The runtime GUI reads this file so it knows what the model contains. So, if we create a new type of agent/context/projection we add it to the model.score file and then write the Java code for it. This is what we'll do next.

Step 4: Creating the first context
We could just add agents to the root context (called SimTutorial), but I find it better to organise different types of agent into their own sub-contexts. So firstly we'll create a sub-context to hold People agents:

How to create a context in model.score file:
Right-click on ``SimTutorial'' and then Create Member -> Context. This will create a new context called ``SimTutorialContext''. We can now configure this new context:
Right-click on SimTutorialContext and go to Show Properties. The box at the bottom of Eclipse should now show all the properties of our context.
To change the name of the context to something more suitable, click on Label and type ``PeopleContext''. If you scroll down a bit you'll notice that there is a property called File Name for Source Code, this is where we implement the Java code for the context.
Implement the Java class for the context. We've told Repast that we want to create a new context, but at the moment it doesn't do anything (later we want to get the context to create some People). Here's how to create Java code which will make the context do what we want:
The box on the left of the Eclipse workspace shows all the different components of the project. Click on the (+) to expand the SimTutorial folder and then expand the src folder (this is where all our source code is kept).
Right-click on the default package (called ``simtutorial'') and go to New -> Class.
We need the class to have the same name as the context so type ``PeopleContext'' in the Name box.
Finally, we can define parent classes or interfaces here. As we're creating a context we need to extend ``DefaultContext''. Click on Browse next to the Superclass box and type ``DefaultContext'' into the box which appears. After a few seconds Eclipse should find the DefaultContext class (in the repast.simphony.context package). After clicking on OK you should have something that looks like:
Click on OK and then Finish.
Now we have created a new context and a Java class for it. Eclipse will have brought up an editor for this new class. We haven't made any agents yet so we'll ignore the implementation of the context for now. Don't worry about the yellow line underneath DefaultContext, this is Eclipse's way of telling us there will be a compile-time warning (if you hold your mouse over the yellow line you'll see what the warning is). Ignore this for now.

Step 5: Creating the first agent type
We've told repast about our main context, now lets tell it what agents we want to be part of the context (this is very similar to creating a new context).

Create the agent in the model.score.
Click on the model.score tab (near the top of the Eclipse window) to show the model.score file.
Right click on ``PeopleContext'' and then Create member -> Agent.
Change the label to "Person".
Implement the Java classes.
Right click on the ``simtutorial'' package and then New -> Class.
Call the class ``Person''. Then finish.
Again, Eclipse will bring up an editor window for our Person class. Now we've created a new context and a new type of agent who will exist in the context. Check everything's OK by running Simphony. To do this click on the little arrow next to the green button and then "Run SimTutorial Model"



After a few seconds the Simphony GUI should pop up (on the left near the bottom you should see the ``PeopleContext'' subcontext). This is the GUI that we can use to create charts, show displays, output data and so on. You can save the configuration by clicking on the little disk icon so you don't need to re-create everything each time you re-run the model. If everything worked OK (there were no errors) just close Simphony for now.

Step 6: Create a projection for the agents
We've created a context and told repast that we might create some people to exist in the context, but so far we haven't said anything about the space which the agents will inhabit. Repast uses projections to specify relationships between agents and their environment. The types of projection we can use include:

GIS Projections - agents have an location and can move around a geographic environment.
Grid Projections - traditional, CA-type, grid.
Network Projections - specify relationships between agents, i.e. social networks.
In this tutorial we'll create a GIS projection. Here's how:

Tell the model.score about the projection.
In the model.score file, right click on PeopleContext and then Create Member -> Projection - Geography.
Right click on the new projection and choose Show Properties.
Change the label to ``PeopleGeography''. We don't do anything with our projection yet, we''ve just told repast that we want to use one. Because the projection is part of our PeopleContext we'll write the code for the projection in this class so that when Repast creates the PeopleContext, it will also create our PeopleGeography.
Implement the projection
Open up PeopleContext.java (should still be open as a tab in Eclipse).
Add the following default constructor to the class:
public PeopleContext() { super( "PeopleContext"); // must match name in model.scoreGeographyParameters geoParams = new GeographyParameters();// These lines actually create our Geography. Tell Repast to create a new geography projection called "PeopleGeography" in this context.Geography peopleGeography = GeographyFactoryFinder.createGeographyFactory( null).createGeography( "PeopleGeography", this, geoParams); System.out.println( "Created PeopleGeography");}
The PeopleContext() constructor will be called when our model is initialised, so all the code inside it will be executed. The indentation is probably horrible, if you highlight all the code and press Control + I Eclipse will indent everything nicely.

You'll notice that lots of the code is underlined in red. This is Eclipse telling us that there will be compile errors, this is because we need to add some import lines at the top. Eclipse has a nice way of looking for the classes we might want to import, if you click on the tiny red on the left of the line with an error you should get an option to import a class file. Figure 4 illustrates this. Import all the required class files until all the errors have been corrected (check that you are importing classes from a repast simphony package, not a class with the same name from a different package).



Step 7: Create some agents
Ok we're almost there, we have a context to hold our agents and a projection which will give them all a spatial location. Now all that's left to do is create our agents and give them some simple actions.

The first thing we need to do is add a bit more code to our Person class. Open up the class and copy all this lot in (between the open/close curly brackets of the class):

private String name; private int age; public Person() { super(); } public String getName() { return name; } public void setName( String name) { this.name = name; } public int getAge() { return age; } public void setAge( int age) { this.age = age; }
Now we could just put a for-loop in our PeopleContext class which creates some agents, adds them to the context and gives them an location in our projection, something like:

for ( int i=0; i<10; i++) {Person p = new Person(); this.add(p); // `` this'' refers to PeopleContextpeopleGeography.move(p, new GeometryFactory().createPoint( new Coordinate(i,i+1)));}
But this isn't very useful so instead we'll make use of a fantastic feature of Simphony: reading in a shapefile. (If you added the lines above then comment them out now or the agents we load from a shapefile won't display properly).

Here's how to load agents in from an ArcGIS shapefile:

I've already created a little shapefile with some people in it here: people_shapefile.zip. Get it and unzip it into the root directory of the SimTutorial project which is probably here: "My Documents/eclipse_workspace/SimTutorial". It will create a directory called People which contains the shapefile and some other necessary files.
Then add this code after creating the geography in PeopleContext.java:
// Create some people from a shapefile:File shapefile = null; // NOTE: import java.io package!ShapefileLoader personLoader = null; try {shapefile = new File( "People/people.shp");personLoader = new ShapefileLoader(Person.class, shapefile.toURL(),peopleGeography, this);} catch (java.net.MalformedURLException e) {e.printStackTrace();} while (personLoader.hasNext()) {personLoader.next();}
The amazing thing about the shapefileLoader is that if you have an attribute in the shapefile and corresponding get/set methods in your agent, it will automatically create agents with the same values as the shapefile. For example, the people shapefile has ``name'' and ``age'' fields and our Person agent has get and set methods for ``name'' and ``age'' variables, so each Person is created with the correct name and age. Amazing!

The shapefile loader will have loaded every Person from the shapefile into the PeopleContext and given them an appropriate spatial location in the PeopleGeography. We can test this by running through all the agents in the geography and printing their location. If you want to do this you'll need to add these lines after the people have been loaded in PeopleContext.java (not compulsory):

// Get all agents in the geography and print their location: for (Person p:peopleGeography.getAllObjects()) {Geometry geom = peopleGeography.getGeometry(p);Coordinate coord = geom.getCoordinate(); System.out.println(p.getName()+ " is at: ("+coord.x+ ","+coord.y+ ")");}
Note: make sure you import the com.vividsolutions.jts.geometry package for the Geometry object.

Step 8: Get the agents moving
Now that we have loaded our agents into the context and given them a spatial location in the projection we can get them to move around. For now we'll just have them move in a random direction. Firstly, we need to create and schedule a method which will be called every iteration to control the agents:

There are a few ways to schedule things in Simphony, have a look at the ``Working with the scheduler'' section in the Simphony reference docs if you want more info ( http://repast.sourceforge.net/docs/reference/SIM/index.html). For now we'll use annotations, these take advantage of a nice new feature of Java and are good if we know, at compile-time, when we would like a method to be executed.

Put the following code after the setAge method in Person:

// Tell repast to run this function at every iteration@ScheduledMethod(start = 1, interval = 1, priority = 0) public void step() { System.out.println(name+ " has called step method");}
The step() method will now be called at every iteration. If you open the project now and run it (the little green arrow at the top of the Simphony GUI) you should see text telling us that the step() method is being called for each Person. This isn't particularly useful though as the agents don't actually do anything.

To make the agents move around the geography add the following code (put it after the System.out line in the step() method):

// Find the context this person exists in.Context context = ContextUtils.getContext ( this);// Get the GIS projection associated with the contextGeography projection = (Geography)context.getProjection( "PeopleGeography");// Move the agents a small distance in a random directionprojection.moveByVector( this, 5,RandomHelper.nextDoubleFromTo(0, (2* Math.PI)));
It's worth noting that in Simphony all the geographical information about each agent is stored in the projection, not in the agent (the Person class has no variables). This allows our agents to be more generic, you don't have to specifically give them any information about their relationship with each other or the environment. We could, for example, control our agents from another class and then the Person class wouldn't even need know about Repast Simphony!

Step 9: Create a Display
We've pretty-much finished now. You can run Simphony and the agents will move around their geography. To actually see this happen, however, we need to create a display:

Run the model. Remember that all displays, charts etc are created separately from the underlying model source code, we do this using the runtime GUI.
On the list on the left look for the ``Displays'' icon underneath the ``PeopleContext'' folder. Right click on it and choose Add Display.
In the new window which pops up you can configure the display.
Leave the default name (``A Display'') for now, anything will do.
The type of projection should be ``GIS''. Repast has detected that the only projection we have created in the PeopleContext is a GIS geography, this could be Network or Grid if we had created these types of projections as well.
Tell repast that we would like the display to show our PeopleGeography by clicking on it and then clicking on the right arrow to move it accross into the box on the right. You should have something that looks like:
Click Next.
Now we can configure how we would like the agents to be displayed. We can also add other shapefiles to be displayed (like roads, houses etc) by clicking on the + button. For now, just change the fill colour of our People agents (click on Edit) then click next.
The final box lets us configure how often the display will be updated. Click finish.
Finally, save the new model configuration by clicking on the floppy disk at the top. I'm not sure how repast remembers the configuration but it does! Now if we re-compile and/or re-run the model Repast will have remembered this display.
Press the play button and we're off!

You should see some agents wandering around aimlessly, something like this:

A quick note to Mac users: at the time of writing (May 2008) there is a small bug with the displays. This has been documented and a temporary work around can be found on the archives of the repast-interest email list under the title ``GIS in Simphony'' (I'm a Mac user and the workaround works fine for me).

So far we've created a context, added some agents into the context and created a GIS projection so the agents can have a location in a geographical space. Now we could create a Network projection to create a social network for the agents or create another context to hold House objects and give the agents a home.

That's the end of the tutorial, hopefully you've got a better idea of how to use Repast Simphony without using the development GUI. Once you get used to it it is a really great tool. As a quick plug have a look at my blog ( http://crimesim.blogspot.com) to see how I'm using repast to develop a simulation of a city which should predict the movements of burglars. I also intend to put some other tutorials up there. The complete code for the tutorial is also available: PeopleContext.java Person.java

没有评论: