Version 2 (modified by 14 years ago) ( diff ) | ,
---|
Spatial translation of a molecule
Note that we will here explain in full detail how actions are called, this will be omitted in other examples. Note that all code references, such as functions, are linked to the respective files in the source browsers such that you can check on the code right-away.
You can call this translation action via any of the three interface, here we explain it via the CommandLineUI.
The following will start molecuilder with the CommandLineUI as the UIFactory
molecuilder -i test.conf -t 2 0 0 --molecule-by-id 0
It will parse the molecular system found in the pcp config file test.conf and translate it by (2,0,0), i.e. by 2 angstroem in the x direction, and save the file on exit.
But what happens exactly, behind the scenes inside molecuilder?
Code explained
I will break it down into three steps:
- Parsing the input file
- Doing the translation
- Storing updated coordinates to file
Parsing the input file
- What happens exactly here, i.e. how the command line argument -i test.conf is parsed, is explained further below with the translation action. Here, we will emphasize on the parsers for transfering information about molecular systems from the hard drive into the memory.
- For this purpose there is a FormatParser and a ChangeTracker class. The latter is just an observer of the World, noting when something changes, i.e. an atom changes position or its element. Note that the World is the single most important class, containing all atoms, all molecules. FormatParser is a general class to be derived from, i.e. it has virtual functions load() and save() that have to be written in the specializations such as XyzParser or TremoloParser. For each format specification there is such specialization of this FormatParser. Note that not every change in the World is instantly written, just a variable is set noting that something has changed.
- Now, by the file suffix we recognize its format (".conf" means pcp format, i.e. PcpParser). Then, this parser is instantiated with the FormatParserStorage which is simply a container for all instantiated parsers and handles that all output files consist of the same filename only with different suffixes. And the parser's load function will extract the atoms, coordinates and elements, out of the input stream and put them into the World.
Doing the translation
- Now, there is an action class called MoleculeTranslateAction. It has a unique(!) NAME. An Action is nothing but a class containing some data and a performCall() member function wherein the specific doing of the action is coded.
- All actions are instantiated in the so-called MapOfActions by its member function populateActions(), hence also the MoleculeTranslateAction(). Thereby, its NAME and the pointer to its instance is placed in an ActionRegistry, which is a singleton, can be called from anywhere and asked for the instance of a specific action when knowing its name. In this registry the instantiated actions are simply sitting there and waiting to be called forth to do something.
- Moreover, the MapOfActions has lists about which Action belongs to which menu, a short description, what the short form for the command-option is (the long form is always --NAME), what type its parameter has (if any) and also default values (also if any). This information is used by the CommandLineParser to fill in the http://www.boost.org/doc/libs/1_43_0/doc/html/program_options.html boost::program_options with the necessary details to parse all command line arguments into a map for later retrieval.
- See the main() function for an overview what has happened so far and happens now: The CommandLineParser was set, it has parsed all command line arguments and has also noted down their specific ordering on the command line in CommandLineParser::SequenceOfActions. Now, the MainWindow is called. This is the central instance of any user interface (whether textmenu, commandline or graphical) to wait for user interaction.
- In the CommandLineUI variant of the MainWindow in the function display(), we go through this SequenceOfActions. All actions are asked from the repository. If not present, we assume that is not an action but an additonal argument (such as --input or -i above). If it is present, the action is called forth to do the user's bidding.
- In MoleculeTranslateAction::performCall() you notice that first a dialog is constructed and then its display() function is called. This will wait for user interaction and return with a success-or-not statement. If the user input has been complete (success), we proceed and translate the molecule. For this translation action the following information is necessary: The molecule to translate, the vector to translate by and a statement whether periodic boundary conditions shall be adhered.
- These dialogs and their queries are bit more difficult. Each UIFactory variant has its own queries. In case of the text menu, the user is asked on the console for the specific set of values, in the graphical interface a window pops up with boxes to enter the values. However, on the commandline these values have to be fed in already by the knowledgable user: In our case the parameter to our (-t) command line argument, i.e. to our action is the vector. Hence, the dialog receives the action's NAME as reference, whereas for the molecule and the periodicity statement we give the names of options that are defined in MapOfActions. Note that periodicity has a default value of 0 and thus may be omitted.
- These references are necessary for the queries. As in our command line case the queries themselves will turn to CommandLineParser and ask its parsed map of command line arguments for the value belonging to this reference. I.e. for "molecule-by-id" CommandLineParser::vm, contains 0
- With the complete information we call upon molecule::Translate() or molecule::TranslatePeriodically() for the molecule instance obtained via the query.
Storing update info to file
- At the end of the main function, a FormatParserStorage is called again which will create the output streams for all desired formats and ChangeTracker will tell the specific FormatParsers to write the updated information from the World src/World.hpp to file.
- As FormatParserStorage is destroyed at the end of the program, streams are closed.
And that's it.
It might sound complicated but here is a break-down of what is actually needed to create a new action:
- write a new class that inherits from Action as in MoleculeTranslateAction
- give it a decent NAME
- add this NAME along with information about short form, placing in menu, type of parameter into the maps of MapOfActions and insert it also into the generic map.
- if it needs more than one option, check whether appropriatly called options are already in place in the MapOfActions. If not, add your own along type and description information.
And that's all.