R & Fortran Call

R & Fortran call

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!

How to call a Fortran program from R

I see three possibilities:

  1. You compile the Fortran program separately, and call it with R function system(). You will have to pass data through files, in a format that this program can read.

  2. You compile a DLL that you load from R with dyn.load(), then you call a Fortran function with .Fortran(). You can easily pass numeric data (scalars, vectors or arrays), but string data is more difficult to handle. And arrays are copied.

  3. This mechanism to call a DLL function is considered too simplistic and now .Call() is prefered, but to use .Call() you would have to write C wrappers.

I will give an example of the second possibility.
Consider a subroutine in Fortran that evaluates a polynomial by Horner's algorithm:

subroutine horner(n, a, x, y)
implicit none
integer :: n, i
double precision :: a(n), x, y

y = a(n)
do i = n - 1, 1, -1
y = y * x + a(i)
end do
end subroutine

Compile from the command line with:

R CMD SHLIB horner.f90

To call it from R:

dyn.load("horner.dll")

horner <- function(a, x) {
.Fortran("horner", as.integer(length(a)), a, x, y=0)$y
}

horner(c(-2, 0, 1), 1.414)

If you want your Fortran subroutines to print something to RStudio console, you need to do (at least on Windows):

Sys.unsetenv("GFORTRAN_STDOUT_UNIT")
Sys.unsetenv("GFORTRAN_STDERR_UNIT")

This is really a trivial example, and a more complex program will require more work, but you get the idea.


If your Fortran program is standalone (it has a 'program' unit and is supposed to be compiled to an executable called from the command line), and if you are new to Fortran, I would suggest to stick with the first choice, which will be much simpler. That's what the seasonal packaged does: call the executable of Census' X13AS from within R. The executable is in the x13binary package.

R calling Fortran subroutine with character argument

When you use .C to call a Fortran subroutine the calling treats character arguments as being C-style char **. This is not compatible with the Fortran dummy argument of type character(len=255).

You have two 'simple' approaches available:

  • modify the Fortran subroutine to accept arguments looking like char **
  • use .Fortran instead of .C

Modifying the Fortran subroutine to use C interoperability with char ** is better the subject of a new question (for its breadth and being not specific to your R problem). In general, I prefer writing Fortran procedures to be used in R as exposing a C interoperable interface and .C or .Call. With what follows you may also come to that conclusion.

Even the R documentation is not optimistic about passing character arguments with .Fortran:

‘.Fortran’ passes the first (only) character string of a character vector as a C character array to Fortran: that may be usable as ‘character*255’ if its true length is passed separately. Only up to 255 characters of the string are passed back. (How well this works, and even if it works at all, depends on the C and Fortran compilers and the platform.)

You will need to read your documentation about argument passing conventions, such as that for gfortran (consult the appropriate version as these conventions may change).

With .Fortran and gfortran then with a procedure that is not C-interoperable you will need to pass a "hidden" argument to the Fortran procedure specifying the length of the character argument. That is true for explicit length characters (constant length, even length-1, or not) and assumed-length characters.

For gfortran before version 7, this hidden argument is of (R) type integer. Using pow of the question, or with assumed-length argument, we can try something like

bar <- .Fortran("pow", as.character("c"), as.double(x), as.double(0.0), 255L)

Note, however, that this is not standard and inherently not portable. Indeed, as janneb comments and the documentation linked above state, how you pass this hidden argument from R to a gfortran-compiled procedure depends on the version of gfortran used. Using 255L at the end probably won't work beyond gfortran 7. Instead you will need to pass the hidden argument as something matching an integer(c_size_t) (possibly a 64-bit integer). For compilers other than gfortran you may need to do something quite different.

It really is best to use a C-interoperable procedure either with argument interoperable with char ** (using .C) or char [] (using .Fortran). As I say, it's worth going for the first option here, as that leaves more flexibility (like longer characters, more portability, and more character arguments).

Efficient calling of F95 in R: use .Fortran or .Call?

