Merge branch release-4-6
[alexxy/gromacs.git] / src / gromacs / selection / sm_simple.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2009,2010,2011,2012,2013, by the GROMACS development team, led by
5  * David van der Spoel, Berk Hess, Erik Lindahl, and including many
6  * others, as listed in the AUTHORS file in the top-level source
7  * directory and at http://www.gromacs.org.
8  *
9  * GROMACS is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1
12  * of the License, or (at your option) any later version.
13  *
14  * GROMACS is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with GROMACS; if not, see
21  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
23  *
24  * If you want to redistribute modifications to GROMACS, please
25  * consider that scientific software is very special. Version
26  * control is crucial - bugs must be traceable. We will be happy to
27  * consider code for inclusion in the official distribution, but
28  * derived work must not be called official GROMACS. Details are found
29  * in the README & COPYING files - if they are missing, get the
30  * official version at http://www.gromacs.org.
31  *
32  * To help us fund GROMACS development, we humbly ask that you cite
33  * the research papers on the package. Check out http://www.gromacs.org.
34  */
35 /*! \internal \file
36  * \brief
37  * Implements simple keyword selection methods.
38  *
39  * \author Teemu Murtola <teemu.murtola@gmail.com>
40  * \ingroup module_selection
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])
565         {
566             ++j;
567         }
568         out->u.i[i] = j + 1;
569     }
570 }
571
572 /*!
573  * See sel_updatefunc() for description of the parameters.
574  * \p data is not used.
575  *
576  * Returns the atom name for each atom in \p out->u.s.
577  */
578 static void
579 evaluate_atomname(t_topology *top, t_trxframe *fr, t_pbc *pbc,
580                   gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
581 {
582     int  i;
583
584     out->nr = g->isize;
585     for (i = 0; i < g->isize; ++i)
586     {
587         out->u.s[i] = *top->atoms.atomname[g->index[i]];
588     }
589 }
590
591 /*!
592  * See sel_updatefunc() for description of the parameters.
593  * \p data is not used.
594  *
595  * Returns the PDB atom name for each atom in \p out->u.s.
596  */
597 static void
598 evaluate_pdbatomname(t_topology *top, t_trxframe *fr, t_pbc *pbc,
599                      gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
600 {
601     int  i;
602
603     out->nr = g->isize;
604     for (i = 0; i < g->isize; ++i)
605     {
606         char *s = top->atoms.pdbinfo[g->index[i]].atomnm;
607         while (std::isspace(*s))
608         {
609             ++s;
610         }
611         out->u.s[i] = s;
612     }
613 }
614
615 /*!
616  * \param[in] top  Topology structure.
617  * \param     npar Not used.
618  * \param     param Not used.
619  * \param     data Not used.
620  * \returns   0 if atom types are present in the topology, -1 otherwise.
621  *
622  * If the atom types are not found, also prints an error message.
623  */
624 static void
625 check_atomtype(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
626 {
627     bool bOk;
628
629     bOk = (top != NULL && top->atoms.atomtype != NULL);
630     if (!bOk)
631     {
632         GMX_THROW(gmx::InconsistentInputError("Atom types not available in topology"));
633     }
634 }
635
636 /*!
637  * See sel_updatefunc() for description of the parameters.
638  * \p data is not used.
639  *
640  * Returns the atom type for each atom in \p out->u.s.
641  * Segfaults if atom types are not found in the topology.
642  */
643 static void
644 evaluate_atomtype(t_topology *top, t_trxframe *fr, t_pbc *pbc,
645                   gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
646 {
647     int  i;
648
649     out->nr = g->isize;
650     for (i = 0; i < g->isize; ++i)
651     {
652         out->u.s[i] = *top->atoms.atomtype[g->index[i]];
653     }
654 }
655
656 /*!
657  * See sel_updatefunc() for description of the parameters.
658  * \p data is not used.
659  *
660  * Returns the residue name for each atom in \p out->u.s.
661  */
662 static void
663 evaluate_resname(t_topology *top, t_trxframe *fr, t_pbc *pbc,
664                  gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
665 {
666     int  i;
667     int  resind;
668
669     out->nr = g->isize;
670     for (i = 0; i < g->isize; ++i)
671     {
672         resind      = top->atoms.atom[g->index[i]].resind;
673         out->u.s[i] = *top->atoms.resinfo[resind].name;
674     }
675 }
676
677 /*!
678  * See sel_updatefunc() for description of the parameters.
679  * \p data is not used.
680  *
681  * Returns the insertion code for each atom in \p out->u.s.
682  */
683 static void
684 evaluate_insertcode(t_topology *top, t_trxframe *fr, t_pbc *pbc,
685                     gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
686 {
687     int  i;
688     int  resind;
689
690     out->nr = g->isize;
691     for (i = 0; i < g->isize; ++i)
692     {
693         resind         = top->atoms.atom[g->index[i]].resind;
694         out->u.s[i][0] = top->atoms.resinfo[resind].ic;
695     }
696 }
697
698 /*!
699  * See sel_updatefunc() for description of the parameters.
700  * \p data is not used.
701  *
702  * Returns the chain for each atom in \p out->u.s.
703  */
704 static void
705 evaluate_chain(t_topology *top, t_trxframe *fr, t_pbc *pbc,
706                gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
707 {
708     int  i;
709     int  resind;
710
711     out->nr = g->isize;
712     for (i = 0; i < g->isize; ++i)
713     {
714         resind         = top->atoms.atom[g->index[i]].resind;
715         out->u.s[i][0] = top->atoms.resinfo[resind].chainid;
716     }
717 }
718
719 /*!
720  * See sel_updatefunc() for description of the parameters.
721  * \p data is not used.
722  *
723  * Returns the mass for each atom in \p out->u.r.
724  */
725 static void
726 evaluate_mass(t_topology *top, t_trxframe *fr, t_pbc *pbc,
727               gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
728 {
729     int  i;
730
731     out->nr = g->isize;
732     for (i = 0; i < g->isize; ++i)
733     {
734         out->u.r[i] = top->atoms.atom[g->index[i]].m;
735     }
736 }
737
738 /*!
739  * See sel_updatefunc() for description of the parameters.
740  * \p data is not used.
741  *
742  * Returns the charge for each atom in \p out->u.r.
743  */
744 static void
745 evaluate_charge(t_topology *top, t_trxframe *fr, t_pbc *pbc,
746                 gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
747 {
748     int  i;
749
750     out->nr = g->isize;
751     for (i = 0; i < g->isize; ++i)
752     {
753         out->u.r[i] = top->atoms.atom[g->index[i]].q;
754     }
755 }
756
757 /*!
758  * \param[in] top  Topology structure.
759  * \param     npar Not used.
760  * \param     param Not used.
761  * \param     data Not used.
762  * \returns   0 if PDB info is present in the topology, -1 otherwise.
763  *
764  * If PDB info is not found, also prints an error message.
765  */
766 static void
767 check_pdbinfo(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
768 {
769     bool bOk;
770
771     bOk = (top != NULL && top->atoms.pdbinfo != NULL);
772     if (!bOk)
773     {
774         GMX_THROW(gmx::InconsistentInputError("PDB info not available in topology"));
775     }
776 }
777
778 /*!
779  * See sel_updatefunc() for description of the parameters.
780  * \p data is not used.
781  *
782  * Returns the alternate location identifier for each atom in \p out->u.s.
783  */
784 static void
785 evaluate_altloc(t_topology *top, t_trxframe *fr, t_pbc *pbc,
786                 gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
787 {
788     int  i;
789
790     out->nr = g->isize;
791     for (i = 0; i < g->isize; ++i)
792     {
793         out->u.s[i][0] = top->atoms.pdbinfo[g->index[i]].altloc;
794     }
795 }
796
797 /*!
798  * See sel_updatefunc() for description of the parameters.
799  * \p data is not used.
800  *
801  * Returns the occupancy numbers for each atom in \p out->u.r.
802  * Segfaults if PDB info is not found in the topology.
803  */
804 static void
805 evaluate_occupancy(t_topology *top, t_trxframe *fr, t_pbc *pbc,
806                    gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
807 {
808     int  i;
809
810     out->nr = g->isize;
811     for (i = 0; i < g->isize; ++i)
812     {
813         out->u.r[i] = top->atoms.pdbinfo[g->index[i]].occup;
814     }
815 }
816
817 /*!
818  * See sel_updatefunc() for description of the parameters.
819  * \p data is not used.
820  *
821  * Returns the B-factors for each atom in \p out->u.r.
822  * Segfaults if PDB info is not found in the topology.
823  */
824 static void
825 evaluate_betafactor(t_topology *top, t_trxframe *fr, t_pbc *pbc,
826                     gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
827 {
828     int  i;
829
830     out->nr = g->isize;
831     for (i = 0; i < g->isize; ++i)
832     {
833         out->u.r[i] = top->atoms.pdbinfo[g->index[i]].bfac;
834     }
835 }
836
837 /*! \brief
838  * Internal utility function for position keyword evaluation.
839  *
840  * \param[out] out  Output array.
841  * \param[in]  pos  Position data to use instead of atomic coordinates
842  *   (can be NULL).
843  * \param[in]  d    Coordinate index to evaluate (\p XX, \p YY or \p ZZ).
844  *
845  * This function is used internally by evaluate_x(), evaluate_y() and
846  * evaluate_z() to do the actual evaluation.
847  */
848 static void
849 evaluate_coord(real out[], gmx_ana_pos_t *pos, int d)
850 {
851     for (int b = 0; b < pos->count(); ++b)
852     {
853         const real v = pos->x[b][d];
854         for (int i = pos->m.mapb.index[b]; i < pos->m.mapb.index[b+1]; ++i)
855         {
856             out[i] = v;
857         }
858     }
859     // TODO: Make this more efficient by directly extracting the coordinates
860     // from the frame coordinates for atomic positions instead of going through
861     // a position calculation.
862 }
863
864 /*!
865  * See sel_updatefunc_pos() for description of the parameters.
866  * \p data is not used.
867  *
868  * Returns the \p x coordinate for each atom in \p out->u.r.
869  */
870 static void
871 evaluate_x(t_topology * /*top*/, t_trxframe * /*fr*/, t_pbc * /*pbc*/,
872            gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void * /*data*/)
873 {
874     out->nr = pos->m.mapb.nra;
875     evaluate_coord(out->u.r, pos, XX);
876 }
877
878 /*!
879  * See sel_updatefunc() for description of the parameters.
880  * \p data is not used.
881  *
882  * Returns the \p y coordinate for each atom in \p out->u.r.
883  */
884 static void
885 evaluate_y(t_topology * /*top*/, t_trxframe * /*fr*/, t_pbc * /*pbc*/,
886            gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void * /*data*/)
887 {
888     out->nr = pos->m.mapb.nra;
889     evaluate_coord(out->u.r, pos, YY);
890 }
891
892 /*!
893  * See sel_updatefunc() for description of the parameters.
894  * \p data is not used.
895  *
896  * Returns the \p z coordinate for each atom in \p out->u.r.
897  */
898 static void
899 evaluate_z(t_topology * /*top*/, t_trxframe * /*fr*/, t_pbc * /*pbc*/,
900            gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void * /*data*/)
901 {
902     out->nr = pos->m.mapb.nra;
903     evaluate_coord(out->u.r, pos, ZZ);
904 }