1

I'm currently learning Julia and i'm trying to translate a Fortran77 code, but i got this error message and i can't see from where the issue is coming from.

using DelimitedFiles, DataFrames

function diprcbk(iii,x,r)

    if iii==0
        df = DataFrame(readdlm("dipgbw800hp.dat"), [:ya,:xa, :ra, :da])
        ya1=[]
        xa1=[]
        for ix in 1:801:370863
            YA1 = df.ya[ix]
            XA1 = df.xa[ix]
            append!(ya1, YA1)
            append!(xa1, XA1)
        end


        ya=[]
        xa=[]
        da=[]
        ra=[]
        ral=[]
        for ix in 1:1:463
            XA=xa1[ix]
            YA=ya1[ix]
            append!(ya, YA)
            append!(xa, XA)
            DA=df[df.ya .== ya[ix], :da]
            push!(da, DA)

            for ir in 1:1:801
                RA = df.ra[ir]
                RAL=log(RA)
                append!(ra, RA)
                append!(ral, RAL)
            end
        end  
    end
    if iii==1
        df = DataFrame(readdlm("dipmv800hp.dat"), [:ya,:xa, :ra, :da])
        ya1=[]
        xa1=[]
        for ix in 1:801:370863
            YA1 = df.ya[ix]
            XA1 = df.xa[ix]
            append!(ya1, YA1)
            append!(xa1, XA1)
        end
    end

        ya=[]
        xa=[]
        da=[]
        ra=[]
        ral=[]
        for ix in 1:1:463
            XA=xa1[ix]
            YA=ya1[ix]
            append!(ya, YA)
            append!(xa, XA)
            DA=df[df.ya .== ya[ix], :da]
            push!(da, DA)

            for ir in 1:1:801
                RA = df.ra[ir]
                RAL=log(RA)
                append!(ra, RA)
                append!(ral, RAL)
            end
        end   

    if r < ra[1]
        return 0

    #####Maybe the error is somewhere here?#####
    elseif r>= ra[1] && r<=ra[801]

        y = float(log((xa[1])/x))

        for ix in 1:1:(length(ya)-1)

            if y>ya[ix] && y<ya[ix+1]

                indx=ix

                for ir in 1:1:(802-1)
                    if r>ra[ir] && r<ra[ir + 1]
                        indr=ir

                        rl = log(r)

                        function xlinter(x1,x2,y1,y2,x)
                            xlinter = float((y2-y1)*(x-x1)/(x2-x1)+y1)
                            return xlinter
                        end

                        dindr=xlinter(ya[indx],ya[indx+1],da[indx][indr],da[indx+1][indr],y)
                        dindrp1=xlinter(ya[indx],ya[indx+1],da[indx][indr+1],da[indx+1][indr+1],y)
                        diprcbk=xlinter(ral[indr],ral[indr+1],dindr,dindrp1,rl)

                        return diprcbk


                    end
                end
            end
        end  
    ############################################

    elseif r>ra[801]
        return 1

    end

end

MV=[]
GBW=[]
R=[]
for i in -90:1:20
    r=10^((0.1)*i)
    aaa=diprcbk(0, 10^(-4), r)
    bbb=diprcbk(1, 10^(-4), r)
    append!(R, r)
    append!(GBW, aaa)
    append!(MV, bbb)
end

MethodError: objects of type Float64 are not callable

Maybe you forgot to use an operator such as *, ^, %, / etc. ?

Stacktrace:

[1] diprcbk(iii::Int64, x::Float64, r::Float64)

@ Main .\In[25]:94

[2] top-level scope

@ .\In[26]:6

[3] eval

@ .\boot.jl:368 [inlined]

[4] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String)

@ Base .\loading.jl:1428

Henrique
  • 15
  • 4
  • Hi! Providing a runnable code segment helps a lot with debugging such issues. This code isn't runnable without the `.dat` files it tries to read. Can you make a version that's independently runnable that uses some sample data? – Sundar R Oct 22 '22 at 07:18
  • At a glance, there doesn't seem to be an obvious place that this error could occur with this code, so it's also possible that the issue is due to some code run in a previous cell. Could you try restarting the notebook and running just these two cellls, and verify whether the error occurs in that case? – Sundar R Oct 22 '22 at 07:19
  • 1
    Initializing your vectors like this: `R=[]`, will make your code extremely slow, and so will filling them by repeatedly calling `append!`. It's is better to specify the correct element type, and pre-allocate when that information is available. – DNF Oct 22 '22 at 07:43
  • @SundaR Hi!! I'll try to make the version you are saying and edit my question with this version and you tell me if that's what you are asking for. About the second message, the error occour only in the cell where i set the values of `diprcbk` function (aaa and bbb). – Henrique Oct 22 '22 at 08:44
  • @DNF Thanks for the tip! I will try to implement this! – Henrique Oct 22 '22 at 08:47
  • @HenriqueR.MartinsFontes I could locate the error's root if I had the `.dat` file. – Shayan Oct 22 '22 at 08:47
  • @fandak You can download it from here: http://gaes.usc.es/phenom/rcbk/ it will give you the Fortran77 code with the `.dat` files – Henrique Oct 22 '22 at 08:52
  • @HenriqueR.MartinsFontes, Ok, I'm on it. – Shayan Oct 22 '22 at 08:54
  • 1
    The code has been written inefficiently. After a little enhancement, I can run it for 20 iterations. I mean, from `i=-90` into `i=-70`. But after that, there's an index error (`BoundsError`) in calculating the `dindr` variable. Are you sure about the code? This is the content of `R` for `i=-70`: `1.0e-9, 1.2589254117941663e-9, 1.584893192461111e-9, 1.9952623149688745e-9, 2.511886431509582e-9, ..., 3.981071705534969e-8, 5.0118723362727144e-8, 6.30957344480193e-8`. – Shayan Oct 22 '22 at 09:36
  • 1
    Hm. I just realized that the code for `iii==0` and `iii==1` branches are identical. Is that correct? Why not just change the file name instead of repeating all that code? – DNF Oct 22 '22 at 09:50

