Calling a function with 2 arguments of type Float64 and a struct, via its dotted version

Hi there,
I have defined a struct and a function (at the Julia REPL) like:

using Parameters

@with_kw struct Cosmo_model
Omega_m0::Float64 = 0.3
Omega::FLoat64_Lambda0 =0.7
end

function E_Hubble(z::Float64, cosmo::Cosmo_model)
@unpack Omega_m0, Omega_Lambda0 = cosmo
sqrt(Omega_m0*(1 + z)^3 + Omega_Lambda0)
end

After defining:

cosmo = Cosmo_model()

when I call E_Hubble with the first argument a “scalar”, such as:

E_Hubble(1.0, cosmo)

it works fine. However, I could not manage to make it work with an array, with its dotted version, such as:

z = [0.0, 1.0]
E_Hubble.(z, cosmo)

I get the following error:

ERROR: MethodError: no method matching length(::Supercosmo_model)
Closest candidates are:
length(::Core.MethodTable) at reflection.jl:957
length(::CompositeException) at task.jl:41
length(::Base.Iterators.Flatten{Tuple{}}) at iterators.jl:1061

I then have 2 questions:

(1) how can I make it work with an array for the first argument?

(2) is the general way I have coded the struct and the function above the best one, under all aspects, including performance? Should I really use the Parameters package or should I stick to Julia core? Any specific comments are very much welcome, since this is one of my first codings in Julia…

Thanks a lot!

The problem happens because Julia is trying to broadcast over cosmo as if it were some kind of array or other container (that’s the default behavior of broadcasting). To tell Julia to treat cosmo as a scalar, you can do:

E_Hubble.(z, Ref(cosmo))

where the Ref type acts as an instruction to treat its argument as a scalar.

To tell Julia to treat all Cosmo_model instances as scalars in broadcasting, you can do:

Base.broadcastable(s::Cosmo_model) = Ref(s)

and then E_Hubble.(z, cosmo) will just work. In other words, this tells Julia that any Cosmo_model should always be wrapped in a Ref (and thus treated as a scalar) automatically when broadcasting.

Your code looks fine, but it will be easier to read if you can quote your code so that it is formatted properly.

One thing I would mention is that structs in Julia are almost always written LikeThis instead of Like_this, so I would have done:

@with_kw struct CosmoModel
  ...
end

As for using Parameters.jl, it’s a really great tool, and there’s no reason not to use it if it fits your needs. One of the most important features of Julia is the fact that “core” Julia code is not inherently faster or better than anything you can write in your own code or find in a package.

5 Likes

Thanks for the prompt and informative reply.

I would like to further plot and use @manipulate, like:

z = 0.0:0.01:3.0
Omegas = 0.1:0.01:1.0
mp = @manipulate for Omega_m0 in Omegas
  cosmo = Cosmo_model(Omega_m0, Omega_Lambda0)
  E_H = E_Hubble.(z, Ref(cosmo))
  plot(z, E_H)
end

However, no plot is generated at all :frowning: