001/* The DE domain director.
002
003 Copyright (c) 1998-2018 The Regents of the University of California.
004 All rights reserved.
005 Permission is hereby granted, without written agreement and without
006 license or royalty fees, to use, copy, modify, and distribute this
007 software and its documentation for any purpose, provided that the above
008 copyright notice and the following two paragraphs appear in all copies
009 of this software.
010
011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
015 SUCH DAMAGE.
016
017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
022 ENHANCEMENTS, OR MODIFICATIONS.
023
024 PT_COPYRIGHT_VERSION_2
025 COPYRIGHTENDKEY
026 */
027package ptolemy.domains.de.kernel;
028
029import java.util.ArrayList;
030import java.util.Collection;
031import java.util.HashMap;
032import java.util.HashSet;
033import java.util.Iterator;
034import java.util.List;
035import java.util.Set;
036
037import ptolemy.actor.Actor;
038import ptolemy.actor.ActorExecutionAspect;
039import ptolemy.actor.CompositeActor;
040import ptolemy.actor.Director;
041import ptolemy.actor.FiringEvent;
042import ptolemy.actor.IOPort;
043import ptolemy.actor.Manager;
044import ptolemy.actor.QuasiTransparentDirector;
045import ptolemy.actor.Receiver;
046import ptolemy.actor.SuperdenseTimeDirector;
047import ptolemy.actor.util.CausalityInterface;
048import ptolemy.actor.util.CausalityInterfaceForComposites;
049import ptolemy.actor.util.Dependency;
050import ptolemy.actor.util.Time;
051import ptolemy.data.BooleanToken;
052import ptolemy.data.IntToken;
053import ptolemy.data.Token;
054import ptolemy.data.expr.Parameter;
055import ptolemy.data.type.BaseType;
056import ptolemy.kernel.CompositeEntity;
057import ptolemy.kernel.util.Attribute;
058import ptolemy.kernel.util.DebugListener;
059import ptolemy.kernel.util.IllegalActionException;
060import ptolemy.kernel.util.InternalErrorException;
061import ptolemy.kernel.util.KernelException;
062import ptolemy.kernel.util.NameDuplicationException;
063import ptolemy.kernel.util.Nameable;
064import ptolemy.kernel.util.NamedObj;
065import ptolemy.kernel.util.Settable;
066import ptolemy.kernel.util.Workspace;
067
068///////////////////////////////////////////////////////////////////
069//// DEDirector
070
071/**
072 <p>This director implements the discrete-event (DE) model of computation (MoC).
073 It should be used as the local director of a CompositeActor that is
074 to be executed according to the DE MoC. This director maintains a totally
075 ordered set of events and processes these events in the order defined on
076 their tags and depths.
077 </p><p>
078 An event is associated with a tag, which is a tuple of timestamp and
079 microstep. A timestamp indicates the model time when this event occurs. It
080 is an object of the {@link ptolemy.actor.util.Time} class. A microstep is an
081 integer which represents the index of the sequence of execution phases when
082 this director processes events with the same timestamp. Two tags are equal
083 if they have the same timestamp and microstep. If two events have the same
084 tag, they are called simultaneous events.
085 </p><p>
086 Microsteps can only be increased by calling the fireAt() method. For example,
087 when an actor requests to be fired again at the current model time, a
088 new event with the same timestamp but a bigger microstep (incremented by 1)
089 will be generated.
090 </p><p>
091 An event is also associated with a depth reflecting its priority, based
092 on which a DE director chooses the execution order for simultaneous events.
093 A depth is an integer and a larger value of depth indicates a lower priority.
094 The depth of an event is determined by topologically sorting all the ports
095 of actors according to their data dependencies over which there is no time
096 delay.
097 </p><p>
098 The order of events is defined as follows. An event A is said to be earlier
099 than another event B if A's timestamp is smaller than B's; or if A's
100 timestamp is the same as B's, and A's microstep is smaller than B's; or if
101 A's tag is the same as B's, and A's depth is smaller than B's. By giving
102 events this well-defined order, this director can handle simultaneous events
103 in a deterministic way.
104 </p><p>
105 The bottleneck in a typical DE simulator is in the maintenance of the
106 global event queue. This director uses the calendar queue as the global
107 event queue. This is an efficient algorithm with O(1) time complexity in
108 both enqueue and dequeue operations. Sorting in the
109 {@link ptolemy.actor.util.CalendarQueue} class is done according to the
110 order defined above.
111 </p><p>
112 The complexity of the calendar algorithm is sensitive to the length of the
113 event queue. When the size of the event queue becomes too long or changes
114 very often, the simulation performance suffers from the penalties of queuing
115 and dequeuing events. A few mechanisms are implemented to reduce such
116 penalties by keeping the event queue short. The first mechanism is to only
117 store in the event queue <i>pure</i> events and the <i>trigger</i> events
118 with the same timestamp and microstep as those of the director. See
119 {@link DEEvent} for explanation of these two types of events. What is more,
120 no duplicate trigger events are allowed in the event queue. Another mechanism
121 is that in a hierarchical model, each level keeps a local event queue.
122 A lower level only reports the earliest event to its upper level
123 to schedule a future firing. The last mechanism is to maintain a list which
124 records all actors that are disabled. Any triggers sent to the actors in
125 this list are discarded.
126 </p><p>
127 In the initialize() method, depths of actors and IO ports are statically
128 analyzed and calculated. They are not calculated in the preinitialize()
129 method because hierarchical models may change their structures during their
130 preinitialize() method. For example, a modal model does not specify its
131 initial state (and its refinement) until the end of its preinitialize()
132 method. See {@link ptolemy.domains.modal.kernel.FSMActor}. In order to support
133 mutation, this director recalculates the depths at the beginning of its next
134 iteration.
135 </p><p>
136 There are two types of depths: one is associated with IO ports, which
137 reflects the order of trigger events; the other one is associated with
138 actors, which is for pure events. The relationship between the depths of IO
139 ports and actors is that the depth of an actor is the smallest of the depths
140 of its IO ports. Pure events can only be produced by calling the fireAt()
141 method, and trigger events can only be produced by actors that produce
142 outputs. See {@link ptolemy.domains.de.kernel.DEReceiver#put(Token)}.
143 </p><p>
144 Directed loops of IO ports with no delay will trigger an exception.
145 These are called <i>causality loops</i>. Such loops can be broken with
146 actors whose output ports do not have an immediate dependence on their
147 input ports, such as the <i>TimeDelay</i> actor.  Notice that the
148 <i>TimeDelay</i> actor breaks a causality loop even if the time
149 delay is set to 0.0. This is because DE uses a <i>superdense</i>
150 notion of time.  The output is interpreted as being strictly later
151 than the input even though its time value is the same.
152 Whether a causality loop exists is determined by the
153 {@link ptolemy.actor.util.CausalityInterface} returned by each actor's
154 getCausalityInterface() method.
155 </p><p>
156 An input port in a DE model contains an instance of DEReceiver.
157 When a token is put into a DEReceiver, that receiver posts a trigger
158 event to the director. This director sorts trigger events in a global event
159 queue.
160 </p><p>
161 An iteration, in the DE domain, is defined as processing all the events
162 whose tags are equal to the current tag of the director (also called the
163 model tag). At the beginning of the fire() method, this director dequeues
164 a subset of the earliest events (the ones with smallest timestamp, microstep,
165 and depth) that have the same destination actor
166 from the global event queue. Then, this director fires that actor.
167 This actor must consume tokens from its input port(s),
168 and usually produces new events on its output port(s). These new events will
169 trigger the destination actors to fire. It is important that the actor
170 actually consumes tokens from its inputs, even if the tokens are solely
171 used to trigger reactions, because the actor will be fired repeatedly
172 until there are no more tokens in its input ports with the same tag,
173 or until the actor returns false in its prefire() method. The
174 director then keeps dequeuing and processing the earliest events from the
175 event queue until no more events have the same tag.
176 </p><p>
177 Note that each time this director fires an actor, it
178 also invokes postfire() on that actor.
179 Note that under this policy, it is possible for an actor to be fired and postfired
180 multiple times in an iteration.
181 This does not really correctly implement superdense time semantics, but it is
182 an approximation that will reject some models that should be able to be executed.
183 An actor like the TimeDelay will be fired (and postfired) multiple times
184 at a superdense time index if it is in a feedback loop.
185 </p><p>
186 A model starts from the time specified by <i>startTime</i>. This is blank
187 by default, which indicates that the start time is the current time of
188 the enclosing director, if there is one, and 0.0 otherwise.
189 The stop time of the execution can be set
190 using the <i>stopTime</i> parameter. The parameter has a default value
191 <i>Infinity</i>, which means the execution runs forever.
192 </p><p>
193 Execution of a DE model ends when the timestamp of the earliest event
194 exceeds the stop time. This stopping condition is checked inside
195 the postfire() method of this director. By default, execution also ends
196 when the global event queue becomes empty. Sometimes, the desired
197 behaviour is for the director to wait on an empty queue until another
198 thread makes new events available. For example, a DE actor may produce
199 events when a user hits a button on the screen. To prevent ending the
200 execution when there are no more events, set the
201 <i>stopWhenQueueIsEmpty</i> parameter to <code>false</code>.
202 </p><p>
203 Parameters <i>isCQAdaptive</i>, <i>minBinCount</i>, and
204 <i>binCountFactor</i>, are used to configure the calendar queue.
205 Changes to these parameters are ignored when the model is running.
206 </p><p>
207 If the parameter <i>synchronizeToRealTime</i> is set to <code>true</code>,
208 then the director will not process events until the real time elapsed
209 since the model started matches the timestamp of the event.
210 This ensures that the director does not get ahead of real time. However,
211 of course, this does not ensure that the director keeps up with real time.
212 </p><p>
213 This director tolerates changes to the model during execution.
214 The change should be queued with a component in the hierarchy using
215 requestChange().  While invoking those changes, the method
216 invalidateSchedule() is expected to be called, notifying the director
217 that the topology it used to calculate the priorities of the actors
218 is no longer valid.  This will result in the priorities (depths of actors)
219 being recalculated the next time prefire() is invoked.
220 </p><p>
221 <b>Limitations</b>: According to [1], at each microstep, DE should
222 perform a fixed point iteration. This implementation does not do that,
223 and consequently, this director is not able to execute all correctly
224 constructed DE models. For an example, see
225 $PTII/ptolemy/domains/de/test/auto/DEFixedPointLimitation.xml.
226 That example has a DE opaque composite actor in a feedback loop.
227 In principle, there should be no causality loop. The actor output
228 should be able to be produced without knowing the input. However,
229 the inside director has to guarantee that when it fires any of
230 its contained actors, all inputs of a given microstep are available
231 to that actor. As a consequence, the opaque actor also needs to know
232 all of its inputs at the current microstep. Hence, a causality loop
233 is reported. We encourage the reader to make a variant of this director
234 that can handle such models.
235  </p><p>
236 <b>References</b>:
237 <br>
238 [1] Lee, E. A. and H. Zheng (2007). Leveraging Synchronous Language
239 Principles for Heterogeneous Modeling and Design of Embedded Systems.
240 EMSOFT, Salzburg, Austria, October, ACM.
241
242 @author Lukito Muliadi, Edward A. Lee, Jie Liu, Haiyang Zheng
243 @version $Id$
244 @since Ptolemy II 0.2
245 @Pt.ProposedRating Green (hyzheng)
246 @Pt.AcceptedRating Yellow (hyzheng)
247 */
248public class DEDirector extends Director implements SuperdenseTimeDirector {
249
250    /* NOTE: This implementation of DE has a very subtle bug documented in the
251     * following test:
252     *   $PTII/ptolemy/domains/de/test/auto/knownFailedTests/DirectFeedback.xml
253     * This test exposes a subtle bug in DE that is probably not worth
254     * fixing because the only fix I can find would incur considerable
255     * overhead on every event transaction, and it is rather difficult to
256     * write an actor that will trigger the bug. The SuperdensTimeTest
257     * actor used in this test is such an actor, but as of this writing,
258     * there are no such actor in the library.
259     *
260     * The bug occurs when an actor declares that an output port does
261     * not depend on any input (something that is rather hard to do
262     * correctly), and then feeds back a signal directly
263     * from the output to an input. The bug is that an output token
264     * produced by the actor may be visible to the actor in the very same
265     * firing of the actor, or in postfire of the same iteration. This violates
266     * a principle in DE that when an actor firing begins, all inputs at
267     * the current superdense time are available.
268     */
269
270    /** Construct a director in the default workspace with an empty string
271     *  as its name. The director is added to the list of objects in
272     *  the workspace. Increment the version number of the workspace.
273     *  @exception NameDuplicationException If construction of Time objects fails.
274     *  @exception IllegalActionException If construction of Time objects fails.
275     */
276    public DEDirector()
277            throws IllegalActionException, NameDuplicationException {
278        super();
279        _initParameters();
280    }
281
282    /** Construct a director in the workspace with an empty name.
283     *  The director is added to the list of objects in the workspace.
284     *  Increment the version number of the workspace.
285     *  @param workspace The workspace of this object.
286     *  @exception NameDuplicationException If construction of Time objects fails.
287     *  @exception IllegalActionException If construction of Time objects fails.
288     */
289    public DEDirector(Workspace workspace)
290            throws IllegalActionException, NameDuplicationException {
291        super(workspace);
292        _initParameters();
293    }
294
295    /** Construct a director in the given container with the given name.
296     *  The container argument must not be null, or a
297     *  NullPointerException will be thrown.
298     *  If the name argument is null, then the name is set to the
299     *  empty string. Increment the version number of the workspace.
300     *  @param container Container of the director.
301     *  @param name Name of this director.
302     *  @exception IllegalActionException If the
303     *   director is not compatible with the specified container.
304     *  @exception NameDuplicationException If the container not a
305     *   CompositeActor and the name collides with an entity in the container.
306     */
307    public DEDirector(CompositeEntity container, String name)
308            throws IllegalActionException, NameDuplicationException {
309        super(container, name);
310        _initParameters();
311    }
312
313    ///////////////////////////////////////////////////////////////////
314    ////                         parameters                        ////
315
316    /** The factor when adjusting the bin number.
317     *  This parameter must contain an IntToken.
318     *  Changes to this parameter are ignored when the model is running.
319     *  The value defaults to 2.
320     */
321    public Parameter binCountFactor;
322
323    /** A flag indicating whether this director should enforce
324     *  microstep semantics, throwing an exception when actors
325     *  deliver events at microstep 0. Such events can arise from
326     *  attempting to deliver to the DE domain a continuous signal
327     *  from the Continuous domain. This is a boolean that defaults
328     *  to false.
329     */
330    public Parameter enforceMicrostepSemantics;
331
332    /** Specify whether the calendar queue adjusts its bin number
333     *  at run time. This parameter must contain a BooleanToken.
334     *  If this parameter is true, the calendar queue will adapt
335     *  its bin number with respect to the distribution of events.
336     *  Changes to this parameter are ignored when the model is running.
337     *  The value defaults to true.
338     */
339    public Parameter isCQAdaptive;
340
341    /** The minimum (initial) number of bins in the calendar queue.
342     *  This parameter must contain an IntToken.
343     *  Changes to this parameter are ignored when the model is running.
344     *  The value defaults to 2.
345     */
346    public Parameter minBinCount;
347
348    /** Specify whether the execution stops when the queue is empty.
349     *  This parameter must contain a
350     *  BooleanToken. If this parameter is true, the
351     *  execution of the model will be stopped when the queue is empty.
352     *  The value defaults to true.
353     */
354    public Parameter stopWhenQueueIsEmpty;
355
356    /** Specify whether the execution should synchronize to the
357     *  real time. This parameter must contain a BooleanToken.
358     *  If this parameter is true, then do not process events until the
359     *  elapsed real time matches the time stamp of the events.
360     *  The value defaults to false.
361     */
362    public Parameter synchronizeToRealTime;
363
364    ///////////////////////////////////////////////////////////////////
365    ////                         public methods                    ////
366
367    /** Append the specified listener to the current set of debug listeners.
368     *  If an event queue has been created, register the listener to that queue.
369     *  @param listener The listener to be added to the list of listeners
370     *  to which debug messages are sent.
371     *  @see #removeDebugListener(DebugListener)
372     */
373    @Override
374    public void addDebugListener(DebugListener listener) {
375        if (_eventQueue != null) {
376            synchronized (_eventQueueLock) {
377                _eventQueue.addDebugListener(listener);
378            }
379        }
380
381        super.addDebugListener(listener);
382    }
383
384    /** Update the director parameters when attributes are changed.
385     *  Changes to <i>isCQAdaptive</i>, <i>minBinCount</i>, and
386     *  <i>binCountFactor</i> parameters will only be effective on
387     *  the next time when the model is executed.
388     *  @param attribute The changed parameter.
389     *  @exception IllegalActionException If the parameter set is not valid.
390     *  Not thrown in this class.
391     */
392    @Override
393    public void attributeChanged(Attribute attribute)
394            throws IllegalActionException {
395        if (attribute == stopWhenQueueIsEmpty) {
396            _stopWhenQueueIsEmpty = ((BooleanToken) stopWhenQueueIsEmpty
397                    .getToken()).booleanValue();
398        } else if (attribute == synchronizeToRealTime) {
399            _synchronizeToRealTime = ((BooleanToken) synchronizeToRealTime
400                    .getToken()).booleanValue();
401        } else if (attribute == enforceMicrostepSemantics) {
402            _enforceMicrostepSemantics = ((BooleanToken) enforceMicrostepSemantics
403                    .getToken()).booleanValue();
404        } else {
405            super.attributeChanged(attribute);
406        }
407    }
408
409    /** Cancel a requested firing of the given actor at the given model
410     *  time microstep 1.
411     *  @param actor The actor scheduled to be fired.
412     *  @param time The requested time.
413     *  @exception IllegalActionException If cancelling a firing is not
414     *   supported by the current event queue.
415     */
416    public void cancelFireAt(Actor actor, Time time)
417            throws IllegalActionException {
418        cancelFireAt(actor, time, 1);
419    }
420
421    /** Cancel a requested firing of the given actor at the given model
422     *  time with the given microstep.
423     *  @param actor The actor scheduled to be fired.
424     *  @param time The requested time.
425     *  @param index The microstep.
426     *  @exception IllegalActionException If cancelling a firing is not
427     *   supported by the current event queue.
428     */
429    public void cancelFireAt(Actor actor, Time time, int index)
430            throws IllegalActionException {
431        if (_eventQueue == null) {
432            throw new IllegalActionException(this,
433                    "Calling cancelFireAt() before preinitialize().");
434        }
435        if (_debugging) {
436            _debug("DEDirector: Cancelling firing of actor "
437                    + actor.getFullName() + " at " + time + " with microstep "
438                    + index);
439        }
440        int depth = _getDepthOfActor(actor);
441        _eventQueue.remove(new DEEvent(actor, time, index, depth));
442    }
443
444    /** Clone the object into the specified workspace. The new object is
445     *  <i>not</i> added to the directory of that workspace (you must do this
446     *  yourself if you want it there).
447     *  The result is an attribute with no container.
448     *  @param workspace The workspace for the cloned object.
449     *  @exception CloneNotSupportedException Not thrown in this base class
450     *  @return The new Attribute.
451     */
452    @Override
453    public Object clone(Workspace workspace) throws CloneNotSupportedException {
454        DEDirector newObject = (DEDirector) super.clone(workspace);
455        newObject._disabledActors = null;
456        newObject._eventQueue = null;
457        newObject._eventQueueLock = new Object();
458        newObject._exceedStopTime = false;
459        newObject._isInitializing = false;
460        newObject._microstep = 1;
461        newObject._noMoreActorsToFire = false;
462        newObject._stopFireRequested = false;
463        return newObject;
464    }
465
466    /** Return a string that describes the depths of actors and their ports.
467     *  These depths are used to prioritize firings, where lower depths
468     *  result in higher priorities.
469     *  @return A string that describes the depths of actors and their ports.
470     *  @exception IllegalActionException If there is a causality loop.
471     */
472    public String describePriorities() throws IllegalActionException {
473        CompositeActor container = (CompositeActor) getContainer();
474        CausalityInterfaceForComposites causality = (CausalityInterfaceForComposites) container
475                .getCausalityInterface();
476        return causality.describeDepths();
477    }
478
479    /** Fire actors according to events in the event queue. The actual
480     *  selecting which events to process is done in _fire(). _fire()
481     *  will return whether the previous firing was successful. According
482     *  to this information, it is decided whether _fire() should be called
483     *  again in order to keep processing events. After each actor firing,
484     *  book keeping procedures are called, to keep track of the current
485     *  state of the scheduler. The model time of the next events are also
486     *  checked to see if we have produced an event of smaller timestamp.
487     *  @see #_fire
488     *  @exception IllegalActionException If we couldn't process an event
489     *  or if an event of smaller timestamp is found within the event queue.
490     */
491    @Override
492    public void fire() throws IllegalActionException {
493        if (_debugging) {
494            _debug("========= " + this.getName() + " director fires at "
495                    + getModelTime() + "  with microstep as " + _microstep);
496        }
497
498        // NOTE: This fire method does not call super.fire()
499        // because this method is very different from that of the super class.
500        // A BIG while loop that handles all events with the same tag.
501        while (true) {
502            int result = _fire();
503            assert result <= 1 && result >= -1;
504            if (result == 1) {
505                continue;
506            } else if (result == -1) {
507                _noActorToFire();
508                return;
509            } // else if 0, keep executing
510
511            // after actor firing, the subclass may wish to perform some book keeping
512            // procedures. However in this class the following method does nothing.
513            _actorFired();
514
515            if (!_checkForNextEvent()) {
516                break;
517            } // else keep executing in the current iteration
518        } // Close the BIG while loop.
519
520        // Since we are now actually stopping the firing, we can set this false.
521        _stopFireRequested = false;
522
523        if (_debugging) {
524            _debug("DE director fired!");
525        }
526    }
527
528    /** Schedule an actor to be fired at the specified time by posting
529     *  a pure event to the director, and return the time at which
530     *  the specified actor will be fired. If the requested time is in the past
531     *  relative to the current time, then it will be increased to match
532     *  current time. The caller to this method is responsible for throwing
533     *  an exception if it is not acceptable for that time to differ from
534     *  the requested time.
535     *  <p>
536     *  If this director is embedded within another model (the container
537     *  has an executive director), and this method is being called between
538     *  iterations of this director (which can only occur from a thread
539     *  different from the one firing this director), then
540     *  this method also delegates a request to the executive director
541     *  to fire the container of this director at the requested time.
542     *  If the executive director returns a value different from the
543     *  specified time, then this method will use that revised value
544     *  to schedule the firing of the specified actor, and will return
545     *  that value.
546     *  <p>
547     *  A subtle corner case can occur in a multithreaded execution that
548     *  will trigger an exception. In particular, it is possible for this
549     *  director to delegate a request to its executive director, and
550     *  for that request to be honored before it has posted the event
551     *  on its own local event queue. This situation is avoided, for
552     *  example, by putting this director within a ThreadedComposite
553     *  actor. If this situation occurs, an exception will be thrown.
554     *  @param actor The scheduled actor to fire.
555     *  @param time The scheduled time to fire.
556     *  @return The time at which the actor will be fired, which matches
557     *   the argument.
558     *  @exception IllegalActionException If the event queue is not ready,
559     *   or if a threading error occurs that would result in returning
560     *   a time value that is already in the past.
561     */
562    @Override
563    public Time fireAt(Actor actor, Time time) throws IllegalActionException {
564        return fireAt(actor, time, 1);
565    }
566
567    /** Request a firing of the given actor at the given model
568     *  time with the given microstep. Most actors will not want to use
569     *  this method, but if you need for a firing to occur at microstep 0,
570     *  then use this method to trigger that firing. Note that any actor
571     *  that fires at microstep 0 is expected to not produce any output
572     *  events at that firing.
573     *  @param actor The actor scheduled to be fired.
574     *  @param time The requested time.
575     *  @param index The microstep.
576     *  @return An instance of Time with value NEGATIVE_INFINITY, or
577     *   if there is an executive director, the time at which the
578     *   container of this director will next be fired
579     *   in response to this request.
580     *  @see #fireAtCurrentTime(Actor)
581     *  @exception IllegalActionException If there is an executive director
582     *   and it throws it. Derived classes may choose to throw this
583     *   exception for other reasons.
584     */
585    @Override
586    public Time fireAt(Actor actor, Time time, int index)
587            throws IllegalActionException {
588        if (_eventQueue == null) {
589            throw new IllegalActionException(this,
590                    "Calling fireAt() before preinitialize().");
591        }
592        if (_debugging) {
593            _debug("DEDirector: Actor " + actor.getFullName()
594                    + " requests refiring at " + time + " with microstep "
595                    + index);
596        }
597        // Normally, we do not need to delegate the request up
598        // the hierarchy. This will be done in postfire.
599        // We want to keep event queues at all levels in hierarchy
600        // as short as possible. So, this pure event is not reported
601        // to the higher level in hierarchy immediately. The postfire
602        // method of this director will report the next
603        // earliest event in the event queue to the higher level.
604        // However, if this request is occurring between iterations within
605        // an opaque composite actor, then postfire() will not
606        // be invoked again to pass this fireAt() request up
607        // the hierarchy to the executive director.  We
608        // have to pass it up here. We need to do this before
609        // enqueueing the local event because the enclosing director
610        // may return a different time from the one we specified.
611        // We would like to prevent time from advancing while this request
612        // is passed up the chain. Otherwise, the enclosing executive
613        // director could respond to the fireAt() request before we
614        // get our own request posted on the event queue. This has the
615        // unfortunate cost of resulting in multiple nested synchronized
616        // blocks being possible, which will almost certainly trigger a
617        // deadlock. Hence, we cannot do the following within the synchronized
618        // block. Instead, we have to check for the error after the synchronized
619        // block and throw an exception.
620        Time result = time;
621        if (_delegateFireAt) {
622            if (result.compareTo(getModelTime()) < 0) {
623                // NOTE: There is no assurance in a multithreaded situation
624                // that time will not advance prior to the posting of
625                // this returned time on the local event queue, so
626                // an exception can still occur reporting an attempt
627                // to post an event in the past.
628                result = getModelTime();
629            }
630            CompositeActor container = (CompositeActor) getContainer();
631            if (_debugging) {
632                _debug("DEDirector: Requests refiring of container: "
633                        + container.getName() + " at time " + time
634                        + " with microstep " + index);
635            }
636            // Enqueue a pure event to fire the container of this director.
637            // Note that if the enclosing director is ignoring fireAt(),
638            // or if it cannot refire at exactly the requested time,
639            // then the following will throw an exception.
640            result = fireContainerAt(result, index);
641        }
642        synchronized (_eventQueueLock) {
643            if (!_delegateFireAt) {
644                // If we have not made a request to the executive director,
645                // then we can modify time here. If we have, then we can't,
646                // but if the time of that request is now in the past,
647                // we will throw an exception with an attempt to post
648                // an event in the past.
649                if (result.compareTo(getModelTime()) < 0) {
650                    // NOTE: There is no assurance in a multithreaded situation
651                    // that time will not advance prior to the posting of
652                    // this returned time on the local event queue, so
653                    // an exception can still occur reporting an attempt
654                    // to post an event in the past.
655                    result = getModelTime();
656                }
657            }
658            if (result.compareTo(getModelTime()) == 0 && index <= _microstep
659                    && !_isInitializing) {
660                // NOTE: Incrementing the microstep here is wrong if we are in initialize().
661                index = _microstep + 1;
662
663                if (index == Integer.MAX_VALUE) {
664                    throw new IllegalActionException(this, actor,
665                            "Microstep has hit the maximum while scheduling a firing of "
666                                    + actor.getFullName()
667                                    + ". Perhaps the model has a stuttering Zeno Condition?");
668                }
669            }
670
671            _enqueueEvent(actor, result, index);
672
673            // Findbugs: Multithreaded correctness,
674            // [M M MWN] Mismatched notify() [MWN_MISMATCHED_NOTIFY]
675            //    This method calls Object.notify() or Object.notifyAll()
676            //    without obviously holding a lock on the object.
677            //    Calling notify() or notifyAll() without a lock
678            //    held will result in an IllegalMonitorStateException
679            //    being thrown.
680            // Actually, this seems to be Find Bugs error since the
681            // statement is within a synchronized (_eventQueueLock) block.
682            _eventQueueLock.notifyAll();
683        }
684        return result;
685    }
686
687    /** Fire the actor actor at the current model time or, if synchronizeToRealTime
688     *  is enabled and we are past the initialization phase of execution,
689     *  then fire the actor at the model time that corresponds to the current
690     *  real time. This model time is computed by subtracting the model start time
691     *  recorded by this director at the beginning of the simulation from the
692     *  system time and dividing by 1000, as the default unit of time is seconds.
693     *  @param actor The actor to be fired.
694     *  @return The model time the actor will be fired at.
695     *  @exception IllegalActionException If thrown while creating a Time object
696     *  or while calling fireAt.
697     */
698    @Override
699    public Time fireAtCurrentTime(Actor actor) throws IllegalActionException {
700        if (_synchronizeToRealTime && !_isInitializing) {
701            long elapsedTime = elapsedTimeSinceStart();
702            // NOTE: The Time constructor that takes a long argument interprets
703            // that long as a multiple of the time resolution.
704            // Hence, we use the static milliseconds() method.
705            Time modelTimeForCurrentRealTime = Time.milliseconds(this,
706                    elapsedTime);
707            return fireAt(actor, modelTimeForCurrentRealTime);
708        } else {
709            // NOTE: We do not need to override the functionality of
710            // fireAtCurrentTime(Actor) because in
711            // the base class it does the right thing. In particular, it attempts
712            // to fire at the time returned by getModelTime(), but if by the time
713            // it enters the synchronized block that time is in the past, it
714            // adjusts the time to match current time. This is exactly what
715            // fireAtCurrentTime(Actor) should do.
716            return super.fireAtCurrentTime(actor);
717        }
718    }
719
720    /** Schedule an actor to be fired in the specified time relative to
721     *  the current model time.
722     *  @param actor The scheduled actor to fire.
723     *  @param time The scheduled time to fire.
724     *  @exception IllegalActionException If the specified time contains
725     *  a negative time value, or event queue is not ready.
726     */
727    public void fireAtRelativeTime(Actor actor, Time time)
728            throws IllegalActionException {
729        fireAt(actor, time.add(getModelTime()));
730    }
731
732    /** Return a causality interface for the composite actor that
733     *  contains this director. This base class returns an
734     *  instance of {@link CausalityInterfaceForComposites}, but
735     *  subclasses may override this to return a domain-specific
736     *  causality interface.
737     *  @return A representation of the dependencies between input ports
738     *   and output ports of the container.
739     */
740    @Override
741    public CausalityInterface getCausalityInterface() {
742        return new DECausalityInterface((Actor) getContainer(),
743                defaultDependency());
744    }
745
746    /** Get the current microstep.
747     *  @return microstep of the current time.
748     *  @see #getIndex()
749     *  @see #setIndex(int)
750     *  @see ptolemy.actor.SuperdenseTimeDirector
751     */
752    public int getMicrostep() {
753        return _microstep;
754    }
755
756    /* Return the event queue. Note that this method is not synchronized.
757     *  Any further accesses to this event queue needs synchronization.
758     *  @return The event queue.
759     */
760    /* Appears to not be used, and seems dangerous anyway
761     * since accesses to the event queue need to be synchronized.
762    public DEEventQueue getEventQueue() {
763        return _eventQueue;
764    }
765     */
766
767    /** Return the timestamp of the next event in the queue.
768     *  The next iteration time, for example, is used to estimate the
769     *  run-ahead time, when a continuous time composite actor is embedded
770     *  in a DE model. If there is no event in the event queue, a positive
771     *  infinity object is returned.
772     *  @return The time stamp of the next event in the event queue.
773     * @exception IllegalActionException If Time object cannot be created.
774     */
775    @Override
776    public Time getModelNextIterationTime() throws IllegalActionException {
777        Time aFutureTime = Time.POSITIVE_INFINITY;
778
779        synchronized (_eventQueueLock) {
780            // Record the model next iteration time as the tag of the the earliest
781            // event in the queue.
782            if (_eventQueue.size() > 0) {
783                aFutureTime = _eventQueue.get().timeStamp();
784            }
785
786            // Iterate the event queue to find the earliest event with a bigger tag
787            // ((either timestamp or microstop). If such an event exists,
788            // use its time as the model next iteration time. If no such event
789            // exists, it means that the model next iteration time still needs to
790            // be resolved. In other words, the model next iteration time is
791            // just the current time.
792            Object[] events = _eventQueue.toArray();
793            for (Object event2 : events) {
794                DEEvent event = (DEEvent) event2;
795                Time eventTime = event.timeStamp();
796                int eventMicrostep = event.microstep();
797                if (eventTime.compareTo(getModelTime()) > 0
798                        || eventMicrostep > _microstep) {
799                    aFutureTime = eventTime;
800                    break;
801                }
802            }
803        }
804        // Go through hierarchy to find the minimum step.
805        Director executiveDirector = ((CompositeActor) getContainer())
806                .getExecutiveDirector();
807        // Some composites, such as RunCompositeActor want to be treated
808        // as if they are at the top level even though they have an executive
809        // director, so be sure to check _isTopLevel().
810        if (executiveDirector != null && !_isTopLevel()) {
811
812            Time aFutureTimeOfUpperLevel = localClock
813                    .getLocalTimeForEnvironmentTime(
814                            executiveDirector.getModelNextIterationTime());
815
816            if (aFutureTime.compareTo(aFutureTimeOfUpperLevel) > 0) {
817                aFutureTime = aFutureTimeOfUpperLevel;
818            }
819        }
820
821        return aFutureTime;
822    }
823
824    /** Return the timestamp of the next event in the queue. This is
825     *  different from getModelNextIterationTime as it just considers
826     *  the local event queue and not that of directors higher up in
827     *  the model hierarchy.
828     *  @return The timestamp of the next event in the local event
829     *  queue.
830     */
831    public Time getNextEventTime() {
832        if (_eventQueue.size() == 0) {
833            return null;
834        }
835        return _eventQueue.get().timeStamp();
836    }
837
838    /** Return the start time parameter value.
839     *  <p>
840     *  When the start time is too big, the double representation loses
841     *  the specified time resolution. To avoid this loss, use the
842     *  {@link #getModelStartTime()} instead.</p>
843     *  @return the start time.
844     *  @exception IllegalActionException If the enclosing director throws it.
845     *  @deprecated As Ptolemy II 4.1, use {@link #getModelStartTime()}
846     *  instead.
847     */
848    @Deprecated
849    @Override
850    public final double getStartTime() throws IllegalActionException {
851        // This method is final for performance reason.
852        return getModelStartTime().getDoubleValue();
853    }
854
855    /** Return the stop time.
856     *  <p>
857     *  When the stop time is too big, the double representation loses
858     *  the specified time resolution. To avoid this loss, use the
859     *  {@link #getModelStopTime()} instead.</p>
860     *  @return the stop time.
861     *  @exception IllegalActionException If getModelStopTime() throws it.
862     *  @deprecated As Ptolemy II 4.1, use {@link #getModelStopTime()}
863     *  instead.
864     */
865    @Deprecated
866    @Override
867    public final double getStopTime() throws IllegalActionException {
868        // This method is final for performance reason.
869        return getModelStopTime().getDoubleValue();
870    }
871
872    /** Return a superdense time index for the current time,
873     *  where the index is equal to the microstep.
874     *  @return A superdense time index.
875     *  @see #setIndex(int)
876     *  @see ptolemy.actor.SuperdenseTimeDirector
877     */
878    @Override
879    public int getIndex() {
880        return _microstep;
881    }
882
883    /** Initialize all the contained actors by invoke the initialize() method
884     *  of the super class. If any events are generated during the
885     *  initialization, and the container is not at the top level, request a
886     *  refiring.
887     *  <p>
888     *  The real start time of the model is recorded when this method
889     *  is called. This method is <i>not</i> synchronized on the workspace,
890     *  so the caller should be.</p>
891     *
892     *  @exception IllegalActionException If the initialize() method of
893     *   the super class throws it.
894     */
895    @Override
896    public void initialize() throws IllegalActionException {
897        _isInitializing = true;
898
899        synchronized (_eventQueueLock) {
900            _eventQueue.clear();
901
902            // Reset the following private variables.
903            _disabledActors = null;
904            _exceedStopTime = false;
905            _noMoreActorsToFire = false;
906            _stopFireRequested = false;
907
908            // Initialize the microstep to zero, even though
909            // DE normally wants to run with microstep 1 or higher.
910            // During initialization, some contained actors will request
911            // firings. One of those might be a Continuous subsystem,
912            // which will explicitly request a firing at microstep 0.
913            // Others will have their requests automatically set
914            // to microstep 1. Thus, with normal DE-only models,
915            // the only events in the event queue after initialization
916            // will all have microstep 1, and hence that is where the
917            // simulation will start.
918            _microstep = 0;
919            // This could be getting re-initialized during execution
920            // (e.g., if we are inside a modal model), in which case,
921            // if the enclosing director is a superdense time director,
922            // we should initialize to its microstep, not to our own.
923            // NOTE: Some (weird) directors pretend they are not embedded even
924            // if they are (e.g. in Ptides), so we call _isEmbedded() to give
925            // the subclass the option of pretending it is not embedded.
926            if (isEmbedded()) {
927                Nameable container = getContainer();
928                if (container instanceof CompositeActor) {
929                    Director executiveDirector = ((CompositeActor) container)
930                            .getExecutiveDirector();
931                    // Some composites, such as RunCompositeActor want to be treated
932                    // as if they are at the top level even though they have an executive
933                    // director, so be sure to check _isTopLevel().
934                    if (executiveDirector instanceof SuperdenseTimeDirector
935                            && !_isTopLevel()) {
936                        _microstep = ((SuperdenseTimeDirector) executiveDirector)
937                                .getIndex();
938                    }
939                }
940            }
941        }
942        // Release lock to invoke super.initialize(), because that invokes
943        // actors and they may need to post events.
944        super.initialize();
945
946        synchronized (_eventQueueLock) {
947            // Register the stop time as an event such that the model is
948            // guaranteed to stop at that time. This event also serves as
949            // a guideline for an embedded Continuous model to know how much
950            // further to integrate into future. But only do this if the
951            // stop time is finite.
952            Time stopTime = getModelStopTime();
953            if (!stopTime.isPositiveInfinite()) {
954                fireAt((Actor) getContainer(), stopTime, 1);
955            }
956
957            if (isEmbedded() && !_eventQueue.isEmpty()) {
958                // If the event queue is not empty and the container is not at
959                // the top level, ask the upper level director in the
960                // hierarchy to refire the container at the timestamp of
961                // the earliest event of the local event queue.
962                // This design allows the upper level director to keep a
963                // relatively short event queue.
964                _requestFiring();
965                // Indicate that fireAt() request should be passed
966                // up the chain if they are made before the next iteration.
967                _delegateFireAt = true;
968            } else {
969                _delegateFireAt = false;
970            }
971
972            _isInitializing = false;
973        }
974    }
975
976    /** Indicate that a schedule for the model may no longer be valid.
977     *  This forces the actor depths to be recalculated the next time
978     *  they are accessed.
979     */
980    @Override
981    public void invalidateSchedule() {
982        CompositeActor container = (CompositeActor) getContainer();
983        CausalityInterfaceForComposites causality = (CausalityInterfaceForComposites) container
984                .getCausalityInterface();
985        causality.invalidate();
986    }
987
988    /** Return the object to use to obtain a mutex lock on this director.
989     *  This class overrides the base class to return the event queue lock object.
990     *  @return An object to use to obtain a lock on this director.
991     */
992    @Override
993    public Object mutexLockObject() {
994        return _eventQueueLock;
995    }
996
997    /** Return a new receiver of the type DEReceiver.
998     *  @return A new DEReceiver.
999     */
1000    @Override
1001    public Receiver newReceiver() {
1002        if (_debugging && _verbose) {
1003            _debug("Creating a new DE receiver.");
1004        }
1005
1006        return new DEReceiver();
1007    }
1008
1009    /** Return false if there are no more actors to be fired or the stop()
1010     *  method has been called. Otherwise, if the director is an embedded
1011     *  director and the local event queue is not empty, request the executive
1012     *  director to refire the container of this director at the timestamp of
1013     *  the first event in the event queue.
1014     *  @return True If this director will be fired again.
1015     *  @exception IllegalActionException If the postfire method of the super
1016     *  class throws it, or the stopWhenQueueIsEmpty parameter does not contain
1017     *  a valid token, or refiring can not be requested.
1018     */
1019    @Override
1020    public boolean postfire() throws IllegalActionException {
1021        boolean result = super.postfire();
1022
1023        // If any output ports still have tokens to transfer,
1024        // request a refiring at the current time.
1025        CompositeActor container = (CompositeActor) getContainer();
1026        Iterator<IOPort> outports = container.outputPortList().iterator();
1027        boolean moreOutputsToTransfer = false;
1028        while (outports.hasNext() && !moreOutputsToTransfer) {
1029            IOPort outport = outports.next();
1030            for (int i = 0; i < outport.getWidthInside(); i++) {
1031                if (outport.hasNewTokenInside(i)) {
1032                    moreOutputsToTransfer = true;
1033                    break;
1034                }
1035            }
1036        }
1037
1038        // Reset the microstep to zero if the next event is
1039        // in the future.
1040        synchronized (_eventQueueLock) {
1041            if (!_eventQueue.isEmpty() && !moreOutputsToTransfer) {
1042                DEEvent next = _eventQueue.get();
1043                if (next.timeStamp().compareTo(getModelTime()) > 0) {
1044                    _microstep = 0;
1045                }
1046            }
1047            boolean stop = ((BooleanToken) stopWhenQueueIsEmpty.getToken())
1048                    .booleanValue();
1049
1050            // Request refiring and/or stop the model.
1051            // There are two conditions to stop the model.
1052            // 1. There are no more actors to be fired (i.e. event queue is
1053            // empty), and either of the following conditions is satisfied:
1054            //     a. the stopWhenQueueIsEmpty parameter is set to true.
1055            //     b. the current model time equals the model stop time.
1056            // 2. The event queue is not empty, but the current time exceeds
1057            // the stop time.
1058            if (moreOutputsToTransfer) {
1059                fireContainerAt(getModelTime());
1060            } else if (_noMoreActorsToFire && (stop
1061                    || getModelTime().compareTo(getModelStopTime()) == 0)) {
1062                if (_debugging) {
1063                    _debug("No more actors to fire and time to stop.");
1064                }
1065                _exceedStopTime = true;
1066                result = false;
1067            } else if (_exceedStopTime) {
1068                // If the current time is bigger than the stop time,
1069                // stop the model execution.
1070                result = false;
1071            } else if (isEmbedded() && !_eventQueue.isEmpty()) {
1072                // If the event queue is not empty and the container is an
1073                // embedded model, ask the upper level director in the
1074                // hierarchy to refire the container at the timestamp of the
1075                // first event of the local event queue.
1076                // This design allows the upper level director (actually all
1077                // levels in hierarchy) to keep a relatively short event queue.
1078                _requestFiring();
1079            }
1080        }
1081        if (isEmbedded()) {
1082            // Indicate that fireAt() requests should be passed up the
1083            // hierarchy if they are made before the next iteration.
1084            _delegateFireAt = true;
1085        }
1086        // NOTE: The following commented block enforces that no events with
1087        // different tags can exist in the same receiver.
1088        // This is a quite different semantics from the previous designs,
1089        // and its effects are still under investigation and debate.
1090        //        // Clear all of the contained actor's input ports.
1091        //        for (Iterator actors = ((CompositeActor)getContainer())
1092        //                .entityList(Actor.class).iterator();
1093        //                actors.hasNext();) {
1094        //            Entity actor = (Entity)actors.next();
1095        //            Iterator ports = actor.portList().iterator();
1096        //            while (ports.hasNext()) {
1097        //                IOPort port = (IOPort)ports.next();
1098        //                if (port.isInput()) {
1099        //                    // Clear all receivers.
1100        //                    Receiver[][] receivers = port.getReceivers();
1101        //                    if (receivers == null) {
1102        //                        throw new InternalErrorException(this, null,
1103        //                                "port.getReceivers() returned null! "
1104        //                                + "This should never happen. "
1105        //                                + "port was '" + port + "'");
1106        //                    }
1107        //                    for (int i = 0; i < receivers.length; i++) {
1108        //                        Receiver[] receivers2 = receivers[i];
1109        //                        for (int j = 0; j < receivers2.length; j++) {
1110        //                            receivers2[j].clear();
1111        //                        }
1112        //                    }
1113        //                }
1114        //            }
1115        //        }
1116        return result;
1117    }
1118
1119    /** Set the model time to the outside time if this director is
1120     *  not at the top level. Check the time of the next event to decide
1121     *  whether to fire. Return true if there are inputs to this composite
1122     *  actor, or the time of the next event is equal to the current model
1123     *  time. Otherwise, return false.
1124     *  <p>
1125     *  Note that microsteps are not synchronized.
1126     *  </p><p>
1127     *  Throw an exception if the current model time is greater than the next
1128     *  event time.
1129     *  @return True if the composite actor is ready to fire.
1130     *  @exception IllegalActionException If there is a missed event,
1131     *  or the prefire method of the super class throws it, or can not
1132     *  query the tokens of the input ports of the container of this
1133     *  director.</p>
1134     */
1135    @Override
1136    public boolean prefire() throws IllegalActionException {
1137
1138        // NOTE: super.prefire() is not of much use, because we want
1139        // to set current time adjusted for accumulated suspend time.
1140
1141        if (_debugging) {
1142            _debug("DEDirector: Called prefire().");
1143        }
1144
1145        // The following call sets the local time to match
1146        // the environment time (with drift and offset taken into account),
1147        // but it does not set the microstep. We do that below.
1148        boolean newActorFromProposeTime = super.prefire();
1149
1150        // Have to also do this for the microstep.
1151        if (isEmbedded()) {
1152            Nameable container = getContainer();
1153            if (container instanceof CompositeActor) {
1154                Director executiveDirector = ((CompositeActor) container)
1155                        .getExecutiveDirector();
1156                // Some composites, such as RunCompositeActor want to be treated
1157                // as if they are at the top level even though they have an executive
1158                // director, so be sure to check _isTopLevel().
1159                if (executiveDirector instanceof SuperdenseTimeDirector
1160                        && !_isTopLevel()) {
1161                    _microstep = ((SuperdenseTimeDirector) executiveDirector)
1162                            .getIndex();
1163                }
1164                if (_debugging) {
1165                    _debug("DEDirector: Set microstep to " + _microstep);
1166                }
1167            }
1168        }
1169
1170        // A top-level DE director is always ready to fire.
1171        if (_isTopLevel()) {
1172            if (_debugging) {
1173                _debug("Prefire returns " + newActorFromProposeTime);
1174            }
1175            return true && newActorFromProposeTime;
1176        }
1177
1178        // If embedded, check the timestamp of the next event to decide
1179        // whether this director is ready to fire.
1180        synchronized (_eventQueueLock) {
1181            Time modelTime = getModelTime();
1182            Time nextEventTime = Time.POSITIVE_INFINITY;
1183
1184            if (!_eventQueue.isEmpty()) {
1185                DEEvent nextEvent = _eventQueue.get();
1186                nextEventTime = nextEvent.timeStamp();
1187            }
1188
1189            // If the model time is larger (later) than the first event
1190            // in the queue, then
1191            // catch up with the current model time by discarding
1192            // the old events. Do not, however, discard events whose
1193            // index but not time has passed.
1194            while (modelTime.compareTo(nextEventTime) > 0) {
1195                DEEvent skippedEvent = _eventQueue.take();
1196                if (_debugging) {
1197                    _debug("Skipping event at time (" + nextEventTime
1198                            + ") destined for actor "
1199                            + skippedEvent.actor().getFullName());
1200                }
1201                if (!_eventQueue.isEmpty()) {
1202                    DEEvent nextEvent = _eventQueue.get();
1203                    nextEventTime = nextEvent.timeStamp();
1204                } else {
1205                    nextEventTime = Time.POSITIVE_INFINITY;
1206                }
1207            }
1208        }
1209        // NOTE: An alternative would be to throw an exception. This means that the
1210        // enclosing director is breaking the fireAt() contract, since
1211        // it presumably returned a value indicating it would do the
1212        // firing and then failed to do it. However, we don't do that
1213        // because the old style of modal models (in the fsm domain)
1214        // will result in this exception being thrown. The
1215        // code to do that is below.
1216        /*
1217        if (modelTime.compareTo(nextEventTime) > 0) {
1218            throw new IllegalActionException(this,
1219                    "DEDirector expected to be fired at time "
1220                    + nextEventTime
1221                    + " but instead is being fired at time "
1222                    + modelTime);
1223        }
1224         */
1225
1226        // If model time is strictly less than the next event time,
1227        // then there are no events on the event queue with this
1228        // model time, and hence, if there are also no input events,
1229        // then there is nothing to do, and we can return false.
1230        /* The following is no longer correct.
1231         * We need to ensure that postfire() is invoked so that fireAt()
1232         * gets called. Although fireAt() should have already been called
1233         * for pending events in the event queue, it may need to be done again
1234         * because we may have been suspending when the resulting fire occurred.
1235         * EAL 9/18/09
1236        if (!nextEventTime.equals(modelTime)) {
1237            // If the event timestamp is greater than the model timestamp,
1238            // we check if there's any external input.
1239            Iterator<?> inputPorts = container.inputPortList().iterator();
1240            boolean hasInput = false;
1241
1242            while (inputPorts.hasNext() && !hasInput) {
1243                IOPort port = (IOPort) inputPorts.next();
1244
1245                for (int i = 0; i < port.getWidth(); i++) {
1246                    if (port.hasToken(i)) {
1247                        hasInput = true;
1248                        break;
1249                    }
1250                }
1251            }
1252
1253            if (!hasInput) {
1254                // If there is no internal event, it is not the correct
1255                // time to fire.
1256                // NOTE: This may happen because the container is statically
1257                // scheduled by its director to fire at this time.
1258                // For example, a DE model in a Giotto model.
1259                result = false;
1260            }
1261        }
1262         */
1263
1264        if (_debugging) {
1265            _debug("Prefire returns true.");
1266        }
1267        // Indicate that fireAt requests can be handled locally because
1268        // we are within an iteration.
1269        _delegateFireAt = false;
1270        return true && newActorFromProposeTime;
1271    }
1272
1273    /** Set the current timestamp to the model start time, invoke the
1274     *  preinitialize() methods of all actors deeply contained by the
1275     *  container.
1276     *  <p>
1277     *  This method should be invoked once per execution, before any
1278     *  iteration. Actors cannot produce output data in their preinitialize()
1279     *  methods. If initial events are needed, e.g. pure events for source
1280     *  actor, the actors should do so in their initialize() method.
1281     *  </p><p>
1282     *  This method is <i>not</i> synchronized on the workspace, so the
1283     *  caller should be.</p>
1284     *
1285     *  @exception IllegalActionException If the preinitialize() method of the
1286     *  container or one of the deeply contained actors throws it, or the
1287     *  parameters, minBinCount, binCountFactor, and isCQAdaptive, do not have
1288     *  valid tokens.
1289     */
1290    @Override
1291    public void preinitialize() throws IllegalActionException {
1292        if (_eventQueue != null) {
1293            // This execution may be overlapped with the previous.
1294            // See https://wiki.eecs.berkeley.edu/ptexternal/Main/Main/NotifyAll
1295            synchronized (_eventQueueLock) {
1296                _isInitializing = true;
1297                // Initialize an event queue.
1298                _eventQueue = new DECQEventQueue(
1299                        ((IntToken) minBinCount.getToken()).intValue(),
1300                        ((IntToken) binCountFactor.getToken()).intValue(),
1301                        ((BooleanToken) isCQAdaptive.getToken())
1302                                .booleanValue());
1303            }
1304        } else {
1305            _isInitializing = true;
1306            // Initialize an event queue.
1307            _eventQueue = new DECQEventQueue(
1308                    ((IntToken) minBinCount.getToken()).intValue(),
1309                    ((IntToken) binCountFactor.getToken()).intValue(),
1310                    ((BooleanToken) isCQAdaptive.getToken()).booleanValue());
1311        }
1312        // Add debug listeners.
1313        if (_debugListeners != null) {
1314            Iterator<?> listeners = _debugListeners.iterator();
1315
1316            while (listeners.hasNext()) {
1317                DebugListener listener = (DebugListener) listeners.next();
1318                _eventQueue.addDebugListener(listener);
1319            }
1320        }
1321
1322        // Call the preinitialize method of the super class.
1323        super.preinitialize();
1324
1325        if (getContainer() instanceof CompositeActor) {
1326            // Tests in ptolemy/configs/test expand the configuration which
1327            // results in the ModelDirectory getting expanded.  In the
1328            // ModelDirectory, the container might be an EntityLibrary.
1329            // The Ptides director is calling preinitialize() in
1330            // attributeChanged(), which means that this code gets called.
1331
1332            // Do this here so that performance measurements
1333            // clearly indicate that the cost is in static analysis
1334            // done in preinitialize.
1335            CompositeActor container = (CompositeActor) getContainer();
1336            CausalityInterfaceForComposites causality = (CausalityInterfaceForComposites) container
1337                    .getCausalityInterface();
1338            causality.checkForCycles();
1339        }
1340
1341        _actorsFinished = new ArrayList();
1342
1343        if (_debugging && _verbose) {
1344            _debug("## Depths assigned to actors and ports:");
1345            _debug(describePriorities());
1346        }
1347        _issueExecutionAspectWarning();
1348    }
1349
1350    /** Unregister a debug listener.  If the specified listener has not
1351     *  been previously registered, then do nothing.
1352     *  @param listener The listener to remove from the list of listeners
1353     *   to which debug messages are sent.
1354     *  @see #addDebugListener(DebugListener)
1355     */
1356    @Override
1357    public void removeDebugListener(DebugListener listener) {
1358        if (_eventQueue != null) {
1359            synchronized (_eventQueueLock) {
1360                _eventQueue.removeDebugListener(listener);
1361            }
1362        }
1363
1364        super.removeDebugListener(listener);
1365    }
1366
1367    /** Resume the execution of an actor that was previously blocked because
1368     *  it didn't have all the resources it needed for execution. This method
1369     *  puts an event into the queue for the current time.
1370     *
1371     *  @param actor The actor that resumes execution.
1372     *  @exception IllegalActionException Not thrown here but in derived classes.
1373     */
1374    @Override
1375    public void resumeActor(NamedObj actor) throws IllegalActionException {
1376        List<DEEvent> events = _actorsInExecution.get(actor);
1377        ActorExecutionAspect aspect = getExecutionAspect(actor);
1378        if (aspect == null) {
1379            throw new IllegalActionException(this, "Cannot resume actor "
1380                    + actor.getName() + " because aspect cannot be found.");
1381        }
1382        NamedObj container = aspect.getContainer();
1383        if (container == null) {
1384            throw new IllegalActionException(this,
1385                    "Cannot get container of actor " + actor.getName());
1386        }
1387        Director director = ((CompositeActor) container).getDirector();
1388        if (director == null) {
1389            throw new IllegalActionException(this,
1390                    "Cannot get director of container " + container.getName()
1391                            + " of actor " + actor.getName());
1392        }
1393
1394        Time time = director.getModelTime();
1395        DEEvent event = events.get(0);
1396        events.remove(event);
1397        _actorsInExecution.put((Actor) actor, events);
1398
1399        if (event.ioPort() != null) {
1400            _enqueueTriggerEvent(event.ioPort(), time);
1401        } else {
1402            _enqueueEvent((Actor) actor, time, 1);
1403        }
1404        fireContainerAt(time);
1405        if (_actorsFinished == null) {
1406            _actorsFinished = new ArrayList();
1407        }
1408        _actorsFinished.add((Actor) actor);
1409    }
1410
1411    /** Set the superdense time index. This should only be
1412     *  called by an enclosing director.
1413     *  @exception IllegalActionException Not thrown in this base class.
1414     *  @see #getIndex()
1415     *  @see ptolemy.actor.SuperdenseTimeDirector
1416     */
1417    @Override
1418    public void setIndex(int index) throws IllegalActionException {
1419        if (_debugging) {
1420            _debug("Setting superdense time index to " + index);
1421        }
1422        _microstep = index;
1423    }
1424
1425    /** Request the execution of the current iteration to stop.
1426     *  This is similar to stopFire(), except that the current iteration
1427     *  is not allowed to complete.  This is useful if there is actor
1428     *  in the model that has a bug where it fails to consume inputs.
1429     *  An iteration will never terminate if such an actor receives
1430     *  an event.
1431     *  If the director is paused waiting for events to appear in the
1432     *  event queue, then it stops waiting, and calls stopFire() for all actors
1433     *  that are deeply contained by the container of this director.
1434     */
1435    @Override
1436    public void stop() {
1437        if (_eventQueue != null) {
1438            synchronized (_eventQueueLock) {
1439                _stopRequested = true;
1440                _eventQueueLock.notifyAll();
1441            }
1442        }
1443
1444        super.stop();
1445    }
1446
1447    /** Request the execution of the current iteration to complete.
1448     *  If the director is paused waiting for events to appear in the
1449     *  event queue, then it stops waiting,
1450     *  and calls stopFire() for all actors
1451     *  that are deeply contained by the container of this director.
1452     */
1453    @Override
1454    public void stopFire() {
1455        if (_eventQueue != null) {
1456            synchronized (_eventQueueLock) {
1457                _stopFireRequested = true;
1458                _eventQueueLock.notifyAll();
1459            }
1460        }
1461
1462        super.stopFire();
1463    }
1464
1465    // FIXME: it is questionable whether the multirate FSMActor and FSMDirector
1466    // should be used in DE as the default? I will say NO.
1467
1468    /** Return an array of suggested directors to use with
1469     *  ModalModel. Each director is specified by its full class
1470     *  name.  The first director in the array will be the default
1471     *  director used by a modal model.
1472     *  @return An array of suggested directors to be used with ModalModel.
1473     *  @see ptolemy.actor.Director#suggestedModalModelDirectors()
1474     */
1475    @Override
1476    public String[] suggestedModalModelDirectors() {
1477        String[] defaultSuggestions = new String[2];
1478        defaultSuggestions[1] = "ptolemy.domains.modal.kernel.MultirateFSMDirector";
1479        defaultSuggestions[0] = "ptolemy.domains.modal.kernel.FSMDirector";
1480        return defaultSuggestions;
1481    }
1482
1483    /** Transfer data from an input port of the container to the ports
1484     *  it is connected to on the inside.  This transfers at most one token
1485     *  on each channel, and overrides the base class to temporarily set
1486     *  the microstep to match or exceed that of the enclosing director if
1487     *  the enclosing director implements SuperdenseTimeDirector.
1488     *  Otherwise, it sets the microstep to match or exceed 1
1489     *  to ensure that inputs are interpreted as discrete values.
1490     *  @param port The port to transfer tokens from.
1491     *  @return True if at least one data token is transferred.
1492     *  @exception IllegalActionException If the port is not an opaque
1493     *  input port.
1494     */
1495    @Override
1496    public boolean transferInputs(IOPort port) throws IllegalActionException {
1497        int defaultMicrostep = _defaultMicrostep;
1498        int previousMicrostep = _microstep;
1499        SuperdenseTimeDirector enclosingDirector = _enclosingSuperdenseTimeDirector();
1500        if (enclosingDirector != null) {
1501            defaultMicrostep = enclosingDirector.getIndex();
1502        }
1503        if (_microstep < defaultMicrostep) {
1504            try {
1505                _microstep = defaultMicrostep;
1506                return super.transferInputs(port);
1507            } finally {
1508                _microstep = previousMicrostep;
1509            }
1510        }
1511        return super.transferInputs(port);
1512    }
1513
1514    // NOTE: We used to override transferOutputs
1515    // to transfer ALL output tokens at boundary of
1516    // hierarchy to outside. See de/test/auto/transferInputsandOutputs.xml.
1517    // However, the right thing to do is to request a refiring at the current
1518    // if outputs remain to be transferred. So that's what we do now.
1519
1520    /** Invoke the wrapup method of the super class. Reset the private
1521     *  state variables.
1522     *  @exception IllegalActionException If the wrapup() method of
1523     *  one of the associated actors throws it.
1524     */
1525    @Override
1526    public void wrapup() throws IllegalActionException {
1527        super.wrapup();
1528        _disabledActors = null;
1529        synchronized (_eventQueueLock) {
1530            _eventQueue.clear();
1531        }
1532        _noMoreActorsToFire = false;
1533        _microstep = 0;
1534    }
1535
1536    ///////////////////////////////////////////////////////////////////
1537    ////                         protected methods                 ////
1538
1539    /** Perform book keeping procedures after an actor firing.
1540     *  In this base class, do nothing.
1541     *  @exception IllegalActionException Not thrown in this base class.
1542     *  Derived classes may throw it if book keeping procedures are not
1543     *  successful.
1544     */
1545    protected void _actorFired() throws IllegalActionException {
1546    }
1547
1548    /** Enforces a firing of a DE director only handles events with the
1549     *  same tag. Checks what is the model time of the earliest event
1550     *  in the event queue.
1551     *  @return true if the earliest event in the event queue is at the
1552     *  same model time as the event that was just processed. Else if
1553     *  that event's timestamp is in the future, return false.
1554     *  @exception IllegalActionException If model time is set backwards.
1555     */
1556    protected boolean _checkForNextEvent() throws IllegalActionException {
1557        // The following code enforces that a firing of a
1558        // DE director only handles events with the same tag.
1559        // If the earliest event in the event queue is in the future,
1560        // this code terminates the current iteration.
1561        // This code is applied on both embedded and top-level directors.
1562        synchronized (_eventQueueLock) {
1563            if (!_eventQueue.isEmpty()) {
1564                DEEvent next = _eventQueue.get();
1565
1566                if (next.timeStamp().compareTo(getModelTime()) > 0) {
1567                    // If the next event is in the future time,
1568                    // jump out of the big while loop in fire() and
1569                    // proceed to postfire().
1570                    return false;
1571                } else if (next.microstep() > _microstep) {
1572                    // If the next event has a bigger microstep,
1573                    // jump out of the big while loop in fire() and
1574                    // proceed to postfire().
1575                    return false;
1576                } else if (next.timeStamp().compareTo(getModelTime()) < 0
1577                        || next.microstep() < _microstep) {
1578                    throw new IllegalActionException(
1579                            "The tag of the next event (" + next.timeStamp()
1580                                    + "." + next.microstep()
1581                                    + ") can not be less than"
1582                                    + " the current tag (" + getModelTime()
1583                                    + "." + _microstep + ") !");
1584                } else {
1585                    // The next event has the same tag as the current tag,
1586                    // indicating that at least one actor is going to be
1587                    // fired at the current iteration.
1588                    // Continue the current iteration.
1589                }
1590            }
1591        }
1592        return true;
1593    }
1594
1595    /** Disable the specified actor.  All events destined to this actor
1596     *  will be ignored. If the argument is null, then do nothing.
1597     *  @param actor The actor to disable.
1598     */
1599    protected void _disableActor(Actor actor) {
1600        if (actor != null) {
1601            if (_debugging) {
1602                _debug("Actor ", ((Nameable) actor).getName(), " is disabled.");
1603            }
1604
1605            if (_disabledActors == null) {
1606                _disabledActors = new HashSet<Actor>();
1607            }
1608
1609            _disabledActors.add(actor);
1610        }
1611    }
1612
1613    /** Put a pure event into the event queue to schedule the given actor to
1614     *  fire at the specified timestamp.
1615     *  <p>
1616     *  The default microstep for the queued event is equal to one,
1617     *  unless the time is equal to the current time, where the microstep
1618     *  will be the current microstep plus one.
1619     *  </p><p>
1620     *  The depth for the queued event is the minimum of the depths of
1621     *  all the ports of the destination actor.
1622     *  </p><p>
1623     *  If there is no event queue or the given actor is disabled, then
1624     *  this method does nothing.</p>
1625     *
1626     *  @param actor The actor to be fired.
1627     *  @param time The timestamp of the event.
1628     *  @param defaultMicrostep If the requested firing time is in the future,
1629     *   then use this defaultMicrostep for the microstep.
1630     *  @exception IllegalActionException If the time argument is less than
1631     *  the current model time, or the depth of the actor has not be calculated,
1632     *  or the new event can not be enqueued.
1633     */
1634    protected void _enqueueEvent(Actor actor, Time time, int defaultMicrostep)
1635            throws IllegalActionException {
1636        if (_eventQueue == null
1637                || _disabledActors != null && _disabledActors.contains(actor)) {
1638            return;
1639        }
1640
1641        // Adjust the microstep if it is less than or equal to the current
1642        // microstep.
1643        int microstep = defaultMicrostep;
1644        if (time.compareTo(getModelTime()) == 0 && microstep <= _microstep) {
1645            // If during initialization, do not increase the microstep.
1646            // This is based on the assumption that an actor only requests
1647            // one firing during initialization. In fact, if an actor requests
1648            // several firings at the same time,
1649            // only the first request will be granted.
1650            if (!_isInitializing) {
1651                microstep = _microstep + 1;
1652
1653                if (microstep == Integer.MAX_VALUE) {
1654                    throw new IllegalActionException(this, actor,
1655                            "Microstep has hit the maximum while scheduling a firing of "
1656                                    + actor.getFullName()
1657                                    + ". Perhaps the model has a stuttering Zeno Condition?");
1658                }
1659            }
1660        } else if (time.compareTo(getModelTime()) < 0) {
1661            throw new IllegalActionException(actor,
1662                    "Attempt to queue an event in the past:"
1663                            + " Current time is " + getModelTime()
1664                            + " while event time is " + time);
1665        }
1666
1667        int depth = _getDepthOfActor(actor);
1668
1669        if (_debugging) {
1670            _debug("DEDirector: enqueue a pure event: ",
1671                    ((NamedObj) actor).getName(),
1672                    "time = " + time + " microstep = " + microstep + " depth = "
1673                            + depth);
1674        }
1675
1676        DEEvent newEvent = new DEEvent(actor, time, microstep, depth);
1677        synchronized (_eventQueueLock) {
1678            _eventQueue.put(newEvent);
1679        }
1680    }
1681
1682    /** Put a trigger event into the event queue. A trigger event is
1683     *  an event destined for the specified port that will convey
1684     *  data to that port at the current time and microstep.
1685     *  The depth for the queued event is the
1686     *  depth of the destination IO port. The microstep of
1687     *  the enqueued event will be the greater of the current
1688     *  microstep and 1. That is, an event destined for a port
1689     *  is never queued with microstep less than 1.
1690     *  <p>
1691     *  If the event queue is not ready or the actor containing the destination
1692     *  port is disabled, do nothing.
1693     *
1694     *  @param ioPort The destination IO port.
1695     *  @exception IllegalActionException If the time argument is not the
1696     *  current time, or the depth of the given IO port has not be calculated,
1697     *  or the new event can not be enqueued.
1698     */
1699    protected void _enqueueTriggerEvent(IOPort ioPort)
1700            throws IllegalActionException {
1701        _enqueueTriggerEvent(ioPort, localClock.getLocalTime());
1702    }
1703
1704    /** Put a trigger event into the event queue with a timestamp that can be
1705     *  different from the current model time.
1706     *  Only resource schedulers can enqueue trigger events with future timestamps.
1707     *  @param ioPort The destination IO port.
1708     *  @param time The timestamp of the new event.
1709     *  @exception IllegalActionException If the time argument is not the
1710     *  current time, or the depth of the given IO port has not be calculated,
1711     *  or the new event can not be enqueued.
1712     */
1713    private void _enqueueTriggerEvent(IOPort ioPort, Time time)
1714            throws IllegalActionException {
1715        Actor actor = (Actor) ioPort.getContainer();
1716        if (_eventQueue == null
1717                || _disabledActors != null && _disabledActors.contains(actor)) {
1718            return;
1719        }
1720
1721        /* NOTE: We would like to throw an exception if the microstep is
1722         * zero, but this breaks models with CT inside DE.
1723         * The CTDirector does not have a notion of superdense time.
1724         * Ideally, we could detect that is coming from a submodel that
1725         * does not implement SuperdenseTimeDirector, and hence doesn't
1726         * know any better.
1727         * Unfortunately, it is rather difficult to determine where
1728         * the event originated, since it could have come from arbitrarily
1729         * deep in the hierarchy. At a minimum, this would create
1730         * a dependency on domains/modal.
1731         */
1732        if (_microstep < 1 && _enforceMicrostepSemantics) {
1733            throw new IllegalActionException(this, ioPort.getContainer(),
1734                    "Received a non-discrete event at port " + ioPort.getName()
1735                            + " of actor " + ioPort.getContainer().getName()
1736                            + ". Discrete events are required to have microstep greater than zero,"
1737                            + " but this one has microstep " + _microstep
1738                            + ". Perhaps a Continuous submodel is sending a continuous rather than"
1739                            + " discrete signal?");
1740        }
1741        int depth = _getDepthOfIOPort(ioPort);
1742
1743        int microstep = _microstep;
1744        if (microstep < 1) {
1745            microstep = 1;
1746        }
1747
1748        if (_aspectsPresent) {
1749            if (_aspectForActor.get(actor) != null
1750                    && _aspectForActor.get(actor).isWaitingForResource(actor)) {
1751                Object[] eventArray = _eventQueue.toArray();
1752                for (Object object : eventArray) {
1753                    DEEvent event = (DEEvent) object;
1754                    if (event.actor().equals(actor)) {
1755                        if (event.timeStamp().compareTo(time) == 0
1756                                && event.microstep() == 1) {
1757                            microstep = microstep + 1;
1758                        } else if (event.timeStamp().compareTo(time) < 0) {
1759                            time = event.timeStamp();
1760                            microstep = microstep + 1;
1761                        }
1762                    }
1763                }
1764            }
1765        }
1766
1767        if (_debugging) {
1768            _debug("enqueue a trigger event for ", ((NamedObj) actor).getName(),
1769                    " time = " + time + " microstep = " + microstep
1770                            + " depth = " + depth);
1771        }
1772
1773        // Register this trigger event.
1774        DEEvent newEvent = new DEEvent(ioPort, time, microstep, depth);
1775        synchronized (_eventQueueLock) {
1776            _eventQueue.put(newEvent);
1777        }
1778    }
1779
1780    /** Advance the current model tag to that of the earliest event in
1781     *  the event queue, and fire all actors that have requested or
1782     *  are triggered to be fired at the current tag. If
1783     *  <i>synchronizeToRealTime</i> is true, then before firing, wait
1784     *  until real time matches or exceeds the timestamp of the
1785     *  event. Note that the default unit for time is seconds.
1786     *  <p>
1787     *  Each actor is fired repeatedly (prefire(), fire()),
1788     *  until either it has no more input tokens, or its prefire() method
1789     *  returns false. Note that if the actor fails to consume its
1790     *  inputs, then this can result in an infinite loop.
1791     *  Each actor that is fired is then postfired once at the
1792     *  conclusion of the iteration.
1793     *  </p><p>
1794     *  If there are no events in the event queue, then the behavior
1795     *  depends on the <i>stopWhenQueueIsEmpty</i> parameter. If it is
1796     *  false, then this thread will stall until events become
1797     *  available in the event queue. Otherwise, time will advance to
1798     *  the stop time and the execution will halt.</p>
1799     *
1800     *  @return 0 if firing was successful, and the next event in event
1801     *   queue should be checked for processing;
1802     *   -1 if there's no actor to fire, and we should not keep firing;
1803     *   1 if there's no actor to fire, but the next event should be
1804     *   checked for processing.
1805     *  @exception IllegalActionException If the firing actor throws it, or
1806     *   event queue is not ready, or an event is missed, or time is set
1807     *   backwards.
1808     */
1809    protected int _fire() throws IllegalActionException {
1810        // Find the next actor to be fired.
1811        Actor actorToFire = _getNextActorToFire();
1812
1813        // Check whether the actor to be fired is null.
1814        // -- If the actor to be fired is null,
1815        // There are two conditions that the actor to be fired
1816        // can be null.
1817        if (actorToFire == null) {
1818            if (_isTopLevel()) {
1819                // Case 1:
1820                // If this director is an executive director at
1821                // the top level, a null actor means that there are
1822                // no events in the event queue.
1823                if (_debugging) {
1824                    _debug("No more events in the event queue.");
1825                }
1826
1827                // Setting the following variable to true makes the
1828                // postfire method return false.
1829                // Do not do this if _stopFireRequested is true,
1830                // since there may in fact be actors to fire, but
1831                // their firing has been deferred.
1832                if (!_stopFireRequested) {
1833                    _noMoreActorsToFire = true;
1834                }
1835            } else {
1836                // Case 2:
1837                // If this director belongs to an opaque composite model,
1838                // which is not at the top level, the director may be
1839                // invoked by an update of an external parameter port.
1840                // Therefore, no actors contained by the composite model
1841                // need to be fired.
1842                // NOTE: There may still be events in the event queue
1843                // of this director that are scheduled for future firings.
1844                if (_debugging) {
1845                    _debug("No actor requests to be fired "
1846                            + "at the current tag.");
1847                }
1848            }
1849            // Nothing more needs to be done in the current iteration.
1850            // Simply return.
1851            // Since we are now actually stopping the firing, we can set this false.
1852            _stopFireRequested = false;
1853            return -1;
1854        }
1855
1856        // NOTE: Here we used to check to see whether
1857        // the actor to be fired is the container of this director,
1858        // and if so, return to give the outside domain a chance to react
1859        // to that event. This strategy assumed that the
1860        // topological sort would always assign the composite actor the
1861        // lowest priority, which would guarantee that all the inside actors
1862        // have fired (reacted to their triggers) before the composite
1863        // actor is what is returned. However, the priority no longer
1864        // seems to always be lower. A better strategy is to continue
1865        // firing until we have exhausted all events with the current
1866        // tag and microstep.
1867        if (actorToFire == getContainer()) {
1868            /* What we used to do (before 5/17/09):
1869            // Since we are now actually stopping the firing, we can set this false.
1870            _stopFireRequested = false;
1871            return;
1872             */
1873            return 1;
1874        }
1875
1876        if (_debugging) {
1877            _debug("****** Actor to fire: " + actorToFire.getFullName());
1878        }
1879
1880        // Keep firing the actor to be fired until there are no more input
1881        // tokens available in any of its input ports with the same tag, or its prefire()
1882        // method returns false.
1883        boolean refire;
1884
1885        do {
1886            refire = false;
1887
1888            // NOTE: There are enough tests here against the
1889            // _debugging variable that it makes sense to split
1890            // into two duplicate versions.
1891            if (_debugging) {
1892                // Debugging. Report everything.
1893                // If the actor to be fired is not contained by the container,
1894                // it may just be deleted. Put this actor to the
1895                // list of disabled actors.
1896                if (!((CompositeEntity) getContainer())
1897                        .deepContains((NamedObj) actorToFire)) {
1898                    _debug("Actor no longer under the control of this director. Disabling actor.");
1899                    _disableActor(actorToFire);
1900                    break;
1901                }
1902
1903                _debug(new FiringEvent(this, actorToFire,
1904                        FiringEvent.BEFORE_PREFIRE));
1905
1906                if (!actorToFire.prefire()) {
1907                    _debug("*** Prefire returned false.");
1908                    break;
1909                }
1910
1911                _debug(new FiringEvent(this, actorToFire,
1912                        FiringEvent.AFTER_PREFIRE));
1913
1914                _debug(new FiringEvent(this, actorToFire,
1915                        FiringEvent.BEFORE_FIRE));
1916
1917                actorToFire.fire();
1918                _debug(new FiringEvent(this, actorToFire,
1919                        FiringEvent.AFTER_FIRE));
1920
1921                _debug(new FiringEvent(this, actorToFire,
1922                        FiringEvent.BEFORE_POSTFIRE));
1923
1924                if (!actorToFire.postfire()) {
1925                    _debug("*** Postfire returned false:",
1926                            ((Nameable) actorToFire).getName());
1927
1928                    // This actor requests not to be fired again.
1929                    _disableActor(actorToFire);
1930                    break;
1931                }
1932
1933                _debug(new FiringEvent(this, actorToFire,
1934                        FiringEvent.AFTER_POSTFIRE));
1935            } else {
1936                // No debugging.
1937                // If the actor to be fired is not contained by the container,
1938                // it may just be deleted. Put this actor to the
1939                // list of disabled actors.
1940                if (!((CompositeEntity) getContainer())
1941                        .deepContains((NamedObj) actorToFire)) {
1942                    _disableActor(actorToFire);
1943                    break;
1944                }
1945                if (!actorToFire.prefire()) {
1946                    break;
1947                }
1948
1949                actorToFire.fire();
1950                // NOTE: It is the fact that we postfire actors now that makes
1951                // this director not comply with the actor abstract semantics.
1952                // However, it's quite a redesign to make it comply, and the
1953                // semantics would not be backward compatible. It really needs
1954                // to be a new director to comply.
1955                if (!actorToFire.postfire()) {
1956                    // This actor requests not to be fired again.
1957                    _disableActor(actorToFire);
1958                    break;
1959                }
1960
1961            }
1962
1963            // Check all the input ports of the actor to see whether there
1964            // are more input tokens to be processed.
1965            // FIXME: This particular situation can only occur if either the
1966            // actor failed to consume a token, or multiple
1967            // events with the same destination were queued with the same tag.
1968            // In theory, both are errors. One possible fix for the latter
1969            // case would be to requeue the token with a larger microstep.
1970            // A possible fix for the former (if we can detect it) would
1971            // be to throw an exception. This would be far better than
1972            // going into an infinite loop.
1973            Iterator<?> inputPorts = actorToFire.inputPortList().iterator();
1974
1975            while (inputPorts.hasNext() && !refire) {
1976                IOPort port = (IOPort) inputPorts.next();
1977
1978                // iterate all the channels of the current input port.
1979                for (int i = 0; i < port.getWidth(); i++) {
1980                    if (port.hasNewToken(i)) {
1981                        if (_debugging) {
1982                            _debug("Port named " + port.getName()
1983                                    + " still has input on channel " + i
1984                                    + ". Refire the actor.");
1985                        }
1986                        // refire only if can be scheduled.
1987                        if (!_aspectsPresent || _schedule(
1988                                (NamedObj) actorToFire, getModelTime())) {
1989                            refire = true;
1990
1991                            // Found a channel that has input data,
1992                            // jump out of the for loop.
1993                            break;
1994                        } else if (_aspectsPresent) {
1995                            if (_actorsInExecution == null) {
1996                                _actorsInExecution = new HashMap();
1997                            }
1998                            List<DEEvent> events = _actorsInExecution
1999                                    .get(actorToFire);
2000                            if (events == null) {
2001                                events = new ArrayList<DEEvent>();
2002                            }
2003
2004                            events.add(new DEEvent(port, getModelTime(), 1,
2005                                    _getDepthOfActor(actorToFire)));
2006                            _actorsInExecution.put(actorToFire, events);
2007                        }
2008                    }
2009                }
2010            }
2011        } while (refire); // close the do {...} while () loop
2012        // NOTE: On the above, it would be nice to be able to
2013        // check _stopFireRequested, but this doesn't actually work.
2014        // In particular, firing an actor may trigger a call to stopFire(),
2015        // for example if the actor makes a change request, as for example
2016        // an FSM actor will do.  This will prevent subsequent firings,
2017        // incorrectly.
2018        return 0;
2019    }
2020
2021    /** Return the depth of an actor.
2022     *  @param actor An actor whose depth is requested.
2023     *  @return An integer indicating the depth of the given actor.
2024     *  @exception IllegalActionException If the actor depth has
2025     *   not been computed (this should not occur if the ioPort is under the control
2026     *   of this director).
2027     */
2028    protected int _getDepthOfActor(Actor actor) throws IllegalActionException {
2029        CompositeActor container = (CompositeActor) getContainer();
2030        CausalityInterfaceForComposites causality = (CausalityInterfaceForComposites) container
2031                .getCausalityInterface();
2032        return causality.getDepthOfActor(actor);
2033    }
2034
2035    /** Return the depth of an ioPort.
2036     *  @param ioPort A port whose depth is requested.
2037     *  @return An integer representing the depth of the specified ioPort.
2038     *  @exception IllegalActionException If the ioPort does not have
2039     *   a depth (this should not occur if the ioPort is under the control
2040     *   of this director).
2041     */
2042    protected int _getDepthOfIOPort(IOPort ioPort)
2043            throws IllegalActionException {
2044        CompositeActor container = (CompositeActor) getContainer();
2045        CausalityInterfaceForComposites causality = (CausalityInterfaceForComposites) container
2046                .getCausalityInterface();
2047        return causality.getDepthOfPort(ioPort);
2048    }
2049
2050    /** Dequeue the events that have the smallest tag from the event queue.
2051     *  Return their destination actor. Advance the model tag to their tag.
2052     *  If the timestamp of the smallest tag is greater than the stop time
2053     *  then return null. If there are no events in the event queue, and
2054     *  the stopWhenQueueIsEmpty parameter is set to true, then return null.
2055     *  Both cases will have the effect of stopping the simulation.
2056     *  <p>
2057     *  If the stopWhenQueueIsEmpty parameter is false and the queue is empty,
2058     *  then stall the current thread by calling wait() on the _eventQueue
2059     *  until there are new events available.  If the synchronizeToRealTime
2060     *  parameter is true, then this method may suspend the calling thread
2061     *  by using Object.wait(long) to let elapsed real time catch up with the
2062     *  current model time.</p>
2063     *  @return The next actor to be fired, which can be null.
2064     *  @exception IllegalActionException If event queue is not ready, or
2065     *  an event is missed, or time is set backwards.
2066     */
2067    protected Actor _getNextActorToFire() throws IllegalActionException {
2068        if (_eventQueue == null) {
2069            throw new IllegalActionException(
2070                    "Fire method called before the preinitialize method.");
2071        }
2072
2073        Actor actorToFire = null;
2074        DEEvent lastFoundEvent = null;
2075        DEEvent nextEvent = null;
2076
2077        // Keep taking events out until there are no more events that have the
2078        // same tag and go to the same destination actor, or until the queue is
2079        // empty, or until a stop is requested.
2080        // LOOPLABEL::GetNextEvent
2081        while (!_stopRequested) {
2082            // Get the next event from the event queue.
2083            if (_stopWhenQueueIsEmpty) {
2084                if (_eventQueue.isEmpty()) {
2085                    // If the event queue is empty,
2086                    // jump out of the loop: LOOPLABEL::GetNextEvent
2087                    break;
2088                }
2089            }
2090
2091            if (isEmbedded()) {
2092                // If the director is not at the top level.
2093                if (_eventQueue.isEmpty()) {
2094                    // This could happen if the container simply fires
2095                    // this composite at times it chooses. Most directors
2096                    // do this (SDF, SR, Continuous, etc.). It can also
2097                    // happen if an input is provided to a parameter port
2098                    // and the container is DE.
2099                    // In all these cases, no actors inside need to be
2100                    // fired.
2101                    break;
2102                }
2103                // For an embedded DE director, the following code prevents
2104                // the director from reacting to future events with bigger
2105                // time values in their tags.
2106                // For a top-level DE director, there is no such constraint
2107                // because the top-level director is responsible to advance
2108                // simulation by increasing the model tag.
2109                nextEvent = _eventQueue.get();
2110
2111                // An embedded director should process events
2112                // that only happen at the current tag.
2113                // If the event is in the past, that is an error,
2114                // because the event should have been consumed in prefire().
2115                if (nextEvent.timeStamp().compareTo(getModelTime()) < 0) {
2116                    // missed an event
2117                    throw new IllegalActionException(
2118                            "Fire: Missed an event: the next event tag "
2119                                    + nextEvent.timeStamp() + " :: "
2120                                    + nextEvent.microstep()
2121                                    + " is earlier than the current model tag "
2122                                    + getModelTime() + " :: " + _microstep
2123                                    + " !");
2124                }
2125
2126                // If the event is in the future time, it is ignored
2127                // and will be processed later. There is some complexity
2128                // here for backward compatibility with directors that do
2129                // not support superdense time. If the enclosing director
2130                // does not support superdense time, then we ignore the
2131                // microstep. Otherwise, we require the microstep of
2132                // the event to match the microstep that was set in
2133                // prefire(), which matches the microstep of the enclosing
2134                // director.
2135                boolean microstepMatches = true;
2136                Nameable container = getContainer();
2137                if (container instanceof CompositeActor) {
2138                    Director executiveDirector = ((CompositeActor) container)
2139                            .getExecutiveDirector();
2140                    // Some composites, such as RunCompositeActor want to be treated
2141                    // as if they are at the top level even though they have an executive
2142                    // director, so be sure to check _isTopLevel().
2143                    if (executiveDirector instanceof SuperdenseTimeDirector
2144                            && !_isTopLevel()) {
2145                        // If the next event microstep in the past (which it should
2146                        // not be normally), then we will consider it to match.
2147                        microstepMatches = nextEvent.microstep() <= _microstep;
2148                    }
2149                }
2150
2151                int comparison = nextEvent.timeStamp()
2152                        .compareTo(getModelTime());
2153                if (comparison > 0 || comparison == 0 && !microstepMatches) {
2154                    // reset the next event
2155                    nextEvent = null;
2156
2157                    // jump out of the loop: LOOPLABEL::GetNextEvent
2158                    break;
2159                }
2160            } else { // if (!topLevel)
2161                // If the director is at the top level
2162                // If the event queue is empty, normally
2163                // a blocking read is performed on the queue.
2164                // However, there are two conditions that the blocking
2165                // read is not performed, which are checked below.
2166                if (_eventQueue.isEmpty()) {
2167                    // The two conditions are:
2168                    // 1. An actor to be fired has been found; or
2169                    // 2. There are no more events in the event queue,
2170                    // and the current time is equal to the stop time.
2171                    if (actorToFire != null
2172                            || getModelTime().equals(getModelStopTime())) {
2173                        // jump out of the loop: LOOPLABEL::GetNextEvent
2174                        break;
2175                    }
2176                }
2177
2178                // Otherwise, if the event queue is empty,
2179                // a blocking read is performed on the queue.
2180                // stopFire() needs to also cause this to fall out!
2181                synchronized (_eventQueueLock) {
2182                    while (_eventQueue.isEmpty() && !_stopRequested
2183                            && !_stopFireRequested) {
2184                        if (_debugging) {
2185                            _debug("Queue is empty. Waiting for input events.");
2186                        }
2187
2188                        try {
2189                            // NOTE: Release the read access held
2190                            // by this thread to prevent deadlocks.
2191                            // NOTE: If a ChangeRequest has been requested,
2192                            // then _eventQueue.notifyAll() is called
2193                            // and stopFire() is called, so we will stop
2194                            // waiting for events. However,
2195                            // CompositeActor used to call stopFire() before
2196                            // queuing the change request, which created the risk
2197                            // that the below wait() would be terminated by
2198                            // a notifyAll() on _eventQueue with _stopFireRequested
2199                            // having been set, but before the change request has
2200                            // actually been filed.  See CompositeActor.requestChange().
2201                            // Does this matter? It means that on the next invocation
2202                            // of the fire() method, we could resume waiting on an empty queue
2203                            // without having filed the change request. That filing will
2204                            // no longer succeed in interrupting this wait, since
2205                            // stopFire() has already been called. Only on the next
2206                            // instance of change request would the first change
2207                            // request get a chance to execute.
2208                            workspace().wait(_eventQueueLock);
2209                        } catch (InterruptedException e) {
2210                            // If the wait is interrupted,
2211                            // then stop waiting.
2212                            break;
2213                        }
2214                    } // Close the blocking read while loop
2215
2216                    // To reach this point, either the event queue is not empty,
2217                    // or _stopRequested or _stopFireRequested is true, or an interrupted exception
2218                    // happened.
2219                    if (_eventQueue.isEmpty()) {
2220                        // Stop is requested or this method is interrupted.
2221                        // This can occur, for example, if a change has been requested.
2222                        // jump out of the loop: LOOPLABEL::GetNextEvent
2223                        return null;
2224                    }
2225                    // At least one event is found in the event queue.
2226                    nextEvent = _eventQueue.get();
2227                } // Close synchronized block
2228            }
2229
2230            // This is the end of the different behaviors of embedded and
2231            // top-level directors on getting the next event.
2232            // When this point is reached, the nextEvent can not be null.
2233            // In the rest of this method, this is not checked any more.
2234
2235            // If the actorToFire is null, find the destination actor associated
2236            // with the event just found. Store this event as lastFoundEvent and
2237            // go back to continue the GetNextEvent loop.
2238            // Otherwise, check whether the event just found goes to the
2239            // same actor to be fired. If so, dequeue that event and continue
2240            // the GetNextEvent loop. Otherwise, jump out of the GetNextEvent
2241            // loop.
2242            // TESTIT
2243            if (actorToFire == null) {
2244                // If the actorToFire is not set yet,
2245                // find the actor associated with the event just found,
2246                // and update the current tag with the event tag.
2247                Time currentTime;
2248                int depth = 0;
2249                try {
2250                    synchronized (_eventQueueLock) {
2251                        lastFoundEvent = _eventQueue.get();
2252                        currentTime = _consultTimeRegulators(
2253                                lastFoundEvent.timeStamp());
2254
2255                        // NOTE: Synchronize to real time here for backward compatibility,
2256                        // but the preferred way to do this is now to use a
2257                        // {@link SynchronizeToRealTime} attribute, which implements the
2258                        //  {@link TimeRegulator} interface.
2259                        if (_synchronizeToRealTime) {
2260                            // If synchronized to the real time.
2261                            Manager manager = ((CompositeActor) getContainer())
2262                                    .getManager();
2263                            while (!_stopRequested && !_stopFireRequested) {
2264                                lastFoundEvent = _eventQueue.get();
2265                                currentTime = lastFoundEvent.timeStamp();
2266
2267                                if (currentTime
2268                                        .compareTo(getModelStopTime()) > 0) {
2269                                    // Next event is past the stop time of the model.
2270                                    // Do not stall.
2271                                    break;
2272                                }
2273
2274                                long elapsedTime = elapsedTimeSinceStart();
2275
2276                                // NOTE: We assume that the elapsed time can be
2277                                // safely cast to a double.  This means that
2278                                // the DE domain has an upper limit on running
2279                                // time of Double.MAX_VALUE milliseconds.
2280                                double elapsedTimeInSeconds = elapsedTime
2281                                        / 1000.0;
2282                                ptolemy.actor.util.Time elapsed = new ptolemy.actor.util.Time(
2283                                        this, elapsedTimeInSeconds);
2284                                if (currentTime.compareTo(elapsed) <= 0) {
2285                                    // Enough real time has passed already. Do not stall.
2286                                    break;
2287                                }
2288
2289                                // NOTE: We used to do the following, but it had a limitation.
2290                                // In particular, if any user code also calculated the elapsed
2291                                // time and then constructed a Time object to post an event
2292                                // on the event queue, there was no assurance that the quantization
2293                                // would be the same, and hence it was possible for that event
2294                                // to be in the past when posted, even if done in the same thread.
2295                                // To ensure that the comparison of current time against model time
2296                                // always yields the same result, we have to do the comparison using
2297                                // the Time class, which is what the event queue does.
2298                                /*
2299                                if (currentTime.getDoubleValue() <= elapsedTimeInSeconds) {
2300                                    break;
2301                                }*/
2302
2303                                long timeToWait = (long) (currentTime
2304                                        .subtract(elapsed).getDoubleValue()
2305                                        * 1000.0);
2306
2307                                if (timeToWait > 0) {
2308                                    if (_debugging) {
2309                                        _debug("Waiting for real time to pass: "
2310                                                + timeToWait);
2311                                    }
2312
2313                                    try {
2314                                        // NOTE: The built-in Java wait() method
2315                                        // does not release the
2316                                        // locks on the workspace, which would block
2317                                        // UI interactions and may cause deadlocks.
2318                                        // SOLUTION: explicitly release read permissions.
2319                                        depth = _workspace
2320                                                .releaseReadPermission();
2321                                        // Allow change requests to execute immediately while we are waiting.
2322                                        // This will have the side effect of executing any pending change requests.
2323                                        setDeferringChangeRequests(false);
2324                                        // Tell the manager what thread is waiting.
2325                                        manager.setWaitingThread(
2326                                                Thread.currentThread());
2327                                        _eventQueueLock.wait(timeToWait);
2328                                    } catch (InterruptedException ex) {
2329                                        // Ignore and circulate around the loop.
2330                                        // The interrupt could be due to a change request,
2331                                        // which we will want to process.
2332                                        // This used to do the following with flawed reasoning:
2333                                        /*
2334                                        throw new IllegalActionException(
2335                                            this,
2336                                            ex,
2337                                            "Thread interrupted when waiting for"
2338                                                    + " real time to match model time.");
2339                                        */
2340                                        // The reasoning was:
2341                                        // Continue executing?
2342                                        // No, because this could be a problem if any
2343                                        // actor assumes that model time always exceeds
2344                                        // real time when synchronizeToRealTime is set.
2345                                        //
2346                                        // But this is flawed because we are in a while loop
2347                                        // that will check again for matching to real time.
2348                                        // EAL 10/27/15.
2349                                    } finally {
2350                                        setDeferringChangeRequests(true);
2351                                        manager.setWaitingThread(null);
2352                                    }
2353                                }
2354                            } // while
2355                              // If stopFire() has been called, then the wait for real
2356                              // time above was interrupted by a change request. Hence,
2357                              // real time will not have reached the time of the first
2358                              // event in the event queue. If we allow this method to
2359                              // proceed, it will set model time to that event time,
2360                              // which is in the future. This violates the principle
2361                              // of synchronize to real time.  Hence, we must return
2362                              // without processing the event or incrementing time.
2363
2364                            // NOTE: CompositeActor used to call stopFire() before
2365                            // queuing the change request, which created the risk
2366                            // that the above wait() would be terminated by
2367                            // a notifyAll() on _eventQueue with _stopFireRequested
2368                            // having been set, but before the change request has
2369                            // actually been filed.  See CompositeActor.requestChange().
2370                            // Does this matter? It means that on the next invocation
2371                            // of the fire() method, we could resume processing the
2372                            // same event, waiting for real time to elapse, without
2373                            // having filed the change request. That filing will
2374                            // no longer succeed in interrupting this wait, since
2375                            // stopFire() has already been called. Alternatively,
2376                            // before we get to the wait for real time in the next
2377                            // firing, the change request could complete and be
2378                            // executed.
2379                            if (_stopRequested || _stopFireRequested) {
2380                                return null;
2381                            }
2382                        } // if (_synchronizeToRealTime)
2383                    } // sync
2384                } finally {
2385                    if (depth > 0) {
2386                        _workspace.reacquireReadPermission(depth);
2387                    }
2388                }
2389
2390                // Consume the earliest event from the queue. The event must be
2391                // obtained here, since a new event could have been enqueued
2392                // into the queue while the queue was waiting. Note however
2393                // that this would usually be an error. Any other thread that
2394                // posts events in the event queue should do so in a change request,
2395                // which will not be executed during the above wait.
2396                // Nonetheless, we are conservative here, and take the earliest
2397                // event in the event queue.
2398                synchronized (_eventQueueLock) {
2399                    lastFoundEvent = _eventQueue.take();
2400                    currentTime = lastFoundEvent.timeStamp();
2401                    actorToFire = lastFoundEvent.actor();
2402
2403                    // NOTE: The _enqueueEvent method discards the events
2404                    // for disabled actors.
2405                    if (_disabledActors != null
2406                            && _disabledActors.contains(actorToFire)) {
2407                        // This actor has requested not to be fired again.
2408                        if (_debugging) {
2409                            _debug("Skipping disabled actor: ",
2410                                    ((Nameable) actorToFire).getFullName());
2411                        }
2412
2413                        actorToFire = null;
2414
2415                        // start a new iteration of the loop:
2416                        // LOOPLABEL::GetNextEvent
2417                        continue;
2418                    }
2419
2420                    // Advance the current time to the event time.
2421                    // NOTE: This is the only place that the model time changes.
2422                    setModelTime(currentTime);
2423
2424                    // Advance the current microstep to the event microstep.
2425                    _microstep = lastFoundEvent.microstep();
2426                    if (_debugging) {
2427                        _debug("Current time is: (" + currentTime + ", "
2428                                + _microstep + ")");
2429                    }
2430                    // Exceeding stop time means the current time is strictly
2431                    // bigger than the model stop time.
2432                    if (currentTime.compareTo(getModelStopTime()) > 0) {
2433                        if (_debugging) {
2434                            _debug("Current time has passed the stop time.");
2435                        }
2436
2437                        _exceedStopTime = true;
2438                        return null;
2439                    }
2440                }
2441            } else { // i.e., actorToFire != null
2442                // In a previous iteration of this while loop,
2443                // we have already found an event and the actor to react to it.
2444                // Check whether the newly found event has the same tag
2445                // and destination actor. If so, they are
2446                // handled at the same time. For example, a pure
2447                // event and a trigger event that go to the same actor.
2448                if (nextEvent.hasTheSameTagAs(lastFoundEvent)
2449                        && nextEvent.actor() == actorToFire) {
2450                    // Consume the event from the queue and discard it.
2451                    // In theory, there should be no event with the same depth
2452                    // as well as tag because
2453                    // the DEEvent class equals() method returns true in this
2454                    // case, and the CalendarQueue class does not enqueue an
2455                    // event that is equal to one already on the queue.
2456                    // Note that the Repeat actor, for one, produces a sequence
2457                    // of outputs, each of which will have the same microstep.
2458                    // These reduce to a single event in the event queue.
2459                    // The DEReceiver in the downstream port, however,
2460                    // contains multiple tokens. When the one event on
2461                    // event queue is encountered, then the actor will
2462                    // be repeatedly fired until it has no more input tokens.
2463                    // However, there could be events with the same tag
2464                    // and different depths, e.g. a trigger event and a pure
2465                    // event going to the same actor.
2466                    synchronized (_eventQueueLock) {
2467                        _eventQueue.take();
2468                    }
2469                } else {
2470                    // Next event has a future tag or a different destination.
2471                    break;
2472                }
2473            }
2474            if (actorToFire != null && _aspectsPresent) {
2475                if (_actorsFinished.contains(actorToFire)) {
2476                    _actorsFinished.remove(actorToFire);
2477                } else if (!_schedule((NamedObj) actorToFire, getModelTime())) {
2478                    _nextScheduleTime.get(_aspectForActor.get(actorToFire))
2479                            .add(getModelTime());
2480                    if (_actorsInExecution == null) {
2481                        _actorsInExecution = new HashMap();
2482                    }
2483                    List<DEEvent> events = _actorsInExecution.get(actorToFire);
2484                    if (events == null) {
2485                        events = new ArrayList<DEEvent>();
2486                    }
2487                    events.add(lastFoundEvent);
2488                    _actorsInExecution.put(actorToFire, events);
2489                    actorToFire = null;
2490                }
2491            }
2492        } // close the loop: LOOPLABEL::GetNextEvent
2493
2494        // Note that the actor to be fired can be null.
2495        return actorToFire;
2496    }
2497
2498    /** In DE, a warning is issued when execution aspects are used because
2499     *  these might change the DE semantics of the execution. In Ptides,
2500     *  this is not the case.
2501     *  @exception IllegalActionException If thrown by getExecutionAspect().
2502     */
2503    protected void _issueExecutionAspectWarning()
2504            throws IllegalActionException {
2505        if (_executionAspects.size() > 0) {
2506            boolean _aspectUsed = false;
2507            if (getContainer() instanceof CompositeActor) {
2508                for (Object entity : ((CompositeActor) getContainer())
2509                        .entityList()) {
2510                    Actor actor = (Actor) entity;
2511                    if (getExecutionAspect((NamedObj) actor) != null) {
2512                        _aspectUsed = true;
2513                        break;
2514                    }
2515                }
2516            }
2517            if (_aspectUsed) {
2518                //if (!MessageHandler.yesNoQuestion(
2519                System.out.println(
2520                        "WARNING: The execution aspects in this model can "
2521                                + "influence the timing of actors by delaying the \n"
2522                                + "execution, potentially changing the behavior. "
2523                                + "There is no guarantee that actors fire at the \n"
2524                                + "time they request to be fired. \n"
2525                                + "Use Ptides for deterministic DE behavior that is "
2526                                + "not influenced by execution aspects. \n");
2527                //+ "Continue?")) {
2528                //stop();
2529                //}
2530            }
2531        }
2532    }
2533
2534    /** There are no actor to fire. In this base class, do nothing. Subclasses
2535     *  may override this method in case there is no actor to fire.
2536     *  @exception IllegalActionException Not thrown in this base class.
2537     *  Derived classes may throw it if unable to get the next actuation
2538     *  event.
2539     */
2540    protected void _noActorToFire() throws IllegalActionException {
2541    }
2542
2543    /** Schedule an actor for execution on a ExecutionAspect. If the actor can
2544     *  execute this method returns true. If resources are not available this
2545     *  method returns false.
2546     *
2547     *  @param actor The actor.
2548     *  @param timestamp The time the actor requests to be scheduled.
2549     *  @return True if actor was scheduled and can be fired.
2550     *  @exception IllegalActionException Thrown if parameters cannot be read, actor cannot be
2551     *   scheduled or container cannot be fired at future time.
2552     */
2553    @Override
2554    protected boolean _schedule(NamedObj actor, Time timestamp)
2555            throws IllegalActionException {
2556        boolean schedule = super._schedule(actor, timestamp);
2557        if (!schedule) {
2558            ActorExecutionAspect scheduler = getExecutionAspect(actor);
2559            if (scheduler != null) {
2560                ((CompositeActor) scheduler.getContainer()).getDirector()
2561                        .fireAt((Actor) scheduler, getModelTime()
2562                                .add(_nextScheduleTime.get(scheduler)));
2563            } else {
2564                throw new InternalErrorException(this, null,
2565                        "_getExecutionAspect(" + actor.getFullName()
2566                                + ") returned null?");
2567            }
2568        }
2569        return schedule;
2570    }
2571
2572    /** Actors and their matching events currently in execution and waiting
2573     *  for resources.
2574     */
2575    protected HashMap<Actor, List<DEEvent>> _actorsInExecution;
2576
2577    /** Actors that just got granted all the resources they needed for
2578     *  execution but have not actually been fired yet. After the actor
2579     *  is fired, it is removed from this list.
2580     */
2581    protected List<Actor> _actorsFinished;
2582
2583    ///////////////////////////////////////////////////////////////////
2584    ////                         protected variables               ////
2585
2586    /** The set of actors that have returned false in their postfire()
2587     *  methods. Events destined for these actors are discarded and
2588     *  the actors are  never fired.
2589     */
2590    protected Set<Actor> _disabledActors;
2591
2592    /** The queue used for sorting events. */
2593    protected DEEventQueue _eventQueue;
2594
2595    /** The lock for the queue. */
2596    protected Object _eventQueueLock = new Object();
2597
2598    /** A local boolean variable indicating whether this director is in
2599     *  initialization phase execution.
2600     */
2601    protected boolean _isInitializing = false;
2602
2603    /** The current microstep. */
2604    protected int _microstep = 1;
2605
2606    /** Set to true when it is time to end the execution. */
2607    protected boolean _noMoreActorsToFire = false;
2608
2609    /** Flag that stopFire() has been called. */
2610    protected boolean _stopFireRequested = false;
2611
2612    ///////////////////////////////////////////////////////////////////
2613    ////                         private methods                   ////
2614
2615    /** Return the nearest enclosing director that implements
2616     *  SuperdenseTimeDirector, or null if there
2617     *  is none.  The enclosing SuperdenseTimeDirector director is a director
2618     *  above this in the hierarchy, possibly separated by composite
2619     *  actors with actors that implement the QuasiTransparentDirector
2620     *  interface, such as FSMDirector or CaseDirector.
2621     *  @return The enclosing ContinuousDirector, or null if there is none.
2622     */
2623    private SuperdenseTimeDirector _enclosingSuperdenseTimeDirector() {
2624        if (_enclosingSuperdenseTimeDirectorVersion != _workspace
2625                .getVersion()) {
2626            // Update the cache.
2627            _enclosingSuperdenseTimeDirector = null;
2628            NamedObj container = getContainer().getContainer();
2629            while (container != null) {
2630                if (container instanceof Actor) {
2631                    Director director = ((Actor) container).getDirector();
2632                    if (director instanceof SuperdenseTimeDirector) {
2633                        _enclosingSuperdenseTimeDirector = (SuperdenseTimeDirector) director;
2634                        break;
2635                    }
2636                    if (!(director instanceof QuasiTransparentDirector)) {
2637                        break;
2638                    }
2639                }
2640                container = container.getContainer();
2641            }
2642            _enclosingSuperdenseTimeDirectorVersion = _workspace.getVersion();
2643        }
2644        return _enclosingSuperdenseTimeDirector;
2645    }
2646
2647    /** initialize parameters. Set all parameters to their default values.
2648     */
2649    private void _initParameters() {
2650        _verbose = true;
2651        _defaultMicrostep = 1;
2652        try {
2653            stopWhenQueueIsEmpty = new Parameter(this, "stopWhenQueueIsEmpty");
2654            stopWhenQueueIsEmpty.setExpression("true");
2655            stopWhenQueueIsEmpty.setTypeEquals(BaseType.BOOLEAN);
2656
2657            synchronizeToRealTime = new Parameter(this,
2658                    "synchronizeToRealTime");
2659            synchronizeToRealTime.setExpression("false");
2660            synchronizeToRealTime.setTypeEquals(BaseType.BOOLEAN);
2661
2662            isCQAdaptive = new Parameter(this, "isCQAdaptive");
2663            isCQAdaptive.setExpression("true");
2664            isCQAdaptive.setTypeEquals(BaseType.BOOLEAN);
2665            isCQAdaptive.setVisibility(Settable.EXPERT);
2666
2667            minBinCount = new Parameter(this, "minBinCount");
2668            minBinCount.setExpression("2");
2669            minBinCount.setTypeEquals(BaseType.INT);
2670            minBinCount.setVisibility(Settable.EXPERT);
2671
2672            binCountFactor = new Parameter(this, "binCountFactor");
2673            binCountFactor.setExpression("2");
2674            binCountFactor.setTypeEquals(BaseType.INT);
2675            binCountFactor.setVisibility(Settable.EXPERT);
2676
2677            enforceMicrostepSemantics = new Parameter(this,
2678                    "enforceMicrostepSemantics");
2679            enforceMicrostepSemantics.setExpression("false");
2680            enforceMicrostepSemantics.setTypeEquals(BaseType.BOOLEAN);
2681        } catch (KernelException e) {
2682            throw new InternalErrorException(
2683                    "Cannot set parameter:\n" + e.getMessage());
2684        }
2685    }
2686
2687    /** Request that the container of this director be refired in some
2688     *  future time specified by the first event of the local event queue.
2689     *  This method is used when the director is embedded inside an opaque
2690     *  composite actor. If the queue is empty, then throw an
2691     *  IllegalActionException.
2692     *  @exception IllegalActionException If the queue is empty, or
2693     *   if the executive director does not respect the fireAt() call.
2694     */
2695    protected void _requestFiring() throws IllegalActionException {
2696        DEEvent nextEvent = null;
2697        synchronized (_eventQueueLock) {
2698            nextEvent = _eventQueue.get();
2699        }
2700
2701        if (_debugging) {
2702            CompositeActor container = (CompositeActor) getContainer();
2703            _debug("DEDirector: Requests refiring of: " + container.getName()
2704                    + " at time " + nextEvent.timeStamp());
2705        }
2706
2707        // Enqueue a pure event to fire the container of this director.
2708        fireContainerAt(nextEvent.timeStamp(), nextEvent.microstep());
2709    }
2710
2711    ///////////////////////////////////////////////////////////////////
2712    ////                         private variables                 ////
2713
2714    /** Indicator that calls to fireAt() should be delegated
2715     *  to the executive director.
2716     */
2717    private boolean _delegateFireAt = false;
2718
2719    /** Cache for the enclosing superdense time director. */
2720    private SuperdenseTimeDirector _enclosingSuperdenseTimeDirector;
2721
2722    /** Cache version for the enclosing superdense time director. */
2723    private long _enclosingSuperdenseTimeDirectorVersion = -1;
2724
2725    /** Cached value of enforceMicrostepSemantics parameter. */
2726    private boolean _enforceMicrostepSemantics = false;
2727
2728    /** Set to true when the time stamp of the token to be dequeue
2729     *  has exceeded the stopTime.
2730     */
2731    private boolean _exceedStopTime = false;
2732
2733    /** Decide whether the simulation should be stopped when there's no more
2734     *  events in the global event queue. By default, its value is 'true',
2735     *  meaning that the simulation will stop under that circumstances.
2736     *  Setting it to 'false', instruct the director to wait on the queue
2737     *  while some other threads might enqueue events in it.
2738     */
2739    private boolean _stopWhenQueueIsEmpty = true;
2740
2741    /** Specify whether the director should wait for elapsed real time to
2742     *  catch up with model time.
2743     */
2744    private boolean _synchronizeToRealTime;
2745
2746    ///////////////////////////////////////////////////////////////////
2747    ////                         inner classes                     ////
2748
2749    /** Causality interface for the DEDirector that reflects the limitations
2750     *  from not having an implementation that computes a fixed point.
2751     *  Specifically, this causality interface extends CausalityInterfaceForComposites
2752     *  so that it can do the depth analysis internally, but for the ports
2753     *  of the container, it declares that all outputs depend on all inputs.
2754     *  This is necessary to ensure that if a DE opaque composite is fired
2755     *  only when all inputs at the current microstep are known. See
2756     *  $PTII/ptolemy/domains/de/test/auto/DEFixedPointLimitation.xml.
2757     */
2758    private static class DECausalityInterface
2759            extends CausalityInterfaceForComposites {
2760        // FindBugs indicates that this should be a static class.
2761
2762        /** Construct a causality interface for the specified actor.
2763         *  @param actor The actor for which this is a causality interface.
2764         *   This is required to be an instance of CompositeEntity.
2765         *  @param defaultDependency The default dependency of an output
2766         *   port on an input port.
2767         *  @exception IllegalArgumentException If the actor parameter is not
2768         *  an instance of CompositeEntity.
2769         */
2770        public DECausalityInterface(Actor actor, Dependency defaultDependency)
2771                throws IllegalArgumentException {
2772            super(actor, defaultDependency);
2773        }
2774
2775        /** Return a collection of the ports in this actor that depend on
2776         *  or are depended on by the specified port. A port X depends
2777         *  on a port Y if X is an output and Y is an input and
2778         *  getDependency(X,Y) returns oTimesIdentity()
2779         *  of the default dependency specified in the constructor.
2780         *  <p>
2781         *  This class presumes (but does not check) that the
2782         *  argument is a port contained by the associated actor.
2783         *  If the actor is an input, then it returns a collection of
2784         *  all the outputs. If the actor is output, then it returns
2785         *  a collection of all the inputs.
2786         *  @param port The port to find the dependents of.
2787         *  @return a collection of ports that depend on or are depended on
2788         *   by the specified port.
2789         *  @exception IllegalActionException Not thrown in this base class.
2790         */
2791        @Override
2792        public Collection<IOPort> dependentPorts(IOPort port)
2793                throws IllegalActionException {
2794            if (port.isOutput()) {
2795                if (port.isInput()) {
2796                    // Port is both input and output.
2797                    HashSet<IOPort> result = new HashSet<IOPort>();
2798                    result.addAll(_actor.inputPortList());
2799                    result.addAll(_actor.outputPortList());
2800                    return result;
2801                }
2802                // Port is output and not input.
2803                return _actor.inputPortList();
2804            } else if (port.isInput()) {
2805                // Port is input and not output.
2806                return _actor.outputPortList();
2807            } else {
2808                // Port is neither input nor output.
2809                return _EMPTY_COLLECTION;
2810            }
2811        }
2812
2813        /** Return a collection of the input ports in this actor that are
2814         *  in the same equivalence class with the specified input
2815         *  port. This class returns a collection of all
2816         *  the input ports of the container actor.
2817         *  @param input The port to find the equivalence class of.
2818         *  @return set of the input ports in this actor that are
2819         *  in an equivalence class with the specified input.
2820         *  @exception IllegalArgumentException If the argument is not
2821         *   contained by the associated actor.
2822         *  @exception IllegalActionException Not thrown in this base class.
2823         */
2824        @Override
2825        public Collection<IOPort> equivalentPorts(IOPort input)
2826                throws IllegalActionException {
2827            if (input.getContainer() != _actor || !input.isInput()) {
2828                throw new IllegalArgumentException(
2829                        "equivalentPort() called with argument "
2830                                + input.getFullName()
2831                                + " that is not an input port for "
2832                                + _actor.getFullName());
2833            }
2834            return _actor.inputPortList();
2835        }
2836
2837        /** Return the dependency between the specified input port
2838         *  and the specified output port.  This class returns
2839         *  the default dependency if the first port is an input
2840         *  port owned by this actor and the second one is an output
2841         *  port owned by this actor. Otherwise, it returns the
2842         *  additive identity of the dependency.
2843         *  @param input The input port.
2844         *  @param output The output port.
2845         *  @return The dependency between the specified input port
2846         *   and the specified output port.
2847         *  @exception IllegalActionException Not thrown in this base class.
2848         */
2849        @Override
2850        public Dependency getDependency(IOPort input, IOPort output)
2851                throws IllegalActionException {
2852            if (input.isInput() && input.getContainer() == _actor
2853                    && output.isOutput() && output.getContainer() == _actor) {
2854                return _defaultDependency;
2855            }
2856            return _defaultDependency.oPlusIdentity();
2857        }
2858    }
2859}