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