Merge branch 'release-4-6'
[alexxy/gromacs.git] / src / gromacs / selection / selhelp.cpp
1 /*
2  *
3  *                This source code is part of
4  *
5  *                 G   R   O   M   A   C   S
6  *
7  *          GROningen MAchine for Chemical Simulations
8  *
9  * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
10  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
11  * Copyright (c) 2001-2009, The GROMACS development team,
12  * check out http://www.gromacs.org for more information.
13
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  *
19  * If you want to redistribute modifications, please consider that
20  * scientific software is very special. Version control is crucial -
21  * bugs must be traceable. We will be happy to consider code for
22  * inclusion in the official distribution, but derived work must not
23  * be called official GROMACS. Details are found in the README & COPYING
24  * files - if they are missing, get the official version at www.gromacs.org.
25  *
26  * To help us fund GROMACS development, we humbly ask that you cite
27  * the papers on the package - you can find them in the top README file.
28  *
29  * For more info, check our website at http://www.gromacs.org
30  */
31 /*! \internal \file
32  * \brief
33  * Implements functions in selhelp.h.
34  *
35  * \author Teemu Murtola <teemu.murtola@cbr.su.se>
36  * \ingroup module_selection
37  */
38 #include <string>
39 #include <vector>
40 #include <utility>
41
42 #include <boost/shared_ptr.hpp>
43
44 #include "gromacs/onlinehelp/helptopic.h"
45 #include "gromacs/utility/file.h"
46 #include "gromacs/utility/format.h"
47
48 #include "selhelp.h"
49 #include "selmethod.h"
50 #include "symrec.h"
51
52 namespace
53 {
54
55 struct CommonHelpText
56 {
57     static const char name[];
58     static const char title[];
59     static const char *const text[];
60 };
61
62 const char CommonHelpText::name[] = "selections";
63 const char CommonHelpText::title[] =
64     "Selection syntax and usage";
65 const char *const CommonHelpText::text[] = {
66     "This program supports selections in addition to traditional index files.",
67     "Please read the subtopic pages (available through \"help topic\") for",
68     "more information.",
69     "Explanation of command-line arguments for specifying selections can be",
70     "found under the \"cmdline\" subtopic, and general selection syntax is",
71     "described under \"syntax\". Available keywords can be found under",
72     "\"keywords\", and concrete examples under \"examples\".",
73     "Other subtopics give more details on certain aspects.",
74     "\"help all\" prints the help for all subtopics.",
75 };
76
77 struct ArithmeticHelpText
78 {
79     static const char name[];
80     static const char title[];
81     static const char *const text[];
82 };
83
84 const char ArithmeticHelpText::name[] = "arithmetic";
85 const char ArithmeticHelpText::title[] =
86     "Arithmetic expressions in selections";
87 const char *const ArithmeticHelpText::text[] = {
88     "Basic arithmetic evaluation is supported for numeric expressions.",
89     "Supported operations are addition, subtraction, negation, multiplication,",
90     "division, and exponentiation (using ^).",
91     "Result of a division by zero or other illegal operations is undefined.",
92 };
93
94 struct CmdLineHelpText
95 {
96     static const char name[];
97     static const char title[];
98     static const char *const text[];
99 };
100
101 const char CmdLineHelpText::name[] = "cmdline";
102 const char CmdLineHelpText::title[] =
103     "Specifying selections from command line";
104 const char *const CmdLineHelpText::text[] = {
105     "There are two alternative command-line arguments for specifying",
106     "selections:[BR]",
107     "1. [TT]-select[tt] can be used to specify the complete selection as a",
108     "string on the command line.[BR]",
109     "2. [TT]-sf[tt] can be used to specify a file name from which the",
110     "selection is read.[BR]",
111     "If both options are specified, [TT]-select[tt] takes precedence.",
112     "If neither of the above is present, the user is prompted to type the",
113     "selection on the standard input (a pipe can also be used to provide",
114     "the selections in this case).",
115     "This is also done if an empty string is passed to [TT]-select[tt].[PAR]",
116
117     "Option [TT]-n[tt] can be used to provide an index file.",
118     "If no index file is provided, default groups are generated.",
119     "In both cases, the user can also select an index group instead of",
120     "writing a full selection.",
121     "The default groups are generated by reading selections from a file",
122     "[TT]defselection.dat[tt]. If such a file is found in the current",
123     "directory, it is used instead of the one provided by default.[PAR]",
124
125     "Depending on the tool, two additional command-line arguments may be",
126     "available to control the behavior:[BR]",
127     "1. [TT]-seltype[tt] can be used to specify the default type of",
128     "positions to calculate for each selection.[BR]",
129     "2. [TT]-selrpos[tt] can be used to specify the default type of",
130     "positions used in selecting atoms by coordinates.[BR]",
131     "See \"help positions\" for more information on these options.",
132 };
133
134 struct EvaluationHelpText
135 {
136     static const char name[];
137     static const char title[];
138     static const char *const text[];
139 };
140
141 const char EvaluationHelpText::name[] = "evaluation";
142 const char EvaluationHelpText::title[] =
143     "Selection evaluation and optimization";
144 const char *const EvaluationHelpText::text[] = {
145     "Boolean evaluation proceeds from left to right and is short-circuiting",
146     "i.e., as soon as it is known whether an atom will be selected, the",
147     "remaining expressions are not evaluated at all.",
148     "This can be used to optimize the selections: you should write the",
149     "most restrictive and/or the most inexpensive expressions first in",
150     "boolean expressions.",
151     "The relative ordering between dynamic and static expressions does not",
152     "matter: all static expressions are evaluated only once, before the first",
153     "frame, and the result becomes the leftmost expression.[PAR]",
154
155     "Another point for optimization is in common subexpressions: they are not",
156     "automatically recognized, but can be manually optimized by the use of",
157     "variables. This can have a big impact on the performance of complex",
158     "selections, in particular if you define several index groups like this:",
159     "  [TT]rdist = distance from com of resnr 1 to 5;[tt][BR]",
160     "  [TT]resname RES and rdist < 2;[tt][BR]",
161     "  [TT]resname RES and rdist < 4;[tt][BR]",
162     "  [TT]resname RES and rdist < 6;[tt][BR]",
163     "Without the variable assignment, the distances would be evaluated three",
164     "times, although they are exactly the same within each selection.",
165     "Anything assigned into a variable becomes a common subexpression that",
166     "is evaluated only once during a frame.",
167     "Currently, in some cases the use of variables can actually lead to a small",
168     "performance loss because of the checks necessary to determine for which",
169     "atoms the expression has already been evaluated, but this should not be",
170     "a major problem.",
171 };
172
173 struct ExamplesHelpText
174 {
175     static const char name[];
176     static const char title[];
177     static const char *const text[];
178 };
179
180 const char ExamplesHelpText::name[] = "examples";
181 const char ExamplesHelpText::title[] =
182     "Selection examples";
183 const char *const ExamplesHelpText::text[] = {
184     "Below, examples of increasingly complex selections are given.[PAR]",
185
186     "Selection of all water oxygens:[BR]",
187     "  resname SOL and name OW",
188     "[PAR]",
189
190     "Centers of mass of residues 1 to 5 and 10:[BR]",
191     "  res_com of resnr 1 to 5 10",
192     "[PAR]",
193
194     "All atoms farther than 1 nm of a fixed position:[BR]",
195     "  not within 1 of (1.2, 3.1, 2.4)",
196     "[PAR]",
197
198     "All atoms of a residue LIG within 0.5 nm of a protein (with a custom name):[BR]",
199     "  \"Close to protein\" resname LIG and within 0.5 of group \"Protein\"",
200     "[PAR]",
201
202     "All protein residues that have at least one atom within 0.5 nm of a residue LIG:[BR]",
203     "  group \"Protein\" and same residue as within 0.5 of resname LIG",
204     "[PAR]",
205
206     "All RES residues whose COM is between 2 and 4 nm from the COM of all of them:[BR]",
207     "  rdist = res_com distance from com of resname RES[BR]",
208     "  resname RES and rdist >= 2 and rdist <= 4",
209     "[PAR]",
210
211     "Selection like C1 C2 C2 C3 C3 C4 ... C8 C9 (e.g., for g_bond):[BR]",
212     "  name \"C[1-8]\" merge name \"C[2-9]\"",
213 };
214
215 struct KeywordsHelpText
216 {
217     static const char name[];
218     static const char title[];
219     static const char *const text[];
220 };
221
222 const char KeywordsHelpText::name[] = "keywords";
223 const char KeywordsHelpText::title[] =
224     "Selection keywords";
225 const char *const KeywordsHelpText::text[] = {
226     "The following selection keywords are currently available.",
227     "For keywords marked with a star, additional help is available through",
228     "\"help KEYWORD\", where KEYWORD is the name of the keyword.",
229 };
230
231 struct LimitationsHelpText
232 {
233     static const char name[];
234     static const char title[];
235     static const char *const text[];
236 };
237
238 const char LimitationsHelpText::name[] = "limitations";
239 const char LimitationsHelpText::title[] =
240     "Selection limitations";
241 const char *const LimitationsHelpText::text[] = {
242     "Some analysis programs may require a special structure for the input",
243     "selections (e.g., [TT]g_angle[tt] requires the index group to be made",
244     "of groups of three or four atoms).",
245     "For such programs, it is up to the user to provide a proper selection",
246     "expression that always returns such positions.",
247     "[PAR]",
248
249     "Due to technical reasons, having a negative value as the first value in",
250     "expressions like[BR]",
251     "[TT]charge -1 to -0.7[tt][BR]",
252     "result in a syntax error. A workaround is to write[BR]",
253     "[TT]charge {-1 to -0.7}[tt][BR]",
254     "instead.",
255 };
256
257 struct PositionsHelpText
258 {
259     static const char name[];
260     static const char title[];
261     static const char *const text[];
262 };
263
264 const char PositionsHelpText::name[] = "positions";
265 const char PositionsHelpText::title[] =
266     "Specifying positions in selections";
267 const char *const PositionsHelpText::text[] = {
268     "Possible ways of specifying positions in selections are:[PAR]",
269
270     "1. A constant position can be defined as [TT][XX, YY, ZZ][tt], where",
271     "[TT]XX[tt], [TT]YY[tt] and [TT]ZZ[tt] are real numbers.[PAR]",
272
273     "2. [TT]com of ATOM_EXPR [pbc][tt] or [TT]cog of ATOM_EXPR [pbc][tt]",
274     "calculate the center of mass/geometry of [TT]ATOM_EXPR[tt]. If",
275     "[TT]pbc[tt] is specified, the center is calculated iteratively to try",
276     "to deal with cases where [TT]ATOM_EXPR[tt] wraps around periodic",
277     "boundary conditions.[PAR]",
278
279     "3. [TT]POSTYPE of ATOM_EXPR[tt] calculates the specified positions for",
280     "the atoms in [TT]ATOM_EXPR[tt].",
281     "[TT]POSTYPE[tt] can be [TT]atom[tt], [TT]res_com[tt], [TT]res_cog[tt],",
282     "[TT]mol_com[tt] or [TT]mol_cog[tt], with an optional prefix [TT]whole_[tt]",
283     "[TT]part_[tt] or [TT]dyn_[tt].",
284     "[TT]whole_[tt] calculates the centers for the whole residue/molecule,",
285     "even if only part of it is selected.",
286     "[TT]part_[tt] prefix calculates the centers for the selected atoms, but",
287     "uses always the same atoms for the same residue/molecule. The used atoms",
288     "are determined from the the largest group allowed by the selection.",
289     "[TT]dyn_[tt] calculates the centers strictly only for the selected atoms.",
290     "If no prefix is specified, whole selections default to [TT]part_[tt] and",
291     "other places default to [TT]whole_[tt].",
292     "The latter is often desirable to select the same molecules in different",
293     "tools, while the first is a compromise between speed ([TT]dyn_[tt]",
294     "positions can be slower to evaluate than [TT]part_[tt]) and intuitive",
295     "behavior.[PAR]",
296
297     "4. [TT]ATOM_EXPR[tt], when given for whole selections, is handled as 3.",
298     "above, using the position type from the command-line argument",
299     "[TT]-seltype[tt].[PAR]",
300
301     "Selection keywords that select atoms based on their positions, such as",
302     "[TT]dist from[tt], use by default the positions defined by the",
303     "[TT]-selrpos[tt] command-line option.",
304     "This can be overridden by prepending a [TT]POSTYPE[tt] specifier to the",
305     "keyword. For example, [TT]res_com dist from POS[tt] evaluates the",
306     "residue center of mass distances. In the example, all atoms of a residue",
307     "are either selected or not, based on the single distance calculated.",
308 };
309
310 struct SyntaxHelpText
311 {
312     static const char name[];
313     static const char title[];
314     static const char *const text[];
315 };
316
317 const char SyntaxHelpText::name[] = "syntax";
318 const char SyntaxHelpText::title[] =
319     "Selection syntax";
320 const char *const SyntaxHelpText::text[] = {
321     "A set of selections consists of one or more selections, separated by",
322     "semicolons. Each selection defines a set of positions for the analysis.",
323     "Each selection can also be preceded by a string that gives a name for",
324     "the selection for use in, e.g., graph legends.",
325     "If no name is provided, the string used for the selection is used",
326     "automatically as the name.[PAR]",
327
328     "For interactive input, the syntax is slightly altered: line breaks can",
329     "also be used to separate selections. \\ followed by a line break can",
330     "be used to continue a line if necessary.",
331     "Notice that the above only applies to real interactive input,",
332     "not if you provide the selections, e.g., from a pipe.[PAR]",
333
334     "It is possible to use variables to store selection expressions.",
335     "A variable is defined with the following syntax:[BR]",
336     "[TT]VARNAME = EXPR ;[tt][BR]",
337     "where [TT]EXPR[tt] is any valid selection expression.",
338     "After this, [TT]VARNAME[tt] can be used anywhere where [TT]EXPR[tt]",
339     "would be valid.[PAR]",
340
341     "Selections are composed of three main types of expressions, those that",
342     "define atoms ([TT]ATOM_EXPR[tt]s), those that define positions",
343     "([TT]POS_EXPR[tt]s), and those that evaluate to numeric values",
344     "([TT]NUM_EXPR[tt]s). Each selection should be a [TT]POS_EXPR[tt]",
345     "or a [TT]ATOM_EXPR[tt] (the latter is automatically converted to",
346     "positions). The basic rules are as follows:[BR]",
347     "1. An expression like [TT]NUM_EXPR1 < NUM_EXPR2[tt] evaluates to an",
348     "[TT]ATOM_EXPR[tt] that selects all the atoms for which the comparison",
349     "is true.[BR]",
350     "2. Atom expressions can be combined with boolean operations such as",
351     "[TT]not ATOM_EXPR[tt], [TT]ATOM_EXPR and ATOM_EXPR[tt], or",
352     "[TT]ATOM_EXPR or ATOM_EXPR[tt]. Parentheses can be used to alter the",
353     "evaluation order.[BR]",
354     "3. [TT]ATOM_EXPR[tt] expressions can be converted into [TT]POS_EXPR[tt]",
355     "expressions in various ways, see \"help positions\" for more details.[PAR]",
356
357     "Some keywords select atoms based on string values such as the atom name.",
358     "For these keywords, it is possible to use wildcards ([TT]name \"C*\"[tt])",
359     "or regular expressions (e.g., [TT]resname \"R[AB]\"[tt]).",
360     "The match type is automatically guessed from the string: if it contains",
361     "other characters than letters, numbers, '*', or '?', it is interpreted",
362     "as a regular expression.",
363     "Strings that contain non-alphanumeric characters should be enclosed in",
364     "double quotes as in the examples. For other strings, the quotes are",
365     "optional, but if the value conflicts with a reserved keyword, a syntax",
366     "error will occur. If your strings contain uppercase letters, this should",
367     "not happen.[PAR]",
368
369     "Index groups provided with the [TT]-n[tt] command-line option or",
370     "generated by default can be accessed with [TT]group NR[tt] or",
371     "[TT]group NAME[tt], where [TT]NR[tt] is a zero-based index of the group",
372     "and [TT]NAME[tt] is part of the name of the desired group.",
373     "The keyword [TT]group[tt] is optional if the whole selection is",
374     "provided from an index group.",
375     "To see a list of available groups in the interactive mode, press enter",
376     "in the beginning of a line.",
377 };
378
379 } // namespace
380
381 namespace gmx
382 {
383
384 namespace
385 {
386
387 /*! \internal \brief
388  * Help topic implementation for an individual selection method.
389  *
390  * \ingroup module_selection
391  */
392 class KeywordDetailsHelpTopic : public AbstractSimpleHelpTopic
393 {
394     public:
395         //! Initialize help topic for the given selection method.
396         explicit KeywordDetailsHelpTopic(const gmx_ana_selmethod_t &method)
397             : method_(method)
398         {
399         }
400
401         virtual const char *name() const
402         {
403             return method_.name;
404         }
405         virtual const char *title() const
406         {
407             return NULL;
408         }
409
410     protected:
411         virtual std::string helpText() const
412         {
413             return concatenateStrings(method_.help.help, method_.help.nlhelp);
414         }
415
416     private:
417         const gmx_ana_selmethod_t &method_;
418
419         GMX_DISALLOW_COPY_AND_ASSIGN(KeywordDetailsHelpTopic);
420 };
421
422 /*! \internal \brief
423  * Custom help topic for printing a list of selection keywords.
424  *
425  * \ingroup module_selection
426  */
427 class KeywordsHelpTopic : public CompositeHelpTopic<KeywordsHelpText>
428 {
429     public:
430         KeywordsHelpTopic();
431
432         virtual void writeHelp(File *file) const;
433
434     private:
435         /*! \brief
436          * Container for known selection methods.
437          *
438          * The first item in the pair is the name of the selection method, and
439          * the second points to the static data structure that describes the
440          * method.
441          * The name in the first item may differ from the name of the static
442          * data structure if an alias is defined for that method.
443          */
444         typedef std::vector<std::pair<std::string,
445                                       const gmx_ana_selmethod_t *> >
446                 MethodList;
447
448         /*! \brief
449          * Prints a brief list of keywords (selection methods) available.
450          *
451          * \param[in] file  Where to write the list.
452          * \param[in] type  Only methods that return this type are printed.
453          * \param[in] bModifiers  If false, \ref SMETH_MODIFIER methods are
454          *      excluded, otherwise only them are printed.
455          */
456         void printKeywordList(File *file, e_selvalue_t type, bool bModifiers) const;
457
458         MethodList              methods_;
459 };
460
461 KeywordsHelpTopic::KeywordsHelpTopic()
462 {
463     // TODO: This is not a very elegant way of getting the list of selection
464     // methods, but this needs to be rewritten in any case if/when #652 is
465     // implemented.
466     gmx_sel_symtab_t *symtab;
467     _gmx_sel_symtab_create(&symtab);
468     gmx_ana_selmethod_register_defaults(symtab);
469     boost::shared_ptr<gmx_sel_symtab_t> symtabGuard(symtab, &_gmx_sel_symtab_free);
470
471     gmx_sel_symrec_t *symbol = _gmx_sel_first_symbol(symtab, SYMBOL_METHOD);
472     while (symbol)
473     {
474         const char *symname = _gmx_sel_sym_name(symbol);
475         const gmx_ana_selmethod_t *method = _gmx_sel_sym_value_method(symbol);
476         methods_.push_back(std::make_pair(std::string(symname), method));
477         if (method->help.nlhelp > 0 && method->help.help != NULL)
478         {
479             addSubTopic(HelpTopicPointer(new KeywordDetailsHelpTopic(*method)));
480         }
481         symbol = _gmx_sel_next_symbol(symbol, SYMBOL_METHOD);
482     }
483 }
484
485 void KeywordsHelpTopic::writeHelp(File *file) const
486 {
487     writeBasicHelpTopic(file, *this, helpText());
488
489     /* Print the list of keywords */
490     file->writeLine();
491     file->writeLine("Keywords that select atoms by an integer property:");
492     file->writeLine("(use in expressions or like \"atomnr 1 to 5 7 9\")");
493     printKeywordList(file, INT_VALUE, false);
494
495     file->writeLine();
496     file->writeLine("Keywords that select atoms by a numeric property:");
497     file->writeLine("(use in expressions or like \"occupancy 0.5 to 1\")");
498     printKeywordList(file, REAL_VALUE, false);
499
500     file->writeLine();
501     file->writeLine("Keywords that select atoms by a string property:");
502     file->writeLine("(use like \"name PATTERN [PATTERN] ...\")");
503     printKeywordList(file, STR_VALUE, false);
504
505     file->writeLine();
506     file->writeLine("Additional keywords that directly select atoms:");
507     printKeywordList(file, GROUP_VALUE, false);
508
509     file->writeLine();
510     file->writeLine("Keywords that directly evaluate to positions:");
511     file->writeLine("(see also \"help positions\")");
512     printKeywordList(file, POS_VALUE, false);
513
514     file->writeLine();
515     file->writeLine("Additional keywords:");
516     printKeywordList(file, POS_VALUE, true);
517     printKeywordList(file, NO_VALUE, true);
518 }
519
520 void KeywordsHelpTopic::printKeywordList(File *file, e_selvalue_t type,
521                                          bool bModifiers) const
522 {
523     MethodList::const_iterator iter;
524     for (iter = methods_.begin(); iter != methods_.end(); ++iter)
525     {
526         const gmx_ana_selmethod_t &method = *iter->second;
527         bool bIsModifier = (method.flags & SMETH_MODIFIER) != 0;
528         if (method.type == type && bModifiers == bIsModifier)
529         {
530             bool bHasHelp = (method.help.nlhelp > 0 && method.help.help != NULL);
531             file->writeString(formatString(" %c ", bHasHelp ? '*' : ' '));
532             if (method.help.syntax != NULL)
533             {
534                 file->writeLine(method.help.syntax);
535             }
536             else
537             {
538                 const std::string &symname = iter->first;
539                 file->writeString(symname);
540                 if (symname != method.name)
541                 {
542                     file->writeString(formatString(" (synonym for %s)", method.name));
543                 }
544                 file->writeLine();
545             }
546         }
547     }
548 }
549
550 } // namespace
551
552 /*! \cond internal */
553 HelpTopicPointer createSelectionHelpTopic()
554 {
555     CompositeHelpTopicPointer root(new CompositeHelpTopic<CommonHelpText>);
556     root->registerSubTopic<SimpleHelpTopic<ArithmeticHelpText> >();
557     root->registerSubTopic<SimpleHelpTopic<CmdLineHelpText> >();
558     root->registerSubTopic<SimpleHelpTopic<EvaluationHelpText> >();
559     root->registerSubTopic<SimpleHelpTopic<ExamplesHelpText> >();
560     root->registerSubTopic<KeywordsHelpTopic>();
561     root->registerSubTopic<SimpleHelpTopic<LimitationsHelpText> >();
562     root->registerSubTopic<SimpleHelpTopic<PositionsHelpText> >();
563     root->registerSubTopic<SimpleHelpTopic<SyntaxHelpText> >();
564     return move(root);
565 }
566 //! \cond
567
568 } // namespace gmx