High-Level Access to MIRIAD Data: miriad

On the commandline, you refer to datasets by their filenames. The miriad module provides two fundamental classes, VisData and ImData, which analogously let you refer to datasets in a Python program. Instances of these class are lightweight and provide features to make it easy to perform common operations on your data.

To instantiate one of these classes, just call the constructor with a filename as an argument:

from miriad import VisData, ImData
vis = VisData ('./fx64c-3c147-1400')
im = ImData ('./residual.rm')

It’s important to understand that these objects are references to datasets, and as such the underlying file doesn’t have to exist when you create the object. Also, creating one of these objects is a very cheap operation.

Both miriad.VisData and miriad.ImData are subclasses of a more generic class, miriad.Data. Instances of this class have methods and properties that provide common functionality regarding MIRIAD datasets. One set of functionality is checking basic properties of the dataset on disk:

  • Data.exists to see if it exists on disk.
  • Data.mtime to check when it was last modified. This requires that the dataset exists; the variant attribute umtime returns unconditionally. (Hence the “u” prefix to its name.)
  • Data.realPath() to get its canonical filename.

You can also perform some basic operations. (From here on out, we will drop the ‘’Data’’ prefix in the names we show. Also, note that you can click on the link associated with all of these function or property names to access the more detailed reference documentation for that item.)

You can create more Data instances with filenames similar to existing ones:

  • vvis() creates a new VisData instance referencing a similar filename.
  • vim() creates a new ImData instance referencing a similar filename.

And you can open the dataset with open() to get access to its contents. See Low-Level Access to MIRIAD Data for more information.

You may also wish to enable tracing of MIRIAD task execution in miriad-python by calling basicTrace(). There are a few more rarely-used members of Data not mentioned here that are documented in the API reference below.

Visibility Datasets

The VisData subclass of Data has additional routines specifically useful for UV data:

  • catTo() runs uvcat on a dataset to produce a copy of it.
  • averTo() runs uvaver on a dataset to produce an averaged copy of it.
  • lwcpTo() creates a “lightweight copy” of a dataset, duplicating its metadata but not the visibilities, which makes certain common operations much faster.
  • readLowlevel() opens the dataset directly for lowlevel access to the visibility data.

Besides these routines, the VisData subclass implements several generic methods specified in Data, so you should always create a VisData instance when you know that you’re referring to a visibility dataset.

Image Datasets

The ImData subclass of Data is used for referencing image data. It currently does not have any routines specifically applicable to image data, but it implements several of the Data methods correctly, so you should always create a ImData instance when you know that you’re referring to an image dataset.

miriad API Reference

This section presents a detailed API reference for the miriad module.

Dataset Classes

class miriad.Data(basedata)
Synopsis :Generic reference to a MIRIAD dataset.
Parameters:basedata (anything upon which str() can be called) – The filename of the underyling dataset.

The constructor returns a new instance that references a dataset with the filename str(basedata). However, you should create VisData and ImData instances rather than generic Data instances whenever possible, to take advantage of the more-specialized functionality they offer.

The stringification of a Data instance returns the filename of the underlying dataset.

Data implements equality testing and hashing. One dataset is equal to another if and only if both are instances of Data or any of its subclasses and the os.path.realpath() of the filenames underlying both datasets are equal.

apply(task, **params)

Configure a task to run on this dataset.

Parameters:
  • task (TaskBase) – the task to set up
  • params – extra task parameters
Return type:

TaskBase

Returns:

task

Set the appropriate input option (‘vis’ or ‘in’) of the mirexec.TaskBase task to self. Also apply any keywords in params to task via mirexec.TaskBase.applyParams(). Returns task for easy chaining:

import miriad
from mirtask import TaskUVFlag
v = miriad.VisData ('dataset')
v.apply (TaskUVFlag (), flagval='f', select='ant(1)').run ()

# The above example could also be written:

TaskUVFlag (vis=v, flagval='f', select='ant(1)').run ()

This function isn’t implemented in the generic Data class. The subclasses VisData and ImData override it to set the appropriate task input keyword.

checkExists()
Return type:None

Check if the Data exists on disk. If so, do nothing and return. If not, raise an Exception.

copyTo(dest)

Copy the dataset to a new location.

Parameters:dest (str, or anything upon which str() can be called.) – the filename of the copy of the dataset
Return type:Data
Returns:self

Copies this dataset to a new location on disk. The dataset must exist. Approximately equivalent to the shell command cp -r {self} {dest}. trace() is called with a “[copy]” operation.

