Pathfinder scripts can be edited within the Pathfinder user interface and are stored with other model data inside the save file (PTH).
Once a script has been added to a model, it will automatically be used any time anyone runs that model.
Since this is an experimental feature, a flag must be set to enable the script editor.
This flag can be set by either running Pathfinder from a console window (recommended when creating/debugging scripts) or by editing the Windows Start Menu shortcuts.
To enable the script editor, it is necessary to add the following VM argument when running Pathfinder:
-Dex_enable_scripting
The above form of the argument can be used as-in when part of a batch file (e.g. monte carlo runs), but requires a modification when running Pathfinder as part of a shortcut or from the command line:
-J-Dex_enable_scripting
The -J
instructs the wrapper executable to unpack the argument as a VM parameter.
For example:
pathfinder.exe -J-Dex_enable_scripting
Once this flag has been enabled, an option will be added to the Model :
menu
If the script editor is not enabled, the presence of custom scripts will trigger a warning when loading the PTH file.
When working with scripts, please keep in mind the following details:
- Scripts run when the simulation is initialized, before any movement.
To run code after initialization, you must add callback functions.
- Scripting is not compatible with simulation restart.
- All scripts share the same global scope, creating a situation that shares the same advantages and disadvantages with JavaScript development for web browsers.
Namely, you can conveniently create library classes that are shared across multiple script blocks as defined in Pathfinder, but you can just as easily overwrite important variables by accident.
JavaScript namespacing is the topic to learn more about if you are having trouble with the latter case.
- When finding an element of the model by name, if you have the setting , General tab, Results section, Include Group Names in Output option checked, then you must use the full name including the group name(s) for the identification string.
For example, a door named
Center Door
, in the Floor 0.0 m
group, would be referred to as the string Floor 0.0 m->Center Door
, where groups and objects are separated by ->
characters.
The Pathfinder API provides low-level access to the internals of a Pathfinder simulation.
It consists of four modules:
Name | Object | Description |
---|
Simulation Control | api.simctl.v1 | Simulation management and callbacks |
Geometry | api.geometry.v1 | Access simulation objects like doors and rooms |
Agents | api.agents.v1 | Access agent/occupant data during the simulation |
Input/Outout | api.io.v1 | Access the out/err/in streams for I/O. |
The v1 on the end of the object name gives access to a specific version of that API and will allow us to keep legacy scripts operational if we introduce API-breaking changes.
The following convenience variables will be used in all examples in this documentation.
var sim = api.simctl.v1;
var geom = api.geometry.v1;
var agents = api.agents.v1;
var io = api.io.v1;
The Core API describes operations that are explicitly supported by Pathfinder’s API.
The Simulation Control API makes it possible to register callbacks to execute code during the simulation.
Register a callback function.
It will be invoked once on each simulation timestep.
The function accepts one parameter:
Parameter | Type | Description |
---|
t | double | Current simulation time |
sim.onUpdate( function (t) {
// do this every time step
});
Register a callback function.
It will be invoked once at the end of the simulation.
sim.onExit( function () {
// do this once after the simulation has ended
// recommended for closing PrintStream
});
The Geometry API provides methods to access geometry objects like doors, rooms, and measurement regions.
In addition, methods are provided to open/close doors and change the direction that agents can move through doors.
The geometry methods use the objects of type ANode
which is a class that includes both doors and rooms and type Region
which represents a measurement region.
var geom = api.geometry.v1;
Find a single door or room by name.
var door = geom.find("Door to Atrium");
Find all named doors or rooms that match a regular expression.
Additional information on regular expressions in Java see java regex.
var doors = geom.findAll("Door to Atrium");
Set the allowed direction of travel through a door.
//Set the door direction to allow travel in both directions.
geom.setDoorDir( door, "" );
//Set the door direction closest to the +X axis.
geom.setDoorDir( door, "+x" );
//Set the door direction closest to the vector (1, -.2)
geom.setDoorDir( door, "1 -.2" );
The Agents API provides methods to access agents during the simulation.
var agents = api.agents.v1;
Find a single agent by name.
var agent = agents.find("00028");
Find all agents whose center point is within a measurement region.
var regionA = geom.find("Region-A");
var agentsInRegionA = agents.findAll( regionA );
Find all named agents that match a regular expression.
Additional information on regular expressions in Java see java regex.
var agentsNamedStaff = agents.findAll( "staff-??" );
Returns a list of all agents that have ever been in the simulation, including those that have exited.
var agents = agents.getAllAgentsEver();
api.io.v1
The Input/Output API provides methods to write to and read from the simulation input and output streams.
This method can be used to open a PrintStream to a file in the current simulation’s working directory.
Streams should be closed when the simulation exits to prevent file locking issues.
var fileout = openPrintStream("myfile.tsv");
Simulation standard output stream.
Text will appear alongside other console output.
io.out.println("message");
Simulation standard error stream.
Text will appear alongside other console output and may be colored red depending on the editor.
io.err.println("message");
Simulation standard input stream.
Possibly a way to collect user input from the console or piping together applications…?
The Core API describes operations that are explicitly supported by Pathfinder’s API, but it’s possible to access a much wider range of objects.
An example of a common situation is when dealing with the findAll()
methods that return an instance of java.util.List
.
Another example is the OccAgent
object that is returned by the find()
method.
In addition, you can create arbitrary instances of objects using the API.
In general:
- If you are trying to deal with objects that you receive as a result from a Core API function, there should be some guidance in that section of the Core API documentation.
- If you are interested in creating an instance of a class from scratch, the general pattern is to use the
Java.type()
method to look up a type definition and then use that type to create new instances.
Create a file using the Java platform library.
var PSType = Java.type("java.io.PrintStream");
var fileStream = new PSType("myfile.txt");
fileStream.println("Hello");
filestream.close();
Basically, you can write any program you want by using the extended API because it encompasses both JavaScript and the Java platform.
The details of how really dive into these is beyond the scope of this document, but if you have specific questions or requests for code examples, please send us an email.