001/* A merge actor for the Continuous domain.
002
003 Copyright (c) 1997-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.domains.continuous.lib;
029
030import java.util.LinkedList;
031import java.util.List;
032
033import ptolemy.actor.lib.Transformer;
034import ptolemy.data.BooleanToken;
035import ptolemy.data.Token;
036import ptolemy.data.expr.Parameter;
037import ptolemy.data.type.BaseType;
038import ptolemy.kernel.CompositeEntity;
039import ptolemy.kernel.util.IllegalActionException;
040import ptolemy.kernel.util.NameDuplicationException;
041
042///////////////////////////////////////////////////////////////////
043//// ContinuousMerge
044
045/**
046 A merge actor for the Continuous domain. This port has a multiport
047 input and on each firing, sends the input from channel 0 to the
048 output, if the input at channel 0 is present. Otherwise, it sends
049 the input from channel 1, if it is present. It continues to search
050 the inputs in channel order until it finds one that is present
051 or it runs out of input channels. In the latter case, the output
052 will be absent.
053 <p>
054 By default, this actor discards data on all channels after
055 the first channel that has present data. If you set the <i>discard</i>
056 parameter to false, however, then it will collect all present
057 data in queue and output it in the next microstep until all
058 present inputs have been produced on the output.
059 Note that setting this to false creates a risk of a chattering
060 Zeno system if a continuous signal is provided as input.
061 <p>
062 Note that this actor can merge continuous signals with discrete
063 ones, but the resulting signal may not be piecewise continuous.
064 This will be a bit odd. It is most useful to merge discrete signals
065 or signals that are piecewise continuous.
066
067 @author Edward A. Lee
068 @version $Id$
069 @since Ptolemy II 8.0
070 @Pt.ProposedRating Yellow (eal)
071 @Pt.AcceptedRating Red (eal)
072 */
073public class ContinuousMerge extends Transformer {
074    /** Construct an actor in the specified container with the specified
075     *  name. Create ports and make the input port a multiport.
076     *  @param container The container.
077     *  @param name The name.
078     *  @exception NameDuplicationException If an actor
079     *   with an identical name already exists in the container.
080     *  @exception IllegalActionException If the actor cannot be contained
081     *   by the proposed container.
082     */
083    public ContinuousMerge(CompositeEntity container, String name)
084            throws NameDuplicationException, IllegalActionException {
085        super(container, name);
086        input.setMultiport(true);
087
088        _attachText("_iconDescription",
089                "<svg>\n" + "<polygon points=\"-10,20 10,10 10,-10, -10,-20\" "
090                        + "style=\"fill:green\"/>\n" + "</svg>\n");
091
092        discard = new Parameter(this, "discard");
093        discard.setExpression("true");
094        discard.setTypeEquals(BaseType.BOOLEAN);
095    }
096
097    ///////////////////////////////////////////////////////////////////
098    ////                         parameters                        ////
099
100    /** Indicator of whether to discard present inputs on channel numbers
101     *  higher than the first one. This is a boolean that defaults to true.
102     */
103    public Parameter discard;
104
105    ///////////////////////////////////////////////////////////////////
106    ////                         public methods                    ////
107
108    /** Read the input channels in order until either a present input
109     *  is found or we run out of channels. In the former case, the first
110     *  encountered input value is produced on the output. In the latter
111     *  case, the output will be absent.
112     *  @exception IllegalActionException If there is no director, or
113     *   the input can not be read, or the output can not be sent.
114     */
115    @Override
116    public void fire() throws IllegalActionException {
117        super.fire();
118        boolean discardValue = ((BooleanToken) discard.getToken())
119                .booleanValue();
120        boolean outputProduced = false;
121        if (_pending != null && _pending.size() > 0) {
122            output.send(0, _pending.remove(0));
123            outputProduced = true;
124        }
125        for (int i = 0; i < input.getWidth(); i++) {
126            if (input.hasToken(i)) {
127                if (!outputProduced) {
128                    output.send(0, input.get(i));
129                    outputProduced = true;
130                }
131                if (discardValue) {
132                    return;
133                } else {
134                    if (_pending == null) {
135                        _pending = new LinkedList<Token>();
136                    }
137                    _pending.add(input.get(i));
138                }
139            }
140        }
141    }
142
143    /** Initialize this actor by clearing memory of any pending outputs.
144     *  @exception IllegalActionException If a derived class throws it.
145     */
146    @Override
147    public void initialize() throws IllegalActionException {
148        super.initialize();
149        if (_pending != null) {
150            _pending.clear();
151        }
152    }
153
154    /** If there are any pending outputs, then request a refiring at the
155     *  current time.
156     *  @return True if execution can continue into the next iteration.
157     *  @exception IllegalActionException Not thrown in this base class.
158     */
159    @Override
160    public boolean postfire() throws IllegalActionException {
161        if (_pending != null && _pending.size() > 0) {
162            getDirector().fireAtCurrentTime(this);
163        }
164        return super.postfire();
165    }
166
167    ///////////////////////////////////////////////////////////////////
168    ////                         private variables                 ////
169
170    /** Queue of pending output events. */
171    private List<Token> _pending;
172}