# ModelingToolkit connector error with Arrays

**URL:** <https://discourse.julialang.org/t/modelingtoolkit-connector-error-with-arrays/123565>\
**Category:** General Usage\
**Tags:** modelingtoolkit\
**Created:** [December 7, 2024, 12:27pm UTC](https://discourse.julialang.org/t/modelingtoolkit-connector-error-with-arrays/123565 "2024-12-07T12:27:18Z")\
**Posts on this page:** 1\
**Showing post:** 11

<div class="post-metadata">

**Author:** ![RobbesU](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/robbesu/32/212459_2.png) [@RobbesU](https://discourse.julialang.org/u/RobbesU)\
**Post date:** [February 3, 2025, 11:22am UTC](https://discourse.julialang.org/t/modelingtoolkit-connector-error-with-arrays/123565/11 "2025-02-03T11:22:08Z")

</div>

This works (`Julia 1.11.3`, `MTK 9.61.0` and `9.62.0`)

This little test system comprises a mass-flange-inputforce system with gravity, a forced sinusoidal input function via the flange, and a constant force direct on the mass.  
(edit: added the packages and constants used)

```julia
using ModelingToolkit
using DifferentialEquations
using LaTeXStrings
using Plots
import LinearAlgebra as LA
import ModelingToolkitStandardLibrary.Mechanical.Translational as T
import ModelingToolkitStandardLibrary.Blocks as B

using ModelingToolkit: t_nounits as t, D_nounits as D

# a few constants for easy test switching
const G_EARTH = [0.0, 0.0, -9.81] # m/s²
const G_MOON = [0.0, 0.0, -1.625]
const G_MARS = [0.0, 0.0, -3.72076]
const Earth="Earth"
const Moon="Moon"
const Mars="Mars"
const gravities=Dict(Earth => G_EARTH, Moon=>G_MOON, Mars=>G_MARS)

@connector function Flange3D(;name)

	vars = @variables begin
		f(t)[1:3], [connect=Flow, description = "Cut force resolved in connector"]
		v(t)[1:3], [description = "Cut velocities in connector"]
	end

	pars = []
	
	v,f = collect.((v,f))
	vars = [v;f]
	eqs = [1~1] # This avoids "BoundsError: attempt to access 0-element Vector{Vector{Any}} at index [0]"
	eq = eqs==[] ? Equation[] : eqs
	
	ODESystem(eq, t, vars, pars; name)
end

@component function Mass3D(; name, m, g=G_EARTH) 

	pars = @parameters begin # this allows the params to be set in mtkbuild call OR as system parameters
		m=m
		g[1:3]=g  
		f0[1:3]=[0.,0.,0.]
	end
	
    vars = @variables begin
        s(t)[1:3] # =[0.,0.,0.], [description = "Positions in [m] along X, Y and Z axes of the mass"]
        v(t)[1:3] # =[0.,0.,0.], [description = "Velocities in [m/s] along X, Y and Z axes of the mass"]
		a(t)[1:3], [description = "Acceleration in [m/s²] along the X,Y,Z axes of the mass"]
		f(t)[1:3], [description = "Forces in [N] along X,Y,Z axes of the mass"]
    end

    systems = @named begin
		flange = Flange3D() # connects v & f
	end

    eqs = [
        collect(D.(s) .~ v)...
        collect(D.(v) .~ a)...
        collect(v .~ flange.v)...
        collect(f .~ flange.f)...
        collect(a .~ (f .+f0)./m .+ g)...
	]

	initialization_eqs=[]
	
	return ODESystem(eqs, t, vars, pars; systems, name, initialization_eqs)
end

@component function ForceFunction3D(; name, a0=[0.,0.,0.])
	pars = @parameters a0[1:3]=a0
	vars = @variables f(t) 
    systems = @named begin
        output = B.RealOutputArray(; nout=3)
    end
	@constants π=pi # this makes for 'pretty' equations in display
	
	f = a0 .* sin(π*t) # this gets passed through!
    eqs = [
        collect(output.u .~ -f)...
	]
	
	return ODESystem(eqs, t, vars, pars; systems, name)
end

@component function Force3D(; name)
	pars = []
	vars = []
    systems = @named begin
        input = B.RealInputArray(; nin=3, guess=[0.,0.,0.])
		flange = Flange3D()
    end
    eqs = [
		collect(flange.f .~ input.u)...
	]
	
	return ODESystem(eqs, t, vars, pars; name, systems) 
end

@component function ForcedMass3D(;name, m, g=G_EARTH, a0=[0.,0.,0.] )
	pars = []
	vars = []
	systems = @named begin
		force = Force3D()
		force_func = ForceFunction3D(a0=a0)
		mass = Mass3D(m=m,g=g)
	end
	eqs = [
		ModelingToolkit.connect(force_func.output, force.input )
		ModelingToolkit.connect(force.flange, mass.flange)
	]

	return ODESystem(eqs, t, vars, pars; systems, name)
end

@mtkbuild sys1 = ForcedMass3D(m=1.0); # = @named + structural_simplity()

parameters(sys1) # mass.f0, mass.g, mass.m, force_func.a0

```

Simulate it with the variable parameters available without recreating the ODESystem:

```julia
	dt = 0.02
	duration = 5.0
	tspan, ts = time_span(duration, dt) # duration, dt
	
	# MTK unknows are pos s & vel v: unknowns(simple_sys) 
	s00 = [0.,0.,0.]
	v00 = [0.,0.,0.]
	s0 = [10., 20., 10.]
	v0 = [5., 2., 3.]
	a0 = [0.,10.,+20] # amplitude of input force function
	f0 = [1.,0.,10.] # constant forces on mass over and above gravity
	z0 = [0.,0.,0.]
	
	p = Earth
	g = gravities[p]
	m = 1.
	
	u0 = []  
	p0 = Dict( :mass₊m=>m, :mass₊g=>g, :mass₊f0=>f0, :force_func₊a0=>a0) # ... this works :-)
	
	forcedmass_init_eqs = [
		collect(sys1.mass.s .~ s0 )...
		collect(sys1.mass.v .~ v0 )...
	]
	
	prob = ODEProblem(sys1, u0, tspan, p0; initialization_eqs=forcedmass_init_eqs)

	sol = solve(prob, Rodas5(), dt=dt, saveat=ts)
	plot(sol, title="$p? trajectory")

```

---

_[View the full topic](https://discourse.julialang.org/t/modelingtoolkit-connector-error-with-arrays/123565)._
