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$
1
  • $\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
    Commented Dec 20, 2017 at 17:57

1 Answer 1

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$
2
  • $\begingroup$ Works only if there is an closed-form solution to the ODE :) $\endgroup$
    – anderstood
    Commented Dec 20, 2017 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
    Commented Dec 20, 2017 at 21:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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