Problems reading data with JLD (edited title)

OK. I’ve never used either of these packages before, but I think it’s roughly this:

The thing returned from Interpolations is callable, as in the

println(f(x))

line in f2

When JLD loads the interpolations object, if it isn’t able to see an example of one, it reconstructs it as something that is not callable. Hence all the type warnings. Note that the type it generates is JLD.var"##Interpolations.Extrapolation....

This is ugly, but you can fix it by having an otherwise pointless call to Interpolate in f2:

function f3()
    # does nothing except exist
    fxx = LinearInterpolation(vec(collect(1.0:5.0)), rand(Float64,5)) 
    f2 = JLD.load("test.jld","f")
    println(f2(3))
end

I’m sure the JLD authors can suggest something more elegant, but that works.

Graham

also works if you explicitly import LinearInterpolation.

using Interpolations:LinearInterpolation,vec
...

Graham

I’m afraid this and your other suggestion didn’t work for me.

I took the drastic step of reading the documentation for JLD (schoolboy error, I know, but it is very short), and found that, when you save the variable, you can force JLD to load the appropriate type along with the variable from the file.

module Testmodule

using JLD, Interpolations

export Function1, Function2

function Function1()
    f = LinearInterpolation(vec(collect(1.0:5.0)), rand(Float64, 5))
    jldopen("test.jld", "w") do file
        addrequire(file, Interpolations)
        write(file, "f", f)
    end
end

function Function2(x::Float64)
    f = load("test.jld", "f")
    f(x)
end

end

which gives

julia> include("Testmodule.jl");

julia> using .Testmodule

julia> Function1()

julia> Function2(1.5)
0.23688469834108172

If this works for my actual code and nobody objects, I’m going to mark this as the Solution.

3 Likes

Bad news I’m afraid. Whilst the method above works for that test case, the problem is that it doesn’t just allow the variable to be loaded from the file; it actually imports the module (‘Interpolations’ in the example above) and then loads the variable. This means that you have to be really careful not to import the module twice, because the ‘load’ statement sneaks the module in with the data. It seems to me this is not a good feature, basically booby-trapping the saved file (although admittedly self-booby-trapped if it’s my file). I’ve just been tying myself in knots trying not to do just that with my actual code. This is proving irritating and, under the influence of Father’s Day beers, very difficult. I will return to it tomorrow when sober and report back. I expect I’m making a meal of it and just need to take a deep breath and think about it carefully.

I would also say that

is certainly true, and I have been using

 push!(LOAD_PATH, pwd());

to make sure I get this right.

I found that the following code works if you break it into two files in the same directory.

Run_Script.jl

cd(@__DIR__)
push!(LOAD_PATH, pwd())
using Testmodule, JLD, Interpolations

Function1()

x = Function2(1.5)

println(x)

Testmodule.jl

module Testmodule
    using JLD, Interpolations
    export Function1, Function2

    function Function1()
        f = LinearInterpolation(vec(collect(1.0:5.0)), rand(Float64,5))
        save("test.jld", "f", f)
    end

    function Function2(x::Float64)
        f = load("test.jld","f")
        return f(x)
    end
end

Here is the result I get:

julia> x = Function2(1.5)
0.20506794337594836

julia> println(x)
0.20506794337594836

However, if I do not call JLD and Interpolations in the top level script Run_Script.jl, it produces the same method error that you found. I think this is the problem greg_plowman was referring to. It is not clear to my why you need to call JLD and Interpolations in Main, but it solves the problem. Presumably you can use reexport inside your module if you don’t want to invoke JLD and Interpolations manually in your script.

Let me start by thanking everybody for helping me with this. I looked at Reexport.jl (not what I wanted to be reading first thing on a Monday morning with a slight hangover) and I pondered all my exertions over the weekend, and I decided that, as an applied mathematician, and not a computer scientist, I can do without all this hassle. I’ve therefore rewritten my code so that it save the large matrices that underlie my linear interpolants, so now, instead of trying to read and write interpolants and the type ‘beamparams’ that I defined, my code reads and writes the raw data and reconstructs everything whenever it runs. This is a tiny overhead that gives me no difficulties, and I now have a module, which I can try to package later.

It seems to me that if IO of nonstandard data is so difficult and buggy, somebody really ought to sort it out (presumably the author of JLD.jl). Is there any way of changing the title of this thread so that is specifically relates to JLD?

Thanks again,

JB

The method error was indeed very strange and seems to be a bug. This is the first time I have encountered an error like this. I can say that this experience is not typical. It might be a good idea to open an issue with JLD and provide your minimum working example.

As an aside, If you decide to turn your project into a package (even if it is something you only use locally), I recommend using PkgTemplates to initialize your package. There is small upfront investment in learning the setup, but it helps make your code modular and reusable. For scripts that call your packages, I recommend project specific environments because it minimizes version conflicts and you can control the versions of your dependencies. Doing so ensures that your code will run a year later. Otherwise, there is a risk that a dependency might have a breaking change that you may want to deal with at a later time.

You should be able to scroll up to the title in this thread and select the pencil icon to change the title.

1 Like

There are several threads here on discourse where similar issues have been discussed. There is, to my knowledge, no truly reliable way of saving and reloading user defined types. If I’m wrong about this, I would really, really like someone to tell me.

The problem is hard to solve because the type system is complex (parametric types with many possible constructors).

One solution that has been proposed a few times: Write a function that handles the roundtrip conversion from user defined objects to simpler, reliably loaded types (e.g. Arrays of floats). This seems to be the solution that jbpatzer has finally adopted. In this case, it seems the most robust solution to me.

2 Likes