/* * Project: MoleCuilder * Description: creates and alters molecular systems * Copyright (C) 2010 University of Bonn. All rights reserved. * Please see the LICENSE file or "Copyright notice" in builder.cpp for details. */ /** * \file python.dox * * Created on: Nov 01, 2011 * Author: heber */ /** * \page userinterfaces-python Python module * * Via boost::python all of Molecuilder Action's are exported into a python * module such that all functionality can also be directly used in a python * script. * * This is done in \b src/Python/PythonScripting.cpp. * * There again some preprocessor magic is happening. One the one hand we * need GlobalListOfActions.hpp to have a list of all actions available. * Second, in AllActionPython.hpp we define export functions for every * Action (in essence we use the COMMAND function, see Action_impl_pre.hpp, * which makes an Action usable internally as a normal function). * * Then, at the beginning of the BOOST_PYTHON_MODULE declaration we initialize * the ActionHistory (same as in main() in builder.cpp), and on exit we * perform cleanUp() via the atexit() hook to make sure that everything * is not only removed but more importantly in the correct orders. This is * required because we use many static elements which have to be deinitialized * in the correct sequence as they depend on one another. * * \section userinterfaces-python-first-test A first test script * * A small python test script would then look like this: * \code * import pyMoleCuilder as mol * mol.WorldInput("test.xyz") * mol.SelectAtomById("0") * mol.AtomRemove() * mol.wait() * mol.getSelectedMolarMass() * mol.wait() * \endcode * which loads a file \b test.xyz into the (internal) World, selects the first * atom and removes it. Notice \b mol.wait() at the end. This might be necessary * as actions are executed in a different thread than the python script itself. * Hence, if you require values from molecuilder you have to make sure that * all your actions have been processed by this second thread. That's what * wait() is good for. It waits until action queue thread is idle. Then you * can be sure that molecuilder has removed all atoms, performed all selections * and any value you retrieve is up-to-date. * * Note that there are two \b wait()s present in the example. As the Actions * are executed in another thread and the above commands just tell the MoleCuilder * library (the ActionQueue to be precise) to enqueue the requested action, * we have to wait (in the main thread) until the actions actually have been * executed before we continue (i.e. when we need the new state where the * atoms have been removed) and before we \b terminate! * * \section userinterfaces-python-running Running a test script * * In most cases however, python cannot find the library (except molecuilder * has been installed in some system-default folder). In this case you should * prefix your call to the python interpreter with: * \code * PYTHONPATH="/src/.libs" python * \endcode * where \a is the top build directory of molecuilder. If you have * installed molecuilder (\code make install \endcode), but the * \a (i.e. the \a prefix given at to the configure call) is non- * standard, then prepend this * \code * PYTHONPATH="/share/site-packages" python * \endcode * * \section userinterfaces-python-autostart Using python script as autostart file * * If in the current directory a file \b molecuilder.py is found, the contents * is executed as a regular python script. * * \note Each commands needs to be taken from a molecule called \a pyMoleCuilder. * Hence, use * \code * pyMoleCuilder.WorldInput("test.xyz") * pyMoleCuilder.wait() * \endcode * * \note Each command needs to be followed by brackets regardless of any present * arguments. * \code * pyMoleCuilder.SelectionAllMolecules() * pyMoleCuilder.wait() * \endcode * * \note Each argument must be given as a string as it is basically as if the * commands were given on the command line, \sa userinterfaces-commandline * \code * pyMoleCuilder.SelectAtomById("0") * pyMoleCuilder.wait() * \endcode * * \warning Again, take note of the added wait()s that ensure the all enqueued * actions also have been executed. This is especially important in scripts as * otherwise your script may deadlock. That's because ActionQueue's destructor * waits for the thread that executes the actions to end, and in another thread * we still want to access to ActionQueue whose instance is however locked as * it is about the get destroyed. * * \subsection userinterfaces-python-notes-cleanup Cleaning up or reset state ... * * Whenever you need to reset the internal state of the molecuilder, i.e. * you want to save the current file and work on something new, use * \code * mol.cleanUp() * \endcode * This frees all memory, removes all static instances on the heap, and saves * your input file (\sa WorldInputAction). * * \subsection userinterfaces-python-help Help inside the interpreter * * Note that the pyMoleCuilder module is fully documented. I.e. * \code * import pyMoleCuilder as mol * help(mol) * \endcode * gives you a complete list of present functions/Actions in the module * including their signature and a brief description (this is all * automatically generated via the proprocessor magic from the Action's * \b .def files). * * Likewise you may obtain help on each single function, e.g. * \code * import pyMoleCuilder as mol * help(mol.WorldInput) * \endcode * gives you the docu string on WorldInputAction. * * \subsection userinterfaces-python-notes-wait Waiting for the action queue * * Note again that actions are executed in a different thread as the python * script. Hence, we require synchronization at certain intervals where you * require molecuilder to be up to speed. All commands you executed such * as * \code * import pyMoleCuilder as mol * mol.WorldInput("foo.xyz") * mol.wait() * \endcode * just queue this specific input action but not execute it right away. That's * left to the other thread. Hence, you need to wait() before: * -# you access mol.get...() functions as these are not actions themselves. * -# you need to have files written by molecuilder to be parsed in the python * script. * * * \date 2013-09-28 * */