ParselTongue Tutorial

Mark Kettenis

JIVE

Table of Contents

1. Starting an interactive ParselTongue session
2. Running AIPS tasks
3. Array Indexing
4. Accessing AIPS data
Headers
Tables
Convenience functions
Cleaning up
5. Scripts
6. Wizardry

Chapter 1. Starting an interactive ParselTongue session

For this tutorial we will use an interactive ParselTongue session:

$ ParselTongue
Python 2.3.4 (#1, Oct  5 2004, 00:17:14) 
[GCC 3.3.4 (pre 3.3.5 20040809)] on linux2
Type "help", "copyright", "credits" or "license" for more information.

Welcome to ParselTongue
Please enter your AIPS user ID number: 3601
>>>

Chapter 2. Running AIPS tasks

Use the AIPSTask class to run AIPS tasks:

  1. Create an instance for the task you want to run

    >>> fitld = AIPSTask('fitld')
    

  2. Set attributes (adverbs)

    >>> fitld.infile = '/tmp/4C39.25.FITS'
    >>> fitld.clint = 0.33
    

  3. Go!

    >>> fitld.go()
    ...
    

Attributes are not shared between instances:

>>> fitld2 = AIPSTask('fitld')
>>> print fitld.clint
0.33
>>> print fitld2.clint
0.0

AIPS Tasks can return attributes:

>>> imean = AIPSTask('imean')
>>> imean.inname = '4C39.25'
>>> imean.inclass = 'ICL001'
>>> imean.indisk = 1
>>> imean.go()
...
>>> print imean.pixavg, imean.pixstd
0.00019473816792 0.00434004655108

Output is logged to AIPS.log if you set it to a file-like object:

>>> AIPS.log = open('/tmp/pt.log', 'a')
>>> imean.go()
...
>>> for line in open('/tmp/pt.log'): print line,
...

The verbosity of the output is controlled by AIPSTask.msgkill:

  • > 0 - Reduce output on both screen and log

  • < 0 - Reduce output only on screen

>>> imean.msgkill = 2
>>> imean.go()
...

Chapter 3. Array Indexing

There are different array indexing conventions around:

  • AIPS uses 1-based array indexing (like FORTRAN)

  • Python uses 0-based array indexing (like everyone else)

Unfortunately 0-based indexing is very confusing for things like APARM. Therefore ParselTongue arrays used for task attributes are a bit special and have element 0 hardwired to None.

>>> imean.trc = AIPSList([256, 256])
>>> imean.trc[1:] = [256, 256]
>>> print imean.trc
[None, 256.0, 256.0, 0.0, 0.0, 0.0, 0.0, 0.0]

>>> imean.trc[0] = 1
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "/export/jive/kettenis/opt/ParselTongue/share/parseltongue/python/Task.py", line 131, in __setitem__
    raise ValueError, msg
ValueError: setting element '0' is prohibited

>>> print PythonList(imean.trc)
[256.0, 256.0, 0.0, 0.0, 0.0, 0.0, 0.0]

Chapter 4. Accessing AIPS data

Use the AIPSUVData and AIPSImage classes to access the metadata associated with AIPS UV data and images:

  1. Create an instance for the data set you want to access:

    >>> uvdata = AIPSUVData('N03L1', 'UVDATA', 1, 1)
    >>> image = AIPSImage('4C39.25', 'ICL001', 1, 1)
    

Note that we refer to data sets by their name, class, disk and sequence number and not by its catalog number.

It is easy to check whether the data set actually exists in the AIPS catalog:

>>> uvdata.exists()
False
>>> image.exists()
True

These ParselTongue data can be used conveniently when running AIPS tasks:

>>> fitld = AIPSTask('fitld')
>>> fitld.infile = '/tmp/N03L1.IDI'
>>> fitld.clint = 0.33
>>> fitld.outdata = uvdata
>>> fitld.go()
...
>>> uvdata.exists()
True

Headers

You can access the header through the header attribute:

>>> uvdata.header
...
>>> uvdata.header.telescop
'EVN     '
>>> image.header
...
>>> image.header.date_obs
'2005-03-01'

Keywords are the same as for the AIPS GETHEAD verb, but lower case with '-' replaced by '_'.

Tables

What tables do we have?

>>> uvdata.tables
[[1, 'AIPS HI'], [1, 'AIPS AT'], [1, 'AIPS NX'], [1, 'AIPS CL'], [1, 'AIPS FQ'], [1, 'AIPS AN'], [1, 'AIPS SU']]

These tables can be opened for further analysis:

>>> sutable = uvdata.table('SU', 1)
>>> for row in sutable:
...     print row.source, row.raapp, row.decapp
...
3C84             49.9489485008 41.513581044
DA193            88.8813073705 39.8151637728

It is also possible to access individual rows directly:

>>> cltable = uvdata.table('CL', 1)
>>> print cltable[0]
...

Convenience functions

ParselTongue includes some convenience functions that

>>> uvdata.antennas
['MC', 'WB', 'NT', 'JB']
>>> uvdata.sources
['3C84', 'DA193']
>>> uvdata.polarizations
['R', 'L']
>>> uvdata.stokes
['RR', 'LL', 'RL', 'LR']
>>> image.stokes
['I']

Cleaning up

Finally when you're done you should clean up. The following command removes the entire data set:

>>> image.zap()
>>> image.exists()
False

It is also possible to remove individual tables:

>>> uvdata.tables
[[1, 'AIPS HI'], [1, 'AIPS AT'], [1, 'AIPS NX'], [1, 'AIPS CL'], [1, 'AIPS FQ'], [1, 'AIPS AN'], [1, 'AIPS SU']]
>>> uvdata.table('NX', 1).zap()
>>> uvdata.tables
[[1, 'AIPS HI'], [1, 'AIPS AT'], [1, 'AIPS CL'], [1, 'AIPS FQ'], [1, 'AIPS AN'], [1, 'AIPS SU']]

There is an alternative way for zapping tables that might come handy if you want to zap all tables of a particular type:

>>> uvdata.tables
>>> uvdata.zap_table('AT', -1)
>>> uvdata.tables
[[1, 'AIPS HI'], [1, 'AIPS CL'], [1, 'AIPS FQ'], [1, 'AIPS AN'], [1, 'AIPS SU']]

Chapter 5. Scripts

In order to use ParselTongue from scripts you'll need to import the appropriate ParselTongue modules and set your AIPS user number. For the examples we have seen before, something like the following will suffice:

from AIPS import AIPS
from AIPSTask import AIPSTask, AIPSList
from AIPSData import AIPSUVData, AIPSImage

AIPS.userno = 3601

Starting ParselTongue scripts is easiest done by using the ParselTongue command:

$ ParselTongue script.py

This will start Python with all the magic environment variables set.

Chapter 6. Wizardry

For Hogwarts graduates it is even possible to create new extension tables. The following bit of code creates a new CL table with a different amplitude calibration:

from AIPS import AIPS
from Wizardry.AIPSData import AIPSUVData

AIPS.userno = 3601

data = AIPSUVData('N03L1', 'UVDATA', 1, 1)
oldcl = data.table('CL', 1)

newcl = data.attach_table('CL', 2, no_term=oldcl.keywords['NO_TERM'])
newcl.keywords['NO_ANT'] = oldcl.keywords['NO_ANT']

for row in oldcl:
    row.real1 = [2 * x for x in row.real1]
    row.real2 = [2 * x for x in row.real2]
    newcl.append(row)

newcl.close()
oldcl.close()

Wizardry.AIPSUVData is very similar to the normal AIPSUVData but is in a different module because it doesn't support remote executaion like AIPSUVData does. Remote execution will be adressed later in this workshop.

It is also possible to change an existing table (although that is not very AIPS-ish):

from Wizardry.AIPSData import AIPSUVData
from AIPS import AIPS

AIPS.userno = 3602

data = AIPSUVData('N03L1', 'UVDATA', 1, 1)
table = data.table('CL', 1)

for row in table:
    row.real1 = [2 * x for x in row.real1]
    row.real2 = [2 * x for x in row.real2]
    row.update()

table.close()

It's also possible to get at the actual visibilities in a UV data set. Here is a little script that uses matplotlib to make a UV coverage plot:

from Wizardry.AIPSData import AIPSUVData
from AIPS import AIPS

from pylab import plot, show

AIPS.userno = 3601

data = AIPSUVData('MULTI', 'UVDATA', 1, 3)
u = []
v = []
for visibility in data:
    u.append(visibility.uvw[0])
    v.append(visibility.uvw[1])

plot(u, v, '.')
show()

And here is a script that makes a plot of the phase for a single channel on a randomly chosen baseline:

from Wizardry.AIPSData import AIPSUVData
from AIPS import AIPS

from pylab import plot, show
from math import atan2

AIPS.userno = 3601

data = AIPSUVData('MULTI', 'UVDATA', 1, 3)
phase = []
time = []
for visibility in data:
    if visibility.baseline == [1, 2]:
        re = visibility.visibility[0, 0, 0, 0]
        im = visibility.visibility[0, 0, 0, 1]
        phase.append(atan2(re, im))
        time.append(visibility.time)

plot(time, phase, '.')
show()