Reputation: 437
I'm trying to use FortranFile to get an output that I can use in my simulation code written in F95. I'm having troubles getting fortranfile to work properly. Maybe it's because I do not understand how it works. Here's my problem:
If I want to write a 1D array using FortranFile, it works fine:
nx = 128
bxo = np.zeros(nx, dtype=float)
bxo = something
import fortranfile as fofi
bxf=fofi.FortranFile('Fbx.dat',mode='w')
bxf.writeReals(bxo,prec='d')
bxf.close()
The above 1D version works like a charm. As soon as I try to do it for a 2D array, I get problems
nx = 128; ny = 128
bxo = np.zeros((nx,ny), dtype=float)
bxo = something
import fortranfile as fofi
bxf=fofi.FortranFile('Fbx.dat',mode='w')
bxf.writeReals(bxo,prec='d')
bxf.close()
When I try to do this, I get the following error:
---------------------------------------------------------------------------
error Traceback (most recent call last)
/Library/Frameworks/Python.framework/Versions/7.3/lib/python2.7/site-packages/IPython/utils/py3compat.py in execfile(fname, *where)
173 else:
174 filename = fname
--> 175 __builtin__.execfile(filename, *where)
/Users/parashar/Dropbox/sandbox/test2d.py in <module>()
130 vyf=fofi.FortranFile('Fvy.dat',mode='w')
131 vzf=fofi.FortranFile('Fvz.dat',mode='w')
--> 132 bxf.writeReals(bxo,prec='d')
133 byf.writeReals(byo,prec='d')
134 bzf.writeReals(bzo,prec='d')
/Users/parashar/Dropbox/sandbox/fortranfile.py in writeReals(self, reals, prec)
215 _fmt = self.ENDIAN + prec
216 for r in reals:
--> 217 self.write(struct.pack(_fmt,r))
218 self._write_check(length_bytes)
219
error: required argument is not a float
Any ideas what could be going on?
Thanks!
Upvotes: 1
Views: 1322
Reputation: 437
I like Emmet's suggestion but given that my knowledge of python is very basic, it would be a lot of effort for a short goal. I just realized that I could handle the situation in a slightly different manner.
Direct access files in Fortran do not have the unnecessary leading/trailing information that the usual unformatted fortran files do. So the simplest way to deal with unformatted data exchanged between Fortran and Python is to treat the files as direct access in Fortran. Here is an example of how we can use data to/from python/fortran.
Python code:
import numpy as np
nx=128; ny=128;
bxo=np.zeros((nx,ny),dtype=float)
bxo=something
bxf=open('Fbx.dat',mode='wb')
np.transpose(bxo).tofile(bxf) # We transpose the array to map indices
# from python to fortran properly
bxo.close()
Fortran code:
program test
implicit none
double precision, dimension(128,128) :: bx
integer :: NNN, i, j
inquire(iolength=NNN) bx
open(unit=23,file='Fbx.dat',form='unformatted',status='old',&
access='direct',recl=NNN)
read(23,rec=1) bx
close(23)
! Write it out to a text file to test it
! by plotting in gnuplot
do i=1,128; do j=1,128
write(23,*) i,j,bx(i,j)
enddo; enddo
end
Because we are using the standard binary formate to read/write data, this method will work with arrays of any size unlike the FortranFile method.
I have realized that by sticking to direct access files in Fortran, we can have wider compatibility with other languages e.g. Python, IDL etc. This way we do not have to worry about the weird leading trailing markers, endian-ness etc.
I hope this will help someone else in my situation too.
Upvotes: 1
Reputation: 6411
I've never had to do anything with Fortran and Python at the same time, and know absolutely nothing about fortranfile.py, but my best guess is that fortranfile is not numpy-aware.
When you use 1D numpy arrays, or Python arrays, lists, etc. the iteration in the last part of the stack trace suggests that it's expecting an iterable of numbers ("for r in reals"), whereas when you try to serialize a 2D numpy array, I'm not sure what it gets (i.e. what "r" ends up being), maybe an iterable of iterators, or an iterable of 1D arrays. In short, 'r' is not just the number that's expected ("required argument is not a float"), but something else (like a 1D array, list, etc.).
I would try have a look and see if there's an alternative to writeReals() in fortranfile and, if not, hack one in that can handle 2D arrays with a bit of copypasta.
I would start by putting in a diagnostic print before that "self.write()" line (217) that tells you what 'r' actually is, since it isn't the expected float.
Upvotes: 0