Getting Started Documentation Glish Learn More Programming Contact Us
Version 1.9 Build 1556
News FAQ
Search Home


next up previous
Next: Scripts and Functions Up: NOTE 195 Getting Started with Glish for AIPS++ Previous: Variable Assignment and Automatic Typing

Arrays

Array operations are one of glish's strong points for both code economy and computing efficiency. The notation takes a bit of getting used to.

An array variable may be created either by assigning to it an array constant or the result of an array expression,

- indices := 1:512
- ar3 := ar2 * ar1

or by using the array initialization function,

- image1 := array(0.0, 256, 256)

The array variable, 'image1', becomes the type of the first argument of 'array()', which is the array initialization value. The first argument itself may be a scalar or an array. The rest of the arguments are array dimensions of any length and number that will fit in memory.

Most arrays are created by assignment. The primary use for the 'array()' function is to create an empty array to be filled piecemeal later. Again, remember that an assignment can change the size of an array or even turn it into a scalar.

Users of IDL, PV-Wave, and, to some extent, IRAF will find glish's array index notation familiar. Fortran and C programmers will be tempted to attack arrays with integer indices and iterative loops. Resist the temptation when possible because the intrinsic array operations are much faster.

To avoid an abstraction of arrays let's load a continuum receiver data column from one of the sample data tables. A small portion of this table looks like

	RECEIVER_ID  PHASE  CAL  SUBSCN    DATA
              0         0     0      1     600885
              1         0     0      1     572540
              0         1     1      1     649341
              1         1     1      1     617254
              0         0     0      2     601413
              1         0     0      2     573158
              0         1     1      2     649827
              1         1     1      2     617841
              0         0     0      3     602472
              1         0     0      3     574106

There are many more rows and columns to this table, but these include the interesting columns for the moment.

Now load the 'DATA' column from table t1 into a glish array. This table has already been opened using the AIPS++ table system if you included 'glishtutorial.g'.

- data := t1.getcol('DATA')

If you want a complete picture of this table, browse the table with

- t1.browse()

The vector 'data' (1-D array) contains interleaved data from two receiver channels with the noise calibration signal turned on and off. To look at a single element just use an integer index.

- data[3]
649341

Notice that indices start at 1. To access a contiguous range of values in the vector use an index range.

- data[1:5]
[600885 572540 649341 617254 601413]

Any subset of vector contents may be acquired with an index array containing the indices of the values you want.

- indx := [2,5,9]
- data[indx]
[572540 601413 602472]

or just simply

- data[[2,5,9]]
[572540 601413 602472]

Notice the second set of square brackets which define the index list as members of an integer vector rather than indices of different dimensions of a three-dimensional array. To digress a moment, a multidimensional array is addressed as follows:

- mda := array(0.0, 16, 16, 16)
- mda[5, 3, 14]			# column 5, row 3, slice 14
- mda[ , 6, 5]			# all values in row 6, slice 5
- mda[11, , ]			# values in the column 11 plane
- mda[ , ,3:5]			# 3 planes of slices 3, 4, and 5

The # character is the comment delimiter. Everything from it to the end of the line is ignored by glish.

If you like, you can load an example of a two-dimensional array of data from a different table that contains a column of spectra.

- spectra := t7.getcol('DATA')

Glish variables have attributes, a few of which are predefined. The dimensions of an array are contained in its 'shape' attribute. The syntax for an attribute variable is

- spectra::shape
[1024 33]

In this case, there are 33 spectra of 1024 channels each.

Back to our 'data' vector, rather than generate an index vector it is more efficient to create a boolean vector with the same number of elements as the 'data' vector and use it as an element mask. For example, to get all of the 'data' values for receiver 1 with the calibration noise ``on'' get the RECEIVER_ID and CAL columns.

- rcvr := t1.getcol('RECEIVER_ID');
- cal := t1.getcol('CAL')

Then make a boolean vector of the same length and use it as an index mask to the 'data' vector.

- mask := (rcvr == 1) & (cal == 1)
- mask[1:10]
[F F F T F F F T F F]  

- data_cal_1 := data[mask]
- data_cal_1[1:5]
[617254 617841 618768 619804 620325]

- print length(data), length(data_cal_1)
960 240

From the values and length of 'data_cal_1' we can see that it contains the values from the 'data' vector where the boolean vector, 'mask' , is true. The function length() returns the number of elements in the array, not the number of bytes. The equivalent subarray access could be written without the intermediate 'mask' variable.

- data_cal_1 := data[rcvr == 1 & cal == 1]

We have also used the operator precedence rules to eliminate the parentheses, but, when in doubt, use parentheses. The comparison operators are

<  >  <=  >=  ==  !=

which are less than, greater than, less than or equal to, greater than or equal to, equal to, and not equal to, respectively. The boolean operators are ``and'', ``or'', and ``not''.

&  |  !

All of the arithmetic, comparison, and boolean operators operate on arrays element by element. Therefore, all arrays in an expression must be of the same size in each dimension. For example,

- [1:3] * [1:3]
[1 4 9]

It is not a vector dot product.

For a graphical illustration of what we have done with the extracted data column get one more column, 'Time', from the table and plot the two data vectors against it.

- times := t1.getcol('Time')
- times -:= as_integer(times)		# remove day numbers
- mp := pgplotter()
- mp.env(.96294,.96304,5.6e5,6.6e5,0,0)
- mp.line(times[1:32], data[1:32])
- sometimes := (times[1:32])[mask[1:32]]
- mp.eras()
- mp.env(.96294,.96304,6.1e5,6.3e5,0,0)
- mp.line(sometimes, data_cal_1[1:length(sometimes)])

The second line above illustrates one of the combined arithmetic and assignment operators ( +:= -:= *:= /:= %:= {\^{:\/}}= &:= |:= ) that are also found in C. The assignment of 'sometimes' is a combined use of vector ranges and a mask.

If we assume that the receiver 1 noise calibration intensity is 1.4 Kelvins, we can plot a calibrated scan with the additional commands

- data_cal_off_1 := data[rcvr == 1 & cal == 0]
- dataK := 1.4 * ((data_cal_1 + data_cal_off_1) / 2.0) /
+ (data_cal_1 - data_cal_off_1)
- mp.eras()
- mp.plotxy([1:len(dataK)],dataK)

Note that a different (and simpler) plotting function, mp.plotxy(), replaces the mp.env() and mp.line() commands used previously. The latter functions were used at first because of the unusual requirements on the axes ranges.

You should see four scans through a radio source placed end to end. These are actually four separate scans in the same table that were taken with a cross pointing scan procedure on the 140-foot. Note that the + on the third line in the previous example is the glish prompt and not an indication that you should type the plus character.

All of the other column names in this table may be listed with

- t1.colnames()

Here are some additional indexing ideas.

Rotate a vector five places.

- rot_vector := data[[5:data::shape,1:4]]

Delete out-of-range values.

- purged := data[data < 700000]

Make a new time vector to match the 'purged' vector.

- ptime := times[data < 700000]

Reverse a vector.

- flipped := data[data::shape:1]

Splice two vectors together.

- spliced := [v1, v2]


next up previous
Next: Scripts and Functions Up: NOTE 195 Getting Started with Glish for AIPS++ Previous: Variable Assignment and Automatic Typing
Please send questions or comments about AIPS++ to aips2-request@nrao.edu.
Copyright © 1995-2000 Associated Universities Inc., Washington, D.C.

Return to AIPS++ Home Page
2006-10-15