Here's my thoughts on the situation:

.Call is the generally preferred interface. It provides you a pointer to the underlying R data object (a SEXP) directly, and so all of the memory management is then your decision to make. You can respect the NAMED field and duplicate the data if you want, or ignore it (if you know that you won't be modifying the data in place, or feel comfortable doing that for some other reason)

.Fortran tries to automagically provide the appropriate data types from an R SEXP object to a Fortran subroutine; however, its use is generally discouraged (for reasons not entirely clear to me, to be honest)

You should have some luck calling compiled Fortran code from C / C++ routines. Given a Fortran subroutine called fortran_subroutine, you should be able to provide a forward declaration in your C / C++ code as e.g. (note: you'll need a leading extern "C" for C++ code):

void fortran_subroutine_(<args>);

Note the trailing underscore on the function name -- this is just how Fortran compilers (that I am familiar with, e.g. gfortran) 'mangle' symbol names by default, and so the symbol that's made available will have that trailing underscore.

In addition, you'll need to make sure the <args> you choose map to from the corresponding C types to the corresponding Fortran types. Fortunately, R-exts provides such a table.

In the end, R's R CMD build would automatically facilitate the compilation + linking process for an R package. Because I am evidently a glutton for punishment, I've produced an example package which should provide enough information for you to get a sense of how the bindings work there.

using a Fortran module in R?

Thanks to @roygvib and @francescalus this is my working module:

Module Fortranpi
IMPLICIT NONE
contains
subroutine dboard(darts, dartsscore)
integer, intent(in) :: darts
double precision, intent(out) :: dartsscore
double precision :: x_coord, y_coord
integer :: score, n

score = 0
do n = 1, darts
call random_number(x_coord)
call random_number(y_coord)

if ((x_coord**2 + y_coord**2) <= 1.0d0) then
score = score + 1
end if
end do

dartsscore = 4.0d0*score/darts

end subroutine dboard

subroutine pi(avepi, DARTS, ROUNDS) bind(C, name="pi_")
use, intrinsic :: iso_c_binding, only : c_double, c_int
real(c_double), intent(out) :: avepi
integer(c_int), intent(in) :: DARTS, ROUNDS
integer :: MASTER, rank, i, n
integer, allocatable :: seed(:)
double precision :: pi_est, homepi, pirecv, pisum

! we set it to zero in the sequential run
rank = 0
! initialize the random number generator
! we make sure the seed is different for each task
call random_seed()
call random_seed(size = n)
allocate(seed(n))
seed = 12 + rank*11
call random_seed(put=seed(1:n))
deallocate(seed)

avepi = 0
do i = 0, ROUNDS-1
call dboard(darts, pi_est)
! calculate the average value of pi over all iterations
avepi = ((avepi*i) + pi_est)/(i + 1)
end do
end subroutine pi

end module Fortranpi

Fail in calling a Fortran subroutine from R

You could use the inline package -- here is its first example:

R> x <- as.numeric(1:10)
R> n <- as.integer(10)
R> code <- "
+ integer i
+ do 1 i=1, n(1)
+ 1 x(i) = x(i)**3
+ "
R> cubefn <- cfunction(signature(n="integer", x="numeric"), code,
+ convention=".Fortran")
R> print(cubefn)
An object of class 'CFunc'
function (n, x)
.Primitive(".Fortran")(<pointer: 0x7fc8a8db7660>, n = as.integer(n),
x = as.double(x))
<environment: 0x8193e98>
code:
1:
2: SUBROUTINE file2e6b876b50a29 ( n, x )
3: INTEGER n(*)
4: DOUBLE PRECISION x(*)
5:
6: integer i
7: do 1 i=1, n(1)
8: 1 x(i) = x(i)**3
9:
10: RETURN
11: END
12:
R> cubefn(n, x)$x
[1] 1 8 27 64 125 216 343 512 729 1000
R>

I would use this to make sure your code builds and runs, and once that is accomplished, suggest to create a package.



Related Topics



Leave a reply



Submit