5
$\begingroup$

I'm using NDSolve inside a module, and I appear to have a memory leak. The relevant code is:

  mpl = 1/Sqrt[6.70837*10^-39];
  gsT = 106.75;
  Sup[ΛI_?NumericQ, ΓI_?NumericQ] := 
  Module[{a, ρr, Trad, tf, s, t},
     ClearAll[tf]; ClearAll[Trad]; ClearAll[s];
     tf = 10/ΓI;
     ClearAll[a]; ClearAll[ρr];
     s = NDSolve[{a'[t] == a[t]*Sqrt[(8 π)/(3 mpl^2) (ρr[t] + ΛI^4/a[t]^3 Exp[-ΓI t])], ρr'[t] + 4*Sqrt[(8 π)/(3 mpl^2) (ρr[t] + ΛI^4/a[t]^3 Exp[-ΓI t])] ρr[t] == ΓI ΛI^4/a[t]^3 Exp[-ΓI t], a[0] == 1, ρr[0] == 0}, {a, ρr}, {t, 0, tf}, MaxStepFraction -> 10^-5, MaxSteps -> 10^6];
    {a = a /. s[[1]], ρr = ρr /. s[[1]]};
    Trad[t_] := (30/(π^2 gsT) ρr[t])^(1/4);
    Trad[tf]*a[tf]]

(I then evaluate Sup[x,y] for a variety of x and y values; actually, my goal is to make a contour plot of it.)

As you can see, I'm explicitly clearing a[t] and Rho[t] before I call NDSolve; however, these don't appear to get deleted after the module evaluates. Looking at the global variables, I have a$1058, a$1186, and so on. This is causing my memory usage to spiral out of control.

The problem seems to be that DownValues are being assigned to these functions and so they're not getting cleared. (I have set $HistoryLength to zero.)

How can I get the module to really, truly clear these functions?

$\endgroup$
13
  • $\begingroup$ See the last paragraph under Module -- Advanced Uses here. It's likely due to that. The solution is to clear these variables after (not before) they've been used. Try ending the Module with result = Trad[tf]*a[tf]; Clear[...]; result, where you clear everything that doesn't seem to get cleared properly. $\endgroup$
    – Szabolcs
    Commented Mar 26, 2015 at 20:14
  • $\begingroup$ @Szabolcs I tried that (editing the end of the module to be result = Trad[tf]*a[tf]; ClearAll[tf]; ClearAll[Trad]; ClearAll[s]; ClearAll[a]; ClearAll[\ \[Rho]r]; result ) which didn't work- I still get multiple copes in Global` $\endgroup$ Commented Mar 26, 2015 at 20:18
  • $\begingroup$ Do not use ClearAll because it removes the Temporary attribute. Use simply Clear instead. I don't remember all the details of how this works, but see also the comment discussion under the answer I linked. $\endgroup$
    – Szabolcs
    Commented Mar 26, 2015 at 20:20
  • 1
    $\begingroup$ That's because Clear removes definitions associated with the symbol, but it doesn't remove the symbol itself. Remove removed the symbol and replaced references to it (if they exist) with "something else" that is formatted as Removed["name"] but is really a special object. About why this happens: it's strange that e.g. a isn't cleared properly because it doesn't in fact have a downvalue, only an ownvalue. It is likely that NDSolve creates some internal structures that hold references to the symbols that were used in the equation. It might help if ... $\endgroup$
    – Szabolcs
    Commented Mar 26, 2015 at 20:28
  • 1
    $\begingroup$ you don't assign the interpolating functions to the same symbol that you used inside NDSolve. It might also help to use Block instead of Module, as Block doesn't create temporary symbols, it just makes definitions temporary. The usual problem with using Block instead of Module is when you pass symbols to the function (the arguments x and y) that have names identical with something you use internally. This cannot happen here because of ?NumericQ. So Block would be appropriate. All that said, it is still very annoying that this problem happens ... $\endgroup$
    – Szabolcs
    Commented Mar 26, 2015 at 20:29

4 Answers 4

7
$\begingroup$

It is a little known fact and probably not well documented, but since version 9 one can use just strings as variables (dependent and independent) in NDSolve, which in this case helps to solve the memory problem in a rather elegant way:

mpl=1/Sqrt[6.70837*10^-39];
gsT=106.75;
Sup[LamdaI_?NumericQ,GammaI_?NumericQ]:=Module[{
        a,rhor,Trad,tf,s,t
    },
    tf=10/GammaI;
    s=NDSolve[{
            "a"'["t"]=="a"["t"]*Sqrt[(8 Pi)/(3 mpl^2) ("rhor"["t"]+LamdaI^4/"a"["t"]^3 Exp[-GammaI "t"])],
            "rhor"'["t"]+4*Sqrt[(8 Pi)/(3 mpl^2) ("rhor"["t"]+LamdaI^4/"a"["t"]^3 Exp[-GammaI "t"])] "rhor"["t"]==GammaI LamdaI^4/"a"["t"]^3 Exp[-GammaI "t"],"a"[0]==1,"rhor"[0]==0
        },{"a","rhor"},{"t",0,tf},
        MaxStepFraction->10^-5,MaxSteps->10^6
    ];
    a="a"/.s[[1]];
    rhor="rhor"/.s[[1]];
    Trad=Function[t,(30/(Pi^2 gsT) rhor[t])^(1/4)];
    Trad[tf]*a[tf]
]

note that I used a pure function instead of DownValues to define Trad which is also a trick which helps to prevent the known Module leakages. For me this function does not leak any variables anymore and I think should be free of memory leaks as well. Of course one could do the same thing in a programmatical way, but that needs some care to prevent leakage as for some reason even the evaluation of just the derivatives seems to be enough to make the local variables survive as Szabolcs has found out...

