Merge remote-tracking branch 'origin/release-4-6' into HEAD
[alexxy/gromacs.git] / src / gromacs / selection / sm_keywords.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 internal selection methods for numeric and string keyword
34  * evaluation.
35  *
36  * \author Teemu Murtola <teemu.murtola@cbr.su.se>
37  * \ingroup module_selection
38  */
39 #ifdef HAVE_CONFIG_H
40 #include <config.h>
41 #endif
42
43 #include <ctype.h>
44 #ifdef HAVE_SYS_TYPES_H
45 #include <sys/types.h>  /*old Mac needs types before regex.h*/
46 #endif
47 #ifdef HAVE_REGEX_H
48 #include <regex.h>
49 #define USE_REGEX
50 #endif
51
52 #include "macros.h"
53 #include "smalloc.h"
54 #include "string2.h"
55
56 #include "gromacs/selection/selmethod.h"
57 #include "gromacs/utility/errorcodes.h"
58 #include "gromacs/utility/messagestringcollector.h"
59
60 #include "keywords.h"
61 #include "parsetree.h"
62 #include "scanner.h"
63 #include "selelem.h"
64
65 /** Allocates data for integer keyword evaluation. */
66 static void *
67 init_data_kwint(int npar, gmx_ana_selparam_t *param);
68 /** Allocates data for real keyword evaluation. */
69 static void *
70 init_data_kwreal(int npar, gmx_ana_selparam_t *param);
71 /** Allocates data for string keyword evaluation. */
72 static void *
73 init_data_kwstr(int npar, gmx_ana_selparam_t *param);
74 /** Initializes data for integer keyword evaluation. */
75 static void
76 init_kwint(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
77 /** Initializes data for real keyword evaluation. */
78 static void
79 init_kwreal(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
80 /** Initializes data for string keyword evaluation. */
81 static void
82 init_kwstr(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
83 /** Frees the memory allocated for string keyword evaluation. */
84 static void
85 free_data_kwstr(void *data);
86 /** Evaluates integer selection keywords. */
87 static void
88 evaluate_keyword_int(t_topology *top, t_trxframe *fr, t_pbc *pbc,
89                      gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
90 /** Evaluates real selection keywords. */
91 static void
92 evaluate_keyword_real(t_topology *top, t_trxframe *fr, t_pbc *pbc,
93                       gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
94 /** Evaluates string selection keywords. */
95 static void
96 evaluate_keyword_str(t_topology *top, t_trxframe *fr, t_pbc *pbc,
97                      gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
98
99 /*! \internal \brief
100  * Data structure for integer keyword expression evaluation.
101  */
102 typedef struct t_methoddata_kwint
103 {
104     /** Array of values for the keyword. */
105     int               *v;
106     /** Number of ranges in the \p r array. */
107     int                n;
108     /*! \brief
109      * Array of sorted integer ranges to match against.
110      *
111      * Each range is made of two integers, giving the endpoints (inclusive).
112      * This field stores the pointer to the ranges allocated by the
113      * parameter parser; see \ref SPAR_RANGES for more information.
114      */
115     int               *r;
116 } t_methoddata_kwint;
117
118 /*! \internal \brief
119  * Data structure for real keyword expression evaluation.
120  */
121 typedef struct t_methoddata_kwreal
122 {
123     /** Array of values for the keyword. */
124     real              *v;
125     /** Number of ranges in the \p r array. */
126     int                n;
127     /*! \brief
128      * Array of sorted ranges to match against.
129      *
130      * Each range is made of two values, giving the endpoints (inclusive).
131      * This field stores the pointer to the ranges allocated by the
132      * parameter parser; see \ref SPAR_RANGES for more information.
133      */
134     real              *r;
135 } t_methoddata_kwreal;
136
137 /*! \internal \brief
138  * Data structure for string keyword expression evaluation.
139  */
140 typedef struct t_methoddata_kwstr
141 {
142     /** Array of values for the keyword. */
143     char             **v;
144     /** Number of elements in the \p val array. */
145     int                n;
146     /*! \internal \brief
147      * Array of strings/regular expressions to match against.
148      */
149     struct t_methoddata_kwstr_match {
150         /** true if the expression is a regular expression, false otherwise. */
151         bool           bRegExp;
152         /** The value to match against. */
153         union {
154 #ifdef USE_REGEX
155             /** Compiled regular expression if \p bRegExp is true. */
156             regex_t    r;
157 #endif
158             /** The string if \p bRegExp is false; */
159             char      *s;
160         }              u;
161     }                 *m;
162     /**< Array of strings/regular expressions to match against.*/
163 } t_methoddata_kwstr;
164
165 /** Parameters for integer keyword evaluation. */
166 static gmx_ana_selparam_t smparams_keyword_int[] = {
167     {NULL, {INT_VALUE, -1, {NULL}}, NULL, SPAR_ATOMVAL},
168     {NULL, {INT_VALUE, -1, {NULL}}, NULL, SPAR_RANGES | SPAR_VARNUM},
169 };
170
171 /** Parameters for real keyword evaluation. */
172 static gmx_ana_selparam_t smparams_keyword_real[] = {
173     {NULL, {REAL_VALUE, -1, {NULL}}, NULL, SPAR_ATOMVAL | SPAR_DYNAMIC},
174     {NULL, {REAL_VALUE, -1, {NULL}}, NULL, SPAR_RANGES | SPAR_VARNUM},
175 };
176
177 /** Parameters for string keyword evaluation. */
178 static gmx_ana_selparam_t smparams_keyword_str[] = {
179     {NULL, {STR_VALUE, -1, {NULL}}, NULL, SPAR_ATOMVAL},
180     {NULL, {STR_VALUE, -1, {NULL}}, NULL, SPAR_VARNUM},
181 };
182
183 /** \internal Selection method data for integer keyword evaluation. */
184 gmx_ana_selmethod_t sm_keyword_int = {
185     "kw_int", GROUP_VALUE, SMETH_SINGLEVAL,
186     asize(smparams_keyword_int), smparams_keyword_int,
187     &init_data_kwint,
188      NULL,
189     &init_kwint,
190      NULL,
191      NULL,
192      NULL,
193     &evaluate_keyword_int,
194      NULL,
195     {NULL, 0, NULL},
196 };
197
198 /** \internal Selection method data for real keyword evaluation. */
199 gmx_ana_selmethod_t sm_keyword_real = {
200     "kw_real", GROUP_VALUE, SMETH_SINGLEVAL,
201     asize(smparams_keyword_real), smparams_keyword_real,
202     &init_data_kwreal,
203      NULL,
204     &init_kwreal,
205      NULL,
206      NULL,
207      NULL,
208     &evaluate_keyword_real,
209      NULL,
210     {NULL, 0, NULL},
211 };
212
213 /** \internal Selection method data for string keyword evaluation. */
214 gmx_ana_selmethod_t sm_keyword_str = {
215     "kw_str", GROUP_VALUE, SMETH_SINGLEVAL,
216     asize(smparams_keyword_str), smparams_keyword_str,
217     &init_data_kwstr,
218      NULL,
219     &init_kwstr,
220      NULL,
221     &free_data_kwstr,
222      NULL,
223     &evaluate_keyword_str,
224      NULL,
225     {NULL, 0, NULL},
226 };
227
228 /** Initializes keyword evaluation for an arbitrary group. */
229 static void
230 init_kweval(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
231 /** Initializes output for keyword evaluation in an arbitrary group. */
232 static void
233 init_output_kweval(t_topology *top, gmx_ana_selvalue_t *out, void *data);
234 /** Frees the data allocated for keyword evaluation in an arbitrary group. */
235 static void
236 free_data_kweval(void *data);
237 /** Initializes frame evaluation for keyword evaluation in an arbitrary group. */
238 static void
239 init_frame_kweval(t_topology *top, t_trxframe *fr, t_pbc *pbc, void *data);
240 /** Evaluates keywords in an arbitrary group. */
241 static void
242 evaluate_kweval(t_topology *top, t_trxframe *fr, t_pbc *pbc,
243                 gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
244
245 /*! \internal \brief
246  * Data structure for keyword evaluation in arbitrary groups.
247  */
248 typedef struct
249 {
250     /** Wrapped keyword method for evaluating the values. */
251     gmx_ana_selmethod_t  *kwmethod;
252     /** Method data for \p kwmethod. */
253     void                 *kwmdata;
254     /** Group in which \p kwmethod should be evaluated. */
255     gmx_ana_index_t       g;
256 } t_methoddata_kweval;
257
258 /** Parameters for keyword evaluation in an arbitrary group. */
259 static gmx_ana_selparam_t smparams_kweval[] = {
260     {NULL,   {GROUP_VALUE, 1, {NULL}}, NULL, SPAR_DYNAMIC},
261 };
262
263
264 /********************************************************************
265  * INTEGER KEYWORD EVALUATION
266  ********************************************************************/
267
268 /*!
269  * \param[in] npar  Not used.
270  * \param     param Not used.
271  * \returns   Pointer to the allocated data (\ref t_methoddata_kwint).
272  *
273  * Allocates memory for a \ref t_methoddata_kwint structure.
274  */
275 static void *
276 init_data_kwint(int npar, gmx_ana_selparam_t *param)
277 {
278     t_methoddata_kwint *data;
279
280     snew(data, 1);
281     return data;
282 }
283
284 /*!
285  * \param[in] top   Not used.
286  * \param[in] npar  Not used (should be 2).
287  * \param[in] param Method parameters (should point to \ref smparams_keyword_int).
288  * \param[in] data  Should point to \ref t_methoddata_kwint.
289  */
290 static void
291 init_kwint(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
292 {
293     t_methoddata_kwint *d = (t_methoddata_kwint *)data;
294
295     d->v = param[0].val.u.i;
296     d->n = param[1].val.nr;
297     d->r = param[1].val.u.i;
298 }
299
300 /*!
301  * See sel_updatefunc() for description of the parameters.
302  * \p data should point to a \c t_methoddata_kwint.
303  *
304  * Does a binary search to find which atoms match the ranges in the
305  * \c t_methoddata_kwint structure for this selection.
306  * Matching atoms are stored in \p out->u.g.
307  */
308 static void
309 evaluate_keyword_int(t_topology *top, t_trxframe *fr, t_pbc *pbc,
310                      gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
311 {
312     t_methoddata_kwint *d = (t_methoddata_kwint *)data;
313     int                 n, i, j, jmin, jmax;
314     int                 val;
315
316     out->u.g->isize = 0;
317     n    = d->n;
318     for (i = 0; i < g->isize; ++i)
319     {
320         val = d->v[i];
321         if (d->r[0] > val || d->r[2*n-1] < val)
322         {
323             continue;
324         }
325         jmin = 0;
326         jmax = n;
327         while (jmax - jmin > 1)
328         {
329             j = jmin + (jmax - jmin) / 2;
330             if (val < d->r[2*j])
331             {
332                 jmax = j;
333             }
334             else
335             {
336                 jmin = j;
337                 if (val <= d->r[2*j+1])
338                 {
339                     break;
340                 }
341                 /* ++jmin;*/
342             }
343         }
344         if (val <= d->r[2*jmin+1])
345         {
346             out->u.g->index[out->u.g->isize++] = g->index[i];
347         }
348     }
349 }
350
351
352 /********************************************************************
353  * REAL KEYWORD EVALUATION
354  ********************************************************************/
355
356 /*!
357  * \param[in] npar  Not used.
358  * \param     param Not used.
359  * \returns   Pointer to the allocated data (\ref t_methoddata_kwreal).
360  *
361  * Allocates memory for a \ref t_methoddata_kwreal structure.
362  */
363 static void *
364 init_data_kwreal(int npar, gmx_ana_selparam_t *param)
365 {
366     t_methoddata_kwreal *data;
367
368     snew(data, 1);
369     return data;
370 }
371
372 /*!
373  * \param[in] top   Not used.
374  * \param[in] npar  Not used (should be 2).
375  * \param[in] param Method parameters (should point to \ref smparams_keyword_real).
376  * \param[in] data  Should point to \ref t_methoddata_kwreal.
377  * \returns   0 (the initialization always succeeds).
378  */
379 static void
380 init_kwreal(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
381 {
382     t_methoddata_kwreal *d = (t_methoddata_kwreal *)data;
383
384     d->v = param[0].val.u.r;
385     d->n = param[1].val.nr;
386     d->r = param[1].val.u.r;
387 }
388
389 /*!
390  * See sel_updatefunc() for description of the parameters.
391  * \p data should point to a \c t_methoddata_kwreal.
392  *
393  * Does a binary search to find which atoms match the ranges in the
394  * \c t_methoddata_kwreal structure for this selection.
395  * Matching atoms are stored in \p out->u.g.
396  */
397 static void
398 evaluate_keyword_real(t_topology *top, t_trxframe *fr, t_pbc *pbc,
399                      gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
400 {
401     t_methoddata_kwreal *d = (t_methoddata_kwreal *)data;
402     int                  n, i, j, jmin, jmax;
403     real                 val;
404
405     out->u.g->isize = 0;
406     n    = d->n;
407     for (i = 0; i < g->isize; ++i)
408     {
409         val = d->v[i];
410         if (d->r[0] > val || d->r[2*n-1] < val)
411         {
412             continue;
413         }
414         jmin = 0;
415         jmax = n;
416         while (jmax - jmin > 1)
417         {
418             j = jmin + (jmax - jmin) / 2;
419             if (val < d->r[2*j])
420             {
421                 jmax = j;
422             }
423             else
424             {
425                 jmin = j;
426                 if (val <= d->r[2*j+1])
427                 {
428                     break;
429                 }
430                 /* ++jmin;*/
431             }
432         }
433         if (val <= d->r[2*jmin+1])
434         {
435             out->u.g->index[out->u.g->isize++] = g->index[i];
436         }
437     }
438 }
439
440
441 /********************************************************************
442  * STRING KEYWORD EVALUATION
443  ********************************************************************/
444
445 /*!
446  * \param[in] npar  Not used.
447  * \param     param Not used.
448  * \returns Pointer to the allocated data (\ref t_methoddata_kwstr).
449  *
450  * Allocates memory for a \ref t_methoddata_kwstr structure.
451  */
452 static void *
453 init_data_kwstr(int npar, gmx_ana_selparam_t *param)
454 {
455     t_methoddata_kwstr *data;
456
457     snew(data, 1);
458     return data;
459 }
460
461 /*!
462  * \param[in] top   Not used.
463  * \param[in] npar  Not used (should be 2).
464  * \param[in] param Method parameters (should point to \ref smparams_keyword_str).
465  * \param[in] data  Should point to \ref t_methoddata_kwstr.
466  */
467 static void
468 init_kwstr(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
469 {
470     t_methoddata_kwstr *d = (t_methoddata_kwstr *)data;
471     char               *s;
472     int                 i;
473     size_t              j;
474     bool                bRegExp;
475
476     d->v   = param[0].val.u.s;
477     d->n   = param[1].val.nr;
478     /* Return if this is not the first time */
479     if (d->m)
480     {
481         return;
482     }
483     snew(d->m, d->n);
484     for (i = 0; i < d->n; ++i)
485     {
486         s = param[1].val.u.s[i];
487         bRegExp = false;
488         for (j = 0; j < strlen(s); ++j)
489         {
490             if (ispunct(s[j]) && s[j] != '?' && s[j] != '*')
491             {
492                 bRegExp = true;
493                 break;
494             }
495         }
496         if (bRegExp)
497         {
498             // TODO: Get rid of these prints to stderr
499 #ifdef USE_REGEX
500             char               *buf;
501             snew(buf, strlen(s) + 3);
502             sprintf(buf, "^%s$", s);
503             if (regcomp(&d->m[i].u.r, buf, REG_EXTENDED | REG_NOSUB))
504             {
505                 bRegExp = false;
506                 fprintf(stderr, "WARNING: error in regular expression,\n"
507                                 "         will match '%s' as a simple string\n", s);
508             }
509             sfree(buf);
510 #else
511             bRegExp = false;
512             fprintf(stderr, "WARNING: no regular expressions support,\n"
513                             "         will match '%s' as a simple string\n", s);
514 #endif
515         }
516         if (!bRegExp)
517         {
518             d->m[i].u.s = s;
519         }
520         d->m[i].bRegExp = bRegExp;
521     }
522 }
523
524 /*!
525  * \param data Data to free (should point to a \ref t_methoddata_kwstr).
526  *
527  * Frees the memory allocated for t_methoddata_kwstr::val.
528  */
529 static void
530 free_data_kwstr(void *data)
531 {
532     t_methoddata_kwstr *d = (t_methoddata_kwstr *)data;
533     int                 i;
534
535     for (i = 0; i < d->n; ++i)
536     {
537         if (d->m[i].bRegExp)
538         {
539 #ifdef USE_REGEX
540             /* This branch should only be taken if regular expressions
541              * are available, but the ifdef is still needed. */
542             regfree(&d->m[i].u.r);
543 #endif
544         }
545     }
546     sfree(d->m);
547 }
548
549 /*!
550  * See sel_updatefunc() for description of the parameters.
551  * \p data should point to a \c t_methoddata_kwstr.
552  *
553  * Does a linear search to find which atoms match the strings in the
554  * \c t_methoddata_kwstr structure for this selection.
555  * Wildcards are allowed in the strings.
556  * Matching atoms are stored in \p out->u.g.
557  */
558 static void
559 evaluate_keyword_str(t_topology *top, t_trxframe *fr, t_pbc *pbc,
560                      gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
561 {
562     t_methoddata_kwstr *d = (t_methoddata_kwstr *)data;
563     int                 i, j;
564     bool                bFound;
565
566     out->u.g->isize = 0;
567     for (i = 0; i < g->isize; ++i)
568     {
569         bFound = false;
570         for (j = 0; j < d->n && !bFound; ++j)
571         {
572             if (d->m[j].bRegExp)
573             {
574 #ifdef USE_REGEX
575                 /* This branch should only be taken if regular expressions
576                  * are available, but the ifdef is still needed. */
577                 if (!regexec(&d->m[j].u.r, d->v[i], 0, NULL, 0))
578                 {
579                     bFound = true;
580                 }
581 #endif
582             }
583             else
584             {
585                 if (gmx_wcmatch(d->m[j].u.s, d->v[i]) == 0)
586                 {
587                     bFound = true;
588                 }
589             }
590         }
591         if (bFound)
592         {
593             out->u.g->index[out->u.g->isize++] = g->index[i];
594         }
595     }
596 }
597
598
599 /********************************************************************
600  * KEYWORD EVALUATION FOR ARBITRARY GROUPS
601  ********************************************************************/
602
603 /*!
604  * \param[in] top   Not used.
605  * \param[in] npar  Not used.
606  * \param[in] param Not used.
607  * \param[in] data  Should point to \ref t_methoddata_kweval.
608  * \returns   0 on success, a non-zero error code on return.
609  *
610  * Calls the initialization method of the wrapped keyword.
611  */
612 static void
613 init_kweval(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
614 {
615     t_methoddata_kweval *d = (t_methoddata_kweval *)data;
616
617     d->kwmethod->init(top, 0, NULL, d->kwmdata);
618 }
619
620 /*!
621  * \param[in]     top   Not used.
622  * \param[in,out] out   Pointer to output data structure.
623  * \param[in,out] data  Should point to \c t_methoddata_kweval.
624  * \returns       0 for success.
625  */
626 static void
627 init_output_kweval(t_topology *top, gmx_ana_selvalue_t *out, void *data)
628 {
629     t_methoddata_kweval *d = (t_methoddata_kweval *)data;
630
631     out->nr = d->g.isize;
632 }
633
634 /*!
635  * \param data Data to free (should point to a \c t_methoddata_kweval).
636  *
637  * Frees the memory allocated for all the members of \c t_methoddata_kweval.
638  */
639 static void
640 free_data_kweval(void *data)
641 {
642     t_methoddata_kweval *d = (t_methoddata_kweval *)data;
643
644     _gmx_selelem_free_method(d->kwmethod, d->kwmdata);
645 }
646
647 /*!
648  * \param[in]  top  Topology.
649  * \param[in]  fr   Current frame.
650  * \param[in]  pbc  PBC structure.
651  * \param      data Should point to a \ref t_methoddata_kweval.
652  * \returns    0 on success, a non-zero error code on error.
653  *
654  * Creates a lookup structure that enables fast queries of whether a point
655  * is within the solid angle or not.
656  */
657 static void
658 init_frame_kweval(t_topology *top, t_trxframe *fr, t_pbc *pbc, void *data)
659 {
660     t_methoddata_kweval *d = (t_methoddata_kweval *)data;
661
662     d->kwmethod->init_frame(top, fr, pbc, d->kwmdata);
663 }
664
665 /*!
666  * See sel_updatefunc() for description of the parameters.
667  * \p data should point to a \c t_methoddata_kweval.
668  *
669  * Calls the evaluation function of the wrapped keyword with the given
670  * parameters, with the exception of using \c t_methoddata_kweval::g for the
671  * evaluation group.
672  */
673 static void
674 evaluate_kweval(t_topology *top, t_trxframe *fr, t_pbc *pbc,
675                 gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
676 {
677     t_methoddata_kweval *d = (t_methoddata_kweval *)data;
678
679     d->kwmethod->update(top, fr, pbc, &d->g, out, d->kwmdata);
680 }
681
682 /*!
683  * \param[out]  selp    Pointer to receive a pointer to the created selection
684  *      element (set to NULL on error).
685  * \param[in]   method  Keyword selection method to evaluate.
686  * \param[in]   param   Parameter that gives the group to evaluate \p method in.
687  * \param[in]   scanner Scanner data structure.
688  * \returns     0 on success, non-zero error code on error.
689  *
690  * Creates a \ref SEL_EXPRESSION selection element (pointer put in \c *selp)
691  * that evaluates the keyword method given by \p method in the group given by
692  * \p param.
693  */
694 int
695 _gmx_sel_init_keyword_evaluator(t_selelem **selp, gmx_ana_selmethod_t *method,
696                                 t_selexpr_param *param, void *scanner)
697 {
698     t_selelem            *sel;
699     t_methoddata_kweval  *data;
700
701     gmx::MessageStringCollector *errors = _gmx_sel_lexer_error_reporter(scanner);
702     char  buf[1024];
703     sprintf(buf, "In evaluation of '%s'", method->name);
704     gmx::MessageStringContext   context(errors, buf);
705
706     if ((method->flags & (SMETH_SINGLEVAL | SMETH_VARNUMVAL))
707         || method->outinit || method->pupdate)
708     {
709         _gmx_selexpr_free_params(param);
710         GMX_ERROR(gmx::eeInternalError,
711                   "Unsupported keyword method for arbitrary group evaluation");
712     }
713
714     *selp = NULL;
715     sel = _gmx_selelem_create(SEL_EXPRESSION);
716     _gmx_selelem_set_method(sel, method, scanner);
717
718     snew(data, 1);
719     data->kwmethod = sel->u.expr.method;
720     data->kwmdata  = sel->u.expr.mdata;
721     gmx_ana_index_clear(&data->g);
722
723     snew(sel->u.expr.method, 1);
724     memcpy(sel->u.expr.method, data->kwmethod, sizeof(gmx_ana_selmethod_t));
725     sel->u.expr.method->flags       |= SMETH_VARNUMVAL;
726     sel->u.expr.method->init_data    = NULL;
727     sel->u.expr.method->set_poscoll  = NULL;
728     sel->u.expr.method->init         = method->init ? &init_kweval : NULL;
729     sel->u.expr.method->outinit      = &init_output_kweval;
730     sel->u.expr.method->free         = &free_data_kweval;
731     sel->u.expr.method->init_frame   = method->init_frame ? &init_frame_kweval : NULL;
732     sel->u.expr.method->update       = &evaluate_kweval;
733     sel->u.expr.method->pupdate      = NULL;
734     sel->u.expr.method->nparams      = asize(smparams_kweval);
735     sel->u.expr.method->param        = smparams_kweval;
736     _gmx_selelem_init_method_params(sel, scanner);
737     sel->u.expr.mdata = data;
738
739     sel->u.expr.method->param[0].val.u.g = &data->g;
740
741     sfree(param->name);
742     param->name = NULL;
743     if (!_gmx_sel_parse_params(param, sel->u.expr.method->nparams,
744                                sel->u.expr.method->param, sel, scanner))
745     {
746         _gmx_selelem_free(sel);
747         return -1;
748     }
749     *selp = sel;
750     return 0;
751 }