<aside> <img src="/icons/reorder_gray.svg" alt="/icons/reorder_gray.svg" width="40px" />

Menu

</aside>

Overview

Logistics

Program

Reaching the venue

Before the workshop

After the workshop

Hands-on tutorials

Tutorial 1: Visualization with CARTA

Tutorial 2: Continuum Imaging

Tutorial 3: Line Imaging

Tutorial 4: Self-Calibration

Tutorial 5: ALMA Archive

Lectures

Lecture 1: ALMA Overview

Lecture 2: Basics of Interferometry and Imaging

Lecture 3: Introduction to CASA

Lecture 4: Introduction to Calibration and Self-Calibration

Lecture 5: Science Ready Data Products and Weblog

Lecture 6: NRAO/NAASC services

<aside>

Download tutorial2_script_continuum_imaging.py

This script was written for CASA 6.6.6 (ALMA pipeline version)
Source: First Look at Imaging (CASA Guide)
<https://casaguides.nrao.edu/index.php/First_Look_at_Imaging_CASA_6.6.1>
Adapted for ALMA Data Reduction Workshop at Universidad de Chile 
Pietro Curone ([email protected]) 29 October 2025

</aside>

Dataset

TW Hya calibrated continuum measurement set (435 MB, already contained in the twhya_firstlook.tar you can download from the Before the workshop page)

twhya_calibrated.ms.tar (Download)

Your working directory should look like:

Tutorial2_continuum_imaging >> ls
tutorial2_script_continuum_imaging.py
twhya_calibrated.ms.tar

Untar with:

# In bash
tar -xvzf twhya_calibrated.ms.tar
Tutorial2_continuum_imaging >> ls
tutorial2_script_continuum_imaging.py
twhya_calibrated.ms
twhya_calibrated.ms.tar

Open CASA

Open a CASA terminal

Tutorial2_continuum_imaging >> casa

A Python prompt will appear like this:

CASA <1>:

CASA is running on a python interpreter, so python syntax is valid here.

A complete description of CASA and all its tasks is available in the documentation.

Import useful libraries

# In CASA
import os
import numpy as np

Getting information on the dataset

listobs(vis='twhya_calibrated.ms',
        listfile='twhya_calibrated.ms.txt',
        overwrite=True)

Important sections: Scans, Fields, and Spectral Windows

Inspecting the data

plotms(vis='twhya_calibrated.ms',
       xaxis='u',
       yaxis='v',
       avgchannel='10000',
       avgspw=False,
       avgtime='1e9',
       avgscan=False,
       coloraxis='field',
       showgui=True)

Save resulting plot as png file directly:

plotms(vis='twhya_calibrated.ms',
       xaxis='u',
       yaxis='v',
       avgchannel='10000',
       avgspw=False,
       avgtime='1e9',
       avgscan=False,
       coloraxis='field',
       showgui=False,
       plotfile='twhya_calibrated_uvcoverage.png')

Let’s plot the uv-coverage of the science target only

plotms(vis='twhya_calibrated.ms',
       xaxis='u',
       yaxis='v',
       field='TW Hya',
       avgchannel='10000',
       avgspw=False,
       avgtime='1e9',
       avgscan=False,
       showgui=False,
       plotfile='twhya_calibrated_uvcoverage_science_target.png')

twhya_calibrated_uvcoverage_science_target.png

Given our averaging, each pair of points represent a single baseline, per spw (we have only one), per scan.

Try setting avgscan=True

Check the Amplitude vs Baseline (= uv-distance) plot:

plotms(vis='twhya_calibrated.ms',
       xaxis='UVdist',
       yaxis='Amp',
       avgchannel='10000',
       avgspw=False,
       avgtime='1e9',
       avgscan=False,
       field='TW Hya',  
       showgui=False,
       plotfile='twhya_calibrated_amp-v-uvdist_science_target.png')

twhya_calibrated_amp-v-uvdist_science_target.png

Split out the science target and average in frequency and time

First, in case you've run this task before, let's remove old versions of the dataset that use the same name (CASA tends to not overwrite and to raise a SEVERE error instead).

os.system('rm -rf twhya_science_target_avg.ms')

We average in frequency (8 channels) and time (30s) as we are really only interested in continuum imaging at this point. This reduces the data volume without losing much information.

split(vis='twhya_calibrated.ms', # Old measurement set (435 MB)
      outputvis='twhya_science_target_avg.ms',  # New measurement set (13 MB)
      datacolumn='data',
      field='TW Hya',  
      width='8',
      timebin='30s')

Inspect the new MS:

listobs(vis='twhya_science_target_avg.ms',
        listfile='twhya_science_target_avg.ms.txt',
        overwrite=True)

Image the science target

Dirty Image

Let’s estimate the proper cell size and image size:

imagename = 'twhya_cont_dirtyimage'

os.system(f'rm -rf {imagename}.*') # Remove old versions in case you've run this before

tclean(vis='twhya_science_target_avg.ms',
       imagename=imagename,
       specmode='mfs',
       gridder='standard',
       deconvolver='hogbom',
       cell=['0.1arcsec'],
       imsize=250,
       weighting='briggs',
       robust=0.5,
       niter=0,    # Dirty image
       interactive=False)

Screenshot 2025-10-28 at 19.10.10.png

The beam size is 0.56’’ x 0.42’’, so our calculation was correct!

CLEAN image

Let’s define a circular mask around the source. The center of the source can be established by eye or, more precisely, with a 2D Gaussian fit in CARTA.

Set the mask major axis in CARTA using the ruler.

mask_ra  = '11h01m51.837s'
mask_dec = '-34.42.17.216'
mask_pa  = 0  # mask position angle in degrees (here 0 as we want a circular mask)
mask_inc = 0   # mask inclination in degrees

mask_maj = 1.3  # semimajor axis of mask in arcsec
mask_min = mask_maj*np.cos(mask_inc * np.pi/180) #semiminor axis of mask in arcsec 

mask = f'ellipse[[{mask_ra}, {mask_dec}], [{mask_maj}arcsec, {mask_min}arcsec], {mask_pa}deg]'
imagename = 'twhya_cont_CLEANimage'

os.system(f'rm -rf {imagename}.*') # Remove old versions in case you've run this before

tclean(vis='twhya_science_target_avg.ms',
       imagename=imagename,
       specmode='mfs',
       gridder='standard',
       deconvolver='hogbom',
       cell=['0.1arcsec'],
       imsize=250,
       weighting='briggs',
       robust=0.5,
       mask=mask,    # Use the mask we just defined
       niter=1000000,    # Just choose a high number
       nsigma=3,    # CLEAN down to a threshold of 3 times the rms noise
       fastnoise=False,     # Better noise calculation
       interactive=False)

Screenshot 2025-10-28 at 19.10.13.png

To export to a fits file

exportfits(imagename = f'{imagename}.image',
           fitsimage = f'{imagename}.fits')

Perform primary beam correction

os.system(f'rm -rf {imagename}.pbcor.image')

Perform primary beam correction and generate primary beam corrected image:

impbcor(imagename=f'{imagename}.image',
        pbimage=f'{imagename}.pb',
        outfile=f'{imagename}.pbcor.image')

Screenshot 2025-10-28 at 19.14.15.png

Alternatives