Programs, Functions, & Documentation


In this tutorial we will cover: how to write IDL programs and functions and how to properly document your IDL code.

To write your first IDL program open a file called firstpro.pro in emacs or xemacs. The .pro extension identifies this file as an IDL routine and also enables idlwave markup if it has been installed. Copy and paste or type the following bit of code into the file firstpro.pro and save it:

pro firstpro

    print, 'Good morning, Arizona!'

return
end

Start idl in a terminal in the same directory where you've saved firstpro.pro and compile it with

.run firstpro

Note that you don't need to specify the .pro extension. Equivalently you can type

.r firstpro

Run your program by typing at the IDL command prompt

firstpro

There are some convenient shortcuts in IDL that you will gradually pick up. In this case .run is the same as .r. Note that .run (and all other executive commands) can only be used at the command prompt and not within programs. It is useful because if there were a bug in your code then the program would not compile. Try to sabotage your program by placing a "typo" somewhere in the code and try to re-compile. Then fix it and see what happens. You should re-compile your program whenever you make a change to it. Next let's say we want to de-bug our program. We can put in a stop and play with all the variables until we have debugged our program. Change your program to look like this:

pro firstpro

    theta = 2*!pi*findgen(100)/100.0
    sinewave = sin(theta)
 
    print, interpol(sinewave,theta,!pi/2.0)
 
    stop

return
end

Compile your routine and run it. This program generates a sine wave and then prints the value of the sine wave at pi divided by two (which should be one). But because of the stop we are still in the program firstpro.pro. To see this type

help

You will see all of the variables in the current session. You will also see that IDL knows you're in firstpro and that you've stopped at line 8. Let's make sure the sine wave looks right. Let's plot it!

window, 0, xsize=450, ysize=450
plot, theta, sinewave, xstyle=3, ystyle=3, thick=2.0, $
   xtitle='Theta (Radians)', ytitle='Sin(Theta)'

We will discuss the keywords used in the call to plot in more detail in Making Plots & Postscript. You can do whatever you want here: define new variables, print existing variables, or whatever you want. To continue through the rest of the program (you can imagine having multiple stops throughout a long program) type

.continue

or, more conveniently,

.c

There are two more commands I want to discuss here. Run your program again so that it reaches the stop. If you type

return

then you will be returned to the MAIN level (or the "top" of the IDL session). This is exactly what happens when IDL sees the return in firstpro. Imagine you had multiple "nested" procedures or functions, however. For example, try this program (still call it firstpro.pro):

pro make_sine, theta, sinewave

    theta = 2*!pi*findgen(100)/100.0
    sinewave = sin(theta)
 
    stop
 
return
end

pro firstpro

    make_sine, theta, sinewave
    print, interpol(sinewave,theta,!pi/2.0)
 
    stop
    
return
end

The program make_sine is a sub-routine whose purpose in life is to generate a sine wave. Compile this program, run it, and then type help. You will see that IDL has successfully compiled two programs (make_sine and firstpro) and that you've stopped on line 6 in make_sine and line 13 in firstpro. As you can see you're "deeper" into the IDL session. To continue you might type return or .c but you would also stop on line 16 in firstpro which would be okay if you also need to debug firstpro. Sometimes, however, you just want to return to the MAIN level. Rerun firstpro and then type

retall

and then help to see that you're back in the MAIN level and none of your variables have been preserved. If things get really messed up then you can "reset" your IDL session by typing

.reset_session

or

.reset

This command is equivalent to exiting IDL (by typing exit) and re-starting a new session. Besides programs there are also functions. In general there is nothing functions can do that programs can't but your programs will be much more logical and shorter if you use functions for particular tasks. Type this function into a new file called firstfunc.pro:

function firstfunc, npts=npts, x=x

    if n_elements(npts) eq 0L then npts = 10.0
    x = findgen(npts+1)-npts/2.0
    coeff = [-10.5,5.0]
    model = coeff[0] + coeff[1]*x^2
 
return, model
end

