A simple Reader/FileWriter Filter in Ptolemy II

Greg Rohling asked about creating a simple filter in Ptolemy II that reads from standard input and writes to standard output.

A number of interesting issues arose from this.

Reader and FileWriter

Ptolemy II 1.0.1 includes two actors that are present as .java files in $PTII/ptolemy/actor/lib, but not viewable in vergil. These two files are $PTII/ptolemy/actor/lib/Reader.java $PTII/ptolemy/actor/lib/FileWriter.java

These actors were not included because they have the following problems:

Reader should read in expressions and serialized tokens.

FileWriter should not declare its input type to be token, but should rather let the type system resolve to the most specific type.

We need ASCII & Serialized formats, and perhaps a MATLAB format. Really, a complete redo is necessary perhaps using serialized token. In preinitialize, we could:

  1. open a file
  2. figure out the type of the token
  3. declare the output

Of course, the writer would write the type first.

To access these actors from within Vergil, edit $PTII/ptolemy/actor/lib/sources.xml and add

<entity name="Reader" class="ptolemy.actor.lib.Reader">
<doc>Read from a file</doc>
</entity>
and edit $PTII/ptolemy/actor/lib/sinks.xml and add
<entity name="FileWriter" class="ptolemy.actor.lib.FileReader">
<doc>Write to a file</doc>
</entity>
If you restart vergil, the Reader and FileWriter models should be visible in the sources and sinks palettes.

The syntax of the sourceURL parameter for the Reader actor is a little tricky.

If the sourceURL parameter is an empty string, then the System.in is used for input. It is possible to load a file from the local file system by using the prefix "file://" instead of "http://". Relative file paths are allowed. To specify a file relative to the current directory, use "../" or "./". For example, if the current directory contains a file called "test.txt", then sourceURL should be set to "file:./test.txt". If the parent directory contains a file called "test.txt", then sourceURL should be set to "file:../test.txt". To reference the file test.txt, located at "/tmp/test.txt", sourceURL should be set to "file:///tmp/test.txt" The default value is "file:///tmp/test.txt".

Unfortunately, if the URL is wrong, Reader.java prints the exception to stdout and resets it to "", which is of little help. The bogus code is:

        } catch (IOException ex) {
                System.out.println("URL not found..." + ex.getMessage());
                //throw new IllegalActionException(this, ex.getMessage());

                sourceURL.setToken(new StringToken(""));
            }
Which is no help if you start Vergil within windows from the Start menu That code should be changed to:
            } catch (IOException ex) {
                throw new IllegalActionException(this, ex.getMessage());
            }

and Reader.java should be recompiled, see $PTII/doc/install.htm for details about rebuilding.

MoMLSimpleApplication

To run a simple MoML file as an application, I created $PTII/ptolemy/actor/gui/MoMLSimpleApplication.java:

/* An application that executes non-graphical 
   models specified on the command line.

 Copyright (c) 2001 The Regents of the University of California.
 All rights reserved.
 Permission is hereby granted, without written agreement and without
 license or royalty fees, to use, copy, modify, and distribute this
 software and its documentation for any purpose, provided that the above
 copyright notice and the following two paragraphs appear in all copies
 of this software.

 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
 SUCH DAMAGE.

 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
 ENHANCEMENTS, OR MODIFICATIONS.

                                        PT_COPYRIGHT_VERSION_2
                                        COPYRIGHTENDKEY

@ProposedRating Red (cxh at eecs)
@AcceptedRating Red (eal@eecs.berkeley.edu)
*/

package ptolemy.actor.gui;

// Ptolemy imports
import ptolemy.actor.CompositeActor;
import ptolemy.actor.Manager;
import ptolemy.kernel.util.Workspace;
import ptolemy.moml.MoMLParser;

//////////////////////////////////////////////////////////////////////////
//// MoMLSimpleApplication
/** A simple application that reads in a .xml file as a command
line argument and runs it.
MoMLApplication sets the look and feel, and
ptolemy.actor.gui.Configuration.createPrimaryTableau() calls
javax.swing.SwingUtilities.invokeLater(), which starts up Swing,
so we can't use MoMLApplication for non-graphical simulations.

@author Christopher Hylands
@version $Id: MoMLSimpleApplication.java,v 1.2 2001/05/16 23:12:37 cxh Exp $
*/
public class MoMLSimpleApplication {
     ///////////////////////////////////////////////////////////////////
    ////                         public methods                    ////

