001/* A composite actor that executes a submodel in fire(). 002 003 Copyright (c) 2003-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 028 */ 029package ptolemy.actor.lib.hoc; 030 031import java.util.Iterator; 032 033import ptolemy.actor.TypedIOPort; 034import ptolemy.data.IntToken; 035import ptolemy.data.expr.Parameter; 036import ptolemy.data.expr.Variable; 037import ptolemy.data.type.BaseType; 038import ptolemy.kernel.CompositeEntity; 039import ptolemy.kernel.util.Attribute; 040import ptolemy.kernel.util.IllegalActionException; 041import ptolemy.kernel.util.InternalErrorException; 042import ptolemy.kernel.util.NameDuplicationException; 043import ptolemy.kernel.util.Workspace; 044 045/////////////////////////////////////////////////////////////////// 046//// RunCompositeActor 047 048/** 049 This is a composite actor that can execute the contained model 050 completely, as if it were a top-level model, on each firing. 051 This can be used to define an actor whose firing behavior 052 is given by a complete execution of a submodel. 053 <p> 054 An instance of this actor can have ports added to it. If it has 055 input ports, then on each firing, before executing the referenced 056 model, this actor will read an input token from the input port, if 057 there is one, and use it to set the value of a top-level parameter 058 in the contained model that has the same name as the port, if there 059 is one. The simplest way to ensure that there is a matching parameter 060 is to use a PortParameter for inputs. However, this actor will work 061 also for ordinary ports. In this case, if this actor has a 062 parameter with the same name as the port, and it is an instance 063 of Variable (or its derived class Parameter), then the token 064 read at the input is moved into it using its setToken() method. 065 Otherwise, if it is an instance of Settable, then a string representation 066 of the token is copied using the setExpression() method. 067 Input ports should not be multiports, and if they are, then 068 all but the first channel will be ignored. 069 <p> 070 If this actor has output ports and the contained model is executed, 071 then upon completion of that execution, if this actor has parameters 072 whose names match those of the output ports, then the final value of 073 those parameters is sent to the output ports. If such a parameter is an 074 instance of Variable (or its derived class Parameter), then its 075 contained token is sent to the output token. Otherwise, if it is an 076 instance of Settable, then a string token is produced on the output 077 with its value equal to that returned by getExpression() of the 078 Settable. Output ports should not be multiports. If they are, 079 then all but the first channel will be ignored. 080 A typical use of this actor will use the SetVariable actor 081 inside to define the value of the output port. 082 <p> 083 In preinitialize(), type constraints are set up so that input 084 and output ports with (name) matching parameters are constrained 085 to have compatible types. Note that if the ports or parameters 086 are changed during execution, then it will be necessary to set 087 up matching type constraints by hand. Since this isn't possible 088 to do from Vergil, the ports and parameters of this actor 089 should not be changed using Vergil during execution. 090 <p> 091 This actor also overrides the requestChange() method and the 092 executeChangeRequests() method to execute the given change. It does not 093 delegate the change request to the container, but executes the request 094 immediately or records it, depending on whether setDeferringChangeRequests() 095 has been called with a true argument. 096 097 @author Edward A. Lee, Yang Zhao, Elaine Cheong 098 @version $Id$ 099 @since Ptolemy II 4.0 100 @see ModelReference 101 @see ptolemy.actor.lib.SetVariable 102 @Pt.ProposedRating Yellow (eal) 103 @Pt.AcceptedRating Red (eal) 104 */ 105public class RunCompositeActor extends LifeCycleManager { 106 /** Construct an actor in the default workspace with no 107 * container and an empty string as its name. Add the actor to the 108 * workspace directory. You should set the local director or 109 * executive director before attempting to send data to the actor or 110 * to execute it. Increment the version number of the workspace. 111 * @exception NameDuplicationException If there is already a parameter with 112 * name firingCountLimit. 113 * @exception IllegalActionException If the firingCountLimit cannot be 114 * initialized. 115 */ 116 public RunCompositeActor() 117 throws IllegalActionException, NameDuplicationException { 118 super(); 119 _init(); 120 } 121 122 /** Construct a RunCompositeActor in the specified workspace with 123 * no container and an empty string as a name. You can then change 124 * the name with setName(). If the workspace argument is null, then 125 * use the default workspace. You should set the local director or 126 * executive director before attempting to send data to the actor 127 * or to execute it. Add the actor to the workspace directory. 128 * Increment the version number of the workspace. 129 * @param workspace The workspace that will list the actor. 130 * @exception NameDuplicationException If there is already a parameter with 131 * name firingCountLimit. 132 * @exception IllegalActionException If the firingCountLimit cannot be 133 * initialized. 134 */ 135 public RunCompositeActor(Workspace workspace) 136 throws IllegalActionException, NameDuplicationException { 137 super(workspace); 138 _init(); 139 } 140 141 /** Construct a RunCompositeActor with a name and a container. 142 * The container argument must not be null, or a 143 * NullPointerException will be thrown. This actor will use the 144 * workspace of the container for synchronization and version counts. 145 * If the name argument is null, then the name is set to the empty string. 146 * Increment the version of the workspace. This actor will have no 147 * local director initially, and its executive director will be simply 148 * the director of the container. 149 * 150 * @param container The container. 151 * @param name The name of this actor. 152 * @exception IllegalActionException If the container is incompatible 153 * with this actor. 154 * @exception NameDuplicationException If the name coincides with 155 * an actor already in the container. 156 */ 157 public RunCompositeActor(CompositeEntity container, String name) 158 throws IllegalActionException, NameDuplicationException { 159 super(container, name); 160 _init(); 161 } 162 163 /////////////////////////////////////////////////////////////////// 164 //// parameters //// 165 166 /** Indicator to run the contained model a limited number of times. 167 * If this parameter has a value greater than zero, then after 168 * executing the inside model the specified number of times, 169 * {@link #postfire()} will return false. This is an int that 170 * defaults to 0, which means that there is no limit. 171 */ 172 public Parameter firingCountLimit; 173 174 /////////////////////////////////////////////////////////////////// 175 //// public methods //// 176 177 /** Run a complete execution of the contained model. A complete 178 * execution consists of invocation of super.initialize(), 179 * repeated invocations of super.prefire(), super.fire(), and 180 * super.postfire(), followed by super.wrapup(). The invocations 181 * of prefire(), fire(), and postfire() are repeated until either 182 * the model indicates it is not ready to execute (prefire() 183 * returns false), or it requests a stop (postfire() returns 184 * false or stop() is called). Before running the complete 185 * execution, this method calls the director's transferInputs() 186 * method to read any available inputs. After running the 187 * complete execution, it calls transferOutputs(). The subclass 188 * of this can set the <i>_isSubclassOfRunCompositeActor</i> to be 189 * true to call the fire method of the superclass of this. 190 * @exception IllegalActionException If there is no director, or if 191 * the director's action methods throw it. 192 */ 193 @Override 194 public void fire() throws IllegalActionException { 195 // Note that super.fire() is not called here probably because 196 // CompositeActor.fire() transfers inputs. 197 198 // FIXME: CompositeActor.fire() invokes the piggyback.fire(), 199 // this method does not. 200 201 if (_debugging) { 202 _debug("---- calling fire(), which will execute a subsystem."); 203 } 204 205 _executeInsideModel(); 206 } 207 208 /** Initialize this actor, which in this case, does nothing. The 209 * initialization of the submodel is accomplished in fire(). The 210 * subclass of this can set the 211 * <i>_isSubclassOfRunCompositeActor</i> to be true to call the 212 * initialize method of the superclass of this. 213 * @exception IllegalActionException Not thrown in this base class, 214 * but declared so the subclasses can throw it. 215 */ 216 @Override 217 public void initialize() throws IllegalActionException { 218 // FIXME: Why does this method not call super.initialize()? 219 // CompositeActor.initialize() invokes the initialize method 220 // of the local director and resets the receivers. Are 221 // these steps not necessary here? 222 if (_debugging) { 223 _debug("Called initialize(), which does nothing."); 224 } 225 _iteration = 0; 226 } 227 228 /** Return true, indicating that execution can continue. The 229 * subclass of this can set the 230 * <i>_isSubclassOfRunCompositeActor</i> to be true to call the 231 * postfire method of the superclass of this. 232 * @exception IllegalActionException Not thrown in this base class, 233 * but declared so the subclasses can throw it. 234 */ 235 @Override 236 public boolean postfire() throws IllegalActionException { 237 int limitValue = ((IntToken) firingCountLimit.getToken()).intValue(); 238 if (limitValue > 0) { 239 _iteration++; 240 if (_iteration >= limitValue) { 241 if (_debugging) { 242 _debug("Called postfire(), which returns false."); 243 } 244 return false; 245 } 246 } 247 if (_debugging) { 248 _debug("Called postfire(), which returns true."); 249 } 250 // FIXME: Why does calling super.postfire() cause a causality loop exception with test/auto/RunCompositeActor3.xml 251 // FIXME: Shouldn't piggybacked methods be called here? 252 //return super.postfire(); 253 return true; 254 } 255 256 /** Return true, indicating that this actor is always ready to fire. 257 * @exception IllegalActionException Not thrown in this base class, 258 * but declared so the subclasses can throw it. 259 */ 260 @Override 261 public boolean prefire() throws IllegalActionException { 262 // FIXME: Why is super.prefire() not called here, which calls 263 // CompositeActor.prefire(). CompositeActor.prefire() invokes 264 // prefire() on the director and the piggybacked methods, 265 // which does not happen here. 266 if (_debugging) { 267 _debug("Called prefire(), which returns true."); 268 } 269 270 return true; 271 } 272 273 /** Override the base class to set type constraints between the 274 * output ports and parameters of this actor whose name matches 275 * the output port. If there is no such parameter, then create 276 * an instance of Variable with a matching name and set up the 277 * type constraints to that instance. The type of the output 278 * port is constrained to be at least that of the parameter 279 * or variable. 280 * @exception IllegalActionException If there is no director, or if 281 * the director's preinitialize() method throws it, or if this actor 282 * is not opaque. 283 */ 284 @Override 285 public void preinitialize() throws IllegalActionException { 286 super.preinitialize(); 287 288 Iterator ports = outputPortList().iterator(); 289 290 while (ports.hasNext()) { 291 TypedIOPort port = (TypedIOPort) ports.next(); 292 293 // Ensure that the production rate is one. 294 // FIXME: This may not be right if there is no 295 // actual source of data for this port (e.g. no 296 // SetVariable actor). 297 Variable rate = (Variable) port.getAttribute("tokenProductionRate"); 298 299 if (rate == null) { 300 try { 301 rate = new Variable(port, "tokenProductionRate"); 302 } catch (NameDuplicationException e) { 303 throw new InternalErrorException(e); 304 } 305 } 306 307 rate.setToken(new IntToken(1)); 308 309 String portName = port.getName(); 310 Attribute attribute = getAttribute(portName); 311 312 if (attribute == null) { 313 try { 314 workspace().getWriteAccess(); 315 attribute = new Variable(this, portName); 316 } catch (NameDuplicationException ex) { 317 throw new InternalErrorException(ex); 318 } finally { 319 workspace().doneWriting(); 320 } 321 } 322 323 // attribute is now assured to be non-null. 324 if (attribute instanceof Variable) { 325 port.setTypeAtLeast((Variable) attribute); 326 } else { 327 // Assume the port type must be a string. 328 port.setTypeEquals(BaseType.STRING); 329 } 330 } 331 } 332 333 /** Override the base class to do nothing. 334 * @exception IllegalActionException Not thrown in this base class, 335 * but declared so the subclasses can throw it. 336 */ 337 @Override 338 public void wrapup() throws IllegalActionException { 339 if (_debugging) { 340 _debug("Called wrapup(), which does nothing."); 341 } 342 } 343 344 /////////////////////////////////////////////////////////////////// 345 //// protected methods //// 346 347 /** Set the class name and create the parameters. 348 * @exception NameDuplicationException If there is already a parameter with 349 * name firingCountLimit. 350 * @exception IllegalActionException If the firingCountLimit cannot be 351 * initialized. 352 */ 353 protected void _init() 354 throws IllegalActionException, NameDuplicationException { 355 // By default, when exporting MoML, the class name is whatever 356 // the Java class is, which in this case is RunCompositeActor. 357 // In derived classes, however, we usually do not want to identify 358 // the class name as that of the derived class, but rather want 359 // to identify it as RunCompositeActor. This way, the MoML 360 // that is exported does not depend on the presence of the 361 // derived class Java definition. Thus, we force the class name 362 // here to be RunCompositeActor. 363 setClassName("ptolemy.actor.lib.hoc.RunCompositeActor"); 364 365 firingCountLimit = new Parameter(this, "firingCountLimit"); 366 firingCountLimit.setTypeEquals(BaseType.INT); 367 firingCountLimit.setExpression("0"); 368 } 369 370 /////////////////////////////////////////////////////////////////// 371 //// private variables //// 372 373 /** The count of iterations. */ 374 private int _iteration; 375}