user1638145
user1638145

Reputation: 2049

Fortran: formatted read

I have a file looking like this:

startSpecifier

(  251)-0.0110365 (  168)-0.0110365 ( 1267) 0.0108601 (  980) 0.0108601 (

(  251)-0.0110365 (

endSpecifier

I don't know how often the format repeats per line in the infile.

I need to get arrays looking like this (for the upper example):

a=[251, 268, 1267, 980, 251]
b=-0.0110365, -0.0110365, 0.0108601,...]

Any suggestions as to how to tackle the problem?

Upvotes: 1

Views: 523

Answers (2)

Bálint Aradi
Bálint Aradi

Reputation: 3812

In my oppinion, you have basically two options:

  • You program a linked list in Fortran, read the file line by line, parse the lines and append the elements you extract into your linked lists. When the reading is finished, you convert your linked lists into arrays. We are doing that when reading in user data of unknown length in DFTB+, but that requires unfortunately quite a lot of programming.

  • Alternatively, you could use a script language to extract data from your input file and store in a more Fortran-friendly format. Below an example in Python, but you can use any other script language of your choice:

    from __future__ import print_function
    import sys
    import re
    
    PAT1 = re.compile(r"\(\s*(?P<int>\d+)\)")
    PAT2 = re.compile(r"\)\s*(?P<float>-?\d+\.\d+)\s*\(")
    
    txt = sys.stdin.read()
    ints = PAT1.findall(txt)
    floats = PAT2.findall(txt)
    
    print(len(ints))
    print(" ".join(ints))
    print(" ".join(floats))
    

    Store the script as convert.py and run it like:

    python convert.py < mydata.dat > newdata.dat
    

    where I assumed, that your data is stored in mydata.dat. The new file newdata.dat
    would then look like:

    5
    251 168 1267 980 251
    -0.0110365 -0.0110365 0.0108601 0.0108601 -0.0110365
    

    This you can easily parse with Fortran by reading the integer in the first line, allocate your integer and float array to the size given in it, and read in the two arrays with two read statements.

Upvotes: 1

I would use

do line = 1,nlines  !or just do and exit on end of file, it's up to you
    lower = (line-1)*items_per_line + 1
    upper = line*items_per_line
    read (unit,fmt='(999(tr1,i5,tr1,f11))') (a(i),b(i),i=lower,upper)
end do

Add any other read(unit,*) to skip lines where apropriate.

If the field widths are really fixed, as it seems from your example.

Upvotes: 0

Related Questions