|
1 | 1 | module MechGlueDiffEqBase |
2 | | -import Unitfu: AbstractQuantity, Quantity, ustrip |
3 | | -import DiffEqBase: value, ODE_DEFAULT_NORM, UNITLESS_ABS2 |
| 2 | +import Unitfu: AbstractQuantity, Quantity, ustrip, norm |
| 3 | +import DiffEqBase: value, ODE_DEFAULT_NORM, UNITLESS_ABS2, zero |
| 4 | +import DiffEqBase: calculate_residuals, @muladd |
| 5 | +using RecursiveArrayTools |
4 | 6 | export value, ODE_DEFAULT_NORM, UNITLESS_ABS2, Unitfu, AbstractQuantity, Quantity |
| 7 | +export norm, ArrayPartition |
5 | 8 |
|
6 | | - |
7 | | -import RecipesBase |
8 | | -import RecipesBase.@recipe |
9 | | -import SciMLBase |
10 | | -import SciMLBase: AbstractTimeseriesSolution, RecipesBase |
11 | | -import SciMLBase: AbstractDiscreteProblem, AbstractRODESolution, SensitivityInterpolation |
12 | | -import SciMLBase: getsyms, interpret_vars, cleansyms |
13 | | -import SciMLBase: diffeq_to_arrays, issymbollike, getindepsym_defaultt |
14 | | -import SciMLBase: DEFAULT_PLOT_FUNC |
15 | | - |
16 | | - |
| 9 | +# This is identical to what DiffEqBase defines for Unitful |
17 | 10 | function value(x::Type{AbstractQuantity{T,D,U}}) where {T,D,U} |
18 | 11 | T |
19 | 12 | end |
20 | | -function value(x::AbstractQuantity) |
21 | | - x.val |
22 | | -end |
| 13 | +# This is different from what DiffEqBase defines for Unitful |
| 14 | +value(::Type{<:AbstractQuantity{T,D,U}}) where {T,D,U<:Core.TypeofBottom} = Base.undef_ref_str |
| 15 | +value(x::Q) where {Q<:AbstractQuantity} = ustrip(x) |
| 16 | + |
| 17 | + |
| 18 | +# This is identical to what DiffEqBase defines for Unitful |
23 | 19 | @inline function ODE_DEFAULT_NORM(u::AbstractArray{<:AbstractQuantity,N},t) where {N} |
| 20 | + # Support adaptive errors should be errorless for exponentiation |
24 | 21 | sqrt(sum(x->ODE_DEFAULT_NORM(x[1],x[2]),zip((value(x) for x in u),Iterators.repeated(t))) / length(u)) |
25 | 22 | end |
| 23 | +# This is identical to what DiffEqBase defines for Unitful |
26 | 24 | @inline function ODE_DEFAULT_NORM(u::Array{<:AbstractQuantity,N},t) where {N} |
27 | 25 | sqrt(sum(x->ODE_DEFAULT_NORM(x[1],x[2]),zip((value(x) for x in u),Iterators.repeated(t))) / length(u)) |
28 | 26 | end |
29 | | -@inline function ODE_DEFAULT_NORM(u::AbstractQuantity,t) |
30 | | - abs(value(u)) |
| 27 | + |
| 28 | +# This is identical to what DiffEqBase defines for Unitful |
| 29 | + |
| 30 | +@inline function ODE_DEFAULT_NORM(u::AbstractQuantity, t) |
| 31 | + abs(ustrip(u)) |
31 | 32 | end |
| 33 | +# This is slightly different from what DiffEqBase defines for Unitful |
32 | 34 | @inline function UNITLESS_ABS2(x::AbstractQuantity) |
33 | | - real(abs2(x)/oneunit(x)*oneunit(x)) |
| 35 | + real(abs2(x) / (oneunit(x)^2)) |
34 | 36 | end |
35 | | - |
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. |
38 | | -@recipe function f(sol::AbstractTimeseriesSolution{T, N, A}; |
39 | | - plot_analytic=false, |
40 | | - denseplot = (sol.dense || |
41 | | - typeof(sol.prob) <: AbstractDiscreteProblem) && |
42 | | - !(typeof(sol) <: AbstractRODESolution) && |
43 | | - !(hasfield(typeof(sol),:interp) && |
44 | | - typeof(sol.interp) <: SensitivityInterpolation), |
45 | | - plotdensity = min(Int(1e5),sol.tslocation==0 ? |
46 | | - (typeof(sol.prob) <: AbstractDiscreteProblem ? |
47 | | - max(1000,100*length(sol)) : |
48 | | - max(1000,10*length(sol))) : |
49 | | - 1000*sol.tslocation), |
50 | | - tspan = nothing, axis_safety = 0.1, |
51 | | - vars=nothing) where {T<:Quantity, N, A<:Array{<:Quantity}} |
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...,) |
137 | | -end |
138 | | - |
139 | 37 | end |
0 commit comments