Using Gildas/Class from Python

As many people have been asking me on how to use Gildas/Class from within Python, I’ll try to give a quick tour here. You will need to have Class installed including the Pyclass extension.

Before you start the Python script you need to initialize Gildas in the shell. Make also sure it is in your $PYTHONPATH. On my local PC using a bash shell where Gildas is installed in $GILDAS_DIR that is

source $GILDAS_DIR/initgag.sh
export PYTHONPATH=$PYTHONPATH:$GILDAS_DIR/gildas-exe-mar18b/x86_64-ubuntu14.04-gfortran/python/

The example above is for the version of Class tested in March 2018 – you might need to change the path for your installed version accordingly. Check if Class is running as usual and that indeed you find the Gildas-path in your $PYTHONPATH.

Then you can execute the Python script or go into iPython. Here is a minimal example:

import pygildas, pyclass
 
# if you want your program to catch PygildasErrors:
from pgutils import PygildasError
 
# you are good to go from here, but to access stuff easier, I prefer
# to assign the two most commonly used objects to individual 
# variables for easy access
 
# get the gildas command line interpreter to issue commands quickly
sic = pyclass.comm
 
# get the pyclass.gdict object for easy Gildas variable access
g = pyclass.gdict
 
# just execute commands as you would within Class
# you just do not have the display - use matplotlib ;)
sic('SIC MESSAGE GLOBAL ON') # or OFF for less noise
 
sic('file in "myData.apex"')
# ...

To access Gildas variables we use the pyclass.gdict (the object we assigned to g). Unfortunately it is a bit inconvenient to use, as it does not support auto-completion or directly shows us the available Gildas variables in a pythonic way. But we can simply extend it’s functionality to do so. (I’ve submitted a feature suggestion to IRAM, so maybe it will be included in one of the next releases) – This has been included in PyClass with the May 2018 release and is only needed for older installations.

But let’s see how to acess Gildas variables now:

# enhance the Gildas dict to allow auto-completion
# no longer needed after May 2018 release of PyClass
setattr(g.__class__, '__dir__', lambda _: pygildas.dict.keys())
# now you can use auto-ompletion in iPython:
# > g.<TAB> # will let you auto-complete all variables in iPython
 
# get a list of all variables
dir(g)
 
# read variables
x = g.rx # access x-axis array
y = g.ry # access y-axis array
sigma = g.sigma
 
# set variable
g.myvar = 'test'
# you can check that it was set with sic('exa myvar')
# WARNING: the length/type of a variable will not change 
# when you set it the second time! First delete then set again.
 
# delete variable
delattr(g, 'myvar')
# sic('exa myvar') raises an error, as myvar is no longer defined
 
# access the current index (after file in "..."; find...)
# gives information you find through sic('list') usually
g.idx.sourc
g.idx.line
g.idx.teles
# ...

You are ready to go from here.Take x and y and do whatever you like with your data in Python or use matplotlib to display the data. Below some commands that I use and should help getting you started.

# if you want to acces RA-DEC you need to assign them
# as the Gildas variable lambda is not accessible through
# Python, as it is a Pyghon built-in
sic('define double ra')
sic('define double dec')
sic('let ra lambda') # [rad]
sic('let dec beta') # [rad]
ra = g.ra / np.pi * 12 # [hours]
dec = g.dec / np.pi * 180 # [deg]
 
# if you want to catch a Gildas/Class error
try:
    sic('a command that does not work')
except PygildasError, e:
    print(e)
 
# and here just some examples what was in my script
# including some stuff using input from Python
filename = 'test.apex'
obs_line = 'CO3_2'
 
sic('file in "%s"' % filename)
sic('find /line %s' % obs_line)
if g.found == 0:
    raise RuntimeError('No data found!')
 
sic('get first')
sic('set unit v')
sic('stitch /nocheck')
 
sic('modify velocity %.1f' % source_velocity
frequencies = {'C18O(2-1)': 219560.35410, # [MHz]
               '13CO(2-1)': 220398.68420, # [MHz]
               'CO(2-1)': 230538.00000, # [MHz]
               'CO(3-2)': 345795.98990, # [MHz]
               'CO(4-3)': 461040.76820, # [MHz]
               '[CI](3P1-3P2)': 492160.65} # [MHz]
sic('modify frequency %f' % frequencies[line])
sic('set mode x %i %i' % (-200, 200))
 
# accessing the table of contents (toc)
# for instance list all sources available
sic('list /toc source')
if hasattr(g.toc, 'sour'):
    for source_name in g.toc.sour:
        print(source_name)
 
# or list all lines available
sic('list /toc line')
if hasattr(g.toc, 'line'):
    for line in g.toc.line:
        print(line)

I hope that helps.

Cheers,
  Carsten

PS: This is not meant to be a complete guide to all you ever wanted to know about pyGildas/Class. I’m also no guru on Class. So i can not answer general questions on how to do stuff in class or python.

If you have specific comments/suggestions on how to enhance this mini-guide, let me know – either in the comments or by email (ck[at]carsten-koenig[dot]de). Feedback is much appreciated.