wiki:SimpleScilabWrapper

A simple file-based Scilab wrapper for OpenTURNS

Introduction

The test case considered in this example is adapted from

ExampleAxialStressedBeam

This example is a simple beam, restrained at one side and stressed by a traction load F at the other side.

This Scilab wrapper is adapted from the wrapper described at :

ExampleWrapperScilab

The files used in this tutorial are available in a zip provided in attachment of this page:

The file-based wrapping method

From the Scilab point of view, the computation done in "code.sce" has the following steps :

  • Execute the "input.sce" script which defines the variables R and F.
  • Compute the output G = R - F / (100.0 * %pi)
  • Write the value of the output G into the file "output.txt".

From the OpenTURNS point of view, the computation has the following steps :

  • Write the "input.sce" script.
  • Run the Scilab script code.sce.
  • Read the value of the output G from the file "output.txt".

The accuracy of the communication

An important detail is that Scilab and OpenTURNS use doubles for their floating point numbers. This corresponds to binary 64 floating point numbers in the IEEE 754 standard, which implies that the number of significant bits is 53, which corresponds to roughly 16 significant decimal digits. In order to have a write-read cycle which is error free, the theory states that 17 decimal significant digits must be written in the data file. This can be achieved with the format "%.17e" in Scilab or Python.

Check the Scilab part

The Scilab script "code.sce" is the following.

// Read the data
exec("input.sce",-1);
// Perform the computation
G = R - F / (100.0 * %pi);
mprintf("R=%s\n",string(R));
mprintf("F=%s\n",string(F));
mprintf("G=%s\n",string(G));
// Save the result
f = mopen("output.txt", "wt");
mfprintf(f, "%.17e", G);
file("close", f);
// Exit
quit;

We make this test on Windows. In order to make the experiment work, we must be able to call Scilab whatever the current directory.

  1. Locate the path to the Scilab binary.
  • Start the Windows explorer (e.g. Win+e).
  • Enter %PROGRAMFILES% as the directory path.
  • A "Scilab-x.x.x" directory should be there.
  • The main executable is : Scilab-x.x.x/bin/Scilex.exe

In my case, the Scilex program is in :

C:\Program Files\scilab-5.3.3\bin
  1. Add the PATH of Scilab to the environment.
  • Start > Control Panel > System and Security > System > Advanced System Settings > Environment Variables
  • See the "System Variables" pane
  • Select the "Path" variable
  • Push the "Modify" button
  • Add the path to the Scilex.exe binary at the end. Separate the items with ";".
  1. Check that Scilab can run the script.
  • Click Start button
  • Enter "cmd".
  • Go to the directory which contains the "code.sce" script, for example:
cd "C:\Users\MyName\Documents\SimpleScilabOTWrapper"

  • Run the Scilab engine on the script:

Scilex -f code.sce

If the input file input.sce contains :

R=3.00000000000000000e+02
F=7.50000000000000000e+04

then this prints :

C:\Users\MyName\Documents\SimpleScilabOTWrapper>Scilex -f code.sce
        ___________________________________________
                        scilab-5.3.3

                Consortium Scilab (DIGITEO)
              Copyright (c) 1989-2011 (INRIA)
              Copyright (c) 1989-2007 (ENPC)
        ___________________________________________
Startup execution:
  loading initial environment
R=300
F=75000
G=61.267585

and writes the file output.txt, with the content:

6.12675853621570070e+001

The values printed in the Scilab console have more significant digits that the values printed in the file. This is because the values printed in the console are to be read by a human (me), while the values printed in the file are to be read by OpenTURNS.

The Scilab script ends with the statement :

quit;

This makes Scilab exit and prevents from entering in the classical interactive mode that we use most of the time. Here, we are interested only in the Scilab engine and this is why we use the "batch" mode.

Executing Scilab from Python

In order to run Scilab from Python, we could directly use the os.system function, as in the following example:

os.system("Scilex -nwni -f code.sce")

One problem with this method is that, on the MS Windows platform, if we launch a subprocess from within a non-console process, then a console window temporarily appears. This is especially ugly in the context of a Monte-Carlo simulation, since hundreds of these windows appear.

In order to solve this problem, we can use the subprocess Python module and, more precisely, its subprocess.Popen function.

