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