FIXME: Doesn’t clean up correctly if an error occurs midway through the copy.

classmethod defaultImClass(klass, iclass)

Set the class used by vim().

Arg :iclass: the class to be used by vim()
Raises ValueError:
 if iclass is not a subclass of ImData

Sets the class instantiated by all calls to vim(). This method is a class method, and so sets the value used by all instances of Data. This can be useful if you have a customized subclass of ImData that you want to use throughout a program:

class MyIm (ImData):
  def myfunc (self):
    # Perform some useful function ...

Data.defaultImClass (MyIm)

im = MyIm ('foo')
im2 = im.vim ('avg')
# im2 is an instance of MyIm, too

iclass must be a subclass of ImData.

classmethod defaultVisClass(klass, vclass)

Set the class used by vvis().

Parameters:vclass (any subclass of VisData) – the class to be used by vvis()
Raises ValueError:
 if vclass is not a subclass of VisData

Sets the class instantiated by all calls to vvis(). This method is a class method, and so sets the value used by all instances of Data. This can be useful if you have a customized subclass of VisData that you want to use throughout a program:

class MyVis (VisData):
  def myfunc (self):
    # Perform some useful function ...

Data.defaultVisClass (MyVis)

v = MyVis ('foo')
v2 = v.vvis ('avg')
# v2 is an instance of MyVis, too

vclass must be a subclass of VisData.

delete()

Delete the dataset.

Return type:Data
Returns:self

Deletes the dataset from disk. If the dataset doesn’t exist, silently does nothing. Approximately equivalent to the shell command rm -r {self}. If deletion occurs, trace() is called with a “[delete]” operation. If the dataset path corresponds to a symbolic link, only the link is deleted.

exists

Read-only bool. True if the dataset specified by this class actually exists. (If False, the dataset corresponding to this object can be created by the execution of a command.)

makeVariant(name, kind=None)

Create another Data instance with a similar name.

Parameters:
  • name (str) – the extension to to append to the original dataset’s name
  • kind (callable, returning Data; if None, use Data) – the factory method to create the new dataset
Return type:

Data

Returns:

a new dataset.

Creates a new dataset with an underlying filename of self.name. For example:

v = VisData ('orig')
d = v.makeVariant ('avg')
v.averTo (d, 10)
# Executes: uvaver vis=orig out=orig.avg interval=10

The argument kind specifies the factory function used to create the instance. A class name or a custom function taking one string argument are appropriate.

For the common case, the more tersely-named functions vvis() and vim() will create new VisData and ImData variants, respectively.

moveTo(dest)

Move the dataset to a new location.

Parameters:dest (str, or anything upon which str() can be called.) – the new filename for the dataset
Return type:Data
Returns:self

Renames this dataset to a new location on disk. The dataset must exist. Uses os.rename(), so renaming a dataset across devices will not work, but the rename is atomic. trace() is called with a “[rename]” operation.

mtime

Read-only int. The modification time of the history item of this dataset. Raises OSError if the dataset does not exist. Useful for checking whether a dataset needs to be regenerated, in conjunction with the umtime attribute:

def maybeCat (src, dest, **params):
  # If dest doesn't exist or src has been modified more
  # recently than src, perform a uvcat.
  if dest.umtime < src.mtime:
     dest.delete ()
     src.catTo (dest, **params)
open(mode)

Opens the dataset for access.

Parameters:mode (str) – The mode to open the dataset in. Use ‘rw’ to open the dataset in read-write mode, ‘c’ to create the dataset, and ‘a’ to append to an existing dataset. Generic Data instances support ‘rw’ and ‘c’. Instances of VisData support ‘rw’, ‘c’, and ‘a’.
Return type:mirtask.DataSet or subclass
Returns:An opened dataset

This implementation opens the dataset in a generic way. To be able to access visibility or image data through the usual functions, make sure to call this function on an instance of the VisData or ImData classes, which override the implementation to open the dataset in the correct manner for their corresponding data types.

path(*args)
Return type:str
Returns:A path composed of user-defined items relative to this dataset’s path.

Construct a path relative to this dataset’s path.

realPath()
Return type:str
Returns:The real path (as defined by os.path.realpath()) to this dataset.

Get the “real path” (defined by os.path.realpath()) to this dataset.

umtime

Read-only int. The “unconditional” modification time of this dataset – equivalent to mtime, but zero is returned if the dataset does not exist. See the example in mtime for potential uses.