Note this seems to be an unwanted feature which just happend to work by accident. Newer versions (I think starting from 11.2) strings are not accepted as variable names anymore, of course making my answer useless for these newer versions...

$\endgroup$
2
2
$\begingroup$

From the comments that Szabolcs gave, Clear and ClearAll are ineffective, but using Remove works. So now the module reads:

    Sup[\[CapitalLambda]I_?NumericQ, \[CapitalGamma]I_?NumericQ] := 
    Module[{a, \[Rho]r, Trad, tf, s, t, result},
      tf = 10/\[CapitalGamma]I;
      s = NDSolve[{a'[t] ==a[t]*Sqrt[(8 \[Pi])/(3 mpl^2) (\[Rho]r[t] + \[CapitalLambda]I^4/a[t]^3 Exp[-\[CapitalGamma]I t])], \[Rho]r'[t] +4*Sqrt[(8 \[Pi])/(3 mpl^2) (\[Rho]r[t] + \[CapitalLambda]I^4/a[t]^3 Exp[-\[CapitalGamma]I t])] \[Rho]r[t] == \[CapitalGamma]I \[CapitalLambda]I^4/a[t]^3 Exp[-\[CapitalGamma]I t],a[0] == 1, \[Rho]r[0] == 0}, {a, \[Rho]r}, {t, 0, tf},MaxStepFraction -> 10^-5, MaxSteps -> 10^6];
     {a = a /. s[[1]], \[Rho]r = \[Rho]r /. s[[1]]};
     Trad[t_] := (30/(\[Pi]^2 gsT) \[Rho]r[t])^(1/4);
     result = Trad[tf]*a[tf];
     Remove[tf]; Remove[Trad]; Remove[s]; Remove[a]; Remove[\[Rho]r]; Remove[t];
     result
     ]

I'm still not entirely sure why Remove works when the others didn't, but it does.

$\endgroup$
3
  • 1
    $\begingroup$ Could it be due to "ClearAll also removes all properties and definitions, but leaves the symbol intact" (from documentation of Remove)? $\endgroup$
    – Mahdi
    Commented Mar 26, 2015 at 20:39
  • 1
    $\begingroup$ ClearAll does remove Temporary, which as @Szabolcs said could be a problem, but Clear doesn't have this issue, and doesn't work either. $\endgroup$ Commented Mar 26, 2015 at 20:40
  • $\begingroup$ I think @Mahdi means that, ClearAll will clear things inside the symbol, but won't destroy the symbol. Actually this is not related to Module, just try a = 1; Clear["a"]; ?a and a = 1; Remove["a"]; ?a. BTW I think using Clear or ClearAll instead of Remove here is OK, because though the temporary variables are still there, they're now empty, which is usually not a big problem. $\endgroup$
    – xzczd
    Commented May 4, 2018 at 5:34
2
$\begingroup$

The reason Clear did not work is because the variables are referenced from the system cache. You need to ClearSystemCache[] as well. (Or wait for the references to get cleared from the cache themselves.)

This thus works:

Sup[ΛI_?NumericQ, ΓI_?NumericQ] := 
 Module[{a, ρr, Trad, tf, s, t, result}, tf = 10/ΓI;
  s = NDSolve[{a'[t] == 
  a[t]*Sqrt[(8 π)/(3 mpl^2) (ρr[
        t] + ΛI^4/
         a[t]^3 Exp[-ΓI t])], ρr'[t] + 
   4*Sqrt[(8 π)/(3 mpl^2) (ρr[
         t] + ΛI^4/
          a[t]^3 Exp[-ΓI t])] ρr[
     t] == ΓI ΛI^4/
    a[t]^3 Exp[-ΓI t], 
 a[0] == 1, ρr[0] == 0}, {a, ρr}, {t, 0, tf}, 
MaxStepFraction -> 10^-5, MaxSteps -> 10^6];
{a = a /. s[[1]], ρr = ρr /. s[[1]]};
Trad[t_] := (30/(π^2 gsT) ρr[t])^(1/4);
result = Trad[tf]*a[tf];
Clear[tf, Trad, s, a, ρr, t];
ClearSystemCache[];
result]

Edit: In fact, one can (at least in 11.1.1) forgo the Clear entirely and just ClearSystemCache. This makes me wonder why it is necessary to do this at all, since in principle the system cache should clear old entries by itself.

$\endgroup$
0
$\begingroup$

The string as a function name method by @Albert Retey no longer work in MMA 11. But Block[] seems to work in this specific case.

  mpl = 1/Sqrt[6.70837*10^-39];
  gsT = 106.75;
  Sup[ΛI_?NumericQ, ΓI_?NumericQ] := 
  Block[{a, ρr, Trad, tf, s, t},
     tf = 10/ΓI;
     s = NDSolve[{a'[t] == a[t]*Sqrt[(8 π)/(3 mpl^2) (ρr[t] + ΛI^4/a[t]^3 Exp[-ΓI t])], ρr'[t] + 4*Sqrt[(8 π)/(3 mpl^2) (ρr[t] + ΛI^4/a[t]^3 Exp[-ΓI t])] ρr[t] == ΓI ΛI^4/a[t]^3 Exp[-ΓI t], a[0] == 1, ρr[0] == 0}, {a, ρr}, {t, 0, tf}, MaxStepFraction -> 10^-5, MaxSteps -> 10^6];
    {a = a /. s[[1]], ρr = ρr /. s[[1]]};
    Trad[t_] := (30/(π^2 gsT) ρr[t])^(1/4);
    Trad[tf]*a[tf]]

Try to run it by

Table[{Sup[10^16, 10^8], Information["a$*"]}, {3}]

You should not see any new a$XXXXX generated.

$\endgroup$

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.