Note – The more experienced programmer might find the first couple of examples in this section worth skipping. In this section, you’ll begin to write your own applications. We’ll start very slowly by looking at a traditional “do nothing” code.
Let’s get started on your first application. Enter the following code via your choice of text editor. Save it as nowt.f.
You’ll need an interface file as well, despite the lack of code, as it is required by alink. Again, enter this with your text editor, but this time save it as nowt.ifl
Now we can compile and link the code in the following way. From the UNIX prompt type:
This should create an executable file called nowt. Try running nowt. If you’ve done everything correctly, nowt happens. While this is a good sign, it’s hardly gripping stuff. You could always edit the code so it reads:
Note that you can run alink to recompile nowt.f without changing the interface file. This is because the nowt application still doesn’t require any parameters to work.
Let’s now progress to a code which opens a Starlink (.sdf) data file. Enter the following code and save it as sesame.f
And of course we’ll need the obligatory interface file sesame.ifl
Now, to compile sesame use:
If you get error messages, first make sure you have started the Starlink software on your session. If you still have trouble, try the command star_dev. (This sets up a link to the Starlink libraries – don’t worry too much about how it works). Note the change in the alink command from the previous ones.
Now try running your code. You should get:
Assuming your code works(!), you can give the name of an NDF file which it will read and promptly do nothing. This code appears to be another “do nothing” code. It isn’t, so let’s take a closer look at what’s going on.
Firstly, we start the application with the usual
It is a convention when writing ADAM applications to always have a subroutine (of the same name as the application) with an integer argument instead of the more familiar
statement. Don’t worry too much about why this should be the case. The next line merely declares some variables. Now we get to:
This line opens the file you told it to. It associates the file with a parameter called IN. In order to get information about the parameter IN, the application looked in the interface file. It was told that for this parameter it would need to prompt the user into providing a file name by using a message.
IMG_IN also found out some information about the image. Its size is returned via the arguments NX and NY. The next variable (IP) is a pointer. We will return to this concept in the next section. STATUS is used to check all is well.
The next call,
simply closes the image associated with the parameter IN and tidies up. Applications which call more than one image must apply this call to all the images used.
In the last section, we used two subroutine calls of the form CALL IMG_ These subroutines are part of the IMG library. You can find out all about the facilities offered by IMG by reading SUN/160.
IMG is a collection of software designed to make the task of reading astronomical data easy. It allows access to both the data itself and the header information contained within the files. It can be called from both Fortran and C codes (we will stick to the former) and forms part of the NDF library. The NDF library is somewhat more complex (and somewhat more powerful) than the IMG library, so let’s save any more discussion on it until later sections.
When the alink command was used in the last section,
you explicitly told alink that you needed to link sesame.f to the IMG library. You must make absolutely sure that every time you use the IMG library, you inform alink in this way! This also goes for any other Starlink libraries you use (as we will do later on in this book).
Opening and closing files is fine, but what you really want to be able to do is get to your data. ADAM libraries have a particular way of handling arrays of data. Remember how in sesame.f you used:
but we didn’t discuss the integer variable IP? Well, this is related to data access. Specifically, IP acts as a pointer to the array of data in the file. Users of the C programming language will be familiar with the concept of pointers, but Fortran programmers will generally have little or no experience of them. No problem, you don’t need to know the ins and outs of how they work. Put simply, a pointer tells a piece of code where some information is kept in the memory of the machine. In the case of the applications we’re going to be looking at in a minute, we’ll use pointers to “map” how the data contained in a file is held in the memory of your machine.
In this section, we’ll go through two applications. The first demonstrates how data in a file is mapped into an array of values. The second covers the methods of creating new files and updating old files.
Type in the following code and save it as stats.f
Have a go at writing your own interface file for stats and compile it with alink. Finally, try running it on an NDF (i.e. .sdf) file of your choice.
Let’s have a careful look at how this code is constructed. The main body of the code consists of opening an image, calling a subroutine which does the actual work, followed by a call to close the image and clean up. You’ll find this structure in a lot of Starlink software. It helps to keep the code uncluttered and is easy to maintain, so we recommend that you try to stick to it.
The call to the DOSTAT subroutine shows how pointers are used to access the data in the file. The %VAL statement is a VAX extension to Fortran. Normally, when a Fortran code uses arrays, it needs to have some information about the size of the array right from the outset. There is no method of doing memory allocation “on the fly”. (This is not true of Fortran 90, but let’s restrict ourselves to using Fortran 77 for this guide). This just isn’t practical for applications which have to deal with many different sizes of images.
The %VAL method makes the pointer (in this case IP) look just like an array. What’s more, it makes sure that the array is of the right size, in this case NX by NY pixels. This is not a feature of “standard” Fortran 77, but unless you hear otherwise, it should be OK on your machine.
You’ll see that when the subroutine DOSTAT inherits the %VAL, it does so with a ready-made array of real values. This way, there is no need to pre-define your array sizes.
When you want to write out a data file you want to do one of two things. Either you want to write out the same data file you read in, presumably with some modification, or you want to create an entirely new file. The IMG library quite happily lets you do both. The next two codes describe each of these processes in turn.
Enter the code for clip.f:
and the corresponding interface file clip.ifl:
and compile it using alink, remembering to link to the IMG library.
You can check that your code has worked by using the stats application from the last section. You should see how the reported maximum and minimum data values have changed if you chose your clipping limits appropriately.
This code modifies your input file, i.e. no new file is created. This is often not the most useful form of output as, especially in data reduction, you might want to repeat a step with the original data many times. In such a case, it is more useful to preserve the input data and create a new file from scratch. This next code demonstrates how this is done using the IMG library.
Enter the following code for bigger.f.
Notice how the code reads two distinct images in with a single statement.
The interface file, bigger.ifl, looks a little different to that which you have already seen: