Merge release-4-6 into master
[alexxy/gromacs.git] / src / gromacs / selection / sm_keywords.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2009,2010,2011,2012, by the GROMACS development team, led by
5  * David van der Spoel, Berk Hess, Erik Lindahl, and including many
6  * others, as listed in the AUTHORS file in the top-level source
7  * directory and at http://www.gromacs.org.
8  *
9  * GROMACS is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1
12  * of the License, or (at your option) any later version.
13  *
14  * GROMACS is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with GROMACS; if not, see
21  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
23  *
24  * If you want to redistribute modifications to GROMACS, please
25  * consider that scientific software is very special. Version
26  * control is crucial - bugs must be traceable. We will be happy to
27  * consider code for inclusion in the official distribution, but
28  * derived work must not be called official GROMACS. Details are found
29  * in the README & COPYING files - if they are missing, get the
30  * official version at http://www.gromacs.org.
31  *
32  * To help us fund GROMACS development, we humbly ask that you cite
33  * the research papers on the package. Check out http://www.gromacs.org.
34  */
35 /*! \internal \file
36  * \brief
37  * Implements internal selection methods for numeric and string keyword
38  * evaluation.
39  *
40  * \author Teemu Murtola <teemu.murtola@gmail.com>
41  * \ingroup module_selection
42  */
43 #include <cctype>
44 #include <cstring>
45
46 #include <string>
47
48 #include <boost/shared_ptr.hpp>
49
50 #include "gromacs/legacyheaders/macros.h"
51 #include "gromacs/legacyheaders/smalloc.h"
52 #include "gromacs/legacyheaders/string2.h"
53
54 #include "gromacs/selection/selmethod.h"
55 #include "gromacs/utility/exceptions.h"
56 #include "gromacs/utility/gmxregex.h"
57 #include "gromacs/utility/messagestringcollector.h"
58 #include "gromacs/utility/stringutil.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 namespace
138 {
139
140 /*! \internal \brief
141  * Single item in the list of strings/regular expressions to match.
142  *
143  * \ingroup module_selection
144  */
145 class StringKeywordMatchItem
146 {
147     public:
148         /*! \brief
149          * Constructs a matcher from a string.
150          *
151          * \param[in] matchType String matching type.
152          * \param[in] str       String to use for matching.
153          */
154         StringKeywordMatchItem(gmx::SelectionStringMatchType matchType,
155                                const char                   *str)
156             : str_(str)
157         {
158             bool bRegExp = (matchType == gmx::eStringMatchType_RegularExpression);
159             if (matchType == gmx::eStringMatchType_Auto)
160             {
161                 for (size_t j = 0; j < std::strlen(str); ++j)
162                 {
163                     if (std::ispunct(str[j]) && str[j] != '?' && str[j] != '*')
164                     {
165                         bRegExp = true;
166                         break;
167                     }
168                 }
169             }
170             if (bRegExp)
171             {
172                 if (!gmx::Regex::isSupported())
173                 {
174                     GMX_THROW(gmx::InvalidInputError(gmx::formatString(
175                                                              "No regular expression support, "
176                                                              "cannot match \"%s\"", str)));
177                 }
178                 regex_.reset(new gmx::Regex(str));
179             }
180         }
181
182         /*! \brief
183          * Checks whether this item matches a string.
184          *
185          * \param[in] matchType String matching type.
186          * \param[in] value     String to match.
187          * \returns   true if this item matches \p value.
188          */
189         bool match(gmx::SelectionStringMatchType matchType,
190                    const char                   *value) const
191         {
192             if (matchType == gmx::eStringMatchType_Exact)
193             {
194                 return str_ == value;
195             }
196             else if (regex_)
197             {
198                 return gmx::regexMatch(value, *regex_);
199             }
200             else
201             {
202                 return gmx_wcmatch(str_.c_str(), value) == 0;
203             }
204         }
205
206     private:
207         //! The raw string passed for the matcher.
208         std::string                     str_;
209         //! Regular expression compiled from \p str_, if applicable.
210         boost::shared_ptr<gmx::Regex>   regex_;
211 };
212
213 /*! \internal \brief
214  * Data structure for string keyword expression evaluation.
215  */
216 struct t_methoddata_kwstr
217 {
218     /** Matching type for the strings. */
219     gmx::SelectionStringMatchType       matchType;
220     /** Array of values for the keyword. */
221     char                              **v;
222     /** Array of strings/regular expressions to match against.*/
223     std::vector<StringKeywordMatchItem> matches;
224 };
225
226 } // namespace
227
228 /** Parameters for integer keyword evaluation. */
229 static gmx_ana_selparam_t smparams_keyword_int[] = {
230     {NULL, {INT_VALUE, -1, {NULL}}, NULL, SPAR_ATOMVAL},
231     {NULL, {INT_VALUE, -1, {NULL}}, NULL, SPAR_RANGES | SPAR_VARNUM},
232 };
233
234 /** Parameters for real keyword evaluation. */
235 static gmx_ana_selparam_t smparams_keyword_real[] = {
236     {NULL, {REAL_VALUE, -1, {NULL}}, NULL, SPAR_ATOMVAL | SPAR_DYNAMIC},
237     {NULL, {REAL_VALUE, -1, {NULL}}, NULL, SPAR_RANGES | SPAR_VARNUM},
238 };
239
240 /** Parameters for string keyword evaluation. */
241 static gmx_ana_selparam_t smparams_keyword_str[] = {
242     {NULL, {STR_VALUE, -1, {NULL}}, NULL, SPAR_ATOMVAL},
243     {NULL, {STR_VALUE, -1, {NULL}}, NULL, SPAR_VARNUM},
244 };
245
246 /** \internal Selection method data for integer keyword evaluation. */
247 gmx_ana_selmethod_t sm_keyword_int = {
248     "kw_int", GROUP_VALUE, SMETH_SINGLEVAL,
249     asize(smparams_keyword_int), smparams_keyword_int,
250     &init_data_kwint,
251     NULL,
252     &init_kwint,
253     NULL,
254     NULL,
255     NULL,
256     &evaluate_keyword_int,
257     NULL,
258     {NULL, 0, NULL},
259 };
260
261 /** \internal Selection method data for real keyword evaluation. */
262 gmx_ana_selmethod_t sm_keyword_real = {
263     "kw_real", GROUP_VALUE, SMETH_SINGLEVAL,
264     asize(smparams_keyword_real), smparams_keyword_real,
265     &init_data_kwreal,
266     NULL,
267     &init_kwreal,
268     NULL,
269     NULL,
270     NULL,
271     &evaluate_keyword_real,
272     NULL,
273     {NULL, 0, NULL},
274 };
275
276 /** \internal Selection method data for string keyword evaluation. */
277 gmx_ana_selmethod_t sm_keyword_str = {
278     "kw_str", GROUP_VALUE, SMETH_SINGLEVAL,
279     asize(smparams_keyword_str), smparams_keyword_str,
280     &init_data_kwstr,
281     NULL,
282     &init_kwstr,
283     NULL,
284     &free_data_kwstr,
285     NULL,
286     &evaluate_keyword_str,
287     NULL,
288     {NULL, 0, NULL},
289 };
290
291 /** Initializes keyword evaluation for an arbitrary group. */
292 static void
293 init_kweval(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
294 /** Initializes output for keyword evaluation in an arbitrary group. */
295 static void
296 init_output_kweval(t_topology *top, gmx_ana_selvalue_t *out, void *data);
297 /** Frees the data allocated for keyword evaluation in an arbitrary group. */
298 static void
299 free_data_kweval(void *data);
300 /** Initializes frame evaluation for keyword evaluation in an arbitrary group. */
301 static void
302 init_frame_kweval(t_topology *top, t_trxframe *fr, t_pbc *pbc, void *data);
303 /** Evaluates keywords in an arbitrary group. */
304 static void
305 evaluate_kweval(t_topology *top, t_trxframe *fr, t_pbc *pbc,
306                 gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
307
308 /*! \internal \brief
309  * Data structure for keyword evaluation in arbitrary groups.
310  */
311 typedef struct
312 {
313     /** Wrapped keyword method for evaluating the values. */
314     gmx_ana_selmethod_t  *kwmethod;
315     /** Method data for \p kwmethod. */
316     void                 *kwmdata;
317     /** Group in which \p kwmethod should be evaluated. */
318     gmx_ana_index_t       g;
319 } t_methoddata_kweval;
320
321 /** Parameters for keyword evaluation in an arbitrary group. */
322 static gmx_ana_selparam_t smparams_kweval[] = {
323     {NULL,   {GROUP_VALUE, 1, {NULL}}, NULL, SPAR_DYNAMIC},
324 };
325
326
327 /********************************************************************
328  * INTEGER KEYWORD EVALUATION
329  ********************************************************************/
330
331 /*!
332  * \param[in] npar  Not used.
333  * \param     param Not used.
334  * \returns   Pointer to the allocated data (\ref t_methoddata_kwint).
335  *
336  * Allocates memory for a \ref t_methoddata_kwint structure.
337  */
338 static void *
339 init_data_kwint(int npar, gmx_ana_selparam_t *param)
340 {
341     t_methoddata_kwint *data;
342
343     snew(data, 1);
344     return data;
345 }
346
347 /*!
348  * \param[in] top   Not used.
349  * \param[in] npar  Not used (should be 2).
350  * \param[in] param Method parameters (should point to \ref smparams_keyword_int).
351  * \param[in] data  Should point to \ref t_methoddata_kwint.
352  */
353 static void
354 init_kwint(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
355 {
356     t_methoddata_kwint *d = (t_methoddata_kwint *)data;
357
358     d->v = param[0].val.u.i;
359     d->n = param[1].val.nr;
360     d->r = param[1].val.u.i;
361 }
362
363 /*!
364  * See sel_updatefunc() for description of the parameters.
365  * \p data should point to a \c t_methoddata_kwint.
366  *
367  * Does a binary search to find which atoms match the ranges in the
368  * \c t_methoddata_kwint structure for this selection.
369  * Matching atoms are stored in \p out->u.g.
370  */
371 static void
372 evaluate_keyword_int(t_topology *top, t_trxframe *fr, t_pbc *pbc,
373                      gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
374 {
375     t_methoddata_kwint *d = (t_methoddata_kwint *)data;
376     int                 n, i, j, jmin, jmax;
377     int                 val;
378
379     out->u.g->isize = 0;
380     n               = d->n;
381     for (i = 0; i < g->isize; ++i)
382     {
383         val = d->v[i];
384         if (d->r[0] > val || d->r[2*n-1] < val)
385         {
386             continue;
387         }
388         jmin = 0;
389         jmax = n;
390         while (jmax - jmin > 1)
391         {
392             j = jmin + (jmax - jmin) / 2;
393             if (val < d->r[2*j])
394             {
395                 jmax = j;
396             }
397             else
398             {
399                 jmin = j;
400                 if (val <= d->r[2*j+1])
401                 {
402                     break;
403                 }
404                 /* ++jmin;*/
405             }
406         }
407         if (val <= d->r[2*jmin+1])
408         {
409             out->u.g->index[out->u.g->isize++] = g->index[i];
410         }
411     }
412 }
413
414
415 /********************************************************************
416  * REAL KEYWORD EVALUATION
417  ********************************************************************/
418
419 /*!
420  * \param[in] npar  Not used.
421  * \param     param Not used.
422  * \returns   Pointer to the allocated data (\ref t_methoddata_kwreal).
423  *
424  * Allocates memory for a \ref t_methoddata_kwreal structure.
425  */
426 static void *
427 init_data_kwreal(int npar, gmx_ana_selparam_t *param)
428 {
429     t_methoddata_kwreal *data;
430
431     snew(data, 1);
432     return data;
433 }
434
435 /*!
436  * \param[in] top   Not used.
437  * \param[in] npar  Not used (should be 2).
438  * \param[in] param Method parameters (should point to \ref smparams_keyword_real).
439  * \param[in] data  Should point to \ref t_methoddata_kwreal.
440  * \returns   0 (the initialization always succeeds).
441  */
442 static void
443 init_kwreal(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
444 {
445     t_methoddata_kwreal *d = (t_methoddata_kwreal *)data;
446
447     d->v = param[0].val.u.r;
448     d->n = param[1].val.nr;
449     d->r = param[1].val.u.r;
450 }
451
452 /*!
453  * See sel_updatefunc() for description of the parameters.
454  * \p data should point to a \c t_methoddata_kwreal.
455  *
456  * Does a binary search to find which atoms match the ranges in the
457  * \c t_methoddata_kwreal structure for this selection.
458  * Matching atoms are stored in \p out->u.g.
459  */
460 static void
461 evaluate_keyword_real(t_topology *top, t_trxframe *fr, t_pbc *pbc,
462                       gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
463 {
464     t_methoddata_kwreal *d = (t_methoddata_kwreal *)data;
465     int                  n, i, j, jmin, jmax;
466     real                 val;
467
468     out->u.g->isize = 0;
469     n               = d->n;
470     for (i = 0; i < g->isize; ++i)
471     {
472         val = d->v[i];
473         if (d->r[0] > val || d->r[2*n-1] < val)
474         {
475             continue;
476         }
477         jmin = 0;
478         jmax = n;
479         while (jmax - jmin > 1)
480         {
481             j = jmin + (jmax - jmin) / 2;
482             if (val < d->r[2*j])
483             {
484                 jmax = j;
485             }
486             else
487             {
488                 jmin = j;
489                 if (val <= d->r[2*j+1])
490                 {
491                     break;
492                 }
493                 /* ++jmin;*/
494             }
495         }
496         if (val <= d->r[2*jmin+1])
497         {
498             out->u.g->index[out->u.g->isize++] = g->index[i];
499         }
500     }
501 }
502
503
504 /********************************************************************
505  * STRING KEYWORD EVALUATION
506  ********************************************************************/
507
508 /*!
509  * \param[in] npar  Not used.
510  * \param     param Not used.
511  * \returns Pointer to the allocated data (t_methoddata_kwstr).
512  *
513  * Allocates memory for a t_methoddata_kwstr structure.
514  */
515 static void *
516 init_data_kwstr(int npar, gmx_ana_selparam_t *param)
517 {
518     t_methoddata_kwstr *data = new t_methoddata_kwstr();
519     data->matchType = gmx::eStringMatchType_Auto;
520     return data;
521 }
522
523 /*!
524  * \param[in,out] sel   Selection element to initialize.
525  * \param[in]     matchType  Method to use to match string values.
526  *
527  * Sets the string matching method for string keyword matching.
528  */
529 void
530 _gmx_selelem_set_kwstr_match_type(const gmx::SelectionTreeElementPointer &sel,
531                                   gmx::SelectionStringMatchType           matchType)
532 {
533     t_methoddata_kwstr *d = (t_methoddata_kwstr *)sel->u.expr.mdata;
534
535     if (sel->type != SEL_EXPRESSION || !sel->u.expr.method
536         || sel->u.expr.method->name != sm_keyword_str.name)
537     {
538         return;
539     }
540     d->matchType = matchType;
541 }
542
543 /*!
544  * \param[in] top   Not used.
545  * \param[in] npar  Not used (should be 2).
546  * \param[in] param Method parameters (should point to \ref smparams_keyword_str).
547  * \param[in] data  Should point to t_methoddata_kwstr.
548  */
549 static void
550 init_kwstr(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
551 {
552     t_methoddata_kwstr *d = (t_methoddata_kwstr *)data;
553
554     d->v   = param[0].val.u.s;
555     /* Return if this is not the first time */
556     if (!d->matches.empty())
557     {
558         return;
559     }
560     int n = param[1].val.nr;
561     d->matches.reserve(n);
562     for (int i = 0; i < n; ++i)
563     {
564         const char *s = param[1].val.u.s[i];
565         d->matches.push_back(StringKeywordMatchItem(d->matchType, s));
566     }
567 }
568
569 /*!
570  * \param data Data to free (should point to a t_methoddata_kwstr).
571  */
572 static void
573 free_data_kwstr(void *data)
574 {
575     t_methoddata_kwstr *d = (t_methoddata_kwstr *)data;
576     delete d;
577 }
578
579 /*!
580  * See sel_updatefunc() for description of the parameters.
581  * \p data should point to a \c t_methoddata_kwstr.
582  *
583  * Does a linear search to find which atoms match the strings in the
584  * \c t_methoddata_kwstr structure for this selection.
585  * Wildcards are allowed in the strings.
586  * Matching atoms are stored in \p out->u.g.
587  */
588 static void
589 evaluate_keyword_str(t_topology *top, t_trxframe *fr, t_pbc *pbc,
590                      gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
591 {
592     t_methoddata_kwstr *d = (t_methoddata_kwstr *)data;
593
594     out->u.g->isize = 0;
595     for (int i = 0; i < g->isize; ++i)
596     {
597         for (size_t j = 0; j < d->matches.size(); ++j)
598         {
599             if (d->matches[j].match(d->matchType, d->v[i]))
600             {
601                 out->u.g->index[out->u.g->isize++] = g->index[i];
602                 break;
603             }
604         }
605     }
606 }
607
608
609 /********************************************************************
610  * KEYWORD EVALUATION FOR ARBITRARY GROUPS
611  ********************************************************************/
612
613 /*!
614  * \param[in] top   Not used.
615  * \param[in] npar  Not used.
616  * \param[in] param Not used.
617  * \param[in] data  Should point to \ref t_methoddata_kweval.
618  * \returns   0 on success, a non-zero error code on return.
619  *
620  * Calls the initialization method of the wrapped keyword.
621  */
622 static void
623 init_kweval(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
624 {
625     t_methoddata_kweval *d = (t_methoddata_kweval *)data;
626
627     d->kwmethod->init(top, 0, NULL, d->kwmdata);
628 }
629
630 /*!
631  * \param[in]     top   Not used.
632  * \param[in,out] out   Pointer to output data structure.
633  * \param[in,out] data  Should point to \c t_methoddata_kweval.
634  * \returns       0 for success.
635  */
636 static void
637 init_output_kweval(t_topology *top, gmx_ana_selvalue_t *out, void *data)
638 {
639     t_methoddata_kweval *d = (t_methoddata_kweval *)data;
640
641     out->nr = d->g.isize;
642     _gmx_selvalue_reserve(out, out->nr);
643 }
644
645 /*!
646  * \param data Data to free (should point to a \c t_methoddata_kweval).
647  *
648  * Frees the memory allocated for all the members of \c t_methoddata_kweval.
649  */
650 static void
651 free_data_kweval(void *data)
652 {
653     t_methoddata_kweval *d = (t_methoddata_kweval *)data;
654
655     _gmx_selelem_free_method(d->kwmethod, d->kwmdata);
656     sfree(d);
657 }
658
659 /*!
660  * \param[in]  top  Topology.
661  * \param[in]  fr   Current frame.
662  * \param[in]  pbc  PBC structure.
663  * \param      data Should point to a \ref t_methoddata_kweval.
664  * \returns    0 on success, a non-zero error code on error.
665  *
666  * Creates a lookup structure that enables fast queries of whether a point
667  * is within the solid angle or not.
668  */
669 static void
670 init_frame_kweval(t_topology *top, t_trxframe *fr, t_pbc *pbc, void *data)
671 {
672     t_methoddata_kweval *d = (t_methoddata_kweval *)data;
673
674     d->kwmethod->init_frame(top, fr, pbc, d->kwmdata);
675 }
676
677 /*!
678  * See sel_updatefunc() for description of the parameters.
679  * \p data should point to a \c t_methoddata_kweval.
680  *
681  * Calls the evaluation function of the wrapped keyword with the given
682  * parameters, with the exception of using \c t_methoddata_kweval::g for the
683  * evaluation group.
684  */
685 static void
686 evaluate_kweval(t_topology *top, t_trxframe *fr, t_pbc *pbc,
687                 gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
688 {
689     t_methoddata_kweval *d = (t_methoddata_kweval *)data;
690
691     d->kwmethod->update(top, fr, pbc, &d->g, out, d->kwmdata);
692 }
693
694 /*!
695  * \param[in]   method  Keyword selection method to evaluate.
696  * \param[in]   params  Parameter that gives the group to evaluate \p method in.
697  * \param[in]   scanner Scanner data structure.
698  * \returns     Pointer to the created selection element (NULL on error).
699  *
700  * Creates a \ref SEL_EXPRESSION selection element that evaluates the keyword
701  * method given by \p method in the group given by \p param.
702  *
703  * The name of \p param should be empty.
704  */
705 gmx::SelectionTreeElementPointer
706 _gmx_sel_init_keyword_evaluator(gmx_ana_selmethod_t                     *method,
707                                 const gmx::SelectionParserParameterList &params,
708                                 void                                    *scanner)
709 {
710     gmx::MessageStringCollector *errors = _gmx_sel_lexer_error_reporter(scanner);
711     char  buf[1024];
712     sprintf(buf, "In evaluation of '%s'", method->name);
713     gmx::MessageStringContext   context(errors, buf);
714
715     if ((method->flags & (SMETH_SINGLEVAL | SMETH_VARNUMVAL))
716         || method->outinit || method->pupdate)
717     {
718         GMX_THROW(gmx::InternalError(
719                           "Unsupported keyword method for arbitrary group evaluation"));
720     }
721
722     gmx::SelectionTreeElementPointer sel(
723             new gmx::SelectionTreeElement(SEL_EXPRESSION));
724     _gmx_selelem_set_method(sel, method, scanner);
725
726     t_methoddata_kweval  *data;
727     snew(data, 1);
728     data->kwmethod = sel->u.expr.method;
729     data->kwmdata  = sel->u.expr.mdata;
730     gmx_ana_index_clear(&data->g);
731
732     snew(sel->u.expr.method, 1);
733     memcpy(sel->u.expr.method, data->kwmethod, sizeof(gmx_ana_selmethod_t));
734     sel->u.expr.method->flags       |= SMETH_VARNUMVAL;
735     sel->u.expr.method->init_data    = NULL;
736     sel->u.expr.method->set_poscoll  = NULL;
737     sel->u.expr.method->init         = method->init ? &init_kweval : NULL;
738     sel->u.expr.method->outinit      = &init_output_kweval;
739     sel->u.expr.method->free         = &free_data_kweval;
740     sel->u.expr.method->init_frame   = method->init_frame ? &init_frame_kweval : NULL;
741     sel->u.expr.method->update       = &evaluate_kweval;
742     sel->u.expr.method->pupdate      = NULL;
743     sel->u.expr.method->nparams      = asize(smparams_kweval);
744     sel->u.expr.method->param        = smparams_kweval;
745     _gmx_selelem_init_method_params(sel, scanner);
746     sel->u.expr.mdata = data;
747
748     sel->u.expr.method->param[0].val.u.g = &data->g;
749
750     if (!_gmx_sel_parse_params(params, sel->u.expr.method->nparams,
751                                sel->u.expr.method->param, sel, scanner))
752     {
753         return gmx::SelectionTreeElementPointer();
754     }
755     return sel;
756 }