MethodError for function calling with an argument a parametric composite type (struct)

Hi there

I have the following code, which, if necessary I might strip down.

using Parameters
using Unitful

@with_kw struct EosConst{T<:Real}
    w_0::T = -1.0
@with_kw struct EosCPL{T<:Real}
    w_0::T = -1
    w_a::T = 0

Eos = Union{EosConst, EosCPL}

@with_kw struct CosmoModel{T1<:Real,T2<:Unitful.Quantity,T3<:Eos}
    h_Hubble::T1 = 0.69
    Ω_m0::T1 = 0.3
    T_γ0::T2 = 2.75u"K"
    Ω_γ0::T1 = 0.0
    Ω_ν0::T1 = 0.0
    Ω_r0::T1 = Ω_γ0 + Ω_ν0; @assert Ω_r0 == Ω_γ0 + Ω_ν0
    Ω_n0::T1 = Ω_m0 + Ω_r0; @assert Ω_n0 == Ω_m0 + Ω_r0
    Ω_exo0::T1 = 0.7
    Ω_tot0::T1 = Ω_n0 + Ω_exo0; @assert Ω_tot0 == Ω_n0 + Ω_exo0
    Ω_K0::T1 = 0.0; @assert Ω_K0 == 1 - Ω_tot0
    eos::T3 = EosConst()

function E_Hubble(z; cosmo::CosmoModel)
    @unpack Ω_m0, Ω_r0, Ω_exo0, Ω_K0, eos = cosmo
    return sqrt(Ω_m0*(1 + z)^3 + Ω_r0*(1 + z)^4 + Ω_K0*(1 + z)^2 + Ω_exo0*(1 + z)^(3*(1 + eos.w_0)))

When I issue the commands:

c = CosmoModel()
E_Hubble(0.0, c)

the first one works ok, but the second one spits the following:

ERROR: MethodError: no method matching E_Hubble(::Float64, ::CosmoModel{Float64,Quantity{Float64,𝚯,Unitful.FreeUnits{(K,),𝚯,nothing}},EosConst{Float64}})
Closest candidates are:
  E_Hubble(::Any; cosmo) at /home/orca/Dropbox/research/modified_gravity/programs/mocalvao/julia/cosmo/src/background.jl:32
 [1] top-level scope at REPL[7]:1

What am I doing wrong?

E_Hubble expects cosmo as a keyword argument, and is getting it as a regular/positional argument instead.


How silly of me! Thanks a lot.

I would now like to generalize my (generic) function E_Hubble(z, c::CosmoModel) above, such that it has 2 distinct methods: one for the struct EosConst, and another for the struct EosCPL, which are present inside the struct CosmoModel, via the union’ed type Eos. How should I go about declaring these distinct methods, given that the direct argument of the function is a struct of type CosmoModel, not directly of EosConst or EosCPL ?

Another strategy is, of course, to insert an if block inside the current E_Hubble function to test, via typeof, for the 2 distinct substructs EosConst and EosCPL. In this case, I would circumvent having to define two distinct methods.

I wonder however about the differences in performance of these two approaches: (i) two methods somehow based on signature, (ii) or the last one, with just one method and an if block…

If more advisable, I can post a new topic…

Usually it’s best to start a new topic for visibility. I probably wouldn’t have seen this if I hadn’t left the window open for the rest of the day, since the topic is solved and the new question wasn’t a direct reply :wink:

You could declare two separate methods based on the parameters of CosmsoModel, like

function E_Hubble(z, cosmo::CosmoModel{T1, T2, EosCPL}) where {T1, T2}
function E_Hubble(z, cosmo::CosmoModel{T1, T2, EosConst}) where {T1, T2}

But it might make more sense to hand the work off to another method that dispatches directly on Eos, or to split the CosmoModel struct into smaller pieces.

1 Like

@tomerarnon Thanks. I had gathered both of your suggestions. I will try to code them, check and, if necessary, post a new topic.

1 Like