-
Notifications
You must be signed in to change notification settings - Fork 389
Description
See also #1772.
Update: The basic idea of this change is to keep track of whether the simulation is currently in a prepared state (e.g. nest.Prepare() has been called, but nest.Cleanup() hasn't), and put nest.Prepare and nest.Cleanup into wrappers which only invoke the expensive kernel functions if they are necessary/appropriate according to that status. The current motivation for exposing Prepare/Run/Cleanup rather than just one simulation command to the PyNEST user is that the user can save time by not cleaning up between runs (see the Running simulations guide). With the wrappers, the overhead of calling nest.Prepare twice becomes negligible, and we can remove much of that complexity from the API and documentation (see below for details and precisifications).
Is your feature request related to a problem? Please describe.
It is related to the problem I described in #1772, which is related to the fact that the user has to learn about 4 commands (Update: actually 5, if you include the RunManager)+at least 1 pitfall (see #1772 for the pitfall) for running simulations once vs. in stages. It seems to me that, by introducing some wrappers on the PyNEST level, the pitfall would vanish, only 2 functions would be necessary to document/understand (and the others could be deprecated/removed), and almost all users would only need to learn about 1 of them. I write here to understand whether I am missing something and it's more complicated in reality.
Describe the solution you'd like
- The PyNEST API module keeps track of a global Boolean variable "prepared". It is initialized to
False. nest.Prepare()is replaced by a wrapper that only calls the originalnest.Prepare()ifprepared == False, and setsprepared = Trueafterwards.nest.Run()is replaced by a wrapper that checks ifprepared == True, and callsnest.Prepare()before the originalnest.Run()if it was false. UPDATE/Clarification: If it finds thatprepared == Truealready, it skips thePrepare()call. Another UPDATE: Actually, because the new Prepare() checks whetherprepared == Truealready and doesn't invoke the NEST kernel if it is, it wouldn't hurt performance too much to skip the check in the new Run() function.nest.Simulate()is replaced by a wrapper that calls the newnest.Run()(which in turn will callnest.Prepare()if the simulation wasn't prepared), followed bynest.Cleanup().nest.SetStatus()is replaced by a wrapper that checks ifprepared == False, and callsnest.Cleanup()before the originalnest.SetStatus()otherwise. UPDATE: We also could skip the if check without much performance cost, as the newnest.Cleanup()will also check whetherprepared == Trueand not do anything expensive if it is already/stillFalse.model.set()changed in the same way asnest.SetStatus().nest.Cleanup()is replaced by a wrapper that only calls the originalnest.Cleanup()ifprepared == True, and setsprepared = Falseafterwards.- include
atexit.register(Cleanup)from theatexitmodule in the PyNEST initialisation code so thatnest.Cleanup()is called on program exit automatically (would this work in the way I understand it works?). nest.RunManager()deprecated/removed.
Alternatively, one could implement these wrapper functions in the NEST kernel.
If I understand correctly, these changes by themselves would be completely backwards-compatible and not change the behaviour of currently correct PyNEST simulation code (as well as introducing minimal overhead). However, they would make life easier for the user, who now can usually call nest.Run() instead of understanding and distinguishing Prepare/Cleanup/Simulate/Run. Only in the presumably rare case where they want to close/sync files in the middle of the simulation script, they would also need to know about and call nest.Cleanup(). The other functions (nest.Simulate() and nest.Prepare()) could be deprecated/removed from the documentation and user-visible API in the next step. The SetStatus-after-Prepare pitfall (#1772) would vanish.
Describe alternatives you've considered
I'm somewhat on the fence on whether to call the new nest.Run() function "nest.Run()" or "nest.Simulate()", because:
In the variant described above, the remaining difference between the new nest.Run() and the new nest.Simulate() would be that, as is the case currently, nest.Simulate() will be guaranteed to exit with the kernel in a cleaned-up state/files closed/whatever.
If we instead call the function that becomes the new nest.Run() above "nest.Simulate()", I see two advantages and a disadvantage:
-
Advantages: I guess that most simulation code out there is fine with an unclean kernel after Simulate, and the cleanup being done automatically once on script termination (with the
atexithandler). So just calling the newnest.Run()nest.Simulate()will be fine, and scripts will continue to work without users having to learn about a new command/changing their scripts/understanding one more entry in the NEST-X-to-X+1 porting guide. Scripts that didn't care about using Prepare/Run/Simulate before will can become faster. -
Disadvantage: However, if a script depends on the kernel being cleaned up after a
Simulate()call in the middle of the python code, and theSimulatesuddenly stops doing that, it may cause a lot of grief to whatever student tries to port that script to the next NEST version and doesn't understand why it doesn't work anymore.
Am I missing something here, and is it more complicated to do? If my understanding is correct, this seems like a relatively straightforward change in the PyNEST module to me, which I'd be happy to implement and write some unit tests for.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status