@@ -10,8 +10,10 @@ using Pkg
1010# Rev fixes precompilation https://github.com/hzgzh/XSteam.jl/pull/2
1111Pkg.add(Pkg.PackageSpec(;name="XSteam", rev="f2a1c589054cfd6bba307985a3a534b6f5a1863b"))
1212
13- using ModelingToolkit, JuliaSimCompiler, Symbolics, XSteam, Polynomials, BenchmarkTools, CairoMakie, OrdinaryDiffEq
13+ using ModelingToolkit, JuliaSimCompiler, Symbolics, XSteam, Polynomials, BenchmarkTools, OrdinaryDiffEq
1414using OMJulia
15+
16+ using ModelingToolkit: t_nounits as t, D_nounits as D
1517```
1618
1719## Setup Julia Code
@@ -24,8 +26,6 @@ using OMJulia
2426#Source -> o--o--o--o--o--o--o -> Sink
2527# advection diff source PDE
2628
27- @variables t
28- D = Differential(t)
2929m_flow_source(t) = 2.75
3030T_source(t) = (t > 12 * 3600) * 56.0 + 12.0
3131@register_symbolic m_flow_source(t)
@@ -410,6 +410,72 @@ Legend(f2[1,2], _lines, names)
410410f2
411411```
412412
413+ ## Symbolic jacobian timings
414+
415+ To avoid scaling issues with `structural_simplify` on ModelingToolkit.jl models, we will
416+ compile functions using JuliaSimCompiler.jl and trace through the resultant functions.
417+
418+ ```julia
419+ function run_and_time_jacobian!(mtk_times, mtk_no_hashconsing_times, N)
420+ @named testbench = TestBenchPreinsulated(L=470, N=N, dn=0.3127, t_layer=[0.0056, 0.058])
421+ sys = structural_simplify(IRSystem(testbench), loop=false)
422+ # tspan doesn't matter
423+ prob = ODEProblem(sys, [], (0.0, 1.0); sparse = true)
424+
425+ t = ModelingToolkit.t_nounits
426+ n_states = length(prob.u0)
427+ @variables x(t)[1:n_states]
428+ n_params = length(prob.p)
429+ @variables p[1:n_params]
430+
431+ x = collect(x)
432+ p = collect(p)
433+ expr = zeros(Num, n_states)
434+ prob.f.f(expr, x, p, t)
435+
436+ expr = map(Symbolics.unwrap, expr)
437+ x = map(Symbolics.unwrap, x)
438+ mtk_time = @elapsed jac1 = Symbolics.jacobian(expr, x)
439+ push!(mtk_times, mtk_time)
440+
441+ SymbolicUtils.ENABLE_HASHCONSING[] = false
442+ @variables x(t)[1:n_states]
443+ @variables p[1:n_params]
444+ x = collect(x)
445+ p = collect(p)
446+ expr = zeros(Num, n_states)
447+ prob.f.f(expr, x, p, t)
448+ expr = map(Symbolics.unwrap, expr)
449+ no_hashconsing_time = @elapsed jac2 = Symbolics.jacobian(expr, x)
450+ push!(mtk_no_hashconsing_times, no_hashconsing_time)
451+ SymbolicUtils.ENABLE_HASHCONSING[] = true
452+
453+ @assert all(isequal.(jac1, jac2))
454+ end
455+ ```
456+
457+
458+ ```julia
459+ @time run_and_time_jacobian!(Float64[], Float64[], 4) # precompile
460+ mtk_times = Float64[]
461+ mtk_no_hashconsing_times = Float64[]
462+ for n in N
463+ run_and_time_jacobian!(Float64[], Float64[], n)
464+ end
465+ ```
466+
467+ ## Generate Plots
468+
469+ ```julia
470+ f3 = Figure(size=(800,1200));
471+ ss_names = ["MTK", "JSIR"];
472+ let ax = Axis(f3[1, 1]; yscale = log10, xscale = log10, title = "Jacobian Time")
473+ _lines = [lines!(N, mtk_times), lines!(N, mtk_no_hashconsing_times)]
474+ Legend(f3[1, 2], _lines, ["With Hashconsing", "Without Hashconsing"])
475+ end
476+ f3
477+ ```
478+
413479## Appendix
414480
415481```julia, echo = false
0 commit comments