2

I am able to use a fortran subroutine in R as long as I don't have it inside a module.For example:

subroutine dboard(darts, dartsscore)
  implicit none
  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)
  implicit none
  double precision, intent(out)   ::  avepi
  integer, intent(in)             ::  DARTS, ROUNDS
  integer                         ::  MASTER, rank, i, n
  integer, allocatable            ::  seed(:)
  double precision                ::  pi_est, homepi, pirecv, pisum

interface 
   subroutine dboard(darts, dartsscore)
      implicit none
      integer, intent(in)           :: darts
      double precision, intent(out) :: dartsscore
   end subroutine dboard
end interface

! 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    

Can be compiled for R with:

R CMD SHLIB ./Fortran/Fpi.f90

and I can run it in R with:

mypi <- function(DARTS, ROUNDS) {
  dyn.load("./Fortran/Fpi.so")
  retvals <- .Fortran("pi", avepi = as.numeric(1), DARTS =  as.integer(DARTS), ROUNDS =  as.integer(ROUNDS))
  return(retvals$avepi)
}

mypi(DARTS = 50000, ROUNDS = 10)

I would like to write my fortran subroutines inside a module. I thought this was not possible, but @roygvib and @francescalus mentioned it is in one of my previous questions

How do you do the "attaching bind("c",name=...)" thing that @roygvib mentioned in that post?

Thanks!


I made the changes suggested in the comments:

Module Fortranpi
IMPLICIT NONE
contains
subroutine dboard(darts, dartsscore)
  implicit none
  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_")
  implicit none
  double precision, intent(out)   ::  avepi
  integer, intent(in)             ::  DARTS, ROUNDS
  integer                         ::  MASTER, rank, i, n
  integer, allocatable            ::  seed(:)
  double precision                ::  pi_est, homepi, pirecv, pisum

interface
   subroutine dboard(darts, dartsscore)
      implicit none
      integer, intent(in)           :: darts
      double precision, intent(out) :: dartsscore
   end subroutine dboard
end interface

! 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

When I try to build the package with Rstudio I get these errors:

==> R CMD INSTALL --no-multiarch --with-keep.source MyPi

* installing to library ‘/home/ignacio/R/x86_64-pc-linux-gnu-library/3.2’
make: Nothing to be done for 'all'.
* installing *source* package ‘MyPi’ ...
** libs
installing to /home/ignacio/R/x86_64-pc-linux-gnu-library/3.2/MyPi/libs
** R
** preparing package for lazy loading
** help
*** installing help indices
** building package indices
** testing if installed package can be loaded
Error in library.dynam(lib, package, package.lib) : 
  shared object ‘Fortranpi.so’ not found
Error: loading failed
Execution halted
ERROR: loading failed
* removing ‘/home/ignacio/R/x86_64-pc-linux-gnu-library/3.2/MyPi’
* restoring previous ‘/home/ignacio/R/x86_64-pc-linux-gnu-library/3.2/MyPi’

Exited with status 1.

I believe the problem could be the NAMESPACE

useDynLib(Fpi)
exportPattern("^[[:alpha:]]+")
Community
  • 1
  • 1
Ignacio
  • 7,646
  • 16
  • 60
  • 113
  • sorry about that, i made a mistake when pasting my code into stackoverflow. This code as is works on R. You only need to save the fortran code in ./Fortran/.Fpi.f90 – Ignacio Jul 25 '15 at 21:45
  • Hmm... there are lots of similar posts and bind(c) was already mentioned there http://stackoverflow.com/questions/31395435/use-fortran-subroutine-in-r-undefined-symbol – roygvib Jul 25 '15 at 21:48
  • I know, those are my posts... I'm trying to learn. The mention you talk about: `function dboard(darts) bind(C, name="dboard_")` was not helpful because of my ignorance and lack of reproducible example. Thanks anyway – Ignacio Jul 25 '15 at 21:51
  • Try changing the Fortran code (declaration part) as pi(avepi, DARTS, ROUNDS) bind(C, name="pi_") and include everything in a module, while deleting interface blocks. Please let us know the error message then (I guess there may appear type warning etc). – roygvib Jul 25 '15 at 21:52
  • I don't longer have a .so file. I don't know why – Ignacio Jul 25 '15 at 22:13
  • Hmm... because I have no further options, let's wait for a hacker to appear :) – roygvib Jul 25 '15 at 22:15
  • I believe I've solved your [original problem](http://stackoverflow.com/q/31395435). – francescalus Jul 25 '15 at 22:16
  • Hi @francescalus He seems to have compilation problem but I don't know why it happens... (because I've never used R). Though I don't think the .mod file comes into play here, does there seem to be some issue in the above compilation? – roygvib Jul 25 '15 at 22:20
  • I had to add `subroutine dboard(darts, dartsscore) bind(C, name="dboard_")`You guys are great! Thanks a lot! – Ignacio Jul 25 '15 at 22:21
  • @roygvib My experience of R can be about summed up by my other answer... The errors above mean nothing to me. – francescalus Jul 25 '15 at 22:23
  • @francescalus Okay, thanks very much :D It's nice to know that modules can be used with R anyway. – roygvib Jul 25 '15 at 22:24

1 Answers1

3

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
Ignacio
  • 7,646
  • 16
  • 60
  • 113
  • I'd also be interested to know (as I don't have a clue) why it's important for `dboard` to be interoperable. Is that a consequence of the `.Fortran`? If you do need this, then that cuts down an awful lot what you can do on the Fortran side: as above, all arguments must be interoperable, which means giving up an awful lot of flexibility. – francescalus Jul 25 '15 at 22:35
  • 1
    I just made those changes. All the code necesary to run this on R is on github https://github.com/ignacio82/MyPi I will keep playing around and see if I can take the binding from dboard. – Ignacio Jul 25 '15 at 22:38
  • I was able to take remove it. I was probably making some other mistake before. Can you explain why is not necessary there? Thanks! – Ignacio Jul 25 '15 at 22:42
  • The delights of interoperability is that you don't need to make the local variables, such as `seed`, `x_coord`, of interoperable types. Indeed, the allocatable `seed` cannot be interoperable regardless of its kind parameter. You're entirely free to do what you will here outside the dummy/actual arguments. – francescalus Jul 25 '15 at 22:43
  • Essentially, the only reference to `dboard` is from Fortran procedures. Fortran procedures don't need references to other Fortran procedures to be interoperable. – francescalus Jul 25 '15 at 22:45
  • Makes sense! Is the new version correct? only the `in` and `out` parameters have to b interoperable? – Ignacio Jul 25 '15 at 22:46
  • The other wasn't _wrong_ - there's no harm in having any particular choice of kind for local variables - but this one is perhaps the least minimal change. Yes, it would just be those arguments of `pi` which have to be of the interoperable types. – francescalus Jul 25 '15 at 22:50