8cca62b067b9f7143ff6a216e04f7ccda8a4e80b
[alexxy/gromacs.git] / src / gromacs / selection / selelem.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 functions in selelem.h.
38  *
39  * \author Teemu Murtola <teemu.murtola@gmail.com>
40  * \ingroup module_selection
41  */
42 #include "gmxpre.h"
43
44 #include "selelem.h"
45
46 #include <cstring>
47
48 #include "gromacs/selection/indexutil.h"
49 #include "gromacs/selection/position.h"
50 #include "gromacs/utility/exceptions.h"
51 #include "gromacs/utility/gmxassert.h"
52 #include "gromacs/utility/smalloc.h"
53 #include "gromacs/utility/stringutil.h"
54
55 #include "keywords.h"
56 #include "mempool.h"
57 #include "poscalc.h"
58 #include "selmethod.h"
59
60 /*!
61  * \param[in] sel Selection for which the string is requested
62  * \returns   Pointer to a string that corresponds to \p sel->type.
63  *
64  * The return value points to a string constant and should not be \p free'd.
65  *
66  * The function returns NULL if \p sel->type is not one of the valid values.
67  */
68 const char *
69 _gmx_selelem_type_str(const gmx::SelectionTreeElement &sel)
70 {
71     const char *p = NULL;
72     switch (sel.type)
73     {
74         case SEL_CONST:      p = "CONST";    break;
75         case SEL_EXPRESSION: p = "EXPR";     break;
76         case SEL_BOOLEAN:    p = "BOOL";     break;
77         case SEL_ARITHMETIC: p = "ARITH";    break;
78         case SEL_ROOT:       p = "ROOT";     break;
79         case SEL_SUBEXPR:    p = "SUBEXPR";  break;
80         case SEL_SUBEXPRREF: p = "REF";      break;
81         case SEL_GROUPREF:   p = "GROUPREF"; break;
82         case SEL_MODIFIER:   p = "MODIFIER"; break;
83             // No default clause so we intentionally get compiler errors
84             // if new selection choices are added later.
85     }
86     return p;
87 }
88
89 /*!
90  * \param[in] val Value structore for which the string is requested.
91  * \returns   Pointer to a string that corresponds to \p val->type,
92  *   NULL if the type value is invalid.
93  *
94  * The return value points to a string constant and should not be \p free'd.
95  */
96 const char *
97 _gmx_sel_value_type_str(const gmx_ana_selvalue_t *val)
98 {
99     const char *p = NULL;
100     switch (val->type)
101     {
102         case NO_VALUE:       p = "NONE";  break;
103         case INT_VALUE:      p = "INT";   break;
104         case REAL_VALUE:     p = "REAL";  break;
105         case STR_VALUE:      p = "STR";   break;
106         case POS_VALUE:      p = "VEC";   break;
107         case GROUP_VALUE:    p = "GROUP"; break;
108             // No default clause so we intentionally get compiler errors
109             // if new selection choices are added later.
110     }
111     return p;
112 }
113
114 /*! \copydoc _gmx_selelem_type_str() */
115 const char *
116 _gmx_selelem_boolean_type_str(const gmx::SelectionTreeElement &sel)
117 {
118     const char *p = NULL;
119     switch (sel.u.boolt)
120     {
121         case BOOL_NOT:  p = "NOT"; break;
122         case BOOL_AND:  p = "AND"; break;
123         case BOOL_OR:   p = "OR";  break;
124         case BOOL_XOR:  p = "XOR"; break;
125             // No default clause so we intentionally get compiler errors
126             // if new selection choices are added later.
127     }
128     return p;
129 }
130
131
132 namespace gmx
133 {
134
135 SelectionTreeElement::SelectionTreeElement(e_selelem_t              type,
136                                            const SelectionLocation &location)
137     : location_(location)
138 {
139     this->type       = type;
140     this->flags      = (type != SEL_ROOT) ? SEL_ALLOCVAL : 0;
141     if (type == SEL_BOOLEAN)
142     {
143         this->v.type = GROUP_VALUE;
144         this->flags |= SEL_ALLOCDATA;
145     }
146     else
147     {
148         this->v.type = NO_VALUE;
149     }
150     _gmx_selvalue_clear(&this->v);
151     std::memset(&this->u, 0, sizeof(this->u));
152     this->evaluate   = NULL;
153     this->mempool    = NULL;
154     this->cdata      = NULL;
155 }
156
157 SelectionTreeElement::~SelectionTreeElement()
158 {
159     /* Free the children.
160      * Must be done before freeing other data, because the children may hold
161      * references to data in this element. */
162     child.reset();
163
164     freeValues();
165     freeExpressionData();
166     freeCompilerData();
167 }
168
169 void SelectionTreeElement::freeValues()
170 {
171     mempoolRelease();
172     if ((flags & SEL_ALLOCDATA) && v.u.ptr)
173     {
174         /* The number of position/group structures is constant, so the
175          * backup of using sel->v.nr should work for them.
176          * For strings, we report an error if we don't know the allocation
177          * size here. */
178         int n = (v.nalloc > 0) ? v.nalloc : v.nr;
179         switch (v.type)
180         {
181             case STR_VALUE:
182                 GMX_RELEASE_ASSERT(v.nalloc != 0,
183                                    "SEL_ALLOCDATA should only be set for allocated "
184                                    "STR_VALUE values");
185                 for (int i = 0; i < n; ++i)
186                 {
187                     sfree(v.u.s[i]);
188                 }
189                 break;
190             case GROUP_VALUE:
191                 for (int i = 0; i < n; ++i)
192                 {
193                     gmx_ana_index_deinit(&v.u.g[i]);
194                 }
195                 break;
196             default: /* No special handling for other types */
197                 break;
198         }
199     }
200     _gmx_selvalue_free(&v);
201     if (type == SEL_SUBEXPRREF && u.param != NULL)
202     {
203         // TODO: This is now called from two different locations.
204         // It is likely that one of them is unnecessary, but that requires
205         // extra analysis to clarify.
206         _gmx_selelem_free_param(u.param);
207     }
208 }
209
210 void
211 SelectionTreeElement::freeExpressionData()
212 {
213     if (type == SEL_EXPRESSION || type == SEL_MODIFIER)
214     {
215         _gmx_selelem_free_method(u.expr.method, u.expr.mdata);
216         u.expr.mdata  = NULL;
217         u.expr.method = NULL;
218         /* Free position data */
219         delete u.expr.pos;
220         u.expr.pos = NULL;
221         /* Free position calculation data */
222         if (u.expr.pc)
223         {
224             gmx_ana_poscalc_free(u.expr.pc);
225             u.expr.pc = NULL;
226         }
227     }
228     if (type == SEL_ARITHMETIC)
229     {
230         sfree(u.arith.opstr);
231         u.arith.opstr = NULL;
232     }
233     if (type == SEL_SUBEXPR || type == SEL_ROOT
234         || (type == SEL_CONST && v.type == GROUP_VALUE))
235     {
236         gmx_ana_index_deinit(&u.cgrp);
237     }
238     if (type == SEL_GROUPREF)
239     {
240         sfree(u.gref.name);
241     }
242 }
243
244 void SelectionTreeElement::mempoolReserve(int count)
245 {
246     if (!mempool)
247     {
248         return;
249     }
250     switch (v.type)
251     {
252         case INT_VALUE:
253             v.u.i = static_cast<int *>(
254                     _gmx_sel_mempool_alloc(mempool, sizeof(*v.u.i)*count));
255             break;
256
257         case REAL_VALUE:
258             v.u.r = static_cast<real *>(
259                     _gmx_sel_mempool_alloc(mempool, sizeof(*v.u.r)*count));
260             break;
261
262         case GROUP_VALUE:
263             _gmx_sel_mempool_alloc_group(mempool, v.u.g, count);
264             break;
265
266         default:
267             GMX_THROW(gmx::InternalError("Memory pooling not implemented for requested type"));
268     }
269 }
270
271 void SelectionTreeElement::mempoolRelease()
272 {
273     if (!mempool)
274     {
275         return;
276     }
277     switch (v.type)
278     {
279         case INT_VALUE:
280         case REAL_VALUE:
281             _gmx_sel_mempool_free(mempool, v.u.ptr);
282             _gmx_selvalue_setstore(&v, NULL);
283             break;
284
285         case GROUP_VALUE:
286             if (v.u.g)
287             {
288                 _gmx_sel_mempool_free_group(mempool, v.u.g);
289             }
290             break;
291
292         default:
293             GMX_THROW(gmx::InternalError("Memory pooling not implemented for requested type"));
294     }
295 }
296
297 void SelectionTreeElement::fillNameIfMissing(const char *selectionText)
298 {
299     GMX_RELEASE_ASSERT(type == SEL_ROOT,
300                        "Should not be called for non-root elements");
301     if (name().empty())
302     {
303         // Check whether the actual selection given was from an external group,
304         // and if so, use the name of the external group.
305         SelectionTreeElementPointer child = this->child;
306         while (child->type == SEL_MODIFIER)
307         {
308             if (!child->child || child->child->type != SEL_SUBEXPRREF
309                 || !child->child->child)
310             {
311                 break;
312             }
313             child = child->child->child;
314         }
315         if (child->type == SEL_EXPRESSION
316             && child->child && child->child->type == SEL_SUBEXPRREF
317             && child->child->child)
318         {
319             if (child->child->child->type == SEL_CONST
320                 && child->child->child->v.type == GROUP_VALUE)
321             {
322                 setName(child->child->child->name());
323                 return;
324             }
325             // If the group reference is still unresolved, leave the name empty
326             // and fill it later.
327             if (child->child->child->type == SEL_GROUPREF)
328             {
329                 return;
330             }
331         }
332         // If there still is no name, use the selection string.
333         setName(selectionText);
334     }
335 }
336
337 void SelectionTreeElement::checkUnsortedAtoms(
338         bool bUnsortedAllowed, ExceptionInitializer *errors) const
339 {
340     const bool bUnsortedSupported
341         = (type == SEL_CONST && v.type == GROUP_VALUE)
342             || type == SEL_ROOT || type == SEL_SUBEXPR || type == SEL_SUBEXPRREF
343             // TODO: Consolidate.
344             || type == SEL_MODIFIER
345             || (type == SEL_EXPRESSION && (u.expr.method->flags & SMETH_ALLOW_UNSORTED));
346
347     // TODO: For some complicated selections, this may result in the same
348     // index group reference being flagged as an error multiple times for the
349     // same selection.
350     SelectionTreeElementPointer child = this->child;
351     while (child)
352     {
353         child->checkUnsortedAtoms(bUnsortedAllowed && bUnsortedSupported,
354                                   errors);
355         child = child->next;
356     }
357
358     // The logic here is simplified by the fact that only constant groups can
359     // currently be the root cause of SEL_UNSORTED being set, so only those
360     // need to be considered in triggering the error.
361     if (!bUnsortedAllowed && (flags & SEL_UNSORTED)
362         && type == SEL_CONST && v.type == GROUP_VALUE)
363     {
364         std::string message = formatString(
365                     "Group '%s' cannot be used in selections except "
366                     "as a full value of the selection, "
367                     "because atom indices in it are not sorted and/or "
368                     "it contains duplicate atoms.",
369                     name().c_str());
370         errors->addNested(InconsistentInputError(message));
371     }
372 }
373
374 void SelectionTreeElement::resolveIndexGroupReference(
375         gmx_ana_indexgrps_t *grps, int natoms)
376 {
377     GMX_RELEASE_ASSERT(type == SEL_GROUPREF,
378                        "Should only be called for index group reference elements");
379     if (grps == NULL)
380     {
381         std::string message = formatString(
382                     "Cannot match '%s', because index groups are not available.",
383                     name().c_str());
384         GMX_THROW(InconsistentInputError(message));
385     }
386
387     gmx_ana_index_t foundGroup;
388     std::string     foundName;
389     if (u.gref.name != NULL)
390     {
391         if (!gmx_ana_indexgrps_find(&foundGroup, &foundName, grps, u.gref.name))
392         {
393             std::string message = formatString(
394                         "Cannot match '%s', because no such index group can be found.",
395                         name().c_str());
396             GMX_THROW(InconsistentInputError(message));
397         }
398     }
399     else
400     {
401         if (!gmx_ana_indexgrps_extract(&foundGroup, &foundName, grps, u.gref.id))
402         {
403             std::string message = formatString(
404                         "Cannot match '%s', because no such index group can be found.",
405                         name().c_str());
406             GMX_THROW(InconsistentInputError(message));
407         }
408     }
409
410     if (!gmx_ana_index_check_sorted(&foundGroup))
411     {
412         flags |= SEL_UNSORTED;
413     }
414
415     sfree(u.gref.name);
416     type = SEL_CONST;
417     gmx_ana_index_set(&u.cgrp, foundGroup.isize, foundGroup.index,
418                       foundGroup.nalloc_index);
419     setName(foundName);
420
421     if (natoms > 0)
422     {
423         checkIndexGroup(natoms);
424     }
425 }
426
427 void SelectionTreeElement::checkIndexGroup(int natoms)
428 {
429     GMX_RELEASE_ASSERT(type == SEL_CONST && v.type == GROUP_VALUE,
430                        "Should only be called for index group elements");
431     if (!gmx_ana_index_check_range(&u.cgrp, natoms))
432     {
433         std::string message = formatString(
434                     "Group '%s' cannot be used in selections, because it "
435                     "contains negative atom indices and/or references atoms "
436                     "not present (largest allowed atom index is %d).",
437                     name().c_str(), natoms);
438         GMX_THROW(InconsistentInputError(message));
439     }
440 }
441
442 } // namespace gmx
443
444 /*!
445  * \param[in,out] sel   Selection element to set the type for.
446  * \param[in]     vtype Value type for the selection element.
447  *
448  * If the new type is \ref GROUP_VALUE or \ref POS_VALUE, the
449  * \ref SEL_ALLOCDATA flag is also set.
450  *
451  * This function should only be called at most once for each element,
452  * preferably right after calling _gmx_selelem_create().
453  */
454 void
455 _gmx_selelem_set_vtype(const gmx::SelectionTreeElementPointer &sel,
456                        e_selvalue_t                            vtype)
457 {
458     GMX_RELEASE_ASSERT(sel->type != SEL_BOOLEAN || vtype == GROUP_VALUE,
459                        "Boolean elements must have a group value");
460     GMX_RELEASE_ASSERT(sel->v.type == NO_VALUE || vtype == sel->v.type,
461                        "_gmx_selelem_set_vtype() called more than once");
462     sel->v.type = vtype;
463     if (vtype == GROUP_VALUE || vtype == POS_VALUE)
464     {
465         sel->flags |= SEL_ALLOCDATA;
466     }
467 }
468
469 void
470 _gmx_selelem_free_param(gmx_ana_selparam_t *param)
471 {
472     if (param->val.u.ptr != NULL)
473     {
474         if (param->val.type == GROUP_VALUE)
475         {
476             for (int i = 0; i < param->val.nr; ++i)
477             {
478                 gmx_ana_index_deinit(&param->val.u.g[i]);
479             }
480         }
481         _gmx_selvalue_free(&param->val);
482     }
483 }
484
485 void
486 _gmx_selelem_free_method(gmx_ana_selmethod_t *method, void *mdata)
487 {
488     sel_freefunc free_func = NULL;
489
490     /* Save the pointer to the free function. */
491     if (method && method->free)
492     {
493         free_func = method->free;
494     }
495
496     /* Free the method itself.
497      * Has to be done before freeing the method data, because parameter
498      * values are typically stored in the method data, and here we may
499      * access them. */
500     if (method)
501     {
502         /* Free the memory allocated for the parameters that are not managed
503          * by the selection method itself. */
504         for (int i = 0; i < method->nparams; ++i)
505         {
506             _gmx_selelem_free_param(&method->param[i]);
507         }
508         sfree(method->param);
509         sfree(method);
510     }
511     /* Free method data. */
512     if (mdata)
513     {
514         if (free_func)
515         {
516             free_func(mdata);
517         }
518         else
519         {
520             sfree(mdata);
521         }
522     }
523 }
524
525 /*!
526  * \param[in] fp      File handle to receive the output.
527  * \param[in] sel     Root of the selection subtree to print.
528  * \param[in] bValues If true, the evaluated values of selection elements
529  *   are printed as well.
530  * \param[in] level   Indentation level, starting from zero.
531  */
532 void
533 _gmx_selelem_print_tree(FILE *fp, const gmx::SelectionTreeElement &sel,
534                         bool bValues, int level)
535 {
536     int          i;
537
538     fprintf(fp, "%*c %s %s", level*2+1, '*',
539             _gmx_selelem_type_str(sel), _gmx_sel_value_type_str(&sel.v));
540     if (!sel.name().empty())
541     {
542         fprintf(fp, " \"%s\"", sel.name().c_str());
543     }
544     fprintf(fp, " flg=");
545     if (sel.flags & SEL_FLAGSSET)
546     {
547         fprintf(fp, "s");
548     }
549     if (sel.flags & SEL_SINGLEVAL)
550     {
551         fprintf(fp, "S");
552     }
553     if (sel.flags & SEL_ATOMVAL)
554     {
555         fprintf(fp, "A");
556     }
557     if (sel.flags & SEL_VARNUMVAL)
558     {
559         fprintf(fp, "V");
560     }
561     if (sel.flags & SEL_DYNAMIC)
562     {
563         fprintf(fp, "D");
564     }
565     if (!(sel.flags & SEL_VALFLAGMASK))
566     {
567         fprintf(fp, "0");
568     }
569     if (sel.flags & SEL_ALLOCVAL)
570     {
571         fprintf(fp, "Av");
572     }
573     if (sel.flags & SEL_ALLOCDATA)
574     {
575         fprintf(fp, "Ad");
576     }
577     if (sel.mempool)
578     {
579         fprintf(fp, "P");
580     }
581     if (sel.type == SEL_CONST)
582     {
583         if (sel.v.type == INT_VALUE)
584         {
585             fprintf(fp, " %d", sel.v.u.i[0]);
586         }
587         else if (sel.v.type == REAL_VALUE)
588         {
589             fprintf(fp, " %f", sel.v.u.r[0]);
590         }
591         else if (sel.v.type == GROUP_VALUE)
592         {
593             const gmx_ana_index_t *g = sel.v.u.g;
594             if (!g || g->isize == 0)
595             {
596                 g = &sel.u.cgrp;
597             }
598             fprintf(fp, " (%d atoms)", g->isize);
599         }
600     }
601     else if (sel.type == SEL_BOOLEAN)
602     {
603         fprintf(fp, " %s", _gmx_selelem_boolean_type_str(sel));
604     }
605     else if (sel.type == SEL_EXPRESSION
606              && sel.u.expr.method->name == sm_compare.name)
607     {
608         _gmx_selelem_print_compare_info(fp, sel.u.expr.mdata);
609     }
610     if (sel.evaluate)
611     {
612         fprintf(fp, " eval=");
613         _gmx_sel_print_evalfunc_name(fp, sel.evaluate);
614     }
615     if (sel.v.nalloc < 0)
616     {
617         fprintf(fp, " (ext)");
618     }
619     fprintf(fp, "\n");
620
621     if ((sel.type == SEL_CONST && sel.v.type == GROUP_VALUE) || sel.type == SEL_ROOT)
622     {
623         const gmx_ana_index_t *g = sel.v.u.g;
624         if (!g || g->isize == 0 || sel.evaluate != NULL)
625         {
626             g = &sel.u.cgrp;
627         }
628         if (g->isize < 0)
629         {
630             fprintf(fp, "%*c group: (null)\n", level*2+1, ' ');
631         }
632         else if (g->isize > 0)
633         {
634             fprintf(fp, "%*c group:", level*2+1, ' ');
635             if (g->isize <= 20)
636             {
637                 for (i = 0; i < g->isize; ++i)
638                 {
639                     fprintf(fp, " %d", g->index[i] + 1);
640                 }
641             }
642             else
643             {
644                 fprintf(fp, " %d atoms", g->isize);
645             }
646             fprintf(fp, "\n");
647         }
648     }
649     else if (sel.type == SEL_EXPRESSION)
650     {
651         if (sel.u.expr.pc)
652         {
653             fprintf(fp, "%*c COM", level*2+3, '*');
654             fprintf(fp, "\n");
655         }
656     }
657     else if (sel.type == SEL_SUBEXPRREF && sel.u.param != NULL)
658     {
659         fprintf(fp, "%*c param", level*2+1, ' ');
660         if (sel.u.param->name != NULL)
661         {
662             fprintf(fp, " \"%s\"", sel.u.param->name);
663         }
664         if (sel.u.param->val.nalloc < 0)
665         {
666             fprintf(fp, " (ext)");
667         }
668         else
669         {
670             fprintf(fp, " nalloc: %d", sel.u.param->val.nalloc);
671         }
672         fprintf(fp, "\n");
673     }
674
675     if (sel.cdata)
676     {
677         _gmx_selelem_print_compiler_info(fp, sel, level);
678     }
679
680     if (bValues && sel.type != SEL_CONST && sel.type != SEL_ROOT && sel.v.u.ptr)
681     {
682         fprintf(fp, "%*c value: ", level*2+1, ' ');
683         switch (sel.v.type)
684         {
685             case POS_VALUE:
686                 /* In normal use, the pointer should never be NULL, but it's
687                  * useful to have the check for debugging to avoid accidental
688                  * segfaults when printing the selection tree. */
689                 if (sel.v.u.p->x)
690                 {
691                     fprintf(fp, "(%f, %f, %f)",
692                             sel.v.u.p->x[0][XX], sel.v.u.p->x[0][YY],
693                             sel.v.u.p->x[0][ZZ]);
694                 }
695                 else
696                 {
697                     fprintf(fp, "(null)");
698                 }
699                 break;
700             case GROUP_VALUE:
701                 fprintf(fp, "%d atoms", sel.v.u.g->isize);
702                 if (sel.v.u.g->isize < 20)
703                 {
704                     if (sel.v.u.g->isize > 0)
705                     {
706                         fprintf(fp, ":");
707                     }
708                     for (i = 0; i < sel.v.u.g->isize; ++i)
709                     {
710                         fprintf(fp, " %d", sel.v.u.g->index[i] + 1);
711                     }
712                 }
713                 break;
714             default:
715                 fprintf(fp, "???");
716                 break;
717         }
718         fprintf(fp, "\n");
719     }
720
721     /* Print the subexpressions with one more level of indentation */
722     gmx::SelectionTreeElementPointer child = sel.child;
723     while (child)
724     {
725         if (!(sel.type == SEL_SUBEXPRREF && child->type == SEL_SUBEXPR))
726         {
727             _gmx_selelem_print_tree(fp, *child, bValues, level+1);
728         }
729         child = child->next;
730     }
731 }
732
733 /*!
734  * \param[in] root Root of the subtree to query.
735  * \returns true if \p root or any any of its elements require topology
736  *   information, false otherwise.
737  */
738 bool
739 _gmx_selelem_requires_top(const gmx::SelectionTreeElement &root)
740 {
741     if (root.type == SEL_EXPRESSION || root.type == SEL_MODIFIER)
742     {
743         if (root.u.expr.method && (root.u.expr.method->flags & SMETH_REQTOP))
744         {
745             return true;
746         }
747         if (root.u.expr.pc && gmx_ana_poscalc_requires_top(root.u.expr.pc))
748         {
749             return true;
750         }
751     }
752     gmx::SelectionTreeElementPointer child = root.child;
753     while (child)
754     {
755         if (_gmx_selelem_requires_top(*child))
756         {
757             return true;
758         }
759         child = child->next;
760     }
761     return false;
762 }