Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
29279 Discussions

Data passing w/ mixed programming f2008+python.

rudi-gaelzer
New Contributor I
931 Views

I would like to have your suggestions for the following task.

I'm developing a F2008 code that has to call a python script (specifically a special function in the mpmath lib) which will generate an array of data values that I want to transfer back to the fortran exec.

I can easily come up with a couple of  possible alternatives, all of which require the use of the intrinsic execute_command_line.  I can easily execute the python code with it, but how to transfer the results?

The simpler (and dumber, I guess) alternative is to write the results into a file and than load it into the F2008 code.

Another possibility is to call a C code which in turn calls the python script.  A third alternative would be to use f2py in order to avoid calling a C procedure, but I don't know if this is feasible...

Anyone can give me a tip here?

Thanks.

0 Kudos
9 Replies
Steven_L_Intel1
Employee
931 Views

If C code can call Python, then Fortran can call Python. I don't know how one does calls to Python but it sounds as if you have a handle on how to do it in C. If you can show us a sample C code we can show you how to do it in Fortran.

0 Kudos
mecej4
Honored Contributor III
931 Views

If you want to call Python merely for the purpose of generating an array of special function values, it is very likely that there is existing Fortran code to calculate that special function. Can you provide details so that we can assess the possibilities? In particular, which special function?

0 Kudos
rudi-gaelzer
New Contributor I
931 Views

mecej4 wrote:

If you want to call Python merely for the purpose of generating an array of special function values, it is very likely that there is existing Fortran code to calculate that special function. Can you provide details so that we can assess the possibilities? In particular, which special function?

I don't believe there is, since I've already spent some (well, a lot) of time looking for it...

In any case, I need to evaluate the Meijer G function for a given set of parameters...

I know that in most cases you can express the G function as a combination of hypergeometrics, but when some of the lower parameters differ by an integer the function assumes a logarithmic behavior that cannot be expressed as a simple hypergeometric series.

Additionaly, even in the hypergeometric case, although there is a general-purpose code developed by Warren Perger and collaborators and distributed by CPC, the particular combination of pFq's I have starts to suffer from round-off errors when the parameters become too large.  So, I'm developing a specific code for my G function.

OTOH, the mpmath library (in Scientific Python) provides access to the G function in arbitrary precision.  I intend to call the python routine in order to generate a table of coefficients (and transfer them to fortran) and use them to evaluate the G function via a Fourier-Chebyshev series.

 

0 Kudos
rudi-gaelzer
New Contributor I
931 Views

Steve Lionel (Intel) wrote:

If C code can call Python, then Fortran can call Python. I don't know how one does calls to Python but it sounds as if you have a handle on how to do it in C. If you can show us a sample C code we can show you how to do it in Fortran.

Thanks, Steve.

I've found in this topic:

http://stackoverflow.com/questions/3286448/calling-a-python-method-from-c-c-and-extracting-its-return-value

a sample C code that succeeds on calling a python routine.

I'm including both the C and python codes below because I wasn't able to attach the files.

Compiling the C main with gcc:

$>gcc call_function.c -I/usr/include/python2.7 -lpython2.7

worked all right.  I'm running Fedora 22 and needed the python-devel.x86_64 rpm that provides Python.h.

Is it simple to write a corresponding C function that can be called from F2008?

Thank you.

================== C main code =====================================================

#include <Python.h>
#include <stdlib.h>
int main()
{
   // Set PYTHONPATH TO working directory
   setenv("PYTHONPATH",".",1);

   PyObject *pName, *pModule, *pDict, *pFunc, *pValue, *presult;


   // Initialize the Python Interpreter
   Py_Initialize();


   // Build the name object
   pName = PyString_FromString((char*)"arbName");

   // Load the module object
   pModule = PyImport_Import(pName);


   // pDict is a borrowed reference
   pDict = PyModule_GetDict(pModule);


   // pFunc is also a borrowed reference
   pFunc = PyDict_GetItemString(pDict, (char*)"someFunction");

   if (PyCallable_Check(pFunc))
   {
       pValue=Py_BuildValue("(z)",(char*)"something");
       PyErr_Print();
       printf("Let's give this a shot!\n");
       presult=PyObject_CallObject(pFunc,pValue);
       PyErr_Print();
   } else
   {
       PyErr_Print();
   }
   printf("Result is %d\n",PyInt_AsLong(presult));
   Py_DECREF(pValue);

   // Clean up
   Py_DECREF(pModule);
   Py_DECREF(pName);

   // Finish the Python Interpreter
   Py_Finalize();


    return 0;
}


========================= Python function =============================

def someFunction(text):
    print 'You passed this Python program '+text+' from C! Congratulations!'
    return 12345

 

0 Kudos
Steven_L_Intel1
Employee
931 Views

Can you attach Python.h? Put it in a tar or zip file.

0 Kudos
rudi-gaelzer
New Contributor I
931 Views

