001/* An actor that delays the input by the specified amount. 002 003 Copyright (c) 1998-2015 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.Director; 031import ptolemy.actor.SuperdenseTimeDirector; 032import ptolemy.data.Token; 033import ptolemy.kernel.CompositeEntity; 034import ptolemy.kernel.util.IllegalActionException; 035import ptolemy.kernel.util.NameDuplicationException; 036import ptolemy.kernel.util.Workspace; 037 038/////////////////////////////////////////////////////////////////// 039//// MicrostepDelay 040 041/** 042 This actor delays the input by one microstep. The output is always 043 absent in the first firing. This actor is designed 044 to be used in domains where the director implements 045 SuperdenseTimeDirector, like Continuous and DE. 046 Inputs are read only during the postfire() method. 047 If an input is present, then this actor schedules itself to fire again 048 to produce the just received token on the corresponding output channel in 049 the next microstep at the same time stamp. 050 <p> 051 When this actor is used in the Continuous domain, it requires that its 052 input be purely discrete (specifically that it be absent at microstep 0). 053 The reason for rejecting continuous inputs is that a continuous input 054 would cause a stuttering Zeno condition, where time cannot advance. 055 056 @author Edward A. Lee 057 @version $Id$ 058 @since Ptolemy II 10.0 059 @Pt.ProposedRating Yellow (eal) 060 @Pt.AcceptedRating Red (eal) 061 */ 062public class MicrostepDelay extends Transformer { 063 /** Construct an actor with the specified container and name. 064 * Constrain that the output type to be the same as the input type. 065 * @param container The composite entity to contain this one. 066 * @param name The name of this actor. 067 * @exception IllegalActionException If the entity cannot be contained 068 * by the proposed container. 069 * @exception NameDuplicationException If the container already has an 070 * actor with this name. 071 */ 072 public MicrostepDelay(CompositeEntity container, String name) 073 throws NameDuplicationException, IllegalActionException { 074 super(container, name); 075 076 output.setTypeSameAs(input); 077 } 078 079 /////////////////////////////////////////////////////////////////// 080 //// public methods //// 081 082 /** Clone the actor into the specified workspace. Set a type 083 * constraint that the output type is the same as the that of input. 084 * @param workspace The workspace for the new object. 085 * @return A new actor. 086 * @exception CloneNotSupportedException If a derived class has 087 * has an attribute that cannot be cloned. 088 */ 089 @Override 090 public Object clone(Workspace workspace) throws CloneNotSupportedException { 091 MicrostepDelay newObject = (MicrostepDelay) super.clone(workspace); 092 newObject.output.setTypeSameAs(newObject.input); 093 return newObject; 094 } 095 096 /** Declare that the output does not depend on the input in a firing. 097 * @exception IllegalActionException If the causality interface 098 * cannot be computed. 099 * @see #getCausalityInterface() 100 */ 101 @Override 102 public void declareDelayDependency() throws IllegalActionException { 103 _declareDelayDependency(input, output, 0.0); 104 } 105 106 /** Read one token from the input. Send out a token that is scheduled 107 * to be produced at the current time. 108 * @exception IllegalActionException If there is no director, or the 109 * input can not be read, or the output can not be sent. 110 */ 111 @Override 112 public void fire() throws IllegalActionException { 113 super.fire(); 114 if (_pendingOutput != null) { 115 output.send(0, _pendingOutput); 116 if (_debugging) { 117 _debug("Sending output. Value = " + _pendingOutput); 118 } 119 } else { 120 // Nothing to send. Assert the output to be absent. 121 output.send(0, null); 122 if (_debugging) { 123 _debug("Nothing to send. Asserting absent output at time " 124 + getDirector().getModelTime()); 125 } 126 } 127 } 128 129 /** Initialize the states of this actor. 130 * @exception IllegalActionException If the director does 131 * not implement SuperdenseTimeDirector. 132 */ 133 @Override 134 public void initialize() throws IllegalActionException { 135 super.initialize(); 136 _pendingOutput = null; 137 138 if (!(getDirector() instanceof SuperdenseTimeDirector)) { 139 throw new IllegalActionException(this, 140 "MicrostepDelay can only be used with a director that implements " 141 + "SuperdenseTimeDirector, such as ContinuousDirector or DEDirector."); 142 } 143 } 144 145 /** Return false indicating that this actor can be fired even if 146 * the inputs are unknown. 147 * @return False. 148 */ 149 @Override 150 public boolean isStrict() { 151 return false; 152 } 153 154 /** Read the input, if there is one, and request refiring. 155 * @exception IllegalActionException If scheduling to refire cannot 156 * be performed, or if there is input and the current microstep is 157 * zero, or if the superclass throws it. 158 */ 159 @Override 160 public boolean postfire() throws IllegalActionException { 161 // No point in using the isTime() method here, since we need 162 // all the intermediate values. 163 Director director = getDirector(); 164 if (input.hasToken(0)) { 165 /* Do not enforce this. It is useful sometimes. 166 int microstep = ((SuperdenseTimeDirector) director).getIndex(); 167 if (microstep == 0) { 168 throw new IllegalActionException(this, 169 "Input is not purely discrete."); 170 } 171 */ 172 _pendingOutput = input.get(0); 173 // Do not use fireAtCurrentTime() because if synchronizeToRealTime is set, 174 // that will not necessarily match the current model time. 175 director.fireAt(this, director.getModelTime()); 176 if (_debugging) { 177 _debug("Read input with value = " + _pendingOutput); 178 } 179 } else { 180 _pendingOutput = null; 181 } 182 return super.postfire(); 183 } 184 185 /////////////////////////////////////////////////////////////////// 186 //// protected variables //// 187 188 /** A token to send in the next microstep. */ 189 protected Token _pendingOutput; 190}