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