/*
* This file is part of the GROMACS molecular simulation package.
*
- * Copyright (c) 2009,2010,2011,2012, by the GROMACS development team, led by
- * David van der Spoel, Berk Hess, Erik Lindahl, and including many
- * others, as listed in the AUTHORS file in the top-level source
- * directory and at http://www.gromacs.org.
+ * 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.
*
* GROMACS is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* \author Teemu Murtola <teemu.murtola@gmail.com>
* \ingroup module_selection
*/
-#include <cstring>
+#include "gmxpre.h"
-#include "gromacs/legacyheaders/smalloc.h"
+#include "selelem.h"
+
+#include <cstring>
#include "gromacs/selection/indexutil.h"
-#include "gromacs/selection/poscalc.h"
#include "gromacs/selection/position.h"
-#include "gromacs/selection/selmethod.h"
#include "gromacs/utility/exceptions.h"
#include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/smalloc.h"
+#include "gromacs/utility/stringutil.h"
#include "keywords.h"
#include "mempool.h"
-#include "selelem.h"
+#include "poscalc.h"
+#include "selmethod.h"
/*!
* \param[in] sel Selection for which the string is requested
const char *
_gmx_selelem_type_str(const gmx::SelectionTreeElement &sel)
{
+ const char *p = NULL;
switch (sel.type)
{
- case SEL_CONST: return "CONST";
- case SEL_EXPRESSION: return "EXPR";
- case SEL_BOOLEAN: return "BOOL";
- case SEL_ARITHMETIC: return "ARITH";
- case SEL_ROOT: return "ROOT";
- case SEL_SUBEXPR: return "SUBEXPR";
- case SEL_SUBEXPRREF: return "REF";
- case SEL_GROUPREF: return "GROUPREF";
- case SEL_MODIFIER: return "MODIFIER";
- }
- return NULL;
+ case SEL_CONST: p = "CONST"; break;
+ case SEL_EXPRESSION: p = "EXPR"; break;
+ case SEL_BOOLEAN: p = "BOOL"; break;
+ case SEL_ARITHMETIC: p = "ARITH"; break;
+ case SEL_ROOT: p = "ROOT"; break;
+ case SEL_SUBEXPR: p = "SUBEXPR"; break;
+ case SEL_SUBEXPRREF: p = "REF"; break;
+ case SEL_GROUPREF: p = "GROUPREF"; break;
+ case SEL_MODIFIER: p = "MODIFIER"; break;
+ // No default clause so we intentionally get compiler errors
+ // if new selection choices are added later.
+ }
+ return p;
}
/*!
const char *
_gmx_sel_value_type_str(const gmx_ana_selvalue_t *val)
{
+ const char *p = NULL;
switch (val->type)
{
- case NO_VALUE: return "NONE";
- case INT_VALUE: return "INT";
- case REAL_VALUE: return "REAL";
- case STR_VALUE: return "STR";
- case POS_VALUE: return "VEC";
- case GROUP_VALUE: return "GROUP";
+ case NO_VALUE: p = "NONE"; break;
+ case INT_VALUE: p = "INT"; break;
+ case REAL_VALUE: p = "REAL"; break;
+ case STR_VALUE: p = "STR"; break;
+ case POS_VALUE: p = "VEC"; break;
+ case GROUP_VALUE: p = "GROUP"; break;
+ // No default clause so we intentionally get compiler errors
+ // if new selection choices are added later.
}
- return NULL;
+ return p;
}
/*! \copydoc _gmx_selelem_type_str() */
const char *
_gmx_selelem_boolean_type_str(const gmx::SelectionTreeElement &sel)
{
+ const char *p = NULL;
switch (sel.u.boolt)
{
- case BOOL_NOT: return "NOT"; break;
- case BOOL_AND: return "AND"; break;
- case BOOL_OR: return "OR"; break;
- case BOOL_XOR: return "XOR"; break;
+ case BOOL_NOT: p = "NOT"; break;
+ case BOOL_AND: p = "AND"; break;
+ case BOOL_OR: p = "OR"; break;
+ case BOOL_XOR: p = "XOR"; break;
+ // No default clause so we intentionally get compiler errors
+ // if new selection choices are added later.
}
- return NULL;
+ return p;
}
sfree(v.u.s[i]);
}
break;
- case POS_VALUE:
- for (int i = 0; i < n; ++i)
- {
- gmx_ana_pos_deinit(&v.u.p[i]);
- }
- break;
case GROUP_VALUE:
for (int i = 0; i < n; ++i)
{
break;
}
}
- if (flags & SEL_ALLOCVAL)
+ if (v.nalloc > 0)
{
- sfree(v.u.ptr);
+ if (v.type == POS_VALUE)
+ {
+ delete [] v.u.p;
+ }
+ else
+ {
+ sfree(v.u.ptr);
+ }
}
_gmx_selvalue_setstore(&v, NULL);
if (type == SEL_SUBEXPRREF && u.param)
u.expr.mdata = NULL;
u.expr.method = NULL;
/* Free position data */
- if (u.expr.pos)
- {
- gmx_ana_pos_free(u.expr.pos);
- u.expr.pos = NULL;
- }
+ delete u.expr.pos;
+ u.expr.pos = NULL;
/* Free position calculation data */
if (u.expr.pc)
{
}
}
+void SelectionTreeElement::fillNameIfMissing(const char *selectionText)
+{
+ GMX_RELEASE_ASSERT(type == SEL_ROOT,
+ "Should not be called for non-root elements");
+ if (name().empty())
+ {
+ // Check whether the actual selection given was from an external group,
+ // and if so, use the name of the external group.
+ SelectionTreeElementPointer child = this->child;
+ while (child->type == SEL_MODIFIER)
+ {
+ if (!child->child || child->child->type != SEL_SUBEXPRREF
+ || !child->child->child)
+ {
+ break;
+ }
+ child = child->child->child;
+ }
+ if (child->type == SEL_EXPRESSION
+ && child->child && child->child->type == SEL_SUBEXPRREF
+ && child->child->child)
+ {
+ if (child->child->child->type == SEL_CONST
+ && child->child->child->v.type == GROUP_VALUE)
+ {
+ setName(child->child->child->name());
+ return;
+ }
+ // If the group reference is still unresolved, leave the name empty
+ // and fill it later.
+ if (child->child->child->type == SEL_GROUPREF)
+ {
+ return;
+ }
+ }
+ // If there still is no name, use the selection string.
+ setName(selectionText);
+ }
+}
+
+void SelectionTreeElement::checkUnsortedAtoms(
+ bool bUnsortedAllowed, ExceptionInitializer *errors) const
+{
+ const bool bUnsortedSupported
+ = (type == SEL_CONST && v.type == GROUP_VALUE)
+ || type == SEL_ROOT || type == SEL_SUBEXPR || type == SEL_SUBEXPRREF
+ // TODO: Consolidate.
+ || type == SEL_MODIFIER
+ || (type == SEL_EXPRESSION && (u.expr.method->flags & SMETH_ALLOW_UNSORTED));
+
+ // TODO: For some complicated selections, this may result in the same
+ // index group reference being flagged as an error multiple times for the
+ // same selection.
+ SelectionTreeElementPointer child = this->child;
+ while (child)
+ {
+ child->checkUnsortedAtoms(bUnsortedAllowed && bUnsortedSupported,
+ errors);
+ child = child->next;
+ }
+
+ // The logic here is simplified by the fact that only constant groups can
+ // currently be the root cause of SEL_UNSORTED being set, so only those
+ // need to be considered in triggering the error.
+ if (!bUnsortedAllowed && (flags & SEL_UNSORTED)
+ && type == SEL_CONST && v.type == GROUP_VALUE)
+ {
+ std::string message = formatString(
+ "Group '%s' cannot be used in selections except "
+ "as a full value of the selection, "
+ "because atom indices in it are not sorted and/or "
+ "it contains duplicate atoms.",
+ name().c_str());
+ errors->addNested(InconsistentInputError(message));
+ }
+}
+
+void SelectionTreeElement::resolveIndexGroupReference(
+ gmx_ana_indexgrps_t *grps, int natoms)
+{
+ GMX_RELEASE_ASSERT(type == SEL_GROUPREF,
+ "Should only be called for index group reference elements");
+ if (grps == NULL)
+ {
+ std::string message = formatString(
+ "Cannot match '%s', because index groups are not available.",
+ name().c_str());
+ GMX_THROW(InconsistentInputError(message));
+ }
+
+ gmx_ana_index_t foundGroup;
+ std::string foundName;
+ if (u.gref.name != NULL)
+ {
+ if (!gmx_ana_indexgrps_find(&foundGroup, &foundName, grps, u.gref.name))
+ {
+ std::string message = formatString(
+ "Cannot match '%s', because no such index group can be found.",
+ name().c_str());
+ GMX_THROW(InconsistentInputError(message));
+ }
+ }
+ else
+ {
+ if (!gmx_ana_indexgrps_extract(&foundGroup, &foundName, grps, u.gref.id))
+ {
+ std::string message = formatString(
+ "Cannot match '%s', because no such index group can be found.",
+ name().c_str());
+ GMX_THROW(InconsistentInputError(message));
+ }
+ }
+
+ if (!gmx_ana_index_check_sorted(&foundGroup))
+ {
+ flags |= SEL_UNSORTED;
+ }
+
+ sfree(u.gref.name);
+ type = SEL_CONST;
+ gmx_ana_index_set(&u.cgrp, foundGroup.isize, foundGroup.index,
+ foundGroup.nalloc_index);
+ setName(foundName);
+
+ if (natoms > 0)
+ {
+ checkIndexGroup(natoms);
+ }
+}
+
+void SelectionTreeElement::checkIndexGroup(int natoms)
+{
+ GMX_RELEASE_ASSERT(type == SEL_CONST && v.type == GROUP_VALUE,
+ "Should only be called for index group elements");
+ if (!gmx_ana_index_check_range(&u.cgrp, natoms))
+ {
+ std::string message = formatString(
+ "Group '%s' cannot be used in selections, because it "
+ "contains negative atom indices and/or references atoms "
+ "not present (largest allowed atom index is %d).",
+ name().c_str(), natoms);
+ GMX_THROW(InconsistentInputError(message));
+ }
+}
+
} // namespace gmx
/*!
}
else if (param->val.type == POS_VALUE)
{
- for (j = 0; j < param->val.nr; ++j)
+ if (param->val.nalloc > 0)
{
- gmx_ana_pos_deinit(¶m->val.u.p[j]);
+ delete[] param->val.u.p;
+ _gmx_selvalue_setstore(¶m->val, NULL);
}
}