vim(name)

Create an ImData variant of this dataset.

Parameters:name (str) – the extension to append to the dataset’s name
Return type:ImData
Returns:a new dataset object

Returns self.makeVariant (name, klass) where klass is, by default, ImData. The value of klass can be overridden by calling defaultImClass().

vvis(name)

Create a VisData variant of this dataset.

Parameters:name (str) – the extension to append to the dataset’s name
Return type:VisData
Returns:a new dataset object

Returns self.makeVariant (name, klass) where klass is, by default, VisData. The value of klass can be overridden by calling defaultVisClass().

class miriad.VisData(basedata)
Synopsis :Reference to a MIRIAD visibility dataset.

This subclass of Data is for referring to visibility datasets. It has special functions handy for use with visibility data and inherits many generic features from the Data class.

averTo(dest, interval, **params)

uvaver this dataset to dest.

Parameters:
  • dest (Data, str, or any other stringable) – the destination dataset
  • interval (numeric) – the averaging interval, in minutes
  • params – extra parameters to pass to the uvaver command
Return type:

None

Invokes the task uvaver via mirexec.TaskUVAver. Checks if the source dataset exists but does no checking on the destination dataset. Approximately equivalent to the shell command uvaver vis={self} out={dest} interval={interval} {params...}.

catTo(dest, **params)

uvcat this dataset to dest.

Parameters:
  • dest (Data, str, or any other stringable) – the destination dataset
  • params – extra parameters to pass to the uvcat command
Return type:

None

Invokes the task uvcat via mirexec.TaskUVCat. Checks if the source dataset exists but does no checking on the destination dataset. Approximately equivalent to the shell command uvcat vis={self} out={dest} {params...}.

lwcpTo(dest, skip=(), forceabs=False)

Make a lightweight copy of this dataset in dest.

Parameters:
  • dest (Data, str, or any other stringable) – the destination dataset
  • skip (collection of str) – names of dataset files to skip when copying
  • forceabs – if the link should be to an absolute path
Return type:

None

Creates a “lightweight” copy of the source dataset. This is a clone of the original dataset in which all of the items are copied except for the “visdata” item, which is instead symbolically linked back to the original dataset. This item is usually by far the largest component of a UV dataset and is also not modified during most analysis operations. Checks if the source dataset exists and deletes the destination if it already exists. If the copy succeeds, trace() is called with a “[lwcp]” operation.

The implementation of the copy is simple: every regular file in the source dataset is copied to the destination directory, except for ‘visdata’ which is handled as described above. Other items are ignored. If any errors occur, the function attempts to delete the destination dataset.

The symbolic link is to an absolute path unless the paths of both self and dest are relative and forceabs is False.

quickHash(hash=None, hex=False)

Compute a cryptographic hash of the dataset, cheating a bit.

Parameters:
  • hash (compatible with hashlib.HASH) – (optional) an object that computes hashes
  • hex (bool) – whether to return the digest encoded as hexadecimal or not
Returns:

the hash value

Return type:

str

Returns the hash of the UV dataset in string form. If hex is True, the return value is the hash represented in hexadecimal; otherwise, the return value is a string of binary values. The hash is computed using updateHash(), and hence is subject to the same caveats mentioned in the documentation of that function.

If hash is None (the default), a SHA1 hash is computed. If hash is not None, it may be prefilled with other data if you desire.

readLowlevel(uvdOptions, saveFlags, **kwargs)

Directly access the visibility data.

Parameters:
  • uvdOptions (str) – options controlling the behavior of the UVDAT subsystem
  • saveFlags (bool) – whether to save modified UV flags to the dataset as it is read
  • kwargs – extra arguments to mirtask.uvdat.setupAndRead().
Return type:

generator of (handle, preamble, data, flags)

Returns:

generates a sequence of UV information tuples. See the documentation of mirtask.uvdat.setupAndRead() for more information.

Calls mirtask.uvdat.setupAndRead() on this dataset with the specified arguments.

updateHash(updatefunc)

Update a cryptographic hash with information about the dataset, cheating a bit.

Parameters:updatefunc (callable, taking 1 str argument) – the object to update with hash data from the dataset
Returns:self

This function aids in the computation of a cryptographic hash of a visibility dataset. It takes as an argument an “update” function, expected to be the update() method on some hash object, and invokes it with data from the dataset. A key caveat is that the entire dataset is not hashed, as this could involve a huge amount of I/O with a large dataset. Instead, representative portions of the dataset are hashed, with the intent being that the hash will change for any typical modifications to the dataset.

