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