Using a Fortran Module in R

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

Use Fortran subroutine in R? Undefined symbol

Your problem comes down to the declaration of dboard:

   double precision                ::  pi_est, homepi, pirecv, pisum, dboard

Here you are saying that dboard is an external function, rather than a module procedure. This explains why there is a symbol dboard_ coming into play. You want to remove that:

double precision                ::  pi_est, homepi, pirecv, pisum

and instead rely, in pi on the module procedure-ness of dboard: pi already knows about it without this declaration.

Now, beyond that, because pi is in a module there is going to be some name mangling going on for that subroutine itself. I'd solve this problem by making pi itself a (C) interoperable procedure.

Module Fpi 
IMPLICIT NONE
contains
subroutine pi(avepi, DARTS, ROUNDS) bind(C)
use, intrinsic :: iso_c_binding, only : c_double, c_int
real(c_double), intent(out) :: avepi
integer(c_int), intent(in) :: DARTS, ROUNDS
...

and then using .C rather than .Fortran.

You can keep pi and dboard in the module, and this latter needn't even be interoperable.

Wrap fortran program for use in R

A program is supposed to be linked as an executable, so you can't call it from a subroutine - or you call the executable (with SYSTEM in gfortran), but you could do that directly from R.

The easy way to call Fortran from R is the .Fortran R function, which calls a Fortran subroutine (not a function, nor a program).

The basic steps are :

  • compile a Fortran DLL, exporting the subroutines you need (of course they may be wrappers for other subroutines or functions)
  • put the DLL in a directory in your system path
  • from R, load the DLL with dyn.load
  • call your subroutine with .Fortran.

If you use gfortran, you may just install Rtools, which has everything you need. If you want to use another compiler, you may have some trouble, especially with names.

From your comment to user2188538's answer, I see you already know all these steps, but be very careful with symbol names. From the .Fortran help: Use .Fortran with care for compiled Fortran 9x code: it may not work if the Fortran 9x compiler used differs from the Fortran 77 compiler used when configuring R, especially if the subroutine name is not lower-case or includes an underscore. It is also possible to use .C and do any necessary symbol-name translation yourself.

Also, I suspect your wrapper subroutine should not reside inside a module, or you may have extra trouble with names. But this is only a limitation for the wrapper function, which must be visible from R.

You can check the exported names in your DLL (send objdump -x your.so to a file and look for exported symbols). And check also in R, with is.loaded("your.symbol"), after loading the DLL. Be aware that usually, gfortran appends an extra underscore to names, whereas it's not needed when you call .Fortran from R. As described above, you may use .C instead (but then, remember Fortran arguments are passed by reference).

To check that you understand the whole process, I suggest you test it on a trivial example, such as a unique subroutine mysub(x,y,z) that does only z=x+y. When this one runs, you can elaborate on it to call more complex routines.

edit
You should not use assumed-shape or deferred-shape arrays, when you pass arrays arguments from R to Fortran, but only assumed-size arrays, that is, the usual array passing in Fortran 77. This is because R knows only how to pass a pointer to raw data, whereas assumed-shape and deferred-shape need more information, and R does not know the data structure to do that.

For example, you can do that:

subroutine mysub(n, a)
real :: a(n, n)
...
end subroutine

But this will amost certainly fail:

subroutine mysub(a)
real :: a(:, :)
...
end subroutine

Also, you can't pass function arguments from R to Fortran, as that would need a special data structure for the callback (under the hood, R is a Scheme dialect, and it uses S-expressions). You may do that in C, through .C or .Call (see help for .Call and R Internals).

Find Fortran file used in R package

My approach is as follows:

  1. Google "leaps CRAN GitHub" to find the GitHub source clone
  2. the src/ directory: https://github.com/cran/leaps/tree/master/src
  3. Ctrl+f there or use the repo search feature in GitHub. or in extreme cases, clone the repo and use command-line grep to find the code I need.

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.

R package with Fortran module on Windows? undefined reference to `__stack_chk_fail'

Create a Makevars.win file in your src directory with the following line.

PKG_FCFLAGS="-fno-stack-protector"

Then also change useDynLib(Fpi) in the NAMESPACE to useDynLib(MyPi) as that is what the package name is.

Try and build the package. If the output doesn't show the flag being used, the environmental variable may not currently exist and fail work. Not exactly sure why this would happen. If this is the case, just simply initialize the environmental variable.

Sys.setenv(PKG_FCFLAGS = "")

This gets your package to build on my Windows system.



Related Topics



Leave a reply



Submit