In particular, the full contents of the “vartable” and “header” dataset items are hashed. The last megabyte (or entire contents, if they are smaller) of the following items are hashed as well: visdata, flags, wflags, gains, leakage, bandpass. (The ends of these potentially-large files are hashed so that in the not-uncommon case that a visibility dataset is appended to, its hash will change.)

The “history” item of the dataset is explicitly not included in the hash because it has no bearing on the interpretation of the UV data. Because timestamps are embedded in the history item, two datasets can be produced in an identical way and yet have different history items, which several curtails the usefulness of the hash-based approach.

In the common case that you’re just interested in extracting a cryptographic hash with minimal fuss, use quickHash().

class miriad.ImData(basedata)
Synopsis :Reference to a MIRIAD image dataset.

This subclass of Data is for referring to image datasets. It inherits many generic features from the Data class.

open(mode, axes=None)

Open the dataset that this object references.

Parameters:
  • mode (string) – the mode in which to open the dataset; either “rw” or “c”
  • axes (int ndarray, or None.) – when creating a dataset, the number of pixels along each axis; ignored otherwise. Default is None.
Returns:

an opened mirtask.XYDataSet instance.

Throws :

MiriadError if there’s an error opening an existing dataset or creating a new one

This function opens the dataset and returns a handle to it. Methods such as mirtask.XYDataSet.readPlane() can then be used to access the image data.

If mode is “rw”, an existing dataset is opened, and axes is ignored.

If mode is “c”, a new dataset is created. axes specifies the sizes of the axes of the datacube. The number of axes should be small: nominally less than about six, but anything more than four will probably not work. axes is specified in “inside-out” order, where axes[0] is the axis along which the data vary most rapidly; this is usually a row-type axis. The second-most quickly-varying axis is axes[1], which is usually a column-type axis. Subsequent axes often correspond to different frequencies, velocities, or Stokes parameters.

quickHash(hash=None, hex=False)

Compute a cryptographic hash of the dataset.

Parameters:
  • hash (compatible with hashlib.HASH) – (optional) an object that computes hashes
  • hex (bool) – whether to return the digest encoded as hexadecimal or not
Returns:

the hash value

Return type:

str

Returns the hash of the image dataset in string form. If hex is True, the return value is the hash represented in hexadecimal; otherwise, the return value is a string of binary values. The hash is computed using updateHash(), and hence is subject to the same caveats mentioned in the documentation of that function.

If hash is None (the default), a SHA1 hash is computed. If hash is not None, it may be prefilled with other data if you desire.

updateHash(updatefunc)

Update a cryptographic hash with information about the dataset.

Parameters:updatefunc (callable, taking 1 str argument) – the object to update with hash data from the dataset
Returns:self

This function aids in the computation of a cryptographic hash of an image dataset. It takes as an argument an “update” function, expected to be the update() method on some hash object, and invokes it with data from the dataset.

The full contents of the “header” and “image” dataset items are hashed. The “history” item of the dataset is explicitly not included in the hash because it has no bearing on the interpretation of the image. Because timestamps are embedded in the history item, two images can be produced in an identical way and yet have different history items, which several curtails the usefulness of the hash-based approach.

In the common case that you’re just interested in extracting a cryptographic hash with minimal fuss, use quickHash().

Tracing Task Execution

The miriad module also provides infrastructure for tracing task execution and operations on datasets.

miriad.launchTrace

Traces the execution of commands.

Should be a callable or None. Will be called by trace(), which is invoked every time a MIRIAD task is executed via mirexec or a dataset is renamed, copied, or deleted. launchTrace should take one argument, which will be a list of strings representing the commandline that is being invoked. If none, trace() has no effect.

The function basicTrace() sets launchTrace to a simple default.

miriad.trace(cmd)

Trace the execution of cmd.

Parameters:cmd (list of string) – a command and arguments
Returns:None

Invokes the callable launchTrace with cmd as the argument, unless launchTrace is None, in which case this function is a noop.

The function basicTrace() sets launchTrace to a simple default.

miriad.basicTrace()

Set the tracing function launchTrace to a basic default.

Returns:None

Sets the tracing function launchTrace to a function that prints out every command invoked, prefixed by “MIRIAD: ”. Command parameters are surrounded by single quotes to facilitate copying and pasting into a shell.

The tracing function is stored in the variable launchTrace. An action can be traced by calling trace().