Example of Callable IDL

Don't be daunted by using callable IDL.  It might look complex at first glance but you only need to remember 2 rules:

  1. Use your computer's copy and paste (or save as) abilities to duplicate this example and make your modifications.
  2. Read the comments which will direct you where to make your changes from the example.  (To make it easier, a color code is used.  Black text is the original fortran and all the comments.  Green is what you should simply duplicate and add to your own code without changes.  Be sure not to omit anything in green.  Blue should be used as model and customized to fit your own progam.  To make the colors easier to see, a darker grey background is used for this page.  Your browser preferences can be set to use these page-defined colors, or it may be overridden.)


This example uses callable IDL to plot graphs from a program called align.f.  This is the same align.f program that was re-written in IDL in the re-write example.  You'll see that it's a little more complex, but if your code is longer than one page, this may be the easiest way afterall.

INTRO:  IDL was written as a language to write code 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, align2.f calls a C wrapper called callable_wraps.c  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 an IDL program file to the directory, as well.  This will be where the plot is actually generated.  This IDL example program is called align.pro (remember all IDL program files must end in .pro).  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.


 align2.f
      PROGRAM ALIGN

C This program demonstrates how to use Callable IDL from a FORTRAN program.

C Data for five functions are generated; the data are imported into IDL,
C and a companion IDL program (align.pro) is invoked to plot the data.
C The companion program brings up a widget application. Included are a
C button to exit the application and a draw widget where the imported data
C are plotted.

C All of the arguments and keywords which are passed to the companion
C progrsam (and, subsequently, to the IDL PLOT procedure), are defined in
C this FORTRAN program.

C The use of companion IDL programs for Callable IDL applications is very
C desirable. If designed carefully, they can simplify both "sides" of
C the Callable IDL environment.

C In addition to the companion IDL program, a set of "wrapper" functions,
C written in C, are used to "step" from FORTRAN into the actual IDL
C internal functions that are called. These "wrapper" functions are located
C in the file callable_wraps.c .

C Written by Doug Loucks
C Research Systems, Inc., Oct, 1998

C Function data generation and plot annotation are taken from a program by
C Bill Gadzuk and Barbara am Ende, NIST, October, 1998

C Define a few IDL parameters based upon those found in export.h
      PARAMETER (IDL_FALSE = 0)
      PARAMETER (IDL_TRUE = 1)
      PARAMETER (IDL_TYP_FLOAT = 4)

C This eases changes to the size of the function arrays.
      PARAMETER (NUMPOINTS = 80)

C Declare the arrays for the function data.
      DIMENSION XP(NUMPOINTS),
     *          Y1(NUMPOINTS),
     *          Y2(NUMPOINTS),
     *          Y3(NUMPOINTS),
     *          Y4(NUMPOINTS),
     *          Y5(NUMPOINTS)

      INTEGER*4 options, just_cleanup, status
      INTEGER*4 ndim, dim(1), type
      INTEGER*4 callback /0/
      INTEGER*4 zero /0/
      CHARACTER*1 null

C Initialize local variables.
      null = char(0)

C Initialize Callable IDL.
      options = 0
      status = IDL_Init( options )

C Check for problems. Exit if Callable IDL can't be initialized.
      if (status .eq. IDL_FALSE) then
        print *, 'Failure to Initialize Callable IDL. Status: ', status
        call exit
      endif

C Generate the function data to be plotted (From Barbara am Ende).
      EX = 0.0
      DEX = 0.1

      DO 15 J=1, NUMPOINTS
        X1 = EX
        X2 = EX / 2.0
        X3 = EX / 3.0
        X4 = EX / 4.0
        X5 = EX / 5.0
        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
        EX = EX + DEX
15    CONTINUE

C Prepare to import these data into the IDL environment. First, define
C the arguments to the IDL function that imports data.
      ndim = 1
      dim(1) = NUMPOINTS
      type = IDL_TYP_FLOAT
      callback = 0
      zero = 0

C Import each of the function arrays. For your code, use one function 
C each call forarray you need to import.
C In these examples, the name of the array in IDL is given as the
C first argument, and is enclosed in single quotes.
C The second array name (the 5th argument) is the array name
C as used in the Fortran code.  If you wish to keep the two separately
C named, you could rename the IDL array in quotes as "IDL_xp".
C If so, you should also change the name of the array farther down when
C call the function, IDL_ExecuteStr to include the argument IDL_xp
 
      call IDL_ImportNamedArray( 'xp' // null, ndim, dim,
     *     type, xp, callback, zero )

      call IDL_ImportNamedArray( 'y1' // null, ndim, dim,
     *     type, y1, callback, zero )

      call IDL_ImportNamedArray( 'y2' // null, ndim, dim,
     *     type, y2, callback, zero )

      call IDL_ImportNamedArray( 'y3' // null, ndim, dim,
     *     type, y3, callback, zero )

      call IDL_ImportNamedArray( 'y4' // null, ndim, dim,
     *     type, y4, callback, zero )

      call IDL_ImportNamedArray( 'y5' // null, ndim, dim,
     *     type, y5, callback, zero )

