Reading Fortran-style Complex Numbers From File

Part of my inherited research code is a highly parallelized Fortran90 program that produces, as its primary output, a large text file (~1 GB) of complex numbers in the following format:

 (1.014631909321741E-002,-1.825468883204626E-002)

As part of my migration to Julia, I’m trying to reimplement the analysis code that would operate on this file, and I’m having the darndest time getting Julia to parse the data in the file as complex numbers. I can get as far as the following:

wfn = open("wfn.dat")

str = strip(readline(wfn), [' ', '(', ')'])

This produces the following output:

"1.014631909321741E-002,-1.825468883204626E-002"

However, attempts to use something like val = parse(ComplexF64, str) to convert this to a complex number fails because parse expects an imaginary unit specifier like im or i, which is obviously not there. The ideal result is that val is converted to a complex number whose real and imaginary parts are given by the two numbers in succession. Is there a straightforward way to do this.

(Side note, I’d love a format=“fortran” argument for parse() or readdlm(), especially since this is Fortran’s default complex number format. If this exists somewhere, please let me know.)

This is something I would just ask an AI like chatgpt or claude. They are incredibly good at this.

you want to split first, then parse:

ulia> s = "1.014631909321741E-002,-1.825468883204626E-002"
"1.014631909321741E-002,-1.825468883204626E-002"

julia> re, im = split(s, ',')
2-element Vector{SubString{String}}:
 "1.014631909321741E-002"
 "-1.825468883204626E-002"

julia> val = complex(parse(Float64, re), parse(Float64, im))
0.01014631909321741 - 0.01825468883204626im

If you can get your fortran script to output the correct syntax directly, this also works:

julia> s2 = "0.01014631909321741 - 0.01825468883204626im"
"0.01014631909321741 - 0.01825468883204626im"

julia> parse(ComplexF64, s2)
0.01014631909321741 - 0.01825468883204626im

Personally, I would just preprocess the file with a sed or perl 1-liner to strip out the parentheses (you could also do this in Julia), and read it in Julia as CSV. This will be a lot faster if you have large files, because packages like CSV.jl are highly optimized. It’s also easy.

For example, this seems way easier than the code using split to manually parse every line, and is probably faster (and almost definitely faster if you modify it to use CSV.jl):

using DelimitedFiles
data = readdlm(IOBuffer(replace(read("complex.dat", String), r"[()]"=>"")), ',')
cplx_array = @views complex.(data[:,1], data[:,2])

Thank you! That solves it nicely. For the benefit of future readers, here’s a simple function (incorporating @langestefan’s code) that reads Fortran-style complex numbers, albeit only 1 per line:

function read_fortran_complex(io::IOStream)
    # can remove single space from character list if file
    # has no preceding space
    line = strip(readline(io), [' ', '(', ')'])
    re, im = split(line, ',')
    val = complex(parse(Float64, re), parse(Float64, im))
    return val
end

# example w/ data file complex.dat

len = 1000 # change to number of entries in file
cplx_array = complex(zeros(len)) # initialize as complex to avoid conversion error

file = open("complex.dat")

for i in 1:len
    cplx_array[i] = read_fortran_complex(file)
end

Caveat that the above code should be considered functional, not optimal. There’s probably fancier/faster ways to do this, but this is what works for me.