Tips for making a program more Julian

Thank you for the input, I went ahead and made those changes. Would you happen to know if there is another way to create SimOutput through metaprogramming or something similar? Or would that just be overkill and lead to difficulties reading the code.

that

1 Like

I don’t think this is totally what you meant, but I made state.y a Array{Float32} and then mutated it in the sim_prm.

function sim_prm!(x, u, t, y, hys_state, i, output::Bool)
        # Block 3, PT1, only output
        _, y3 = pt1(x, 0)
        # Block 1, Subtractor
        y1 = -(u, y3)
        # Block 2, Hysteresis
        y2 = hysteresis(y1, hys_state, i)
        # Block 3, PT1, only state
        xdot, _ = pt1(x, y2) 
        if output
            y[1] = y1
            y[2] = y2
            y[3] = y3
        end
        return xdot
    end

This is ok but what is problematic with the tuple solution ?

y=ones(3)
f1() = (1,2,3)
g!(y) = y[1],y[2],y[3]=f1()
using BenchmarkTools
@benchmark g!($y)

cause no allocations:

BenchmarkTools.Trial: 
  memory estimate:  0 bytes
  allocs estimate:  0
  --------------
  minimum time:     1.975 ns (0.00% GC)
  median time:      1.994 ns (0.00% GC)
  mean time:        2.004 ns (0.00% GC)
  maximum time:     6.732 ns (0.00% GC)
  --------------
  samples:          10000
  evals/sample:     1000
1 Like

Oh! I didn’t realize you could do that, as Tuples are immutable. I tried having y as a
Tuple{Float32}, but I couldn’t mutate it after the initial assignment. I do like your solution more and I’ll implement it. Thank you very much for the help!

1 Like

Small vectors like that y are also the place for StaticArrays:

julia> using StaticArrays

julia> f() = @SVector [1,2,3]
f (generic function with 1 method)

julia> y = f()
3-element SVector{3, Int64} with indices SOneTo(3):
 1
 2
 3

julia> using BenchmarkTools

julia> @btime f()
  0.021 ns (0 allocations: 0 bytes)

Your structs can also be cleaner (maybe that is where you thought metaprogramming could be useful) using more extensively the @kwdef or, with some more features, the Parameters package:

julia> using Parameters

julia> @with_kw struct SimOutput{T}
         x_values::Vector{T} = Float32[]
         u_values::Vector{T} = Float32[]
       end
SimOutput

julia> SimOutput()
SimOutput{Float32}
  x_values: Array{Float32}((0,)) Float32[]
  u_values: Array{Float32}((0,)) Float32[]


julia> SimOutput{Float64}()
SimOutput{Float64}
  x_values: Array{Float64}((0,)) Float64[]
  u_values: Array{Float64}((0,)) Float64[]


julia> Out = SimOutput()
SimOutput{Float32}
  x_values: Array{Float32}((0,)) Float32[]
  u_values: Array{Float32}((0,)) Float32[]


julia> @unpack x_values, u_values = Out # can use this inside your functions
SimOutput{Float32}
  x_values: Array{Float32}((0,)) Float32[]
  u_values: Array{Float32}((0,)) Float32[]


julia> x_values
Float32[]


2 Likes