Don't be daunted by using callable IDL. It might look complex at first glance but you only need to remember 2 rules:
INTRO: IDL was written as a language to write from scratch. Using Fortran to call IDL's capabilites to plot graphs is a little klugy, but it can be done without too much trouble if you use this example as a template. The Fortran code calls a "C wrapper." This short C program will not need to be changed or even opened. Just keep a copy of it in the directory where you have your program. Then you will add a
Believe it or not, the easiest way for this to work is for your Fortran
program to call a C language "wrapper" procedure, which in turn calls IDL.
You will have to delete the disspla calls from your code and add the new
calls. For this example, the edited Fortran code is called align2.f.
The C wrapper is wrapalign.c. You will
also need a Makefile and shell script to
compile and execute the programs. For further information on compiling,
go to Compiling Callable IDL.
Remember, all you have to do is copy much of this without worrying.
If you click on the links to the code, you'll see complete versions of
the code. Below, the code has been commented on with colored text.
The following three variables must be added to
your declarations
INTEGER*4 options
INTEGER i_ret
INTEGER just_cleanup
C -----------------------------------------------------------------------------
You must initialize IDL before you make any calls.
I initialize up near the top of my program so I don't accidently put code
in that calls IDL before it's been initialized. Just cut and paste
this as is.
C Call IDL Initialization
call IDL_Init (options, i_ret)
C -----------------------------------------------------------------------------
EX=0.0
DEX=.1
JMAX=80
DO 15 J=1,JMAX
X1=EX
X2=EX/2.
X3=EX/3.
X4=EX/4.
X5=EX/5.
Y1(J)=X1*(2.+X1)/(1.+X1)**2
Y2(J)=X2*(2.+X2)/(1.+X2)**2
Y3(J)=X3*(2.+X3)/(1.+X3)**2
Y4(J)=X4*(2.+X4)/(1.+X4)**2
Y5(J)=X5*(2.+X5)/(1.+X5)**2
XP(J)=EX
15 EX=EX+DEX
C -----------------------------------------------------------------------------
This is the meat of calling IDL. It requires
importing the Fortran arrays to IDL. Here, you are actually calling
a C procedure, with the slightly deceptive name "IDL_ImportNamedArray."
The arguments that are passed to C are the arrays that will be plotted
by IDL.
C
C Call IDL ImportNamedArray
call IDL_ImportNamedArray (Y1, Y2,
Y3, Y4, Y5, XP, i_ret)
C -----------------------------------------------------------------------------
By now, in your Fortran program you've sent the
arrays to C which has had IDL make spiffy graphs. IDL finished its
job and the C wrapper has sent control back to Fortran. Fortran is
done, too, so now you have to close out IDL by using IDL_Cleanup.
Again, this is one of those times where you just copy this code into your
program and don't worry about the why's and wherefores. One minor
note, however, when just_cleanup is set to 1, IDL shuts down. The
usual way is for just_cleanup to be set to 0 which causes IDL to exit after
it shuts down.
C Call IDL Cleanup
just_cleanup = 1
call IDL_Cleanup (just_cleanup,
i_ret)
C -----------------------------------------------------------------------------
STOP
END
#include <stdio.h>
#include "export.h" export.h is a header file that does all the the nasty coding that you'd have to do explicitly in Fortran. This example uses the power of export.h to avoid writing lots of confusing code.
/**************************************************************************/
static void
free_callback(UCHAR *addr)
{
printf("IDL released(%u)\r\n", addr);
}
This is another one of those pieces of code you
copy into your files without worrying about why. Be sure to keep
it up here near the top of your C wrapper.
/**************************************************************************/
void
idl_init_ (int *options, int *i_ret)
{
int argc;
char *argv;
argc = 0;
argv = NULL;
*i_ret = IDL_Init (*options, &argc, &argv);
}
This is another one of those pieces of code you
copy into your files without worrying about why. Be sure to keep
it up here near the top of your C wrapper.
/**************************************************************************/
This is the meat of where you pass your array(s)
to IDL to have them printed. Pay attention to the notes because you'll
have to modify the code to match your data.
In the function definition you'll need to add your arrays for the arguments. In this case there are 6 arrays of type float, and one return variable. I've made it type long because it's a pointer which will hold a very large number, and it isn't adequate to have it be type int. Also, the arguments must be pointers here in C. That's why there's an * before i_ret. The arrays don't have *s because by definitions they are pointers.
This is a C function in spite of the name that
is prefaced with idl. Within here, you'll actually call IDL. Note
that when your Fortran program calls this C function it's going to need
two things: 1) all lower case letters, and 2) an underscore at the
end of the name.
void
idl_importnamedarray_ (float Y1[], float Y2[], float Y3[], float
Y4[], \
float Y5[], float XP[], long *i_ret)
{
This is the declaration of an array of commands
that IDL will use later on. This set of commands creates a "widget" that
is a little window that pops up. It remains on the monitor until
you place the mouse arrow into the window and click. At that point
the window closes. Without the widget the graph is sent to the monitor,
then when the program finishes the graph window closes. All this
occurs in microseconds and you'd never have a chance to inspect the graph.
With the widget, you can look at the graph on the monitor as long as you
like before clicking on the widget and removing both the widget and the
graph. If you want to see the graph on the monitor, cut and paste
these commands into your C wrapper.
static char *cmds2[] = {"a = widget_base()",
"b = widget_button(a, value='Press When Done', \
xsize=300, ysize=200)",
"widget_control,/realize, a",
"dummy = widget_event(a)",
"widget_control,/destroy, a" };
This is the declaration of an array of commands
that IDL will use to send the graph to a postscript file.
static char *cmds[] = { "SET_PLOT, 'PS'",
"DEVICE, FILENAME='align.ps'",
"DEVICE,/INCHES,YOFFSET=2",
};
These are the declarations for your IDL variables.
You'll have one of these pointers for each of your arrays. In this
case I've taken IDL's conventional "v" and appended the name of the array
to them.
IDL_VPTR vY1;
IDL_VPTR vY2;
IDL_VPTR vY3;
IDL_VPTR vY4;
IDL_VPTR vY5;
IDL_VPTR vXP;
dim is the dimension of the arrays. It
is of type IDL_LONG. IDL sets up some predetermined maximum number
of dimensions. I don't know what that maximum is, but it's probably
much bigger than your number of dimensions which will probably be only
1 or 2. Anyway, this declaration simply announces that you'll be
using the variable dim (i.e., cut and paste this statement into your code
without worrying about it).
IDL_LONG dim[IDL_MAX_ARRAY_DIM];
All of the arrays in this example are one dimensional.
Because IDL is like C, it describes the first (and only) dimension as "0."
In this case, all the arrays are the same size: they each have 80
elements.
dim[0] = 80;
Here, at the end of the variable declarations,
I'm putting the call to execute the commands in the array which sets up
the PostScript file. Note you can either set up the array of commands
and execute them all at once using "IDL_Execute" or you can type them in
one at a time using "IDL_ExecuteStr" which is used below to make the plots.
IDL_Execute(sizeof(cmds)/sizeof(char *), cmds);
Here's the important part where you send the array
from C to IDL. You set the pointer equal to the return of the IDL
function IDL_ImportNamedArray. There are several arguments, some
of them you simply copy as shown here, and others you must tailor to your
own arrays. The first argument, in this case "idl_Y1" is the
name of the array once IDL recognizes it; the variable either created or
modified. I simplyl added idl_ to the name of the array in C.
Note that you must use quotation marks here. The second argument,
in this case 1, indicates that there is 1 dimension to the array.
Note that it is a 1 dimensional array, whose first (and only) dimension
is 0 (don't blame me for this convention confusion!). The third
argument is simply dim. The fourth argument gives the
type that the array is. Other types you might use are: IDL_TYP_INT,
IDL_TYP_LONG, IDL_TYP_DOUBLE, IDL_TYP_COMPLEX, AND IDL_TYP_STRING (for
more details see table 5-1 in the IDL Advance Development Guide (v. 5.0)
or IDL External Development Guide (v. 5.1). The fifth argument
is a pointer to your array data. Type (UCHAR *) variable-name-from-arguments-in-the-C-function-definition.
The sixth argument is always free_callback. This is where
that function defined at the top of your C wrapper is called. The
seventh argument is used for structures, that in most cases aren't
used, so simply leave it as (void *) 0.
vY1 = IDL_ImportNamedArray("idl_Y1", 1, dim, IDL_TYP_FLOAT,
(UCHAR *) Y1, free_callback, (void *) 0);
vY2 = IDL_ImportNamedArray("idl_Y2", 1, dim, IDL_TYP_FLOAT,
(UCHAR *) Y2, free_callback, (void *) 0);
vY3 = IDL_ImportNamedArray("idl_Y3", 1, dim, IDL_TYP_FLOAT,
(UCHAR *) Y3, free_callback, (void *) 0);
vY4 = IDL_ImportNamedArray("idl_Y4", 1, dim, IDL_TYP_FLOAT,
(UCHAR *) Y4, free_callback, (void *) 0);
vY5 = IDL_ImportNamedArray("idl_Y5", 1, dim, IDL_TYP_FLOAT,
(UCHAR *) Y5, free_callback, (void *) 0);
vXP = IDL_ImportNamedArray("idl_XP", 1, dim, IDL_TYP_FLOAT,
(UCHAR *) XP, free_callback, (void *) 0);
Now that IDL has received your arrays, you're
ready to plot them. Here I used IDL_ExecuteStr. Note that after
typing IDL_ExcuteStr you must put your IDL command in quotation marks because
you're executing a string that contains a command. Be sure to use
the IDL version of the name of your variables/arrays. Be sure to
not use the IDL symbol $ at the end of each line that is still part of
the same command. You're in a C function and even though you're issuing
an IDL command, the compiler will choke with a $.
IDL_ExecuteStr("PLOT, idl_XP, idl_Y1, \
XTITLE = 'INCIDENT ENERGY (EV)', \
YTITLE = 'T TO V EFFICIENCY', \
PSYM = 0, \
XSTYLE = 1, XRANGE = [0,8], \
YSTYLE = 1, YRANGE = [0,1], \
XTICKS = 4, XMINOR = 10, \
YTICKS = 1, YMINOR = 10, \
CHARSIZE = 1");
The following commands make the overlay plots.
Alternatively, you could have declared an array with all of these plotting
commands in them, then executed them with IDL_Execute().
IDL_ExecuteStr("OPLOT, idl_XP, idl_Y2");
IDL_ExecuteStr("OPLOT, idl_XP, idl_Y3");
IDL_ExecuteStr("OPLOT, idl_XP, idl_Y4");
IDL_ExecuteStr("OPLOT, idl_XP, idl_Y5");
Here the widget is called and executed.
IDL_Execute(sizeof(cmds2)/sizeof(char *), cmds2);
Here I've simply set i_ret to the return of the
last Y array that was passed to IDL. Be sure and use the asterisk
with i_ret, but not the IDL pointer.
*i_ret = (long) vY5;
}
/**************************************************************************/
This is another one of those pieces of code you
copy into your files without worrying about why. Be sure to keep
it down here at the bottom of your C wrapper.
void
idl_cleanup_ (int *just_cleanup, long *i_ret)
{
*i_ret = IDL_Cleanup (*just_cleanup);
}