001/* Continuous-time director.
002
003 Copyright (c) 1998-2016 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
027 */
028package ptolemy.domains.continuous.kernel;
029
030import java.util.Iterator;
031import java.util.LinkedList;
032import java.util.List;
033
034import ptolemy.actor.Actor;
035import ptolemy.actor.CompositeActor;
036import ptolemy.actor.Director;
037import ptolemy.actor.IOPort;
038import ptolemy.actor.QuasiTransparentDirector;
039import ptolemy.actor.continuous.ContinuousStatefulComponent;
040import ptolemy.actor.continuous.ContinuousStatefulDirector;
041import ptolemy.actor.continuous.ContinuousStepSizeController;
042import ptolemy.actor.sched.FixedPointDirector;
043import ptolemy.actor.util.GeneralComparator;
044import ptolemy.actor.util.SuperdenseTime;
045import ptolemy.actor.util.Time;
046import ptolemy.actor.util.TotallyOrderedSet;
047import ptolemy.data.DoubleToken;
048import ptolemy.data.IntToken;
049import ptolemy.data.expr.Parameter;
050import ptolemy.data.expr.StringParameter;
051import ptolemy.data.type.BaseType;
052import ptolemy.kernel.CompositeEntity;
053import ptolemy.kernel.util.Attribute;
054import ptolemy.kernel.util.IllegalActionException;
055import ptolemy.kernel.util.InternalErrorException;
056import ptolemy.kernel.util.InvalidStateException;
057import ptolemy.kernel.util.NameDuplicationException;
058import ptolemy.kernel.util.NamedObj;
059import ptolemy.kernel.util.Settable;
060import ptolemy.kernel.util.Workspace;
061
062///////////////////////////////////////////////////////////////////
063//// ContinuousDirector
064
065/**
066 The continuous time domain is a timed domain that supports
067 continuous-time signals, discrete-event signals, and mixtures of the
068 two. There is a global notion of time that all the actors are aware of.
069 The semantics of this domain is given in the following two papers:
070 <ul>
071 <li>
072 Edward A. Lee and Haiyang Zheng, "<a href="http://ptolemy.eecs.berkeley.edu/publications/papers/05/OperationalSemantics/#in_browser">Operational Semantics of Hybrid Systems</a>,"
073 Invited paper in Proceedings of Hybrid Systems: Computation and Control
074 (HSCC) LNCS 3414, Zurich, Switzerland, March 9-11, 2005.</li>
075 <li>
076 Edward A. Lee, Haiyang Zheng, "<a href="http://ptolemy.eecs.berkeley.edu/publications/papers/07/unifying/index.htm#in_browser">Leveraging Synchronous Language Principles for Heterogeneous Modeling and Design of Embedded Systems</a>,"
077 EMSOFT 07, September 30-October 3, 2007, Salzburg, Austria.</li>
078 </ul>
079 <p>
080 A signal is a set of "events," each of which has a tag and value.
081 The set of values includes a special element, called "absent", denoting
082 the absence of a (normal) value.
083 This director uses superdense time, where every event has a tag
084 that is a member of the set RxN.
085 R is a connected subset of the real numbers (giving "time",
086 and approximated by instances of the Time class),
087 and N is the natural numbers (giving an "index").
088 At a time <i>t</i>, a signal
089 may have multiple values in sequence with tags
090 (<i>t</i>, 0), (<i>t</i>, 1)... Its "initial value" is the value
091 at tag (<i>t</i>, 0). It typically settles to
092 a "final value" after a finite number of indices.
093 If it fails to settle to a final value, the signal is said to
094 have a "stuttering Zeno" condition, and time will not progress.</p>
095 <p>
096 In our semantics, all signals are piecewise continuous.
097 This means that the initial value, as a function of time,
098 is continuous on the left, the final value, as a function
099 of time, is continuous on the right, and the signal
100 has exactly one value (meaning the initial value and the final value
101 are the same) at all times except those
102 on a discrete subset D.</p>
103 <p>
104 A purely continuous signal has exactly one value at
105 all times, meaning that the final value equals the initial
106 value at all times.
107 A purely discrete signal has
108 initial value "absent" and final value "absent" at all
109 times, and at a discrete subset of the times, it may
110 have non-absent values. The only signal that is both
111 purely continuous and purely discrete is the one that
112 is absent at all tags.</p>
113 <p>
114 A signal may be mostly continuous,
115 but have multiple values at a discrete subset of times.
116 These multiple values semantically represent discontinuities
117 in a continuous signal that is not purely continuous.</p>
118 <p>
119 The set of times where signals have more than one distinct value
120 is a discrete subset D of the time line. These times are called
121 "breakpoints" and are treated specially in the execution.
122 Between these times, an ordinary differential equation (ODE)
123 solver governs the execution. Initial values are always given
124 by the ODE solver.</p>
125 <p>
126 The parameters of this director are:
127 <ul>
128 <li> <i>startTime</i>: The start time of the
129 execution.</li>
130
131 <li> <i>stopTime</i>: The stop time of the execution.
132 When the current time reaches this value, postfire() will return false.
133 This will occur whether or not this director is at the top level.</li>
134
135 <li> <i>initStepSize</i>: The suggested integration step size.
136 If the ODE solver is a fixed step size solver, then this parameter
137 gives the step size taken. Otherwise, at the start of execution,
138 this provides the first guess for the integration step size.
139 In later iterations, the integrators provide the suggested step
140 size. This is a double with default value 0.1</li>
141
142 <li> <i>maxStepSize</i>: The maximum step size.
143 This can be used to prevent the solver from too few
144 samples of signals. That is, for certain models, it might
145 be possible to get accurate results for very large step
146 sizes, but plots of the signals may be misleading (even
147 if they are accurate) because they represent the signal
148 with only a few samples. The default value is 1.0.</li>
149
150 <li> <i>maxIterations</i>:
151 The maximum number of iterations that an
152 ODE solver can use to resolve the states of integrators.
153 Implicit solvers, for example, iterate until they converge,
154 and this parameter bounds the number of iterations.
155 An example of an implicit solver is the BackwardsEuler solver.
156 The default value is 20, and the type is int.
157 FIXME: Currently, this package implements no implicit solvers.</li>
158
159 <li> <i>ODESolver</i>:
160 The class name of the ODE solver used for integration.
161 This is a string that defaults to "ExplicitRK23Solver",
162 a solver that tends to deliver smooth renditions of signals.
163 The "ExplicitRK45Solver" may be more efficient in that it can
164 use larger step sizes, but the resulting signals when displayed
165 may be more jagged in appearance.
166 Solvers are all required to be in package
167 "ptolemy.domains.continuous.kernel.solver".
168 If there is another ContinuousDirector above this one
169 in the hierarchy, then the value of this parameter is ignored and the
170 solver given by the first ContinuousDirector above will be used.</li>
171
172 <li> <i>errorTolerance</i>: This is the local truncation
173 error tolerance, used for controlling the integration accuracy
174 in variable step size ODE solvers, and also for determining whether
175 unpredictable breakpoints have been accurately identified. Any actor
176 that implements ContinuousStepSizeControl may use this error
177 tolerance to determine whether the current step is accurate.
178 For example, if the local truncation error
179 in some integrator is greater than this tolerance, then the
180 integration step is considered to have failed, and should be restarted with
181 a reduced step size. The default value is 1e-4.</li>
182 </ul>
183 <p>
184 This director maintains a breakpoint table to record all predictable
185 breakpoints that are greater than or equal to
186 the current time. The breakpoints are sorted in chronological order.
187 Breakpoints at the same time are considered to be identical, and the
188 breakpoint table does not contain duplicate time points. A breakpoint can
189 be inserted into the table by calling the fireAt() method. The fireAt method
190 may be requested by the director, which inserts the stop time of the
191 execution. The fireAt method may also be requested by actors and the
192 requested firing time will be inserted into the breakpoint table.</p>
193 <p>
194 This director is designed to work with any other director that
195 implements the strict actor semantics. As long as the other director does
196 not commit state changes except in postfire(), that director
197 can be used within the model controlled by
198 this director. If, in addition to implementing the strict
199 actor semantics that other director also respects calls to
200 fireAt(), then this director may be used within a model
201 governed by that director.</p>
202 <p>
203 This director is based on the CTDirector by Jie Liu and Haiyang Zheng,
204 but it has a much simpler scheduler and a fixed-point semantics.</p>
205
206 @author Haiyang Zheng and Edward A. Lee, based on CTDirector by Jie Liu and Haiyang Zheng
207 @version $Id$
208 @since Ptolemy II 6.0
209 @Pt.ProposedRating Yellow (hyzheng)
210 @Pt.AcceptedRating Red (hyzheng)
211 */
212public class ContinuousDirector extends FixedPointDirector
213        implements ContinuousStatefulDirector, ContinuousStepSizeController {
214
215    /** Construct a director in the given container with the given name.
216     *  The container argument must not be null, or a NullPointerException
217     *  will be thrown.
218     *  If the name argument is null, then the name is set to the
219     *  empty string. All the parameters take their default values.
220     *  @param container The container.
221     *  @param name Name of this director.
222     *  @exception IllegalActionException If the director is not compatible
223     *   with the specified container. May be thrown by a derived class.
224     *  @exception NameDuplicationException If the name collides with
225     *   a property in the container.
226     */
227    public ContinuousDirector(CompositeEntity container, String name)
228            throws IllegalActionException, NameDuplicationException {
229        super(container, name);
230        _initParameters();
231        setScheduler(new ContinuousScheduler(this, "scheduler"));
232    }
233
234    ///////////////////////////////////////////////////////////////////
235    ////                         parameters                        ////
236
237    /** Error tolerance for data values, used with variable step
238     *  size solvers to determine whether the current step size is accurate.
239     *  The default value is 1e-4, and the type is double.
240     */
241    public Parameter errorTolerance;
242
243    /** User's hint for the initial integration step size.
244     *  The default value is 0.1, and the type is double.
245     */
246    public Parameter initStepSize;
247
248    /** The maximum number of rounds that an
249     *  ODE solver can use to resolve the states of integrators.
250     *  Many solvers, such as RK 2-3 and RK 4-5, use a fixed number
251     *  of rounds (3 and 6, respectively). Implicit ODE solvers use
252     *  however many rounds it takes to converge to a solution within
253     *  a specified accuracy (given by <i>errorTolerance</i>).
254     *  An example of an implicit solver is the BackwardsEuler solver.
255     *  This parameter limits the number of rounds.
256     *  The default value is 20, and the type is int.
257     */
258    public Parameter maxIterations;
259
260    /** The maximum step size.
261     *  The default value is 1.0, and the type is double.
262     */
263    public Parameter maxStepSize;
264
265    /** The class name of the ODE solver used for integration.
266     *  This is a string that defaults to "ExplicitRK23Solver".
267     *  Solvers are all required to be in package
268     *  "ptolemy.domains.continuous.kernel.solver".
269     *  If a solver is changed during execution, the
270     *  change does not take effect until the next execution
271     *  of the model.
272     *  If there is another ContinuousDirector above this one
273     *  in the hierarchy, separated possibly by MultiComposite,
274     *  then the value of this parameter is ignored and the
275     *  solver given by the other ContinuousDirector will be used.
276     */
277    public StringParameter ODESolver;
278
279    ///////////////////////////////////////////////////////////////////
280    ////                         public methods                    ////
281
282    /** React to a change in an attribute. If the changed attribute
283     *  matches a parameter of the director, then the corresponding
284     *  local copy of the parameter value will be updated.
285     *  @param attribute The changed parameter.
286     *  @exception IllegalActionException If the new parameter value
287     *  is not valid.
288     */
289    @Override
290    public void attributeChanged(Attribute attribute)
291            throws IllegalActionException {
292        if (_debugging) {
293            _debug("attributeChanged: Updating ContinuousDirector parameter: "
294                    + attribute.getName());
295        }
296        if (attribute == errorTolerance) {
297            double value = ((DoubleToken) errorTolerance.getToken())
298                    .doubleValue();
299            if (value < 0.0) {
300                throw new IllegalActionException(this,
301                        "Cannot set a negative error tolerance.");
302            }
303            _errorTolerance = value;
304        } else if (attribute == initStepSize) {
305            double value = ((DoubleToken) initStepSize.getToken())
306                    .doubleValue();
307            if (value < 0.0) {
308                throw new IllegalActionException(this,
309                        "Cannot set a negative step size.");
310            }
311            _initStepSize = value;
312        } else if (attribute == maxIterations) {
313            int value = ((IntToken) maxIterations.getToken()).intValue();
314
315            if (value < 1) {
316                throw new IllegalActionException(this,
317                        "Cannot set a zero or negative iteration number.");
318            }
319            _maxIterations = value;
320        } else if (attribute == maxStepSize) {
321            double value = ((DoubleToken) maxStepSize.getToken()).doubleValue();
322            if (value < 0.0) {
323                throw new IllegalActionException(this,
324                        "Cannot set a negative step size.");
325            }
326            _maxStepSize = value;
327        } else {
328            super.attributeChanged(attribute);
329        }
330    }
331
332    /** Clone the object into the specified workspace. The new object is
333     *  <i>not</i> added to the directory of that workspace (you must do this
334     *  yourself if you want it there).
335     *  @param workspace The workspace for the cloned object.
336     *  @exception CloneNotSupportedException Not thrown in this base class
337     *  @return The new Attribute.
338     */
339    @Override
340    public Object clone(Workspace workspace) throws CloneNotSupportedException {
341        ContinuousDirector newObject = (ContinuousDirector) super.clone(
342                workspace);
343        newObject._breakpoints = null;
344        newObject._enclosingContinuousDirectorVersion = -1L;
345        newObject._ODESolver = null;
346        newObject._statefulComponents = new LinkedList();
347        newObject._statefulComponentsVersion = -1L;
348        newObject._stepSizeControllers = new LinkedList();
349        newObject._stepSizeControllersVersion = -1L;
350        return newObject;
351    }
352
353    /** Perform an integration step. This invokes prefire() and fire() of
354     *  actors (possibly repeatedly) and advances the local view of
355     *  time by one step. This normally involves three nested iterative procedures.
356     *  The outer procedure invokes the possibly multiple steps of
357     *  the solver (if it is a multistep solver), unless the step size
358     *  is zero.  The middle one iterates until a suitable step size is
359     *  found. The inner one, implemented by the superclass,
360     *  iterates until a fixed point is found at each time point.
361     *  <p>
362     *  If there is an enclosing ContinuousDirector, however, then this
363     *  method simply performs the current round of execution of the enclosing
364     *  director, using the step size of the enclosing director.
365     *  @exception IllegalActionException If an actor throws it.
366     */
367    @Override
368    public void fire() throws IllegalActionException {
369        if (_debugging) {
370            _debug("Calling fire() at time " + getModelTime() + " index "
371                    + _index);
372        }
373        // If there is an enclosing director, then just execute
374        // its current round.
375        ContinuousDirector enclosingContinuousDirector = _enclosingContinuousDirector();
376        if (enclosingContinuousDirector != null) {
377            // The local model time is not synchronized here because
378            // the prefire method is responsible for it.
379            _currentStepSize = enclosingContinuousDirector._currentStepSize;
380            int round = enclosingContinuousDirector._ODESolver._getRound();
381            _ODESolver._setRound(round);
382            if (_debugging) {
383                _debug("-- Get step size from enclosing Continuous director: "
384                        + _currentStepSize + ", and also the solver round: "
385                        + round + ".");
386            }
387            _resetAllReceivers();
388            _transferInputsToInside();
389            super.fire();
390            _transferOutputsToEnvironment();
391            return;
392        }
393
394        // If there is a commit pending, then this firing should just
395        // produce the outputs from the speculative execution.
396        // The commit will occur in postfire.
397        if (_commitIsPending) {
398            // We are presumably at superdense index 0 of the environment,
399            // but have already executed superdense index 0 of the local model.
400            // Hence, we should produce outputs now and increment our local
401            // superdense index to 1.
402            _transferOutputsToEnvironment();
403            return;
404        }
405
406        _resetAllReceivers();
407
408        // If there is an enclosing director, we know it is not a ContinuousDirector
409        // because we would have returned above if it were. Inputs from any
410        // enclosing domain that is not continuous are discrete, so we should
411        // not read them if the current superdense index is 0. This would
412        // violate the piecewise continuity constraint.
413        if (!_redoingSolverIteration && _index == 0 && isEmbedded()) {
414            // Check the input ports to see if any has an input. If
415            // it does, set the current step size to zero and execute
416            // one round without the input. The input will be read at
417            // the next superdense time index.
418            List<IOPort> ports = ((Actor) getContainer()).inputPortList();
419            for (IOPort port : ports) {
420                for (int i = 0; i < port.getWidth(); i++) {
421                    if (port.isKnown(i) && port.hasToken(i)) {
422                        // There is an input. Do a zero step-size iteration.
423                        _currentStepSize = 0.0;
424                        _ODESolver._reset();
425                        // Before firing, we need to assert absent on all inside
426                        // ports, since we aren't transferring the inputs.
427                        _assertAbsentInside();
428                        super.fire();
429                        _transferOutputsToEnvironment();
430                        return;
431                    }
432                }
433            }
434        }
435
436        // If there are external inputs and there is no enclosing continuous
437        // director, then those external inputs are to be understood as discrete
438        // inputs. We must process them when we have a step size of zero.
439        // However, if we just backtracked (due to our previous step size
440        // having been too big, and the speculative execution having been
441        // nullified by the appearance of an unexpected event), then we should
442        // not call _transferInptusToInside(), because the environment time
443        // is ahead of the local time and any inputs that might present
444        // are in the future. Presumably, since we are redoing a speculative
445        // solver iteration, there must have been no inputs at the
446        // _iterationBeginTime, which is now our _currentTime.
447        if (!_redoingSolverIteration && _transferInputsToInside()
448                || _currentStepSize == 0.0) {
449            _currentStepSize = 0.0;
450            _ODESolver._reset();
451            super.fire();
452            _transferOutputsToEnvironment();
453            _redoingSolverIteration = false;
454            return;
455        }
456
457        // If we get to here, then we are either at the top level, or we
458        // are enclosed within a director that is not a ContinuousDirector
459        // and there are no external inputs and the step size is greater
460        // than zero.  We now need to perform integration.
461        boolean outputsProduced = false;
462        while (!_stopRequested) {
463            // Some solvers take multiple rounds to perform an integration step.
464            // Tell the solver we are starting an integration step by resetting
465            // the solver.
466            _ODESolver._reset();
467
468            if (_debugging) {
469                _debug("-- Execute from iteration begin time "
470                        + _iterationBeginTime + " with step size "
471                        + _currentStepSize + " at index " + _index + ".");
472            }
473
474            // Iterate until the solver is done with the integration step
475            // or the maximum number of iterations is reached.
476            int iterations = 0;
477            try {
478                _isIntermediateStep = true;
479                while (!_ODESolver._isStepFinished()
480                        && iterations < _maxIterations && !_stopRequested) {
481
482                    _resetAllReceivers();
483
484                    // Set receivers connected to the inputs to "absent."
485                    // Note that this cannot be done by calling
486                    // _transferInputsToInside() because if we are redoing
487                    // the solver iteration then there are inputs available,
488                    // but they should not be consumed yet.
489                    // FIXME: Shouldn't this be done only if enclosingContinousDirector is null?
490                    if (enclosingContinuousDirector == null) {
491                        _assertAbsentInside();
492                    }
493
494                    super.fire();
495                    // Outputs should only be produced on the first iteration of
496                    // the solver because after that we are computing values in
497                    // the future. We should not produce more outputs if we
498                    // reduce the step size and try again because that could
499                    // result in multiple output events where there should only
500                    // be one.
501                    if (!_redoingSolverIteration && !outputsProduced) {
502                        // Outputs need to be produced now, since the
503                        // values at the output ports are now the correct
504                        // values at the _iterationBeginTime, which on
505                        // the first pass through, will match the
506                        // current environment time. We do not do this
507                        // if we are redoing the solver iteration, since
508                        // presumably those outputs were already produced,
509                        // and current time in the environment has passed
510                        // the time that they were produced.
511                        _transferOutputsToEnvironment();
512                        outputsProduced = true;
513                    }
514
515                    // Advance the local view of time such that
516                    // the inputs to the integrators
517                    // can be calculated by firing all the actors.
518                    // Note that this doesn't change global model time.
519                    // It only changes the local view of time.
520                    double timeIncrement = _ODESolver._getRoundTimeIncrement();
521                    // This will return 1.0 when there is one or zero more
522                    // steps for the solver. Hence, the next step will not
523                    // be an intermediate step.
524                    if (timeIncrement == 1.0) {
525                        _isIntermediateStep = false;
526                    }
527                    localClock.setLocalTime(_iterationBeginTime
528                            .add(_currentStepSize * timeIncrement));
529                    _index = 0;
530                    if (_debugging) {
531                        _debug("-- Setting current time for the next ODE solver round: "
532                                + getModelTime() + " and index to 0.");
533                    }
534                    _ODESolver._setRound(_ODESolver._getRound() + 1);
535
536                    if (_debugging) {
537                        _debug("ODE solver solves the round #"
538                                + _ODESolver._getRound());
539                    }
540                    // Increase the iteration count.
541                    iterations++;
542                }
543            } finally {
544                _isIntermediateStep = false;
545                _redoingSolverIteration = false;
546            }
547            // If the step size is accurate and we did not reach the
548            // maximum number of iterations then we are done.
549            // Otherwise, we have to try again with a smaller step size.
550            if (isStepSizeAccurate() && iterations <= _maxIterations) {
551                // All actors agree with the current step size,
552                // or we have reached the maximum allowed number of iterations.
553                // The integration step is finished.
554                break;
555            } else {
556                if (iterations > _maxIterations) {
557                    // If any step size control actor is unsatisfied with the
558                    // current step size, refine the step size to a smaller one.
559                    _setCurrentStepSize(_currentStepSize / 2);
560                } else {
561                    // There is some step size control actor that is
562                    // unsatisfied with the current step size, refine the
563                    // step size to a smaller one.
564                    double refinedStep = refinedStepSize();
565                    // Make sure the result is actually a change.
566                    if (refinedStep >= _currentStepSize) {
567                        // Actors suggestion is not useful.
568                        // Choose instead half the current step size.
569                        refinedStep = _currentStepSize * 0.5;
570                        if (_debugging) {
571                            _debug("-- Adjusting step size to: " + refinedStep);
572                        }
573                    }
574                    _setCurrentStepSize(refinedStep);
575                }
576
577                if (_debugging) {
578                    _debug("-- Step was not accurate. Refine the step size to: "
579                            + _currentStepSize);
580                }
581                // Restore the saved state of the stateful actors,
582                // including the save starting time of this integration.
583                rollBackToCommittedState();
584            }
585        }
586    }
587
588    /** Handle firing requests from the contained actors by registering
589     *  breakpoints. If the specified time is earlier than the current time,
590     *  then request a firing at the current time.
591     *  Otherwise, insert the specified time into the
592     *  breakpoint table. If the specified time is earlier than or
593     *  equal to the current time, then for the breakpoint table entry,
594     *  use an index one larger than the current index, unless this director
595     *  is currently in initialize(), in which case use the current index.
596     *  If the requested time is in the future, then use the requested index.
597     *  @param actor The actor that requests the firing.
598     *  @param time The requested firing time.
599     *  @param index The microstep.
600     *  @return The time at which the actor passed as an argument
601     *   will be fired.
602     *  @exception IllegalActionException If the time is earlier than
603     *  the current time.
604     */
605    @Override
606    public Time fireAt(Actor actor, Time time, int index)
607            throws IllegalActionException {
608        if (_debugging) {
609            String name = "this director";
610            if (actor != null) {
611                name = actor.getName();
612            }
613            _debug("** fireAt() called by " + name
614                    + ", which requests refiring at " + time);
615        }
616        synchronized (_breakpoints) {
617            // Check if the request time is earlier than the current time.
618            Time currentTime = getModelTime();
619            int comparisonResult = time.compareTo(currentTime);
620            // Adjust time to at least match the current time.
621            if (comparisonResult < 0) {
622                time = currentTime;
623            }
624            if (comparisonResult <= 0) {
625                // If during initialization, do not increase the microstep.
626                // This is based on the assumption that an actor only requests
627                // one firing during initialization. In fact, if an actor requests
628                // several firings at the same time,
629                // only the first request will be granted.
630                if (index <= _index) {
631                    if (_isInitializing) {
632                        index = _index;
633                    } else {
634                        index = _index + 1;
635                    }
636                }
637            }
638            // Insert a superdense time object as a breakpoint into the
639            // breakpoint table.
640            _breakpoints.insert(new SuperdenseTime(time, index));
641            if (_debugging) {
642                _debug("** Inserted breakpoint with time = " + time
643                        + ", and index = " + index);
644            }
645            return time;
646        }
647    }
648
649    /** Return the current integration step size.
650     *  @return The current integration step size.
651     */
652    @Override
653    public final double getCurrentStepSize() {
654        // This method is final for performance reason.
655        return _currentStepSize;
656    }
657
658    /** Return the local truncation error tolerance.
659     *  @return The local truncation error tolerance.
660     */
661    @Override
662    public final double getErrorTolerance() {
663        // This method is final for performance reason.
664        return _errorTolerance;
665    }
666
667    /** Initialize model after type resolution.
668     *  If a start time has been explicitly set, then set the start
669     *  time to that value. Otherwise, inherit if from the environment,
670     *  if there is one, and set it to 0.0 otherwise.
671     *  In addition to calling the initialize() method of the super class,
672     *  this method records the current system time as the "real" starting
673     *  time of the execution. This starting time is used when the
674     *  execution is synchronized to real time.
675     *
676     *  @exception IllegalActionException If the super class throws it.
677     */
678    @Override
679    public void initialize() throws IllegalActionException {
680        _isInitializing = true;
681
682        // In case we are being reinitialized by a reset transition,
683        // clear the breakpoint table. This must be done before
684        // actors are initialized because they may call fireAt(),
685        // which will insert items in the breakpoint table.
686        _breakpoints.clear();
687
688        // set current time and initialize actors.
689        super.initialize();
690
691        // The above method sets the microstep to match the enclosing
692        // director if this director is embedded. In the Continuous
693        // domain, however, this is not the right thing to do. We
694        // might be getting initialized within a modal model, in
695        // which case the enclosing director may have a larger
696        // microstep. But we still want to begin with a microstep of zero.
697        // FIXME: No idea whether this is right!
698        // _index = 0;
699
700        // Make sure the first step has zero step size.
701        // This ensures that actors like plotters will be postfired at
702        // the start time.
703        _currentStepSize = 0.0;
704        Time startTime = getModelStartTime();
705        Time stopTime = getModelStopTime();
706        Time currentTime = getModelTime();
707
708        // If this director is embedded, then request a firing at the
709        // start and stop times. However, do not do this if there is
710        // an enclosing ContinuousDirector.
711
712        // The reason for doing this is that if a Continuous composite actor
713        // is embedded in a DE model but has no input ports, without the
714        // following statements, the composite actor has no chance to be fired.
715        // Also, we want to be sure to be fired at the stop time.
716        if (isEmbedded() && _enclosingContinuousDirector() == null) {
717            // In preinitialize(), _startTime was set to the start time of
718            // the executive director. However, this invocation of initialize()
719            // may be occurring later in the execution of a model, as a result
720            // for example of a reset transition. In that case, _startTime
721            // may be in the past relative to the environment time.
722            // The super.initialize() call above should have set our
723            // current time to match the environment time, so we use
724            // the maximum of _startTime and the current time as the
725            // first firing time.
726            if (startTime.compareTo(currentTime) >= 0) {
727                fireContainerAt(startTime, 0);
728            } else {
729                // Use a microstep of 1 here on the assumption
730                // that initialization could create discontinuities.
731                fireContainerAt(currentTime, 1);
732            }
733            if (!stopTime.isInfinite()
734                    && stopTime.compareTo(currentTime) >= 0) {
735                fireContainerAt(stopTime);
736            }
737        }
738        // Set a breakpoint with index 0 for the stop time.
739        if (!stopTime.isInfinite() && stopTime.compareTo(currentTime) >= 0) {
740            _breakpoints.insert(new SuperdenseTime(stopTime, 0));
741        }
742
743        _commitIsPending = false;
744        _postfireReturns = true;
745        _isInitializing = false;
746        _redoingSolverIteration = false;
747
748        // NOTE: If we are being reinitialized during execution (e.g. because
749        // of a reset transition), then our current local time is set to match
750        // the environment time if startTime is blank (the default), meaning that
751        // start time is inherited from the environment. Otherwise, the accumulated
752        // suspend time should be set to the difference between the current time
753        // of the environment and the start time. In either case, this is the
754        // difference between the current time and the environment time.
755    }
756
757    /** Return true if all step size control actors agree that the current
758     *  step is accurate and if there are no breakpoints in the past.
759     *  @return True if all step size control actors agree with the current
760     *   step size.
761     */
762    @Override
763    public boolean isStepSizeAccurate() {
764        _debug("-- Check accuracy for output step size control actors:");
765
766        // A zero step size is always accurate.
767        if (_currentStepSize == 0) {
768            return true;
769        }
770
771        boolean accurate = true;
772
773        // Ask ALL the actors whether the current step size is accurate.
774        // Note that ALL the step size controllers need to be queried.
775        Iterator stepSizeControlActors = _stepSizeControllers().iterator();
776        while (stepSizeControlActors.hasNext() && !_stopRequested) {
777            ContinuousStepSizeController actor = (ContinuousStepSizeController) stepSizeControlActors
778                    .next();
779            boolean thisAccurate = actor.isStepSizeAccurate();
780            if (_debugging) {
781                _debug("---- Checking output step size control actor: "
782                        + ((NamedObj) actor).getFullName() + ", which returns "
783                        + thisAccurate);
784            }
785            accurate = accurate && thisAccurate;
786        }
787
788        if (!_breakpoints.isEmpty()) {
789            SuperdenseTime nextBreakpoint = (SuperdenseTime) _breakpoints
790                    .first();
791            Time breakpointTime = nextBreakpoint.timestamp();
792            int comparison = breakpointTime.compareTo(getModelTime());
793            if (comparison < 0) {
794                accurate = false;
795            }
796        }
797
798        if (_debugging) {
799            _debug("-- Result of accuracy check: " + accurate);
800        }
801        return accurate;
802    }
803
804    /** If this director is not at the top level and the breakpoint table
805     *  is not empty, request a refiring at the first breakpoint or at
806     *  the local current time (iteration start time plus the step size),
807     *  whichever is less. Postfire all controlled actors.
808     *  <p>
809     *  If the <i>synchronizeToRealTime</i> parameter is <i>true</i>,
810     *  then this method will block execution until the real time catches
811     *  up with current model time. The units for time are seconds.
812     *  @return True if the Director wants to be fired again in the future.
813     *  @exception IllegalActionException If the current model time exceeds
814     *   the stop time, or refiring can not be granted, or the super class throws it.
815     */
816    @Override
817    public boolean postfire() throws IllegalActionException {
818        if (_debugging) {
819            _debug("Calling postfire().");
820        }
821        // If time exceeds the stop time, then either we failed
822        // to execute at the stop time, or the return value of
823        // false was ignored, or the return value of false in
824        // prefire() was ignored. All of these conditions are bugs.
825        if (getModelTime().compareTo(getModelStopTime()) > 0) {
826            throw new IllegalActionException(this,
827                    "Current time exceeds the specified stopTime.");
828        }
829        boolean result = _postfireReturns;
830        // This code is sufficiently confusing that, at the expense
831        // of code duplication, we completely separate three cases.
832        if (_enclosingContinuousDirector() != null) {
833            // Need to closely coordinate with the enclosing director
834            result = result && _postfireWithEnclosingContinuousDirector();
835        } else if (isEmbedded()) {
836            result = result && _postfireWithEnclosingNonContinuousDirector();
837        } else {
838            // This director is at the top level.
839            result = result && _postfireAtTopLevel();
840        }
841        return result;
842    }
843
844    /** Initialize the fixed-point iteration by setting all receivers to
845     *  unknown, and return true if we have not passed the stop time.
846     *
847     *  Record the current model time as the beginning time of the current
848     *  iteration, and if there is a pending invocation of postfire()
849     *  from a previous integration step, invoke that now.
850     *  @return True if this director is ready to fire.
851     *  @exception IllegalActionException If thrown by the super class,
852     *   or if the model time of the environment is less than our current
853     *   model time.
854     */
855    @Override
856    public boolean prefire() throws IllegalActionException {
857        if (_debugging) {
858            _debug("\nCalling prefire() at time " + getModelTime()
859                    + " and index " + _index);
860        }
861        // This code is sufficiently confusing that, at the expense
862        // of code duplication, we completely separate three cases.
863        if (_enclosingContinuousDirector() != null) {
864            // Need to closely coordinate with the enclosing director
865            return _prefireWithEnclosingContinuousDirector();
866        } else if (isEmbedded()) {
867            return _prefireWithEnclosingNonContinuousDirector();
868        } else {
869            // This director is at the top level.
870            return _prefireAtTopLevel();
871        }
872    }
873
874    /** Preinitialize the model for an execution. This method is
875     *  called only once for each simulation.
876     *
877     *  @exception IllegalActionException If the super class throws it, or
878     *  local variables cannot be initialized.
879     */
880    @Override
881    public void preinitialize() throws IllegalActionException {
882        super.preinitialize();
883        // Time objects can only be instantiated after super.preinitialize()
884        // is called, where the time resolution is resolved.
885        _initializeLocalVariables();
886    }
887
888    /** Return the refined step size, which is the minimum of the
889     *  current step size and the suggested step size of all actors that
890     *  implement ContinuousStepSizeController and that also ensures
891     *  that we do not pass a breakpoint. If these actors
892     *  request a step size smaller than the time resolution, then
893     *  the first time this happens this method returns the time resolution.
894     *  If it happens again on the next call to this method, then this
895     *  method throws an exception.
896     *  @return The refined step size.
897     *  @exception IllegalActionException If the scheduler throws it or the
898     *  refined step size is less than the time resolution.
899     */
900    @Override
901    public double refinedStepSize() throws IllegalActionException {
902        if (_debugging) {
903            _debug("-- Refining the current step size from "
904                    + _currentStepSize);
905        }
906
907        double timeResolution = getTimeResolution();
908        double refinedStep = _currentStepSize;
909
910        Iterator stepSizeControlActors = _stepSizeControllers().iterator();
911        while (stepSizeControlActors.hasNext() && !_stopRequested) {
912            ContinuousStepSizeController actor = (ContinuousStepSizeController) stepSizeControlActors
913                    .next();
914            refinedStep = Math.min(refinedStep, actor.refinedStepSize());
915        }
916
917        // If the requested step size is smaller than the time
918        // resolution, then set the step size to the time resolution.
919        // Set a flag indicating that we have done that so that if
920        // the step size as time resolution is still too large,
921        // throw an exception.
922        if (refinedStep < timeResolution) {
923            if (!_triedTheMinimumStepSize) {
924                // First time requested step size is less than time resolution
925                refinedStep = timeResolution;
926                _triedTheMinimumStepSize = true;
927            } else {
928                throw new IllegalActionException(this,
929                        "The refined step size is less than the time "
930                                + "resolution, at time " + getModelTime());
931            }
932        } else {
933            _triedTheMinimumStepSize = false;
934        }
935
936        if (_debugging) {
937            _debug("-- Refined step size suggested by the actors: "
938                    + refinedStep);
939        }
940
941        if (!_breakpoints.isEmpty()) {
942            SuperdenseTime nextBreakpoint = (SuperdenseTime) _breakpoints
943                    .first();
944            Time nextBreakpointTime = nextBreakpoint.timestamp();
945            int comparison = nextBreakpointTime
946                    .compareTo(_iterationBeginTime.add(refinedStep));
947            if (comparison < 0) {
948                refinedStep = nextBreakpointTime.subtract(_iterationBeginTime)
949                        .getDoubleValue();
950                if (refinedStep < 0.0) {
951                    throw new IllegalActionException(this,
952                            "Cannot set a step size to respect the breakpoint at "
953                                    + nextBreakpoint);
954                }
955                if (_debugging) {
956                    _debug("-- Refined step size determined by the breakpoint table: "
957                            + refinedStep);
958                }
959            }
960        }
961
962        return refinedStep;
963    }
964
965    /** Resume the actor at the specified time. If the actor has not
966     *  been suspended since the last call to initialize(), then this
967     *  has no effect.
968     *  @exception IllegalActionException If the fireAt() request throws it.
969     */
970    @Override
971    public void resume() throws IllegalActionException {
972        super.resume();
973        // Request a firing at the current time to ensure that
974        // we restart here.
975        fireAt(null, getModelTime());
976    }
977
978    /** Roll back all actors that implement ContinuousStatefulComponent
979     *  to committed state, and set local model time to the start
980     *  of the integration period.
981     *  @exception IllegalActionException If the rollback attempts to go
982     *   back further than the last committed time.
983     */
984    @Override
985    public void rollBackToCommittedState() throws IllegalActionException {
986        // Restore the local view of model time to
987        // the start of the integration step.
988        localClock.setLocalTime(_iterationBeginTime);
989        _index = _iterationBeginIndex;
990
991        if (_debugging) {
992            _debug("-- Roll back time to: " + _iterationBeginTime
993                    + " and index " + _index);
994        }
995
996        Iterator rollbacks = _statefulComponents().iterator();
997        while (rollbacks.hasNext()) {
998            ContinuousStatefulComponent actor = (ContinuousStatefulComponent) rollbacks
999                    .next();
1000            actor.rollBackToCommittedState();
1001        }
1002    }
1003
1004    /** Set a new value to the current time of the model. This overrides
1005     *  the base class to allow time to move backwards (to support rollback)
1006     *  and to discard any breakpoints in the breakpoint table that are
1007     *  in the past relative to the specified time.
1008     *  This overrides the setCurrentTime() in the Director base class.
1009     *  Although this method is public, actors should never call it.
1010     *  @param newTime The new current simulation time.
1011     *  @exception IllegalActionException If the time is in the past
1012     *   relative to the time of local committed state.
1013     */
1014    @Override
1015    public final void setModelTime(Time newTime) throws IllegalActionException {
1016        // We don't call super.getModelTime() because Director.setModelTime()
1017        // merely sets the local time of the localClock.  We want to do more here.
1018
1019        if (_ignoreSetTime) {
1020            return;
1021        }
1022        // This method is final for performance reason.
1023        if (_debugging) {
1024            _debug("** Environment is setting current time to " + newTime);
1025        }
1026        Time currentTime = getModelTime();
1027        int comparison = newTime.compareTo(currentTime);
1028        if (comparison > 0) {
1029            // New time is ahead of the current local time.
1030            // This should not happen.
1031            throw new IllegalActionException(this,
1032                    "ContinuousDirector expected to be invoked at time "
1033                            + currentTime
1034                            + ", but instead its time is being set to "
1035                            + newTime);
1036            // NOTE: An alternative would be invalidate a pending commit
1037            // and discard intermediate breakpoints.
1038            // Code is below.
1039            /*
1040            if (_commitIsPending) {
1041                _commitIsPending = false;
1042                rollBackToCommittedState();
1043            }
1044            _currentTime = newTime;
1045            _iterationBeginTime = _currentTime;
1046            _handleBreakpointsBefore(_currentTime, 0);
1047            // Set the step size to 0.0, which will ensure that any
1048            // actors (like plotters) are postfired at the new model time.
1049            // This also reinitializes the adaptive step size calculation,
1050            // which is probably reasonable since things may have
1051            // changed significantly.
1052            _currentStepSize = 0.0;
1053             */
1054        } else if (comparison < 0) {
1055            // The new time is behind the current time.
1056            // This is legal only if we have a commit pending.
1057            if (!_commitIsPending) {
1058                throw new IllegalActionException(this,
1059                        "Attempting to roll back time from " + currentTime
1060                                + " to " + newTime
1061                                + ", but state has been committed.");
1062            }
1063            // We have to re-do the integration
1064            // with a smaller step size that brings us up to the current
1065            // environment time.
1066            // NOTE: This depends on the property that if an integration
1067            // step with a larger step size was successful and produced
1068            // no events, then an integration step with this now smaller
1069            // step size will also be successful and produce no events.
1070            _currentStepSize = newTime.subtract(_iterationBeginTime)
1071                    .getDoubleValue();
1072            if (_debugging) {
1073                _debug("**** Setting step size to: " + _currentStepSize);
1074            }
1075            // If the step size is now negative, then we are trying
1076            // to roll back too far.
1077            if (_currentStepSize < 0.0) {
1078                throw new IllegalActionException(this,
1079                        "Attempting to roll back time from "
1080                                + _iterationBeginTime + " to " + newTime
1081                                + ", but state has been committed.");
1082            }
1083            rollBackToCommittedState();
1084        }
1085    }
1086
1087    /** Return an array of suggested ModalModel directors to use
1088     *  with ContinuousDirector. The only available director is
1089     *  ModalDirector because we need a director that implements
1090     *  the strict actor semantics.
1091     *  @return An array of suggested directors to be used with ModalModel.
1092     */
1093    @Override
1094    public String[] suggestedModalModelDirectors() {
1095        // This method does not call the method defined in the super class,
1096        // because this method provides complete new information.
1097        String[] defaultSuggestions = new String[1];
1098        defaultSuggestions[0] = "ptolemy.domains.continuous.kernel.HybridModalDirector";
1099        return defaultSuggestions;
1100    }
1101
1102    /** Return the suggested step size for next integration. The suggested step
1103     *  size is the minimum of suggestions from all step size control actors
1104     *  and the time until the next breakpoint,
1105     *  and it never exceeds 10 times of the current step size.
1106     *  If there are no step size control actors at all, then return
1107     *  5 times of the current step size. However, the suggested step size
1108     *  never exceeds the maximum step size.  If this director has not been
1109     *  fired since initialize() or the previous call to suggestedStepSize(),
1110     *  then return the value of <i>maxStepSize</i>.
1111     *  @return The suggested step size for next integration.
1112     *  @exception IllegalActionException If an actor suggests an illegal step size.
1113     */
1114    @Override
1115    public double suggestedStepSize() throws IllegalActionException {
1116        double suggestedStep = _initStepSize;
1117
1118        if (_currentStepSize != 0.0) {
1119            // Increase the current step size, then ask the step-size control
1120            // actors for their suggestions and choose the minimum.
1121            // We could use _maxStepSize here, but if the current step
1122            // size is very small w.r.t. the maximum, then this will almost
1123            // certainly be too much of a change in step size. Hence, we
1124            // increase the step size more slowly.
1125            suggestedStep = 10.0 * _currentStepSize;
1126            if (_debugging) {
1127                _debug("---- Speculatively set step size to " + suggestedStep);
1128            }
1129
1130            Iterator stepSizeControlActors = _stepSizeControllers().iterator();
1131            while (stepSizeControlActors.hasNext() && !_stopRequested) {
1132                ContinuousStepSizeController actor = (ContinuousStepSizeController) stepSizeControlActors
1133                        .next();
1134                double suggestedStepSize = actor.suggestedStepSize();
1135                if (suggestedStepSize < 0.0) {
1136                    throw new IllegalActionException((Actor) actor,
1137                            "Actor requests invalid step size: "
1138                                    + suggestedStepSize);
1139                }
1140                if (_debugging) {
1141                    _debug("---- Step size control actor "
1142                            + ((NamedObj) actor).getName()
1143                            + " suggests next step size = "
1144                            + suggestedStepSize);
1145                }
1146                if (suggestedStep > suggestedStepSize) {
1147                    if (_debugging) {
1148                        _debug("----- Revising step size to "
1149                                + suggestedStepSize);
1150                    }
1151                    suggestedStep = suggestedStepSize;
1152                }
1153            }
1154        }
1155        // The suggested step size should not exceed the maximum step size.
1156        if (suggestedStep > _maxStepSize) {
1157            suggestedStep = _maxStepSize;
1158        }
1159
1160        // If there are breakpoints, set the suggested step size as the
1161        // time to the next breakpoint, if it is less than the value
1162        // so far.
1163        if (!_breakpoints.isEmpty()) {
1164            SuperdenseTime nextBreakpoint = (SuperdenseTime) _breakpoints
1165                    .first();
1166            Time breakpointTime = nextBreakpoint.timestamp();
1167            double result = breakpointTime.subtract(getModelTime())
1168                    .getDoubleValue();
1169            if (result < 0.0) {
1170                throw new InternalErrorException(
1171                        "Missed a breakpoint at time " + breakpointTime
1172                                + ". Current time is " + getModelTime());
1173            }
1174            if (result < suggestedStep) {
1175                suggestedStep = result;
1176                if (_debugging) {
1177                    _debug("----- The first breakpoint is at "
1178                            + nextBreakpoint);
1179                    _debug("----- Revising suggested step size due to breakpoint to "
1180                            + suggestedStep);
1181                }
1182            }
1183        }
1184
1185        // Next ensure the selected step size does not take us
1186        // past the stop time.
1187        // NOTE: This test could possibly be eliminated by
1188        // putting the stop time on the breakpoint table. Be sure,
1189        // however, that this results in the right number of
1190        // events generated at the stop time. This is very tricky,
1191        // and probably not worth the effort.
1192        Time targetTime = getModelTime().add(suggestedStep);
1193        Time stopTime = getModelStopTime();
1194        if (targetTime.compareTo(stopTime) > 0) {
1195            suggestedStep = stopTime.subtract(getModelTime()).getDoubleValue();
1196            if (_debugging) {
1197                _debug("----- Revising step size due to stop time to "
1198                        + suggestedStep);
1199            }
1200        }
1201        return suggestedStep;
1202    }
1203
1204    /** Override the base class to do nothing. The fire() method of
1205     *  this director handles transferring inputs.
1206     *  @param port The port to transfer tokens from.
1207     *  @return False.
1208     *  @exception IllegalActionException Not thrown in this base class.
1209     */
1210    @Override
1211    public boolean transferInputs(IOPort port) throws IllegalActionException {
1212        return false;
1213    }
1214
1215    /** Override the base class to do nothing. The fire() method of
1216     *  this director handles transferring outputs.
1217     *  @param port The port to transfer tokens from.
1218     *  @return False.
1219     *  @exception IllegalActionException Not thrown in this base class.
1220     */
1221    @Override
1222    public boolean transferOutputs(IOPort port) throws IllegalActionException {
1223        return false;
1224    }
1225
1226    ///////////////////////////////////////////////////////////////////
1227    ////                         protected methods                 ////
1228
1229    /** Return the current step size.
1230     *  @return The current step size.
1231     */
1232    protected double _getCurrentStepSize() {
1233        return _currentStepSize;
1234    }
1235
1236    /** Return the ODE solver used to resolve states by the director.
1237     *  @return The ODE solver used to resolve states by the director.
1238     */
1239    protected final ContinuousODESolver _getODESolver() {
1240        // This method is final for performance reason.
1241        return _ODESolver;
1242    }
1243
1244    /** Create and initialize all parameters to their default values.
1245     *  This is called by the constructor.
1246     */
1247    protected void _initParameters() {
1248        try {
1249            initStepSize = new Parameter(this, "initStepSize");
1250            initStepSize.setExpression("0.1");
1251            initStepSize.setTypeEquals(BaseType.DOUBLE);
1252
1253            maxStepSize = new Parameter(this, "maxStepSize");
1254            maxStepSize.setExpression("1.0");
1255            maxStepSize.setTypeEquals(BaseType.DOUBLE);
1256
1257            maxIterations = new Parameter(this, "maxIterations");
1258            maxIterations.setExpression("20");
1259            maxIterations.setTypeEquals(BaseType.INT);
1260
1261            errorTolerance = new Parameter(this, "errorTolerance");
1262            errorTolerance.setExpression("1e-4");
1263            errorTolerance.setTypeEquals(BaseType.DOUBLE);
1264
1265            iterations.setVisibility(Settable.NONE);
1266
1267            ODESolver = new StringParameter(this, "ODESolver");
1268            ODESolver.setExpression("ExplicitRK23Solver");
1269            ODESolver.addChoice("ExplicitRK23Solver");
1270            ODESolver.addChoice("ExplicitRK45Solver");
1271            /* FIXME: These solvers are currently not implemented in this package.
1272             ODESolver.addChoice(new StringToken("BackwardEulerSolver")
1273             .toString());
1274             ODESolver.addChoice(new StringToken("ForwardEulerSolver")
1275             .toString());
1276             */
1277        } catch (IllegalActionException e) {
1278            //Should never happens. The parameters are always compatible.
1279            throw new InternalErrorException("Parameter creation error: " + e);
1280        } catch (NameDuplicationException ex) {
1281            throw new InvalidStateException(this,
1282                    "Parameter name duplication: " + ex);
1283        }
1284    }
1285
1286    /** Instantiate an ODESolver from its classname. Given the solver's full
1287     *  class name, this method will try to instantiate it by looking
1288     *  for the corresponding java class.
1289     *  @param className The solver's full class name.
1290     *  @return a new ODE solver.
1291     *  @exception IllegalActionException If the solver can not be created.
1292     */
1293    protected final ContinuousODESolver _instantiateODESolver(String className)
1294            throws IllegalActionException {
1295
1296        // All solvers must be in the package given by _solverClasspath.
1297        if (!className.trim().startsWith(_solverClasspath)) {
1298            className = _solverClasspath + className;
1299        }
1300
1301        if (_debugging) {
1302            _debug("instantiating solver..." + className);
1303        }
1304
1305        ContinuousODESolver newSolver;
1306
1307        try {
1308            Class solver = Class.forName(className);
1309            newSolver = (ContinuousODESolver) solver.newInstance();
1310        } catch (ClassNotFoundException e) {
1311            throw new IllegalActionException(this,
1312                    "ODESolver: " + className + " is not found.");
1313        } catch (InstantiationException e) {
1314            throw new IllegalActionException(this,
1315                    "ODESolver: " + className + " instantiation failed." + e);
1316        } catch (IllegalAccessException e) {
1317            throw new IllegalActionException(this,
1318                    "ODESolver: " + className + " is not accessible.");
1319        }
1320
1321        newSolver._makeSolverOf(this);
1322        return newSolver;
1323    }
1324
1325    /** Return true if debugging is turned on.
1326     *  This exposes whether debugging is happening to the package.
1327     *  @return True if debugging is turned on.
1328     */
1329    protected final boolean _isDebugging() {
1330        return _debugging;
1331    }
1332
1333    /** Return true if the solver is at the first or intermediate steps
1334     *  of a multi-step solver. If there is an enclosing continuous
1335     *  director, this method delegates to that director. Otherwise,
1336     *  it checks the current step of the solver.
1337     *  @return True if either the solver is not doing a multi-step
1338     *   solution or it is at the last step of the multi-step solution.
1339     *  @exception IllegalActionException If the Time class throws it.
1340     */
1341    protected boolean _isIntermediateStep() throws IllegalActionException {
1342        ContinuousDirector enclosingDirector = _enclosingContinuousDirector();
1343        if (enclosingDirector != null) {
1344            return enclosingDirector._isIntermediateStep();
1345        }
1346        return _isIntermediateStep;
1347    }
1348
1349    /** Expose the debug method to the package.
1350     *  @param message The message that is to be reported.
1351     */
1352    protected void _reportDebugMessage(String message) {
1353        _debug(message);
1354    }
1355
1356    ///////////////////////////////////////////////////////////////////
1357    ////                         protected variables               ////
1358
1359    /** A local boolean variable indicating whether this director is in
1360     *  initialization phase execution.
1361     */
1362    protected boolean _isInitializing = false;
1363
1364    /** The current time at the start of the current integration step.
1365     */
1366    protected Time _iterationBeginTime;
1367
1368    ///////////////////////////////////////////////////////////////////
1369    ////                         private methods                   ////
1370
1371    /** Set all receivers on the inside of input ports to
1372     *  absent.
1373     *  @exception IllegalActionException If the send fails.
1374     */
1375    private void _assertAbsentInside() throws IllegalActionException {
1376        CompositeActor container = (CompositeActor) getContainer();
1377        Iterator inports = container.inputPortList().iterator();
1378        while (inports.hasNext()) {
1379            IOPort port = (IOPort) inports.next();
1380            int insideWidth = port.getWidthInside();
1381            for (int i = 0; i < insideWidth; i++) {
1382                port.sendInside(i, null);
1383            }
1384        }
1385    }
1386
1387    /** Commit the current state by postfiring the actors under the
1388     *  control of this director. Also, set the current time, index,
1389     *  and step size for the next iteration. If the current step size
1390     *  is 0.0, then this just increments the index. Otherwise, it sets
1391     *  the index to 0.
1392     *  @return True if it is OK to fire again.
1393     */
1394    private boolean _commit() throws IllegalActionException {
1395        Time currentTime = getModelTime();
1396        if (_debugging) {
1397            _debug("Committing the current states at " + currentTime);
1398        }
1399
1400        // If current time matches a time on the breakpoint table
1401        // with the current index, then remove that breakpoint because we have
1402        // just completed execution of that iteration. Only do this, however,
1403        // if the current step size is 0.0, since breakpoints should be dealt
1404        // with always with step size 0.0
1405        if (_currentStepSize == 0.0 && !_breakpoints.isEmpty()) {
1406            SuperdenseTime nextBreakpoint = (SuperdenseTime) _breakpoints
1407                    .first();
1408            Time breakpointTime = nextBreakpoint.timestamp();
1409            int comparison = breakpointTime.compareTo(currentTime);
1410            if (comparison == 0 && nextBreakpoint.index() <= _index) {
1411                if (_debugging) {
1412                    _debug("Removing breakpoint at " + nextBreakpoint);
1413                }
1414                _breakpoints.removeFirst();
1415            }
1416        }
1417
1418        // Postfire the contained actors.
1419        // This must be done before refining the step size and
1420        // before updating _index because the actors may call fireAt()
1421        // in their postfire() method, which will insert breakpoints,
1422        // which will affect the next step size.
1423        // NOTE: This increments _index.
1424        // FIXME: This also resets all receivers, which is redundant since in this
1425        // director, resetting receivers is handled by fire(). Efficiency concern?
1426        _postfireReturns = super.postfire();
1427
1428        // If the current time is equal to the stop time, return false.
1429        // Check, however, to make sure that the breakpoints table
1430        // does not contain the current model time, which would mean
1431        // that more events may be generated at this time.
1432        // If the index of the breakpoint is the same as the current
1433        // index, then we have executed it.  This must be called
1434        // after postfire() of the controlled actors is called, because
1435        // they may call fireAt(), which inserts events in the breakpoint
1436        // table.
1437        if (currentTime.equals(getModelStopTime())) {
1438            SuperdenseTime nextBreakpoint = (SuperdenseTime) _breakpoints
1439                    .first();
1440            if (nextBreakpoint == null
1441                    || nextBreakpoint.timestamp().compareTo(currentTime) > 0) {
1442                return false;
1443            }
1444        }
1445
1446        // Update the index. Note that this must happen before
1447        // we refine the step size because the updated value gives
1448        // the step size for the _next_ iteration.
1449        if (_currentStepSize != 0.0) {
1450            _index = 0;
1451        }
1452
1453        // Set the suggested step size for next integration step by polling
1454        // the contained actors and examining the breakpoint table.
1455        _setCurrentStepSize(suggestedStepSize());
1456
1457        // Set the start time of the current iteration.
1458        // The iterationBegintime will be used for roll back when the current
1459        // step size is incorrect.
1460        _iterationBeginTime = currentTime;
1461        _iterationBeginIndex = _index;
1462
1463        return _postfireReturns;
1464    }
1465
1466    /** Return the enclosing continuous director, or null if there
1467     *  is none.  The enclosing continuous director is a director
1468     *  above this in the hierarchy, possibly separated by composite
1469     *  actors with actors that implement the QuasiTransparentDirector
1470     *  interface, such as FSMDirector or CaseDirector.
1471     *  @return The enclosing ContinuousDirector, or null if there is none.
1472     */
1473    private ContinuousDirector _enclosingContinuousDirector() {
1474        if (_enclosingContinuousDirectorVersion != _workspace.getVersion()) {
1475            // Update the cache.
1476            _enclosingContinuousDirector = null;
1477            NamedObj container = getContainer().getContainer();
1478            while (container != null) {
1479                if (container instanceof Actor) {
1480                    Director director = ((Actor) container).getDirector();
1481                    if (director instanceof ContinuousDirector) {
1482                        _enclosingContinuousDirector = (ContinuousDirector) director;
1483                        break;
1484                    }
1485                    if (!(director instanceof QuasiTransparentDirector)) {
1486                        break;
1487                    }
1488                }
1489                container = container.getContainer();
1490            }
1491            _enclosingContinuousDirectorVersion = _workspace.getVersion();
1492        }
1493        return _enclosingContinuousDirector;
1494    }
1495
1496    /** Throw an exception if there are any breakpoints in the breakpoint
1497     *  table before the specified time.
1498     *  @param time The time.
1499     *  @param index The superdense time index.
1500     *  @exception IllegalActionException If there are any breakpoints in the
1501     *   breakpoint table earlier than the specified time.
1502     */
1503    private void _handleBreakpointsBefore(Time time, int index)
1504            throws IllegalActionException {
1505        if (!_breakpoints.isEmpty()) {
1506            SuperdenseTime nextBreakpoint = (SuperdenseTime) _breakpoints
1507                    .first();
1508            Time breakpointTime = nextBreakpoint.timestamp();
1509            if (breakpointTime.compareTo(time) < 0) {
1510                throw new IllegalActionException(this,
1511                        "ContinuousDirector expected to be fired at time "
1512                                + breakpointTime
1513                                + " but instead is being fired at time "
1514                                + time);
1515            }
1516        }
1517        // NOTE: An alternative would be to discard breakpoints earlier
1518        // than the specified time. The code for doing that is below.
1519        /*
1520        while (!_breakpoints.isEmpty()) {
1521            SuperdenseTime nextBreakpoint = (SuperdenseTime) _breakpoints
1522                    .first();
1523            Time breakpointTime = nextBreakpoint.timestamp();
1524            int comparison = breakpointTime.compareTo(time);
1525            if (comparison > 0
1526                    || (comparison == 0 && nextBreakpoint.index() > index)) {
1527                // Next breakpoint is in the future.
1528                break;
1529            } else {
1530                if (_debugging) {
1531                    _debug(">>>> Discarding a breakpoint from the breakpoint table: "
1532                            + nextBreakpoint);
1533                }
1534                _breakpoints.removeFirst();
1535            }
1536        }
1537         */
1538    }
1539
1540    /** Initialize the local variables of this ContinuousDirector. Create or
1541     *  clear the breakpoints table. Instantiate an ODE solver.
1542     *  This method is called in the preinitialize method.
1543     */
1544    private void _initializeLocalVariables() throws IllegalActionException {
1545        _maxIterations = ((IntToken) maxIterations.getToken()).intValue();
1546        _maxStepSize = ((DoubleToken) maxStepSize.getToken()).doubleValue();
1547        _currentStepSize = _initStepSize;
1548
1549        _iterationBeginTime = getModelStartTime();
1550        _iterationBeginIndex = 0;
1551
1552        // clear the existing breakpoint table or
1553        // create a breakpoint table if necessary
1554        if (_breakpoints != null) {
1555            if (_debugging) {
1556                _debug(getFullName(), "clears the breakpoint table.");
1557            }
1558            _breakpoints.clear();
1559        } else {
1560            if (_debugging) {
1561                _debug(getFullName(), "creates a breakpoint table.");
1562            }
1563            _breakpoints = new TotallyOrderedSet(new GeneralComparator());
1564        }
1565
1566        // Instantiate an ODE solver, using the class name given
1567        // by ODESolver parameter, which is a string parameter.
1568        String solverClassName;
1569        // If there is an enclosing ContinuousDirector, then use its solver
1570        // specification instead of the local one.
1571        ContinuousDirector enclosingDirector = _enclosingContinuousDirector();
1572        if (enclosingDirector != null) {
1573            solverClassName = enclosingDirector.ODESolver.stringValue().trim();
1574        } else {
1575            solverClassName = ODESolver.stringValue().trim();
1576        }
1577        _ODESolver = _instantiateODESolver(_solverClasspath + solverClassName);
1578    }
1579
1580    /** Postfire method when this director is at the top level.
1581     *  @return True if it is OK to fire again.
1582     */
1583    private boolean _postfireAtTopLevel() throws IllegalActionException {
1584        // Commit the current state and postfire all actors.
1585        boolean result = _commit();
1586        // The above call will increment the index if the current step
1587        // size is zero, and set it to zero otherwise. At the top level,
1588        // we want to set it to 1, not zero because we just committed
1589        // the index 0 iteration for the current time. The next iteration
1590        // should run with index 1.
1591        if (_index == 0) {
1592            _index++;
1593        }
1594        return result;
1595    }
1596
1597    /** Postfire method when the enclosing director
1598     *  is an instance of this same class.
1599     *  @return True if it is OK to fire again.
1600     */
1601    private boolean _postfireWithEnclosingContinuousDirector()
1602            throws IllegalActionException {
1603        boolean postfireResult = _commit();
1604        // The above call will increment the index if the current step
1605        // size is zero, and set it to zero otherwise. At the top level,
1606        // we want to set it to 1, not zero because we just committed
1607        // the index 0 iteration for the current time. The next iteration
1608        // should run with index 1.
1609        if (_index == 0) {
1610            _index++;
1611        }
1612
1613        // Request a refiring at the current time if the
1614        // next step size has been set to 0.0, and at the
1615        // next breakpoint time otherwise.
1616        if (_currentStepSize == 0.0) {
1617            // We assume the enclosing director will
1618            // post this firing request at the next microstep.
1619            fireContainerAt(getModelTime());
1620        } else if (_breakpoints.size() > 0) {
1621            // Request a firing at the time of the first breakpoint.
1622            SuperdenseTime nextBreakpoint = (SuperdenseTime) _breakpoints
1623                    .first();
1624            fireContainerAt(nextBreakpoint.timestamp(), nextBreakpoint.index());
1625        }
1626
1627        return postfireResult;
1628    }
1629
1630    /** Postfire method when the enclosing director
1631     *  is not an instance of this same class.
1632     *  @return True if it is OK to fire again.
1633     */
1634    private boolean _postfireWithEnclosingNonContinuousDirector()
1635            throws IllegalActionException {
1636        Time currentTime = getModelTime();
1637        // If a commit is pending, just do the commit and request a refiring
1638        // at the current time.
1639        if (_commitIsPending) {
1640            _commitIsPending = false;
1641            fireContainerAt(currentTime, 0);
1642
1643            // Commit the current state and postfire all actors.
1644            boolean result = _commit();
1645            // The above call will increment the index if the current step
1646            // size is zero, and set it to zero otherwise. At the top level,
1647            // we want to set it to 1, not zero because we just committed
1648            // the index 0 iteration for the current time. The next iteration
1649            // should run with index 1.
1650            if (_index == 0) {
1651                _index++;
1652            }
1653            return result;
1654        }
1655        Director enclosingDirector = ((Actor) getContainer())
1656                .getExecutiveDirector();
1657        int currentTimeAheadOfOutsideTime = currentTime
1658                .compareTo(enclosingDirector.getModelTime());
1659        if (currentTimeAheadOfOutsideTime > 0) {
1660            // We have to defer the commit until current time of the environment
1661            // matches our local current time. Call fireAt() to ensure that the
1662            // enclosing director invokes prefire at the local current time.
1663            // This local current time should not exceed the least time on
1664            // the breakpoint table.
1665            // The following will throw an exception if the enclosing director
1666            // does not respect the fireAt() request exactly.
1667            fireContainerAt(currentTime, 0);
1668            // When that firing occurs, we want the index to be 0.
1669            _index = 0;
1670            _commitIsPending = true;
1671            if (_debugging) {
1672                _debug("postfire() requests refiring at time " + currentTime
1673                        + " and defers the commit.");
1674            }
1675            return true;
1676        } else {
1677            // Current time is less than or equal to the environment time.
1678            // NOTE: It is, in theory, impossible for local current time to
1679            // be less than the environment time because the prefire() method
1680            // would have thrown an exception. Hence, current time must match
1681            // the environment time.
1682
1683            // Request a refiring at the current time.
1684            // The reason for this is that local time has not advanced,
1685            // so we can't be sure of any interval of future time over which
1686            // we will not produce an event. Only when the step size is
1687            // greater than zero, as we have speculatively executed into
1688            // the future, can we allow the enclosing director to advance time.
1689            // The following will throw an exception if the enclosing director
1690            // does not respect the fireAt() request exactly.
1691            // However, it could be that the current iteration is actually
1692            // a deferred commit, in which case local time has advanced
1693            // and we don't need to request a refiring at the current time.
1694            fireContainerAt(currentTime, 0);
1695
1696            // The following call will increment the index if the current step
1697            // size is zero, and set it to zero otherwise. At the top level,
1698            return _commit();
1699        }
1700    }
1701
1702    /** Prefire method when this director is at the top level.
1703     *  @return True if it is OK to fire.
1704     */
1705    private boolean _prefireAtTopLevel() throws IllegalActionException {
1706        Time currentTime = getModelTime();
1707        // If the current time and index matches the first entry in the breakpoint
1708        // table, then remove that entry.
1709        if (!_breakpoints.isEmpty()) {
1710            SuperdenseTime nextBreakpoint = (SuperdenseTime) _breakpoints
1711                    .first();
1712            Time breakpointTime = nextBreakpoint.timestamp();
1713            int comparison = breakpointTime.compareTo(currentTime);
1714            // Note that we don't compare the superdense time of the breakpoint
1715            // because it is not important. It was created, probably, with
1716            // fireAt(), which does not take a superdense time index.
1717            if (comparison < 0) {
1718                // At the top level, we should not have missed a breakpoint.
1719                throw new IllegalActionException(this,
1720                        "Missed a breakpoint time at " + breakpointTime
1721                                + ", with index " + nextBreakpoint.index());
1722            } else if (comparison == 0 && nextBreakpoint.index() <= _index) {
1723                if (_debugging) {
1724                    _debug("-- The current superdense time is a breakpoint, "
1725                            + nextBreakpoint + ", which is removed.");
1726                }
1727                _breakpoints.removeFirst();
1728            }
1729        }
1730        boolean result = super.prefire();
1731        // Initialize everything for the fixedpoint iteration.
1732        // NOTE: This is done in fire. Not necessary here.
1733        // _resetAllReceivers();
1734
1735        if (_debugging) {
1736            _debug("ContinuousDirector: prefire() returns " + result);
1737        }
1738        return result;
1739    }
1740
1741    /** Prefire method when the enclosing director
1742     *  is an instance of this same class.
1743     *  @return True if it is OK to fire.
1744     */
1745    private boolean _prefireWithEnclosingContinuousDirector()
1746            throws IllegalActionException {
1747        // Call the super.prefire() method, which will synchronize time to the outside time.
1748        // That time may get modified below to align not with the immediate outside time,
1749        // but rather with the time of the enclosing continuous director, modified as
1750        // needed by accumulated suspend time. As a consequence, we set a flag to
1751        // ignore the time that is set.
1752        boolean result = true;
1753        Time currentTime = getModelTime();
1754        try {
1755            _ignoreSetTime = true;
1756            result = super.prefire();
1757        } finally {
1758            _ignoreSetTime = false;
1759        }
1760
1761        // Set the time and step size to match that of the enclosing director.
1762        ContinuousDirector enclosingDirector = _enclosingContinuousDirector();
1763        _currentStepSize = enclosingDirector._currentStepSize;
1764        // Do not use setCommittedTime on the following line because we
1765        // are probably speculatively executing into the future.
1766        localClock.setLocalTime(
1767                localClock.getLocalTimeForCurrentEnvironmentTime());
1768
1769        if (_debugging) {
1770            _debug("-- Setting current time to " + currentTime
1771                    + ", which aligns with the enclosing director's time of "
1772                    + enclosingDirector.getModelTime());
1773        }
1774
1775        _iterationBeginTime = localClock.getLocalTimeForEnvironmentTime(
1776                enclosingDirector._iterationBeginTime);
1777
1778        // FIXME: Probably shouldn't make the index match that of the environment!
1779        // There may have been suspensions happening. So what should the index be?
1780        // Here we set it to zero if the round is greater than zero. But what
1781        // about other conditions?
1782        // _index = enclosingDirector._index;
1783        int round = enclosingDirector._ODESolver._getRound();
1784        if (round > 0) {
1785            _index = 0;
1786        } else if (_currentStepSize == 0.0) {
1787            /* FIXME: Bogus. This will force the first execution to be at microstep 1.
1788            _index++;
1789             */
1790        }
1791
1792        _iterationBeginIndex = enclosingDirector._iterationBeginIndex;
1793
1794        // If we have passed the stop time, then return false.
1795        // This can occur if we are inside a modal model and were not
1796        // active when the stop time elapsed.
1797        if (_iterationBeginTime.compareTo(getModelStopTime()) > 0) {
1798            if (_debugging) {
1799                _debug("-- prefire() returns false because stop time is exceeded at "
1800                        + _iterationBeginTime);
1801            }
1802            return false;
1803        }
1804
1805        // Handle breakpoint entries earlier
1806        // than or equal to the iteration begin time.
1807        _handleBreakpointsBefore(_iterationBeginTime, _index);
1808
1809        // Initialize everything for the fixedpoint iteration.
1810        // NOTE: This is done in fire(), and anyway, should not be done
1811        // if there is commit pending.
1812        // _resetAllReceivers();
1813
1814        if (_debugging) {
1815            _debug("-- prefire() returns " + result);
1816        }
1817        return result;
1818    }
1819
1820    /** Prefire method when the enclosing director
1821     *  is not an instance of this same class.
1822     *  @return True if it is OK to fire.
1823     */
1824    private boolean _prefireWithEnclosingNonContinuousDirector()
1825            throws IllegalActionException {
1826        CompositeActor container = (CompositeActor) getContainer();
1827        Director executiveDirector = ((Actor) container).getExecutiveDirector();
1828        Time currentTime = getModelTime();
1829
1830        // Check the enclosing model time against the local model time.
1831        // Note that time has already been automatically adjusted with the
1832        // accumulated suspend time.
1833        Time outTime = localClock.getLocalTimeForCurrentEnvironmentTime();
1834
1835        int localTimeExceedsOutsideTime = currentTime.compareTo(outTime);
1836
1837        Time modifiedTime = _consultTimeRegulators(currentTime);
1838        int modifiedTimeExceedsLocalTime = modifiedTime.compareTo(currentTime);
1839
1840        // Rollback has to occur if either the local time exceeds the modified time
1841        // or a time regulator requires a smaller current time than the current time.
1842        if (localTimeExceedsOutsideTime > 0
1843                || modifiedTimeExceedsLocalTime < 0) {
1844            ///////////////////////////////////////////////////////////////
1845            // First case: Local current time exceeds that of the environment.
1846            if (!_commitIsPending) {
1847                throw new IllegalActionException(this,
1848                        "The model time of " + container.getFullName()
1849                                + " is greater than the environment time. "
1850                                + "Environment: " + outTime
1851                                + ", the model time (iteration begin time): "
1852                                + currentTime);
1853            }
1854            if (modifiedTimeExceedsLocalTime < 0
1855                    && modifiedTime.compareTo(outTime) < 0) {
1856                throw new IllegalActionException(this,
1857                        "A TimeRegulator requires time to be set back to "
1858                                + modifiedTime
1859                                + ", which is less than the last commit time of "
1860                                + outTime);
1861            }
1862            // If we get here, local time exceeds the environment time
1863            // and we have speculatively executed past that local time.
1864            // But now, we cannot commit that execution because an unexpected
1865            // event has occurred.  Instead, we have to re-do the integration
1866            // with a smaller step size that brings us up to the current
1867            // environment time.
1868            // NOTE: This depends on the property that if an integration
1869            // step with a larger step size was successful and produced
1870            // no events, then an integration step with this now smaller
1871            // step size will also be successful and produce no events.
1872            // FIXME: This property is not true in general. E.g., we
1873            // might have missed a level crossing with a larger step
1874            // size that we won't miss with the smaller one! What
1875            // to do about this?
1876            _currentStepSize = outTime.subtract(_iterationBeginTime)
1877                    .getDoubleValue();
1878            // If the step size is now negative, then we are trying
1879            // to roll back too far.
1880            if (_currentStepSize < 0.0) {
1881                throw new IllegalActionException(this,
1882                        "Attempting to roll back time from "
1883                                + _iterationBeginTime + " to " + outTime
1884                                + ", but state has been committed.");
1885            }
1886            rollBackToCommittedState();
1887            _commitIsPending = false;
1888            // Set a flag to prevent the fire() method from reading inputs
1889            // and resetting the step size to 0.0 if there are inputs
1890            // present. Presumably, there are no inputs present at the
1891            // _iterationBeginTime because had there been any, then
1892            // the speculative execution that we are rolling back
1893            // would not have occurred. However, it could be a new input
1894            // has occurred at the _iterationBeginTime, but with a
1895            // larger microstep. In this case, there could be new inputs.
1896            if (_currentStepSize != 0.0) {
1897                _redoingSolverIteration = true;
1898            }
1899        } else if (localTimeExceedsOutsideTime == 0 && _commitIsPending) {
1900            ///////////////////////////////////////////////////////////////
1901            // Second case:
1902            // A commit is pending and the environment time matches
1903            // our local time. This means that no additional events have
1904            // arrived during the interval of the last successful integration
1905            // step. This microstep will simply do the commit that is pending,
1906            // producing any outputs previously computed in the speculative
1907            // execution. It will then request a refiring at the current time.
1908            // FIXME: Why set the current step size to zero?
1909            _currentStepSize = 0.0;
1910            // If the enclosing director implements SuperdenseTimeDirector,
1911            // then we used to get the current index from it.
1912            // However, we can't really trust the outside director to have
1913            // incremented the index, and it would incorrect to execute
1914            // without increment it. So we use our own index.
1915            /*
1916            if (executiveDirector instanceof SuperdenseTimeDirector) {
1917                _index = ((SuperdenseTimeDirector) executiveDirector).getIndex();
1918            }
1919             */
1920            return true;
1921        } else if (localTimeExceedsOutsideTime < 0) {
1922            ///////////////////////////////////////////////////////////////
1923            // Third case:
1924            // Local current time is behind environment time.
1925            // This should not happen. This used to happen if
1926            // we are inside a modal model and have been
1927            // disabled at the time that the commit
1928            // would be effective. We should cancel any pending commit.
1929            if (_commitIsPending) {
1930                _commitIsPending = false;
1931                rollBackToCommittedState();
1932            }
1933
1934            // We should set current time to the environment time and set
1935            // the step size to zero.
1936            this.localClock.setLocalTime(
1937                    localClock.getLocalTimeForCurrentEnvironmentTime());
1938
1939            if (_debugging) {
1940                _debug("-- Setting current time to match enclosing non-ContinuousDirector: "
1941                        + currentTime + ", and step size to 0.0.");
1942            }
1943            _currentStepSize = 0.0;
1944        } else {
1945            ///////////////////////////////////////////////////////////////
1946            // Fourth case:
1947            // Environment time matches local time and there is no pending
1948            // commit.
1949            // Adjust the step size to
1950            // make sure the time does not exceed the next iteration
1951            // time of the environment during this next integration step.
1952            Time environmentNextIterationTime = localClock
1953                    .getLocalTimeForEnvironmentTime(
1954                            executiveDirector.getModelNextIterationTime());
1955
1956            Time localTargetTime = _iterationBeginTime.add(_currentStepSize);
1957            if (environmentNextIterationTime.compareTo(localTargetTime) < 0) {
1958                _currentStepSize = environmentNextIterationTime
1959                        .subtract(currentTime).getDoubleValue();
1960                if (_debugging) {
1961                    _debug("-- Revising step size due to environment's next iteration time to "
1962                            + _currentStepSize);
1963                }
1964            }
1965            // If the enclosing director implements SuperdenseTimeDirector,
1966            // then we used to get the current index from it.
1967            // But we can't trust the enclosing director to do the right
1968            // thing with the index. It becomes too fragile.
1969            /*
1970            if (executiveDirector instanceof SuperdenseTimeDirector) {
1971                _index = ((SuperdenseTimeDirector) executiveDirector).getIndex();
1972            }
1973             */
1974        }
1975
1976        // If the current time and index match the first entry in the breakpoint
1977        // table, then remove that entry. An index is deemed to match if
1978        // the breakpoint index is less than or equal to the current time index.
1979        if (!_breakpoints.isEmpty()) {
1980            SuperdenseTime nextBreakpoint = (SuperdenseTime) _breakpoints
1981                    .first();
1982            Time breakpointTime = nextBreakpoint.timestamp();
1983            localTimeExceedsOutsideTime = breakpointTime.compareTo(currentTime);
1984            if (localTimeExceedsOutsideTime < 0) {
1985                throw new IllegalActionException(this,
1986                        "ContinuousDirector expected to be fired at time "
1987                                + breakpointTime
1988                                + " but instead is being fired at time "
1989                                + currentTime);
1990            }
1991
1992            // NOTE: An alternative would be
1993            // to remove any breakpoints from the table that are now in the past.
1994            // In theory, this should not happen. The code for doing that is below.
1995            /*
1996            while (localTimeExceedsOutsideTime < 0
1997                    || (localTimeExceedsOutsideTime == 0 && nextBreakpoint
1998                            .index() < _index)) {
1999                if (_debugging) {
2000                    _debug("Remove a breakpoint that we missed: "
2001                            + breakpointTime);
2002                }
2003                _breakpoints.removeFirst();
2004                if (_breakpoints.isEmpty()) {
2005                    break;
2006                }
2007                nextBreakpoint = (SuperdenseTime) _breakpoints.first();
2008                breakpointTime = nextBreakpoint.timestamp();
2009                localTimeExceedsOutsideTime = breakpointTime
2010                        .compareTo(_currentTime);
2011            }
2012             */
2013            if (localTimeExceedsOutsideTime == 0
2014                    && nextBreakpoint.index() <= _index) {
2015                if (_debugging) {
2016                    _debug("-- The current superdense time is a breakpoint, "
2017                            + nextBreakpoint + ", which is removed.");
2018                }
2019                _breakpoints.removeFirst();
2020            }
2021        }
2022
2023        // Do not call super.prefire() because it sets the local mode
2024        // time to match that of the executive director, defeating the
2025        // above logic. Therefore, we have duplicate what it does here.
2026        _synchronizeToRealTime();
2027        _postfireReturns = true;
2028
2029        // Initialize everything for the fixedpoint iteration.
2030        // NOTE: This is handled by fire(), and anyway, should
2031        // not be done if there is a commit pending.
2032        // _resetAllReceivers();
2033
2034        if (_debugging) {
2035            _debug("Called prefire(), which returns true.");
2036        }
2037        return true;
2038    }
2039
2040    /** Set the current step size.
2041     *  @param stepSize The step size to be set.
2042     *  @see #_currentStepSize
2043     */
2044    private void _setCurrentStepSize(double stepSize) {
2045        if (_debugging) {
2046            _debug("----- Setting the current step size to " + stepSize);
2047        }
2048        _currentStepSize = stepSize;
2049    }
2050
2051    /** Return a list of stateful components, which includes actors
2052     *  deeply contained within the container of this director that
2053     *  implement the ContinuousStatefulComponent interface and
2054     *  directors of opaque composite actors within the container
2055     *  of this director that implement the same interface.
2056     *  @return A list of objects implementing ContinuousStatefulComponent.
2057     */
2058    private List _statefulComponents() {
2059        if (_workspace.getVersion() != _statefulComponentsVersion) {
2060            // Construct the list.
2061            _statefulComponents.clear();
2062            CompositeEntity container = (CompositeEntity) getContainer();
2063            Iterator actors = container.deepEntityList().iterator();
2064            while (actors.hasNext()) {
2065                Object actor = actors.next();
2066                if (actor instanceof ContinuousStatefulComponent) {
2067                    _statefulComponents.add(actor);
2068                } else if (actor instanceof CompositeActor
2069                        && ((CompositeEntity) actor).isOpaque()
2070                        && !((CompositeEntity) actor).isAtomic()) {
2071                    Director director = ((Actor) actor).getDirector();
2072                    if (director instanceof ContinuousStatefulComponent) {
2073                        _statefulComponents.add(director);
2074                    }
2075                }
2076            }
2077            _statefulComponentsVersion = _workspace.getVersion();
2078        }
2079        return _statefulComponents;
2080    }
2081
2082    /** Return a list of step-size controllers.
2083     *  @return A list of step-size control actors.
2084     */
2085    private List _stepSizeControllers() {
2086        if (_workspace.getVersion() != _stepSizeControllersVersion) {
2087            // Construct the list.
2088            _stepSizeControllers.clear();
2089            CompositeEntity container = (CompositeEntity) getContainer();
2090            Iterator actors = container.deepEntityList().iterator();
2091            while (actors.hasNext()) {
2092                Object actor = actors.next();
2093                if (actor instanceof ContinuousStepSizeController) {
2094                    _stepSizeControllers.add(actor);
2095                } else if (actor instanceof CompositeActor
2096                        && ((CompositeEntity) actor).isOpaque()
2097                        && !((CompositeEntity) actor).isAtomic()) {
2098                    Director director = ((Actor) actor).getDirector();
2099                    if (director instanceof ContinuousStepSizeController) {
2100                        _stepSizeControllers.add(director);
2101                    }
2102                }
2103            }
2104            _stepSizeControllersVersion = _workspace.getVersion();
2105        }
2106        return _stepSizeControllers;
2107    }
2108
2109    /** Transfer inputs from the environment to inside.
2110     *  @exception IllegalActionException If the transferInputs(Port)
2111     *   method throws it.
2112     *  @return True if at least one token is transferred.
2113     */
2114    private boolean _transferInputsToInside() throws IllegalActionException {
2115        // If there are no input ports, this method does nothing.
2116        if (_debugging) {
2117            _debug("** Transfer inputs to the inside.");
2118        }
2119        boolean result = false;
2120        CompositeActor container = (CompositeActor) getContainer();
2121        Iterator inports = container.inputPortList().iterator();
2122        while (inports.hasNext() && !_stopRequested) {
2123            IOPort port = (IOPort) inports.next();
2124            result = super.transferInputs(port) || result;
2125        }
2126        return result;
2127    }
2128
2129    /** Transfer outputs to the environment.
2130     *  @exception IllegalActionException If the transferOutputs(Port)
2131     *   method throws it.
2132     */
2133    private void _transferOutputsToEnvironment() throws IllegalActionException {
2134        if (_debugging) {
2135            _debug("** Transfer outputs to the environment.");
2136        }
2137
2138        // If there are no output ports, this method does nothing.
2139        CompositeActor container = (CompositeActor) getContainer();
2140        Iterator outports = container.outputPortList().iterator();
2141        while (outports.hasNext() && !_stopRequested) {
2142            IOPort p = (IOPort) outports.next();
2143            super.transferOutputs(p);
2144        }
2145    }
2146
2147    ///////////////////////////////////////////////////////////////////
2148    ////                         private variables                 ////
2149
2150    /** A table for breakpoints. */
2151    private TotallyOrderedSet _breakpoints;
2152
2153    /** Flag indicating that postfire() did not commit the state at the
2154     *  local current time.
2155     */
2156    private boolean _commitIsPending = false;
2157
2158    /** Simulation step sizes. */
2159    private double _currentStepSize;
2160
2161    /** The enclosing continuous director. */
2162    private ContinuousDirector _enclosingContinuousDirector = null;
2163
2164    /** The version for __enclosingContinuousDirector. */
2165    private long _enclosingContinuousDirectorVersion = -1;
2166
2167    /** The error tolerance for state resolution. */
2168    private double _errorTolerance;
2169
2170    /** Flag to temporarily ignore the setModelTime() calls. */
2171    private boolean _ignoreSetTime = false;
2172
2173    /** A cache of the value of initStepSize. */
2174    private double _initStepSize;
2175
2176    /** Flag indicating that the solver is iterating through the first or
2177     *  intermediate steps in a multi-step solver.
2178     */
2179    private boolean _isIntermediateStep = false;
2180
2181    /** The index of the time at which the current integration step began. */
2182    private int _iterationBeginIndex;
2183
2184    /** The maximum iterations for implicit ODE solver to resolve states. */
2185    private int _maxIterations;
2186
2187    /** The maximum step size used for integration. */
2188    private double _maxStepSize;
2189
2190    /** The ODE solver, which is an instance of the class given by
2191     *  the <i>ODESolver</i> parameter.
2192     */
2193    private ContinuousODESolver _ODESolver = null;
2194
2195    /** Flag indicating that we are redoing a speculative solver iteration. */
2196    private boolean _redoingSolverIteration = false;
2197
2198    /** The package name for the solvers supported by this director. */
2199    private static String _solverClasspath = "ptolemy.domains.continuous.kernel.solver.";
2200
2201    /** The list of stateful actors. */
2202    private List _statefulComponents = new LinkedList();
2203
2204    /** The version for the list of step size control actors. */
2205    private long _statefulComponentsVersion = -1;
2206
2207    /** The list of step size control actors. */
2208    private List _stepSizeControllers = new LinkedList();
2209
2210    /** The version for the list of step size control actors. */
2211    private long _stepSizeControllersVersion = -1;
2212
2213    /** The local flag variable indicating whether the we have tried
2214     *  the time resolution as the integration step size. */
2215    private boolean _triedTheMinimumStepSize = false;
2216}