ダイナミクスを直接使用する高速アルゴリズムを使用してODEの解の結果をプロットするコードを考えると、画面上に解を非常に高速にプロットすることがわかります。
このアルゴリズムをManipulate[]に統合したところ、プロット部分が以前よりもはるかに遅くなっていることに気付きました。
私はこれに4時間費やしましたが、これがなぜなのかわかりません。私は誰かが問題と問題が何であるかを見つけることができることを願っています。
アルゴリズムは、ここでの私の他の質問に対するレオニードの回答で今日投稿されたものです(レオニードに感謝します!)
アルゴリズムは非常に高速であり、プロットも高速にレンダリングします。ただし、ダイナミクスを直接使用します。Manipulate内で使用したいのですが。
私はそれをManipulateに統合しましたが、私が知っている限りでは、コードが進んでいるので、正しく実行したかどうかはわかりませんが、結果は正しいです。
プロットは機能し、元のアルゴリズムと同じように正しいプロットを生成しますが、プロットの速度ははるかに遅くなりました。すべてのパラメーターは両方の場合で同じです(つまり、問題のパラメーター)。これは私が長い間苦労してきた問題です。マニピュレートを使用するときにfpsを高速化する方法。
したがって、問題は、Manipulate内で実行するために統合することにあるか、効率的でないものを作成したか、ManipulateがすでにDynamicModule []を使用しており、これがプロットのレンダリングを遅くしたり、プロセス全体を遅くしたりするという副作用があったためである可能性があります。
Leonidコードを統合したManipulateコードを投稿します(さまざまな方法を試しましたが、すべてプロットが遅くなります。これは以下の1つのバージョンです)。
Manipulate[
Module[{ll = emptyList[], sol, plot, t, y, angle,
llaux = emptyList[]},
plot[] :=
Graphics[{Hue[0.67`, 0.6`, 0.6`], Line[fromLinkedList[ll]]},
AspectRatio -> 1/GoldenRatio, Axes -> True,
AxesLabel -> {"time", "angle"},
PlotRange -> {{0, max}, {-Pi/4, Pi/4}}, PlotRangeClipping -> True];
llaux = ll;
sol := First@
NDSolve[{y''[t] + 0.01 y'[t] + Sin[y[t]] == 0, y[0] == Pi/4,
y'[0] == 0}, y, {t, time, time + 1}];
angle := y /. sol;
ll := With[{res =
If[llaux === emptyList[] || pop[llaux][[1]] != time,
addToList[llaux, {time, angle[time]}],(*else*)llaux]},
llaux = res];
Dynamic[plot[]]
]
,
{{time, 0, "run"}, 0, max, Dynamic@delT, AnimationRate -> 1,
ControlType -> Trigger}, {{delT, 0.01, "delT"}, 0.01, 1, 0.01,
Appearance -> "Labeled"},
{{y0, Pi/4, "y(0)"}, -Pi, Pi, Pi/100, Appearance -> "Labeled"},
{{yder0, 0, "y'(0)"}, -1, 1, .1, Appearance -> "Labeled"},
{{linkedList, {}}, None},
TrackedSymbols :> {time},
Initialization :> (
max = 200;
toLinkedList[data_List] := Fold[linkedList, linkedList[], data];
fromLinkedList[ll_linkedList] :=
List @@ Flatten[ll, Infinity, linkedList];
addToList[ll_, value_] := linkedList[ll, value];
pop[ll_] := Last@ll;
emptyList[] := linkedList[];
)
]
これが元のコードで、Leonidがここに投稿したものとまったく同じですが、上部に2つのパラメーターを追加したので、速度を比較しやすくするために、両方のバージョンでまったく同じパラメーターが実行されます。これを実行すると、上記と比較して、画面上でプロットが生成される速度に気付くでしょう。
なぜ速度の違いがあるのかを見つけるのに助けが欲しいです。アルゴリズムが外部では非常に高速であることがわかっているので、プロットの速度の違いはManipulate内のDyanmicsの相互作用によるものであると仮定します。
max = 200; delT = 0.01;
ClearAll[linkedList, toLinkedList, fromLinkedList, addToList, pop,
emptyList];
(*SetAttributes[linkedList,HoldAllComplete];*)
toLinkedList[data_List] := Fold[linkedList, linkedList[], data];
fromLinkedList[ll_linkedList] :=
List @@ Flatten[ll, Infinity, linkedList];
addToList[ll_, value_] := linkedList[ll, value];
pop[ll_] := Last@ll;
emptyList[] := linkedList[];
Clear[getData];
Module[{ll = emptyList[], time = 0, restart, plot, y},
getData[] := fromLinkedList[ll];
plot[] :=
Graphics[{Hue[0.67`, 0.6`, 0.6`], Line[fromLinkedList[ll]]},
AspectRatio -> 1/GoldenRatio, Axes -> True,
AxesLabel -> {"time", "angle"},
PlotRange -> {{0, max}, {-Pi/4, Pi/4}}, PlotRangeClipping -> True];
DynamicModule[{sol, angle, llaux},
restart[] := (time = 0; llaux = emptyList[]);
llaux = ll;
sol := First@
NDSolve[{y''[t] + 0.01 y'[t] + Sin[y[t]] == 0, y[0] == Pi/4,
y'[0] == 0}, y, {t, time, time + 1}];
angle := y /. sol;
ll := With[{res =
If[llaux === emptyList[] || pop[llaux][[1]] != time,
addToList[llaux, {time, angle[time]}],(*else*)llaux]},
llaux = res
];
Column[{
Row[{Dynamic@delT, Slider[Dynamic[delT], {0.01, 1., 0.01}]}],
Dynamic[time, {None, Automatic, None}],
Row[{Trigger[Dynamic[time], {0, max, Dynamic@delT},
AppearanceElements -> {"PlayPauseButton"}],
Button[Style["Restart", Small], restart[]]}
],
Dynamic[plot[]]}, Frame -> True
]
]
]
ヒントや試してみてくれてありがとう。
アップデート
わかりました、これは面白くなってきています。Dynamicsを使用するだけでCDFを作成できることを私は知りませんでした。Manipulateを使用する必要があると思いました。しかし、私は間違っていました。試してみましたが、実際に動作します。 これは私のサイトにあります。これは、減衰駆動振り子(関節に駆動力が存在するために無秩序な動きを示す)のシミュレーションであり、マニピュレートではなくダイナミクスを使用して記述されています。
上記のコードは次のとおりです。
DynamicModule[{sol, angle, bob, r, time = 0, animationRate = 1},
(*simulation of damped and driven pendulum, exhibit chaotic motion*)
Dynamic@Grid[{
{Trigger[Dynamic[time], {0, Infinity, 0.01}, animationRate,
AppearanceElements -> {"PlayPauseButton", "ResetButton"}],
Style["time (sec)", 10], Dynamic[time]},
{
Dynamic@Show[Graphics[{
{Dashed, Gray, Thin, Circle[{0, 0}, 1]},
{Red, Thick, Line[{{0, 0}, bob}]},
{Blue, PointSize[0.1], Point[bob]}
}, ImagePadding -> 10], ImageSize -> 300], SpanFromLeft
}}, Frame -> True, Alignment -> Left],
Initialization :>
(
sol :=
First@NDSolve[{y''[t] + 0.1 y'[t] + Sin[y[t]] == 1.5 Cos[t],
y[0] == Pi/4, y'[0] == 0}, y, {t, time, time + 1},
Sequence@ndsolveOptions];
bob := {Sin[(y /. sol)[time]], - Cos[(y /. sol)[time]]};
ndsolveOptions = {MaxSteps -> Infinity,
Method -> {"StiffnessSwitching",
Method -> {"ExplicitRungeKutta", Automatic}},
AccuracyGoal -> 10, PrecisionGoal -> 10};
)
]
これは、ダイレクトダイナミクスを使用した最初のCDFです。画面の更新におけるパフォーマンスの違いを確認したい場合は、Manipulateを使用した上記のバージョンを次に示します。この場合、大きな違いはわかりませんでしたが、これは振り子の位置をプロットしていること、バッファリングは不要、データ処理はないことに注意してください。ボブの位置をポイントごとにプロットするだけです。
Manipulate[
(
sol = First@
NDSolve[{y''[t] + 0.1 y'[t] + Sin[y[t]] == 1.5 Cos[t],
y[0] == Pi/4, y'[0] == 0}, y, {t, time, time + 1},
Sequence@ndsolveOptions];
bob = {Sin[(y /. sol)[time]], - Cos[(y /. sol)[time]]};
Show[Graphics[{
{Dashed, Gray, Thin, Circle[{0, 0}, 1]},
{Red, Thick, Line[{{0, 0}, bob}]},
{Blue, PointSize[0.1], Point[bob]}
}, ImagePadding -> 10], ImageSize -> 300]
),
{{time, 0, "run"}, 0, Infinity, 0.01, AnimationRate -> animationRate,
AppearanceElements -> {"PlayPauseButton", "ResetButton"}},
Initialization :>
(
animationRate = 1;
ndsolveOptions = {MaxSteps -> Infinity,
Method -> {"StiffnessSwitching",
Method -> {"ExplicitRungeKutta", Automatic}},
AccuracyGoal -> 10, PrecisionGoal -> 10};
)
]
ダイナミクスだけでCDFを作成できるようになったのは非常に興味深いことだと思います。