Skip to content

Steady state sweeps

julia
using HarmonicBalance, SteadyStateDiffEq, ModelingToolkit
using BenchmarkTools, Plots, StaticArrays, OrdinaryDiffEq, LinearAlgebra
using HarmonicBalance: OrderedDict

@variables α ω ω0 F γ η t x(t);

diff_eq = DifferentialEquation(
    d(x, t, 2) + ω0^2 * x + α * x^3 + γ * d(x, t) + η * d(x, t) * x^2 ~ F * cos* t), x
)
add_harmonic!(diff_eq, x, ω)
harmonic_eq = get_harmonic_equations(diff_eq)

fixed = (ω0 => 1.0, γ => 1e-2, F => 0.02, α => 1.0, η => 0.3)
ω_span = (0.8, 1.3);
ω_range = range(ω_span..., 201);
varied = ω => ω_range

result_HB = get_steady_states(harmonic_eq, varied, fixed)
plot(result_HB, "sqrt(u1^2+v1^2)")

Steady state sweep using SteadyStateDiffEq.jl

julia
param = OrderedDict(merge(Dict(fixed), Dict=> 1.1)))
x0 = [0, 0.0];
prob_ss = SteadyStateProblem(
    harmonic_eq, x0, param; in_place=false, u0_constructor=x -> SVector(x...)
)

varied = 6 => ω_range
result_ss = steady_state_sweep(
    prob_ss, DynamicSS(Rodas5()); varied, abstol=1e-5, reltol=1e-5
)

plot(result_HB, "sqrt(u1^2+v1^2)")
plot!(ω_range, norm.(result_ss); c=:gray, ls=:dash)

Adiabatic evolution

julia
timespan = (0.0, 50_000)
sweep = AdiabaticSweep=> (0.8, 1.3), timespan) # linearly interpolate between two values at two times
ode_problem = ODEProblem(harmonic_eq, fixed; u0=[0.01; 0.0], timespan, sweep)
time_soln = solve(ode_problem, Tsit5(); saveat=250)

plot(result_HB, "sqrt(u1^2+v1^2)")
plot(time_soln.t, norm.(time_soln.u))

using follow_branch

julia
followed_branch, Ys = follow_branch(1, result_HB; y="√(u1^2+v1^2)")
Y_followed_gr =
    real.([Ys[param_idx][branch] for (param_idx, branch) in enumerate(followed_branch)]);

plot(result_HB, "sqrt(u1^2+v1^2)")
plot!(ω_range, Y_followed_gr; c=:gray, ls=:dash)

comparison

julia
@btime result_ss = steady_state_sweep(
    prob_ss, DynamicSS(Rodas5()); varied, abstol=1e-5, reltol=1e-5
)

@btime time_soln = solve(ode_problem, Tsit5(); saveat=250)

@btime begin
    followed_branch, Ys = follow_branch(1, result_HB; y="√(u1^2+v1^2)")
    Y_followed_gr =
        real.([Ys[param_idx][branch] for (param_idx, branch) in enumerate(followed_branch)])
end
201-element Vector{Float64}:
 0.05519114899138603
 0.055799978946403664
 0.05642407910800841
 0.05706400920350061
 0.05772035586647756
 0.058393734206693935
 0.05908478948483706
 0.05979419889977807
 0.06052267349639453
 0.06127096020262131

 0.031358143559610405
 0.031045637155686527
 0.03073872580091137
 0.03043726150835462
 0.03014110149137382
 0.02985010793545113
 0.029564147782042915
 0.02928309252370293
 0.02900681800979332

Plotting them together gives:

julia
plot(ω_range, norm.(result_ss))
plot!(ω_range, norm.(time_soln.u))
plot!(ω_range, Y_followed_gr)


This page was generated using Literate.jl.