2 * This file is part of the GROMACS molecular simulation package.
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.
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.
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.
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.
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.
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.
37 * Implements functions in selelem.h.
39 * \author Teemu Murtola <teemu.murtola@gmail.com>
40 * \ingroup module_selection
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"
58 #include "selmethod.h"
61 * \param[in] sel Selection for which the string is requested
62 * \returns Pointer to a string that corresponds to \p sel->type.
64 * The return value points to a string constant and should not be \p free'd.
66 * The function returns NULL if \p sel->type is not one of the valid values.
69 _gmx_selelem_type_str(const gmx::SelectionTreeElement &sel)
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.
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.
94 * The return value points to a string constant and should not be \p free'd.
97 _gmx_sel_value_type_str(const gmx_ana_selvalue_t *val)
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.
114 /*! \copydoc _gmx_selelem_type_str() */
116 _gmx_selelem_boolean_type_str(const gmx::SelectionTreeElement &sel)
118 const char *p = NULL;
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.
135 SelectionTreeElement::SelectionTreeElement(e_selelem_t type,
136 const SelectionLocation &location)
137 : location_(location)
140 this->flags = (type != SEL_ROOT) ? SEL_ALLOCVAL : 0;
141 if (type == SEL_BOOLEAN)
143 this->v.type = GROUP_VALUE;
144 this->flags |= SEL_ALLOCDATA;
148 this->v.type = NO_VALUE;
150 _gmx_selvalue_clear(&this->v);
151 std::memset(&this->u, 0, sizeof(this->u));
152 this->evaluate = NULL;
153 this->mempool = NULL;
157 SelectionTreeElement::~SelectionTreeElement()
159 /* Free the children.
160 * Must be done before freeing other data, because the children may hold
161 * references to data in this element. */
165 freeExpressionData();
169 void SelectionTreeElement::freeValues()
172 if ((flags & SEL_ALLOCDATA) && v.u.ptr)
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
178 int n = (v.nalloc > 0) ? v.nalloc : v.nr;
182 GMX_RELEASE_ASSERT(v.nalloc != 0,
183 "SEL_ALLOCDATA should only be set for allocated "
185 for (int i = 0; i < n; ++i)
191 for (int i = 0; i < n; ++i)
193 gmx_ana_index_deinit(&v.u.g[i]);
196 default: /* No special handling for other types */
200 _gmx_selvalue_free(&v);
201 if (type == SEL_SUBEXPRREF && u.param != NULL)
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);
211 SelectionTreeElement::freeExpressionData()
213 if (type == SEL_EXPRESSION || type == SEL_MODIFIER)
215 _gmx_selelem_free_method(u.expr.method, u.expr.mdata);
217 u.expr.method = NULL;
218 /* Free position data */
221 /* Free position calculation data */
224 gmx_ana_poscalc_free(u.expr.pc);
228 if (type == SEL_ARITHMETIC)
230 sfree(u.arith.opstr);
231 u.arith.opstr = NULL;
233 if (type == SEL_SUBEXPR || type == SEL_ROOT
234 || (type == SEL_CONST && v.type == GROUP_VALUE))
236 gmx_ana_index_deinit(&u.cgrp);
238 if (type == SEL_GROUPREF)
244 void SelectionTreeElement::mempoolReserve(int count)
253 v.u.i = static_cast<int *>(
254 _gmx_sel_mempool_alloc(mempool, sizeof(*v.u.i)*count));
258 v.u.r = static_cast<real *>(
259 _gmx_sel_mempool_alloc(mempool, sizeof(*v.u.r)*count));
263 _gmx_sel_mempool_alloc_group(mempool, v.u.g, count);
267 GMX_THROW(gmx::InternalError("Memory pooling not implemented for requested type"));
271 void SelectionTreeElement::mempoolRelease()
281 _gmx_sel_mempool_free(mempool, v.u.ptr);
282 _gmx_selvalue_setstore(&v, NULL);
288 _gmx_sel_mempool_free_group(mempool, v.u.g);
293 GMX_THROW(gmx::InternalError("Memory pooling not implemented for requested type"));
297 void SelectionTreeElement::fillNameIfMissing(const char *selectionText)
299 GMX_RELEASE_ASSERT(type == SEL_ROOT,
300 "Should not be called for non-root elements");
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)
308 if (!child->child || child->child->type != SEL_SUBEXPRREF
309 || !child->child->child)
313 child = child->child->child;
315 if (child->type == SEL_EXPRESSION
316 && child->child && child->child->type == SEL_SUBEXPRREF
317 && child->child->child)
319 if (child->child->child->type == SEL_CONST
320 && child->child->child->v.type == GROUP_VALUE)
322 setName(child->child->child->name());
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)
332 // If there still is no name, use the selection string.
333 setName(selectionText);
337 void SelectionTreeElement::checkUnsortedAtoms(
338 bool bUnsortedAllowed, ExceptionInitializer *errors) const
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));
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
350 SelectionTreeElementPointer child = this->child;
353 child->checkUnsortedAtoms(bUnsortedAllowed && bUnsortedSupported,
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)
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.",
370 errors->addNested(InconsistentInputError(message));
374 void SelectionTreeElement::resolveIndexGroupReference(
375 gmx_ana_indexgrps_t *grps, int natoms)
377 GMX_RELEASE_ASSERT(type == SEL_GROUPREF,
378 "Should only be called for index group reference elements");
381 std::string message = formatString(
382 "Cannot match '%s', because index groups are not available.",
384 GMX_THROW(InconsistentInputError(message));
387 gmx_ana_index_t foundGroup;
388 std::string foundName;
389 if (u.gref.name != NULL)
391 if (!gmx_ana_indexgrps_find(&foundGroup, &foundName, grps, u.gref.name))
393 std::string message = formatString(
394 "Cannot match '%s', because no such index group can be found.",
396 GMX_THROW(InconsistentInputError(message));
401 if (!gmx_ana_indexgrps_extract(&foundGroup, &foundName, grps, u.gref.id))
403 std::string message = formatString(
404 "Cannot match '%s', because no such index group can be found.",
406 GMX_THROW(InconsistentInputError(message));
410 if (!gmx_ana_index_check_sorted(&foundGroup))
412 flags |= SEL_UNSORTED;
417 gmx_ana_index_set(&u.cgrp, foundGroup.isize, foundGroup.index,
418 foundGroup.nalloc_index);
423 checkIndexGroup(natoms);
427 void SelectionTreeElement::checkIndexGroup(int natoms)
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))
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));
445 * \param[in,out] sel Selection element to set the type for.
446 * \param[in] vtype Value type for the selection element.
448 * If the new type is \ref GROUP_VALUE or \ref POS_VALUE, the
449 * \ref SEL_ALLOCDATA flag is also set.
451 * This function should only be called at most once for each element,
452 * preferably right after calling _gmx_selelem_create().
455 _gmx_selelem_set_vtype(const gmx::SelectionTreeElementPointer &sel,
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");
463 if (vtype == GROUP_VALUE || vtype == POS_VALUE)
465 sel->flags |= SEL_ALLOCDATA;
470 _gmx_selelem_free_param(gmx_ana_selparam_t *param)
472 if (param->val.u.ptr != NULL)
474 if (param->val.type == GROUP_VALUE)
476 for (int i = 0; i < param->val.nr; ++i)
478 gmx_ana_index_deinit(¶m->val.u.g[i]);
481 _gmx_selvalue_free(¶m->val);
486 _gmx_selelem_free_method(gmx_ana_selmethod_t *method, void *mdata)
488 sel_freefunc free_func = NULL;
490 /* Save the pointer to the free function. */
491 if (method && method->free)
493 free_func = method->free;
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
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)
506 _gmx_selelem_free_param(&method->param[i]);
508 sfree(method->param);
511 /* Free method data. */
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.
533 _gmx_selelem_print_tree(FILE *fp, const gmx::SelectionTreeElement &sel,
534 bool bValues, int level)
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())
542 fprintf(fp, " \"%s\"", sel.name().c_str());
544 fprintf(fp, " flg=");
545 if (sel.flags & SEL_FLAGSSET)
549 if (sel.flags & SEL_SINGLEVAL)
553 if (sel.flags & SEL_ATOMVAL)
557 if (sel.flags & SEL_VARNUMVAL)
561 if (sel.flags & SEL_DYNAMIC)
565 if (!(sel.flags & SEL_VALFLAGMASK))
569 if (sel.flags & SEL_ALLOCVAL)
573 if (sel.flags & SEL_ALLOCDATA)
581 if (sel.type == SEL_CONST)
583 if (sel.v.type == INT_VALUE)
585 fprintf(fp, " %d", sel.v.u.i[0]);
587 else if (sel.v.type == REAL_VALUE)
589 fprintf(fp, " %f", sel.v.u.r[0]);
591 else if (sel.v.type == GROUP_VALUE)
593 const gmx_ana_index_t *g = sel.v.u.g;
594 if (!g || g->isize == 0)
598 fprintf(fp, " (%d atoms)", g->isize);
601 else if (sel.type == SEL_BOOLEAN)
603 fprintf(fp, " %s", _gmx_selelem_boolean_type_str(sel));
605 else if (sel.type == SEL_EXPRESSION
606 && sel.u.expr.method->name == sm_compare.name)
608 _gmx_selelem_print_compare_info(fp, sel.u.expr.mdata);
612 fprintf(fp, " eval=");
613 _gmx_sel_print_evalfunc_name(fp, sel.evaluate);
615 if (sel.v.nalloc < 0)
617 fprintf(fp, " (ext)");
621 if ((sel.type == SEL_CONST && sel.v.type == GROUP_VALUE) || sel.type == SEL_ROOT)
623 const gmx_ana_index_t *g = sel.v.u.g;
624 if (!g || g->isize == 0 || sel.evaluate != NULL)
630 fprintf(fp, "%*c group: (null)\n", level*2+1, ' ');
632 else if (g->isize > 0)
634 fprintf(fp, "%*c group:", level*2+1, ' ');
637 for (i = 0; i < g->isize; ++i)
639 fprintf(fp, " %d", g->index[i] + 1);
644 fprintf(fp, " %d atoms", g->isize);
649 else if (sel.type == SEL_EXPRESSION)
653 fprintf(fp, "%*c COM", level*2+3, '*');
657 else if (sel.type == SEL_SUBEXPRREF && sel.u.param != NULL)
659 fprintf(fp, "%*c param", level*2+1, ' ');
660 if (sel.u.param->name != NULL)
662 fprintf(fp, " \"%s\"", sel.u.param->name);
664 if (sel.u.param->val.nalloc < 0)
666 fprintf(fp, " (ext)");
670 fprintf(fp, " nalloc: %d", sel.u.param->val.nalloc);
677 _gmx_selelem_print_compiler_info(fp, sel, level);
680 if (bValues && sel.type != SEL_CONST && sel.type != SEL_ROOT && sel.v.u.ptr)
682 fprintf(fp, "%*c value: ", level*2+1, ' ');
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. */
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]);
697 fprintf(fp, "(null)");
701 fprintf(fp, "%d atoms", sel.v.u.g->isize);
702 if (sel.v.u.g->isize < 20)
704 if (sel.v.u.g->isize > 0)
708 for (i = 0; i < sel.v.u.g->isize; ++i)
710 fprintf(fp, " %d", sel.v.u.g->index[i] + 1);
721 /* Print the subexpressions with one more level of indentation */
722 gmx::SelectionTreeElementPointer child = sel.child;
725 if (!(sel.type == SEL_SUBEXPRREF && child->type == SEL_SUBEXPR))
727 _gmx_selelem_print_tree(fp, *child, bValues, level+1);
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.
739 _gmx_selelem_requires_top(const gmx::SelectionTreeElement &root)
741 if (root.type == SEL_EXPRESSION || root.type == SEL_MODIFIER)
743 if (root.u.expr.method && (root.u.expr.method->flags & SMETH_REQTOP))
747 if (root.u.expr.pc && gmx_ana_poscalc_requires_top(root.u.expr.pc))
752 gmx::SelectionTreeElementPointer child = root.child;
755 if (_gmx_selelem_requires_top(*child))