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