001/* A clock source. 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.actor.lib; 029 030import ptolemy.actor.Manager; 031import ptolemy.actor.parameters.PortParameter; 032import ptolemy.actor.util.Time; 033import ptolemy.data.ArrayToken; 034import ptolemy.data.DoubleToken; 035import ptolemy.data.IntToken; 036import ptolemy.data.StringToken; 037import ptolemy.data.Token; 038import ptolemy.data.expr.Parameter; 039import ptolemy.data.type.ArrayType; 040import ptolemy.data.type.BaseType; 041import ptolemy.kernel.CompositeEntity; 042import ptolemy.kernel.util.Attribute; 043import ptolemy.kernel.util.IllegalActionException; 044import ptolemy.kernel.util.InternalErrorException; 045import ptolemy.kernel.util.NameDuplicationException; 046import ptolemy.kernel.util.Settable; 047import ptolemy.kernel.util.Workspace; 048 049/////////////////////////////////////////////////////////////////// 050//// Clock 051 052/** 053 This actor produces a periodic signal, a sequence of events at 054 regularly spaced intervals. 055 At the beginning of each time interval of length given by <i>period</i>, 056 starting from the time at which initialize() is invoked, 057 this actor initiates a sequence of output events with values given by 058 <i>values</i> and offset into the period given by <i>offsets</i>. 059 These parameters contain arrays, which are required to have the same length. 060 The <i>offsets</i> array contains doubles, which 061 must be nondecreasing and nonnegative, 062 or an exception will be thrown when it is set. 063 If any entry is greater than or equal to the <i>period</i> 064 then the corresponding output will never be produced. 065 <p> 066 The <i>values</i> parameter by default 067 contains an array of IntTokens with values 1 and 0. The default 068 <i>offsets</i> array is {0.0, 1.0}. Thus, the default output will be 069 alternating 1 and 0 with 50% duty cycle. The default period 070 is 2.0. 071 <p> 072 The type of the output can be any token type. This type is inferred 073 from the element type of the <i>values</i> parameter. 074 <p> 075 If the <i>period</i> is changed at any time, either by 076 providing an input or by changing the parameter, then the 077 new period will take effect as soon as possible. That is, 078 if there is already a period in progress, it may be cut 079 short if the new period is shorter so that its time matches 080 the new period. But it will only be cut short if current 081 time has not passed the cycle start time plus the new period. 082 Otherwise, the period in progress will run to completion. 083 <p> 084 This actor can generate finite sequences by specifying 085 a finite <i>numberOfCycles</i>. The numberOfCycles has a default value 086 UNBOUNDED, indicating infinite length of executions. If numberOfCycles is 087 a positive number, once the specified number of cycles has been completed, 088 then this actor returns false from the postfire() method, which indicates 089 to the director that the actor should not be fired again. 090 (A cycle is "completed" each time the last event in the <i>values</i> 091 array is produced). 092 <p> 093 The actor can also generate a finite sequence by giving a finite 094 value to the <i>stopTime</i> parameter. This gives a time rather than 095 a number of cycles, and thus can be used to stop the clock in the middle 096 of a cycle, unlike <i>numberOfCycles</i>. Just like <i>numberOfCycles</i>, 097 when the stop time is reached, the actor's postfire() method returns 098 false. 099 <p> 100 If the <i>trigger</i> input is connected, then an output will only 101 be produced if a input has been received since the last output. 102 The trigger input has no effect on the first output. After the 103 first output event, no further output event will be produced 104 until a time greater than or equal to the time at which a trigger 105 input is received. At that time, the output produced will have 106 whatever value would have been produced if the trigger input 107 was not connected. Note that this trigger is typically useful 108 in a feedback situation, where the output of the clock 109 eventually results in a trigger input. If the time-stamp 110 of that trigger input is less than the time between clock 111 events, then the clock will behave as if there were no 112 trigger input. Otherwise, it will "skip beats." 113 <p> 114 This actor can be a bit tricky to use inside a ModalModel. 115 In particular, if the actor is in a state refinement, then 116 it may "skip a beat" because of the state not being the current 117 state at the time of the beat. If this occurs, the clock will 118 simply stop firing, and will produce no further outputs. 119 To prevent this, the clock may be reinitialized 120 (by setting the <i>reset</i> flag 121 of a modal model transition). Alternatively, you can assign 122 a value to the 123 the <i>period</i> of the Clock in the <i>setActions</i> 124 of the transition. This will also have the effect of 125 waking up the clock, but with a subtle difference. 126 If you use a <i>reset</i> transition, the clock starts 127 over upon entering the destination state. If you set 128 the <i>period</i> parameter instead, then the clock 129 behaves as if it had been running all along (except 130 that its period may get changed). Thus, in the first 131 case, the output events are aligned with the time 132 of the transition, while in the second case, they 133 are aligned with the start time of the model execution. 134 <p> 135 This actor is a timed source; the untimed version is Pulse. 136 137 @author Edward A. Lee, Haiyang Zheng 138 @version $Id$ 139 @since Ptolemy II 0.3 140 @deprecated Use DiscreteClock. 141 @Pt.ProposedRating Yellow (eal) 142 @Pt.AcceptedRating Yellow (yuhong) 143 */ 144@Deprecated 145public class Clock extends TimedSource { 146 /** Construct an actor with the specified container and name. 147 * @param container The container. 148 * @param name The name of this actor. 149 * @exception IllegalActionException If the entity cannot be contained 150 * by the proposed container. 151 * @exception NameDuplicationException If the container already has an 152 * actor with this name. 153 */ 154 public Clock(CompositeEntity container, String name) 155 throws NameDuplicationException, IllegalActionException { 156 super(container, name); 157 158 period = new PortParameter(this, "period"); 159 period.setExpression("2.0"); 160 period.setTypeEquals(BaseType.DOUBLE); 161 162 offsets = new Parameter(this, "offsets"); 163 offsets.setExpression("{0.0, 1.0}"); 164 offsets.setTypeEquals(new ArrayType(BaseType.DOUBLE)); 165 166 // Call this so that we don't have to copy its code here... 167 attributeChanged(offsets); 168 169 // Set the values parameter. 170 values = new Parameter(this, "values"); 171 values.setExpression("{1, 0}"); 172 173 // Set type constraint on the output. 174 output.setTypeAtLeast(ArrayType.elementType(values)); 175 176 // Call this so that we don't have to copy its code here... 177 attributeChanged(values); 178 179 // Set the numberOfCycles parameter. 180 // Create a symbolic name for the default. 181 Parameter unbounded = new Parameter(this, "UNBOUNDED"); 182 unbounded.setPersistent(false); 183 unbounded.setExpression("-1"); 184 unbounded.setVisibility(Settable.EXPERT); 185 numberOfCycles = new Parameter(this, "numberOfCycles"); 186 numberOfCycles.setTypeEquals(BaseType.INT); 187 numberOfCycles.setExpression("UNBOUNDED"); 188 189 // Set the output signal type as DISCRETE to indicate 190 // that the outputs of this actor are discrete events. 191 new Parameter(output, "signalType", new StringToken("DISCRETE")); 192 193 // Set the trigger signal type as DISCRETE. 194 new Parameter(trigger, "signalType", new StringToken("DISCRETE")); 195 } 196 197 /////////////////////////////////////////////////////////////////// 198 //// ports and parameters //// 199 200 /** The number of cycles to produce, or UNBOUNDED to specify no limit. 201 * This is an integer with default UNBOUNDED. 202 */ 203 public Parameter numberOfCycles; 204 205 /** The offsets at which the specified values will be produced. 206 * This parameter must contain an array of doubles, and it defaults 207 * to {0.0, 1.0}. 208 */ 209 public Parameter offsets; 210 211 /** The period of the output waveform. 212 * This is a double that defaults to 2.0. 213 */ 214 public PortParameter period; 215 216 /** The values that will be produced at the specified offsets. 217 * This parameter must contain an ArrayToken, and it defaults to 218 * {1, 0} 219 */ 220 public Parameter values; 221 222 /////////////////////////////////////////////////////////////////// 223 //// public methods //// 224 225 /** If the argument is the <i>offsets</i> parameter, check that the 226 * array is nondecreasing and has the right dimension; if the 227 * argument is <i>period</i>, check that it is positive. Other 228 * sanity checks with <i>period</i> and <i>values</i> are done in 229 * the fire() method. 230 * @param attribute The attribute that changed. 231 * @exception IllegalActionException If the offsets array is not 232 * nondecreasing and nonnegative, or if the director will not 233 * respect the fireAt() call. 234 */ 235 @Override 236 public void attributeChanged(Attribute attribute) 237 throws IllegalActionException { 238 if (attribute == offsets) { 239 ArrayToken offsetsValue = (ArrayToken) offsets.getToken(); 240 _offsets = new double[offsetsValue.length()]; 241 242 double previous = 0.0; 243 244 for (int i = 0; i < offsetsValue.length(); i++) { 245 _offsets[i] = ((DoubleToken) offsetsValue.getElement(i)) 246 .doubleValue(); 247 248 // Check nondecreasing property. 249 if (_offsets[i] < previous) { 250 throw new IllegalActionException(this, 251 "Value of offsets is not nondecreasing " 252 + "and nonnegative."); 253 } 254 255 previous = _offsets[i]; 256 } 257 // Re-initialize the actor if we are running. 258 if (getManager() != null) { 259 Manager.State state = getManager().getState(); 260 if (state == Manager.ITERATING || state == Manager.PAUSED) { 261 // Reinitialize. 262 initialize(); 263 } 264 } 265 } else if (attribute == period) { 266 double periodValue = ((DoubleToken) period.getToken()) 267 .doubleValue(); 268 if (_debugging) { 269 _debug("Setting period to " + periodValue); 270 } 271 272 if (periodValue <= 0.0) { 273 throw new IllegalActionException(this, 274 "Period is required to be positive. " 275 + "Period given: " + periodValue); 276 } 277 // Schedule the next firing if we are running. 278 if (_initialized) { 279 // If this model has been dormant (e.g. in a ModalModel) 280 // then it needs to catch up. 281 _catchUp(); 282 // The _tentativeNextOutputTime may already 283 // be in the future beyond the point where we want it 284 // with the new period. Seems kind of tricky to get the 285 // right value. Only if the _phase is zero is this an 286 // issue, since in that case, the cycleStartTime has 287 // been updated to the start of the new cycle, which 288 // is too far in the future. 289 if (_phase == 0 && _firstOutputProduced) { 290 Time potentialNextOutputTime = _tentativeCycleStartTime 291 .subtract(_previousPeriod).add(periodValue); 292 if (potentialNextOutputTime 293 .compareTo(getDirector().getModelTime()) >= 0) { 294 _tentativeNextOutputTime = potentialNextOutputTime; 295 _tentativeCycleStartTime = potentialNextOutputTime; 296 // If this occurs outside fire(), e.g. in a modal 297 // model state transition, we also need to set the _cycleStartTime 298 // and _nextOutputTime. 299 if (!_tentative) { 300 _nextOutputTime = _tentativeNextOutputTime; 301 _cycleStartTime = _tentativeCycleStartTime; 302 } 303 } 304 } 305 _fireAt(_tentativeNextOutputTime); 306 } 307 _previousPeriod = periodValue; 308 } else { 309 super.attributeChanged(attribute); 310 } 311 } 312 313 /** Clone the actor into the specified workspace. This calls the 314 * base class and then sets the parameter public members to refer 315 * to the parameters of the new actor. 316 * @param workspace The workspace for the new object. 317 * @return A new actor. 318 * @exception CloneNotSupportedException If a derived class contains 319 * an attribute that cannot be cloned. 320 */ 321 @Override 322 public Object clone(Workspace workspace) throws CloneNotSupportedException { 323 Clock newObject = (Clock) super.clone(workspace); 324 325 try { 326 ArrayToken offsetsValue = (ArrayToken) offsets.getToken(); 327 newObject._offsets = new double[offsetsValue.length()]; 328 System.arraycopy(_offsets, 0, newObject._offsets, 0, 329 _offsets.length); 330 } catch (IllegalActionException ex) { 331 // CloneNotSupportedException does not have a constructor 332 // that takes a cause argument, so we use initCause 333 CloneNotSupportedException throwable = new CloneNotSupportedException(); 334 throwable.initCause(ex); 335 throw throwable; 336 } 337 try { 338 newObject.output 339 .setTypeAtLeast(ArrayType.elementType(newObject.values)); 340 } catch (IllegalActionException e) { 341 // Should have been caught before. 342 throw new InternalErrorException(e); 343 } 344 345 return newObject; 346 } 347 348 /** Output the current value of the clock if the time is right 349 * and, if connected, a trigger has been received. 350 * @exception IllegalActionException If 351 * the value in the offsets parameter is encountered that is greater 352 * than the period, or if there is no director. 353 */ 354 @Override 355 public void fire() throws IllegalActionException { 356 // Cannot call super.fire() because it consumes 357 // trigger inputs. 358 Time currentTime = getDirector().getModelTime(); 359 if (_debugging) { 360 _debug("Called fire() at time " + currentTime); 361 } 362 363 // Use the strategy pattern here so that derived classes can 364 // override how this is done. 365 _updateTentativeValues(); 366 367 // This must be after the above update because it may trigger 368 // a call to attributeChanged(), which uses the tentative values. 369 // Moreover, we should set a flag so that if attributeChanged() 370 // is called, then it is notified that the change is tentative. 371 // It is tentative because the input may be tentative. 372 // We should not commit any state changes in fire(). 373 try { 374 _tentative = true; 375 period.update(); 376 } finally { 377 _tentative = false; 378 } 379 380 // Check the trigger input, if it is connected. 381 boolean triggerConnected = false; 382 if (trigger.numberOfSources() > 0) { 383 triggerConnected = true; 384 for (int i = 0; i < trigger.getWidth(); i++) { 385 if (trigger.isKnown(i) && trigger.hasToken(i)) { 386 trigger.get(i); 387 _tentativeTriggered = true; 388 } 389 } 390 } 391 392 if (_enabled) { 393 _catchUp(); 394 // Produce an output only if we exactly match a phase time 395 // and, if the trigger input is connected, we have been triggered. 396 // Also make sure that if the phase is the same as the previous phase, 397 // then time has incremented. 398 if (_isTimeForOutput()) { 399 if (!triggerConnected || _tentativeTriggered) { 400 output.send(0, _getValue(_tentativePhase)); 401 } 402 // Even if we skip the output because of the lack 403 // of a trigger, we need to act as if we produced an 404 // output for the purposes of scheduling the next event. 405 _outputProduced = true; 406 } 407 } 408 } 409 410 /** Schedule the first firing and initialize local variables. 411 * @exception IllegalActionException If the parent class throws it, 412 * or if the <i>values</i> parameter is not a row vector, or if the 413 * fireAt() method of the director throws it, or if the director will not 414 * respect the fireAt() call. 415 */ 416 @Override 417 public void initialize() throws IllegalActionException { 418 super.initialize(); 419 420 // Start cycles at the current time. 421 // This is important in modal models that reinitialize the actor. 422 _cycleStartTime = getDirector().getModelTime(); 423 _tentativeCycleStartTime = _cycleStartTime; 424 _cycleCount = 0; 425 _phase = 0; 426 _tentativePhase = _phase; 427 _nextOutputTime = _cycleStartTime.add(_offsets[_phase]); 428 _tentativeNextOutputTime = _nextOutputTime; 429 430 // Make sure the first output is enabled. 431 _firstOutputProduced = false; 432 _outputProduced = false; 433 _enabled = true; 434 _tentativeEnabled = _enabled; 435 _previousPeriod = ((DoubleToken) period.getToken()).doubleValue(); 436 437 // Enable without a trigger input on the first firing. 438 _triggered = true; 439 _tentativeTriggered = _triggered; 440 441 if (_debugging) { 442 _debug("Requesting firing at time " + _nextOutputTime); 443 } 444 _fireAt(_nextOutputTime); 445 446 _initialized = true; 447 } 448 449 /** Update the state of the actor and schedule the next firing, 450 * if appropriate. 451 * @exception IllegalActionException If the director throws it when 452 * scheduling the next firing. 453 */ 454 @Override 455 public boolean postfire() throws IllegalActionException { 456 if (_debugging) { 457 _debug("Postfiring at " + getDirector().getModelTime()); 458 } 459 _updateStates(); 460 461 if (_outputProduced) { 462 _firstOutputProduced = true; 463 } 464 return super.postfire(); 465 } 466 467 /** Check that the length of the <i>values</i> and 468 * <i>offsets</i> parameters are the same. 469 * @return True. 470 * @exception IllegalActionException If the <i>values</i> and 471 * <i>offsets</i> parameters do not have the same length. 472 */ 473 @Override 474 public boolean prefire() throws IllegalActionException { 475 if (_debugging) { 476 _debug("Called prefire()"); 477 } 478 // Check the length of the values and offsets arrays. 479 // This is done here because it cannot be done in 480 // attributeChanged(), since the two parameters are set 481 // separately, and checking in initialize() is not really 482 // sufficient, since the values of these parameters can 483 // change at run time. 484 ArrayToken val = (ArrayToken) values.getToken(); 485 if (_offsets.length != val.length()) { 486 throw new IllegalActionException(this, 487 "Values and offsets vectors do not have the same length."); 488 } 489 490 // Cannot call super.prefire() because it has different semantics 491 // for the trigger input. 492 return true; 493 } 494 495 /** Override the base class to indicate that the actor has not 496 * been initialized. 497 * @exception IllegalActionException If the superclass throws it. 498 */ 499 @Override 500 public void wrapup() throws IllegalActionException { 501 super.wrapup(); 502 _initialized = false; 503 } 504 505 /////////////////////////////////////////////////////////////////// 506 //// protected methods //// 507 508 /** Catch up the tentative view 509 * of what the next output time should be. 510 * This sets _tentativeNextOutputTime to a value that 511 * is equal to or greater than current time, and it updates 512 * _tentativePhase and _tentativeCycleStartTime to correspond 513 * with this _tentativeNextOutputTime. If _tentativeNextOutputTime 514 * is already equal to or greater than current time, then do nothing. 515 * @exception IllegalActionException If the period is invalid. 516 */ 517 protected void _catchUp() throws IllegalActionException { 518 Time currentTime = getDirector().getModelTime(); 519 if (_tentativeNextOutputTime == null) { 520 // Initialization hasn't happened yet. No catch up to do. 521 return; 522 } 523 if (_tentativeNextOutputTime.compareTo(currentTime) >= 0) { 524 return; 525 } 526 // Find the first cycle time and phase greater than the 527 // current one that equals or exceeds current time. 528 // It might not be the very next phase because we could 529 // have been disabled in a modal model, or we could have 530 // skipped cycles due to not being triggered. 531 double periodValue = ((DoubleToken) period.getToken()).doubleValue(); 532 Time phaseStartTime = _tentativeCycleStartTime 533 .add(_offsets[_tentativePhase]); 534 while (phaseStartTime.compareTo(currentTime) < 0) { 535 _tentativePhase++; 536 if (_tentativePhase >= _offsets.length) { 537 _tentativePhase = 0; 538 _tentativeCycleStartTime = _tentativeCycleStartTime 539 .add(periodValue); 540 } 541 phaseStartTime = _tentativeCycleStartTime 542 .add(_offsets[_tentativePhase]); 543 } 544 _tentativeNextOutputTime = phaseStartTime; 545 } 546 547 /** Get the specified output value, checking the form of the values 548 * parameter. 549 * @param index The index of the output values. 550 * @return A token that contains the output value. 551 * @exception IllegalActionException If the index is out of the range of 552 * the values parameter. 553 */ 554 protected Token _getValue(int index) throws IllegalActionException { 555 ArrayToken val = (ArrayToken) values.getToken(); 556 557 if (val == null || val.length() <= index) { 558 throw new IllegalActionException(this, 559 "Index out of range of the values parameter."); 560 } 561 562 return val.getElement(index); 563 } 564 565 /** Return true if the current time is the right time for an output. 566 * @return True if the current time matches the _nextOutputTime. 567 * @exception IllegalActionException If the time is not right an 568 * a refiring cannot be requested. 569 */ 570 protected boolean _isTimeForOutput() throws IllegalActionException { 571 Time currentTime = getDirector().getModelTime(); 572 return _tentativeNextOutputTime.equals(currentTime); 573 } 574 575 /** Copy values committed in initialize() or in the last postfire() 576 * into the corresponding tentative variables. In effect, this loads 577 * the last known good value for these variables, which is particularly 578 * important if time has gone backwards. This is done in a 579 * protected method because derived classes may want to override 580 * it. 581 * @exception IllegalActionException Not thrown in this base class. 582 */ 583 protected void _updateTentativeValues() throws IllegalActionException { 584 _outputProduced = false; 585 _tentativeCycleStartTime = _cycleStartTime; 586 _tentativeEnabled = _enabled; 587 _tentativeNextOutputTime = _nextOutputTime; 588 _tentativePhase = _phase; 589 _tentativeTriggered = _triggered; 590 } 591 592 /** Update the states and request refiring if necessary. 593 * @exception IllegalActionException If the numberOfCycles parameter does 594 * not contain a valid parameter or can not request refiring, or if the director will not 595 * respect the fireAt() call.. 596 */ 597 protected void _updateStates() throws IllegalActionException { 598 // Schedule another firing if we are enabled 599 // and either an output was produced 600 // or a trigger input was received. 601 boolean triggerConnected = trigger.numberOfSources() > 0; 602 boolean fireAtNeeded = _tentativeEnabled 603 && (!triggerConnected && _outputProduced || triggerConnected 604 && _tentativeTriggered && !_outputProduced); 605 _cycleStartTime = _tentativeCycleStartTime; 606 _phase = _tentativePhase; 607 if (_outputProduced) { 608 _phase++; 609 if (_phase == _offsets.length) { 610 double periodValue = ((DoubleToken) period.getToken()) 611 .doubleValue(); 612 _cycleStartTime = _cycleStartTime.add(periodValue); 613 // Make the tentative value match, in case attributeChanged() 614 // is called before the next firing. 615 _tentativeCycleStartTime = _cycleStartTime; 616 _cycleCount++; 617 _phase = 0; 618 } 619 _tentativeTriggered = false; 620 } 621 _triggered = _tentativeTriggered; 622 _enabled = _tentativeEnabled; 623 _nextOutputTime = _cycleStartTime.add(_offsets[_phase]); 624 625 if (fireAtNeeded) { 626 if (_debugging) { 627 _debug("Requesting firing at: " + _nextOutputTime + "."); 628 } 629 _fireAt(_nextOutputTime); 630 } 631 632 // This should be computed after the above so that a firing 633 // gets requested for the tail end of the output pulses. 634 int cycleLimit = ((IntToken) numberOfCycles.getToken()).intValue(); 635 _enabled = _enabled && (cycleLimit <= 0 || _cycleCount <= cycleLimit); 636 } 637 638 /////////////////////////////////////////////////////////////////// 639 //// protected variables //// 640 641 /** The count of cycles executed so far, or 0 before the start. */ 642 protected transient int _cycleCount; 643 644 /** The most recent cycle start time. */ 645 protected transient Time _cycleStartTime; 646 647 /** Indicator of whether the specified number of cycles have 648 * been completed. Also used in derived classes to turn on 649 * and off the clock. 650 */ 651 protected transient boolean _enabled; 652 653 /** Indicator of whether the first output has been produced. */ 654 protected transient boolean _firstOutputProduced = false; 655 656 /** The time for the next output. */ 657 protected transient Time _nextOutputTime; 658 659 /** Cache of offsets array value. */ 660 protected transient double[] _offsets; 661 662 /** Indicator of whether an output was produced in this iteration. */ 663 protected transient boolean _outputProduced = false; 664 665 /** The phase of the next output. */ 666 protected transient int _phase; 667 668 /** The tentative time for the next output. */ 669 protected transient Time _tentativeNextOutputTime; 670 671 /////////////////////////////////////////////////////////////////// 672 //// private variables //// 673 674 /** True if the actor has been initialized. */ 675 private transient boolean _initialized; 676 677 /** The previous value of the period. */ 678 private transient double _previousPeriod; 679 680 // Following variables recall data from the fire to the postfire method. 681 682 /** The tentative start time of the most recent cycle. */ 683 private transient Time _tentativeCycleStartTime; 684 685 /** Flag indicating that an update to period is occurring 686 * in the fire() method. 687 */ 688 private transient boolean _tentative = false; 689 690 /** The indicator of whether the specified number of cycles 691 * have been completed. */ 692 private transient boolean _tentativeEnabled; 693 694 /** The tentative phase of the next output. */ 695 private transient int _tentativePhase; 696 697 /** Tentative indicator of triggered state. */ 698 private transient boolean _tentativeTriggered; 699 700 /** Indicator of whether trigger inputs have arrived 701 * since the last output. 702 */ 703 private transient boolean _triggered; 704}