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