wrapper_calling_shell_command
available with openturns and somewhat inspired from the scilab example. Wrappers allow you to call an external program as the function through which you propagate uncertainty with openturns, so that you can write you function in the language you are familiar with (R here) but still take advantage of open turns. This was done in fedora with R and open turns installed (see this post for how to install open turns on a fedora 10 machine).
The first thing we need to do is to grab the template from the installed open turns.
$ mkdir ~/opwrappers $ cp -fr /usr/local/share/openturns/WrapperTemplates/wrapper_calling_shell_command ~/opwrappers/rwrapper $ cd ~/opwrappers/rwrapper/ $ ll total 300 -rw-r--r-- 1 romain romain 27 2009-01-23 11:54 AUTHORS -rwxr-xr-x 1 romain romain 1304 2009-01-23 11:54 bootstrap -rw-r--r-- 1 romain romain 199260 2009-01-23 11:54 ChangeLog -rw-r--r-- 1 romain romain 216 2009-01-23 11:54 code_C1.data -rw-rw-r-- 1 romain romain 1594 2009-01-23 12:42 configure.ac -rw-r--r-- 1 romain romain 18002 2009-01-23 11:54 COPYING -rwxr-xr-x 1 romain romain 1794 2009-01-23 11:54 customize -rw-r--r-- 1 romain romain 9498 2009-01-23 11:54 INSTALL drwxr-xr-x 2 romain romain 4096 2009-01-23 11:54 m4 -rw-rw-r-- 1 romain romain 571 2009-01-23 12:42 Makefile.am -rw-r--r-- 1 romain romain 447 2009-01-23 11:54 myCFunction.c -rw-r--r-- 1 romain romain 455 2009-01-23 11:54 myCFunction.h -rw-r--r-- 1 romain romain 0 2009-01-23 11:54 NEWS -rw-r--r-- 1 romain romain 925 2009-01-23 11:54 README -rwxrwxr-x 1 romain romain 435 2009-01-23 12:03 rwrapper.R -rw-rw-r-- 1 romain romain 3722 2009-01-23 12:42 rwrapper.xml.in -rw-rw-r-- 1 romain romain 1442 2009-01-23 12:42 test.py -rw-rw-r-- 1 romain romain 9349 2009-01-23 12:42 wrapper.c -rw-r--r-- 1 romain romain 27 2009-01-23 11:54 AUTHORSThe first thing to do is to
customize
the wrapper so that it is called rwrapper
instead of the default wcode
. This is achieved by the customize
script:
$ ./customize rwrapperThe files
myCFunction.*
are useless and you can remove them at that point, we won't need the code_C1.c
file either since we are going to write an R script instead.
$ rm myCFunction.* $ rm code_C1.c $ ll total 288 -rw-r--r-- 1 romain romain 27 2009-01-23 11:54 AUTHORS -rwxr-xr-x 1 romain romain 1304 2009-01-23 11:54 bootstrap -rw-r--r-- 1 romain romain 199260 2009-01-23 11:54 ChangeLog -rw-r--r-- 1 romain romain 216 2009-01-23 11:54 code_C1.data -rw-rw-r-- 1 romain romain 1594 2009-01-23 12:42 configure.ac -rw-r--r-- 1 romain romain 18002 2009-01-23 11:54 COPYING -rwxr-xr-x 1 romain romain 1794 2009-01-23 11:54 customize -rw-r--r-- 1 romain romain 9498 2009-01-23 11:54 INSTALL drwxr-xr-x 2 romain romain 4096 2009-01-23 11:54 m4 -rw-rw-r-- 1 romain romain 571 2009-01-23 12:42 Makefile.am -rw-r--r-- 1 romain romain 0 2009-01-23 11:54 NEWS -rw-r--r-- 1 romain romain 925 2009-01-23 11:54 README -rwxrwxr-x 1 romain romain 435 2009-01-23 12:03 rwrapper.R -rw-rw-r-- 1 romain romain 3722 2009-01-23 12:42 rwrapper.xml.in -rw-rw-r-- 1 romain romain 1442 2009-01-23 12:42 test.py -rw-rw-r-- 1 romain romain 9349 2009-01-23 12:42 wrapper.cNext, we need to write the R script that does the actual work, it needs to grab input file and output file, read data from the input file and write data to the output file. Something like that :
#!/usr/bin/env Rscript # grab arguments argv <- commandArgs( TRUE ) datafile <- argv[1] outfile <- argv[2] # read data from data file rl <- readLines( datafile ) extract <- function( index = 1 ){ rx <- sprintf( "^(I%d *= *)(.*)$", index ) as.numeric( gsub( rx, "\\2", grep(rx, rl, value = TRUE ) ) ) } x1 <- extract( 1 ) x2 <- extract( 2 ) x3 <- extract( 3 ) out <- x1 + x2 + x3 cat( "O1 = ", out, sep = "", file = outfile )Next, we need to modify the Makefile.am file so that the
make install
step copies the rwrapper.R file into the wrappers/bin
directory later.
ACLOCAL_AMFLAGS = -I m4 wrapperdir = $(prefix)/wrappers wrapper_LTLIBRARIES = rwrapper.la wcode_la_SOURCES = wrapper.c wcode_la_CPPFLAGS = $(OPENTURNS_WRAPPER_CPPFLAGS) wcode_la_LDFLAGS = -module -no-undefined -version-info 0:0:0 wcode_la_LDFLAGS += $(OPENTURNS_WRAPPER_LDFLAGS) wcode_la_LIBADD = $(OPENTURNS_WRAPPER_LIBS) XMLWRAPPERFILE = rwrapper.xml wrapper_DATA = $(XMLWRAPPERFILE) EXTRA_DIST = $(XMLWRAPPERFILE).in test.py code_C1.data execbindir = $(prefix)/bin execbin_DATA = rwrapper.RThen, we need to make a few changes to the
rwrapper.xml.in
file. Here is the definition of the output variable:
<variable id="O1" type="out"> <comment>Output 1</comment> <unit>none</unit> <regexp>O1\S*=\S*(\R)</regexp> </variable>You also need to add the
subst
tag in the output file definition (at least with this version of openturns) :
<!-- An output file --> <file id="result" type="out"> <name>The output result file</name> <path>code_C1.result</path> <subst>O1</subst> </file>and then change the command that invokes the script as follows:
<command>Rscript @prefix@/bin/rwrapper.R code_C1.data code_C1.result</command>Download the full rwrapper.xml.in file Once this is done (you can grab a tar.gz of the wrapper at that stage) , you can compile the wrapper by following these steps:
$ ./bootstrap $ ./configure --prefix=/home/romain/openturns --with-openturns=/usr/local $ make $ make installIf all goes well, you should have a
rwrapper.R
file in the ~/openturns/bin
directory and a file rwrapper.xml
in the ~/openturns/wrappers
directory
Before trying the wrapper, we need to copy the input file in the directory where we are going to run openturns (say
/tmp
)
$ cp code_C1.data /tmp $ cd /tmpNow we are good to go and can start using the wrapper from open turns:
$ python >>> from openturns import * >>> p = NumericalPoint( (1,2,3)) >>> f = NumericalMathFunction( "rwrapper" ) >>> print f(p ) class=NumericalPoint name=Unnamed dimension=1 implementation=class=NumericalPointImplementation name=Unnamed dimension=1 values=[6] >>> 1+2+3 6The drawback of this approach is that each time the function needs to be evaluated, a new R session will be launched by Rscript, depending on the number of iterations we want to do this can affect seriously the run time of the study. A way to get around this is to use a single R session and let the wrapper communicate with it. I can see at least two ways to do it:
- by writing the function in python and let python communicate with R (using rpy for instance)
- by writing a c wrapper that would initialize a connection to an R server when the function is created, and call it whenever the function needs to be called