C
C Execute the IDL command that runs the companion IDL program. The
C companion program is passed the data which have been imported into
C IDL.  Here you are calling the name of the procedure contained within
C align.pro and  passing arguments that contain the array names and the
C keywords needed for the plot command.
C
      call IDL_ExecuteStr(
     *  'align, xp, y1,y2,y3,y4,y5,
     *  xtitle = ''INCIDENT ENERGY (EV)'',
     *  xstyle = 1, xticks=4, xminor=10, xrange = [0,8], xsize=500,
     *  ytitle = ''T TO V EFFICIENCY'',
     *  ystyle = 1, yrange = [0,1], ysize=500,
     *  yticks = 1, yminor = 10,
     *  charsize = 1, psym=0,
     *  title=''ALIGN -- Callable IDL Example''' // null )

C Do the IDL cleanup stuff. With just_cleanup set to one, the IDL_Cleanup
C function returns to this program.
      just_cleanup = 1
      status = IDL_Cleanup( just_cleanup )

      print *, 'FORTRAN program TESTPLOT -- Done -- status:', status

      CALL EXIT
      END


callable_wraps.c

/* Nothing in this program should ever need to be modified, so instead of
   color coding it, the text is black.  The program should simply reside in
   the directory with the directory containing the Fortran and IDL programs
   using it. */

/* callable_wraps.c

These wrapper routines are written to be called from FORTRAN programs
that utilize Callable IDL functions.

Two assumptions about the FORTRAN compiler used to compile Callable IDL
FORTRAN programs:

  1) FORTRAN routine names are generated in all lower case letters.
  2) FORTRAN routine names are appended with the underscore (_) character.

Future enhancements planned:
  1) Generalize for all platforms, including FORTRAN underscore
     differences.

Written by Doug Loucks
Research Systems Incorporated, October, 1998
------------------------------------------------------------------------*/

#include <stdio.h>

/* HINT: export.h is in the external directory of the IDL installation
tree. */
#include "export.h"

/*-----------------------------------------------------------------------
Function idl_init_
-----------------------------------------------------------------------*/
int idl_init_(int *options) {
  int argc = 0;
  char *argv[] = {NULL};

  return IDL_Init(*options, &argc, argv);
}
 

/*-----------------------------------------------------------------------
Function idl_executestr_
-----------------------------------------------------------------------*/
void idl_executestr_( char *cmd ) {
  IDL_ExecuteStr( cmd );
}
 

/*-----------------------------------------------------------------------
Function idl_importnamedarray_
-----------------------------------------------------------------------*/
void idl_importnamedarray_(
     char *name,
     int *n_dim,
     IDL_LONG dim[],
     int *type,
     UCHAR *data,
     void *callback,
     void *s ) {

  IDL_VPTR v;

  v = IDL_ImportNamedArray( name, *n_dim, dim, *type, data, callback, s);
}
 

/*-----------------------------------------------------------------------
Function idl_cleanup_
-----------------------------------------------------------------------*/
int idl_cleanup_(int *just_cleanup) {
  printf("IDL is cleaning up...\n");
  return IDL_Cleanup(*just_cleanup);
}


align.pro

; This program was written as a companion to the Callable IDL example
; align.f
;
; Written by Doug Loucks
; Research Systems Incorporated, October, 1998.

;-------------------------------------------------------------------------
; Procedure testplot_event
; Event handler for testplot
;-------------------------------------------------------------------------
; The event handler is used to handle the event of a user clicking on the
; exit button (the button is a widget) in the window of the plot
PRO testplot_event, event
; Get the user value of the widget that generated the event.
  widget_control, event.id, get_uvalue=uvalue

; Handle events.
  case uvalue of
    'exit' : begin
    widget_control, event.top, /destroy
    end

    default: begin
      print, 'Event received, no action:'
      help, event, /struct
    end
  endcase
END

;-------------------------------------------------------------------------
; Procedure align
; This procedure plots 5 functions on the same set of axes.
;
; Input Arguments:
;   xp  Vector of independent values
;   y1  Vector of first set of dependent values.
;   y2  Vector of second set of dependent values.
;   y3  Vector of third set of dependent values.
;   y4  Vector of fourth set of dependent values.
;   y5  Vector of fifth set of dependent values.
;
; The input Keywords coincide with those passed to the PLOT procedure
; and the WIDGET_DRAW procedure.
;-------------------------------------------------------------------------
PRO align, xp, y1, y2, y3, y4, y5,$
    xtitle=xtitle, xstyle=xstyle, xticks=xticks, xminor=xminor,$
    xrange=xrange, xsize=xsize,$
    ytitle=ytitle, ystyle=ystyle, yticks=yticks, yminor=yminor,$
    yrange=yrange, ysize=ysize,$
    charsize=charsize, psym=psym, title=title

;-------------------------------------------------------------------------
; The purpose of the widget is to force the graph to display on the monitor
; until the user is done viewing the graph.  Without the widget, the program
; automatically returns back to Fortran and destroys the graph in microseconds.

; Define the Top Level Base widget.
  tlb = widget_base( title=title, /column )

; Define an Exit button.
  b = widget_button( tlb, value='Exit', uvalue='exit' )

; Define a Draw widget.
  d = widget_draw( tlb, xsize=xsize, ysize=ysize )

  widget_control, tlb, /realize

; Get the window number of the draw widget.
  widget_control, d, get_value=winnum

; Set the Draw widget as the current graphics window.
  wset, winnum

; Plot the first function graph.
  plot, xp, y1,$
        xtitle=xtitle, xstyle=xstyle, xticks=xticks, xminor=xminor,$
        xrange=xrange,$
        ytitle=ytitle, ystyle=ystyle, yticks=yticks, yminor=yminor,$
        yrange=yrange,$
        charsize=charsize, psym=psym, title=title

; Overplot the remaining four functions.
  oplot, xp, y2
  oplot, xp, y3
  oplot, xp, y4
  oplot, xp, y5

; Enter the Xmanager procedure, so that events can be managed.
  xmanager, 'testplot', tlb
END