-
I agree that a user does not always care about seeing every variable value; in that case it is wasteful. On the flip side, I think users still frequently want to see many or all variables that were eliminated in the simplification process. Having the option to choose how the solution is post-processed would be a compromise.
-
I haven’t tried that build_function
option yet. I will likely have to try after the xmas holiday next week.
-
Here is my fake code to mimic what is happening:
using ModelingToolkit
@connector function TestPort(;name)
sts = @variables T #=p h=# #could add more port variables
NonlinearSystem(Equation[], [sts...;], []; name)
end
function long_func(T, N)
sleep(N) #mimic an expensive function
println("waiting for $N seconds at T=$T")
return 1
#could also execute a longer routine below
#=
sum = 0
for i = 1:N
sum += i
end
return sum
=#
end
@register_symbolic long_func(T, N)::Real
function test_comp(;name, ports, N)
inlet = TestPort(;name=ports[1])
outlet = TestPort(;name=ports[2])
#define params and vars
ps = @parameters N=N
#=sts = @variables s=#
#define equations
#FYI: using an intermediate variable `s` will increase run time of `sol[allvars] (more vars to process)`
eqs = [
#=s ~ long_func(inlet.T, N)=#
outlet.T ~ inlet.T + long_func(inlet.T, N)
#=outlet.p ~ inlet.p
outlet.h ~ inlet.h=#
]
compose(NonlinearSystem(eqs, #=sts=# [], ps; name),
inlet, outlet)
end
function test_boundary_in(;name, ports, val)
port = TestPort(;name=ports[1])
ps = @parameters T=val #=h=val p=val=#
eqs = [
port.T ~ T
#=port.h ~ h
port.p ~ p=#
]
compose(NonlinearSystem(eqs, [], ps; name), port)
end
function test_boundary_out(;name, ports)
port = TestPort(;name=ports[1])
compose(NonlinearSystem(Equation[], [], []; name), port)
end
N1 = 1 #sleep seconds
N2 = 2
N3 = 4
@named baseline = test_boundary_in(; ports=[:out], val=0.0)
@named freethrow = test_comp(; ports=[:in, :out], N=N1)
@named halfcourt = test_comp(; ports=[:in, :out], N=N2)
@named freethrow_opp = test_comp(; ports=[:in, :out], N=N3)
@named baseline_opp = test_boundary_out(; ports=[:in])
eqs = [
connect(baseline.out, freethrow.in)
connect(freethrow.out, halfcourt.in)
connect(halfcourt.out, freethrow_opp.in)
connect(freethrow_opp.out, baseline_opp.in)
]
@named mtk_model = NonlinearSystem(eqs, [], [];
systems=[baseline, freethrow, halfcourt, freethrow_opp, baseline_opp])
mtk_alias = alias_elimination(expand_connections(mtk_model))
mtk_simp = structural_simplify(mtk_alias; allow_symbolic=true, allow_parameter=true)
@time prob = NonlinearProblem(mtk_simp, [])
@time sol = solve(prob, NewtonRaphson(;autodiff=false))
@show sol.u
#return key vars one-by-one
println("--baseline--")
@time sol[baseline.out.T]
println("--freethrow--")
@time sol[freethrow.out.T]
println("--halfcourt--")
@time sol[halfcourt.out.T]
println("--opposite freethrow--")
@time sol[freethrow_opp.out.T]
println("--opposite baseline--") #same time as freethrow_opp because no extra long func
@time sol[baseline_opp.in.T]
#return all vars
println("full system")
allvars = states(mtk_model)
@time sol[allvars]
#estimated wait time for 8 vars in allvars
est = 2*0 + 2*N1 + 2*(N1+N2) + 2*(N1+N2+N3)
println("$est seconds estimated")
#TODO:
#1) repeat for more components in a row and run time will start to inflate for `sol[allvars]`
#2) add more intermediate variables to show `long_func` repetition
The run time answers in my terminal are printed below:
--baseline--
0.001184 seconds (1.31 k allocations: 105.406 KiB)
--freethrow--
waiting for 1.0 seconds at T=0.0
1.033398 seconds (5.46 k allocations: 388.171 KiB, 1.84% compilation time: 100% of which was recompilation)
--halfcourt--
waiting for 1.0 seconds at T=0.0
waiting for 2.0 seconds at T=1.0
3.024640 seconds (5.33 k allocations: 379.195 KiB, 0.54% compilation time: 100% of which was recompilation)
--opposite freethrow--
waiting for 1.0 seconds at T=0.0
waiting for 2.0 seconds at T=1.0
waiting for 4.0 seconds at T=2.0
7.082794 seconds (5.82 k allocations: 417.484 KiB, 0.51% compilation time: 100% of which was recompilation)
--opposite baseline--
waiting for 1.0 seconds at T=0.0
waiting for 2.0 seconds at T=1.0
waiting for 4.0 seconds at T=2.0
7.072475 seconds (5.88 k allocations: 421.094 KiB, 0.33% compilation time: 100% of which was recompilation)
full system
waiting for 1.0 seconds at T=0.0
waiting for 1.0 seconds at T=0.0
waiting for 1.0 seconds at T=0.0
waiting for 2.0 seconds at T=1.0
waiting for 1.0 seconds at T=0.0
waiting for 2.0 seconds at T=1.0
waiting for 1.0 seconds at T=0.0
waiting for 2.0 seconds at T=1.0
waiting for 4.0 seconds at T=2.0
waiting for 1.0 seconds at T=0.0
waiting for 2.0 seconds at T=1.0
waiting for 4.0 seconds at T=2.0
22.168350 seconds (11.39 k allocations: 829.844 KiB, 0.23% compilation time: 100% of which was recompilation)
22 seconds estimated