001/* Base class for time-based sources. 002 003 Copyright (c) 1998-2014 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.TimedActor; 032import ptolemy.actor.util.Time; 033import ptolemy.data.BooleanToken; 034import ptolemy.data.DoubleToken; 035import ptolemy.data.expr.Parameter; 036import ptolemy.data.type.BaseType; 037import ptolemy.kernel.CompositeEntity; 038import ptolemy.kernel.util.Attribute; 039import ptolemy.kernel.util.IllegalActionException; 040import ptolemy.kernel.util.NameDuplicationException; 041 042/////////////////////////////////////////////////////////////////// 043//// TimedSource 044 045/** 046 Base class for time-based sources. A time-based source is 047 a source where the output value is a function of current time. 048 For some sequence-based domains, such as SDF, actors of this type 049 probably do not make sense because current time is not incremented. 050 This actor has a parameter, <i>stopTime</i>, that optionally controls 051 the duration for which the actor is fired. When current time reaches 052 the stopTime, postfire() returns false. This indicates 053 to the director that this actor should not be invoked again. 054 The default value of stopTime is <i>Infinity</i>, which results in postfire 055 always returning true. In other words, this makes the lifetime 056 infinite. Derived classes must call super.postfire() for this mechanism to 057 work. 058 059 @author Edward A. Lee 060 @version $Id$ 061 @since Ptolemy II 0.3 062 @Pt.ProposedRating Green (eal) 063 @Pt.AcceptedRating Green (bilung) 064 */ 065public class TimedSource extends Source implements TimedActor { 066 /** Construct an actor with the given container and name. 067 * The <i>stopTime</i> parameter is also constructed. 068 * @param container The container. 069 * @param name The name of this actor. 070 * @exception IllegalActionException If the actor cannot be contained 071 * by the proposed container. 072 * @exception NameDuplicationException If the container already has an 073 * actor with this name. 074 */ 075 public TimedSource(CompositeEntity container, String name) 076 throws NameDuplicationException, IllegalActionException { 077 super(container, name); 078 stopTime = new Parameter(this, "stopTime"); 079 stopTime.setExpression("Infinity"); 080 stopTime.setTypeEquals(BaseType.DOUBLE); 081 082 stopTimeIsLocal = new Parameter(this, "stopTimeIsLocal"); 083 stopTimeIsLocal.setTypeEquals(BaseType.BOOLEAN); 084 stopTimeIsLocal.setExpression("false"); 085 086 _attachText("_iconDescription", "<svg>\n" + "<rect x=\"-20\" y=\"-20\" " 087 + "width=\"40\" height=\"40\" " + "style=\"fill:lightGrey\"/>\n" 088 + "<circle cx=\"0\" cy=\"0\" r=\"17\"" 089 + "style=\"fill:white\"/>\n" 090 + "<line x1=\"0\" y1=\"-15\" x2=\"0\" y2=\"-13\"/>\n" 091 + "<line x1=\"0\" y1=\"14\" x2=\"0\" y2=\"16\"/>\n" 092 + "<line x1=\"-15\" y1=\"0\" x2=\"-13\" y2=\"0\"/>\n" 093 + "<line x1=\"14\" y1=\"0\" x2=\"16\" y2=\"0\"/>\n" 094 + "<line x1=\"0\" y1=\"-8\" x2=\"0\" y2=\"0\"/>\n" 095 + "<line x1=\"0\" y1=\"0\" x2=\"11.26\" y2=\"-6.5\"/>\n" 096 + "</svg>\n"); 097 } 098 099 /////////////////////////////////////////////////////////////////// 100 //// ports and parameters //// 101 102 /** The time at which postfire() should return false. This is a 103 * double that defaults to Infinity, which means that postfire() 104 * never returns false (or at least, doesn't do so due to stopTime 105 * having been exceeded). 106 */ 107 public Parameter stopTime; 108 109 /** If true, use the local time to compare against the <i>stopTime</i> 110 * parameter, rather than the global time. Local time may differ 111 * from global time inside modal models and certain domains 112 * that manipulate time. This is a boolean that defaults 113 * to false. 114 */ 115 public Parameter stopTimeIsLocal; 116 117 /////////////////////////////////////////////////////////////////// 118 //// public methods //// 119 120 /** If the <i>stopTime</i> parameter is changed and the model is 121 * executing, then if the new value is greater 122 * than zero and greater than the current time, then ask the director 123 * to fire this actor at that time. If the new value is less than 124 * the current time, then request refiring at the current time. 125 * @param attribute The attribute that changed. 126 * @exception IllegalActionException If the superclass throws it. 127 */ 128 @Override 129 public void attributeChanged(Attribute attribute) 130 throws IllegalActionException { 131 if (attribute == stopTime) { 132 double newStopTimeValue = ((DoubleToken) stopTime.getToken()) 133 .doubleValue(); 134 135 if (_executing) { 136 Time newStopTime = new Time(getDirector(), newStopTimeValue); 137 Director director = getDirector(); 138 139 if (director != null) { 140 Time currentTime; 141 boolean localTime = ((BooleanToken) stopTimeIsLocal 142 .getToken()).booleanValue(); 143 if (localTime) { 144 currentTime = director.getModelTime(); 145 } else { 146 currentTime = director.getGlobalTime(); 147 } 148 149 if (newStopTime.compareTo(currentTime) > 0) { 150 // NOTE: Do not throw an exception if the director ignores this 151 // stop time request or returns some other value of time. 152 // postfire() will return false on the next firing after time 153 // equals the stop time or exceeds it. 154 director.fireAt(this, newStopTime); 155 } else { 156 /* Do not throw an exception here because it makes it 157 * impossible to change the stop time after the model has run. 158 * 159 throw new IllegalActionException(this, "The stop time " 160 + newStopTime 161 + " is earlier than the current time " 162 + currentTime); 163 */ 164 } 165 } 166 167 _stopTime = newStopTime; 168 } 169 } else { 170 super.attributeChanged(attribute); 171 } 172 } 173 174 /** Get the stop time. 175 * @return The stop time. 176 * @deprecated As of Ptolemy II 4.1, replaced by 177 * {@link #getModelStopTime} 178 */ 179 @Deprecated 180 public double getStopTime() { 181 return getModelStopTime().getDoubleValue(); 182 } 183 184 /** Get the stop time. 185 * @return The stop time. 186 */ 187 public Time getModelStopTime() { 188 return _stopTime; 189 } 190 191 /** Initialize the actor. Schedule a refiring of this actor at the 192 * stop time given by the <i>stopTime</i> parameter. 193 * @exception IllegalActionException If there is no director. 194 */ 195 @Override 196 public void initialize() throws IllegalActionException { 197 super.initialize(); 198 199 Director director = getDirector(); 200 201 if (director == null) { 202 throw new IllegalActionException(this, "No director!"); 203 } 204 205 double stopTimeValue = ((DoubleToken) stopTime.getToken()) 206 .doubleValue(); 207 _stopTime = new Time(getDirector(), stopTimeValue); 208 209 Time currentTime; 210 boolean localTime = ((BooleanToken) stopTimeIsLocal.getToken()) 211 .booleanValue(); 212 if (localTime) { 213 currentTime = director.getModelTime(); 214 } else { 215 currentTime = director.getGlobalTime(); 216 } 217 218 if (!_stopTime.isInfinite() && _stopTime.compareTo(currentTime) > 0) { 219 // NOTE: Do not throw an exception if the director ignores this 220 // stop time request or returns some other value of time. 221 // postfire() will return false on the next firing after time 222 // equals the stop time or exceeds it. 223 director.fireAt(this, _stopTime); 224 _executing = true; 225 } 226 } 227 228 /** Return false if the current time is greater than or equal to 229 * the <i>stopTime</i> parameter value. 230 * Otherwise, return true. Derived classes should call this 231 * at the end of their postfire() method and return its returned 232 * value. 233 * @exception IllegalActionException Not thrown in this base class. 234 */ 235 @Override 236 public boolean postfire() throws IllegalActionException { 237 if (!super.postfire()) { 238 // Presumably, stopRequested is true. 239 return false; 240 } 241 Time currentTime; 242 boolean localTime = ((BooleanToken) stopTimeIsLocal.getToken()) 243 .booleanValue(); 244 if (localTime) { 245 currentTime = getDirector().getModelTime(); 246 } else { 247 currentTime = getDirector().getGlobalTime(); 248 } 249 250 if (currentTime.compareTo(_stopTime) >= 0) { 251 return false; 252 } 253 254 return true; 255 } 256 257 /** Return false if the current time is greater than or equal to 258 * the <i>stopTime</i> parameter value. 259 * Otherwise, return what the superclass returns. 260 * @exception IllegalActionException Not thrown in this base class. 261 */ 262 @Override 263 public boolean prefire() throws IllegalActionException { 264 Boolean result = super.prefire(); 265 Time currentTime; 266 boolean localTime = ((BooleanToken) stopTimeIsLocal.getToken()) 267 .booleanValue(); 268 if (localTime) { 269 currentTime = getDirector().getModelTime(); 270 } else { 271 currentTime = getDirector().getGlobalTime(); 272 } 273 if (currentTime.compareTo(_stopTime) >= 0) { 274 return false; 275 } 276 return result; 277 } 278 279 /** Override the base class to reset a flag that indicates that the 280 * model is executing. This method is invoked exactly once per execution 281 * of an application. None of the other action methods should be 282 * be invoked after it. 283 * @exception IllegalActionException Not thrown in this base class. 284 */ 285 @Override 286 public void wrapup() throws IllegalActionException { 287 super.wrapup(); 288 _executing = false; 289 } 290 291 /////////////////////////////////////////////////////////////////// 292 //// private variables //// 293 // Flag indicating that the model is running. 294 private boolean _executing = false; 295 296 // stop time. 297 private Time _stopTime; 298}