Ptolemy II models can be specified in a number of ways and used in a number of ways. They might be simulations (executable models of some other system) or implementations (the system itself). They might be classical computer programs (applications), or any of a number of network-integrated programs (applets, servlets, or CORBA services, for example). At the current writing, applets have the best developed infrastructure, so we describe here how to construct them. It is possible today to construct other network-integrated architectures, but there is less built-in Ptolemy II support at this time.
Eventually, you will be able to construct applets and other Ptolemy II architectures using XML files. There will also be graphical editors for building these XML files using, for example, block diagrams. However, at this time, you must write Java code to construct a Ptolemy II model.
Ptolemy II models can be embedded in applets1. For convenience, each domain includes a base class XXApplet, where XX is replaced by the domain name. This section uses a DE domain applet to illustrate the basic concepts, so the base class is DEApplet. Refer to subsequent chapters and to the code documentation for more complete information about the classes and methods being used. DEApplet is derived from PtolemyApplet, as shown in figure 2.1 (see appendix A of chapter 1 for UML syntax).
An applet is a Java class that can be referenced by an HTML file and accessed over the web. Unfortunately, most browsers available today do not have built-in support for the (relatively recent) version of Java that Ptolemy II is based on (version 1.2.1). The work around is to use the Java Plug-In, which invokes Sun's Java Runtime Environment (JRE), instead of the browser's default Java runtime. The table below lists platform and plug-in availability.
Platform | Availability |
---|---|
Windows 95, 98, NT | JDK1.2.1 Plug-in installed as part of the JDK or JRE. See http://www.javasoft.com/products/plugin/ |
Irix | Plug-in available, see http://www.sgi.com/Products/Evaluation/#java_plugin |
Solaris 2.6, 2.7 | Custom version of Netscape Navigator available, see http://www.sun.com/solaris/netscape |
Linux | As of 6/13/99, JDK 1.2.1 Plug-in not yet available, see http://www.blackdown.org/. Use the appletviewer program |
Solaris 2.5.1 and all other platforms with JDK 1.2.1 | Use the appletviewer program to run the applets. |
Platforms that do not have the Java Plug-in 1.2.1, but do have the Java Development Kit (JDK) 1.2.1 can use Sun's appletviewer command to run applets locally. Each demonstration directory has a make demo
rule that sets the CLASSPATH
appropriately and then calls appletviewer. We discuss how to run appletviewer
by hand in "Compiling" on page 2-5. However, the appletviewer does not render the HTML text in the web page, so you get only a subset of the information.
Regrettably, the way the plug-in is invoked depends on the browser being used. One approach to creating applets that use the plug-in is to write them as if they were to use the native Java runtime environment of the browser, and then invoke Sun's Plug-In HTML Converter, available on their web site. The converter did not work for me, however, at least under Windows NT (its file browser failed to list HTML files, or any other file, for that matter, in most directories). Thus, I recommend writing the HTML files directly rather than using the converter.
Sample HTML is shown in is shown in figure 2.2. The incredible ugliness and awkwardness of this text is hopefully transitory, while browser vendors agree on how to properly support plug-ins (I hope it is transitory, or plug-ins will not be a long term solution). You should be able to essentially copy what we have, making very few modifications, and get things to work.
The code in figure 2.2, amazingly, relies on the fact that Microsoft's Internet Explorer understands some HTML tags that Netscape Navigator does not, and vice versa. IE uses the <OBJECT>
and </OBJECT>
tags to specify plug-ins. The "classid" is a magic string that is always the same (it identifies the Java version 1.2 run-time environment, in a not very user-friendly way).
The <COMMENT>
and </COMMENT>
tag is understood only by Internet Explorer, so it is used to hide from IE the <EMBED>
and </EMBED>
tags, which Netscape uses to support plug-ins. The Sun appletviewer, a utility program for invoking applets without rendering the surrounding HTML, also uses this tag.
In the case of the <OBJECT>
and </OBJECT>
tags, the specified "codebase" is the place to find the plug-in if it is not already installed. The codebase for the applet itself (the root of the tree to search for classes) is given by a <PARAM>
tag with name "codebase." This is confusing, especially given that for the <EMBED>
and </EMBED>
tags, the plug-in location is given by the pluginspage parameter, and codebase refers to the code base for the applet. We can only hope that some day there will be standardization of HTML.
In the case of the <OBJECT>
and </OBJECT>
tags, if there were any additional applet parameters, they would be given in <PARAM>
tags. For the <EMBED>
and </EMBED>
tags, applet parameters are given as parameters of the <EMBED>
tag.
An HTML file containing the segment shown in figure 2.2 can be found in $PTII/doc/tutorial/tutorial.htm, where $PTII is the home directory of the Ptolemy II installation. For example, on my machine (running Windows NT and using bash as a shell), I have Ptolemy II installed in d:\ptII, and using the system control panel, I have the environment variable PTII set to d:/ptII (I'm not sure whether it matters that the slashes go different ways). Also in that directory are a number of sample Java files for applets, each named TutorialAppletn.java, where n is an integer starting with 1. These files contain a series of applet definitions, each with increasing sophistication, that are discussed below. To compile and use each file, it must be copied into TutorialApplet.java (without the n).
Since our example applets are in a directory $PTII/doc/tutorial, the codebase for the applet is "../.." in figure 2.2, which is the directory $PTII. This permits the applets to refer to any class in the Ptolemy II tree.
There are some parameters in the HTML in figure 2.2 that you may want to change. The width and the height, for example, specify the amount of space on the screen that the browser gives to the applet. Unfortunately, they are specified twice in the file.
Fortunately, getting the Java code right is easy compared to getting the HTML right.
In figure 2.3 is a listing of an extremely simple applet that runs in the discrete-event (DE) domain. The first line declares that the applet is in a package called "doc.tutorial," which matches the directory name relative to the codebase specified in the HTML file.
In the next three lines, the applet imports three classes from Ptolemy II:
DEApplet
: A base class for DE applets that is provided for convenience. This base class creates a top-level composite actor called _toplevel
, a manager called _manager
, and a director called _director
(all protected members of the class, shown in figure 2.1). We will see shortly how to use these.
Clock
: This is an actor that generates a clock signal, which by default is a sequence of events placed one time unit apart and alternating in value between 1 and 0.
TimedPlotter
: This is an actor that plots functions of time.
public class TutorialApplet extends DEApplet { ... }
defines a class called TutorialApplet that extends DEApplet. The new class overrides the init() method of the base class with the following body:
super.init();
try {
Clock clock = new Clock(_toplevel,"clock");
TimedPlotter plotter = new TimedPlotter(_toplevel,"plotter");
_toplevel.connect(clock.output, plotter.input);
} catch (Exception ex) {}
This first invokes the base class, then creates an instance of Clock and an instance of TimedPlotter, and connects them together.
The constructors for Clock and TimedPlotter take two arguments, the container (a composite actor), and an arbitrary name (which must be unique within the container). This example uses the variable _toplevel
, provided by the base class, as a container. The connection is accomplished by the connect() method of the composite actor, which takes two ports as arguments. Instances of Clock have one output port, output
, which is a public member, and instances of TimedPlotter have one input port, input
, which is also a public member. We will discuss the try . . . catch statement below.
To compile this class definition, you must first copy TutorialApplet1.java into TutorialApplet.java (Java requires that file names match the names of the classes they contain). Then set the CLASSPATH environment variable to point to the root of the Ptolemy II tree. For example, in bash, assuming the variable PTII is set,
bash-2.02$ cd $PTII/doc/tutorial
bash-2.02$ cp TutorialApplet1.java TutorialApplet.java
bash-2.02$ CLASSPATH=$PTII
bash-2.02$ export CLASSPATH
bash-2.02$ javac TutorialApplet.java
(The part before the "$" is the prompt issued by bash). You should now be able to run the applet with the command:
bash-2.02$ appletviewer tutorial.htm
The result of running the applet is a new window which should look like that shown in figure 2.4. This is not (yet) a very interesting applet. Let us improve on it.
The code in figure 2.3 has a try ... catch statement that does something that is almost never a good idea: it discards exceptions. If an error were to occur during construction of the model, this statement would mask the error, and the applet would silently fail.
The base class PtolemyApplet, fortunately, provides a report() method (see figure 2.1) for reporting errors in a uniform way. The modified code is shown in figure 2.5.
The applet, as written so far, has the annoying feature that it opens a new window to display the plotted results, as shown in figure 2.4. Most applets will want to display their results in the browser window, as part of the text of a web page.
The TimedPlotter actor, and most other Ptolemy II components with graphical elements, implements the Placeable interface. This interface has a single method, setPanel(), which can be used to specify the panel into which the object should be placed. If this method is not called before the object is mapped to the screen, then the object will create its own frame into which to place itself. This is what happened with our applet, resulting in the frame shown in figure 2.4.
Modified code that places the plot in the applet window itself (an instance of Applet is a Panel) is shown in figure 2.6. Note that the size of the plot is now also specified to match the size of the applet, using the statement:
plotter.plot.setSize(700,300);
This line refers to a public member of the plotter object, called "plot," which is an instance of the class Plot, from the ptolemy.plot package. That class has a method, setSize(), that can be used to control the size of the plot.
The resulting applet looks like that shown in figure 2.7. In this case, the default layout manager of the Applet class is allowed to control where the plot is placed. Arbitrarily fine control can be exercised, however, by placing a new instance of Panel in the applet using any suitable layout manager and then specifying that panel for the plotter using its setPanel() method. This is done in the next section.
By default, the director in the DE domain executes a model for one time unit. This does not give a a very satisfactory plot in figure 2.7. To change the amount of time to 30, include in the body of the init() method the following line:
_director.setStopTime(30.0);
Alternatively, you can set the stop time in the HTML file by setting an applet parameter called "stopTime." To set this applet parameter to 100, add the line
<PARAM NAME="stopTime" VALUE="100">
to the <OBJECT>
... </OBJECT>
body in figure 2.2, and the parameter
stopTime="100"
to the <EMBED>
tag. Regrettably, both must be added or the applet will behave differently in IE and Netscape.
You can instruct the applet to put controls on the screen that allow the applet user to control the model execution time with the following line (see figure 2.1):
add(_createRunControls(2));
The argument specifies how many run control buttons to create. A value of "1" or larger requests a "go" button, while "2" or larger requests both a "go" and a "stop" button. We must also modify the size of the plotter, as shown in figure 2.8. The size is set so that 50 pixels in the vertical direction are allowed for the run controls. The resulting page, with an entered execution time of 30, is shown in figure 2.9.
The default stop time in the entry box can be controlled by setting an applet parameter "defaultStopTime." To set this applet parameter so that the default is 100, add the line
<PARAM NAME="defaultStopTime" VALUE="100">
to the <OBJECT>
... </OBJECT>
body in figure 2.2, and the parameter
defaultStopTime="100"
In the SDF domain, the corresponding parameters are "iterations" and "defaultIterations." For other domains, see the documentation for the XXXApplet class, where XXX is the domain name.
Most actors in Ptolemy II have parameters that control their behavior. The Clock actor, for example, has a period parameter. Parameters are generally public members, instances of the class Parameter. To change the period of the clock from the default 2.0 to, say, 1.0, add the line to the init() method of the applet:
clock.period.setExpression("1.0");
More interestingly, you may wish to offer this control to the applet user. This can be done using built-in Java classes to create an entry box in the applet, or more easily by using an instance of the Query class in the ptolemy.gui package.
The code shown in figure 2.10 results in the browser display shown in figure 2.11. The important changes are shown in bold. First, the class now has a private member _query that is an instance of Query. In addition, a reference to the Clock actor is now stored in a private member _clock instead of in a local variable in the init() method. The following lines have been added to the init() method:
_query.setBackground(getBackground());
_query.addLine("period", "Period", "2.0");
_query.addQueryListener(this);
add(_query);
The first of these sets the background color of the query widget to match the background color of the applet. The second adds a single-line entry box to the query, with name "period," label "Period," and default entry "2.0." The name is an arbitrary string that can be used elsewhere to refer to this particular entry in the query. In this applet, the query has only one entry, so giving it a name seems unnecessary. But in general, a query can have any number of entries, so unique names are necessary.
The third line above informs the query that this applet is a listener, meaning that it should be notified when any entry in the query changes. To be a listener, it must implement the QueryListener interface, which requires that a method changed() be implemented. That method is defined as:
public void changed(String name) {
_clock.period.setExpression(_query.stringValue("period"));
try {
_go();
} catch (Exception ex) {
report("Error executing model.", ex);
}
}
This method is called by the query object whenever an entry in the query changes. The argument is the name of the entry that changed. In this applet, there is only one entry, so we can ignore the argument. We use the stringValue() method of the Query class to obtain the text of the entry, and the setExpression() method of the period parameter to set its value. In addition, we invoke the protected method _go() of the parent class, DEApplet, to execute the model. Thus, whenever the applet user changes the period parameter, the model automatically executes again.
Notice that the method name setExpression() suggests that the value need not be a number, but rather can be an expression. Indeed, this is the case. The expression language that is supported is defined in the Data Package chapter. In short, ordinary arithmetic operations on constants are supported, as are all the methods of the Java Math class (sin(), cos(), etc.), and some pre-defined constants (pi, e, i, ...). In addition, expressions can symbolically refer to other parameters (by name) contained in the same container, or contained in the container of the container. Thus, for example, if you have several actors that you want to have the same parameter value, define a parameter "x" in the container (composite actor) and set the parameters in the actors to have value "x".
The plot display that is generated by this applet can be improved considerably. The TimedPlotter actor is somewhat special in that it contains a public member that is not a Parameter, but is rather an instance of Plot (see the Plot chapter). An instance of Plot can be configured in a large number of ways. In figure 2.12, we have added the following lines to the applet init() method:
plotter.plot.setTitle("clock signal");
plotter.plot.setXLabel("time");
plotter.plot.setImpulses(true);
plotter.plot.setConnected(false);
plotter.plot.setMarksStyle("dots");
The first line defines a title, and the second defines a label for the horizontal axis. The third requests a "stem plot" style, where a line is drawn vertically from the value to the origin. The fourth requests that events not be connected by lines, and the last requests that large dot be placed on each event. The resulting applet, as viewed by Sun's appletviewer, is shown in figure 2.13. A more detailed example is shown in the appendix.
The intent in Ptolemy II is to have a reasonably rich set of actors in the actor libraries. However, it is anticipated that model builders will often need to define their own, custom actors. This is relatively easy to do, as discussed in the following chapter. By convention, when a specialized actor is created for a particular applet or application, we store that actor in the same directory with the applet or application, rather than in the actor libraries. The actor libraries are for generic, reusable actors.
A jar file is a Java Archive File that contains multiple .class files. Applets that are being downloaded over the net will start up more quickly if all the Java .class files are collected together into one or more jar files. This dramatically reduces the number of HTTP transactions.
Models in the Ptolemy II demo directories typically use three separate jar files:
The third jar file is not needed if the model resides in a single .class file. To use jar files, you must modify the HTML shown in 2.2 to read as shown in figure 2.14.
An important downside of using jar files is that during Java development, one must regenerate the jar files each time a Java file is recompiled. If you are developing an applet, you may want to avoid using jar files, or only include jar files that are from packages that are not actively being developed.
To know which jar files in the Ptolemy II tree you might need for your applet, you need to know how the jar files are constructed. The short story is that every package has a jar file that includes subpackages. Since the package structure mirrors the directory structure, it is easy to peruse the Ptolemy II tree (rooted at $PTII) and look for jar files. There are a few exceptions; for example, domain jar files, such as de.jar, do not include the demos, even though the demos are in a subpackage of the domain package.
The longer story is that the make install
rule in Ptolemy II makefiles builds various jar files that contain the Ptolemy II .class files. In general, make install builds a jar file in each directory that contains more than one .class file. If a directory contains subdirectories that in turn contain jar files, then the subdirectory jar files are expanded and included in the upper level jar file. For example, the $PTII/ptolemy/kernel/makefile contains:
# Used to build jar files
PTPACKAGE = ptolemy.kernel
PTDIST = $(PTPACKAGE)$(PTVERSION)
PTCLASSJAR =
# Include the .class files from these jars in PTCLASSALLJAR
PTCLASSALLJARS = \
event/event.jar \
util/util.jar
PTCLASSALLJAR = kernel.jar
In this case make install
will build a jar file called kernel.jar
that contains all the .class files in the current directory and the contents of ptolemy/kernel/event/event.jar and ptolemy/kernel/util/util.jar.
Most applet authors start with the same set of operations: creating an HTML file and a Java file defining a class that extends one of the domain-specific applet classes. To help get started, we have created $PTII/bin/ptmkmodel, a shell script that creates stub files for a model in the demo directory. This script is fairly specialized, supporting in particular the construction of Ptolemy II demos. For example, it assumes the applet will reside in the demo of the directory of the appropriate domain. Nonetheless, the script does illustrate several useful naming conventions, and may help some other authors avoid repetitive operations.
The script is invoked with two arguments, the domain and the name of the model. The domain must be a directory in $PTII/ptolemy/domains, and the name of the model must be a directory that does not yet exist in $PTII/ptolemy/domains/domain/demo/name. The Ptolemy naming convention for a model is that the model name starts with a capital letter and has embedded capital letters at the start of each word. The script creates the model directory and creates several files in the directory.
For example, to create a DE model called Ramp, one would run
Which would create the following files:
cd $PTII/ptolemy/domains/de/demo/Ramp
make
make demo
Note that ptmkmodel has a number of limitations.
You may wish to use this script as a starting point for your own, site-specific script.
Unfortunately, Java plug-in technology is fairly immature. In the current version, we have encountered a number of problems, and have found workarounds that we can share.
Sometimes, after running an applet under a browser, a process remains live even after the browser has been exited. This appears to be a bug with the just-in-time (JIT) compiler included in the plug-in. You can configure the plug-in to disable the JIT. On a Windows installation, the plug-in comes with a control panel (look under Programs in the Start menu). Select the "advanced" tab, and disable the JIT. This will noticeably slow down your applets, but you will not have to kill lingering processes.
While developing applets, it is helpful to be able to reload the applet after modifying the Java code. In Netscape, you must use Shift-reload, and in IE, Control-reload. Unfortunately, this does not always cause the applet to be reloaded. A workaround is described on the Sun website, http://java.sun.com/products/plugin/1.2/docs/controlpanel.html, which says:
"Cache JARs in memory. If this option is checked, the applet classes already loaded will be cached and reused when applet is reloaded. This allows much more efficient memory use. You should leave this option unchecked if you are debugging an applet or are always interested in loading the latest applet classes. The default setting is to cache JARs in memory. Warning: turning off this option makes it more likely that you will get OutOfMemoryErrors, as this reduces sharing of memory."
This option is under the "basic" tab of the same control panel described in the previous hint.
In this appendix, we show the code for a more detailed and more interesting applet in the DE domain. This applet illustrates the "inspection paradox," which briefly stated, says that the average amount of time you wait for Poisson arrivals is twice what you might intuitively expect.
The inspection paradox concerns Poisson arrivals of events. The metaphor used in this applet is that of busses and passengers. Passengers arrive according to a Poisson process. Busses arrive either at regular intervals or according to a Poisson process. The user selects from these two options by clicking the appropriate on-screen control. The user can also control the mean interarrival time of both busses and passengers.
The inspection paradox concerns the average time that a passenger waits for a bus (more precisely, the expected value). If the busses arrive at regular intervals with interarrival time equal to T, then the expected waiting time is T/2, which is perfectly intuitive. Counter intuitively, however, if the busses arrive according to a Poisson process with mean interarrival time equal to T, the expected waiting time is T, not T/2. These expected waiting times are approximated in this applet by the average waiting time. The applet also shows that actual arrival times for both passengers and busses, and the waiting time of each passenger.
The intuition that resolves the paradox is as follows. If the busses are arriving according to a Poisson process, then some intervals between busses are larger than other intervals. A particular passenger is more likely to arrive at the bus stop during one of these larger intervals than during one of the smaller intervals. Thus, the expected waiting time is larger if the bus arrival times are irregular.
This paradox is called the inspection paradox because the passengers are viewed as inspecting the Poisson process of bus arrivals.
The applet code is listed below, and is included in the demo directory of the DE domain. A browser window displaying the applet is shown in figure 2.15. In that figure, there are two plots, one showing the events in the model, namely arrivals of busses and passengers plus the waiting time of passengers as they board the busses. The lower plot shows a histogram of waiting times, which has an approximately exponential shape.
There are a number of interesting features of this applet. It includes an instance of Query, at the upper left, with four entries. The first two are entry boxes similar to that in figure 2.10. The third is a different style of entry called a check box. The fourth is a display-only entry that shows final results from execution of the model.
The mechanism used to obtain and display final results is interesting. First, notice below that the applet uses an instance of the Average actor to calculate the average waiting time of a passenger. The output of this actor is fed an instance of Recorder, an actor that simply stores the data it is given for later querying. The final value of the average waiting time is obtained in the executionFinished() method, which is invoked when the execution of the model is completed.
A second interesting feature of this applet is that in the _go() method, depending on the state of the check box query, the model may be modified structurally before it is executed. Subsequent chapters will explain precisely the meaning of the methods that are used to accomplish this modification.
package ptolemy.domains.de.demo.Inspection;
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import java.util.Enumeration;
import ptolemy.kernel.*;
import ptolemy.kernel.util.*;
import ptolemy.data.*;
import ptolemy.actor.Manager;
import ptolemy.actor.lib.*;
import ptolemy.actor.gui.*;
import ptolemy.gui.Query;
import ptolemy.gui.QueryListener;
import ptolemy.domains.de.kernel.*;
import ptolemy.domains.de.lib.*;
import ptolemy.domains.de.gui.DEApplet;
import ptolemy.plot.*;
/** An applet that uses Ptolemy II DE domain to illustrate the inspection paradox.
@author Edward A. Lee and Lukito Muliadi
*/
public class InspectionApplet extends DEApplet implements QueryListener {
///////////////////////////////////////////////////////////////////
//// public methods ////
/** If the argument is the string "regular", then set the
* variable that controls whether bus arrivals will be regular
* or Poisson. If the argument is anything else, update the
* parameters of the model from the values in the query boxes.
* @param name The name of the entry that changed.
*/
public void changed(String name) {
if (name == "regular") {
_regular = _query.booleanValue("regular");
}
try {
if (_regular) {
_regularBus.period.setToken(new DoubleToken(_query.doubleValue("busmean")));
} else {
_poissonBus.meanTime.setToken(new DoubleToken(_query.doubleValue("busmean")));
_passenger1.meanTime.setToken(new DoubleToken(_query.doubleValue("passmean")));
}
_go();
} catch (IllegalActionException ex) {
throw new InternalErrorException(ex.toString());
}
}
/** Override the base class to display the recorded average.
*/
public void executionFinished(Manager manager) {
super.executionFinished(manager);
_query.setDisplay("average", _recorder.getLatest(0));
}
/** Initialize the applet.
*/
public void init() {
super.init();
try {
_query = new Query();
_query.setBackground(_getBackground());
_query.addLine("busmean", "Bus mean interarrival time", "1.0");
_query.addLine("passmean", "Passenger mean interarrival time", "1.0");
_query.addCheckBox("regular", "Regular bus arrivals", false);
_query.addDisplay("average", "Average waiting time of passengers", "");
add(_query);
_query.addQueryListener(this);
// The 2 argument requests a go and stop button.
add(_createRunControls(2));
if (_regular) {
// Create regular bus source.
_regularBus = new Clock(_toplevel, "regularBus");
// Create Poisson bus source, but then remove from the container,
// since it won't be used unless the user toggles the button.
_poissonBus = new Poisson(_toplevel,"poissonBus");
_poissonBus.setContainer(null);
} else {
// Create Poisson bus source.
_poissonBus = new Poisson(_toplevel, "poissonBus");
// Create regular bus source, but then remove from the container,
// since it won't be used unless the user toggles the button.
_regularBus = new Clock(_toplevel,"regularBus");
_regularBus.setContainer(null);
}
// Set default parameters for both sources.
_regularBus.values.setExpression("[2]");
_regularBus.period.setToken(new DoubleToken(1.0));
_regularBus.offsets.setExpression("[0.0]");
_poissonBus.values.setExpression("[2]");
_poissonBus.meanTime.setToken(new DoubleToken(1.0));
// Create and configure the passenger source.
_passenger1 = new Poisson(_toplevel, "passenger");
_passenger1.values.setExpression("[1]");
_passenger1.meanTime.setToken(new DoubleToken(1.0));
// Waiting time.
_wait = new WaitingTime(_toplevel, "waitingTime");
// Average actor.
Average average = new Average(_toplevel, "average");
// Record the average.
_recorder = new Recorder(_toplevel, "recorder");
// Create and configure a plotter.
_eventplot = new TimedPlotter(_toplevel, "plot");
_eventplot.setPanel(this);
_eventplot.plot.setGrid(false);
_eventplot.plot.setTitle("Events");
_eventplot.plot.addLegend(0, "Bus");
_eventplot.plot.addLegend(1, "Passenger");
_eventplot.plot.addLegend(2, "Wait Time");
_eventplot.plot.setXLabel("Time");
_eventplot.plot.setYLabel("Wait time");
_eventplot.plot.setXRange(0.0, _getStopTime());
_eventplot.plot.setYRange(0.0, 4.0);
_eventplot.plot.setSize(450, 200);
_eventplot.plot.setConnected(false);
_eventplot.plot.setImpulses(true);
_eventplot.plot.setMarksStyle("dots");
_eventplot.fillOnWrapup.setToken(new BooleanToken(false));
// Create and configure a histogram.
_histplot = new HistogramPlotter(_toplevel, "histplot");
_histplot.setPanel(this);
_histplot.histogram.setGrid(false);
_histplot.histogram.setTitle("Histogram of Waiting Times");
_histplot.histogram.setXLabel("Waiting Time");
_histplot.histogram.setYLabel("Passengers");
_histplot.histogram.setXRange(0.0, 6.0);
_histplot.histogram.setYRange(0.0, 20.0);
_histplot.histogram.setSize(450, 200);
_histplot.histogram.setBinWidth(0.2);
_histplot.fillOnWrapup.setToken(new BooleanToken(false));
// Connections, except the bus source, which is postponed.
_busRelation = _toplevel.connect(_wait.waitee, _eventplot.input);
ComponentRelation rel2 = _toplevel.connect(_passenger1.output, _eventplot.input);
_wait.waiter.link(rel2);
ComponentRelation rel3 = _toplevel.connect(_wait.output, _eventplot.input);
_histplot.input.link(rel3);
average.input.link(rel3);
_toplevel.connect(average.output, _recorder.input);
_initCompleted = true;
} catch (Exception ex) {
report("Setup failed:", ex);
}
}
///////////////////////////////////////////////////////////////////
//// protected methods ////
/** Execute the model. This overrides the base class to read the
* values in the query box first and set parameters.
* @exception IllegalActionException If the topology changes or the
* model or parameter changes on the actors throw it.
*/
protected void _go() throws IllegalActionException {
// If an exception occurred during initialization, then we don't
// want to run here. The model is probably not complete.
if (!_initCompleted) return;
// If the manager is not idle then either a run is in progress
// or the model has been corrupted. In either case, we do not
// want to run.
if (_manager.getState() != _manager.IDLE) return;
// Depending on the state of the radio button, we may want
// either regularly spaced bus arrivals, or Poisson arrivals.
// Here, we alter the model topology to implement one or the other.
if (_regular) {
try {
_poissonBus.setContainer(null);
_regularBus.setContainer(_toplevel);
} catch (NameDuplicationException ex) {
throw new InternalErrorException(ex.toString());
}
_regularBus.period.setToken
(new DoubleToken(_query.doubleValue("busmean")));
_regularBus.output.link(_busRelation);
} else {
try {
_regularBus.setContainer(null);
_poissonBus.setContainer(_toplevel);
} catch (NameDuplicationException ex) {
throw new InternalErrorException(ex.toString());
}
_poissonBus.meanTime.setToken(new DoubleToken(_query.doubleValue("busmean")));
_passenger1.meanTime.setToken(new DoubleToken(_query.doubleValue("passmean")));
_poissonBus.output.link(_busRelation);
}
// The the X range of the plotter to show the full run.
// The method being called is a protected member of DEApplet.
_eventplot.plot.setXRange(0.0, _getStopTime());
// Clear the average display.
_query.setDisplay("average", "");
// The superclass sets the stop time of the director based on
// the value in the entry box on the screen. Then it starts
// execution of the model in its own thread, leaving the user
// interface of this applet live.
super._go();
}
///////////////////////////////////////////////////////////////////
//// private variables ////
// Actors in the model.
private Query _query;
private Poisson _poissonBus;
private Clock _regularBus;
private Poisson _passenger1;
private TimedPlotter _eventplot;
private HistogramPlotter _histplot;
private WaitingTime _wait;
// An indicator of whether regular or Poisson bus arrivals are desired.
private boolean _regular = false;
// The relation to which links are made and unmade in response to
// changes in the radio button state that selects regular or Poisson
// bus arrivals.
private ComponentRelation _busRelation;
// Flag to prevent spurious exception being thrown by _go() method.
// If this flag is not true, the _go() method will not execute the model.
private boolean _initCompleted = false;
// The observer of the average.
private Recorder _recorder;
}
An applet is a Java program that is downloaded from a web server by a browser and executed in the client's computer (usually within a plug-in for the browser).
ptII at eecs berkeley edu Copyright © 1998-1999, The Regents of the University of California. All rights reserved.