A module is made by writing the code and packing it into a jar file with a suitable manifest. This can be easily automated using a makefile.
Once a module is completed, the .jar file can be placed in an area accessible via a URL, and can then be incorporated into any other model in the world. Importantly, local models which rely on the module being available can be run by other people without them having to reinstall software.
New entities are written by extending a built in class, EntityImpl. This is a basic implementation of the Neosim Entity interface, and the method which needs to be written is called handleEvents. This is called by the Neosim kernel to advance the time of each entity, and to deliver its events.
class Counter extends EntityImpl {
public Time handleEvents(EventList el, Time endt) {
// Deal with incoming events, advance local time to endt
return endt;
}
}
The code inside handleEvents receives incoming events
in the ordered EventList. These events are of type
Event. An example implementation of this method is:
public Time handleEvents(EventList el, Time endt) {
boolean passed = false;
while (el.hasMoreElements() && !passed) {
Event e = el.top();
if (e.getTime().t <= endt.t) {
e = el.pop();
if (e.getConnection().getDstPortID().id == 0) {
// Port 0 is used for internal system events
defaultEventHandler( e );
} else {
Time outTime = e.getTime();
EntityID src = e.getConnection().getSrcEntityID();
System.out.println("Counter: received spike event");
}
} else {
passed = true;
}
}
return endt;
}
cd examples/entityjar make
public class CounterClass extends EntityClassImpl {
PortID in;
public CounterClass() {
super("CounterClass");
in = addInPort(SpikeEvent.inst.getEventClass(), "in");
}
public Entity makeEntity(Population p, int i) {
return new Counter(this, p, i);
}
}
This can then be made into a module using the JAR tool provided
with the Java development kit:
javac CounterClass.java
jar cvf CounterClass.jar manifest *.class
... where the manifest file looks like:
Name: CounterClass.class
Java-Bean: True
and the result is a file:
CounterClass.jar
which can be made available on the web and included into anyone's
simulation model.
<neosim>
<header>
<author>Fred Howell</author>
<documentation>Test the counter module.</documentation>
</header>
<!-- Define the entities and networks available-->
<prototypes>
<define-entity name="counter" modulename="libCounter"/>
<define-entity name="spike" modulename="libSpike"/>
<define-network name ="simple">
<population name="spikepop" entityname="spike" num="1" />
<population name="counterpop" entityname="counter" num="1" />
<projection name="prj1" srcPop="spikepop" dstPop="counterpop" type="standard" >
<connection src="0" scrPort="out" dst="0" dstPort="in" delay="1"/>
</projection>
</define-network>
</prototypes>
<!-- Instantiate a model-->
<model>
<network name ="simple"/>
</model>
<!-- Control the experiment - specify locations of modules, run time -->
<experiment>
<module name="libSpike" location="http://www.neosim/org/jars/spikegen.jar" version="1" />
<module name="libCounter" location="http://www.neosim.org/jars/CounterClass.jar" version="1" />
<control>
<time value="10.0"/>
</control>
</experiment>
</neosim>
This can then be run using the XML reader .
/** A basic "Hello World" script reader for neosim, * to demonstrate how to package Script Readers in * to JAR files */ public class HelloScript extends BasicApp { public HelloScript() { super(); } /** Bootstrap - runs in main thread */ public void bootstrap(String args[]) { super.bootstrap(args); System.out.println("=== NEOSIM Hello Script " ); PopulationNode root = getPopulationTree(); /** Here we can create cells and run a simulation */ System.out.println("Hello world" ); } }The method which is overridden is bootstrap which accepts command line arguments, and has access to the script reader commands for controlling a simulation.
An example, which runs the simulation for 100.0s is:-
public class HelloControl extends ControlModuleImpl {
Time t;
String msg;
public void init(Hashtable params) {
t = new Time(100.0);
msg = params.get("message");
// could set parameters from the name/value params hashtable
}
public void run(ScriptReader sr) {
System.out.println("Hello from control module message="+msg);
sr.runSim( t );
// issue script reader commands, queries, etc etc
}
}
An example is in examples/controljar. It can be included
in an XML file using:
<control>
<module name="sayhello" location="file:./hellocontrol.jar" message="hello bob"/>
</control>
A user coded projection scheme
User specific projection schemes can be included - see the
example in examples/projectionjar and the
overview of user projections.
In general, a projection is specified as a source method and a
dest method. A new scheme, which connects each entity
in the source population to all the entities within a given distance
could be written:
class ConnectToSphere extends SourceMethodImpl {
public void sendRequests( Entity srce, Population dPop, DestMethod dm ) {
// get list of members of dPop within radius
// for each, call sendRequest() to send a connection request
}
}
class Proj3DSphereImpl extends GeneralProjectionImpl {
public Proj3DSphereImpl( Population srcPop, PortID outPort,
Population destPop, PortID inPort,
Time delay, double radius ) {
super( srcPop, destPop,
new ConnectToSphere(outPort,radius),
new DestMethodImpl(inPort,delay));
}
}
In this example, the source method sends requests to all entities
within a certain distance, and the default destination method
fulfills all requests. Another way to implement this would be
for the source method to send requests to all entities, and have the
destination method compute the distance and say yay or nay. This
would be a much slower implementation.