Compile and run this routine by typing

.r firstfunc
model = firstfunc()

Then plot the parabolla with

plot, model

When only one argument is passed to plot then it assumes that that argument is the ordinate and the abscissa is the index number. Note that a function is distinguished from a program by having parenthesis. In general a function takes inputs (or no inputs) and returns something, in this case the array model. But what if we wanted the x-axis variable? We can have firstfunc give it to us by using keywords. Keywords are extremely important. The best way to learn their functionality is by studying extant IDL routines. The function firstfunc has two keywords, npts and x. The first keyword is an optional input while the second keyword is an optional output. To see how they work try

model = firstfunc(x=x)
plot, x, model, xstyle=3, ystyle=3

If we want to change the number of points in our parabolla we can use the npts optional input:

model = firstfunc(x=x,npts=300.0)
plot, x, model, xstyle=3, ystyle=3

Note that the order of the keywords doesn't matter whereas the order of regular arguments (without an equals sign) does matter. We see that the parabolla is now more finely sampled (having 300 points rather than 10 points). Let's add one more keyword to generate a plot. Modify your program to look like this:

function firstfunc, npts=npts, x=x, doplot=doplot

    if n_elements(npts) eq 0L then npts = 10.0
    x = findgen(npts+1)-npts/2.0
    coeff = [-10.5,5.0]
    model = coeff[0] + coeff[1]*x^2

    if keyword_set(doplot) then begin

       window, 0, xs=450, ys=450
       plot, x, model, xstyle=3, ystyle=3, thick=2.0, xthick=2.0, $
         ythick=2.0, charsize=2.0, charthick=2.0, title='My Parabolla', $
         xtitle='X', ytitle='Y'

    endif
   
return, model
end

Note the extensive use of keywords in the call to plot. Now type

.r firstfunc
model = firstfunc(npts=300.0,/doplot)

The final item in this tutorial is how to properly document your code. It is imperative that you consistently document routines both for yourself and if you think anybody else will ever use your programs. Let's document firstfunc the way I would document it (note that there is no standard convention about how to document an IDL program but this is how I do it). Copy and paste this into your program:

;+
; NAME:
;       FIRSTFUNC()
;
; PURPOSE:
;       Generate a parabolla and optionally plot it.
;
; CALLING SEQUENCE:
;       model = firstfunc([npts=,x=],/doplot)
;
; INPUTS:
;       None
;
; OPTIONAL INPUTS:
;       npts   - number of points in the parabolla (default 10)
;
; KEYWORD PARAMETERS:
;       doplot - if set then generate a plot of the parabolla 
;
; OUTPUTS:
;       model  - the parabolla
;
; OPTIONAL OUTPUTS:
;       x      - abscissa corresponding to MODEL
;
; COMMON BLOCKS:
;       None
;
; PROCEDURES USED:
;
; COMMENTS:
;
; EXAMPLES:
;       To make a parabolla with 300 points and plot it type: 
;
;          IDL> model = firstfunc(npts=300.0,/doplot)
;
; MODIFICATION HISTORY:
;       J. Moustakas, 2003 November 17, U of A
;-

function firstfunc, npts=npts, x=x, doplot=doplot

    if n_elements(npts) eq 0L then npts = 10.0
    x = findgen(npts+1)-npts/2.0
    coeff = [-10.5,5.0]
    model = coeff[0] + coeff[1]*x^2

    if keyword_set(doplot) then begin ; generate a plot

       window, 0, xs=450, ys=450
       plot, x, model, xstyle=3, ystyle=3, thick=2.0, xthick=2.0, $
         ythick=2.0, charsize=2.0, charthick=2.0, title='My Parabolla', $
         xtitle='X', ytitle='Y'

    endif
   
return, model
end

The documentation is offset from the main program by being placed between the "+" and "-" signs. Note that you can comment your code by using a semi-colon. Now, if you want to read the documentation on your routine type

doc_library, 'firstfunc'




Last update 2003 Nov 12. Email J. Moustakas with questions or comments.