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