001/* A DE actor to compare the time stamps of events at its two input ports, and 002 output the difference. 003 004 Copyright (c) 2008-2015 The Regents of the University of California. 005 All rights reserved. 006 Permission is hereby granted, without written agreement and without 007 license or royalty fees, to use, copy, modify, and distribute this 008 software and its documentation for any purpose, provided that the above 009 copyright notice and the following two paragraphs appear in all copies 010 of this software. 011 012 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 013 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 014 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 015 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 016 SUCH DAMAGE. 017 018 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 019 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 020 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 021 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 022 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 023 ENHANCEMENTS, OR MODIFICATIONS. 024 025 PT_COPYRIGHT_VERSION_2 026 COPYRIGHTENDKEY 027 028 */ 029package ptolemy.domains.de.lib; 030 031import java.util.Iterator; 032import java.util.LinkedList; 033import java.util.List; 034 035import ptolemy.actor.TypedIOPort; 036import ptolemy.data.BooleanToken; 037import ptolemy.data.DoubleToken; 038import ptolemy.data.expr.Parameter; 039import ptolemy.data.type.BaseType; 040import ptolemy.domains.de.kernel.DEActor; 041import ptolemy.domains.de.kernel.DEDirector; 042import ptolemy.kernel.CompositeEntity; 043import ptolemy.kernel.util.IllegalActionException; 044import ptolemy.kernel.util.NameDuplicationException; 045import ptolemy.kernel.util.Workspace; 046 047////////////////////////////////////////////////////////////////////////// 048//// TimeCompare 049 050/** 051 A DE actor to compare the time stamps of events at its two input ports, and 052 output the difference. Every time an event can be processed either at input 053 port <code>input1</code> or at <code>input2</code>, the event is consumed. The 054 value that the event carries is insignificant, but the time stamp of the event 055 is recorded in a local list. Time stamps received at the two input ports are 056 stored in two different lists. Every time when both lists have data, the 057 difference between the top elements of the lists is obtained, and is sent to 058 the output port. This done by subtracting the time stamp of every top event in 059 the list for <code>input2</code> with the time stamp of every top event in the 060 list for <code>input1</code>. 061 <p> 062 This actor could potentially consume an infinite amount of memory if the 063 arrival rates of events at the two input ports are different, because one of 064 the lists keeps growing. 065 066 @author Thomas Huining Feng 067 @version $Id$ 068 @since Ptolemy II 8.0 069 @Pt.ProposedRating Red (tfeng) 070 @Pt.AcceptedRating Red (tfeng) 071 */ 072public class TimeCompare extends DEActor { 073 074 /** Construct an actor with the specified container and name. 075 * This is protected because there is no reason to create an instance 076 * of this class, but derived classes will want to invoke the 077 * constructor of the superclass. 078 * @param container The container. 079 * @param name The name. 080 * @exception IllegalActionException If the entity cannot be contained 081 * by the proposed container. 082 * @exception NameDuplicationException If the container already has an 083 * actor with this name. 084 */ 085 public TimeCompare(CompositeEntity container, String name) 086 throws NameDuplicationException, IllegalActionException { 087 super(container, name); 088 089 nonnegative = new Parameter(this, "nonnegative"); 090 nonnegative.setTypeEquals(BaseType.BOOLEAN); 091 nonnegative.setToken(BooleanToken.FALSE); 092 093 input1 = new TypedIOPort(this, "input1", true, false); 094 input2 = new TypedIOPort(this, "input2", true, false); 095 output = new TypedIOPort(this, "output", false, true); 096 output.setTypeEquals(BaseType.DOUBLE); 097 } 098 099 /** Clone this actor into the specified workspace. The new actor is 100 * <i>not</i> added to the directory of that workspace (you must do this 101 * yourself if you want it there). 102 * The result is a new actor with the same ports as the original, but 103 * no connections and no container. A container must be set before 104 * much can be done with this actor. 105 * 106 * @param workspace The workspace for the cloned object. 107 * @exception CloneNotSupportedException If cloned ports cannot have 108 * as their container the cloned entity (this should not occur), or 109 * if one of the attributes cannot be cloned. 110 * @return A new ComponentEntity. 111 */ 112 @Override 113 public Object clone(Workspace workspace) throws CloneNotSupportedException { 114 TimeCompare newObject = (TimeCompare) super.clone(workspace); 115 newObject._input1TimeStamps = new LinkedList<Double>(); 116 newObject._input2TimeStamps = new LinkedList<Double>(); 117 return newObject; 118 } 119 120 /** Fire this actor once. If there are events at its input ports, they are 121 * immediately consumed, and their time stamps are recorded in a list. If 122 * the two internal lists for the two input signals both have data, then 123 * outputs are sent to the output port, which are the difference between 124 * the time stamps in the two lists. 125 * 126 * @exception IllegalActionException If thrown when trying to consume input 127 * events or produce output events. 128 */ 129 @Override 130 public void fire() throws IllegalActionException { 131 super.fire(); 132 133 Double currentTime = ((DEDirector) getDirector()).getModelTime() 134 .getDoubleValue(); 135 136 while (input1.hasNewToken(0)) { 137 input1.get(0); 138 _input1TimeStamps.add(currentTime); 139 } 140 141 while (input2.hasNewToken(0)) { 142 input2.get(0); 143 _input2TimeStamps.add(currentTime); 144 } 145 146 boolean nonnegative = ((BooleanToken) this.nonnegative.getToken()) 147 .booleanValue(); 148 Iterator<Double> input1Iterator = _input1TimeStamps.iterator(); 149 Iterator<Double> input2Iterator = _input2TimeStamps.iterator(); 150 while (input1Iterator.hasNext() && input2Iterator.hasNext()) { 151 double input1 = input1Iterator.next(); 152 double input2 = input2Iterator.next(); 153 input2Iterator.remove(); 154 double difference = input2 - input1; 155 156 if (nonnegative) { 157 while (difference < 0.0 && input2Iterator.hasNext()) { 158 input2 = input2Iterator.next(); 159 input2Iterator.remove(); 160 difference = input2 - input1; 161 } 162 if (difference >= 0.0) { 163 input1Iterator.remove(); 164 output.send(0, new DoubleToken(difference)); 165 } 166 } else { 167 input1Iterator.remove(); 168 output.send(0, new DoubleToken(difference)); 169 } 170 } 171 } 172 173 /** Initialize this actor. 174 * 175 * @exception IllegalActionException Never thrown. 176 */ 177 @Override 178 public void initialize() throws IllegalActionException { 179 super.initialize(); 180 _input1TimeStamps.clear(); 181 _input2TimeStamps.clear(); 182 } 183 184 /** Return ture if this actor can fire. This actor can fire if prefire() of 185 * the superclass returns true, and either of the two input ports, or both, 186 * have token. 187 * 188 * @return true if this actor can fire. 189 * @exception IllegalActionException If thrown when trying to decide 190 * whether the input ports have token or not. 191 */ 192 @Override 193 public boolean prefire() throws IllegalActionException { 194 return super.prefire() && (input1.hasToken(0) || input2.hasToken(0)); 195 } 196 197 /** The first input port. */ 198 public TypedIOPort input1; 199 200 /** The second input port. */ 201 public TypedIOPort input2; 202 203 /** A boolean parameter to decide whether inputs at input2 should be ignored 204 if they lead to negative outputs. */ 205 public Parameter nonnegative; 206 207 /** The output port to which difference values are sent. */ 208 public TypedIOPort output; 209 210 /** The list to store the time stamps received at input1 but have never been 211 compared. */ 212 private List<Double> _input1TimeStamps = new LinkedList<Double>(); 213 214 /** The list to store the time stamps received at input2 but have never been 215 compared. */ 216 private List<Double> _input2TimeStamps = new LinkedList<Double>(); 217}