openlang

Why is a Float64 replacing my struct?

I've encountered something I can't explain. My code passes several parameters around in a struct. Some functions accept it successfully, while another doesn't. Perhaps somebody else can spot the mistake I'm missing.

Everything in this MWE appears fine until the final line raises an error.

using FlexUnits: QuantFieldVector, DimsMod

using Revise

gravity = 9.81u"m/s^2"

net_load(diameter, config) = @. 2*config.initial_load*(sin(acos((config.drum+config.gap)/(config.drum+diameter)))) - π/4*(diameter^2 - config.core^2)*config.density*gravity

limited_load(diameter, config) = max.(net_load(diameter, config), config.min_load)

line_load(diameter, config) = @. (π/4*(diameter^2 - config.core^2)*config.density*gravity + limited_load(diameter, config))/(2*sin(acos((config.drum+config.gap)/(config.drum+diameter))))

mutable struct Carrier{T} <: QuantFieldVector{7,T}
    drum::Quantity{T, D"m"}
    gap::Quantity{T, D"m"}
    core::Quantity{T, D"m"}
    span::Quantity{T, D"m"}
    min_load::Quantity{T, D"N/m"}
    initial_load::Quantity{T, D"N/m"}
    density::Quantity{T, D"kg/m^3"}
end

config = Carrier(26u"in", 31u"mm", 110u"mm", 1.4u"m", 5u"lbf/in",14u"lbf/in", 860u"kg/m^3")
transition_diameter = 0.9u"m"

config.initial_load
net_load(440u"mm", config)
limited_load(440u"mm", config)
line_load(440u"mm", config)
ERROR: FieldError: type Float64 has no field `initial_load`; Float64 has no fields at all.
Stacktrace:
  [1] getproperty
    @ .\Base_compiler.jl:57 [inlined]
  [2] net_load(diameter::Quantity{Float64, StaticDims{m}}, config::Float64)
    @ Main .\REPL[83]:2
  [3] limited_load(diameter::Quantity{Float64, StaticDims{m}}, config::Float64)
    @ Main .\REPL[82]:2

The conversation continues 2

Follow the reasoning
  1. Permalink

    The final line invokes limited_load.(diameter, config). Since config is iterable, broadcasting here behaves rather like [limited_load(diameter, item) for item in config]. Each item apparently contains a field's value*, whose type is Float64 (T). Your net_load subsequently accesses item.initial_load on that Float64.

    *Edit: This reference manual (https://deduction42.github.io/FlexUnits.jl/stable/types/#QuantFieldArrray) confirms that unlike getproperty, getindex produces a numerical scalar rather than a Quantity.

    Generally I dislike the @. macro because it obscures which operations you intend to broadcast, resulting in errors like these. (You also have no real need for something like π ./ 4.)

    Indeed, I can't see why any broadcasting is necessary in line_load, limited_load or net_load here. In the last of those, for instance, don't all the variables on the definition's right hand side seem scalar? I'm not familiar with the meaning of these equations, but

    julia> line_load(diameter, config) = (π/4*(diameter^2 - config.core^2)*config.density*gravity + limited_load(diameter, config))/(2*sin(acos((config.drum+config.gap)/(config.drum+diameter))))
    line_load (generic function with 1 method)
    
    julia> line_load(440u"mm", config)
    2451.775693450669 kg/s²

    works without trouble (even leaving potentially unnecessary broadcasts in limited_load and net_load).

Other sides of the same question

  1. How can I subclass a class inside another class?

    Hi, In a package whose code is outside my control, there is a hierarchy of classes arranged as follows: I'm trying to add a w…

    Replies 1Latest activity scala
  2. Comparing have with let bindings in Lean4

    I've observed that these two expressions and behave identically. This also happens in theorem proofs. Are they interchangeabl…

    Replies 3Latest activity lean-4
  3. TypeScript Map initialization with string array entries

    I'm creating a Map whose entries each hold an array of strings. How can I declare its type and initialize it together in one…

    Replies 2Latest activity typescript