Steve Lionel (Intel) wrote:

Can you attach Python.h? Put it in a tar or zip file.

Actually, no... whenever I try to attach a file the server says I'm not authorized (yes, I'm logged in).

Anyway, I don't think It'll help much, since Python.h includes several other headers (pyconfig.h, pymacconfig.h, etc)...

I'll try to write a the C function and link it with fortran.  If it works, I'll let you know.

0 Kudos
rudi-gaelzer
New Contributor I
931 Views

Steve, a question.

Looking at the documentation for the Fortran 15.0 compiler about the ISO_C_BINDING, I've found that:

  • 64-bit Linux* and Windows*: long double is treated the same as double, so C_LONG_DOUBLE is 8.

    To ensure matching, make sure you use the constants for kind values and the corresponding types in C.

 

So this means that I'll only have access to double precision (8 bytes) variables?  I can't transfer long double values from C?

0 Kudos
Steven_L_Intel1
Employee
931 Views

We believe that gcc makes double and long double mean the same thing (64-bit IEEE) on x64. So it doesn't matter which you use. I'm having a bit of a hard time nailing down a reference for that, but it seems right. The SSE/AVX registers don't support 80-bit floating.

0 Kudos
rudi-gaelzer
New Contributor I
931 Views

I am returning to this topic because I've finally had a couple of free days to implement data passing between python and fortran via C bindings.  Perhaps some day someone may find this useful.

In the codes below, I use the iso_c_binding module to transfer a number of double complex variables to a C function, which wll then access a python script via the Python/C API.  The C code is largely based on the sample given here:

https://docs.python.org/2/extending/embedding.html

The python script itself uses the MPMath library to evaluate the Phi_1 2 variables, confluent hypergeometric function, for which there is NO known implementation in fortran.  The example below can be easily modified for other applications.  Since I'm not an experienced programmer in C nor in python, my implementation might be somewhat naive, but it works if you need quick access to some special function which you can't find in Fortran.  In this case you'll be able to access the awesome MPMath library from within your fortran code.  Just don't expect high performance...

=================== Fortran code ============================

! Evaluates Humbert's Phi_1(a, b, c, x, y) two variables confluent hypergeometric function
!  via F2013 <-> C <-> Python interoperability.
! Ref: Érdelyi, A. Higher Transcendental Functions 1, eq. 5.7.1(20).
program call_cPhi_1
use, intrinsic :: iso_c_binding
implicit none
complex(kind= c_double_complex) :: a, b, c, x, y
INTERFACE
   function cPhi_1(a, b, c, x, y) bind(c)
   import :: c_double_complex
   complex(kind= c_double_complex) :: cPhi_1
   complex(kind= c_double_complex), value :: a, b, c, x, y
   end function cPhi_1
END INTERFACE
!
write(*, '(a)', advance= 'no')'a= ' ; read(*,*)a
write(*, '(a)', advance= 'no')'b= ' ; read(*,*)b
write(*, '(a)', advance= 'no')'c= ' ; read(*,*)c
do
   write(*, '(a)', advance= 'no')'x= ' ; read(*,*)x
   write(*, '(a)', advance= 'no')'y= ' ; read(*,*)y
   print*, 'Phi_1=', cPhi_1(a, b, c, x, y)
end do
end program call_cPhi_1

=========== C code ============================

#include <Python.h>
#include <complex.h>

double complex cphi_1(double complex a, double complex b, double complex c, double complex x, double complex y)
{
/* local variables declarations */
   int i, npars= 5;
   double complex result;
   double complex pars[] = {a, b, c, x, y};
   PyObject *pName, *pModule, *pFunc, *pArgs, *pValue;
   Py_complex res_pc;

   setenv("PYTHONPATH", ".", 1); // Set PYTHONPATH TO working directory
   Py_Initialize();
   pName = PyString_FromString("Humbert_Phi_1");
   pModule = PyImport_Import(pName);
   pFunc = PyObject_GetAttrString(pModule, "Phi_1");
   pArgs = PyTuple_New(npars);
   for (i= 0; i < npars; i++) {
      pValue = PyComplex_FromDoubles(creal(pars),cimag(pars));
      PyTuple_SetItem(pArgs, i, pValue);
   }
   pValue = PyObject_CallObject(pFunc, pArgs);
   res_pc= PyComplex_AsCComplex(pValue);
   result= res_pc.real + res_pc.imag*I;
   return result;
}

============= Python code =====================================

# Evaluates Humbert's Phi_1(a,b,c;x,y) function.
from mpmath import *
def Phi_1(a, b, c, x, y):
   if abs(x) < 1:
      fi1= hyper2d({'m+n':, 'm':},{'m+n':}, x, y)
   else:
      fi1= nsum(lambda n: rf(a,n)*hyp2f1(a + n, b, c + n, x)*y**n/(rf(c,n)*fac(n)), [0,inf])
   return fi1

 

 

0 Kudos
Reply