1
$\begingroup$

I know that this is a "beginner question", and, in fact, I am. I want to improve my code, as it takes really too much time to run. I have already read some other discussions, like here, but I am struggling in translating the simplifications with Table or Do into my example.

The For cycle I want to improve is the following:

zh = 0.4;
list = {};

For[i = 1, i < 10000, i++, 
    With[{zg = -0.6, dh = i*10^-2}, 
         nsol = Block[{eps = $MachineEpsilon}, 
         NDSolve[{phi''[x] + 2*phi'[x]/x + (2*(zg + zh*Exp[-zh*x/dh])/x + 1)*phi[x] == 0, phi[eps] == 1, phi'[eps] == -(zg + zh)}, phi, {x, eps, 20000}, 
                 WorkingPrecision->MachinePrecision, AccuracyGoal->15, PrecisionGoal->8, MaxSteps->Infinity]]];  
    AppendTo[list, 1/Evaluate[(15000*phi[15000])^2 + ((15000-Pi/2)*phi[15000-Pi/2])^2 /. nsol[[1]]]];]

Clearly, this code, written in this way, is highly inefficient. Also, I need to do more of these, with different values for zg inside With, and make some plots out of the lists.

Anyone that can help me with this noob question? Thanks a lot!

$\endgroup$
  • $\begingroup$ Eliminate the AppendTo inside the loop and use Sow and Reap instead. $\endgroup$ – Daniel Huber Oct 21 '20 at 16:12
  • $\begingroup$ Can you provide me with an example? $\endgroup$ – Lele Oct 21 '20 at 16:17
  • $\begingroup$ You should take a look at this, if you haven't yet: mathematica.stackexchange.com/q/134609/12 The documentation of Sow and Reap has several relevant examples. $\endgroup$ – Szabolcs Oct 21 '20 at 16:43
  • 2
    $\begingroup$ Actually I don't see any need for Sow/Reap here. Just use Table. $\endgroup$ – Szabolcs Oct 21 '20 at 16:49
  • 1
    $\begingroup$ I don't see why Table wouldn't work—what exactly have you tried? Also, the code you posted here doesn't run (which is why I can't directly give you the Table translation). Please show a complete, minimal, working example. $\endgroup$ – Szabolcs Oct 21 '20 at 18:58
4
$\begingroup$

Here is an example that uses Table (well, ParallelTable) instead of For. I've also used ParametricNDSolveValue instead of With, mostly to simplify the Table.

phifunc = ParametricNDSolveValue[
  {\[Phi]''[x] + 2 \[Phi]'[x]/x + (2 (zg + zh Exp[-zh x/dh])/x + 1) \[Phi][x] == 0
   , \[Phi][$MachineEpsilon] == 1
   , \[Phi]'[$MachineEpsilon] == -(zg + zh)
   }
  , 1/((15000 \[Phi][15000])^2 + ((15000 - \[Pi]/2) \[Phi][
         15000 - \[Pi]/2])^2)
  , {x, $MachineEpsilon, 20000}
  , {dh \[Element] Reals, zg \[Element] Reals, zh \[Element] Reals}
]
list = ParallelTable[phifunc[i 10^-2, -0.6, 0.4], {i, 1, 10000}]

As far as timing goes, it still seems to take a very long time to run 10000 evaluations, so another answer might provide a faster method. I vaguely recall a way to functionalize calls to NDSolve in a way that stores calculations for faster repeated calls, but I can't find the link.

$\endgroup$
  • $\begingroup$ Thank you @Josh Bishop, this looks better! It still takes a lot of time, though.. $\endgroup$ – Lele Oct 22 '20 at 10:45

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.