1

I inherited some code that looks like this:

Python -> File -> Modern Fortran -> File -> Python

where each File contains a simple array of reals.

I now need to run this program many times and the I/O is hurting me. I want to omit the files and read the Python output into Fortran and read the Fortran output back into Python.

I can omit the first file by calling the Fortran routine from Python and providing the reals as a series of string arguments.

## This Python script converts a to a string and provides it as 
## an argument to the Fortran script test_arg

import subprocess

a = 3.123456789
status = subprocess.call("./test_arg " + str(a), shell=True)

!! This Fortran script reads in a string argument provided by the 
!! above Python script and converts it back to a real.

program test_arg

  character(len=32) :: a_arg
  real*8      :: a, b

  call get_command_argument(1,a_arg)
  read(a_arg,*), a
  print*,a

  b = a*10

end program test_arg

What would a working code snippet look like to output the variable 'b' into another Python script without using an intermediate file?

I've read about f2py, but the amount of refactoring involved in turning the inherited Fortan scripts into Python modules is more than what I want to do.

astromonerd
  • 907
  • 1
  • 15
  • 32
  • 1
    Don't create Fortran program, create a subroutine. Or create a subroutine instead of the main program as an interface to the most part of the Fortran code. – Vladimir F Героям слава Mar 26 '17 at 18:43
  • 1
    You can have the fortran write its output to stdout (`write(*,*)b` ) and you should be able to read the result via subprocess. The fortran needs to be "clean", not writing anything else to stdout. (Actualy integrating the code is better, but this is simple) – agentp Mar 26 '17 at 18:53
  • 2
    I just want to add be careful when using `shell = True` it poses risks – gold_cy Mar 26 '17 at 19:00
  • Thanks. Below the subprocess command that calls the fortran script, can I put another subprocess command that reads stdout from fortran's write(*,*)? Would you be able to provide a minimum working example? – astromonerd Mar 26 '17 at 20:21
  • I've read about the risk of using shell=True, but I haven't figured out a better way to provide both the name of the script and arguments to it. I'm not particularly worried because I am the only user (but those could be my famous last words). – astromonerd Mar 26 '17 at 20:23
  • 1
    reading from process: http://stackoverflow.com/q/2082850/1004168. to get rid of shell you pass the arguments as a list, not one string. – agentp Mar 26 '17 at 22:02

2 Answers2

0

If you could rebuild the Fortran code as a library, you could use that from Python using in several ways.

Roland Smith
  • 42,427
  • 3
  • 64
  • 94
0

I've found that what suits my needs is the following:

## Sends a0 as a string to fortran script.
## Receives stdout from fortran, decodes it from binary to ascii,
## splits up values, and converts to a numpy array.

from subprocess import *
from decimal import Decimal as Dec

a0 = 3.123456789

proc = subprocess.Popen(["./test_arg", str(Dec(a0))], stdout=subprocess.PIPE)
out, err= proc.communicate()
result = np.array(out.decode('ascii').split(), dtype=float)
astromonerd
  • 907
  • 1
  • 15
  • 32