Why does my struct become Float64

I am running into an issue I do not understand. I have some code in which I pass a number of parameters as a struct. It works for some of the functions, but not for another function. I think I need another set of eyes to see where I am going wrong.

All the code in the MWE below seems to work except the last line errors.

using FlexUnits: QuantFieldVector, DimsMod

using Revise

g = 9.81u"m/s^2"

nrr_theoretical(dia, W) = @. 2*W.dnl_start*(sin(acos((W.dd+W.g)/(W.dd+dia)))) - π/4*(dia^2 - W.dc^2)*W.ρ*g

nrr_min(dia, W) = max.(nrr_theoretical(dia, W), W.rrl_min)

dnl_min(dia, W) = @. (π/4*(dia^2 - W.dc^2)*W.ρ*g + nrr_min(dia, W))/(2*sin(acos((W.dd+W.g)/(W.dd+dia))))

mutable struct Foo{T} <: QuantFieldVector{7,T}
        dd::Quantity{T, D"m"}
        g::Quantity{T, D"m"}
        dc::Quantity{T, D"m"}
        ds::Quantity{T, D"m"}
        rrl_min::Quantity{T, D"N/m"}
        dnl_start::Quantity{T, D"N/m"}
        ρ::Quantity{T, D"kg/m^3"}
end

W = Foo(24u"in", 28u"mm", 100u"mm", 1.3u"m", 4u"lbf/in",12u"lbf/in", 835u"kg/m^3")
diatransition = 0.8u"m"

W.dnl_start
nrr_theoretical(400u"mm", W)
nrr_min(400u"mm", W)
dnl_min(400u"mm", W)
ERROR: FieldError: type Float64 has no field `dnl_start`; Float64 has no fields at all.
Stacktrace:
  [1] getproperty
    @ .\Base_compiler.jl:57 [inlined]
  [2] nrr_theoretical(dia::Quantity{Float64, StaticDims{m}}, W::Float64)
    @ Main .\REPL[77]:1
  [3] nrr_min(dia::Quantity{Float64, StaticDims{m}}, W::Float64)
    @ Main .\REPL[76]:1

Your last line calls nrr_min.(dia, W). One can iterate over W, so that this broadcast is similar to [nrr_min(dia, x) for x in W]. Every x is (apparently) the value of a field*, which has type Float64 (T). In nrr_theoretical you then call x.dnl_start for a Float64.

*Edit: In the documentation it is indeed mentioned that getindex (in contrast to getproperty) will return a numerical scalar, not the Quantity.

In general I’m not a fan of the @. macro, as you lose control over what operations you actually want to broadcast, which leads to these kinds of errors. (Additionally, you really don’t need e.g. π ./ 4.)

In fact in this example I’m not sure why we want to broadcast in dnl_min, nrr_min or nrr_theoretical at all. In the latter for example all variables in the definition (on the right hand side) look to be scalars? I don’t understand what the equations are supposed to mean, but

julia> dnl_min(dia, W) = (π/4*(dia^2 - W.dc^2)*W.ρ*g + nrr_min(dia, W))/(2*sin(acos((W.dd+W.g)/(W.dd+dia))))
dnl_min (generic function with 1 method)

julia> dnl_min(400u"mm", W)
2101.522022957716 kg/s²

runs fine (even with possibly useless broadcasts in nrr_min and nrr_theoretical).

Thank you for the clear explanation, the phenomena that I was seeing now makes sense.