JaamSim Programming Manual - Rev 0.51
JaamSim Programming Manual - Rev 0.51
Programming Manual
Revision 0.51
February 29, 2016
Table of Contents
1 Introduction ................................................................................................................. 1
2 Getting Started ............................................................................................................ 2
2.1 System Requirements ................................................................................................... 2
2.2 JaamSim Source Code.................................................................................................. 2
2.3 Java Runtime Environment and Java Development Kit ................................................. 2
2.4 Eclipse ........................................................................................................................... 3
3 Simulation Objects and Methods............................................................................... 8
3.1 Overview ....................................................................................................................... 8
3.2 Simulation Time ............................................................................................................. 9
3.3 Starting a New Process ............................................................................................... 10
3.4 Scheduled Waits ......................................................................................................... 11
3.5 Conditional Waits ........................................................................................................ 12
3.6 Schedule Last.............................................................................................................. 12
3.7 Interrupting or Terminating a Future Event .................................................................. 13
3.8 Discrete-Event Logic ................................................................................................... 13
4 3D Graphics ............................................................................................................... 15
5 Model Inputs .............................................................................................................. 16
5.1 Input Objects ............................................................................................................... 16
5.2 Program Structure for Inputs ....................................................................................... 18
5.3 Unit Conversion ........................................................................................................... 19
5.4 Using an Input ............................................................................................................. 21
5.5 Input Checking and Model Startup .............................................................................. 21
6 Model Outputs ........................................................................................................... 23
7 Graphical User Interface ........................................................................................... 25
7.1 Adding New Default Objects........................................................................................ 26
8 Program Structure .................................................................................................... 29
JaamSim represents the lessons learned from simulation projects we have performed around the
world for more than 35 years. Further background information on JaamSim can be found in the
JaamSim blog: www.jaamsim.com/blog.
JaamSim is free open source software, licensed under Apache 2.0. The latest version of the
software and manuals can be downloaded from the JaamSim website: www.jaamsim.com. The
source code is published on GitHub: www.github.com/jaamsim/jaamsim. Presentations and tutorials
for JaamSim can be found at: www.youtube.com/user/javasimulation.
This Programming Manual proves detailed instructions on how to create new palettes of high-level
objects that can be added on to JaamSim.
The user interface and basic objects provided with JaamSim are documented in a separate User
Manual document. These features are common to all simulation models created with this software.
The instructions in this section assume that you are using a PC with the Windows operating system.
Users of other systems, such Linux and OSX, can modify these instruction appropriately.
JaamSim will run on most modern computers that support OpenGL graphics version 2.1 or later. This
includes laptop computers with Intel Core i5 and i7 series processors 1 with integrated graphics.
NVIDIA graphics cards are preferred for best performance. AMD graphics cards are also supported.
The following system specifications are recommended for optimal performance with complex models:
The Java Runtime Environment (JRE) is needed to execute your Java program. The JRE is
sometimes referred to as the Java Virtual Machine. Although many computers with a Windows
operating system come with the JRE already installed, it is best to uninstall this version and re-install
the latest version.
1. The Java Development Kit (JDK) is needed to program in Java. The JRE and JDK are installed
at the same time.
2. Download the JDK from www.oracle.com/technetwork/java/javase/downloads/index.html. Select
the latest version of Java and download either the 32-bit or 64-bit installation file. For 64-bit
windows users, the 64 bit version is the best choice.
Install the JDK by launching the downloaded installation file. Accept the option to install the JRE at
the same time.
1
Second generation or later Core i5 and i7 processors with integrated graphics are suitable for use with
JaamSim. The integrated graphics capabilities for first generation Core i5 and i7 and earlier versions are not
sufficient for JaamSim. A separate graphics card must be used with these processors.
JaamSim Programming Manual 2 February 29, 2016
2.4 Eclipse
Eclipse is the recommended software development environment for Java. Its installation can be a bit
daunting for the non-professional programmer, but it is well worth the effort in increased productivity
once you start programming. We have described the installation and configuration process in more
detail than is usual to make the installation as straightforward as possible.
2.4.1 Installation
1. Download Eclipse from www.eclipse.org/downloads/. The recommended version is “Eclipse
Classic” (version 4.2.1 at the time of writing). For 64-bit windows users, the 64 bit version is the
best choice.
2. Install Eclipse by unzipping the contents of the download to your C: drive.
3. Append the path for the JDK bin folder (e.g. C:\Program Files\Java\jdk1.7.0_45\bin) to the PATH
environment variable. This must be the only entry to a Java bin folder. The following steps will
take you to the environment variables in Windows 7:
o click on the Start button
o right click on the entry labelled “Computer” and select “Properties”
o select “Advanced System Settings”
o select the “Advanced” tab and click on the “Environment Variables” button
o select “Path” and click the Edit button
o append a semi-colon (“;”) followed by the path to the JDK bin folder
4. Confirm that Eclipse starts successfully by double clicking on eclipse.exe (in the C:\eclipse
folder). An error message will appear if Eclipse cannot find your JDK files. If this happens check
that the PATH was set up correctly in Step 3 above and that there is only one version each of the
JDK and JRE installed on your computer.
5. On startup, Eclipse will prompt you for a workspace. Select the default. After launching
successfully, Eclipse will appear similar to Figure 2-1.
6. Create a shortcut icon for eclipse.exe and place it on your desktop.
A number of additional procedures are required to set up Eclipse to work with the source code for
JaamSim and the JAR files for supporting software.
The next step is to set up Eclipse to work with the source code for JaamSim and the JAR files for
supporting software.
Test the installation by running JaamSim from Eclipse. Click on the green run button to launch the
software. After a short delay to load the code, JaamSim should launch normally.
3.1 Overview
The basic object classes used to implement discrete-event logic within Java are given in Table 3-1.
Note that we have separated the two objects Entity and Process. When an Entity is playing an active
role in the simulation, it will have one or more Processes underway. When it is playing an inactive
role or is temporarily dormant, it will have no Process underway.
Unlike most other simulation software, we have made the distinction between starting a new method,
which is done in series with the original method, and starting a new process, which is done in parallel
with the original method. Other simulation languages return control to the original method if the
called method is halted by a wait – equivalent to starting a new process each time a method is called.
A new process can be created and started using the Process methods in Table 3-2.
JaamSim allows both the process- and event-orientation to be used freely in the construction of a
simulation model:
An event-oriented model is more efficient than a process-oriented model because it minimises the
number of active processes and avoids context switching. However, it is easier to follow complex
model logic in a process-oriented model and in many such models, it is the model’s methods
themselves that limit execution speed rather than the overhead of managing threads. The best
approach is to use an event-oriented style (the scheduleProcess method) whenever possible and
save the process-oriented style (the simWait method) for the more complex parts of the model.
Often, it is useful to prototype new objects using simWait methods and then, after it works correctly,
optimize selected portions by converting the code to use scheduleProcess.
The current simulated time in seconds can be obtained within the model by using the Process
method getSimTime() which returns a double value, e.g.
double t = Process.getSimTime();
Internally, simulation time is maintained as an integer value in order to avoid the accumulation of
round-off error during a simulation run. This internal long-valued time is related to the double-valued
JaamSim Programming Manual 9 February 29, 2016
simulation time by GraphicSimulation input keyword SimulationTimeScale (see the JaamSim User
Manual). The default value for SimulationTimeScale is 1000 so that one unit of internal time is equal
to one millisecond.
JaamSim allows a method to be executed either in series or in parallel in simulated time to the calling
method. In standard Java, a called method is executed in series with the method that called it. For
example, consider the following code for methods aaa() and bbb().
int n;
For this case, the simWait method in bbb() causes time to advance by one hour before control is
passed back to method aaa(). If method aaa() is executed at time = 0, then the property n takes on
the following sequence of values:
• time = 0: n = 1
• time = 0: n = 2
• time = 1: n = 3
• time = 1: n = 4
When a method is called using a startProcess command, it is executed in parallel to the method that
called it. The modified code for methods aaa() and bbb() illustrates this behaviour.
int n;
In this case, a new process is started for the purpose of executing method bbb(), and method aaa()
continues its execution at time 0 while method bbb() is waiting for one hour. Now, the sequence of
values for property n is:
In the above examples, the called method bbb() had no arguments. For methods that do take
arguments, they can be appended after the method name in the startProcess call. For example, the
code
Process.startProcess(“bbb”, arg1, arg2, … , argN);
In this example, the arguments arg1 … argN can be any type of object required by method bbb.
Simulated time can be advanced in a simulation model using a number of different statements. The
simplest type of delay is one whose duration is known in advance. The Process method for a
specified duration delay is:
Process.simWait(duration);
Where duration is a double value denoting the duration of the delay in simulated time. Execution of
the method is resumed at the end of this time.
JaamSim delays execution of the method at this point by suspending the current process and
creating an event which stores the simulated time at which the process is to be resumed. The
EventManager maintains a stack of future events sorted in order of scheduled execution time.
Events scheduled themselves at the same time will be evaluated in stack order (First In - Last Out),
that is, the last event scheduled for a given time will be the first one to be executed.
It is also possible to influence the execution sequence of events scheduled at the same time by
specifying an event priority using the statement:
Process.simWait(duration, priority);
Where duration is the double-valued wait duration and priority is an integer priority. The default
priority of an event is 5. Events scheduled at the same time are executed in order of increasing
A conditional wait is of unknown duration, but instead is determined by logical condition that must be
satisfied in order to end the wait. The syntax for a conditional wait is:
while (booleanExpression) {
Process.waitUntil();
}
Process.waitUntilEnded();
Where booleanExpression can be any expression that evaluates to a boolean value. The boolean
expression must be false to end the wait.
The conditional wait expressions are evaluated at the end of each simulation time. If multiple events
have been scheduled at the same time, all of these events will be executed before the conditional
expressions are checked, and possibly executed.
Conditional waits are evaluated in first-in-first-out order based upon the order they were added to the
conditional queue. Once a condition is satisfied, the program continues execution from that spot until
completion, or another wait is reached in the code. EventManager then continues checking the rest
of the queue and does not re-evaluate the already checked conditionals until the next time advance.
The statements for a conditional wait work in the following manner. The method waitUntil() suspends
the active process and places it in the conditional queue maintained by eventManager. At each time
at which any events have been scheduled, after executing the scheduled events, EventManager
restarts each process one-by-one. On restarting, the process hits the right brace of the while
expression and re-checks the booleanExpression. If the expression is true, the thread is re-
suspended. If it is false, the thread passes out of the while statement and executes waitUnitEnded(),
which removes the process from the conditional queue.
Note that booleanExpression is checked before the thread is suspended. If it is false on first
evaluation, then the thread is never halted at all. It is also possible to rewrite the statements as
follows so that the condition is not checked until the thread has been suspended and all other events
at that time have been executed and all other conditionals have been checked:
do {
Process.waitUntil();
} while (booleanExpression)
Process.waitUntilEnded();
Similarly, if a thread is to be delayed so that it is the last to be executed at a given time, the
booleanExpression can be omitted altogether:
Process.waitUntil();
Process.waitUntilEnded();
A scheduleLast wait does not increase simulation time at all. It waits for all other events to be
evaluated before restarting. Such events are scheduled with a priority of 11 or 12. Regular events
should only be scheduled with a priority of 1-10 so the regular scheduler will place them below the
It is sometimes necessary in a simulation model to interrupt or terminate a future event that has
already been scheduled using Process.simWait(). A future event that is interrupted is executed
immediately, while one that is terminated is simply discarded.
To accomplish either of these actions, the programmer must keep a reference to the process
corresponding to the event to be terminated. For example, the following code saves a reference to
the current process just before it is suspended:
processholder = this.getProcess();
Process.simWait(duration);
processholder = null;
Where processholder is the variable maintaining the reference to the process to be terminated. Note
that this reference must be establish before the thread has be suspended by the simWait().
Process.interruptProcess(processholder);
processholder = null;
Process.terminateProcess(processholder);
processholder = null;
In all of the above code segments, processholder is set to null immediately after the reference is no
longer needed. This is done to prevent a dangling reference to the process which would prevent
proper cleanup once the process has finished execution. It is very important that the programmer not
leave dangling references to processes. For efficiency, processes managed by EventManager are
pooled for re-use later in the simulation. This leaves the possibility of a process being terminated
even though it has completed execution in one place and has been re-started somewhere else in the
program. If this were to occur, it would be a very difficult to debug error.
JaamSim uses the same basic discrete-event logic as other simulation packages. Two master lists
are maintained by the software:
• Future Events. A list of future events sorted into order of increasing event time. Events with
the same event time are sorted in order of increasing priority variable (priority 1 events are
executed before priority 2, and so on). If both the event time and priority are the same, events
are sorted in reverse order in which they were added. That is the last event added is the one
that is executed first.
• Conditional Events. A list of conditional events sorted in the order in which they were added.
That is, the first conditional event that was added is the one that is tested first.
More to come
2
Many of the standard engineering applications use the old-style fixed graphics pipeline instead of shaders,
which severely limits their performance on games type graphics cards. Workstation cards and their drivers are
specially designed to compensate for this shortcoming.
JaamSim provides a powerful system for handling the inputs to a simulation model. The system
allows simple models to be constructed quickly and can be scaled to handle arbitrarily complex
models.
• Keyword definitions are shown interactively as tool tips in the Input Editor.
• Drop down menus in the Input Editor for most inputs.
• Unit conversions are done automatically when the input is read
• Input files for configuring a model are human readable and can be edited directly by the user
• Input files can be created and edited interactively by drag and drop and the Input Editor
without losing any comments and special formatting added directly by the user.
New objects programmed by a user can take advantage of all these features with very little effort:
• New keywords are automatically added to the Input Editor and provided with drop-down
menus as appropriate.
• Documentation is entered in the code as an annotation next to each keyword definition. The
keyword definition appears automatically in the user interface as a tool tip when the user
mouses over the keyword in the Input Editor.
Input objects were created to standardize the various types of inputs required by our simulation
models.
Input objects are defined for an object class and then added to each instance. The following example
shows the standard structure we used:
// CONSTRUCTOR
public NewObject() {
}
}
In this example, the keyword “Key1” is added to the object “NewObject”. This keyword expects an
input of a Queue object (a sub-class of Entity). The input object is defined by the statement:
This defines a property named “key1” that is an EntityInput of type Queue. The definition and
example that will appear in the Input Editor tooltip is given by the @Keyword notation.
Next, an instance of EntityInput is created and assigned to the key1 property by the statement:
The constructor for the EntityInput specified the type of Entity expected (Queue.class), the name
assigned to the keyword (“Key1”), the input category for the keyword (“Cat”), and the default value
(null).
For other types of InputObject, it is not necessary to specify an object class in the constructor since
the InputObject is already specialized to one object type. The general for the constructor is:
where the strings “Key1” and “Cat” are the keyword name and category, respectively, and def is the
default value for the input.
In the case of IntegerInput and ValueInput, it is possible to specify the valid range for the input using
the setValidRange method:
where min and max are the minimum and maximum values for the numerical input. If the
setValidRange method is not use, min and max default to negative and positive infinity, respectfully.
For numerical inputs, the type of unit (time, distance, etc.) must be specified using the setUnitType
method:
key1.setUnitType(ut.class );
where the ut is any valid unit type that is defined for JaamSim. Units are discussed in more detail in
the next section.
The present value of an input object is returned by the method getValue(). To avoid any trouble with
initialization, it is best to use the input object and the getValue() method directly in the code each time
the input is required. There is no need to assign a local variable or another property just to hold the
input value.
Numerical inputs must specify their unit type (time, distance, etc.) using the setUnitType method:
key1.setUnitType(ut.class);
where the ut is any valid unit type that is defined for JaamSim. For example, the code
would create an input keyword “Length” and identify it as expecting an input with the units of
distance. In this case, a valid input would be:
An input without any units would generate an input error message, e.g.
The following unit types have been defined at present. Additional unit types can be created by
adding new sub-classes of Unit.
Note that a dimensionless numerical input should be assigned the unit type DimensionlessUnit.class.
The internal units given in the above table are the ones used for internal calculations. Wherever
possible, we have used SI units for JaamSim’s internal calculations.
The individual units within a unit type are defined by creating instances of the unit type. For example,
the units of metres and kilometres are defined by creating the instances “m” and “km” using the
following inputs:
Define DistanceUnit { m km }
m ConversionFactorToSI { 1 }
km ConversionFactorToSI { 1000 }
Many units are created in this way by the autoload.cfg file, which is loaded automatically on startup.
The autoload file is discussed in more detail in Section 7.1.
The value for an input can be obtained by using the Input method getValue(), which will return the
appropriate object type for the keyword. For example, if the property testKey is used to store the
Input object corresponding to the keyword TestKey, then the present value for this input can be
obtained by executing the following code:
double x = testKey.getValue();
For this example, TestKey was assumed to contain a double, but the same getValue() method can be
used to obtain the present value for any type of Input.
It is best to use the getValue() method every time an input is needed instead of storing a cached
value. This approach ensures that the current value for the input is always used and, in many cases,
allows an input to be changed in the middle of a simulation run without restarting.
Basic checking of a model input to ensure that its format is valid and that its value is within a valid
range is done when the input is first read from the input file or when a new value is entered in the
Input Editor. Further checking is done in the validate() method for each object when the model is
actually started, i.e. when the Start button is clicked. This validate() method is intended to ensure
that there are no missing inputs that would cause errors during execution and that the various inputs
are consistent with one another. Any new objects created by the user will need to include a suitable
validate() method.
For example, the following is a simple validate method for the EntityGenerator class:
@Override
public void validate() {
super.validate();
// Confirm that the next entity in the chain has been specified
if (nextComponent.getValue() == null) {
throw new InputErrorException( "The keyword NextEntity must be set." );
}
}
InputErrorException is a subclass of ErrorException that generates an error message box in the user
interface. The message is also added to the log file for the run. In batch mode, the error message is
logged without generating the message box and the run is terminated.
• earlyInit() – Initialisation of the object that is required on start up or after restarting. All
initialization required for a simulation run should be performed in this method. Initialization
should not be done in the object’s constructor since it will not be repeated on restart.
• startup() – Actual starting of any active objects.
If no specific code is required for the object then the method should be left out altogether so that it
defaults to its super-classes method.
Outputs differ from inputs in that they change continuously during the simulation run. Rather than
storing each output as a property and ensuring that it is updated prior to use, we have chosen to
identity the outputs with methods that calculate and return the desired value. This approach ensures
that the output value is up to date and avoids any unnecessary calculation of outputs that are
infrequently needed.
@Output(name = "AverageServiceTime",
description = "The average time per entity serviced to date.",
unitType = TimeUnit.class)
public double getAverageServiceTime(double simTime) {
return totalWorkingTime/numberProcessed;
}
In this example, AverageServiceTime is name of the output that will appear in the Output Viewer.
The description field will appear as tooltip pop-up when the user mouses over this entry in the Output
Viewer. The unit field indicates that this output has units of time.
The method getAverageServiceTime calculates the value of this output. All outputs must take a time
argument for reasons that will be discussed below. Numerical outputs should always be returned as
a double.
Outputs should always be freshly calculated from the object’s internal state. Storing and using a pre-
calculated output introduces unnecessary computation and is an invitation to logical errors caused by
out of date outputs.
Outputs take a time argument so that, when appropriate, the output can be calculated at any time,
not just at the event times. This approach allows the output to vary continuously between events,
which is helpful for outputs that are used in the 3D display. For example, if the process of travelling
between one location and another is modeled by a start-travelling event and an end-travelling event,
then to show smooth motion, it is necessary to calculate the object’s position at any intermediate
time. This can be done only if the renderer passes the present time to the output method.
The following example show a situation where the time argument can be used.
@Output(name = "FractionCompleted",
description = "The fraction of the service time that has been completed.",
unitType = DimensionlessUnit.class)
public double getFractionCompleted(double simTime) {
if( busy ) {
return (simTime - startOfServiceTime) / serviceTimeInput.getValue();
}
else {
return 0.0;
}
}
In this example, the internal property “startOfServiceTime” was updated when the Server started
processing its present customer and its state “busy” was set to true. By using the time argument
simTime in the calculation, the output FractionCompleted can increase smoothly from 0 to 1 as the
JaamSim Programming Manual 23 February 29, 2016
customer is serviced. This output could be used by a bar gauge or some 3D action to show the
service being performed.
An automatically-loaded input file is used to configure many of the built-in components of JaamSim.
The file in question, autoload.cfg, can be found in the folder
C:\JaamSim-master\src\main\resources\resources\inputs\autoload.cfg
Along with various other tasks, the autoload.cfg file sets up the Palettes and connects the class files
to the objects in the drag-and-drop tools. A Palette is a set of drag-and-droppable objects that
appear in the Model Builder. In the following figure, “Graphical Objects”, “Probability Distributions”,
“Basic Objects”, etc. are Palettes.
The following excerpt from graphic.inc, one of the file loaded by autoload.cfg, shows how the Palette
is created and how the classes DisplayEntity, Arrow, and Text are set up:
graphic.inc (exerpt):
The first two lines define the “Graphic Objects” palette and the three object types: DisplayEntity,
Arrow, and Text. Next, the JavaClass keyword is used to connect these object types with the Java
classes in the program and Palette keyword is used to assign each object to the Graphics Objects
palette.
A user can add new objects to JaamSim by creating a similar file and appending the appropriate
“Include” statement to the end of autoload.cfg. The following example shows the input files for a
hypothetical new palette “New Objects” containing the object type “MyComponent”.
Include sim.inc
Include units.inc
Include observers.inc
Include graphics.inc
Include displayModels.inc
Include basicObjects.inc
Include newObjects.inc ”New line added by the User”
NewObjects.inc file:
The autoload.cfg file is also used for creating all the default objects in JaamSim. In all but a few
cases, instances of high-level objects are created in the autoload.cfg or default.cfg files, not in the
code. By restricting the code to define object class and not the instances, it becomes much easier to
code the logic for stopping and restarting a model as well as to clear one model and to load another.
Default objects can be either built into JaamSim and will always appear, or they can be optional and
saved along with the user’s other inputs. Built-in objects are defined in the autoload.cfg file, while
optional object are defined in the default.cfg file. The user is free to add additional objects to either
file as required.
Default objects that will appear in every model should be defined in the autoload.cfg file. For
example, all the built-in units in JaamSim are defined in the units.inc file (one of the files included in
autoload.cfg). The following excerpt from this file shows the inputs used to define all the time units:
Additional units or other objects can be added to this file by the user.
Default objects that appear when JaamSim is first loaded, but will be cleared when an input file is
loaded, should be defined in the default.cfg file:
C:\JaamSim-master\src\main\resources\resources\inputs\default.cfg
Default.cfg file:
In JaamSim, the discrete-event logic is executed by the EventManager object. Its properties
eventStack and conditionalList are used to maintain the future event and conditional event lists,
respectively.
earlyInit() Initialises the Entity based on its inputs, but does not start any processing yet. The
earlyInit() method is overwritten for each subclass of Entity that requires initialisation.
The default method for Entity does nothing.
lateInit() Performs a second round of initialisation after all the entities in the model have
executed their earlyInit() method.
startUp() Starts any processes required for the Entity to begin the simulation run. Only active
Entities require a startUp() method. The startUp() method is overwritten for each
subclass of Entity that requires starting. The default method for Entity does nothing.
doEnd() Executes any post-run preparation that is required prior to the output report being
written.