# How to use differently sized static arrays per project

**URL:** <https://discourse.julialang.org/t/how-to-use-differently-sized-static-arrays-per-project/62834>\
**Category:** General Usage\
**Tags:** question\
**Created:** [June 13, 2021, 1:26pm UTC](https://discourse.julialang.org/t/how-to-use-differently-sized-static-arrays-per-project/62834 "2021-06-13T13:26:38Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)\
**Post date:** [June 13, 2021, 1:26pm UTC](https://discourse.julialang.org/t/how-to-use-differently-sized-static-arrays-per-project/62834/1 "2021-06-13T13:26:38Z")

</div>

Hello,

I have a module called Utils (see [KiteViewer/Utils.jl at sim · ufechner7/KiteViewer · GitHub](https://github.com/ufechner7/KiteViewer/blob/sim/src/Utils.jl)).

It provides a function se() that returns a struct of simulation settings. These  
settings are loaded from a YAML file.

Now I want to use different settings depending on the system that I am simulating.  
But the project to use must be known BEFORE I load the module Utils.

The reason is that the settings contain the constant “segments” which defines  
the size of static vectors I use for the simulation.

My current plan is to use a file project.txt witch contains the name of the  
settings file that shall be loaded.

And if I change the settings during runtime the program shall update this file and  
then it would re-start itself.

Is there a better way to achieve the desired behavior:

- using statically sized arrays for the simulation
- reload the program when the project and thus the size changes?

I a bit afraid that restarting might be pretty slow because it might cause a lot of recompilation.

Uwe

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [June 13, 2021, 2:40pm UTC](https://discourse.julialang.org/t/how-to-use-differently-sized-static-arrays-per-project/62834/2 "2021-06-13T14:40:50Z")

</div>

I think it is better to parameterize the structs with the size of the vectors. For example, this one:

```julia
struct ExtSysState
    time::Float64 # time since launch in seconds
    orient::UnitQuaternion{Float32} # orientation of the kite
    X::MVector{se().segments+1, MyFloat} 
...
end

```

Use instead:

```julia
struct ExtSysState{N,T}
    time::Float64 # time since launch in seconds
    orient::UnitQuaternion{Float32} # orientation of the kite
    X::MVector{N,T} 
...
end

```

then the definition of the vector size and type will occur in the initialization of the structure, not on module loading. If you follow this pattern in your code, the type of problem will be defined at run time each function.

---

<div class="post-metadata">

**Author:** ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)\
**Post date:** [June 13, 2021, 6:09pm UTC](https://discourse.julialang.org/t/how-to-use-differently-sized-static-arrays-per-project/62834/3 "2021-06-13T18:09:02Z")

</div>

I more-or-less implemented your suggestion, and it works. 🙂

See: [KiteViewer/Utils.jl at sim · ufechner7/KiteViewer · GitHub](https://github.com/ufechner7/KiteViewer/blob/sim/src/Utils.jl)

On the other hand the startup time of my app increased from 11s to 12s.

What was surprising for me was that I cannot do any calculations with the type parameter. I first tried to pass the number of segments, S and use S+1 as vector size, but that did not work. Now I use P, the number of points as type parameter.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [June 13, 2021, 6:32pm UTC](https://discourse.julialang.org/t/how-to-use-differently-sized-static-arrays-per-project/62834/4 "2021-06-13T18:32:20Z")

</div>

> [@ufechner7](#):
>
> What was surprising for me was that I cannot do any calculations with the type parameter.

What you mean here exactly? Three approaches could be used, I think:

1. Annotate the parametric types on the functions (this one is the most elegant, in my opinion, since the function will specialize to that type of `a` anyway:

```julia
function f(a::A{N,T}) where {N,T}
   # use N here
end

```

1. Get the size internaly:

```julia
function f(a)
   N = length(a.x) # a.x is the MVector{N,T}
   ...
end

```

1. Annotate he size in your struct:

```julia
struct A{N,T}
   N::Int
   x::Vector{N,T}
end

```

and initialize it accordingly (and use `a.N` there)

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [June 13, 2021, 6:42pm UTC](https://discourse.julialang.org/t/how-to-use-differently-sized-static-arrays-per-project/62834/5 "2021-06-13T18:42:19Z")

</div>

Some other thing: how many particles are you talking about? `MVectors` with large N (P in your case) are not a good idea and will make compile times be very large. Better data structures are standard vectors or, probably, a vector of SVectors.

---

<div class="post-metadata">

**Author:** ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)\
**Post date:** [June 13, 2021, 6:44pm UTC](https://discourse.julialang.org/t/how-to-use-differently-sized-static-arrays-per-project/62834/6 "2021-06-13T18:44:01Z")

</div>

P is currently 7, might be up to 14, but probably never larger…  
I am pretty happy with these data structures for now, my inner loop needs about 500ns, with normal vectors it is 15 times as much.  
You can find my inner loop in line 270ff of this file: [KiteViewer/KPS3.jl at sim · ufechner7/KiteViewer · GitHub](https://github.com/ufechner7/KiteViewer/blob/sim/src/KPS3.jl)

For now it uses a constant for the number of segments, because if I do not use a constant it allocates… But I will experiment with type parameters, too, lets see…

---

<div class="post-metadata">

**Author:** ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)\
**Post date:** [June 13, 2021, 6:55pm UTC](https://discourse.julialang.org/t/how-to-use-differently-sized-static-arrays-per-project/62834/7 "2021-06-13T18:55:54Z")

</div>

This is the difficult code:

```julia
function residual!(res, yd, y, p, time)
    # unpack the vectors y and yd
    part = reshape(SVector{6*(SEGMENTS)}(y), Size(3, SEGMENTS, 2))
    partd = reshape(SVector{6*(SEGMENTS)}(yd), Size(3, SEGMENTS, 2))
    pos1, vel1 = part[:,:,1], part[:,:,2]
    pos = SVector{SEGMENTS+1}(if i==1 SVector(0.0,0,0) else SVector(pos1[:,i-1]) end for i in 1:SEGMENTS+1)
    vel = SVector{SEGMENTS+1}(if i==1 SVector(0.0,0,0) else SVector(vel1[:,i-1]) end for i in 1:SEGMENTS+1)
    posd1, veld1 = partd[:,:,1], partd[:,:,2]
    posd = SVector{SEGMENTS+1}(if i==1 SVector(0.0,0,0) else SVector(posd1[:,i-1]) end for i in 1:SEGMENTS+1)
    veld = SVector{SEGMENTS+1}(if i==1 SVector(0.0,0,0) else SVector(veld1[:,i-1]) end for i in 1:SEGMENTS+1)

```

If I do not define SEGMENTS as constant, it allocates.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [June 13, 2021, 7:28pm UTC](https://discourse.julialang.org/t/how-to-use-differently-sized-static-arrays-per-project/62834/8 "2021-06-13T19:28:00Z")

</div>

Exactly. If one the input parameters contain the size as a type parameter, use something like:

> [@ufechner7](#):
>
> ```julia
> function residual!(res, yd, y, p::SVector{N,T}, time) where N,T
> pos = SVector{N+1}(...)
> 
> ```

and then it may become non allocating. The point is to make the function specialize to a given N, and then these sizes are known at compile time, even if not apparently constant for the user.

(“particles” in my field are usually on the thousands, so that is why I asked. But with those sizes that is fine)

Ps. For example: [Question about allocations and generators - #3 by lmiq](https://discourse.julialang.org/t/question-about-allocations-and-generators/62693/3)

---

<div class="post-metadata">

**Author:** ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)\
**Post date:** [June 13, 2021, 7:39pm UTC](https://discourse.julialang.org/t/how-to-use-differently-sized-static-arrays-per-project/62834/9 "2021-06-13T19:39:40Z")

</div>

Well, the function is a callback function of the IDA integrator, and I cannot change the function signature… But p is a parameter that I can freely choose (well, within curtain limits). So perhaps your suggestion will work…

---

<div class="post-metadata">

**Author:** ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)\
**Post date:** [June 13, 2021, 8:07pm UTC](https://discourse.julialang.org/t/how-to-use-differently-sized-static-arrays-per-project/62834/10 "2021-06-13T20:07:29Z")

</div>

So I tried:

```julia
function residual!(res, yd, y, p{N}, time) where N

```

and get the error message:

```julia
syntax: "p{N}" is not a valid function argument

```

So what exactly did you suggest?

Found it myself. This might work (at least no syntax error):

```julia
function residual!(res, yd, y, p::Vector{N}, time) where N

```

---

<div class="post-metadata">

**Author:** ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)\
**Post date:** [June 13, 2021, 9:02pm UTC](https://discourse.julialang.org/t/how-to-use-differently-sized-static-arrays-per-project/62834/11 "2021-06-13T21:02:25Z")

</div>

Final solution:

```julia
function residual!(res, yd, y::MVector{S, Float64}, p, time) where S
    # unpack the vectors y and yd
    part = reshape(SVector{S}(y), Size(3, div(S,6), 2))
    partd = reshape(SVector{S}(yd), Size(3, div(S,6), 2))
    pos1, vel1 = part[:,:,1], part[:,:,2]
    pos = SVector{div(S,6)+1}(if i==1 SVector(0.0,0,0) else SVector(pos1[:,i-1]) end for i in 1:div(S,6)+1)
    vel = SVector{div(S,6)+1}(if i==1 SVector(0.0,0,0) else SVector(vel1[:,i-1]) end for i in 1:div(S,6)+1)
    posd1, veld1 = partd[:,:,1], partd[:,:,2]
    posd = SVector{div(S,6)+1}(if i==1 SVector(0.0,0,0) else SVector(posd1[:,i-1]) end for i in 1:div(S,6)+1)
    veld = SVector{div(S,6)+1}(if i==1 SVector(0.0,0,0) else SVector(veld1[:,i-1]) end for i in 1:div(S,6)+1)

```

I could not use the p parameter, because I can use a float or a Vector of float for it, but not an SVector.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [June 13, 2021, 10:56pm UTC](https://discourse.julialang.org/t/how-to-use-differently-sized-static-arrays-per-project/62834/12 "2021-06-13T22:56:09Z")

</div>

> [@ufechner7](#):
>
> So what exactly did you suggest?

Sorry for that. It was a mistake because of lack os attention. What you finally did is correct, and I fixed the example to avoid confusion.
