3
$\begingroup$

I have a notebook which I want to execute multiple times and changing one parameter each time. Intuitively, I want to do something like this:

Table[
        FolderNumber= i; (*  this is the variable inside NoteBookToRun *)
        nb = NotebookOpen[FileNameJoin[{Directory[], NoteBookToRun}]];
        SelectionMove[nb,All,Notebook];
        SelectionEvaluate[nb];

            {ResultsFromNoteBookToRun},
        {i, 1, NumberOfFolders}
     ]

Obviously this won't work because the Table needs to finish before the targeted notebook will execute, so the maximum number I think this can work for is 2.

How can I get my notebook to run multiple times while changing a parameter inside the notebook I want to run?

$\endgroup$
  • 1
    $\begingroup$ Take your notebook code and turn it into a bunch of functions. Save those as a package, maybe. This is what packages are built for. Then you can load the package and call some function that just runs the script. $\endgroup$ – b3m2a1 Feb 4 at 20:32
  • $\begingroup$ That's certainly an option but at this point I would prefer to have a solution where I can just call the notebook -- if possible. If it isn't then I will close the question and just do it manually $\endgroup$ – Q.P. Feb 4 at 20:45
  • $\begingroup$ ...why would you willingly make your life harder like that? Turning the script into a bunch of functions will be almost zero work $\endgroup$ – b3m2a1 Feb 4 at 20:50
  • $\begingroup$ As I said, that is an alternative to what I am asking. If what I am asking is not possible within M, then your suggestion is the answer. But for now what you suggest is NOT an answer to my question...I may as well just stick a loop around my script...there are reasons I don't want to break my code down. $\endgroup$ – Q.P. Feb 5 at 14:21
  • 1
    $\begingroup$ Question 67050 and the answers to it may provide some insights. $\endgroup$ – bbgodfrey Feb 5 at 17:39
2
+100
$\begingroup$

Starting with your intended code...

Table[
        FolderNumber= i; (*  this is the variable inside NoteBookToRun *)
        nb = NotebookOpen[FileNameJoin[{Directory[], NoteBookToRun}]];
        SelectionMove[nb,All,Notebook];
        SelectionEvaluate[nb];

            {ResultsFromNoteBookToRun},
        {i, 1, NumberOfFolders}
     ]

...as you know, SelectionEvaluate is a poor choice for this because all it does it to queue the evaluation, not perform the evaluation and wait for a response. What you probably don't realize is that the similarly-named NotebookEvaluate function (available since v8) is much more powerful and does something very different. It evaluates the notebook synchronously, not returning until the notebook is fully evaluated -- not unlike evaluating a package.

NotebookEvaluate can insert the results or not depending upon the InsertResults option. And you don't even have to visibly open and close notebook windows. NotebookEvaluate, if given a filename for a notebook which is currently unopened, will invisibly open, evaluate, and close the window (saving if needed to insert results).

Changing your proposed code to use NotebookEvaluate is pretty straightforward:

Table[
        FolderNumber= i; (*  this is the variable inside NoteBookToRun *)
        NotebookEvaluate[FileNameJoin[{Directory[], NoteBookToRun}]];
            {ResultsFromNoteBookToRun},
        {i, 1, NumberOfFolders}
     ]

This version follows the default behavior to not insert the results into the notebooks, but if you wish to change that, simply add InsertResults->True.

| improve this answer | |
$\endgroup$
  • $\begingroup$ Enjoy that delicious bounty!! Brilliant this is exactly what I was after. I am sure there are more elegant methods using modules but this fits my needs right now perfectly! $\endgroup$ – Q.P. Feb 11 at 10:29
3
$\begingroup$

I have not used this code in quite a while but I think it still works. The calling notebook could be

Dynamic[{loop, linked`vdtdz}]
distab = {}; Dynamic[distab // TableForm]
Dynamic[return]

Do[linked`vdtdz = 0.1 loop; linked`$callingNotebook = EvaluationNotebook[];
return = NotebookEvaluate[$UserDocumentsDirectory<>"/Mathematica/PSTD_Solve.nb"];
distab = Append[distab, linked`maxai], {loop, 8, 10}]

It passes a variable

linked`vdtdz

and saves the returned variable

linked`maxai

It also temporarily displays a pair of plots produced by the called notebook.

The called notebook begins with

linked = ValueQ[linked`$callingNotebook]; Clear[linked`$callingNotebook]

which determines whether the called notebook actually has been called by another notebook, as opposed to being run on its own. Later, the called notebook uses the passed variable

vdtdz = If[linked, linked`vdtdz, 1.0]; \[CapitalDelta]t0 = vdtdz \[CapitalDelta]z0/vz0

Still later, the called notebook saves plots to disk, depending on whether it actually has been called by another notebook.

If[linked, saveplot = True, (*other code*)]

On its last line of code, the called notebook stores the answer to be returned to the calling notebook and also creates a final pair of plots which automatically are returned.

If[linked, linked`maxai = kout[[1, 4]]; Grid[{{grow3D, growContour}}]]

This may be more than you want. If so, delete what is unnecessary (the plots and the use of Dynamic, for instance).

| improve this answer | |
$\endgroup$

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.