Reputation: 17725
I don't have experience with Fortran, but I am trying to run a very simple loop in that language by calling it from R via the .Fortran() function. Whenever I run the last line of the R code that is pasted below, the R gui crashes and I get no result. I am interest in bringing back the vector of real values x from Fortran into R for further analysis. g is a numeric value between 0 and 1, and n an integer, and they are both supplied by the user in R.
Any help would be much appreciated! Best,
Vincent
Fortran code saved in bar.f:
subroutine bar(n, g, x)
integer n
double precision g
double precision x(n)
integer i
x(1)=1
do 100 i = 2, n
x(i) = x(i-1) * g + 1
100 continue
end
Compiling the DLL in Cygwin with gfortran:
gfortran -shared -obar.dll bar.f
R code:
dyn.load("d:/bar.dll")
is.loaded("bar")
.Fortran("bar", n=as.integer(15), g=as.double(5), x=as.double(rnorm(5)))
Upvotes: 13
Views: 4291
Reputation: 17643
When I compile your code, I can execute the call to .Fortran
once. When I run it a second time, it crashes. However, I noticed that if I make the vector passed for x
the same length as the integer passed for n
suggests it should be, i.e:
.Fortran('bar', n = as.integer(15), g = as.double (5), x = as.double(rnorm(15)) )
I can run the function as many times as I want. So the problem may be that you are telling the Fortran routine it has a vector of length 15 to work with, but are only sending in a vector of length 5. This could be causing the Fortran routine to access memory it is not supposed to which would explain a crash.
Since it looks like you are generating all values of x
in the routine anyway, you could skip generating random numbers and just send in an empty vector using R's double(n)
function, where n
is the length of the empty vector you want to generate:
.Fortran('bar', n = as.integer(15), g = as.double(5), x = double(15))
integer
and character
are useful functions that return vectors like double
.
Also some friendly suggestions concerning Fortran style since you mention you are just getting started with the language:
It might be wise to name your files with a .f90
extension---files ending in .f
are assumed by most compilers to adhere to the old "fixed-form" format which is a PITA as it was designed to be used on punch cards.
The Do 100
... 100 continue
statements are an style of ending loops in Fortran 77. The modern equivalent is Do
.. end do
.
With Fortran functions and subroutines, it is wise to declare the "intent" of variables passing in and out of the routine. The available intent declarations are:
intent(in)
: Signifies variables that are entering the routine only as inputs. Once inside the routine, they should be treated as parameters and the compiler will raise an error if any attempt is made to change them.
intent(out)
: Signifies variables whose values should be generated inside the routine as outputs. The compiler will issue a warning if an intent out variable is not assigned within the routine.
intent(inout)
: Signifies variables that may enter the routine carrying a certain set of values and leave the routine with different values.
Setting intents on variables will help the compiler generate warnings and errors that may save you some bug hunting.
Fortran has a default behavior where any variable not declared in the header of the routine will be an integer if its name starts with i-n and real otherwise. This can cause misspelled variable names to "magically" become variables without the compiler batting an eye or telling you. Setting implicit none
at the top of your routines disables this behavior and allows the compiler to notify you of mistakes that can be very hard to track down otherwise.
A version of your subroutine that takes these suggestions into account would look like the following:
subroutine bar(n, g, x)
implicit none
integer, intent(in):: n
double precision, intent(in):: g
double precision, intent(inout):: x(n)
integer:: i
x(1) = 1
do i = 2, n
x(i) = x(i - 1) * g + 1
end do
end subroutine bar
Also, it is useful to let R compile your libraries using the SHLIB
subcommand of R CMD
:
R CMD SHLIB -o bar.dll bar.f90
This will compile your programs against the R libraries which contain useful functions---such as BLAS routines, stats routines and methods that can print information to the R console. See Writing R Extensions, Section 6 for more info.
Hope this helps!
Upvotes: 27