I am working with a very complex scientific Fortran program that I want to refractor so that it can be mostly called from Python.
My general strategy is to make wrapper functions that can be called by Cython. The big problem is that this fortran program has a LOT of different IO calls scattered throughout it, all of which have hard-coded file-handle numbers (not sure the correct word). I read that it is difficult to mix IO between C and Fortran, so my past strategy was to refactor all of these IO calls to C in one shot. However, many are quite complex so I inevitably introduce some bug, and then I can’t track down where the bug is from due to the number of different IO calls.
I would like to take a much more gradual approach, move one IO call at a time to a C function and test to make sure there are no bugs. But I have no idea how I can mix IO between C, Python, and Fortran (with hard coded file-handle numbers!)
If using complex Fortran descriptors for output I find changing to write to an internal file and then calling a simple C I/O routine that just prints a string works best.
A Fortran file unit number can be anything other than INPUT_UNIT, OUTPUT_UNIT and ERROR_UNIT (which are 5, 6 and 0, in most cases).
You can even ask the open statement to give you an unused unit number with NEWUNIT.
And for the mixing of languages: as @urbanjost suggested, an easier approach would be to return strings to the Python side —in Fortran, for I/O purposes, a string is deemed “internal file”.
I agree that for output just sending a string to C/Python is easiest, but for input it is much more difficult. The files being read are quite complex and I don’t see how to move it to C all at once without introducing errors that are very hard to track down.
Is there any info about how compatible file reading between python/C and Fortran? that is, if I open a file in Fortran with some file unit, either hardcoded or opend with NEWUNIT, and I also did file IO in python/C would there be any issues or conflicts?
From my personal experience doing a similar project, a lot of the work ended up being hunting down memory leaks in allocated-for-lifetime-of-program module variables (eigenvectors, eigenvalues, densities, that kind of thing) that ordinarily Fortran programmers wouldn’t care about when viewing program invocation as a single event (why bother deallocating all that stuff when the process is going to exit and the OS is going to reclaim it anyway?) but which become critical when you’re regularly invoking the “program” as a subroutine within another virtual memory space.
Fortunately the code in question already had some “useless” global deallocators subroutines as a finalization step where the big arrays were already handled, but I still had to do some gardening work for all the pesky small arrays that accumulated over time.
I also seem to recall us needing to do something a little different for the unit numbers, but I would need to go back and look at the code to refresh my memory.