Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to call R functions from Fortran?

Tags:

r

fortran

According to http://gallery.rcpp.org/articles/r-function-from-c++ Rcpp allows users to call R functions from C++. Is there something similar in Fortran so that people can call R function in Fortran code?

like image 870
user1424739 Avatar asked Jun 20 '15 21:06

user1424739


2 Answers

I believe you should look at RFortran? AFAIK it is the only Fortran bindings of R objects, plus it is open source.

EDIT

As per the comments below, I was unaware that RFortran was only applicable on Windows. So, for a more portable answer let's create an example where I will leverage the RInside which makes embedding R functions in C++ code simpler. I also would use the iso_c_binding to interface with C.

testC.cpp

#include <iostream>
#include <RInside.h>                    

void helloR_(int argc, char *argv[], const char *msg);

extern "C" void helloR(int argc, char *argv[], const char *msg) {

    // create an embedded R instance
    RInside R(argc, argv);              

    // convert to string for RInside assignment
    std::string txt = std::string(msg);

    // C++ Notice
    std::cout << "This is C++, " << txt << std::endl;

    // Assign string to R object
    R.assign(txt, "txt");

    // eval the string, give R notice
    R.parseEvalQ("cat('This is R, ', txt, '\n')");
}

testF.f

  PROGRAM MAIN
    USE iso_c_binding
    IMPLICIT NONE
    INTEGER :: argc
    CHARACTER(len=32) :: arg
    CHARACTER(len=32) :: msg

    INTERFACE
      SUBROUTINE R_FUN(argc, arg, msg) bind(C, name="helloR")
        USE iso_c_binding
        INTEGER(kind=c_int), INTENT(IN) :: argc
        CHARACTER(kind=c_char), INTENT(IN) :: arg(*)
        CHARACTER(kind = C_CHAR), INTENT(IN) :: msg(*)
      END SUBROUTINE R_FUN
    END INTERFACE

    print *, "Fortran Calling RInside"
    CALL R_FUN (argc, arg, "Hello World"//C_NULL_CHAR)

  END PROGRAM

The Fortran compilation is simple:

gfortran -c testF.f

The C++ compilation is a little tricky given that you must know where your include directories are for R, Rcpp, and RInside are located.

g++ testC.cpp -c -I/path/to/RInside/include -I/path/to/Rcpp/include -I/usr/share/R/include

Then the linking you need to provide the correct libraries and the lgfortran flag.

g++ -o fcr testF.o testC.o -L/usr/lib/R/lib -lR -L/path/to/RInside/lib/ -lRInside -L/path/to/Rcpp/libs/ -Wl,-rpath,/home/path/to/RInside/lib/ -lRInside -Wl,-rpath,/path/to/Rcpp/libs/ -lgfortran

Now I have a small program demonstrating how to access R functions form Fortran

./fcr
 Fortran Calling RInside
This is C++, Hello World
This is R,  Hello World 
like image 152
cdeterman Avatar answered Oct 25 '22 06:10

cdeterman


A general solution is to write the data to a file from a Fortran program, call EXECUTE_COMMAND_LINE (standard Fortran 2003) or something like SYSTEM (a common extension) to call an R script which writes its results to a file, and then to read those results from the Fortran program.

Since R is free software and is written in R, C, and Fortran, it may be possible to translate R code to Fortran (both are array languages) or to call C or Fortran code directly from your Fortran program.

Otherwise, investigate it its better to call Fortran (or C) from R as you will find much more information on doing this approach. The system for doing that is pretty well defined. It might be that you can do the other way around, but some things need to be initialized for R to work.

like image 33
Zeus Avatar answered Oct 25 '22 07:10

Zeus