1
$\begingroup$

I defined a system of ODEs inside a Manipulate environment. I would like to draw multiple plots of the same NDSolve solution, i.e. I want to plot each variable separately. My code is pretty straightforward (see a little working example below), but I have performance issues.

My guess is that NDSolve is evaluated every time is called inside a Plot. Is there a way to avoid that? Am I doing something wrong (I am an absolute beginner with Mathematica)?

Here is a minimal working example:

Manipulate[
 Module[{sol, t, a, b, kb = 1.0},
  sol = NDSolve[
    {a'[t] == kb*b[t],
     b'[t] == -ka*b[t],
     a[0] == 0.1, b[0] == 0.1},
    {a, b}, {t, 0.0, 5.0}];
  GraphicsRow[{
    Plot[a[t] /. sol, {t, 0.0, 5.0}],
    Plot[b[t] /. sol, {t, 0.0, 5.0}]}
   ]
  ],
 {{ka, 1.0, "ka"}, 1.0, 100.0}
]
$\endgroup$
  • $\begingroup$ Since you're using = and not := NDSolve shouldn't be recomputing when you plot. There might be a trick or two you could do to make this faster (e.g. prerender the plots for specific values of ka then just use manipulate to display parts: plts=Table[Module[{...},sol=NDSolve[...];GraphicsRow[...]],{ka,1.0,100.,10.}]; Manipulate[plts[[i]],{i,1,Length@plts,1}]) but this runs just as fast as I can move the slider on my machine. $\endgroup$ – N.J.Evans Dec 20 '17 at 17:57
5
$\begingroup$

One way is to use DSolve and solve the ODE once, then replace the parameter ka into the solution. Now it is very fast

Manipulate[

GraphicsRow[{
   Plot[a[t]/.sol/.{ka0->ka},{t,0.0,5.0}],
   Plot[b[t]/.sol/.{ka0->ka},{t,0.0,5.0}]
}
],
{{ka,1.0,"ka"},1.0,100.0},
TrackedSymbols:>{ka},
Initialization:>
{
  kb=1;
  sol=First@DSolve[{a'[t]==kb*b[t],b'[t]==-ka0*b[t],a[0]==1/10,b[0]==1/10},
     {a[t],b[t]},t]
}    
]

Notice that when using Initialization section in Manipulate, the symbols in there become global.

enter image description here

Update

To answer comment below. If there is no closed form solution, then the same thing can be done but using ParametricNDSolve as follows

Manipulate[

GraphicsRow[{
  Plot[a[ka][t]/.sol ,{t,0.0,5.0}],
  Plot[b[ka][t]/.sol ,{t,0.0,5.0}]
}
],
  {{ka,1.0,"ka"},1.0,100.0},
  TrackedSymbols:>{ka},

Initialization:>
{
  kb=1;
  sol=ParametricNDSolve[{a'[t]==kb*b[t],b'[t]== 
          - ka0*b[t],a[0]==1/10,b[0]==1/10},{a,b},{t,0,5},{ka0}]
}    
]
$\endgroup$
  • $\begingroup$ Works only if there is an closed-form solution to the ODE :) $\endgroup$ – anderstood Dec 20 '17 at 19:34
  • 2
    $\begingroup$ @anderstood that is correct of course. The ODE given does have closed form solution. If there was no closed form solution, then ParametricNDSolve can be used. Will update now. $\endgroup$ – Nasser Dec 20 '17 at 21:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.