2 Answers2

2

The error message suggests that, at some point, your code has changed the value of a symbol that was originally defined as a function to have a value of a Float64. Then, when your code tries to apply the symbol as a function, it discovers too late that the symbol is a numeric value instead. Originally I thought your redefinition of diprcbk was the problem, but I'm not sure now.

But a problem I did notice is that at one point this line:

bbb=diprcbk(1, 10^(-4), r)

returns nothing. I think this is because you have this syntax:

if x
...
elseif
...
elseif
...
end

which returns nothing if none of the conditions are met. You should probably have a final "else" to catch all the conditions, so that the function always returns a number to the caller.

daycaster
  • 2,655
  • 2
  • 15
  • 18
2

Some initial hints for writing efficient Julia code:

  • Don't define a function inside another function if it's not necessary!
  • Don't define a vector like foo = []. Pre-define it and change its content! like: Array{Float64, 1}(undef, 50) this is a pre-defined vector since I wrote Array{..., 1} with length of 50. Also, this prevents pushing and appending iteratively, which have high computation costs.
  • Don't read the data twice (or even more)! You are reading the *.dat files up to 111 times!! This is a disaster and slows down your code too much!

Here is what you can begin with (I'm sure that you can write much better than this, but it's beyond the scope of this answer, and it's up to your effort):

const df1 = DataFrame(readdlm("dipgbw800hp.dat"), [:ya,:xa, :ra, :da])
const df2 = DataFrame(readdlm("dipmv800hp.dat"), [:ya,:xa, :ra, :da])

function xlinter(x1,x2,y1,y2,x)
    xlinter = float((y2-y1)*(x-x1)/(x2-x1)+y1)
    return xlinter
end

function diprcbk(iii,x,r)

    if iii==0
        # df = DataFrame(readdlm("dipgbw800hp.dat"), [:ya,:xa, :ra, :da])
        df = df1
        ya1= Array{Union{Float64, Vector{Float64}}, 1}(undef, 463)
        xa1= Array{Union{Float64, Vector{Float64}}, 1}(undef, 463)
        for (iter,ix) in enumerate(1:801:370863)
            YA1 = df.ya[ix]
            XA1 = df.xa[ix]
            ya1[iter] = YA1
            xa1[iter] = XA1
        end


        ya=Array{Union{Float64, Vector{Float64}}, 1}(undef, 463)
        xa=Array{Union{Float64, Vector{Float64}}, 1}(undef, 463)
        da=Array{Union{Float64, Vector{Float64}}, 1}(undef, 463)
        ra=Array{Union{Float64, Vector{Float64}}, 1}(undef, 801)
        ral=Array{Union{Float64, Vector{Float64}}, 1}(undef, 801)
        for (iter, ix) in enumerate(1:463)
            XA=xa1[ix]
            YA=ya1[ix]
            ya[iter] = YA
            xa[iter] = XA
            DA=df[df.ya .== ya[ix], :da]
            da[iter] = DA

            for (iter1,ir) in enumerate(1:801)
                RA = df.ra[ir]
                RAL=log(RA)
                ra[iter1] = RA
                ral[iter1] = RAL
            end
        end
    end
    if iii==1
        # df = DataFrame(readdlm("dipmv800hp.dat"), [:ya,:xa, :ra, :da])
        df = df2
        ya1=Array{Union{Float64, Vector{Float64}}, 1}(undef, 463)
        xa1=Array{Union{Float64, Vector{Float64}}, 1}(undef, 463)
        for (iter, ix) in enumerate(1:801:370863)
            YA1 = df.ya[ix]
            XA1 = df.xa[ix]
            ya1[iter] = YA1
            xa1[iter] = XA1
        end

        ya=Array{Union{Float64, Vector{Float64}}, 1}(undef, 463)
        xa=Array{Union{Float64, Vector{Float64}}, 1}(undef, 463)
        da=Array{Union{Float64, Vector{Float64}}, 1}(undef, 463)
        ra=Array{Union{Float64, Vector{Float64}}, 1}(undef, 801)
        ral=Array{Union{Float64, Vector{Float64}}, 1}(undef, 801)
        for (iter, ix) in enumerate(1:463)
            XA=xa1[ix]
            YA=ya1[ix]
            ya[iter] = YA
            xa[iter] = XA
            DA=df[df.ya .== ya[ix], :da]
            da[iter] = DA

            for (iter1, ir) in enumerate(1:801)
                RA = df.ra[ir]
                RAL=log(RA)
                ra[iter1] = RA
                ral[iter1] = RAL
            end
        end
    end

    if r < ra[1]
        return 0

    #####Maybe the error is somewhere here?#####
    elseif r>= ra[1] && r<=ra[801]

        y = float(log((xa[1])/x))

        for ix in 1:(length(ya)-1)

            if y>ya[ix] && y<ya[ix+1]

                indx=ix

                for ir in 1:801
                    if r>ra[ir] && r<ra[ir + 1]
                        indr=ir

                        rl = log(r)

                        dindr=xlinter(ya[indx],ya[indx+1],da[indx][indr],da[indx+1][indr],y)
                        dindrp1=xlinter(ya[indx],ya[indx+1],da[indx][indr+1],da[indx+1][indr+1],y)
                        diprcbk=xlinter(ral[indr],ral[indr+1],dindr,dindrp1,rl)

                        return diprcbk


                    end
                end
            end
        end
    ############################################

    elseif r>ra[801]
        return 1

    end
end

MV=Array{Float64, 1}(undef, 111)
GBW=Array{Float64, 1}(undef, 111)
R=Array{Float64, 1}(undef, 111)
for (iter, i) in enumerate(-90:20)
    @show i
    r=10^((0.1)*i)
    aaa=diprcbk(0, 10^(-4), r)
    bbb=diprcbk(1, 10^(-4), r)
    R[iter] = r
    GBW[iter] = aaa
    MV[iter] = bbb
    @show R[1:iter]
end

Please check if the output is what it has to be.
I used the @show macro to monitor the result of R iteratively. So you can remove them if you're done with the code.

What I have changed in your source code:

  1. Moving the xlinter function definition outside of the diprcbk function.
  2. Changing all *=[] definitions into Array{*, 1}(undef, *) with suitable length and element type.
  3. Using an iterator in for loops to replace the calculated values with the pre-defined ones through utilizing the enumerate function.
  4. Some unnecessary step lengths in a:*:b were removed. Example: a:1:b has a step equal to 1, and we can omit the 1. So a:b would be enough. Please check for further ones that might have been forgotten.
  5. Two variables, named df1 and df2 as two constant global variables created outside of the diprcbk definition. This highly improves runtime. Accordingly, df = DataFrame(readdlm("*.dat"), [:ya,:xa, :ra, :da]) was replaced with df = df1 or df = df2.
Shayan
  • 5,165
  • 4
  • 16
  • 45
  • A very helpful answer! But out of interest, what's the cause of the original error: `MethodError: objects of type Float64 are not callable`? – daycaster Oct 22 '22 at 11:01
  • 1
    @daycaster, Honestly, I couldn't reproduce the error. Because the code was terribly slow, I couldn't wait for the error to show up. So I decided to enhance the code slightly to reduce the runtime and then wait for the error. Luckily the few enhancements were enough to alleviate the issue. Although, many other things can make the code far better. Still, it's not optimal from my sight. – Shayan Oct 22 '22 at 11:36
  • I thought it might be using the function name `diprcbk` as a variable name later. But wasn't sure. – daycaster Oct 22 '22 at 11:50
  • 1
    I think the two branches (for `iii`) are identical. Better to remove the branch and just pass the dataframes in as function arguments. – DNF Oct 22 '22 at 11:53
  • @DNF Indeed, they're redundant. I hand over those enhancements for the OP to deal with since the aim of the question is something else. – Shayan Oct 22 '22 at 12:03
  • @daycaster I didn't get how the name might cause casualties. – Shayan Oct 22 '22 at 12:05
  • @fandak Thank you very much for point out my mistakes and for the hints!!! When i run your version of the code, this error appears: `Cannot convert an object of type Vector{Any} to an object of type Union{Float64, Vector{Float64}}`, so i removed the `Union` and left averything as `Array{Float64, 1}`, except for `da` (here i left as `Array{Vector{Float64}, 1}` ). Also, for some reason the code in julia is slower than the code in python...i guess i can't reproduce the speed of Fortran in Julia or in Python. Again, thank you for the detailed answer, it helped me a lot! – Henrique Oct 24 '22 at 01:00
  • Also wanna thanks DNF and daycaster for contributing to the error discussion! – Henrique Oct 24 '22 at 01:04
  • For the record, the code is working, it is giving the expected values. – Henrique Oct 24 '22 at 01:06