1

I am using some fortran code in python via f2py. I would like to redirect the fortran output to a variable I can play with. There is this question which I found helpful. Redirecting FORTRAN (called via F2PY) output in Python

However, I would also like to optionally have the fortran code write to the terminal as well as recording it. Is this possible?

I have the following silly class which I cobbled together from the question above and also from http://websrv.cs.umt.edu/isis/index.php/F2py_example.

class captureTTY:
    ''' 
    Class to capture the terminal content. It is necessary when you want to
    grab the output from a module created using f2py.
    '''
    def __init__(self,  tmpFile = '/tmp/out.tmp.dat'):
        ''' 
        Set everything up
        '''
        self.tmpFile = tmpFile       
        self.ttyData = []
        self.outfile = False
        self.save = False
    def start(self):
        '''
        Start grabbing TTY data. 
        '''
        # open outputfile
        self.outfile = os.open(self.tmpFile, os.O_RDWR|os.O_CREAT)
        # save the current file descriptor
        self.save = os.dup(1)
        # put outfile on 1
        os.dup2(self.outfile, 1)
        return
    def stop(self):
        '''
        Stop recording TTY data
        '''
        if not self.save:
            # Probably not started
            return
        # restore the standard output file descriptor
        os.dup2(self.save, 1)
        # parse temporary file
        self.ttyData = open(self.tmpFile, ).readlines()
        # close the output file
        os.close(self.outfile)        
        # delete temporary file
        os.remove(self.tmpFile)

My code currently looks something like this:

from fortranModule import fortFunction
grabber = captureTTY()
grabber.start()
fortFunction()
grabber.stop()

My idea is to have a flag called silent that I could use to check whether I allow the fortran output to be displayed or not. This would then be passed to the captureTTY when I construct it, i.e.

from fortranModule import fortFunction
silent = False
grabber = captureTTY(silent)
grabber.start()
fortFunction()
grabber.stop()

I am not really sure how to go about implementing this. The obvious thing to do is:

from fortranModule import fortFunction
silent = False
grabber = captureTTY()
grabber.start()
fortFunction()
grabber.stop()
if not silent:
    for i in grabber.ttyData:
        print i

I am not a big fan of this, as my fortran method takes a long time to run, and it would be nice to see it updated in real time and not just at the end.

Any ideas? The code will be run on Linux & Mac machines, not windows. I've had a look around the web, but haven't found the solution. If there is one, I am sure it will be painfully obvious!

Cheers,

G

Clarification:

From the comments I realise that the above isn't the clearest. What I currently have is the capability to record the output from the fortran method. However, this prevents it from printing to the screen. I can have it print to the screen, but then cannot record it. I want to have the option to do both simultaneously, i.e. record the output and have it print to the screen in real time.

Just as an aside, the fortran code is a fitting algorithm and the actual output that I am interested is the parameters for each iteration.

Community
  • 1
  • 1
Ger
  • 958
  • 1
  • 8
  • 11
  • maybe you don't like this idea, but what I usually do is simply to ask fortran write the output to a log file with frequent flushing, then ask python or other scripts to peek into the log. – nye17 May 29 '12 at 17:44
  • 1
    What does the fortran output look like? Is it an array of numbers? If so, f2py should be able to pass that directly back as a numpy array. – mgilson May 29 '12 at 17:55
  • @mgilson & nye17 I have clarified the issue a bit, see above. I think I may not have been the clearest in what my issue is. – Ger May 29 '12 at 18:10
  • I'm not sure if this would work or not -- but you could try `tail -F` on the temporary file. (in `start`: `self.tail=subprocess.Popen('tail -F %s'%self.tmpFile)` and then in `stop` : `self.tail.terminate()` to make sure it gets shut down...) -- However, this may direct the output to your logfile twice. I'm not sure. – mgilson May 29 '12 at 18:33
  • 3
    @user1027686 ok, just saw your clarification. Then, my naive approach would be ask the fortran to print to both stdout and a log file. While you have the flag to control where you want to print, you can set your python to retrieve records from the log file as well. – nye17 May 29 '12 at 21:27
  • @nye17 Thanks for the idea - I just tried it there. I had to modify it slightly, self.tail = subprocess.Popen('exec tail -f %s'%self.tmpFile, shell = 'bash'). Without the exec it would fork the tail process and it would not be killed by the terminate() call. It doesn't work though: it doesn't print to the screen and confusingly adds mainly duplicate lines to the log file. Thanks for the idea! – Ger May 30 '12 at 10:16
  • @mgilson Opps! The above comment was meant for you. Can't edit it now. – Ger May 30 '12 at 10:35
  • @user1027686 It seems weird that the tail process wouldn't be killed by terminate. It's not terribly weird that the output gets sent to the log twice -- apparently the child inherits the terminal descriptors of it's parent. Out of curiosity, what happens if you send the output of tail to stderr instead of stdout? (`self.tail = subprocess.Popen('exec tail -f %s 1>&2'%self.tmpFile, shell = 'bash')`) – mgilson May 30 '12 at 11:50

1 Answers1

0

Have you tried something like this in the Fortran subroutine? (Assuming foo is what you want to print, and 52 is the unit number of your log file)

write(52,*) foo
write(*,*) foo

This should print foo to the log file and to the screen.

astay13
  • 6,857
  • 10
  • 41
  • 56