001/* A composite where events can occur inside between the times when 002 the outside model invokes the composite. 003 004 Copyright (c) 2004-2018 The Regents of the University of California. 005 All rights reserved. 006 Permission is hereby granted, without written agreement and without 007 license or royalty fees, to use, copy, modify, and distribute this 008 software and its documentation for any purpose, provided that the above 009 copyright notice and the following two paragraphs appear in all copies 010 of this software. 011 012 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 013 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 014 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 015 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 016 SUCH DAMAGE. 017 018 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 019 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 020 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 021 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 022 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 023 ENHANCEMENTS, OR MODIFICATIONS. 024 025 PT_COPYRIGHT_VERSION_2 026 COPYRIGHTENDKEY 027 028 */ 029package ptolemy.actor.lib.hoc; 030 031import java.io.Writer; 032import java.util.Iterator; 033import java.util.List; 034import java.util.PriorityQueue; 035 036import ptolemy.actor.Actor; 037import ptolemy.actor.CompositeActor; 038import ptolemy.actor.Director; 039import ptolemy.actor.Executable; 040import ptolemy.actor.FiringEvent; 041import ptolemy.actor.IOPort; 042import ptolemy.actor.QueueReceiver; 043import ptolemy.actor.Receiver; 044import ptolemy.actor.SuperdenseTimeDirector; 045import ptolemy.actor.parameters.ParameterPort; 046import ptolemy.actor.util.SuperdenseTime; 047import ptolemy.actor.util.Time; 048import ptolemy.data.BooleanToken; 049import ptolemy.data.expr.Parameter; 050import ptolemy.data.type.BaseType; 051import ptolemy.kernel.CompositeEntity; 052import ptolemy.kernel.util.IllegalActionException; 053import ptolemy.kernel.util.NameDuplicationException; 054import ptolemy.kernel.util.Workspace; 055 056/////////////////////////////////////////////////////////////////// 057//// CatchUpComposite 058 059/** 060This composite allows events to occur in the inside model 061between the times when the outside model invokes this composite. 062The inside model is required to have a director. 063<p> 064When this composite actor is fired, it fires the 065inside model to process any unprocessed events it may have 066at earlier times than the environment time of the firing. 067If in any of these "catch up" firings the inside model 068attempts to produce outputs, this director will throw an 069exception. This director then transfers any available 070inputs to the inside model and fires the inside model 071one more time. On this "caught up" firing, the inside 072model is permitted to produce outputs. 073<p> 074By default, if an actor contained by this composite requests 075a firing at a future time, then that request is passed up to 076the containing director. If <i>fireOnlyWhenTriggered</i> is set 077to <i>true</i>, however, then such requests are not passed up. 078In this case, the next firing will occur whenever the container 079has an input to provide to this composite, and catching up will 080occur only at that time. Note that if this composite produces 081outputs, you have to be very careful to ensure that those outputs 082are produced only at times when an input trigger is provided. 083<p> 084Note that a firing of this composite results in one 085or more complete iterations of the inside model, including 086invocations of postfire. Thus, this actor changes state 087in the fire() method, and hence only implements the 088weak actor semantics. Therefore, it should not be used 089inside domains that require a strict actor semantics, 090such as Continuous, which requires that fire() not 091change state (so that backtracking can occur). 092This composite probably can be used in SR, where it 093will be treated as a strict as actor and hence will be 094fired only once per iteration, and only when all inputs 095are known. 096 097 @author Edward A. Lee 098 @version $Id$ 099 @since Ptolemy II 11.0 100 @Pt.ProposedRating Yellow (eal) 101 @Pt.AcceptedRating Red (neuendor) 102 */ 103public class CatchUpComposite extends MirrorComposite { 104 105 /** Create an actor with a name and a container. 106 * The container argument must not be null, or a 107 * NullPointerException will be thrown. This actor will use the 108 * workspace of the container for synchronization and version counts. 109 * If the name argument is null, then the name is set to the empty string. 110 * Increment the version of the workspace. 111 * @param container The container actor. 112 * @param name The name of this actor. 113 * @exception IllegalActionException If the container is incompatible 114 * with this actor. 115 * @exception NameDuplicationException If the name coincides with 116 * an actor already in the container. 117 */ 118 public CatchUpComposite(CompositeEntity container, String name) 119 throws IllegalActionException, NameDuplicationException { 120 super(container, name); 121 _init(container); 122 } 123 124 /** Construct a CatchUpComposite in the specified workspace with 125 * no container and an empty string as a name. You can then change 126 * the name with setName(). If the workspace argument is null, then 127 * use the default workspace. 128 * @param workspace The workspace that will list the actor. 129 * @exception IllegalActionException If the container is incompatible 130 * with this actor. 131 * @exception NameDuplicationException If the name of the 132 * director coincides with an actor already in the container. 133 */ 134 public CatchUpComposite(Workspace workspace) 135 throws IllegalActionException, NameDuplicationException { 136 // This constructor is needed if CatchUpComposite is used as an 137 // actor-oriented class. 138 super(workspace); 139 // FIXME: The null argument will be a problem! 140 _init(null); 141 } 142 143 /////////////////////////////////////////////////////////////////// 144 //// public methods //// 145 146 /** Clone the object into the specified workspace. This overrides 147 * the base class to instantiate a new CatchUpDirector. 148 * @param workspace The workspace for the new object. 149 * @return A new NamedObj. 150 * @exception CloneNotSupportedException If any of the attributes 151 * cannot be cloned. 152 * @see #exportMoML(Writer, int, String) 153 */ 154 @Override 155 public Object clone(Workspace workspace) throws CloneNotSupportedException { 156 CatchUpComposite result = (CatchUpComposite) super.clone(workspace); 157 try { 158 // Remove the old inner CatchUpDirector(s) that is(are) in the wrong workspace. 159 // FIXME: Is this really needed? Following IterateOverArray. 160 String catchUpDirectorName = null; 161 Iterator catchUpDirectors = result 162 .attributeList(CatchUpDirector.class).iterator(); 163 while (catchUpDirectors.hasNext()) { 164 CatchUpDirector oldCatchUpDirector = (CatchUpDirector) catchUpDirectors 165 .next(); 166 if (catchUpDirectorName == null) { 167 catchUpDirectorName = oldCatchUpDirector.getName(); 168 } 169 oldCatchUpDirector.setContainer(null); 170 } 171 172 // Create a new CatchUpDirector that is in the right workspace. 173 CatchUpDirector catchUpDirector = result.new CatchUpDirector( 174 workspace); 175 catchUpDirector.setContainer(result); 176 catchUpDirector.setName(catchUpDirectorName); 177 } catch (Throwable throwable) { 178 throw new CloneNotSupportedException( 179 "Could not clone: " + throwable); 180 } 181 return result; 182 } 183 184 /** Fire any piggybacked actors and then delegate the firing to the director. 185 * This overrides the base class to not transfer inputs or outputs. 186 * Those operations are handled by the director. 187 * @exception IllegalActionException If there is no director, or if 188 * the director's fire() method throws it, or if the actor is not 189 * opaque. 190 */ 191 @Override 192 public void fire() throws IllegalActionException { 193 if (_debugging) { 194 _debug("Calling fire()"); 195 } 196 197 try { 198 _workspace.getReadAccess(); 199 200 // First invoke piggybacked methods. 201 if (_piggybacks != null) { 202 // Invoke the fire() method of each piggyback. 203 for (Executable piggyback : _piggybacks) { 204 piggyback.fire(); 205 } 206 } 207 if (_derivedPiggybacks != null) { 208 // Invoke the fire() method of each piggyback. 209 for (Executable piggyback : _derivedPiggybacks) { 210 piggyback.fire(); 211 } 212 } 213 _director.fire(); 214 } finally { 215 _workspace.doneReading(); 216 } 217 218 if (_debugging) { 219 _debug("Called fire()"); 220 } 221 } 222 223 /////////////////////////////////////////////////////////////////// 224 //// private variables //// 225 226 /** The contained composite actor. */ 227 private Contents _contents; 228 229 /** The default value icon. This is static so that we avoid doing 230 * string concatenation each time we construct this object. 231 */ 232 private static String _defaultIcon = "<svg>\n" 233 + "<rect x=\"-30\" y=\"-20\" width=\"60\" " 234 + "height=\"40\" style=\"fill:cyan\"/>\n" 235 + "<rect x=\"-28\" y=\"-18\" width=\"56\" " 236 + "height=\"36\" style=\"fill:lightgrey\"/>\n" 237 + "<rect x=\"-15\" y=\"-10\" width=\"10\" height=\"8\" " 238 + "style=\"fill:white\"/>\n" 239 + "<rect x=\"-15\" y=\"2\" width=\"10\" height=\"8\" " 240 + "style=\"fill:white\"/>\n" 241 + "<rect x=\"5\" y=\"-4\" width=\"10\" height=\"8\" " 242 + "style=\"fill:white\"/>\n" 243 + "<line x1=\"-5\" y1=\"-6\" x2=\"0\" y2=\"-6\"/>" 244 + "<line x1=\"-5\" y1=\"6\" x2=\"0\" y2=\"6\"/>" 245 + "<line x1=\"0\" y1=\"-6\" x2=\"0\" y2=\"6\"/>" 246 + "<line x1=\"0\" y1=\"0\" x2=\"5\" y2=\"0\"/>" + "</svg>\n"; 247 248 /** The director. */ 249 private CatchUpDirector _director; 250 251 /////////////////////////////////////////////////////////////////// 252 //// private methods //// 253 254 /** Initialize the actor. 255 * @param container The container. 256 * @exception IllegalActionException If the container is incompatible 257 * with this actor. 258 * @exception NameDuplicationException If the name coincides with 259 * an actor already in the container. 260 */ 261 private void _init(CompositeEntity container) 262 throws IllegalActionException, NameDuplicationException { 263 setClassName("ptolemy.actor.lib.hoc.CatchUpComposite"); 264 265 // Create the CatchUpDirector in the proper workspace. 266 _director = new CatchUpDirector(workspace()); 267 _director.setContainer(this); 268 _director.setName("CatchUpDirector"); 269 270 // Create the composite actor for the contents. 271 _contents = new Contents(this, "Contents"); 272 273 // Override the default icon. 274 _attachText("_iconDescription", _defaultIcon); 275 } 276 277 /////////////////////////////////////////////////////////////////// 278 //// inner classes //// 279 280 /////////////////////////////////////////////////////////////////// 281 //// CatchUpDirector 282 283 /** This is a specialized director that, when fired, fires the 284 * inside model to process any unprocessed events it may have 285 * at earlier times than the environment time of the firing. 286 * If in any of these "catch up" firings the inside model 287 * attempts to produce outputs, this director will throw an 288 * exception. This director then transfers any available 289 * inputs to the inside model and fires the inside model 290 * one more time. On this "caught up" firing, the inside 291 * model is permitted to produce outputs. 292 */ 293 private class CatchUpDirector extends Director 294 implements SuperdenseTimeDirector { 295 296 /** Construct an CatchUpDirector in the specified workspace with 297 * no container and an empty string as a name. 298 * @param workspace The workspace. 299 * @exception IllegalActionException If the container is incompatible 300 * with this actor. 301 * @exception NameDuplicationException If the name coincides with 302 * an actor already in the container. 303 */ 304 public CatchUpDirector(Workspace workspace) 305 throws IllegalActionException, NameDuplicationException { 306 super(workspace); 307 setPersistent(false); 308 } 309 310 /** Clone the object into the specified workspace. 311 * @param workspace The workspace for the new object. 312 * @return A new NamedObj. 313 * @exception CloneNotSupportedException If any of the attributes 314 * cannot be cloned. 315 * @see #exportMoML(Writer, int, String) 316 */ 317 @Override 318 public Object clone(Workspace workspace) 319 throws CloneNotSupportedException { 320 CatchUpDirector result = (CatchUpDirector) super.clone(workspace); 321 result._pendingFiringTimes = null; 322 return result; 323 } 324 325 /** Invoke one or more iterations of the contained actor of the 326 * container of this director, allowing it to process any internal 327 * events that it may have at earlier times than the current time 328 * of the enclosing model. That is, perform zero or more 329 * "catch up" iterations of the contained actor, where the contained 330 * actor will see an earlier time than the current time of 331 * the enclosing model, followed by exactly one "caught up" 332 * iteration. The inputs of this composite will be visible to 333 * the inside model only on the "caught up" iteration. 334 * @exception IllegalActionException If any called method of 335 * of the contained actor throws it, or if the contained 336 * actor is not opaque. 337 */ 338 @Override 339 public void fire() throws IllegalActionException { 340 // Don't call "super.fire();" here, this actor contains its 341 // own director. 342 CompositeActor container = (CompositeActor) getContainer(); 343 _postfireReturns = true; 344 345 Director enclosingDirector = container.getExecutiveDirector(); 346 if (enclosingDirector == null) { 347 throw new IllegalActionException(container, 348 "No enclosing director!"); 349 } 350 int microstep = 1; 351 if (enclosingDirector instanceof SuperdenseTimeDirector) { 352 microstep = ((SuperdenseTimeDirector) enclosingDirector) 353 .getIndex(); 354 } 355 SuperdenseTime environmentTime = new SuperdenseTime(getModelTime(), 356 microstep); 357 358 // Perform catch up iterations, if necessary. 359 if (_pendingFiringTimes != null) { 360 SuperdenseTime firstPendingFiringTime = _pendingFiringTimes 361 .peek(); 362 while (firstPendingFiringTime != null) { 363 int comparison = firstPendingFiringTime 364 .compareTo(environmentTime); 365 if (comparison < 0) { 366 // Catch up iteration is needed. 367 _pendingFiringTimes.poll(); 368 369 // Perform catch up firing. 370 try { 371 _catchUpTime = firstPendingFiringTime.timestamp(); 372 _microstep = firstPendingFiringTime.index(); 373 374 if (!_fireContents()) { 375 // Postfire returned false. 376 break; 377 } 378 // If any output port has tokens, this is an error. 379 List<IOPort> ports = outputPortList(); 380 for (IOPort port : ports) { 381 for (int i = 0; i < port.getWidth(); i++) { 382 if (port.hasTokenInside(i)) { 383 throw new IllegalActionException(port, 384 "Illegal output during catch up iteration. " 385 + "Composite actor is attempting to produce an output at time " 386 + _catchUpTime 387 + ", but environment time is past that at " 388 + environmentTime 389 .timestamp()); 390 } 391 } 392 } 393 } finally { 394 _catchUpTime = null; 395 } 396 397 // In case another catch up iteration is needed: 398 firstPendingFiringTime = _pendingFiringTimes.peek(); 399 } else if (comparison == 0) { 400 // Caught up firing will satisfy the request. 401 _pendingFiringTimes.poll(); 402 break; 403 } else { 404 // Pending request is in the future. 405 // Proceed directly to caught up firing. 406 break; 407 } 408 } 409 } 410 411 // Perform caught up iteration only if no catch iteration has returned 412 // false from postfire(). 413 if (_postfireReturns == true) { 414 _microstep = microstep; 415 // Transfer inputs. 416 for (Iterator<?> inputPorts = inputPortList() 417 .iterator(); inputPorts.hasNext() && !_stopRequested;) { 418 IOPort p = (IOPort) inputPorts.next(); 419 if (p instanceof ParameterPort) { 420 ((ParameterPort) p).getParameter().update(); 421 } else { 422 transferInputs(p); 423 } 424 } 425 426 if (!_stopRequested) { 427 _fireContents(); 428 429 // Transfer outputs. 430 if (!_stopRequested) { 431 transferOutputs(); 432 } 433 } 434 435 // If there is a pending request in the future, delegate 436 // a fireAt() request. 437 if (_pendingFiringTimes != null) { 438 SuperdenseTime firstPendingFiringTime = _pendingFiringTimes 439 .peek(); 440 if (firstPendingFiringTime != null && firstPendingFiringTime 441 .compareTo(environmentTime) > 0) { 442 // First argument is ignored, so it can be null. 443 fireAt(null, firstPendingFiringTime.timestamp(), 444 firstPendingFiringTime.index()); 445 } 446 } 447 } 448 } 449 450 /** Request a firing of the given actor at the given model 451 * time. This class delegates the request to the enclosing 452 * director. If the enclosing director returns the same 453 * requested time, then nothing further happens. If the 454 * enclosing director returns a later time, then this method 455 * records the requested time so that on the next firing 456 * a "catch up" iteration will be performed at that time. 457 * If the enclosing director returns an earlier time, 458 * then this method also records the requested time, 459 * and on the next firing, will again attempt to delegate 460 * to the container. 461 * @param actor The actor scheduled to be fired. 462 * @param time The requested time. 463 * @return An instance of Time with the current time value, or 464 * if there is an executive director, the time at which the 465 * container of this director will next be fired 466 * in response to this request. 467 * @see #fireAtCurrentTime(Actor) 468 * @exception IllegalActionException If there is an executive director 469 * and it throws it. Derived classes may choose to throw this 470 * exception for other reasons. 471 */ 472 @Override 473 public Time fireAt(Actor actor, Time time) 474 throws IllegalActionException { 475 // Unless the actor specifically requests a particular microstep, 476 // we assume it knows nothing about microsteps. We use microstep 1 477 // as the default, since this is the default for discrete events. 478 // The Continuous domain will specifically request a firing at 479 // microstep 0. 480 return fireAt(actor, time, 1); 481 } 482 483 /** Request a firing of the given actor at the given model 484 * time with the given microstep. This method behaves exactly 485 * like {@link #fireAt(Actor, Time)}, except that it also 486 * passes up to the executive director the microstep, if there 487 * is one. 488 * @param actor The actor scheduled to be fired. 489 * @param time The requested time. 490 * @param microstep The requested microstep. 491 * @return An instance of Time with the current time value, or 492 * if there is an executive director, the time at which the 493 * container of this director will next be fired 494 * in response to this request. 495 * @see #fireAtCurrentTime(Actor) 496 * @see #fireContainerAt(Time) 497 * @exception IllegalActionException If there is an executive director 498 * and it throws it. Derived classes may choose to throw this 499 * exception for other reasons. 500 */ 501 @Override 502 public Time fireAt(Actor actor, Time time, int microstep) 503 throws IllegalActionException { 504 if (_debugging) { 505 _debug("**** Requesting that enclosing director refire me at " 506 + time + " with microstep " + microstep); 507 } 508 // Translate the local time into an environment time. 509 Time environmentTime = localClock 510 .getEnvironmentTimeForLocalTime(time); 511 Director director = getExecutiveDirector(); 512 if (director instanceof SuperdenseTimeDirector) { 513 int environmentMicrostep = ((SuperdenseTimeDirector) director) 514 .getIndex(); 515 // Microstep should be greater than that of the enclosing director 516 // if the time matches current time. 517 if (getModelTime().equals(time) 518 && microstep < environmentMicrostep) { 519 microstep = environmentMicrostep + 1; 520 } 521 } 522 523 if (((BooleanToken) _contents.fireOnlyWhenTriggered.getToken()) 524 .booleanValue()) { 525 // Do not pass the request up the hierarchy. 526 if (_pendingFiringTimes == null) { 527 _pendingFiringTimes = new PriorityQueue<SuperdenseTime>(); 528 } 529 _pendingFiringTimes.add(new SuperdenseTime(time, microstep)); 530 // Do as below and return time anyway since the inside 531 // actor will think its time matches the requested firing time. 532 return time; 533 } else { 534 Time response = director.fireAt(CatchUpComposite.this, 535 environmentTime, microstep); 536 int comparison = response.compareTo(time); 537 if (comparison == 0) { 538 return time; 539 } else { 540 if (_pendingFiringTimes == null) { 541 _pendingFiringTimes = new PriorityQueue<SuperdenseTime>(); 542 } 543 _pendingFiringTimes 544 .add(new SuperdenseTime(time, microstep)); 545 return time; 546 } 547 } 548 } 549 550 /** Return a superdense time index for the current time, 551 * where the index is equal to the microstep. 552 * @return A superdense time index. 553 * @see #setIndex(int) 554 * @see ptolemy.actor.SuperdenseTimeDirector 555 */ 556 @Override 557 public int getIndex() { 558 return _microstep; 559 } 560 561 /** If a "catch up" iteration is in progress, then return the 562 * time that the inside model should see. Otherwise, return 563 * the environment time. 564 * @return The current time. 565 * @see #setModelTime(Time) 566 */ 567 @Override 568 public Time getModelTime() { 569 if (_catchUpTime == null) { 570 return super.getModelTime(); 571 } 572 return _catchUpTime; 573 } 574 575 /** Initialize contained actors 576 * @exception IllegalActionException If the initialize() method of 577 * the super class throws it. 578 */ 579 @Override 580 public void initialize() throws IllegalActionException { 581 // Initialize the microstep to zero, even though 582 // discrete models normally want to run with microstep 1 or higher. 583 // During initialization, some contained actors will request 584 // firings. One of those might be a Continuous subsystem, 585 // which will explicitly request a firing at microstep 0. 586 // Others will have their requests automatically set 587 // to microstep 1. Thus, with normal discrete models, 588 // the only events in the event queue after initialization 589 // will all have microstep 1, and hence that is where the 590 // simulation will start. 591 _microstep = 0; 592 // This could be getting re-initialized during execution 593 // (e.g., if we are inside a modal model), in which case, 594 // if the enclosing director is a superdense time director, 595 // we should initialize to its microstep, not to our own. 596 // NOTE: Some (weird) directors pretend they are not embedded even 597 // if they are (e.g. in Ptides), so we call _isEmbedded() to give 598 // the subclass the option of pretending it is not embedded. 599 if (isEmbedded()) { 600 Director executiveDirector = getExecutiveDirector(); 601 if (executiveDirector instanceof SuperdenseTimeDirector) { 602 _microstep = ((SuperdenseTimeDirector) executiveDirector) 603 .getIndex(); 604 } 605 } 606 super.initialize(); 607 } 608 609 /** Return a new instance of QueueReceiver. 610 * We use a QueueReceiver rather than the base class's MailboxReceiver 611 * so that more than one token can be transferred to the inside 612 * model on each firing. 613 * @return A new instance of QueueReceiver. 614 * @see QueueReceiver 615 */ 616 @Override 617 public Receiver newReceiver() { 618 return new QueueReceiver(); 619 } 620 621 /** Override the base class to return the logical AND of 622 * what the base class postfire() method returns and the 623 * flag set in fire(). 624 */ 625 @Override 626 public boolean postfire() throws IllegalActionException { 627 boolean superReturns = super.postfire(); 628 return superReturns && _postfireReturns; 629 } 630 631 /** Set the superdense time index. This should only be 632 * called by an enclosing director. 633 * @exception IllegalActionException Not thrown in this base class. 634 * @see #getIndex() 635 * @see ptolemy.actor.SuperdenseTimeDirector 636 */ 637 @Override 638 public void setIndex(int index) throws IllegalActionException { 639 if (_debugging) { 640 _debug("Setting superdense time index to " + index); 641 } 642 _microstep = index; 643 } 644 645 ////////////////////////////////////////////////////////////// 646 //// private methods //// 647 648 /** Iterate the contents composite. 649 * @exception IllegalActionException If the composite throws it. 650 * @return false if postfire() returns false. 651 */ 652 private boolean _fireContents() throws IllegalActionException { 653 if (_debugging) { 654 _debug(new FiringEvent(this, _contents, 655 FiringEvent.BEFORE_ITERATE, 1)); 656 } 657 if (_contents.iterate(1) == Executable.STOP_ITERATING) { 658 _postfireReturns = false; 659 } 660 if (_debugging) { 661 _debug(new FiringEvent(this, _contents, 662 FiringEvent.AFTER_ITERATE, 1)); 663 } 664 return _postfireReturns; 665 } 666 667 ////////////////////////////////////////////////////////////// 668 //// private variables //// 669 670 /** The time that the inside model should see as the current time 671 * during a "catch up" iteration, or null if there is no catch 672 * up iteration in progress. 673 */ 674 private Time _catchUpTime; 675 676 /** The current microstep. */ 677 protected int _microstep = 1; 678 679 /** A sorted list of times of pending fireAt() requests. */ 680 private PriorityQueue<SuperdenseTime> _pendingFiringTimes; 681 682 /** Indicator that the inside model returned false in postfire. */ 683 private boolean _postfireReturns = true; 684 } 685 686 /////////////////////////////////////////////////////////////////// 687 //// Contents 688 689 /** Contents composite that overrides the base class to have a parameter 690 * indicating whether to fire only when triggered. 691 */ 692 public class Contents extends MirrorComposite.MirrorCompositeContents { 693 694 // The Contents class should be public so that cloning works. 695 // To test: (cd $PTII/ptolemy/configs/test/; $PTII/bin/ptjacl allConfigs.tcl) 696 697 public Contents(CompositeEntity container, String name) 698 throws IllegalActionException, NameDuplicationException { 699 super(container, name); 700 701 fireOnlyWhenTriggered = new Parameter(this, 702 "fireOnlyWhenTriggered"); 703 fireOnlyWhenTriggered.setTypeEquals(BaseType.BOOLEAN); 704 fireOnlyWhenTriggered.setExpression("false"); 705 } 706 707 /** If false (the default), then whenever any contained actor 708 * makes a fireAt() request, that request is passed up to the container, 709 * and hence this composite will be fired at the requested time. 710 * If set to true, then the request will not be passed up, 711 * and this composite will be fired only when the container 712 * chooses to fire it. If the containing director is DE, for example, 713 * that will occur only when there is an input event to provide to 714 * this composite. 715 */ 716 public Parameter fireOnlyWhenTriggered; 717 } 718}