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