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