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