[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: How to call fortran subroution?
"Craig Markwardt" <craigmnet@cow.physics.wisc.edu> wrote in message
onwv8m6xpf.fsf@cow.physics.wisc.edu">news:onwv8m6xpf.fsf@cow.physics.wisc.edu...
> I think Stefano is right, you can't call FORTRAN directly from IDL,
> especially with the CALL_EXTERNAL method. That method requires your
> program to conform to a very specific interface for your function
> parameters (two parameters named argc and argv).
>
> I'm looking at the External Development Guide for IDL 5.2. They
> recommend a "wrapper" function written in C, which in turn calls the
> FORTRAN. That manual does give an example where the FORTRAN
> subroutine can be called directly, but the semantics appear to be
> present only on a few platforms (VMS or IBM AIX), and the subroutine
> must still conform to the argc and argv convention.
>
> Questions:
> * What example are you looking at?
> * Does Ronn Kling's book on external linking address FORTRAN?
If your Fortran compiler supports the %VAL and LOC extensions, you can call
a Fortran subroutine or function from IDL via CALL_EXTERNAL using a Fortran
wrapper. I developed the routines shown below to vectorize the following
operation in IDL:
for i = 0L, n_elements(x) - 1L do a[x[i]] = a[x[i]] + b[i]
---begin vecadd.f---
c ... This is the wrapper routine called by IDL
subroutine vecadd(argc, argv)
integer*4 argc, argv(*), j
j = loc(argc)
call vecadd1(%val(argv(1)), %val(argv(2)), %val(argv(3)),
& %val(argv(4)), %val(argv(5)))
end
c ... This is the routine which does the work.
c ... The arguments are defined exactly the same way as in the
c ... call to CALL_EXTERNAL in vecadd.pro
subroutine vecadd1(a, na, x, nx, b)
integer*4 na, nx
real*4 a(na), b(nx)
integer*4 x(nx), i
do i = 1, nx
a(x(i)) = a(x(i)) + b(i)
end do
end
---end vecadd.f
---begin vecadd.pro---
FUNCTION VECADD, ARRAY, INDEX, VALUE
;- Check arguments
if (n_elements(array) eq 0) then $
message, 'Argument A is undefined'
if (n_elements(index) eq 0) then $
message, 'Argument X is undefined'
if (n_elements(value) eq 0) then $
message, 'Argument B is undefined'
if (n_elements(index) ne n_elements(value)) then $
message, 'Arguments X and B must have the same number of elements'
;- Create copies of the arguments with correct type
if (size(a, /tname) ne 'FLOAT') then begin
a = float(array)
endif else begin
a = array
endelse
x = ((long(index) > 0L) < (n_elements(a) - 1L)) + 1L
b = float(value)
;- Call the external routine
result = call_external('vecadd.so', 'vecadd_', $
a, n_elements(a), x, n_elements(x), b)
if (result ne 1) then message, 'Error calling external routine'
;- Return result
return, a
END
---end vecadd.pro---
To compile the Fortran source on SGI IRIX 6.5:
% f77 -n32 -KPIC -c vecadd.f
% ld -n32 -shared -o vecadd.so vecadd.o
(see /usr/local/rsi/idl_5.3/external/call_external/Fortran/Makefile for the
syntax on other UNIX platforms).
To call the routine in IDL 5.3:
a = findgen(10)
x =[3, 5, 7]
b = [2, 4, 6]
print, vecadd(a, x, b), format='(10f5.1)'
0.0 1.0 2.0 5.0 4.0 9.0 6.0 13.0 8.0 9.0
The IDL External Development Guide is quite helpful in explaining how this
works.
Cheers,
Liam.
http://cimss.ssec.wisc.edu/~gumley/