My previous two posts (one and two) described a simple NetLogo example integrated with a NetLogo Java extension, where the Java code implemented a diffusion process on the “patches,” as shown above. As presented, the example used two NetLogo loops to copy data between the DiffusionGrid
object and the patches:
ask patches [
set value (random-float 9.9)
diffusion:set-grid-cell grid pxcor pycor value
set-patch-color
]
...
ask patches [
set value (diffusion:get-grid-cell grid pxcor pycor)
set-patch-color
]
It is also possible to carry out these loops in Java, but doing so requires delving deeper into poorly documented parts of the extensions API. We introduce two new commands which interact directly with the patches from Java. However, these require knowing that the value
variable of a patch is number 5 in the variable list. This fact may be subject to change (if it is not listed first, or if other predefined patch variables are defined).
ask patches [
set value (random-float 9.9)
set-patch-color
]
diffusion:copy-patches-to-grid grid patches
...
diffusion:copy-grid-to-patches grid patches
ask patches [
set-patch-color
]
This version runs in about 3.5 milliseconds per iteration step in “fast” mode (compared to 5.8 milliseconds per iteration step for the previous version, and 41.8 milliseconds per iteration step for a pure NetLogo version). It exploits some more advanced features of the NetLogo Java API:
The Java code behind our modified example consists of two classes implementing copy-patches-to-grid
and copy-grid-to-patches
. Direct patch interaction is shown in green. In red is a Java iteration over the supplied “agentset” of patches:
class SetGridFromPatches extends DefaultCommand {
public Syntax getSyntax() {
return Syntax.commandSyntax(new int[] {Syntax.WildcardType(), Syntax.AgentsetType()});
}
public void perform(Argument args[], Context context) throws ExtensionException, LogoException {
Object g = args[0].get();
if (g instanceof DiffusionGrid) {
DiffusionGrid dg = (DiffusionGrid) g;
AgentSet aset = args[1].getAgentSet();
for (Agent a : aset.agents()) {
if (a instanceof Patch) {
Patch p = (Patch) a;
int x = p.pxcor();
int y = p.pycor();
Object v = p.getVariable(5);
if (v instanceof Double) dg.setValue (x, y, ((Double) v).doubleValue ());
else throw new ExtensionException("Did not find numeric patch variable in slot " + 5);
} else throw new ExtensionException("Non-patch agents passed into copy-patches-to-grid") ;
}
} else throw new ExtensionException(g + " is not a DiffusionGrid") ;
}
}
class SetPatchesFromGrid extends DefaultCommand {
public Syntax getSyntax() {
return Syntax.commandSyntax(new int[] {Syntax.WildcardType(), Syntax.AgentsetType()});
}
public void perform(Argument args[], Context context) throws ExtensionException, LogoException {
Object g = args[0].get();
if (g instanceof DiffusionGrid) {
DiffusionGrid dg = (DiffusionGrid) g;
AgentSet aset = args[1].getAgentSet();
for (Agent a : aset.agents()) {
if (a instanceof Patch) {
Patch p = (Patch) a;
int x = p.pxcor();
int y = p.pycor();
double v = dg.getValue (x, y);
try {
p.setVariable(5, new Double (v));
} catch (AgentException e) {
throw new ExtensionException("Could not set variable in slot " + 5 + " because of " + e);
}
} else throw new ExtensionException("Non-patch agents passed into copy-grid-to-patches") ;
}
} else throw new ExtensionException(g + " is not a DiffusionGrid") ;
}
}
Even closer integration than this is possible; but with greater chances of being impacted by changes to the NetLogo code, or changes in how NetLogo works. The level of integration described here is probably all that is needed, in most cases. For those interested, the complete Java file is here (with all files also at Modeling Commons).
The source code for the standard GIS extension shows how more closely integrated Java can be written.
Pingback: Integrating NetLogo and Java: #2 | Scientific Gems
Pingback: Integrating NetLogo and Java: #1 | Scientific Gems
Pingback: NetLogo post summary | Scientific Gems