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