    /** Create an instance of a single model and run it
     *  @param args The command-line arguments naming the .xml file to run
     */
    public static void main(String args[]) {
	try {
            MoMLParser parser = new MoMLParser();
            CompositeActor toplevel =
                (CompositeActor) parser.parseFile(args[0]);
            Manager manager = new Manager(toplevel.workspace(),
                    "MoMLSimpleApplication");
            toplevel.setManager(manager);
            manager.execute();
        } catch (Exception ex) {
            System.err.println("Command failed: " + ex);
        }
    }
}
To use MoMLSimpleApplication:
  1. Put the above text in $PTII/ptolemy/actor/gui/MoMLSimpleApplication.java
  2. Add a line for MoMLSimpleApplication.java to the makefile
  3. Run make
  4. Create a file called /tmp/doubles.txt that has one double per line:
    1.0
    2.0
    3.0
    
  5. Create a file called /tmp/ReaderWriter.xml that contains this model
    <?xml version="1.0" standalone="no"?>
    <!DOCTYPE entity PUBLIC "-//UC Berkeley//DTD MoML 1//EN"
        "http://ptolemy.eecs.berkeley.edu/xml/dtd/MoML_1.dtd">
    <entity name="ReaderWriter" class="ptolemy.actor.TypedCompositeActor">
        <property name="_vergilSize" class="ptolemy.actor.gui.SizeAttribute" value="[604, 454]">
        </property>
        <property name="_vergilLocation" class="ptolemy.actor.gui.LocationAttribute" value="[102, 100]">
        </property>
        <property name="SDF" class="ptolemy.domains.sdf.kernel.SDFDirector">
            <property name="Scheduler" class="ptolemy.domains.sdf.kernel.SDFScheduler">
            </property>
            <property name="iterations" class="ptolemy.data.expr.Parameter" value="0">
            </property>
            <property name="vectorizationFactor" class="ptolemy.data.expr.Parameter" value="1">
            </property>
            <property name="_location" class="ptolemy.moml.Location" value="38.0, 35.0">
            </property>
        </property>
        <entity name="Reader" class="ptolemy.actor.lib.Reader">
            <property name="sourceURL" class="ptolemy.data.expr.Parameter" value="&quot;&quot;">
            </property>
            <property name="refresh" class="ptolemy.data.expr.Parameter" value="false">
            </property>
            <doc>Read in doubles from either stdin or a URL</doc>
            <property name="_location" class="ptolemy.moml.Location" value="94.0, 166.0">
            </property>
            <port name="output" class="ptolemy.actor.TypedIOPort">
                <property name="output"/>
                <property name="multiport"/>
            </port>
            <port name="trigger" class="ptolemy.actor.TypedIOPort">
                <property name="input"/>
                <property name="multiport"/>
            </port>
        </entity>
        <entity name="FileWriter" class="ptolemy.actor.lib.FileWriter">
            <property name="filename" class="ptolemy.data.expr.Parameter" value="&quot;&quot;">
            </property>
            <doc>Write out tokens to a file or stdout</doc>
            <property name="_location" class="ptolemy.moml.Location" value="218.0, 140.0">
            </property>
            <port name="input" class="ptolemy.actor.TypedIOPort">
                <property name="input"/>
                <property name="multiport"/>
            </port>
        </entity>
        <relation name="relation" class="ptolemy.actor.TypedIORelation">
        </relation>
        <link port="Reader.output" relation="relation"/>
        <link port="FileWriter.input" relation="relation"/>
    </entity>
    
  6. Run the class:
    
    cat /tmp/doubles.txt | $PTII/bin/ptinvoke ptolemy/actor/gui/MoMLSimpleApplication /tmp/ReaderWriter.xml > out 
    
    Note that the above application prints some text to stderr.
BTW - You could write the simulation using Java directly instead of XML, see $PTII/ptolemy/domains/sdf/demo/Butterfly.java

We are working on something we call shallow code generation, which will generate a java file from a .xml file, but it is not yet ready to ship, see the Codegen page

Back to Ptolemy Notes