|
||||||||||
PREV PACKAGE NEXT PACKAGE | FRAMES NO FRAMES |
See:
Description
Interface Summary | |
Filter | Interface representing filters used to refine Populations . |
Population | Interface that represents sets of entities. |
SimEventListener | Interface used to create SimEvent handlers. |
Class Summary | |
Entity | Abstract class from which all entities in a simulation are derived. |
PeriodicEntity | Used to generate SimEvents at
a specifed simulation time interval. |
SimEvent | Event Class used by PeriodicEntity
to signal the passage of simulation time. |
Simulation | Abstract class used to create a simulation. |
Trigger | Abstract class used to create all simulation developer defined triggers. |
WaitResult | Structure returned by Entity methods
waitForTime ,
waitForAction , and
waitForActionOrTrigger
giving the circumstainces of the return. |
Please read this first - Foundation classes and documentation to build process oriented simulations.
![]() |
Java Meets SimulationMITRE Sponsored Research to Improve Java Simulation Performance
|
Project Site Developer Contact Sim Team ![]() |
Building Simulations Infrastructure Documentation
All simulations evolve simulated time to model some aspect of the real world. This package assumes that a simulation consists of entities and their environment that evolve time synchronously, that the entities can interact with each other, and interact with their environment. Each entity executes events or activities that occur at points in simulated time; time evolves for that entity during the gaps between the events.
Entity
is the base class for all simulation entities.
An instance of a Simulation
subclass represents a
group of entities sharing a common definition of simulation time.
Example: Constructing a SimulationHere we build a simple simulation. Two instances of classMyEntity are running in the same simulation;
each instance has a different name but the same behavior.
The class diagram for that simulation is:
![]() |
The class MySimulation contains the main method that actually runs the simulation.
It does this by creating a new instance of itself and invoking the framework method
run on that instance.
The framework also defines method
initialize
that may be overridden by classes extending
Simulation .
The executive executes the initialize method when simulation
time is zero and before simulation time begins to advance.
MySimulation creates two instances of MyEntity and affiliates them with the simulation using the
register framework method.
Entities not registered with a simulation are ignored by the executive.
This source code is available in
tar and
zip archive formats.
class MyEntity extends |
Entities assign simulation time to their computations using inherited framework methods
defined on class Entity
. This section introduces the
waitForTime(x)
method that always
returns control to the Entity
after x
units of time have elapsed.
Other methods, described in later sections, provide more complex control of simulated time.
Example: Advancing TimeThis example extends the simulation constructed in the previous section. Here, class MyEntity displays the string "Hello", "Still here", In this simulation, class MyEntity displays the string "Hello", "Still here", and "Good Bye" at three different points in the evolution of simulation time. As before, two instances of classMyEntity are running in the same simulation.
Each instance has a different name but the same behavior.
This example illustrates:
|
The first action in the MyEntity agenda
displays the string "Hello" using convenience method
msg .
This action is implicitly assigned a simulation time value of zero.
The next statement in the agenda is waitForTime(2.0) .
The waitForTime invocation tells the executive that the entity
wants to place 2.0 units of simulation time between the display of string "Hello" and
the display of "Still here."
This implicitly assigns a simulation time value of 2.0 to the display of string "Still here."
The fourth statement, waitForTime(3.0) , places 3.0 units of simulation time between the
display of "Still here" and the display of "Good Bye."
The display of "Good Bye" is thus assigned a simulation time of 5.0.
The class MySimulation contains the class MyEntity extends |
In the output of MySimulation (below),
the first line contains infrastructure version information displayed by the executive.
In the rest of the output, info
adds the entity name and current simulation time to the supplied message string.
Below is the output of MySimulation.
The first line is infrastructure version information displayed by the executive.
In the rest of the output, info
adds the entity name and current simulation time to the supplied message string.
The output demonstrates the action of the executive to both assign simulation time to entity computations and coordinate the execution of multiple entities. The 2.0 and 3.0 unit waits between the messages caused "Hello" to receive a simulation time of 0.0, "Still here" a value of 2.0, and "Good Bye" a value of 5.0 (2.0 + 3.0). The action of the two instances of MyEntity, Foo and Bar, was interleaved by the executive to maintain proper temporal ordering. Observe that both entities displayed "Hello" before either entity displayed "Still here." Sim API 3.2, Simple Executive 1.4, Thread Flow 1.0 0.0 Bar Hello 0.0 Foo Hello 2.0 Bar Still here 2.0 Foo Still here 5.0 Bar Good Bye 5.0 Foo Good Bye |
waitForTime
to create a relationship between their local computations and the simulation-wide advance of time. The role of
the executive as coordinator of entity execution was also demonstrated.
This section introduces the
Trigger
framework class and
waitForActionOrTrigger
framework method.
Users define Triggers so that entities may control the advance of their simulation
time based on changes in the overall state of the simulation.
Trigger objects are tailored by overriding the
condition
method; the method returns a boolean value.
The simulation executive evaluates the method when needed and returns a true value when it is satisfied.
Since the user can't determine when and how often the executive evaluates condition
,
implementations of the condition
method should not have side effects in the simulation.
Anonymous subclasses are a convenient way to use Triggers because they are syntactically concise and
the code for a specific Trigger
is unlikely to be eligible for general reuse.
The inherited framework method
waitForActionOrTrigger(Triggers, x)
defined in class Entity
provides
another way for Entities to advance simulation time.
This method is similar to the waitForTime
method used in section Advancing Time.
It tells the executive that the entity wants to change the simulation time
associated with the next computation.
Unlike waitForTime
, however, here the amount of simulation time advanced
is conditional.
If an entity's agenda contains the statement waitForTime(7.0)
, simulated time always advances 7.0 units.
With waitForActionOrTrigger(Triggers, x)
,
the time associated with the next statement depends on whether any of its Triggers
was satisfied.
If a Trigger
was satisfied, the time of the next statement is the when the trigger was satisfied.
If none of the Triggers
were satisfied within x
units of simulated time,
simulated time advances x
units.
Example: TriggersThe phenomenon used to illustrate these ideas is the relationship between the weather and a household air conditioner. It has two active entities and a passive support object. Entities model the change in air temperature and the behavior of a thermostat. A support object represents the atmosphere which is affected by the temperature model and sensed by the thermostat model. Here is the class diagram for this simulation:![]() |
The TemperatureModel entity creates a very simple temperature profile by
increasing the temperature from 80 to 90 degrees at a rate of one degree per unit of simulation time.
Each time TemperatureModel changes the temperature, it updates the
Atmosphere object using the setAirTemperature method and
displays the new value using info .
This source code is available in
tar and
zip archive formats.
public class TemperatureModel extends |
Class ThermostatModel contains an anonymous subclass of Trigger .
The anonymous subclass supplies an implementation of method
condition
that tests whether the temperature of the atmosphere is greater than or equal to 85 degrees.
It returns true if it is and false if it is not.
A single instance of this new subclass is created and assigned to the variable tooHot .
The public class ThermostatModel extends |
The class WeatherSim creates the context for the simulation by
registering
an instance of TemperatureModel and an instance of ThermostatModel .
public class WeatherSim extends |
The simulation output below shows TemperatureModel increasing the
temperature one degree for each unit of simulation time.
It ranges from 80 degrees at time 0.0 to 90 degrees at time 10.0.
At simulation time 5.0 the temperature reached 85 degrees.
This triggered the tooHot Trigger in ThermostatModel .
When that happened, the waitForActionOrTrigger(tooHot) statement returned
and the message "Please turn on the air conditioner." was displayed.
This message was also associated with simulation time 5.0.
Sim API 3.2, Simple Executive 1.4, Thread Flow 1.0 0.0 Temperature 80 degrees 1.0 Temperature 81 degrees 2.0 Temperature 82 degrees 3.0 Temperature 83 degrees 4.0 Temperature 84 degrees 5.0 Temperature 85 degrees 5.0 Thermostat Please turn on the air conditioner. 6.0 Temperature 86 degrees 7.0 Temperature 87 degrees 8.0 Temperature 88 degrees 9.0 Temperature 89 degrees 10.0 Temperature 90 degrees |
Entity
whose name is of the form "actionX" where
X is one or more characters.
Action methods are different from other methods in that their invocation can change the
control flow of the entity that offers them.
Specifically, receipt of an action method invocation can effect when
waitForAction
invocations return.
This section also introduces the framework method
waitForAction
.
In section Triggers, a variant of
waitForAction
was used to wait for
a Trigger to be satisfied.
Here the entity waits for an certain amount of time to pass.
The difference between
waitForAction(t)
and
waitForTime(t)
is how they handle action methods.
When waitForTime(t)
is used,
the framework method always returns control after exactly t units of simulation time have passed.
During those t units of simulation time, any number of action methods invocations
could have been received by the entity.
When waitForAction(t)
is used, control returns
when either t units of simulation time have passed or an
action method invocation has been received.
Method waitForAction
returns an instance of class
WaitResult
that contains the circumstances surrounding the return
(waitForTime(t)
and
waitForActionOrTrigger
also return an instance of WaitResult
).
Methods on WaitResult
include:
actionOccurred
is true if an action method invocation caused the wait method to return
eventOccurred
is true if either an action method invocation or a trigger becoming true caused the wait method to return
triggerOccurred
is true if a trigger being satisfied caused the wait method to return.
returnTime
is the simulation time when the wait method returned.
trigger
is the satisfied trigger if a trigger caused the wait method to return.
Example: Action MethodsThis example program has two directly interacting entities. One entity proactively employs a service provided by a second entity. The second entity is mostly reactive but imposes constraints over the timing of the service being offered. Here is the class diagram for the example program:![]() |
PhilanthropistModel is a proactive entity that accepts an instance of
GoodCauseModel when it is constructed.
At two different points in simulation time, PhilanthropistModel interacts with
the GoodCauseModel entity to make a donation using the actionDonate
action method.
This source code is available in
tar and
zip archive formats.
public class PhilanthropistModel extends |
GoodCauseModel accepts donations as long as a donation
is made at least every four units of simulation time.
If four units of simulation time elapse without a donation, the GoodCauseModel
displays the message "No donations received in last 4 hours, going home." and then stops.
GoodCauseModel uses the
WaitResult instance returned by
waitForAction
to control its main loop.
If actionOccurred returns true ,
then a donation was received in less than four units of time and GoodCauseModel
waits for more donations by remaining in the loop and making another call to
waitForAction(4.0) .
If the return value is false , four units of time have passed without a donation and
GoodCauseModel gives up by exiting its main loop, displaying a message, and
ending its agenda .
public class GoodCauseModel extends |
The CharitySim class creates the context for the simulation.
It makes a single instance of GoodCauseModel and assigns it to the variable
recipient .
This was done so that the new instance can be both passed to the framework method
register
and provided to the PhilanthropistModel constructor.
public class CharitySim extends |
The simulation output shows the interaction between the
Philanthropist and the GoodCause .
Philanthropist begins with the message "Hello,"
waits 1.0 units of time, and then makes a food donation.
The corresponding output shows the Philanthropist message "Hello"
at time 0.0 and a message from GoodCause at time 1.0 acknowledging receipt of the food.
The invocation of the action method actionDonate(String donation) caused the
waitForAction(4.0) invocation to return
with a value of true after a wait of only 1.0 units of time.
Since it received a positive return value, main loop in GoodCause makes a second
call to
waitForAction(4.0) .
Sim API 3.2, Simple Executive 1.4, Thread Flow 1.0 0.0 Philanthropist Hello 1.0 GoodCause Food received 2.0 GoodCause Shelter received 3.0 Philanthropist Good Bye 6.0 GoodCause No donations received in last 4 hours, going home. |
agenda
and any code called by the agenda.
An entity agenda
manages proactive behavior with invocation of
time management
services and other entity
action methods
while
trigger and
action method
reception handles the reactive behavior.
All entity control threads can be thought of as running in parallel with
the simulation executive moderating their competing requests to
advance simulation time.
The scheduled event view of simulation sees the world as a collection of events rather than entities. An events is a block of code executed at a single point in simulation time. A simulation contains a dynamic collection of scheduled events, where scheduled event is the pairing of an event (a block of code) with a value of simulation time telling when the code should be executed. The executive executes scheduled events in order of the time values associated with each event. Once executed, the scheduled event is removed from the collection.
Scheduled events are added to the collection by events themselves.
Events create new scheduled events by invoking a framework service that
associates the name of an event with an amount of simulation time that
must pass before the event is executed.
In this framework, an event is any Entity method other
that the agenda method itself.
Events are scheduled using the
schedule(String methodName, double eventDelay)
framework service.
This service can be used to schedule events from any Entity method including the
agenda.
A scheduled event simulation is simply the process where events execute and create other scheduled events. To start this process, a mechanism is needed to identify and execute the initial event; the agenda method serves this purpose. Because the agenda method is invoked at simulation time zero by the executive, it is the right place to schedule an initial event or, more likely, a chain of events. Once that initial event is scheduled, the agenda can complete while the chain of events goes on.
The event scheduling capability introduced in this section works in harmony with the time advancement services used by interacting process-oriented simulations. Entities can simultaneously control their agendas with time advancement services and schedule chains of events as long as they observe the following:
schedule
events.
Object
s using the
schedule(String methodName, double eventDelay, Object[] arguments)
framework service.
When an event is scheduled using this service, the framework determines the class of
each supplied argument.
It uses the name of the method itself plus the list of argument class names
to find the appropriate method for the event.
If a method of the approporate signature cannot be found, the expection
java.lang.IllegalArgumentException
is thrown.
Example: Scheduled EventsThe SchedEventSim simulation below creates a single instance of class SchedEntity. That entity instance, in turn, creates a chain of scheduled events. The scheduled events are methodeventOne at time 2.0 and then method
eventTwo at time 5.0.
The source code for this example is available in
tar and
zip archive formats.
public class SchedEventSim extends |
The executive invokes the agenda method at simulation time zero.
Because no time advancement services are
invoked,
the agenda displays the message "Hello", schedules an event, and
displays the message "Good Bye" all at simulation time zero.
The eventOne method displays the message "Event One"
at time 2.0 because it was scheduled at time zero with a 2.0
time unit delay.
The eventTwo method displays the message "Event Two"
at time 5.0 because it was scheduled by eventOne at
time 2.0 with a requested delay of 3.0.
Note that events continued to execute even though the agenda
finished execution at time zero.
Sim API 4.0, Reference Executive 3.0, Thread Flow 1.6 0.0 SchedEntity Hello 0.0 SchedEntity Good Bye 2.0 SchedEntity Event One 5.0 SchedEntity Event Two |
Example: Mixed Process and Scheduled EventsThe MixedModeSim simulation below creates a single instance of class MixedModeEntity and informs the executive that the simulation should be stopped after 9.0 units of simulation time have passed. That entity instance, in turn, creates a chain of scheduled events. Unlike the previous example, the agenda remains active and performs operations in parallel with the scheduled event execution. The source code for this example is available in tar and zip archive formats.public class MixedModeSim extends Simulation { public void initialize() { register(new MixedModeEntity("MixedModeEntity")); setTimeLast(9.0); } public static void main(String[] args) { new MixedModeSim().run(); } } public class MixedModeEntity extends Entity { public MixedModeEntity(String name) { super(name); } public void eventOne(){ info("Event One"); |
The agenda begins execution at time zero and displays the message "Hello."
It waits 1.0 units of time then schedules method eventOne with a 2.0 time unit delay.
This means eventOne will be executed at time 3.0.
It then waits for 4.0 units of time.
During this delay, time 3.0 arrives and event eventOne displays the message "Event One."
Event eventOne also schedules eventTwo for execution with a 3.0 unit delay.
This gives eventTwo a scheduled execution time of 6.0.
Eventually 4.0 units of time pass for the agenda and it displays the message "Good Bye"
at simulation time 5.0.
When time 6.0 arrives, eventTwo is executed.
It displays message "Event Two Fa" at time 6.0 and reschedules itself to run again in 1.5
units of time.
This is an infinite loop and only ends because MixedModeSim set the
last value of time to 9.0.
Sim API 4.0, Reference Executive 3.0, Thread Flow 1.6 0.0 MixedModeEntity Hello 3.0 MixedModeEntity Event One 5.0 MixedModeEntity Good Bye 6.0 MixedModeEntity Event Two Fa 7.5 MixedModeEntity Event Two Fa La 9.0 MixedModeEntity Event Two Fa La La |
Population
and
Filter
interfaces in this package
exist to allow entities to define interesting entity sets,
examine those sets, and wait for changes in those sets.
Population
represents
a set of entities.
The set is dynamic in the sense that its
membership varies as simulation time progresses.
The executive maintains the membership
of each Population
as the state of the overall simulation changes.
An entity can examine the state of a Population
object,
but can not change it directly.
The simulation developer does not implement the Population
interface.
Entity code obtains Population
objects from the executive,
or by modifying existing Population
objects.
All Population
objects are managed by the executive on the
entity's behalf.
Entity code obtains an initial Population
object by invoking
the method createPopulation
.
This method takes a Java Class
, which must be the Entity
class or a subclass.
The call returns a Population
containing all the currently active
instances of the specified class and any subclass.
If no instances of the class (or subclass) have been registered at the time of
the call, the size of Population
will be zero.
As instances are registered the size of the Population
will increase.
createPopulation
an entity can obtain Population
objects defined by class.
By applying Filter
objects an entity can obtain Populations
whose membership depends on entity state.
Implementations of the Filter
interface
are created by a simulation developer.
The interface defines one method,
passesFilter
, which represents a predicate
to apply to each member of a Population
.
The predicate's computation can involve anything the developer likes, but typically
will involve the state of Population
members.
Filters
are used to define Populations
.
The developer creates an implementation of Filter
, and passes an instance
in the applyFilter
method
on an existing Population
.
The result is a new Population
whose members are all the members of the
original Population
for which passesFilter
returns
true
.
As with all Populations
, the membership is dynamic.
If no members pass the filter at the time the filtered Population
is created,
the size of the Population
will be zero.
The membership may grow:
Filters can be composed in the mathematical sense.
A Population
obtained from applyFilter
could be the object
of another call to applyFilter
with a second Filter
instance,
from the same or another Filter
class.
Thus, given
the members ofPopulation myWidgets = createPopulation(WidgetModel.class); Population blueWidgets = myWidgets.applyFilter(blueFilter); Population hotBlueWidgets = blueWidgets.applyFilter(hotFilter);
hotBlueWidgets
are all active instances of
WidgetModel
(or a subclass) which pass both
blueFilter
and hotFilter
.
Filters
can be used to exclude entities rather than include them.
The method rejectFilter
returns a new Population
whose members are those of the original
Population
for which passesFilter
of the supplied
filter returns false
.
(This defines a "set difference" operation.)
Populations
can be created whose membership is the union
of two Populations
.
If the method join
is invoked on
Population
p1
, passing Population
p2
as the parameter,
the resulting Population
will contain all the members of p1
and p2
.
(This defines a "set union" operation.)
Example: Chaining Populations and FiltersThe object diagram below illustrates definition ofPopulations in
various ways.
Going down the left side of the tree, the Population myWidgets
is formed by invoking createPopulation(WidgetModel.class) on the
Simulation .
It contains all active instances of WidgetModel and its subclasses.
The Population filter1pop is obtained by applying
filter1 to myWidgets .
It contains all members of myWidgets for which passesFilter
of filter1 returns true .
The Population filtered1and2Pop contains all members of
myWidgets that pass both filter1 and filter2 .
Going down the right side of the tree,
![]() |
Populations
resemble Java Sets
.
They are collections of objects that contain no duplicates.
There are Set
-like operations that can be applied to examine their contents,
specifically contains
,
isEmpty
,
iterator
,
size
,
and toArray
.
Generally speaking, the membership of a Population
will change
only when simulation time can change.
However, if an entity examines a Population
, then registers Entities
that could belong to the Population
, and examines the Population
again, it may find that the membership has changed.
An Entity
should not yield to the executive (e.g., by calling
waitForTime
while holding a Population Iterator
.
The behavior of the Iterator
is undefined in such a circumstance.
Entity
uses Triggers
to tie its local computations to
the overall state of the simulation.
As significant expressions of simulation state, Populations
are a natural
source of useful triggers.
The framework offers a number of convenient ways to construct a Trigger
from
a Population
.
The Population
methods
becomesEmpty
,
excludes
,
includes
,
sizeBelow
,
and sizeExceeds
return Triggers
that can be used in the various forms of
waitForActionOrTrigger
.
The intended idiom resembles this:
WaitResult wr = waitForActionOrTrigger(myPopulation.sizeExceeds(0), backstopTime);
Example: An Elk HerdThis example illustrates the use ofPopulations , Filters ,
Events , and Actions .
The simulation contains models of a number of elk in a heard.
Each elk is assigned a life span when it is created.
Each elk lives for that amount of simulation time, unless it is first killed.
The simulation also models a herd manager
whose purpose is to keep the elk population within predetermined bounds.
When the manager detects that the total elk population has dropped below
the minimum, it will create more elk.
When the manager detects that the population of adult elk has exceeded the maximum, it kills
a number of adults.
The herd manager also simulates the natural reproduction by periodically creating a new elk.
Each elk is represented by an instance of |
The code for the PopulationSim appears below.
The HerdManagerModel registers all the ElkModels in the simulation.
A last simulation time is set of 40.0.
public class PopulationSim extends Simulation { public void initialize() { register (new HerdManagerModel()); setTimeLast(40.0); } public static void main(String[] args) { new PopulationSim().run(); } } |
The code for the ElkModel appears below.
The constructor is called by the HerdManagerModel , which supplies a name
with a serial number, and a lifespan.
The ElkModel agenda completes when simulation time has advanced
by the lifespan, unless actionKill is called first.
That would cause the waitForAction invocation to return,
ending the instance.
public class ElkModel extends Entity { private double lifespan; private double birthday; public ElkModel(String name, double lifespan) { super(name); this.lifespan = lifespan; } public void agenda() { info("Born with lifespan " + lifespan); birthday = getTimeNow(); waitForAction(lifespan); info("Died at age " + getAge()); } public double getAge() { return getTimeNow() - birthday; } public void actionKill() { info("Killed"); } } |
The critical part of the code for HerdManagerModel appears below,
with line numbers.
Recall that the herd manager has three tasks: replenish the herd when its numbers
drop too low; cull the herd when adults grow too numerous; and periodically add
an elk as part of normal growth.
For the first two tasks the manager uses Populations created in lines 2 and 3.
Line 2 produces a Population that contains all active
instances of ElkModel .
Line 3 produces a Population of adults by applying a
Filter .
The Filter definition, implemented as the inner class
AdultFilter , appears in lines 38 to 41.
Note that at the time the Populations are obtained they are empty,
because no ElkModel instances have been registered.
They gain members when the initial population is created and registered on line 4.
The herd manager uses the
The normal function of the herd manager consists of creating and registering an
1 public void agenda() { 2 elkHerd = createPopulation(ElkModel.class); 3 adultsInHerd = elkHerd.applyFilter(new AdultFilter()); 4 for (int s = 0; s < initialPopulationSize; s++) register(createElk()); 5 Trigger herdTooSmall = elkHerd.sizeBelow(minimumPopulation); 6 Trigger herdTooBig = adultsInHerd.sizeExceeds(maximumPopulation); 7 schedule("eventNormalBirth", birthInterval); 8 while(true) { 9 WaitResult wr = waitForActionOrTrigger(herdTooSmall, herdTooBig); 10 if (wr.triggerOccurred() && wr.trigger() == herdTooSmall) { 11 replenishHerd(minimumPopulation); 12 } 13 else if (wr.triggerOccurred() && wr.trigger() == herdTooBig) { 14 cullHerd(maximumPopulation / 2); 15 } 16 } 17 } 18 19 public void eventNormalBirth() { 20 info("Normal birth"); 21 register(createElk()); 22 schedule("eventNormalBirth", birthInterval); 23 } 24 25 private void replenishHerd(int number) { 26 info("Replenishing herd by " + number); 27 for (int s = 0; s < number; s++) register(createElk()); 28 } 29 30 private void cullHerd(int number) { 31 info("Culling herd by " + number); 32 Iterator iter = adultsInHerd.iterator(); 33 for (int i = 0; i < number && iter.hasNext(); i++) { 34 ((ElkModel)iter.next()).actionKill(); 35 } 36 } 37 38 public class AdultFilter implements Filter { 39 public boolean passesFilter(Entity e) { 40 return ((ElkModel)e).getAge() >= adultAge; 41 } 42 } |
Simulation
is created.
This thread can be a new one or the thread that created the
Simulation
instance.
A new thread is created for the executive by invoking the start
method on the
Simulation
instance.
The thread that created the
Simulation
instance is
used by the executive when the run
method is invoked.
The start
method is inherited by
Simulation
from class
java.lang.Thread
.
Method run
is specified in interface
java.lang.Runnable.
Reuse of the creating thread is illustrated in the code fragment below:
In line one above,1 x = 13; 2 new MySimulation().run()
; 3 x = 27;
x
is set to a value of 13.
In line two, a new instance of MySimulation
is created
and the run
method
invoked.
The thread of control goes into the
run
invocation
and does not return until the simulation is finished.
That is, the run
invocation
blocks.
All aspects of the simulation see that value of x
as 13.
In line three, the simulation is complete and the value of x
is set to 27.
No part of the simulation ever saw x
equal 27.
In this situation it is not possible to use external controls.
If external controls are needed, the simulation executive must run in an separate thread. This is illustrated in the code segment below:
In line one above,1 x = 13; 2 new MySimulation().start()
; 3 x = 27;
x
is set to a value of 13.
In line two, a new instance of MySimulation
is created
and the start
method invoked.
This creates a new thread for the simulation executive and allows
it to proceed in parallel.
Line three sets the value of x
to 27.
This may happen before the simulation is finished.
Entities in the simulation may see x
have a value
of 13 and then 27 depending how the new thread of the simulation
and the thread that created it are interleaved.
In this situation it is possible to use external controls.
stopSimulation
.
This method informs the executive that the simulation should end as soon as is practical.
When a simulation is stopped in this way, the notification services described in
section Completion Notification are invoked.
The executive contains a value of simulation time known as the "last value of time."
By default, this value is set to Double.POSITIVE_INFINITY
.
Framework method setTimeLast
is available on class Simulation
to adjust the last value of simulation time.
When the executive detects that an entity is attempting to assign a value of simulation time
greater than the last value of time, it will stop
the simulation as soon as is practical.
When a simulation is stopped because it reached the last value of simulation time,
the notification services described in
section Completion Notification are invoked.
entityComplete:
Executed as the final step in the life of an entity.
simulationComplete:
Executed when all entities have ended and all their
entityComplete
methods are finished.
Example: Completion notificationThis simple example demonstrates notification of bothEntity
and Simulation
completion handling.
Class InterruptedEntity overrides framework method
entityComplete
with a single line method that displays the message "Entity complete."
The agenda
attempts to display message "Hello" at time 0.0, "Still here" at time 2.0, and "Good Bye" at time 5.0.
This source code is available in
tar and
zip archive formats.
public class InterruptedEntity extends Entity { public InterruptedEntity() { super("InterruptedEntity"); } public void entityComplete() { info("Entity complete"); } public void agenda() { info("Hello"); waitForTime(2.0); info("Still here"); waitForTime(3.0); info("Good Bye"); } } |
Class FinalSimulation overrides the framework method
simulationComplete
with a single line method that displays the message "Simulation complete."
It also uses framework method
setTimeLast
to set the last value of simulation time to 1.0.
public class FinalSimulation extends Simulation { public void initialize() { register(new InterruptedEntity()); setTimeLast(1.0); } public void simulationComplete() { info("Simulation complete"); } public static void main(String[] args) { new FinalSimulation().run(); } } |
The output of the simulation entity InterruptedEntity contains only two of the
three messages in its agenda .
The simulation executive stopped the simulation at time 2.0 and invoked
the completion method for the entity, displaying "Entity complete" and
then the completion method for the simulation, displaying "Simulation complete."
The last value of simulation time was 2.0 and not
the value 1.0 as requested by the framework invocation
setTimeLast(1.0) .
The simulation executive is only required to
stop the simulation as soon as is practical after the requested
value of 1.0.
Sim API 3.2, Simple Executive 1.4, Thread Flow 1.0 0.0 InterruptedEntity Hello 2.0 InterruptedEntity Still here 2.0 InterruptedEntity Entity complete 2.0 FinalSimulation Simulation complete |
setPace
method on class Simulation
gives the developer control over the maximum rate at which the simulation will evolve.
This is done by specifying the minimum number of real milliseconds that must pass
each time the simulation evolves one unit of simulation time.
It may take more than the specified number of milliseconds to compute a unit of simulation time.
That is, the supporting platform may not have sufficient power to achieve the desired rate.
In this case, the use of
setPace
has no effect.
The simulation can be reset to run as fast as possible by invoking the method with a zero argument
(setPace(0))
Example: Setting the Simulation PaceThis example program demonstrates the use of framework methodsetPace
to control the maximum rate at which the simulation evolves.
Class RocketModel simulates the countdown of a rocket as it prepares for launch.
It does this by displaying a message heard many time at Cape Canaveral: "T minus i seconds"
where i is the number of seconds until launch.
The count goes down from 10 seconds to one second.
After that the "Blast off!" message is displayed.
The waitForTime framework method is used
to place a delay of one unit of simulation time between counts.
This source code is available in
tar and
zip archive formats.
public class RocketModel extends Entity { public RocketModel() { super("Rocket"); } public void agenda() { for (int count = 10; count > 0; count--) { info("T minus " + count + " seconds"); waitForTime(1.0); } info("Blast off!"); } } |
The LaunchSim class creates one instance of entity RocketModel
and registers it with the simulation executive.
Using setPace
it then informs the infrastructure that a minimum of 1000 milliseconds
(one second) of real time must pass for each unit of simulation time.
public class LaunchSim extends Simulation { public void initialize() { register(new RocketModel()); |
The output of the Launch Simulation shows how the infrastructure creates the desired
pace of simulation.
The output does not appear immediately.
There is a one second delay between each displayed line of the count down.
That is, it will take about 10 seconds, as measured by your wrist watch, for
all the output below to appear.
Sim API 3.5, Reference Executive 2.2, Thread Flow 1.3 0.0 Rocket T minus 10 seconds 1.0 Rocket T minus 9 seconds 2.0 Rocket T minus 8 seconds 3.0 Rocket T minus 7 seconds 4.0 Rocket T minus 6 seconds 5.0 Rocket T minus 5 seconds 6.0 Rocket T minus 4 seconds 7.0 Rocket T minus 3 seconds 8.0 Rocket T minus 2 seconds 9.0 Rocket T minus 1 seconds 10.0 Rocket Blast off! |
Simulation
instance.
All external controls are methods on instances of
Simulation
.
They are:
pauseSimulation
-
Suspend activity in the simulation by pausing the executive.
Once paused, simulation time will not advance.
resumeSimulation
-
Resume normal simulation executive operation.
Example: Simulation Pause and ResumeAs inLaunchSim above, DelayedLaunchSim creates and
registers a single instance of RocketModel .
As before, it also uses
setPace
to create a rate where one unit of simulation time corresponds to
one second of real time.
The method delay(long) is a convenience to hide the clutter of an exception handler.
The 1 public class DelayedLaunchSim extends Simulation { 2 3 public void initialize() { 4 register(new RocketModel()); 5 setPace(1000); 6 } 7 8 public void delay(long delay) { 9 try { 10 Thread.sleep(delay); 11 } catch (Exception e) {} 12 } 13 14 public static void main(String[] args) { 15 DelayedLaunchSim dls = new DelayedLaunchSim(); 16 dls. |
The output of the Delayed Launch Simulation shows how the infrastructure creates the desired
pace of simulation and the effect of external controls.
While the main thread slept in line 17, the simulation conducted the countdown
from 10 down to 5.
Each count taking one second of real time.
After the countdown reached 5, the main thread woke up and paused the
simulation.
This results in a 5 second delay after which the countdown resumed at a normal pace.
It takes about 15 seconds, as measured by your wrist watch, for
all the output below to appear.
Sim API 3.5, Reference Executive 2.2, Thread Flow 1.3 0.0 Rocket T minus 10 seconds 1.0 Rocket T minus 9 seconds 2.0 Rocket T minus 8 seconds 3.0 Rocket T minus 7 seconds 4.0 Rocket T minus 6 seconds 5.0 Rocket T minus 5 seconds Five second delay 6.0 Rocket T minus 4 seconds 7.0 Rocket T minus 3 seconds 8.0 Rocket T minus 2 seconds 9.0 Rocket T minus 1 seconds 10.0 Rocket Blast off! |
SimEventListener
.
These listeners wait for the arrival of
SimEvent
events.
Currently, PeriodicEntity
is the only source of
SimEvents
in the framework.
PeriodicEntity
is a
framework-provided subclass of
Entity
.
Instances of
PeriodicEntity
produce a stream of
SimEvents
for their
listeners at regular intervals of simulation time.
The amount of simulation time between events is specified
when the instance of
PeriodicEntity
is created.
Listeners are affiliated with an instance of
PeriodicEntity
by the
addSimEventListener
method and removed with the
removeSimEventListener
method.
Example: Event ListenersClassListenerSim uses
PeriodicEntity
to create periodic events for a listener.
The Listener class extends
SimEventListener to
become a listener for
SimEvent events.
The listener simply displays the simulation time of the
SimEvent
events as they are received.
During initialization, a single instance of
public class ListenerSim extends Simulation { public class Listener implements |
The output of the Listener Simulation shows that events were produced every 1.5
unit of simulation time.
The event stream concluded when the last value of simulation time, 6.0, was reached.
Sim API 3.5, Reference Executive 2.2, Thread Flow 1.3 1.5 ListenerSim Event received at 1.5 3.0 ListenerSim Event received at 3.0 4.5 ListenerSim Event received at 4.5 6.0 ListenerSim Event received at 6.0 |
Simulation
method
setVisible(boolean)
.
The GUI is turn off by default.
A handy way to use the GUI is to turn it on when a
Simulation
instance is created.
This is illustrated below:
public class MySimulation extendsSimulation
{ public void initialize() { ... } public static void main(String[] args) { new MySimulation().setVisible
(true); } }
agenda
or
entityComplete
methods will throw an exception.
The simulation executive will catch any exception thrown by the
these method and supply that exception to the
exceptionHandler
method below:
If this happens, no further attempt will be made to runpublic void exceptionHandler(Exception e) { e.printStackTrace(); }
agenda
or
entityComplete
.
If an exception handler other than the one shown above is needed,
it can be overridden.
The executive will catch and discard any exceptions thrown by
exceptionHandler
itself.
ajc
, rather
than javac
.
The AspectJ compiler, ajc
, is a super set of javac
and should present do differences to a Java developer.
It produces the same byte code as javac
and is thus completely
compatible with the overall Java platform.
To begin using the simulation framework, perform the following tasks:
sim.jar
aspectj-1.1.1.jar
, from the developer
home page.
Execute this file from any directory using the following command:
The installer will ask for the location of your existing Java Home directory and will then ask you where to place thejava -jar aspectj-1.1.1.jar
aspectj1.1
directory. The path you choose will be referenced in this document
as the ASPECTJ_HOME
.
To gain access to the ajc
compiler,
add the following directory to your command path:
ASPECTJ_HOME/bin
sim.jar
,
from the developer
home page.
Place the sim.jar file in a convenient directory.
In this documentation, that directory will be known
as SIM_HOME
.
Make the following invocation to compile program MySim.java
using
the simulation framework:
ajc -aspectpath SIM_HOME/sim.jar MySim.java
ajc
are executed by the same Java virtual machine
as programs compiled with javac
.
To execute an instance of class
Simulation
,
both sim.jar
and aspectjrt.jar
must be in the class path.
The following command will execute MySim.class
if executed from
the directory that contains it.
If thejava -cp .:SIM_HOME/sim.jar:ASPECTJ_HOME/lib/aspectjrt.jar MySim
sim.jar
, aspectjrt.jar
, and the local directory
are included in the definition of the CLASSPATH
environment variable,
the invocation can be shortened to:
java MySim
ajc
can be used in
an ant script rather than javac
.
<target name="build"> <taskdef name="ajc" classname="org.aspectj.tools.ant.taskdefs.AjcTask"> <classpath> <fileset dir="lib"> <include name="aspectjtools.jar"/> </fileset> </classpath> </taskdef> <ajc srcdir="src" destdir="classes" aspectpath="sim.jar"> <classpath> <fileset dir="lib"> <include name="yourJarFile.jar"/> </fileset> </classpath> </ajc> </target>
sim.properties
and
is located in CVS at CVSRoot/sim/resources/sim.properties
.
To be accessible at runtime, a resources
directory containing sim.properties
must exist at the root of the class file structure.
This occurs two ways:
CVSRoot/sim/classes/resources
directory
sim.jar
archive.
CVSRoot/sim/build.xml
moves
the resources
directory to these two places.
Ant target build
copies the resources
directory to
the CVSRoot/sim/classes
directory.
Ant target jar
copies the resources
directory into the sim.jar
archive.
The property file contents are described below:
Property Name | Description | Default Value |
---|---|---|
org.mitre.sim.Flow.class | Process lifecycle services class name. | org.mitre.sim.api3.flow.threads.ThreadFlow |
org.mitre.sim.Executive.class | Simulation executive class name. | org.mitre.sim.api3.exec.reference.ReferenceExecutive |
org.mitre.sim.GUI.components | The components to show on the Simulation's GUI. | control |
org.mitre.sim.GUI.component.<component name>.class | The java class to load for a particular graphical component | [control] = org.mitre.sim.api3.gui.SimControl |
org.mitre.sim.GUI.component.<component name>.* | Properties specific to a particular GUI component | N/A |
org.mitre.sim.GUI.component.control.timeFormatter.class | The time format class to use when displaying the simulation time | java.text.DecimalFormat |
org.mitre.sim.GUI.component.control.timeFormatter.format | Format used to convert the simulation time into a displayable string | #########0.0###### |
org.mitre.sim.Simulation.level | The level that the Simulation logger should log messages at | INFO |
org.mitre.sim.Executive.level | The level that the Executive logger should log messages at | OFF |
org.mitre.sim.Flow.level | The level that the Flow logger should log messages at | OFF |
org.mitre.sim.LogicalProcess.level | The level that the Logical Process [entities] logger should log messages at | INFO |
org.mitre.sim.<Logger Name>.handlers | The default set of handlers to use for a given logger | [Simulation, Executive, Flow, LogicalProcess] = console |
org.mitre.sim.<Logger Name>.handler.<handler name>.class | The java class to load for a given handler | console = java.util.logging.ConsoleHandler |
org.mitre.sim.<Logger Name>.handler.<handler name>.level | The level that a given handler should log at | java.util.logging.Level.ALL [logs all messages] |
org.mitre.sim.<Logger Name>.handler.<handler name>.formatter.class | The formatter for a given handler | [console] = org.mitre.sim.api3.util.BasicFormatter |
org.mitre.sim.<Logger Name>.handler.<handler name>.formatter.format | The format of a log record. This is only useful for the org.mitre.sim.api3.util.BasicFormatter. | {0,date,MMM dd, yyyy} {0,time,HH:mm:ss} {1} {2}'\n'{3}: {4} {5,choice,0#'\n'|1#'\n' {6}} |
State
and
described in the state transition diagram below:
Dormant
:
The entity
instance has been created.
Ready
:
Entity
is registered with the simulation executive and
is waiting to be selected for execution.
Active
:
The simulation executive has passed control to this entity.
There is only one entity in this state at a given time.
WaitingForTime
:
The entity is waiting for a specific value of simulation time to arrive.
At any given point, most entities are in this state or WaitingForEvent.
WaitingForEvent
:
The entity
is waiting for something to change in the simulation environment or
a backstop time to arrive.
At any given point, most entities are in this state or WaitingForTime.
Complete
:
The entity is capable of no further action and is waiting for garbage collection.
Entity
subclass is instantiated.
entity
instance.
agenda
invoked the
waitForTime
method.
agenda
invoked the
waitForAction
or
waitForActionOrTrigger
methods.
agenda
method,
stopSimulation
invocation, or
run
on the
Simulation
subclass ended.
Method Invocation at time ti |
Return Description | Action Method Invoked at time ta |
Trigger
Condition Becomes True at time tc |
Time Elapses x Units |
---|---|---|---|---|
waitForTime (x) |
Return control to the Entity
after x units of time have elapsed.
|
Nothing Happens | Nothing Happens | Returns:WaitResult (false, false, null, ti+x)
|
waitForAction (x) |
Return control to this Entity
when any action method has been
invoked or x units of time have elapsed.
|
Returns:WaitResult (true, false, null, ta)
|
Nothing Happens | Returns:WaitResult (false, false, null, ti+x)
|
waitForActionOrTrigger (triggers, x) |
Return control to this Entity
when any of a set of triggers has been satisfied or
x units of time have elapsed.
| Returns:WaitResult (true, false, null, ta)
|
Returns:WaitResult (false, true, trigger, tc)
|
Returns:WaitResult (false, false, null, ti+x)
|
Copyright © 2003-2004 The MITRE Corporation
|
||||||||||
PREV PACKAGE NEXT PACKAGE | FRAMES NO FRAMES |