/*
+ * This file is part of the GROMACS molecular simulation package.
*
- * This source code is part of
+ * Copyright (c) 2009,2010,2011,2012,2013,2014, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
*
- * G R O M A C S
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
*
- * GROningen MAchine for Chemical Simulations
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
*
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
*
* To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
+ * the research papers on the package. Check out http://www.gromacs.org.
*/
/*! \internal \file
* \brief Selection compilation and optimization.
* Use of memory pooling could still be extended, and a lot of redundant
* gmin/gmax data could be eliminated for complex arithmetic expressions.
*
- * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
* \ingroup module_selection
*/
/*! \internal
* calculated.
* Currently, no other processing is done.
*/
-#include "compiler.h"
+#include "gmxpre.h"
-#include <algorithm>
+#include "compiler.h"
#include <math.h>
#include <stdarg.h>
-#include "gromacs/legacyheaders/smalloc.h"
-#include "gromacs/legacyheaders/string2.h"
-#include "gromacs/legacyheaders/vec.h"
+#include <algorithm>
+#include "gromacs/math/vec.h"
#include "gromacs/selection/indexutil.h"
-#include "gromacs/selection/poscalc.h"
#include "gromacs/selection/selection.h"
-#include "gromacs/selection/selmethod.h"
#include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/smalloc.h"
#include "gromacs/utility/stringutil.h"
#include "evaluate.h"
#include "keywords.h"
#include "mempool.h"
+#include "poscalc.h"
#include "selectioncollection-impl.h"
#include "selelem.h"
+#include "selmethod.h"
using std::min;
using gmx::SelectionTreeElement;
/** Whether memory has been allocated for \p gmin and \p gmax. */
SEL_CDATA_MINMAXALLOC = 16,
/** Whether to update \p gmin and \p gmax in static analysis. */
- SEL_CDATA_DOMINMAX = 128,
+ SEL_CDATA_DOMINMAX = 256,
/** Whether the subexpression uses simple pass evaluation functions. */
SEL_CDATA_SIMPLESUBEXPR = 32,
+ /*! \brief
+ * Whether a static subexpression needs to support multiple evaluations.
+ *
+ * This flag may only be set on \ref SEL_SUBEXPR elements that also have
+ * SEL_CDATA_SIMPLESUBEXPR.
+ */
+ SEL_CDATA_STATICMULTIEVALSUBEXPR = 64,
/** Whether this expression is a part of a common subexpression. */
- SEL_CDATA_COMMONSUBEXPR = 64
+ SEL_CDATA_COMMONSUBEXPR = 128
};
/*! \internal \brief
/** The real evaluation method. */
gmx::sel_evalfunc evaluate;
/** Number of references to a \ref SEL_SUBEXPR element. */
- int refcount;
+ int refcount;
/** Flags for specifying how to treat this element during compilation. */
- int flags;
+ int flags;
/** Smallest selection that can be selected by the subexpression. */
- gmx_ana_index_t *gmin;
+ gmx_ana_index_t *gmin;
/** Largest selection that can be selected by the subexpression. */
- gmx_ana_index_t *gmax;
+ gmx_ana_index_t *gmax;
} t_compiler_data;
{
fprintf(fp, "Ss");
}
+ if (sel.cdata->flags & SEL_CDATA_STATICMULTIEVALSUBEXPR)
+ {
+ fprintf(fp, "Sm");
+ }
if (sel.cdata->flags & SEL_CDATA_COMMONSUBEXPR)
{
fprintf(fp, "Sc");
evaluate = cdata->evaluate;
if (cdata->flags & SEL_CDATA_MINMAXALLOC)
{
- cdata->gmin->name = NULL;
- cdata->gmax->name = NULL;
gmx_ana_index_deinit(cdata->gmin);
gmx_ana_index_deinit(cdata->gmax);
sfree(cdata->gmin);
int nalloc;
GMX_RELEASE_ASSERT(sel->v.type != POS_VALUE,
- "Wrong allocation method called");
+ "Wrong allocation method called");
if (sel->mempool)
{
return;
if (sel->type == SEL_SUBEXPRREF)
{
GMX_RELEASE_ASSERT(sel->child && sel->child->type == SEL_SUBEXPR,
- "Subexpression expected for subexpression reference");
+ "Subexpression expected for subexpression reference");
child = sel->child->child;
GMX_RELEASE_ASSERT(child,
- "Subexpression elements should always have a child element");
+ "Subexpression elements should always have a child element");
}
nalloc = child->v.nr;
}
int nalloc, isize;
GMX_RELEASE_ASSERT(sel->v.type == POS_VALUE,
- "Wrong allocation method called");
+ "Wrong allocation method called");
GMX_RELEASE_ASSERT(!(sel->flags & SEL_ATOMVAL),
- "Per-atom evaluated positions not implemented");
+ "Per-atom evaluated positions not implemented");
if (sel->mempool)
{
return;
if (sel->type == SEL_SUBEXPRREF)
{
GMX_RELEASE_ASSERT(sel->child && sel->child->type == SEL_SUBEXPR,
- "Subexpression expected for subexpression reference");
+ "Subexpression expected for subexpression reference");
child = sel->child->child;
GMX_RELEASE_ASSERT(child,
- "Subexpression elements should always have a child element");
+ "Subexpression elements should always have a child element");
}
- nalloc = child->v.u.p->nr;
- isize = child->v.u.p->m.b.nra;
+ nalloc = child->v.u.p->count();
+ isize = child->v.u.p->m.b.nra;
/* For positions, we want to allocate just a single structure
* for nalloc positions. */
*/
static void
set_evaluation_function(const SelectionTreeElementPointer &sel,
- gmx::sel_evalfunc eval)
+ gmx::sel_evalfunc eval)
{
sel->evaluate = eval;
if (sel->type != SEL_SUBEXPRREF)
if (root->type == SEL_EXPRESSION)
{
bool bSelection = (sel != NULL);
- int flags = bSelection ? POS_COMPLMAX : POS_COMPLWHOLE;
+ int flags = bSelection ? POS_COMPLMAX : POS_COMPLWHOLE;
if (bSelection)
{
if (sel->hasFlag(gmx::efSelection_DynamicMask))
{
SelectionTreeElementPointer next = item->next;
item->next = prev;
- prev = item;
- item = next;
+ prev = item;
+ item = next;
}
return prev;
}
{
std::string name(gmx::formatString("SubExpr %d", i));
sel->setName(name);
- sel->u.cgrp.name = strdup(name.c_str());
}
/*! \brief
*/
static SelectionTreeElementPointer
extract_item_subselections(const SelectionTreeElementPointer &sel,
- int *subexprn)
+ int *subexprn)
{
SelectionTreeElementPointer root;
SelectionTreeElementPointer subexpr;
/*! \brief
* Extracts subexpressions of the selection chain.
- *
+ *
* \param sel First selection in the whole selection chain.
* \returns The new first element for the chain.
*
{
SelectionTreeElementPointer root;
SelectionTreeElementPointer next = sel;
- int subexprn = 0;
+ int subexprn = 0;
while (next)
{
SelectionTreeElementPointer item
{
root = next;
}
- sel = next;
+ sel = next;
next = next->next;
}
return root;
}
else
{
- prev = child;
+ prev = child;
child = child->next;
}
}
snew(r, 1);
r[0] = child->v.u.i[0];
sfree(child->v.u.i);
- child->v.u.r = r;
+ child->v.u.r = r;
child->v.type = REAL_VALUE;
}
else if (child->v.type != REAL_VALUE)
break;
case SEL_SUBEXPR:
- sel->evaluate = ((sel->cdata->flags & SEL_CDATA_SIMPLESUBEXPR)
- ? &_gmx_sel_evaluate_subexpr_simple
- : &_gmx_sel_evaluate_subexpr);
+ if ((sel->cdata->flags & SEL_CDATA_SIMPLESUBEXPR)
+ && !(sel->cdata->flags & SEL_CDATA_STATICMULTIEVALSUBEXPR))
+ {
+ sel->evaluate = &_gmx_sel_evaluate_subexpr_simple;
+ }
+ else
+ {
+ sel->evaluate = &_gmx_sel_evaluate_subexpr;
+ }
break;
case SEL_SUBEXPRREF:
*/
static void
setup_memory_pooling(const SelectionTreeElementPointer &sel,
- gmx_sel_mempool_t *mempool)
+ gmx_sel_mempool_t *mempool)
{
if (sel->type != SEL_SUBEXPRREF)
{
}
if (sel->type == SEL_SUBEXPR
- && (sel->cdata->flags & SEL_CDATA_SIMPLESUBEXPR))
+ && (sel->cdata->flags & SEL_CDATA_SIMPLESUBEXPR)
+ && !(sel->cdata->flags & SEL_CDATA_STATICMULTIEVALSUBEXPR))
{
sel->flags &= ~(SEL_ALLOCVAL | SEL_ALLOCDATA);
if (sel->v.type == GROUP_VALUE || sel->v.type == POS_VALUE)
else if (sel->type == SEL_SUBEXPR
&& (sel->cdata->flags & SEL_CDATA_FULLEVAL))
{
- sel->evaluate = &_gmx_sel_evaluate_subexpr_staticeval;
+ sel->evaluate = &_gmx_sel_evaluate_subexpr_staticeval;
sel->cdata->evaluate = sel->evaluate;
- sel->child->mempool = NULL;
- sel->flags &= ~(SEL_ALLOCVAL | SEL_ALLOCDATA);
+ sel->child->mempool = NULL;
+ sel->flags &= ~(SEL_ALLOCVAL | SEL_ALLOCDATA);
if (sel->v.type == GROUP_VALUE || sel->v.type == POS_VALUE)
{
_gmx_selvalue_setstore(&sel->v, sel->child->v.u.ptr);
while (child)
{
child->cdata->flags |= SEL_CDATA_EVALMAX;
- child = child->next;
+ child = child->next;
}
}
}
init_item_staticeval(child);
}
}
+ /* If an expression is evaluated for a dynamic group, then also
+ * atom-valued parameters need to be evaluated every time. */
+ if ((sel->flags & SEL_DYNAMIC)
+ && (sel->type == SEL_EXPRESSION || sel->type == SEL_MODIFIER)
+ && (child->flags & SEL_ATOMVAL))
+ {
+ child->flags |= SEL_DYNAMIC;
+ child->cdata->flags &= ~SEL_CDATA_STATIC;
+ }
child = child->next;
}
}
while (child)
{
child->cdata->flags &= ~SEL_CDATA_STATICEVAL;
- child = child->next;
+ child = child->next;
}
}
else if (sel->type == SEL_SUBEXPRREF
&& (sel->child->cdata->flags & SEL_CDATA_SIMPLESUBEXPR))
{
- sel->cdata->flags |= SEL_CDATA_SIMPLESUBEXPR;
+ /* See similar condition in init_item_staticeval(). */
+ if ((sel->flags & SEL_ATOMVAL)
+ && (sel->flags & SEL_DYNAMIC)
+ && !(sel->child->flags & SEL_DYNAMIC))
+ {
+ sel->child->cdata->flags |= SEL_CDATA_STATICMULTIEVALSUBEXPR;
+ }
+ else
+ {
+ sel->cdata->flags |= SEL_CDATA_SIMPLESUBEXPR;
+ }
}
/* Process children, but only follow subexpression references if the
* \param[in,out] sc Selection collection data.
*
* The evaluation group of each \ref SEL_ROOT element corresponding to a
- * selection in \p sc is set to NULL. The evaluation grop for \ref SEL_ROOT
+ * selection in \p sc is set to NULL. The evaluation group for \ref SEL_ROOT
* elements corresponding to subexpressions that need full evaluation is set
* to \c sc->gall.
*/
if (root->child->type != SEL_SUBEXPR
|| (root->child->v.type != GROUP_VALUE && !(root->flags & SEL_ATOMVAL)))
{
- gmx_ana_index_set(&root->u.cgrp, -1, 0, root->u.cgrp.name, 0);
+ gmx_ana_index_set(&root->u.cgrp, -1, 0, 0);
}
else if (root->child->cdata->flags & SEL_CDATA_FULLEVAL)
{
- gmx_ana_index_set(&root->u.cgrp, sc->gall.isize, sc->gall.index,
- root->u.cgrp.name, 0);
+ gmx_ana_index_set(&root->u.cgrp, sc->gall.isize, sc->gall.index, 0);
}
root = root->next;
}
*/
static void
mark_subexpr_dynamic(const SelectionTreeElementPointer &sel,
- bool bDynamic)
+ bool bDynamic)
{
if (!bDynamic && !(sel->flags & SEL_DYNAMIC))
{
{
if (sel->child->child->flags & SEL_ALLOCDATA)
{
- sel->flags |= SEL_ALLOCDATA;
+ sel->flags |= SEL_ALLOCDATA;
sel->child->child->flags &= ~SEL_ALLOCDATA;
}
if (sel->child->child->flags & SEL_ALLOCVAL)
{
- sel->flags |= SEL_ALLOCVAL;
- sel->v.nalloc = sel->child->child->v.nalloc;
- sel->child->child->flags &= ~SEL_ALLOCVAL;
+ sel->flags |= SEL_ALLOCVAL;
+ sel->v.nalloc = sel->child->child->v.nalloc;
+ sel->child->child->flags &= ~SEL_ALLOCVAL;
sel->child->child->v.nalloc = -1;
}
}
* */
if (sel->v.type == GROUP_VALUE)
{
- gmx_ana_index_set(&sel->u.cgrp, sel->v.u.g->isize, sel->v.u.g->index, NULL, 0);
+ gmx_ana_index_set(&sel->u.cgrp, sel->v.u.g->isize, sel->v.u.g->index, 0);
}
}
* \returns 0 on success, a non-zero error code on error.
*/
static void
-process_const(gmx_sel_evaluate_t *data,
+process_const(gmx_sel_evaluate_t *data,
const SelectionTreeElementPointer &sel,
- gmx_ana_index_t *g)
+ gmx_ana_index_t *g)
{
if (sel->v.type == GROUP_VALUE)
{
init_method(const SelectionTreeElementPointer &sel, t_topology *top, int isize)
{
/* Find out whether there are any atom-valued parameters */
- bool bAtomVal = false;
+ bool bAtomVal = false;
SelectionTreeElementPointer child = sel->child;
while (child)
{
{
sel->flags |= SEL_METHODINIT;
sel->u.expr.method->init(top, sel->u.expr.method->nparams,
- sel->u.expr.method->param, sel->u.expr.mdata);
+ sel->u.expr.method->param, sel->u.expr.mdata);
}
if (bAtomVal || !(sel->flags & SEL_OUTINIT))
{
else
{
GMX_RELEASE_ASSERT(sel->v.type != POS_VALUE,
- "Output initialization must be provided for "
- "position-valued selection methods");
+ "Output initialization must be provided for "
+ "position-valued selection methods");
GMX_RELEASE_ASSERT(!(sel->flags & SEL_VARNUMVAL),
- "Output initialization must be provided for "
- "SMETH_VARNUMVAL selection methods");
+ "Output initialization must be provided for "
+ "SMETH_VARNUMVAL selection methods");
alloc_selection_data(sel, isize, true);
if ((sel->flags & SEL_DYNAMIC)
&& sel->v.type != GROUP_VALUE && sel->v.type != POS_VALUE)
* reorder_item_static_children() should have been called.
*/
static void
-evaluate_boolean_static_part(gmx_sel_evaluate_t *data,
+evaluate_boolean_static_part(gmx_sel_evaluate_t *data,
const SelectionTreeElementPointer &sel,
- gmx_ana_index_t *g)
+ gmx_ana_index_t *g)
{
/* Find the last static subexpression */
SelectionTreeElementPointer child = sel->child;
init_item_minmax_groups(child);
child->cdata->flags &= ~SEL_CDATA_STATICEVAL;
child->cdata->flags |= sel->cdata->flags & SEL_CDATA_STATICEVAL;
- child->next = next;
+ child->next = next;
// Frees the old static subexpressions.
sel->child = child;
}
{
child->cdata->evaluate = &_gmx_sel_evaluate_static;
/* The cgrp has only been allocated if it originated from an
- * external index group. In that case, we need special handling
- * to preserve the name of the group and to not leak memory.
+ * external index group.
* If cgrp has been set in make_static(), it is not allocated,
* and hence we can overwrite it safely. */
if (child->u.cgrp.nalloc_index > 0)
{
- char *name = child->u.cgrp.name;
gmx_ana_index_copy(&child->u.cgrp, child->v.u.g, false);
gmx_ana_index_squeeze(&child->u.cgrp);
- child->u.cgrp.name = name;
}
else
{
&& sel->child->v.u.g->isize < gmin->isize)
{
GMX_RELEASE_ASSERT(sel->child->type == SEL_CONST,
- "The first child should have already been evaluated "
- "to a constant expression");
+ "The first child should have already been evaluated "
+ "to a constant expression");
gmx_ana_index_reserve(sel->child->v.u.g, gmin->isize);
gmx_ana_index_copy(sel->child->v.u.g, gmin, false);
if (sel->child->u.cgrp.nalloc_index > 0)
{
- /* Keep the name as in evaluate_boolean_static_part(). */
- char *name = sel->child->u.cgrp.name;
gmx_ana_index_reserve(&sel->child->u.cgrp, gmin->isize);
gmx_ana_index_copy(&sel->child->u.cgrp, gmin, false);
- sel->child->u.cgrp.name = name;
}
else
{
GMX_RELEASE_ASSERT(sel->child->u.cgrp.index == sel->child->v.u.g->index,
- "If not allocated, the static group should equal the value");
+ "If not allocated, the static group should equal the value");
sel->child->u.cgrp.isize = sel->child->v.u.g->isize;
}
}
/*! \brief
* Evaluates the static parts of \p sel and analyzes the structure.
- *
+ *
* \param[in] data Evaluation data.
* \param[in,out] sel Selection currently being evaluated.
* \param[in] g Group for which \p sel should be evaluated.
* It does the single most complex task in the compiler: after all elements
* have been processed, the \p gmin and \p gmax fields of \p t_compiler_data
* have been properly initialized, enough memory has been allocated for
- * storing the value of each expression, and the static parts of the
+ * storing the value of each expression, and the static parts of the
* expressions have been evaluated.
* The above is exactly true only for elements other than subexpressions:
* another pass is required for subexpressions that are referred to more than
* once and whose evaluation group is not known in advance.
*/
static void
-analyze_static(gmx_sel_evaluate_t *data,
+analyze_static(gmx_sel_evaluate_t *data,
const SelectionTreeElementPointer &sel,
- gmx_ana_index_t *g)
+ gmx_ana_index_t *g)
{
bool bDoMinMax;
break;
case SEL_SUBEXPR:
- if (sel->cdata->flags & (SEL_CDATA_SIMPLESUBEXPR | SEL_CDATA_FULLEVAL))
+ if (((sel->cdata->flags & SEL_CDATA_SIMPLESUBEXPR) &&
+ !(sel->cdata->flags & SEL_CDATA_STATICMULTIEVALSUBEXPR))
+ || (sel->cdata->flags & SEL_CDATA_FULLEVAL))
{
sel->cdata->evaluate(data, sel, g);
_gmx_selvalue_setstore(&sel->v, sel->child->v.u.ptr);
{
gmx_ana_index_squeeze(sel->cdata->gmin);
gmx_ana_index_squeeze(sel->cdata->gmax);
- sfree(sel->cdata->gmin->name);
- sfree(sel->cdata->gmax->name);
- sel->cdata->gmin->name = NULL;
- sel->cdata->gmax->name = NULL;
}
/* Replace the result of the evaluation */
*/
static void
init_root_item(const SelectionTreeElementPointer &root,
- gmx_ana_index_t *gall)
+ gmx_ana_index_t *gall)
{
const SelectionTreeElementPointer &expr = root->child;
/* Subexpressions with non-static evaluation group should not be
}
/* Set the evaluation group */
- char *name = root->u.cgrp.name;
if (root->evaluate)
{
/* Non-atom-valued non-group expressions don't care about the group, so
if ((expr->flags & SEL_VARNUMVAL)
|| ((expr->flags & SEL_SINGLEVAL) && expr->v.type != GROUP_VALUE))
{
- gmx_ana_index_set(&root->u.cgrp, -1, NULL, NULL, 0);
+ gmx_ana_index_set(&root->u.cgrp, -1, NULL, 0);
}
else if (expr->cdata->gmax->isize == gall->isize)
{
/* Save some memory by only referring to the global group. */
- gmx_ana_index_set(&root->u.cgrp, gall->isize, gall->index, NULL, 0);
+ gmx_ana_index_set(&root->u.cgrp, gall->isize, gall->index, 0);
}
else
{
/* For selections, store the maximum group for
* gmx_ana_selcollection_evaluate_fin() as the value of the root
* element (unused otherwise). */
- if (expr->type != SEL_SUBEXPR && expr->v.u.p->g)
+ if (expr->type != SEL_SUBEXPR && expr->v.u.p->m.mapb.a != NULL)
{
SelectionTreeElementPointer child = expr;
}
if (child->child->flags & SEL_DYNAMIC)
{
+ gmx_ana_index_t g;
+ gmx_ana_index_set(&g, expr->v.u.p->m.mapb.nra, expr->v.u.p->m.mapb.a, 0);
_gmx_selelem_set_vtype(root, GROUP_VALUE);
root->flags |= (SEL_ALLOCVAL | SEL_ALLOCDATA);
_gmx_selvalue_reserve(&root->v, 1);
- gmx_ana_index_copy(root->v.u.g, expr->v.u.p->g, true);
+ gmx_ana_index_copy(root->v.u.g, &g, true);
}
}
}
{
gmx_ana_index_clear(&root->u.cgrp);
}
- root->u.cgrp.name = name;
+}
+
+
+/********************************************************************
+ * REQUIRED ATOMS ANALYSIS
+ ********************************************************************/
+
+/*! \brief
+ * Finds the highest atom index required to evaluate a selection subtree.
+ *
+ * \param[in] sel Root of the selection subtree to process.
+ * \param[in,out] maxAtomIndex The highest atom index required to evaluate the
+ * subtree. The existing value is never decreased, so multiple calls with
+ * the same parameter will compute the maximum over several subtrees.
+ *
+ * For evaluation that starts from a \ref SEL_ROOT element with a fixed group,
+ * children will never extend the evaluation group except for method parameter
+ * evaluation (which have their own root element), so it is sufficient to check
+ * the root. However, children of \ref SEL_EXPRESSION elements (i.e., the
+ * method parameters) may have been independently evaluated to a static group
+ * that no longer has a separate root, so those need to be checked as well.
+ *
+ * Position calculations are not considered here, but are analyzed through the
+ * position calculation collection in the main compilation method.
+ */
+static void
+init_required_atoms(const SelectionTreeElementPointer &sel, int *maxAtomIndex)
+{
+ // Process children.
+ if (sel->type != SEL_SUBEXPRREF)
+ {
+ SelectionTreeElementPointer child = sel->child;
+ while (child)
+ {
+ init_required_atoms(child, maxAtomIndex);
+ child = child->next;
+ }
+ }
+
+ if (sel->type == SEL_ROOT
+ || (sel->type == SEL_CONST && sel->v.type == GROUP_VALUE))
+ {
+ if (sel->u.cgrp.isize > 0)
+ {
+ *maxAtomIndex =
+ std::max(*maxAtomIndex, gmx_ana_index_get_max_index(&sel->u.cgrp));
+ }
+ }
}
&& (sel->cdata->flags & SEL_CDATA_STATICEVAL)
&& !(sel->cdata->flags & SEL_CDATA_FULLEVAL))
{
- char *name;
-
/* We need to free memory allocated for the group, because it is no
* longer needed (and would be lost on next call to the evaluation
- * function). But we need to preserve the name. */
- name = sel->u.cgrp.name;
+ * function). */
gmx_ana_index_deinit(&sel->u.cgrp);
- sel->u.cgrp.name = name;
- sel->evaluate = &_gmx_sel_evaluate_subexpr_staticeval;
+ sel->evaluate = &_gmx_sel_evaluate_subexpr_staticeval;
sel->cdata->evaluate = sel->evaluate;
sel->child->freeValues();
{
if (sel->child->child->flags & SEL_ALLOCVAL)
{
- sel->flags |= SEL_ALLOCVAL;
- sel->flags |= (sel->child->child->flags & SEL_ALLOCDATA);
- sel->v.nalloc = sel->child->child->v.nalloc;
- sel->child->child->flags &= ~(SEL_ALLOCVAL | SEL_ALLOCDATA);
+ sel->flags |= SEL_ALLOCVAL;
+ sel->flags |= (sel->child->child->flags & SEL_ALLOCDATA);
+ sel->v.nalloc = sel->child->child->v.nalloc;
+ sel->child->child->flags &= ~(SEL_ALLOCVAL | SEL_ALLOCDATA);
sel->child->child->v.nalloc = -1;
}
}
&& !(sel->cdata->flags & SEL_CDATA_SIMPLESUBEXPR)
&& (sel->cdata->flags & SEL_CDATA_FULLEVAL))
{
- sel->flags |= SEL_ALLOCVAL;
- sel->flags |= (sel->child->flags & SEL_ALLOCDATA);
- sel->v.nalloc = sel->child->v.nalloc;
- sel->child->flags &= ~(SEL_ALLOCVAL | SEL_ALLOCDATA);
+ sel->flags |= SEL_ALLOCVAL;
+ sel->flags |= (sel->child->flags & SEL_ALLOCDATA);
+ sel->v.nalloc = sel->child->v.nalloc;
+ sel->child->flags &= ~(SEL_ALLOCVAL | SEL_ALLOCDATA);
sel->child->v.nalloc = -1;
}
+
+ /* For static subexpressions with a dynamic evaluation group, there is
+ * no need to evaluate them again, as the SEL_SUBEXPRREF takes care of
+ * everything during evaluation. */
+ if (sel->type == SEL_SUBEXPR
+ && (sel->cdata->flags & SEL_CDATA_SIMPLESUBEXPR)
+ && (sel->cdata->flags & SEL_CDATA_STATICMULTIEVALSUBEXPR))
+ {
+ sel->evaluate = NULL;
+ sel->cdata->evaluate = NULL;
+ }
}
}
if (!sel->u.expr.pc)
{
- cflags |= flags;
+ cflags |= flags;
sel->u.expr.pc = pcc->createCalculation(type, cflags);
}
else
gmx_ana_poscalc_set_flags(sel->u.expr.pc, cflags);
}
gmx_ana_poscalc_set_maxindex(sel->u.expr.pc, sel->cdata->gmax);
- snew(sel->u.expr.pos, 1);
+ sel->u.expr.pos = new gmx_ana_pos_t();
gmx_ana_poscalc_init_pos(sel->u.expr.pc, sel->u.expr.pos);
}
}
void
SelectionCompiler::compile(SelectionCollection *coll)
{
- gmx_ana_selcollection_t *sc = &coll->impl_->sc_;
- gmx_sel_evaluate_t evaldata;
+ gmx_ana_selcollection_t *sc = &coll->impl_->sc_;
+ gmx_sel_evaluate_t evaldata;
SelectionTreeElementPointer item;
- e_poscalc_t post;
- size_t i;
- int flags;
- bool bDebug = (coll->impl_->debugLevel_ >= 2
- && coll->impl_->debugLevel_ != 3);
+ e_poscalc_t post;
+ size_t i;
+ int flags;
+ bool bDebug = (coll->impl_->debugLevel_ >= 2
+ && coll->impl_->debugLevel_ != 3);
/* FIXME: Clean up the collection on exceptions */
/* Initialize the evaluation callbacks and process the tree structure
* to conform to the expectations of the callback functions. */
/* Also, initialize and allocate the compiler data structure */
+ // TODO: Processing the tree in reverse root order would be better,
+ // as it would make dependency handling easier (all subexpression
+ // references would be processed before the actual subexpression) and
+ // could remove the need for most of these extra loops.
item = sc->root;
while (item)
{
optimize_arithmetic_expressions(item);
/* Initialize the compiler data */
init_item_compilerdata(item);
+ item = item->next;
+ }
+ // Initialize the static evaluation compiler flags.
+ // Requires the FULLEVAL compiler flag for the whole tree.
+ item = sc->root;
+ while (item)
+ {
init_item_staticeval(item);
init_item_subexpr_refcount(item);
item = item->next;
coll->printTree(stderr, false);
}
- /* Initialize evaluation groups, position calculations for methods, perform
- * some final optimization, and free the memory allocated for the
- * compilation. */
+ // Initialize evaluation groups, maximum atom index needed for evaluation,
+ // position calculations for methods, perform some final optimization, and
+ // free the memory allocated for the compilation.
+ coll->impl_->maxAtomIndex_ = 0;
/* By default, use whole residues/molecules. */
flags = POS_COMPLWHOLE;
PositionCalculationCollection::typeFromEnum(coll->impl_->rpost_.c_str(),
{
init_root_item(item, &sc->gall);
postprocess_item_subexpressions(item);
+ init_required_atoms(item, &coll->impl_->maxAtomIndex_);
init_item_comg(item, &sc->pcc, post, flags);
free_item_compilerdata(item);
item = item->next;
}
+ coll->impl_->maxAtomIndex_ =
+ std::max(coll->impl_->maxAtomIndex_,
+ sc->pcc.getHighestRequiredAtomIndex());
/* Allocate memory for the evaluation memory pool. */
_gmx_sel_mempool_reserve(sc->mempool, 0);