Merge origin/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]) ++j;
561         out->u.i[i] = j + 1;
562     }
563 }
564
565 /*!
566  * See sel_updatefunc() for description of the parameters.
567  * \p data is not used.
568  *
569  * Returns the atom name for each atom in \p out->u.s.
570  */
571 static void
572 evaluate_atomname(t_topology *top, t_trxframe *fr, t_pbc *pbc,
573                   gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
574 {
575     int  i;
576
577     out->nr = g->isize;
578     for (i = 0; i < g->isize; ++i)
579     {
580         out->u.s[i] = *top->atoms.atomname[g->index[i]];
581     }
582 }
583
584 /*!
585  * See sel_updatefunc() for description of the parameters.
586  * \p data is not used.
587  *
588  * Returns the PDB atom name for each atom in \p out->u.s.
589  */
590 static void
591 evaluate_pdbatomname(t_topology *top, t_trxframe *fr, t_pbc *pbc,
592                      gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
593 {
594     int  i;
595
596     out->nr = g->isize;
597     for (i = 0; i < g->isize; ++i)
598     {
599         char *s = top->atoms.pdbinfo[g->index[i]].atomnm;
600         while (std::isspace(*s))
601         {
602             ++s;
603         }
604         out->u.s[i] = s;
605     }
606 }
607
608 /*!
609  * \param[in] top  Topology structure.
610  * \param     npar Not used.
611  * \param     param Not used.
612  * \param     data Not used.
613  * \returns   0 if atom types are present in the topology, -1 otherwise.
614  *
615  * If the atom types are not found, also prints an error message.
616  */
617 static void
618 check_atomtype(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
619 {
620     bool bOk;
621
622     bOk = (top != NULL && top->atoms.atomtype != NULL);
623     if (!bOk)
624     {
625         GMX_THROW(gmx::InconsistentInputError("Atom types not available in topology"));
626     }
627 }
628
629 /*!
630  * See sel_updatefunc() for description of the parameters.
631  * \p data is not used.
632  *
633  * Returns the atom type for each atom in \p out->u.s.
634  * Segfaults if atom types are not found in the topology.
635  */
636 static void
637 evaluate_atomtype(t_topology *top, t_trxframe *fr, t_pbc *pbc,
638                   gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
639 {
640     int  i;
641
642     out->nr = g->isize;
643     for (i = 0; i < g->isize; ++i)
644     {
645         out->u.s[i] = *top->atoms.atomtype[g->index[i]];
646     }
647 }
648
649 /*!
650  * See sel_updatefunc() for description of the parameters.
651  * \p data is not used.
652  *
653  * Returns the residue name for each atom in \p out->u.s.
654  */
655 static void
656 evaluate_resname(t_topology *top, t_trxframe *fr, t_pbc *pbc,
657                  gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
658 {
659     int  i;
660     int  resind;
661
662     out->nr = g->isize;
663     for (i = 0; i < g->isize; ++i)
664     {
665         resind = top->atoms.atom[g->index[i]].resind;
666         out->u.s[i] = *top->atoms.resinfo[resind].name;
667     }
668 }
669
670 /*!
671  * See sel_updatefunc() for description of the parameters.
672  * \p data is not used.
673  *
674  * Returns the insertion code for each atom in \p out->u.s.
675  */
676 static void
677 evaluate_insertcode(t_topology *top, t_trxframe *fr, t_pbc *pbc,
678                     gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
679 {
680     int  i;
681     int  resind;
682
683     out->nr = g->isize;
684     for (i = 0; i < g->isize; ++i)
685     {
686         resind = top->atoms.atom[g->index[i]].resind;
687         out->u.s[i][0] = top->atoms.resinfo[resind].ic;
688     }
689 }
690
691 /*!
692  * See sel_updatefunc() for description of the parameters.
693  * \p data is not used.
694  *
695  * Returns the chain for each atom in \p out->u.s.
696  */
697 static void
698 evaluate_chain(t_topology *top, t_trxframe *fr, t_pbc *pbc,
699                gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
700 {
701     int  i;
702     int  resind;
703
704     out->nr = g->isize;
705     for (i = 0; i < g->isize; ++i)
706     {
707         resind = top->atoms.atom[g->index[i]].resind;
708         out->u.s[i][0] = top->atoms.resinfo[resind].chainid;
709     }
710 }
711
712 /*!
713  * See sel_updatefunc() for description of the parameters.
714  * \p data is not used.
715  *
716  * Returns the mass for each atom in \p out->u.r.
717  */
718 static void
719 evaluate_mass(t_topology *top, t_trxframe *fr, t_pbc *pbc,
720               gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
721 {
722     int  i;
723
724     out->nr = g->isize;
725     for (i = 0; i < g->isize; ++i)
726     {
727         out->u.r[i] = top->atoms.atom[g->index[i]].m;
728     }
729 }
730
731 /*!
732  * See sel_updatefunc() for description of the parameters.
733  * \p data is not used.
734  *
735  * Returns the charge for each atom in \p out->u.r.
736  */
737 static void
738 evaluate_charge(t_topology *top, t_trxframe *fr, t_pbc *pbc,
739                 gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
740 {
741     int  i;
742
743     out->nr = g->isize;
744     for (i = 0; i < g->isize; ++i)
745     {
746         out->u.r[i] = top->atoms.atom[g->index[i]].q;
747     }
748 }
749
750 /*!
751  * \param[in] top  Topology structure.
752  * \param     npar Not used.
753  * \param     param Not used.
754  * \param     data Not used.
755  * \returns   0 if PDB info is present in the topology, -1 otherwise.
756  *
757  * If PDB info is not found, also prints an error message.
758  */
759 static void
760 check_pdbinfo(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
761 {
762     bool bOk;
763
764     bOk = (top != NULL && top->atoms.pdbinfo != NULL);
765     if (!bOk)
766     {
767         GMX_THROW(gmx::InconsistentInputError("PDB info not available in topology"));
768     }
769 }
770
771 /*!
772  * See sel_updatefunc() for description of the parameters.
773  * \p data is not used.
774  *
775  * Returns the alternate location identifier for each atom in \p out->u.s.
776  */
777 static void
778 evaluate_altloc(t_topology *top, t_trxframe *fr, t_pbc *pbc,
779                 gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
780 {
781     int  i;
782
783     out->nr = g->isize;
784     for (i = 0; i < g->isize; ++i)
785     {
786         out->u.s[i][0] = top->atoms.pdbinfo[g->index[i]].altloc;
787     }
788 }
789
790 /*!
791  * See sel_updatefunc() for description of the parameters.
792  * \p data is not used.
793  *
794  * Returns the occupancy numbers for each atom in \p out->u.r.
795  * Segfaults if PDB info is not found in the topology.
796  */
797 static void
798 evaluate_occupancy(t_topology *top, t_trxframe *fr, t_pbc *pbc,
799                    gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
800 {
801     int  i;
802
803     out->nr = g->isize;
804     for (i = 0; i < g->isize; ++i)
805     {
806         out->u.r[i] = top->atoms.pdbinfo[g->index[i]].occup;
807     }
808 }
809
810 /*!
811  * See sel_updatefunc() for description of the parameters.
812  * \p data is not used.
813  *
814  * Returns the B-factors for each atom in \p out->u.r.
815  * Segfaults if PDB info is not found in the topology.
816  */
817 static void
818 evaluate_betafactor(t_topology *top, t_trxframe *fr, t_pbc *pbc,
819                     gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
820 {
821     int  i;
822
823     out->nr = g->isize;
824     for (i = 0; i < g->isize; ++i)
825     {
826         out->u.r[i] = top->atoms.pdbinfo[g->index[i]].bfac;
827     }
828 }
829
830 /*! \brief
831  * Internal utility function for position keyword evaluation.
832  *
833  * \param[in]  fr   Current frame.
834  * \param[in]  g    Index group for which the coordinates should be evaluated.
835  * \param[out] out  Output array.
836  * \param[in]  pos  Position data to use instead of atomic coordinates
837  *   (can be NULL).
838  * \param[in]  d    Coordinate index to evaluate (\p XX, \p YY or \p ZZ).
839  *
840  * This function is used internally by evaluate_x(), evaluate_y() and
841  * evaluate_z() to do the actual evaluation.
842  */
843 static void
844 evaluate_coord(t_trxframe *fr, gmx_ana_index_t *g, real out[],
845                gmx_ana_pos_t *pos, int d)
846 {
847     int  b, i;
848     real v;
849
850     if (pos)
851     {
852         for (b = 0; b < pos->nr; ++b)
853         {
854             v = pos->x[b][d];
855             for (i = pos->m.mapb.index[b]; i < pos->m.mapb.index[b+1]; ++i)
856             {
857                 out[i] = v;
858             }
859         }
860     }
861     else
862     {
863         for (i = 0; i < g->isize; ++i)
864         {
865             out[i] = fr->x[g->index[i]][d];
866         }
867     }
868 }
869
870 /*!
871  * See sel_updatefunc_pos() for description of the parameters.
872  * \p data is not used.
873  *
874  * Returns the \p x coordinate for each atom in \p out->u.r.
875  */
876 static void
877 evaluate_x(t_topology *top, t_trxframe *fr, t_pbc *pbc,
878            gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data)
879 {
880     out->nr = pos->g->isize;
881     evaluate_coord(fr, pos->g, out->u.r, pos, XX);
882 }
883
884 /*!
885  * See sel_updatefunc() for description of the parameters.
886  * \p data is not used.
887  *
888  * Returns the \p y coordinate for each atom in \p out->u.r.
889  */
890 static void
891 evaluate_y(t_topology *top, t_trxframe *fr, t_pbc *pbc,
892            gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data)
893 {
894     out->nr = pos->g->isize;
895     evaluate_coord(fr, pos->g, out->u.r, pos, YY);
896 }
897
898 /*!
899  * See sel_updatefunc() for description of the parameters.
900  * \p data is not used.
901  *
902  * Returns the \p z coordinate for each atom in \p out->u.r.
903  */
904 static void
905 evaluate_z(t_topology *top, t_trxframe *fr, t_pbc *pbc,
906            gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data)
907 {
908     out->nr = pos->g->isize;
909     evaluate_coord(fr, pos->g, out->u.r, pos, ZZ);
910 }