We use the trickery presented at :

http://code.activestate.com/recipes/409002

which defines the launchWithoutConsole function.

The remaining issue is that subprocess does not use the PATH environment variable. Hence, we have to give the absolute path to the Scilex executable, even if this path is available in the PATH environment variable. This is why we defined the resolve_path as in the page:

http://stackoverflow.com/questions/4965175/make-subprocess-use-windows-system-path

in order to find the absolute path of the Scilex executable automatically from the PATH environment variable.

In the end, we run Scilab by executing the Python statement:

launchWithoutConsole("Scilex",["-f", "code.sce"])

Check the Python part

The Python script testWrapper.py is the following.

from openturns import *

def myScilabFunction(x):
    print "myScilabFunction:"
    [R,F] = x
    print "R:%f" % R
    print "F:%f" % F
    # Write the input file
    f = open("input.sce", "w")
    f.write("R=%.17e\n" % (R))
    f.write("F=%.17e\n" % (F))
    f.close()
    # Run Scilab
    launchWithoutConsole("Scilex",["-f", "code.sce"])
    # Read the output file
    f = open("output.txt", "r")
    line = f.readline()
    y = float(line)
    f.close()
    print "y:%f" % y
    return NumericalPoint([y])

x = NumericalPoint([300.0,75000.0])
y = myScilabFunction(x)

class myScilabWrapper(OpenTURNSPythonFunction) : 
  def __init__(self) : 
     OpenTURNSPythonFunction.__init__(self,2,1)
  def _exec(self,x) : 
      return myScilabFunction(x)

scifun = NumericalMathFunction(myScilabWrapper())

y = scifun(x)

This script is made of two separate parts. In the first part, we define a classical Python function, called myScilabFunction, and execute it. In the second part, we define an OpenTURNSPythonFunction and make it call the previously defined myScilabFunction function.

There are several ways to proceed, but I personnally use the following method.

  • In the Python menu of the console, we can click on File > Open...
  • Select the testWrapper.py script.
  • In the IDLE menu, click on Run > Run Module F5

This makes Python prints :

>>> ================================ RESTART ================================
>>> 
Welcome to OpenTURNS version 1.0
Calling Scilab...
Calling Scilab...

Make the study

We can now use the wrapper to Scilab to make the complete study, which is provided in the "study.py" script. This produces the following output.

>>> ================================ RESTART ================================
>>> 
Welcome to OpenTURNS version 1.0
Calling Scilab...
[...]
Calling Scilab...
MonteCarlo result= probabilityEstimate=2.000000e-002 varianceEstimate=2.960000e-004 standard deviation=1.72e-002 coefficient of variation=8.60e-001 confidenceLength(0.95)=6.74e-002 outerSampling=50 blockSize=2
Number of executed iterations = 50
Pf =  0.02
CV = 0.0172046505341

This result is consistent with the exact failure probability Pf=0.0292 (see ExampleAxialStressedBeam).

On my machine, the previous script requires approximately 2 minutes and a half to run Scilab 50 times.

Conclusion

In order to improve the performance of this wrapper, we make think of several methods.

  • We could make use of the multithreading possibilities of Python, so that we can run several instances of Scilab, at the same time, with different data.
  • We could use the same method as in ExampleWrapperScilab which uses a compiled wrapper to make the link.
  • We could use the generic wrapper to make the link, based on the makeWrapper function. This method is presented in the following post:

http://trac.openturns.org/blog/Scilab%20wrapper

Notice that the makeWrapper function is undocumented.

  • We could try to reduce the extra startup time required to load the Scilab engine. Indeed, the method we have presented is not that fast, partly because it basically runs the Scilab executable everytime. The call_scilab module for Scilab (by S. Ledru) enables to call Scilab from a C/C++ library:

http://help.scilab.org/call_scilab

Creating an OpenTURNS wrapper based on call_scilab would require a bit more work and compilation, but should surely make the computations much faster, in the sense that it will make Scilab behave as a classical C library, without extra startup time. The lack of example with this method has been reported in Ticket #508.

Last modified 5 years ago Last modified on 07/09/12 13:41:50

Attachments (4)

Download all attachments as: .zip