Understanding ModelingToolkit connectors and components

Ok so I think I managed to find the missing part. It does not seem to be enough to state a value for the external forcing directly, so I created an additional Constant3 block to handle such forcings. This, with some corrections based on ModelingToolkitStandardLibrary.jl/src/Mechanical/TranslationalPosition/TranslationalPosition.jl at v2.3.4 · SciML/ModelingToolkitStandardLibrary.jl · GitHub, gives

# Example to demonstrate the trajectory of a moving mass in 3D using ModelingToolkit and modified ModelingToolkitStandardLibrary components
using ModelingToolkit, LinearAlgebra, DifferentialEquations
using ModelingToolkitStandardLibrary.Blocks: RealInput
using GeometryBasics, GLMakie

@variables t
D = Differential(t)

@connector Flange3 begin
    s(t)[1:3] = zeros(3), [description = "Translational position of the node in [m/s]"]
    f(t)[1:3] = zeros(3), [description = "Force entering the node in [N]", connect = Flow]
end

@mtkmodel Force3 begin
    @parameters begin
        f_0[1:3] = zeros(3)
    end
    @components begin
        node = Flange3()
        f = RealInput(; nin=3, u_start=f_0)
    end
    @equations begin
        collect(node.f .~ -f.u)...
    end
end

@mtkmodel Fixed3 begin
    @parameters begin
        s = zeros(3)
    end
    @components begin
        node = Flange3(; s=s)
    end
    @equations begin
        collect(node.s .~ s)...
    end
end

@mtkmodel Free3 begin
    @components begin
        node = MechanicalPort3()
    end
    @variables begin
        f(t)[1:3] = zeros(3)
    end
    @equations begin
        collect(node.f .~ f)...
    end
end

@mtkmodel Constant3 begin
    @components begin
        output = RealOutput(; nout=3)
    end
    @parameters begin
        k[1:3] = zeros(3), [description = "Constant output value of block"]
    end
    @equations begin
        collect(output.u .~ k)...
    end
end

@mtkmodel Mass3 begin
    # Definition of the model icon
    #@icon "..."

    # Definition of the model parameters
    @parameters begin
        m, [description = "Mass of the moving rigid body in [kg]"]
    end

    @variables begin
        (s(t))[1:3] = zeros(3), [description = "Positions in [m] along X, Y and Z axes of the rigid body"]
        (v(t))[1:3] = zeros(3), [description = "Velocities in [m/s] along X, Y and Z axes of the rigid body"]
        (f(t))[1:3] = zeros(3), [description = "Forces in [N] along X, Y and Z axes entering the rigid body"]
    end

    @components begin
        node = Flange3(; s=s)
    end

    @equations begin
        collect(node.s .~ s)...
        collect(node.f .~ f)...
        collect(D.(s) .~ v)...
        collect(D.(v) .~ f ./ m)...
    end
end

@mtkmodel SpringDamper3 begin
    @parameters begin
        k, [description = "Spring stiffness in [N/m]"]
        c, [description = "Damper viscous damping in [N/m]"]
        l0, [description = "Spring length at rest in [m]"]
    end

    @components begin
        origin_node = Flange3()
        target_node = Flange3()
    end

    @variables begin
        l(t), [description = "Spring length in [m]"]
        v(t), [description = "Damper velocity in [m]"]
        f(t)[1:3]
        dir(t)[1:3], [description = "Spring direction"]
    end

    @equations begin
        D(l) ~ v
        l ~ norm(collect(target_node.s .- origin_node.s))
        collect(dir .~ collect(target_node.s .- origin_node.s) ./ l)...
        collect(f .~ k .* collect(dir) .* (l - l0) + c .* collect(dir) .* v)...
        collect(origin_node.f .~ .+f)...
        collect(target_node.f .~ .-f)...
    end
end

@named mass = Mass3(m=1, s=[0.0, 0.0, 0.0])
@named springdamper = SpringDamper3(k=10, l0=0.5, c=2)
@named fix = Fixed3(s=[1.0; -1.0; 2.0])
@named g = Force3()
@named sig = Constant3(k=[0.0; 0.0; -9.81])

eqs = Equation[
    ModelingToolkit.connect(sig.output, g.f)
    ModelingToolkit.connect(g.node, mass.node)
    ModelingToolkit.connect(springdamper.target_node, mass.node)
    ModelingToolkit.connect(springdamper.origin_node, fix.node)
]

@named model = ODESystem(eqs, t, [], []; systems=[mass, fix, springdamper, g, sig])
sys = structural_simplify(model)

At that point, the structural_simplify works and gives as expected 6 degrees of freedom, 3 positions and 3 velocities.

However, if I try to solve that, it fails on some sort of broadcasting.

initial_conditions = reduce(vcat, [collect(mass.s .=> [0.0, 1.0, -0.1]), collect(mass.v .=> [0.5, 1.0, 0.0])])
prob = ODEProblem(sys, initial_conditions, (0.0, 100.0))
sol = solve(prob, Rodas5(), abstol=1e-8, reltol=1e-8, saveat=0:0.1:200)

leads to

ERROR: MethodError: no method matching +(::Vector{Float64}, ::Float64)
For element-wise addition, use broadcasting with dot syntax: array .+ scalar
Closest candidates are:
+(::Any, ::Any, ::Any, ::Any…)
@ Base operators.jl:578
+(::T, ::T) where T<:Union{Float16, Float32, Float64}
@ Base float.jl:408
+(::AbstractAlgebra.MatrixElem{T}, ::Union{AbstractFloat, Integer, Rational}) where T<:AbstractAlgebra.NCRingElement

@ChrisRackauckas I’m using ModelingToolkit v8.73.2, do you think it is the same bug as in Broadcast inside of `@mtkmodel` macro causes precompilation failures when put into a package - #11 by BambOoxX or something else ?