001/* An actor that outputs a sequence with a given step in values. 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.Manager; 031import ptolemy.actor.parameters.PortParameter; 032import ptolemy.data.BooleanToken; 033import ptolemy.data.Token; 034import ptolemy.data.expr.Parameter; 035import ptolemy.kernel.CompositeEntity; 036import ptolemy.kernel.util.Attribute; 037import ptolemy.kernel.util.IllegalActionException; 038import ptolemy.kernel.util.InternalErrorException; 039import ptolemy.kernel.util.NameDuplicationException; 040import ptolemy.kernel.util.Workspace; 041 042/////////////////////////////////////////////////////////////////// 043//// Ramp 044 045/** 046 Produce an output token on each firing with a value that is 047 incremented by the specified step each iteration. The 048 first output is given by the <i>init</i> parameter, and the 049 increment may be given either by the <i>step</i> parameter or by 050 the associated <i>step</i> port. Note that the increment will show 051 up in the output only on the next iteration. If you need it to show 052 up on the current iteration, use the 053 {@link ptolemy.actor.lib.Accumulator} actor. 054 The type of the output is determined by the constraint that it must 055 be greater than or equal to the types of the parameter (and/or the 056 <i>step</i> port, if it is connected). 057 Thus, this actor is 058 polymorphic in the sense that its output data type can be that 059 of any token type that supports addition. 060 061 @see Accumulator 062 @author Yuhong Xiong, Edward A. Lee 063 @version $Id$ 064 @since Ptolemy II 0.2 065 @Pt.ProposedRating Green (eal) 066 @Pt.AcceptedRating Green (bilung) 067 */ 068public class Ramp extends SequenceSource { 069 /** Construct an actor with the given container and name. 070 * In addition to invoking the base class constructors, construct 071 * the <i>init</i> and <i>step</i> parameter and the <i>step</i> 072 * port. Initialize <i>init</i> 073 * to IntToken with value 0, and <i>step</i> to IntToken with value 1. 074 * @param container The container. 075 * @param name The name of this actor. 076 * @exception IllegalActionException If the actor cannot be contained 077 * by the proposed container. 078 * @exception NameDuplicationException If the container already has an 079 * actor with this name. 080 */ 081 public Ramp(CompositeEntity container, String name) 082 throws NameDuplicationException, IllegalActionException { 083 super(container, name); 084 init = new PortParameter(this, "init"); 085 init.setExpression("0"); 086 new Parameter(init.getPort(), "_showName", BooleanToken.TRUE); 087 step = new PortParameter(this, "step"); 088 step.setExpression("1"); 089 new Parameter(step.getPort(), "_showName", BooleanToken.TRUE); 090 091 // set the type constraints. 092 output.setTypeAtLeast(init); 093 output.setTypeAtLeast(step); 094 095 _attachText("_iconDescription", "<svg>\n" + "<rect x=\"-30\" y=\"-20\" " 096 + "width=\"60\" height=\"40\" " + "style=\"fill:white\"/>\n" 097 + "<polygon points=\"-20,10 20,-10 20,10\" " 098 + "style=\"fill:grey\"/>\n" + "</svg>\n"); 099 _resultArray = new Token[1]; 100 101 // Show the firingCountLimit parameter last. 102 firingCountLimit.moveToLast(); 103 } 104 105 /////////////////////////////////////////////////////////////////// 106 //// ports and parameters //// 107 108 /** The value produced by the ramp on its first iteration. 109 * If this value is changed during execution, then the new 110 * value will be the output on the next iteration. 111 * The default value of this parameter is the integer 0. 112 */ 113 public PortParameter init; 114 115 /** The amount by which the ramp output is incremented on each iteration. 116 * The default value of this parameter is the integer 1. 117 */ 118 public PortParameter step; 119 120 /////////////////////////////////////////////////////////////////// 121 //// public methods //// 122 123 /** If the argument is the <i>init</i> parameter, then reset the 124 * state to the specified value. 125 * @param attribute The attribute that changed. 126 * @exception IllegalActionException If <i>init</i> cannot be evaluated 127 * or cannot be converted to the output type, or if the superclass 128 * throws it. 129 */ 130 @Override 131 public void attributeChanged(Attribute attribute) 132 throws IllegalActionException { 133 if (attribute == init) { 134 // If type resolution has happened (the model is running), 135 // then update the current state. 136 Manager manager = getManager(); 137 if (manager != null) { 138 Manager.State state = manager.getState(); 139 if (state == Manager.ITERATING || state == Manager.PAUSED 140 || state == Manager.PAUSED_ON_BREAKPOINT) { 141 _stateToken = output.getType().convert(init.getToken()); 142 } 143 } 144 } else { 145 super.attributeChanged(attribute); 146 } 147 } 148 149 /** Clone the actor into the specified workspace. This calls the 150 * base class and then sets the <code>init</code> and <code>step</code> 151 * public members to the parameters of the new actor. 152 * @param workspace The workspace for the new object. 153 * @return A new actor. 154 * @exception CloneNotSupportedException If a derived class contains 155 * an attribute that cannot be cloned. 156 */ 157 @Override 158 public Object clone(Workspace workspace) throws CloneNotSupportedException { 159 Ramp newObject = (Ramp) super.clone(workspace); 160 161 // set the type constraints. 162 newObject.output.setTypeAtLeast(newObject.init); 163 newObject.output.setTypeAtLeast(newObject.step); 164 _resultArray = new Token[1]; 165 return newObject; 166 } 167 168 /** Send the current value of the state of this actor to the output. 169 * @exception IllegalActionException If calling send() or super.fire() 170 * throws it. 171 */ 172 @Override 173 public void fire() throws IllegalActionException { 174 init.update(); 175 super.fire(); 176 output.send(0, _stateToken); 177 } 178 179 /** Set the state to equal the value of the <i>init</i> parameter. 180 * The state is incremented by the value of the <i>step</i> 181 * parameter on each iteration (in the postfire() method). 182 * @exception IllegalActionException If the parent class throws it. 183 */ 184 @Override 185 public void initialize() throws IllegalActionException { 186 super.initialize(); 187 _stateToken = output.getType().convert(init.getToken()); 188 } 189 190 /** Invoke a specified number of iterations of this actor. Each 191 * iteration updates the state of the actor by adding the 192 * value of the <i>step</i> parameter to the state and sending 193 * the value of the state to the output. The iteration count 194 * is also incremented by the value of <i>count</i>, and if 195 * the result is greater than or equal to <i>firingCountLimit</i> 196 * then return STOP_ITERATING. 197 * <p> 198 * This method should be called instead of the usual prefire(), 199 * fire(), postfire() methods when this actor is used in a 200 * domain that supports vectorized actors. This leads to more 201 * efficient execution. 202 * @param count The number of iterations to perform. 203 * @return COMPLETED if the actor was successfully iterated the 204 * specified number of times. Otherwise, if the maximum 205 * iteration count has been reached, return STOP_ITERATING. 206 * @exception IllegalActionException If iterating cannot be 207 * performed. 208 */ 209 @Override 210 public int iterate(int count) throws IllegalActionException { 211 // Check whether we need to reallocate the output token array. 212 if (count > _resultArray.length) { 213 _resultArray = new Token[count]; 214 } 215 216 // Consume any trigger inputs. 217 // NOTE: It might seem that using trigger.numberOfSources() is 218 // correct here, but it is not. It is possible for channels 219 // to be connected, for example, to other output ports or 220 // even back to this same trigger port, in which case higher 221 // numbered channels will not have their inputs read. 222 for (int i = 0; i < trigger.getWidth(); i++) { 223 if (trigger.hasToken(i, count)) { 224 trigger.get(i, count); 225 } 226 } 227 228 for (int i = 0; i < count; i++) { 229 _resultArray[i] = _stateToken; 230 231 try { 232 step.update(); 233 init.update(); 234 _stateToken = _stateToken.add(step.getToken()); 235 } catch (IllegalActionException ex) { 236 throw new InternalErrorException(this, ex, 237 "Should not be thrown because we have already " 238 + "verified that the tokens can be added"); 239 } 240 } 241 242 output.send(0, _resultArray, count); 243 244 if (_firingCountLimit != 0) { 245 _iterationCount += count; 246 247 if (_iterationCount >= _firingCountLimit) { 248 return STOP_ITERATING; 249 } 250 } 251 252 return COMPLETED; 253 } 254 255 /** Update the state of the actor by adding the value of the 256 * <i>step</i> parameter to the state. Also, increment the 257 * iteration count, and if the result is equal to 258 * <i>firingCountLimit</i>, then 259 * return false. 260 * @return False if the number of iterations matches the number requested. 261 * @exception IllegalActionException If the firingCountLimit parameter 262 * has an invalid expression. 263 */ 264 @Override 265 public boolean postfire() throws IllegalActionException { 266 step.update(); 267 _stateToken = _stateToken.add(step.getToken()); 268 return super.postfire(); 269 } 270 271 /////////////////////////////////////////////////////////////////// 272 //// private variables //// 273 private Token _stateToken = null; 274 275 private Token[] _resultArray; 276}