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