|
From: Tatara, E. R. <ta...@an...> - 2009-07-08 23:33:37
|
John,
As Mike mentioned, we are planning to make this more flexible in the
next release. However, I'll provide some insight on how to get around
using the score file.
The score file provides the following functionality to the runtime:
1. Provides a list of model parameters to the simulation/GUI
2. Provides a list of agents, contexts, and projections to the GUI
3. Parses agent annotations for scheduling and watching.
4. A few other misc things.
If information is not specified in the score file, it's possible to
implement all score functionality programmatically, although it can get
a bit messy if you want to do away with the score completely. However,
I have designed several simulations without specifying any agents,
contexts, or projections in the model.score file. In this case, it only
funtions to specify the context builder class, although again, that
could be done programmatically if you like.
To address the issue of watch and schedule annotations, a bit of custom
code is required. Note that, although agents not defined in the
model.score won't be available to the runtime GUI menus, any display
elements that reference agent classes *will* work fine. Similarly,
projections not defined in the model score will work just fine if you
create them via the ContextBuilder, but will not show up int runtime
menus.
The Repast ScenarioLoader class is responsible for parsing the watch and
scheduled method annotation info from the agent classes specified in the
score file. If you eliminate the contexts and agents from the score
file, you will need to replicate what the ScenarioLoader is doing. This
can be accomplished by creating a custom ModelInitializer class. To do
this, you will need to provide the class and field names of agents that
are to be watched, and the classpath on which all agents with watch and
scheduled method annotations can be found. Normally, you would probably
know this at runtime, so it's not that complicated. The
ModelInitializer executes its initialize method only once when the
runtime is started, unlike the ContextBuilder which runs each time the
simulation is started/restarted.
I have copied an example below. The example files are also located on
the sourceforge repository under
/repast.simphony.demos/src/repast.simphony.demo/watch and /watch.rs.
Please let me know if you have any additional questions.
eric
--- BEGIN MyContextBuilder.java ---
package repast.simphony.demo.watch;
import repast.simphony.context.Context;
import repast.simphony.dataLoader.ContextBuilder;
/**
* Test model for setting up watches and scheduled method via the
ModelInitializer.
* @author Eric tatara
*
*/
public class MyContextBuilder implements ContextBuilder<Agent> {
public Context<Agent> build(Context<Agent> context) {
// Create some agents.
Agent agent1 = new Agent("Agent 1");
Agent agent2 = new Agent("Agent 2");
context.add(agent1);
context.add(agent2);
return context;
}
}
--- END MyContextBuilder.java ---
--- BEGIN MyInitializer.java ---
package repast.simphony.demo.watch;
import java.util.ArrayList;
import java.util.List;
import repast.simphony.engine.controller.ControllerActionConstants;
import
repast.simphony.engine.controller.ScheduledMethodControllerAction;
import repast.simphony.engine.controller.WatcherControllerAction;
import repast.simphony.engine.environment.ControllerAction;
import repast.simphony.engine.environment.ControllerRegistry;
import repast.simphony.engine.environment.RunEnvironmentBuilder;
import repast.simphony.engine.watcher.WatchAnnotationReader;
import repast.simphony.engine.watcher.WatcheeInstrumentor;
import repast.simphony.engine.watcher.WatcherTrigger;
import repast.simphony.scenario.ModelInitializer;
import repast.simphony.scenario.Scenario;
/**
* An initializer that sets up watch and scheduled method annotation
reading.
* This may be used when agent classes are not defined in the
model.score.
*
* @author Eric Tatara
*
*/
public class MyInitializer implements ModelInitializer {
public void initialize(Scenario scen, RunEnvironmentBuilder builder) {
System.out.print("Initializing...");
// Initialize the watch mechanism.
// *** NOTE *** - you cannot reference watched classes at any point
prior
// to initializing watches since the classes can't be loaded at
this point.
WatcheeInstrumentor instrumentor = new WatcheeInstrumentor();
WatcherTrigger.initInstance(instrumentor);
// Call addFieldToWatch for each class/field to be watched
instrumentor.addFieldToWatch("repast.simphony.demo.watch.Agent",
"age");
// Instrument the agent classes in the provided class path.
String agentClassPath = "../repast.simphony.demos/bin";
instrumentor.instrument(agentClassPath);
ControllerRegistry registry = scen.getControllerRegistry();
ControllerAction scheduleRoot =
registry.findAction(scen.getContext().getLabel(),
ControllerActionConstants.SCHEDULE_ROOT);
// Create a list of classes that the watch and scheduled method
annotation
// readers will parse.
List<Class<?>> myClasses = new ArrayList<Class<?>>();
myClasses.add(Agent.class);
WatchAnnotationReader watcherAnnotationReader = new
WatchAnnotationReader();
watcherAnnotationReader.processClasses(myClasses);
ControllerAction watcherAction = new
WatcherControllerAction(watcherAnnotationReader);
registry.addAction(scen.getContext().getLabel(), scheduleRoot,
watcherAction);
// setup scheduledMethod annotation reader / executor for master
context
ScheduledMethodControllerAction action = new
ScheduledMethodControllerAction(myClasses);
registry.addAction(scen.getContext().getLabel(), scheduleRoot,
action);
System.out.print("done.\n");
}
}
--- END MyInitializer.java ---
--- BEGIN Agent.java ---
package repast.simphony.demo.watch;
import repast.simphony.context.Context;
import repast.simphony.engine.schedule.ScheduledMethod;
import repast.simphony.engine.watcher.Watch;
import repast.simphony.engine.watcher.WatchData;
import repast.simphony.engine.watcher.WatcherTriggerSchedule;
import repast.simphony.util.ContextUtils;
/**
* A simple agent class that watches or is watched.
* @author tatara
*
*/
public class Agent {
private int age;
private String name;
public Agent(String name){
this.name = name;
}
/**
* Pick one agent and set its age.
*/
@ScheduledMethod(start=1,pick=1)
public void setMyAge(){
setAge(28);
}
/**
* Method that indicates if this agent has watched another agent.
*
* @param data WatchData
* @param agent the watched agent.
*/
@Watch(id="MY Watch",
watcheeClassName="repast.simphony.demo.watch.Agent",
watcheeFieldNames="age",
triggerCondition="$watcher != $watchee",
whenToTrigger = WatcherTriggerSchedule.LATER)
public void testWatch(WatchData data, Agent agent){
Context context = ContextUtils.getContext(this);
System.out.println(this + " has watched " + agent + " in " +
context);
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
@Override
public String toString(){
return name;
}
}
--- END Agent.java ---
--- BEGIN model.score ---
<?xml version="1.0" encoding="UTF-8"?>
<score:SContext xmlns:score="http://scoreabm.org/score"
label="WatchTest" ID="watchTest" pluralLabel="WatchTests">
<implementation package="repast.simphony.demo.watch"
className="MyContextBuilder" basePath="../repast.simphony.demos"/>
</score:SContext>
--- END model.score ---
--- BEGIN scenario.xml ---
<?xml version="1.0" encoding="UTF-8" ?>
<Scenario>
<repast.simphony.dataLoader.engine.ClassNameDataLoaderAction
context="WatchTest"
file="repast.simphony.dataLoader.engine.ClassNameDataLoaderAction_0.xml"
/>
<model.initializer class="repast.simphony.demo.watch.MyInitializer" />
</Scenario>
--- END scenario.xml ---
--- BEGIN
repast.simphony.dataLoader.engine.ClassNameDataLoaderAction_0.xml ---
<string>repast.simphony.demo.watch.MyContextBuilder</string>
--- END
repast.simphony.dataLoader.engine.ClassNameDataLoaderAction_0.xml ---
Eric Tatara, Ph.D.
Assistant Software Engineer
Center for Complex Adaptive Agent Systems Simulation
Decision and Information Sciences Division
Argonne National Laboratory
-----Original Message-----
From: John Tranier [mailto:tr...@cs...]
Sent: Tuesday, July 07, 2009 12:01 PM
To: rep...@li...
Subject: [Repast-interest] Interfaces & Inheritance within Symphony
Hi,
In order to improve the flexibility of my models, I like to make use of
interfaces to abstract from different possible implementations.
Thus, I define agents & contexts with interfaces + implementing classes.
The problem is that this approach doesn't fit very well with Repast
Symphony since the model score and the scenario entries require to
specify the concrete classes used.
If I want to change the implementation of a context or an agent, I've
almost nothing to do in my code, but then I've to update all the repast
files that was referencing the previous implementation ...
Moreover I've noticed that the scheduling annotation are processed only
if they are defined in a class which is used in model.score file.
If there is a schedule annotation in a super class, this one is not
taken into account.
It would be nice to be able to reference interfaces / super classes in
the score file and in the scenario files, and so to be able to load
easily different implementations at run-time.
Do you think this is feasible?
To achieve this at the moment, I suppose I've to build the scenario with
java programming (but loosing the nice graphical interface ...).
Is there any documentation or code examples you can recommend me to have
a look at how to build a scenario in java ?
Thanks,
John
------------------------------------------------------------------------
------
Enter the BlackBerry Developer Challenge This is your chance to win up
to $100,000 in prizes! For a limited time, vendors submitting new
applications to BlackBerry App World(TM) will have the opportunity to
enter the BlackBerry Developer Challenge. See full prize details at:
http://p.sf.net/sfu/blackberry
_______________________________________________
Repast-interest mailing list
Rep...@li...
https://lists.sourceforge.net/lists/listinfo/repast-interest
|