|
1 | 1 | module MechGlueDiffEqBase |
2 | | -import Unitfu: AbstractQuantity, Quantity |
| 2 | +import Unitfu: AbstractQuantity, Quantity, ustrip |
3 | 3 | import DiffEqBase: value, ODE_DEFAULT_NORM, UNITLESS_ABS2 |
| 4 | +export value, ODE_DEFAULT_NORM, UNITLESS_ABS2, Unitfu, AbstractQuantity, Quantity |
| 5 | + |
| 6 | + |
| 7 | +import RecipesBase |
| 8 | +import RecipesBase.@recipe |
4 | 9 | import SciMLBase |
5 | 10 | import SciMLBase: AbstractTimeseriesSolution, RecipesBase |
6 | 11 | import SciMLBase: AbstractDiscreteProblem, AbstractRODESolution, SensitivityInterpolation |
7 | | -import RecipesBase.@recipe |
8 | | -export value, ODE_DEFAULT_NORM, UNITLESS_ABS2, Unitfu |
| 12 | +import SciMLBase: getsyms, interpret_vars, cleansyms |
| 13 | +import SciMLBase: diffeq_to_arrays, issymbollike, getindepsym_defaultt |
| 14 | +import SciMLBase: DEFAULT_PLOT_FUNC |
| 15 | + |
9 | 16 |
|
10 | 17 | function value(x::Type{AbstractQuantity{T,D,U}}) where {T,D,U} |
11 | 18 | T |
|
26 | 33 | real(abs2(x)/oneunit(x)*oneunit(x)) |
27 | 34 | end |
28 | 35 |
|
29 | | - |
| 36 | +# This recipe is copied from SciMLBase, and only the signature is adopted |
| 37 | +# for use with unitful solutions. It can perhaps be deleted now, and the link to RecipesBase be deleted. |
30 | 38 | @recipe function f(sol::AbstractTimeseriesSolution{T, N, A}; |
31 | 39 | plot_analytic=false, |
32 | 40 | denseplot = (sol.dense || |
|
41 | 49 | 1000*sol.tslocation), |
42 | 50 | tspan = nothing, axis_safety = 0.1, |
43 | 51 | vars=nothing) where {T<:Quantity, N, A<:Array{<:Quantity}} |
44 | | - |
45 | | - print("----------------------------------MechGlueDiffEqBase") |
46 | | - return Unifu.ustrip(sol.u), Unifu.ustrip(sol.t) |
| 52 | + syms = getsyms(sol) |
| 53 | + int_vars = interpret_vars(vars,sol,syms) |
| 54 | + strs = cleansyms(syms) |
| 55 | + |
| 56 | + tscale = get(plotattributes, :xscale, :identity) |
| 57 | + plot_vecs,labels = diffeq_to_arrays(sol,plot_analytic,denseplot, |
| 58 | + plotdensity,tspan,axis_safety, |
| 59 | + vars,int_vars,tscale,strs) |
| 60 | + |
| 61 | + tdir = sign(sol.t[end]-sol.t[1]) |
| 62 | + xflip --> tdir < 0 |
| 63 | + seriestype --> :path |
| 64 | + |
| 65 | + # Special case labels when vars = (:x,:y,:z) or (:x) or [:x,:y] ... |
| 66 | + if typeof(vars) <: Tuple && (issymbollike(vars[1]) && issymbollike(vars[2])) |
| 67 | + xguide --> issymbollike(int_vars[1][2]) ? Symbol(int_vars[1][2]) : strs[int_vars[1][2]] |
| 68 | + yguide --> issymbollike(int_vars[1][3]) ? Symbol(int_vars[1][3]) : strs[int_vars[1][3]] |
| 69 | + if length(vars) > 2 |
| 70 | + zguide --> issymbollike(int_vars[1][4]) ? Symbol(int_vars[1][4]) : strs[int_vars[1][4]] |
| 71 | + end |
| 72 | + end |
| 73 | + |
| 74 | + if (!any(issymbollike,getindex.(int_vars,1)) && getindex.(int_vars,1) == zeros(length(int_vars))) || |
| 75 | + (!any(issymbollike,getindex.(int_vars,2)) && getindex.(int_vars,2) == zeros(length(int_vars))) || |
| 76 | + all(t->Symbol(t)==getindepsym_defaultt(sol),getindex.(int_vars,1)) || all(t->Symbol(t)==getindepsym_defaultt(sol),getindex.(int_vars,2)) |
| 77 | + xguide --> "$(getindepsym_defaultt(sol))" |
| 78 | + end |
| 79 | + if length(int_vars[1]) >= 3 && ((!any(issymbollike,getindex.(int_vars,3)) && getindex.(int_vars,3) == zeros(length(int_vars))) || |
| 80 | + all(t->Symbol(t)==getindepsym_defaultt(sol),getindex.(int_vars,3))) |
| 81 | + yguide --> "$(getindepsym_defaultt(sol))" |
| 82 | + end |
| 83 | + if length(int_vars[1]) >= 4 && ((!any(issymbollike,getindex.(int_vars,4)) && getindex.(int_vars,4) == zeros(length(int_vars))) || |
| 84 | + all(t->Symbol(t)==getindepsym_defaultt(sol),getindex.(int_vars,4))) |
| 85 | + zguide --> "$(getindepsym_defaultt(sol))" |
| 86 | + end |
| 87 | + |
| 88 | + if (!any(issymbollike,getindex.(int_vars,2)) && getindex.(int_vars,2) == zeros(length(int_vars))) || |
| 89 | + all(t->Symbol(t)==getindepsym_defaultt(sol),getindex.(int_vars,2)) |
| 90 | + if tspan === nothing |
| 91 | + if tdir > 0 |
| 92 | + xlims --> (sol.t[1],sol.t[end]) |
| 93 | + else |
| 94 | + xlims --> (sol.t[end],sol.t[1]) |
| 95 | + end |
| 96 | + else |
| 97 | + xlims --> (tspan[1],tspan[end]) |
| 98 | + end |
| 99 | + else |
| 100 | + mins = minimum(sol[int_vars[1][2],:]) |
| 101 | + maxs = maximum(sol[int_vars[1][2],:]) |
| 102 | + for iv in int_vars |
| 103 | + mins = min(mins,minimum(sol[iv[2],:])) |
| 104 | + maxs = max(maxs,maximum(sol[iv[2],:])) |
| 105 | + end |
| 106 | + xlims --> ((1-sign(mins)*axis_safety)*mins,(1+sign(maxs)*axis_safety)*maxs) |
| 107 | + end |
| 108 | + |
| 109 | + # Analytical solutions do not save enough information to have a good idea |
| 110 | + # of the axis ahead of time |
| 111 | + # Only set axis for animations |
| 112 | + if sol.tslocation != 0 && !(typeof(sol) <: AbstractAnalyticalSolution) |
| 113 | + if all(getindex.(int_vars,1) .== DEFAULT_PLOT_FUNC) |
| 114 | + mins = minimum(sol[int_vars[1][3],:]) |
| 115 | + maxs = maximum(sol[int_vars[1][3],:]) |
| 116 | + for iv in int_vars |
| 117 | + mins = min(mins,minimum(sol[iv[3],:])) |
| 118 | + maxs = max(maxs,maximum(sol[iv[3],:])) |
| 119 | + end |
| 120 | + ylims --> ((1-sign(mins)*axis_safety)*mins,(1+sign(maxs)*axis_safety)*maxs) |
| 121 | + |
| 122 | + if length(int_vars[1]) >= 4 |
| 123 | + mins = minimum(sol[int_vars[1][4],:]) |
| 124 | + maxs = maximum(sol[int_vars[1][4],:]) |
| 125 | + for iv in int_vars |
| 126 | + mins = min(mins,minimum(sol[iv[4],:])) |
| 127 | + maxs = max(mins,maximum(sol[iv[4],:])) |
| 128 | + end |
| 129 | + zlims --> ((1-sign(mins)*axis_safety)*mins,(1+sign(maxs)*axis_safety)*maxs) |
| 130 | + end |
| 131 | + end |
| 132 | + end |
| 133 | + |
| 134 | + label --> reshape(labels,1,length(labels)) |
| 135 | + println("----------------------------------MechGlueDiffEqBase") |
| 136 | + (plot_vecs...,) |
47 | 137 | end |
48 | | - # T = Quantity{Float64, ᴸ∙ ᴹ∙ ᵀ⁻², Unitfu.FreeUnits{(N,), ᴸ∙ ᴹ∙ ᵀ⁻², nothing}} |
49 | | - # N = 1 |
50 | | - # A = Vector{Quantity{Float64, ᴸ∙ ᴹ∙ ᵀ⁻², Unitfu.FreeUnits{(N,), ᴸ∙ ᴹ∙ ᵀ⁻², nothing}}} |
51 | | - |
52 | 138 |
|
53 | 139 | end |
0 commit comments