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