Merge branch 'release-4-6'
[alexxy/gromacs.git] / src / gromacs / selection / sm_simple.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 simple keyword selection methods.
34  *
35  * \author Teemu Murtola <teemu.murtola@cbr.su.se>
36  * \ingroup module_selection
37  */
38 #ifdef HAVE_CONFIG_H
39 #include <config.h>
40 #endif
41
42 #include <cctype>
43
44 #include "gromacs/legacyheaders/macros.h"
45
46 #include "gromacs/selection/position.h"
47 #include "gromacs/selection/selmethod.h"
48 #include "gromacs/utility/exceptions.h"
49
50 /** Evaluates the \p all selection keyword. */
51 static void
52 evaluate_all(t_topology *top, t_trxframe *fr, t_pbc *pbc,
53              gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
54 /** Evaluates the \p none selection keyword. */
55 static void
56 evaluate_none(t_topology *top, t_trxframe *fr, t_pbc *pbc,
57               gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
58 /** Evaluates the \p atomnr selection keyword. */
59 static void
60 evaluate_atomnr(t_topology *top, t_trxframe *fr, t_pbc *pbc,
61                 gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
62 /** Evaluates the \p resnr selection keyword. */
63 static void
64 evaluate_resnr(t_topology *top, t_trxframe *fr, t_pbc *pbc,
65                gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
66 /** Evaluates the \p resindex selection keyword. */
67 static void
68 evaluate_resindex(t_topology *top, t_trxframe *fr, t_pbc *pbc,
69                   gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
70 /** Checks whether molecule information is present in the topology. */
71 static void
72 check_molecules(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
73 /** Evaluates the \p molindex selection keyword. */
74 static void
75 evaluate_molindex(t_topology *top, t_trxframe *fr, t_pbc *pbc,
76                   gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
77 /** Evaluates the \p atomname selection keyword. */
78 static void
79 evaluate_atomname(t_topology *top, t_trxframe *fr, t_pbc *pbc,
80                   gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
81 /** Evaluates the \p pdbatomname selection keyword. */
82 static void
83 evaluate_pdbatomname(t_topology *top, t_trxframe *fr, t_pbc *pbc,
84                      gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
85 /** Checks whether atom types are present in the topology. */
86 static void
87 check_atomtype(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
88 /** Evaluates the \p atomtype selection keyword. */
89 static void
90 evaluate_atomtype(t_topology *top, t_trxframe *fr, t_pbc *pbc,
91                   gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
92 /** Evaluates the \p insertcode selection keyword. */
93 static void
94 evaluate_insertcode(t_topology *top, t_trxframe *fr, t_pbc *pbc,
95                     gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
96 /** Evaluates the \p chain selection keyword. */
97 static void
98 evaluate_chain(t_topology *top, t_trxframe *fr, t_pbc *pbc,
99                gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
100 /** Evaluates the \p mass selection keyword. */
101 static void
102 evaluate_mass(t_topology *top, t_trxframe *fr, t_pbc *pbc,
103               gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
104 /** Evaluates the \p charge selection keyword. */
105 static void
106 evaluate_charge(t_topology *top, t_trxframe *fr, t_pbc *pbc,
107                 gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
108 /** Checks whether PDB info is present in the topology. */
109 static void
110 check_pdbinfo(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
111 /** Evaluates the \p altloc selection keyword. */
112 static void
113 evaluate_altloc(t_topology *top, t_trxframe *fr, t_pbc *pbc,
114                 gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
115 /** Evaluates the \p occupancy selection keyword. */
116 static void
117 evaluate_occupancy(t_topology *top, t_trxframe *fr, t_pbc *pbc,
118                    gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
119 /** Evaluates the \p betafactor selection keyword. */
120 static void
121 evaluate_betafactor(t_topology *top, t_trxframe *fr, t_pbc *pbc,
122                     gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
123 /** Evaluates the \p resname selection keyword. */
124 static void
125 evaluate_resname(t_topology *top, t_trxframe *fr, t_pbc *pbc,
126                  gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
127
128 /** Evaluates the \p x selection keyword. */
129 static void
130 evaluate_x(t_topology *top, t_trxframe *fr, t_pbc *pbc,
131            gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data);
132 /** Evaluates the \p y selection keyword. */
133 static void
134 evaluate_y(t_topology *top, t_trxframe *fr, t_pbc *pbc,
135            gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data);
136 /** Evaluates the \p z selection keyword. */
137 static void
138 evaluate_z(t_topology *top, t_trxframe *fr, t_pbc *pbc,
139            gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data);
140
141 /** Help text for atom name selection keywords. */
142 static const char *help_atomname[] = {
143     "ATOM NAME SELECTION KEYWORDS[PAR]",
144
145     "[TT]name[tt] [TT]pdbname[tt] [TT]atomname[tt] [TT]pdbatomname[tt][PAR]",
146
147     "These keywords select atoms by name. [TT]name[tt] selects atoms using",
148     "the Gromacs atom naming convention.",
149     "For input formats other than PDB, the atom names are matched exactly",
150     "as they appear in the input file. For PDB files, 4 character atom names",
151     "that start with a digit are matched after moving the digit to the end",
152     "(e.g., to match 3HG2 from a PDB file, use [TT]name HG23[tt]).",
153     "[TT]pdbname[tt] can only be used with a PDB input file, and selects",
154     "atoms based on the exact name given in the input file, without the",
155     "transformation described above.[PAR]",
156
157     "[TT]atomname[tt] and [TT]pdbatomname[tt] are synonyms for the above two",
158     "keywords."
159 };
160
161 /** \internal Selection method data for \p all selection keyword. */
162 gmx_ana_selmethod_t sm_all = {
163     "all", GROUP_VALUE, 0,
164     0, NULL,
165     NULL,
166     NULL,
167     NULL,
168     NULL,
169     NULL,
170     NULL,
171     &evaluate_all,
172     NULL,
173 };
174
175 /** \internal Selection method data for \p none selection keyword. */
176 gmx_ana_selmethod_t sm_none = {
177     "none", GROUP_VALUE, 0,
178     0, NULL,
179     NULL,
180     NULL,
181     NULL,
182     NULL,
183     NULL,
184     NULL,
185     &evaluate_none,
186     NULL,
187 };
188
189 /** \internal Selection method data for \p atomnr selection keyword. */
190 gmx_ana_selmethod_t sm_atomnr = {
191     "atomnr", INT_VALUE, 0,
192     0, NULL,
193     NULL,
194     NULL,
195     NULL,
196     NULL,
197     NULL,
198     NULL,
199     &evaluate_atomnr,
200     NULL,
201 };
202
203 /** \internal Selection method data for \p resnr selection keyword. */
204 gmx_ana_selmethod_t sm_resnr = {
205     "resnr", INT_VALUE, SMETH_REQTOP,
206     0, NULL,
207     NULL,
208     NULL,
209     NULL,
210     NULL,
211     NULL,
212     NULL,
213     &evaluate_resnr,
214     NULL,
215 };
216
217 /** \internal Selection method data for \p resindex selection keyword. */
218 gmx_ana_selmethod_t sm_resindex = {
219     "resindex", INT_VALUE, SMETH_REQTOP,
220     0, NULL,
221     NULL,
222     NULL,
223     NULL,
224     NULL,
225     NULL,
226     NULL,
227     &evaluate_resindex,
228     NULL,
229 };
230
231 /** \internal Selection method data for \p molindex selection keyword. */
232 gmx_ana_selmethod_t sm_molindex = {
233     "molindex", INT_VALUE, SMETH_REQTOP,
234     0, NULL,
235     NULL,
236     NULL,
237     &check_molecules,
238     NULL,
239     NULL,
240     NULL,
241     &evaluate_molindex,
242     NULL,
243 };
244
245 /** \internal Selection method data for \p atomname selection keyword. */
246 gmx_ana_selmethod_t sm_atomname = {
247     "atomname", STR_VALUE, SMETH_REQTOP,
248     0, NULL,
249     NULL,
250     NULL,
251     NULL,
252     NULL,
253     NULL,
254     NULL,
255     &evaluate_atomname,
256     NULL,
257     {NULL, asize(help_atomname), help_atomname}
258 };
259
260 /** \internal Selection method data for \p pdbatomname selection keyword. */
261 gmx_ana_selmethod_t sm_pdbatomname = {
262     "pdbatomname", STR_VALUE, SMETH_REQTOP,
263     0, NULL,
264     NULL,
265     NULL,
266     &check_pdbinfo,
267     NULL,
268     NULL,
269     NULL,
270     &evaluate_pdbatomname,
271     NULL,
272     {NULL, asize(help_atomname), help_atomname}
273 };
274
275 /** \internal Selection method data for \p atomtype selection keyword. */
276 gmx_ana_selmethod_t sm_atomtype = {
277     "atomtype", STR_VALUE, SMETH_REQTOP,
278     0, NULL,
279     NULL,
280     NULL,
281     &check_atomtype,
282     NULL,
283     NULL,
284     NULL,
285     &evaluate_atomtype,
286     NULL,
287 };
288
289 /** \internal Selection method data for \p resname selection keyword. */
290 gmx_ana_selmethod_t sm_resname = {
291     "resname", STR_VALUE, SMETH_REQTOP,
292     0, NULL,
293     NULL,
294     NULL,
295     NULL,
296     NULL,
297     NULL,
298     NULL,
299     &evaluate_resname,
300     NULL,
301 };
302
303 /** \internal Selection method data for \p chain selection keyword. */
304 gmx_ana_selmethod_t sm_insertcode = {
305     "insertcode", STR_VALUE, SMETH_REQTOP | SMETH_CHARVAL,
306     0, NULL,
307     NULL,
308     NULL,
309     NULL,
310     NULL,
311     NULL,
312     NULL,
313     &evaluate_insertcode,
314     NULL,
315 };
316
317 /** \internal Selection method data for \p chain selection keyword. */
318 gmx_ana_selmethod_t sm_chain = {
319     "chain", STR_VALUE, SMETH_REQTOP | SMETH_CHARVAL,
320     0, NULL,
321     NULL,
322     NULL,
323     NULL,
324     NULL,
325     NULL,
326     NULL,
327     &evaluate_chain,
328     NULL,
329 };
330
331 /** \internal Selection method data for \p mass selection keyword. */
332 gmx_ana_selmethod_t sm_mass = {
333     "mass", REAL_VALUE, SMETH_REQTOP,
334     0, NULL,
335     NULL,
336     NULL,
337     NULL,
338     NULL,
339     NULL,
340     NULL,
341     &evaluate_mass,
342     NULL,
343 };
344
345 /** \internal Selection method data for \p charge selection keyword. */
346 gmx_ana_selmethod_t sm_charge = {
347     "charge", REAL_VALUE, SMETH_REQTOP,
348     0, NULL,
349     NULL,
350     NULL,
351     NULL,
352     NULL,
353     NULL,
354     NULL,
355     &evaluate_charge,
356     NULL,
357 };
358
359 /** \internal Selection method data for \p chain selection keyword. */
360 gmx_ana_selmethod_t sm_altloc = {
361     "altloc", STR_VALUE, SMETH_REQTOP | SMETH_CHARVAL,
362     0, NULL,
363     NULL,
364     NULL,
365     &check_pdbinfo,
366     NULL,
367     NULL,
368     NULL,
369     &evaluate_altloc,
370     NULL,
371 };
372
373 /** \internal Selection method data for \p occupancy selection keyword. */
374 gmx_ana_selmethod_t sm_occupancy = {
375     "occupancy", REAL_VALUE, SMETH_REQTOP,
376     0, NULL,
377     NULL,
378     NULL,
379     &check_pdbinfo,
380     NULL,
381     NULL,
382     NULL,
383     &evaluate_occupancy,
384     NULL,
385 };
386
387 /** \internal Selection method data for \p betafactor selection keyword. */
388 gmx_ana_selmethod_t sm_betafactor = {
389     "betafactor", REAL_VALUE, SMETH_REQTOP,
390     0, NULL,
391     NULL,
392     NULL,
393     &check_pdbinfo,
394     NULL,
395     NULL,
396     NULL,
397     &evaluate_betafactor,
398     NULL,
399 };
400
401 /** \internal Selection method data for \p x selection keyword. */
402 gmx_ana_selmethod_t sm_x = {
403     "x", REAL_VALUE, SMETH_DYNAMIC,
404     0, NULL,
405      NULL,
406      NULL,
407      NULL,
408      NULL,
409      NULL,
410      NULL,
411      NULL,
412     &evaluate_x,
413 };
414
415 /** \internal Selection method data for \p y selection keyword. */
416 gmx_ana_selmethod_t sm_y = {
417     "y", REAL_VALUE, SMETH_DYNAMIC,
418     0, NULL,
419      NULL,
420      NULL,
421      NULL,
422      NULL,
423      NULL,
424      NULL,
425      NULL,
426     &evaluate_y,
427 };
428
429 /** \internal Selection method data for \p z selection keyword. */
430 gmx_ana_selmethod_t sm_z = {
431     "z", REAL_VALUE, SMETH_DYNAMIC,
432     0, NULL,
433      NULL,
434      NULL,
435      NULL,
436      NULL,
437      NULL,
438      NULL,
439      NULL,
440     &evaluate_z,
441 };
442
443 /*!
444  * See sel_updatefunc() for description of the parameters.
445  * \p data is not used.
446  *
447  * Copies \p g to \p out->u.g.
448  */
449 static void
450 evaluate_all(t_topology *top, t_trxframe *fr, t_pbc *pbc,
451              gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
452 {
453     gmx_ana_index_copy(out->u.g, g, false);
454 }
455
456 /*!
457  * See sel_updatefunc() for description of the parameters.
458  * \p data is not used.
459  *
460  * Returns an empty \p out->u.g.
461  */
462 static void
463 evaluate_none(t_topology *top, t_trxframe *fr, t_pbc *pbc,
464               gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
465 {
466     out->u.g->isize = 0;
467 }
468
469 /*!
470  * See sel_updatefunc() for description of the parameters.
471  * \p data is not used.
472  *
473  * Returns the indices for each atom in \p out->u.i.
474  */
475 static void
476 evaluate_atomnr(t_topology *top, t_trxframe *fr, t_pbc *pbc,
477                 gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
478 {
479     int  i;
480
481     out->nr = g->isize;
482     for (i = 0; i < g->isize; ++i)
483     {
484         out->u.i[i] = g->index[i] + 1;
485     }
486 }
487
488 /*!
489  * See sel_updatefunc() for description of the parameters.
490  * \p data is not used.
491  *
492  * Returns the residue numbers for each atom in \p out->u.i.
493  */
494 static void
495 evaluate_resnr(t_topology *top, t_trxframe *fr, t_pbc *pbc,
496                gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
497 {
498     int  i;
499     int  resind;
500
501     out->nr = g->isize;
502     for (i = 0; i < g->isize; ++i)
503     {
504         resind = top->atoms.atom[g->index[i]].resind;
505         out->u.i[i] = top->atoms.resinfo[resind].nr;
506     }
507 }
508
509 /*!
510  * See sel_updatefunc() for description of the parameters.
511  * \p data is not used.
512  *
513  * Returns the residue indices for each atom in \p out->u.i.
514  */
515 static void
516 evaluate_resindex(t_topology *top, t_trxframe *fr, t_pbc *pbc,
517                   gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
518 {
519     int  i;
520
521     out->nr = g->isize;
522     for (i = 0; i < g->isize; ++i)
523     {
524         out->u.i[i] = top->atoms.atom[g->index[i]].resind + 1;
525     }
526 }
527
528 /*!
529  * \param[in] top  Topology structure.
530  * \param     npar Not used.
531  * \param     param Not used.
532  * \param     data Not used.
533  * \returns   0 if molecule info is present in the topology, -1 otherwise.
534  *
535  * If molecule information is not found, also prints an error message.
536  */
537 static void
538 check_molecules(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
539 {
540     bool bOk;
541
542     bOk = (top != NULL && top->mols.nr > 0);
543     if (!bOk)
544     {
545         GMX_THROW(gmx::InconsistentInputError("Molecule information not available in topology"));
546     }
547 }
548
549 /*!
550  * See sel_updatefunc() for description of the parameters.
551  * \p data is not used.
552  *
553  * Returns the molecule indices for each atom in \p out->u.i.
554  */
555 static void
556 evaluate_molindex(t_topology *top, t_trxframe *fr, t_pbc *pbc,
557                   gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
558 {
559     int  i, j;
560
561     out->nr = g->isize;
562     for (i = j = 0; i < g->isize; ++i)
563     {
564         while (top->mols.index[j + 1] <= g->index[i]) ++j;
565         out->u.i[i] = j + 1;
566     }
567 }
568
569 /*!
570  * See sel_updatefunc() for description of the parameters.
571  * \p data is not used.
572  *
573  * Returns the atom name for each atom in \p out->u.s.
574  */
575 static void
576 evaluate_atomname(t_topology *top, t_trxframe *fr, t_pbc *pbc,
577                   gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
578 {
579     int  i;
580
581     out->nr = g->isize;
582     for (i = 0; i < g->isize; ++i)
583     {
584         out->u.s[i] = *top->atoms.atomname[g->index[i]];
585     }
586 }
587
588 /*!
589  * See sel_updatefunc() for description of the parameters.
590  * \p data is not used.
591  *
592  * Returns the PDB atom name for each atom in \p out->u.s.
593  */
594 static void
595 evaluate_pdbatomname(t_topology *top, t_trxframe *fr, t_pbc *pbc,
596                      gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
597 {
598     int  i;
599
600     out->nr = g->isize;
601     for (i = 0; i < g->isize; ++i)
602     {
603         char *s = top->atoms.pdbinfo[g->index[i]].atomnm;
604         while (std::isspace(*s))
605         {
606             ++s;
607         }
608         out->u.s[i] = s;
609     }
610 }
611
612 /*!
613  * \param[in] top  Topology structure.
614  * \param     npar Not used.
615  * \param     param Not used.
616  * \param     data Not used.
617  * \returns   0 if atom types are present in the topology, -1 otherwise.
618  *
619  * If the atom types are not found, also prints an error message.
620  */
621 static void
622 check_atomtype(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
623 {
624     bool bOk;
625
626     bOk = (top != NULL && top->atoms.atomtype != NULL);
627     if (!bOk)
628     {
629         GMX_THROW(gmx::InconsistentInputError("Atom types not available in topology"));
630     }
631 }
632
633 /*!
634  * See sel_updatefunc() for description of the parameters.
635  * \p data is not used.
636  *
637  * Returns the atom type for each atom in \p out->u.s.
638  * Segfaults if atom types are not found in the topology.
639  */
640 static void
641 evaluate_atomtype(t_topology *top, t_trxframe *fr, t_pbc *pbc,
642                   gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
643 {
644     int  i;
645
646     out->nr = g->isize;
647     for (i = 0; i < g->isize; ++i)
648     {
649         out->u.s[i] = *top->atoms.atomtype[g->index[i]];
650     }
651 }
652
653 /*!
654  * See sel_updatefunc() for description of the parameters.
655  * \p data is not used.
656  *
657  * Returns the residue name for each atom in \p out->u.s.
658  */
659 static void
660 evaluate_resname(t_topology *top, t_trxframe *fr, t_pbc *pbc,
661                  gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
662 {
663     int  i;
664     int  resind;
665
666     out->nr = g->isize;
667     for (i = 0; i < g->isize; ++i)
668     {
669         resind = top->atoms.atom[g->index[i]].resind;
670         out->u.s[i] = *top->atoms.resinfo[resind].name;
671     }
672 }
673
674 /*!
675  * See sel_updatefunc() for description of the parameters.
676  * \p data is not used.
677  *
678  * Returns the insertion code for each atom in \p out->u.s.
679  */
680 static void
681 evaluate_insertcode(t_topology *top, t_trxframe *fr, t_pbc *pbc,
682                     gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
683 {
684     int  i;
685     int  resind;
686
687     out->nr = g->isize;
688     for (i = 0; i < g->isize; ++i)
689     {
690         resind = top->atoms.atom[g->index[i]].resind;
691         out->u.s[i][0] = top->atoms.resinfo[resind].ic;
692     }
693 }
694
695 /*!
696  * See sel_updatefunc() for description of the parameters.
697  * \p data is not used.
698  *
699  * Returns the chain for each atom in \p out->u.s.
700  */
701 static void
702 evaluate_chain(t_topology *top, t_trxframe *fr, t_pbc *pbc,
703                gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
704 {
705     int  i;
706     int  resind;
707
708     out->nr = g->isize;
709     for (i = 0; i < g->isize; ++i)
710     {
711         resind = top->atoms.atom[g->index[i]].resind;
712         out->u.s[i][0] = top->atoms.resinfo[resind].chainid;
713     }
714 }
715
716 /*!
717  * See sel_updatefunc() for description of the parameters.
718  * \p data is not used.
719  *
720  * Returns the mass for each atom in \p out->u.r.
721  */
722 static void
723 evaluate_mass(t_topology *top, t_trxframe *fr, t_pbc *pbc,
724               gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
725 {
726     int  i;
727
728     out->nr = g->isize;
729     for (i = 0; i < g->isize; ++i)
730     {
731         out->u.r[i] = top->atoms.atom[g->index[i]].m;
732     }
733 }
734
735 /*!
736  * See sel_updatefunc() for description of the parameters.
737  * \p data is not used.
738  *
739  * Returns the charge for each atom in \p out->u.r.
740  */
741 static void
742 evaluate_charge(t_topology *top, t_trxframe *fr, t_pbc *pbc,
743                 gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
744 {
745     int  i;
746
747     out->nr = g->isize;
748     for (i = 0; i < g->isize; ++i)
749     {
750         out->u.r[i] = top->atoms.atom[g->index[i]].q;
751     }
752 }
753
754 /*!
755  * \param[in] top  Topology structure.
756  * \param     npar Not used.
757  * \param     param Not used.
758  * \param     data Not used.
759  * \returns   0 if PDB info is present in the topology, -1 otherwise.
760  *
761  * If PDB info is not found, also prints an error message.
762  */
763 static void
764 check_pdbinfo(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
765 {
766     bool bOk;
767
768     bOk = (top != NULL && top->atoms.pdbinfo != NULL);
769     if (!bOk)
770     {
771         GMX_THROW(gmx::InconsistentInputError("PDB info not available in topology"));
772     }
773 }
774
775 /*!
776  * See sel_updatefunc() for description of the parameters.
777  * \p data is not used.
778  *
779  * Returns the alternate location identifier for each atom in \p out->u.s.
780  */
781 static void
782 evaluate_altloc(t_topology *top, t_trxframe *fr, t_pbc *pbc,
783                 gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
784 {
785     int  i;
786
787     out->nr = g->isize;
788     for (i = 0; i < g->isize; ++i)
789     {
790         out->u.s[i][0] = top->atoms.pdbinfo[g->index[i]].altloc;
791     }
792 }
793
794 /*!
795  * See sel_updatefunc() for description of the parameters.
796  * \p data is not used.
797  *
798  * Returns the occupancy numbers for each atom in \p out->u.r.
799  * Segfaults if PDB info is not found in the topology.
800  */
801 static void
802 evaluate_occupancy(t_topology *top, t_trxframe *fr, t_pbc *pbc,
803                    gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
804 {
805     int  i;
806
807     out->nr = g->isize;
808     for (i = 0; i < g->isize; ++i)
809     {
810         out->u.r[i] = top->atoms.pdbinfo[g->index[i]].occup;
811     }
812 }
813
814 /*!
815  * See sel_updatefunc() for description of the parameters.
816  * \p data is not used.
817  *
818  * Returns the B-factors for each atom in \p out->u.r.
819  * Segfaults if PDB info is not found in the topology.
820  */
821 static void
822 evaluate_betafactor(t_topology *top, t_trxframe *fr, t_pbc *pbc,
823                     gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
824 {
825     int  i;
826
827     out->nr = g->isize;
828     for (i = 0; i < g->isize; ++i)
829     {
830         out->u.r[i] = top->atoms.pdbinfo[g->index[i]].bfac;
831     }
832 }
833
834 /*! \brief
835  * Internal utility function for position keyword evaluation.
836  *
837  * \param[in]  fr   Current frame.
838  * \param[in]  g    Index group for which the coordinates should be evaluated.
839  * \param[out] out  Output array.
840  * \param[in]  pos  Position data to use instead of atomic coordinates
841  *   (can be NULL).
842  * \param[in]  d    Coordinate index to evaluate (\p XX, \p YY or \p ZZ).
843  *
844  * This function is used internally by evaluate_x(), evaluate_y() and
845  * evaluate_z() to do the actual evaluation.
846  */
847 static void
848 evaluate_coord(t_trxframe *fr, gmx_ana_index_t *g, real out[],
849                gmx_ana_pos_t *pos, int d)
850 {
851     int  b, i;
852     real v;
853
854     if (pos)
855     {
856         for (b = 0; b < pos->nr; ++b)
857         {
858             v = pos->x[b][d];
859             for (i = pos->m.mapb.index[b]; i < pos->m.mapb.index[b+1]; ++i)
860             {
861                 out[i] = v;
862             }
863         }
864     }
865     else
866     {
867         for (i = 0; i < g->isize; ++i)
868         {
869             out[i] = fr->x[g->index[i]][d];
870         }
871     }
872 }
873
874 /*!
875  * See sel_updatefunc_pos() for description of the parameters.
876  * \p data is not used.
877  *
878  * Returns the \p x coordinate for each atom in \p out->u.r.
879  */
880 static void
881 evaluate_x(t_topology *top, t_trxframe *fr, t_pbc *pbc,
882            gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data)
883 {
884     out->nr = pos->g->isize;
885     evaluate_coord(fr, pos->g, out->u.r, pos, XX);
886 }
887
888 /*!
889  * See sel_updatefunc() for description of the parameters.
890  * \p data is not used.
891  *
892  * Returns the \p y coordinate for each atom in \p out->u.r.
893  */
894 static void
895 evaluate_y(t_topology *top, t_trxframe *fr, t_pbc *pbc,
896            gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data)
897 {
898     out->nr = pos->g->isize;
899     evaluate_coord(fr, pos->g, out->u.r, pos, YY);
900 }
901
902 /*!
903  * See sel_updatefunc() for description of the parameters.
904  * \p data is not used.
905  *
906  * Returns the \p z coordinate for each atom in \p out->u.r.
907  */
908 static void
909 evaluate_z(t_topology *top, t_trxframe *fr, t_pbc *pbc,
910            gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data)
911 {
912     out->nr = pos->g->isize;
913     evaluate_coord(fr, pos->g, out->u.r, pos, ZZ);
914 }