/*
+ * 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.
*/
/*! \file
* \brief
* Declares gmx::Selection and supporting classes.
*
- * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
* \inpublicapi
* \ingroup module_selection
*/
#include <string>
#include <vector>
-#include "../legacyheaders/typedefs.h"
+#include "gromacs/selection/position.h"
+#include "gromacs/selection/selectionenums.h"
+#include "gromacs/utility/arrayref.h"
+#include "gromacs/utility/common.h"
+#include "gromacs/utility/gmxassert.h"
-#include "../utility/arrayref.h"
-#include "../utility/common.h"
-#include "../utility/gmxassert.h"
-
-#include "position.h"
-#include "indexutil.h"
-#include "selectionenums.h"
+struct t_topology;
namespace gmx
{
class SelectionOptionStorage;
class SelectionTreeElement;
+class AnalysisNeighborhoodPositions;
class Selection;
class SelectionPosition;
namespace internal
{
-/*! \internal \brief
+/*! \internal
+ * \brief
* Internal data for a single selection.
*
* This class is internal to the selection module, but resides in a public
SelectionData(SelectionTreeElement *elem, const char *selstr);
~SelectionData();
+ //! Returns the name for this selection.
+ const char *name() const { return name_.c_str(); }
//! Returns the string that was parsed to produce this selection.
const char *selectionText() const { return selectionText_.c_str(); }
//! Returns true if the size of the selection (posCount()) is dynamic.
bool isDynamic() const { return bDynamic_; }
+ //! Returns the type of positions in the selection.
+ e_index_t type() const { return rawPositions_.m.type; }
+ //! Returns true if the selection only contains positions with a single atom each.
+ bool hasOnlyAtoms() const { return type() == INDEX_ATOM; }
+
//! Number of positions in the selection.
- int posCount() const { return rawPositions_.nr; }
+ int posCount() const { return rawPositions_.count(); }
//! Returns the root of the evaluation tree for this selection.
SelectionTreeElement &rootElement() { return rootElement_; }
//! \copydoc Selection::initCoveredFraction()
bool initCoveredFraction(e_coverfrac_t type);
+ /*! \brief
+ * Updates the name of the selection if missing.
+ *
+ * \throws std::bad_alloc if out of memory.
+ *
+ * If selections get their value from a group reference that cannot be
+ * resolved during parsing, the name is final only after group
+ * references have been resolved.
+ *
+ * This function is called by SelectionCollection::setIndexGroups().
+ */
+ void refreshName();
/*! \brief
* Computes total masses and charges for all selection positions.
*
* any time after the selection has been parsed, and type() can be accessed
* after the selection has been compiled.
*
+ * There are a few methods that can be used to change the behavior of the
+ * selection. setEvaluateVelocities() and setEvaluateForces() can be called
+ * before the selection is compiled to request evaluation of velocities and/or
+ * forces in addition to coordinates.
+ *
* Each selection is made of a set of positions. Each position has associated
* coordinates, and possibly velocities and forces if they have been requested
* and are available. It also has a set of atoms associated with it; typically
*
* Any attempt to call methods in the object before a selection is
* assigned results in undefined behavior.
+ * isValid() returns `false` for the selection until it is initialized.
*/
Selection() : sel_(NULL) {}
/*! \brief
*/
explicit Selection(internal::SelectionData *sel) : sel_(sel) {}
+ //! Returns whether the selection object is initialized.
+ bool isValid() const { return sel_ != NULL; }
+
+ //! Returns whether two selection objects wrap the same selection.
+ bool operator==(const Selection &other) const
+ {
+ return sel_ == other.sel_;
+ }
+ //! Returns whether two selection objects wrap different selections.
+ bool operator!=(const Selection &other) const
+ {
+ return !operator==(other);
+ }
+
//! Returns the name of the selection.
- const char *name() const { return data().name_.c_str(); }
+ const char *name() const { return data().name(); }
//! Returns the string that was parsed to produce this selection.
const char *selectionText() const { return data().selectionText(); }
//! Returns true if the size of the selection (posCount()) is dynamic.
bool isDynamic() const { return data().isDynamic(); }
//! Returns the type of positions in the selection.
- e_index_t type() const { return data().rawPositions_.m.type; }
+ e_index_t type() const { return data().type(); }
+ //! Returns true if the selection only contains positions with a single atom each.
+ bool hasOnlyAtoms() const { return data().hasOnlyAtoms(); }
//! Total number of atoms in the selection.
int atomCount() const
{
- return data().rawPositions_.g != NULL ? data().rawPositions_.g->isize : 0;
+ return data().rawPositions_.m.mapb.nra;
}
//! Returns atom indices of all atoms in the selection.
ConstArrayRef<int> atomIndices() const
{
- if (data().rawPositions_.g == NULL)
- {
- return ConstArrayRef<int>();
- }
- return ConstArrayRef<int>(data().rawPositions_.g->index,
- data().rawPositions_.g->isize);
+ return constArrayRefFromArray(sel_->rawPositions_.m.mapb.a,
+ sel_->rawPositions_.m.mapb.nra);
}
//! Number of positions in the selection.
int posCount() const { return data().posCount(); }
//! Returns coordinates for this selection as a continuous array.
ConstArrayRef<rvec> coordinates() const
{
- return ConstArrayRef<rvec>(data().rawPositions_.x, posCount());
+ return constArrayRefFromArray(data().rawPositions_.x, posCount());
}
//! Returns whether velocities are available for this selection.
bool hasVelocities() const { return data().rawPositions_.v != NULL; }
ConstArrayRef<rvec> velocities() const
{
GMX_ASSERT(hasVelocities(), "Velocities accessed, but unavailable");
- return ConstArrayRef<rvec>(data().rawPositions_.v, posCount());
+ return constArrayRefFromArray(data().rawPositions_.v, posCount());
}
//! Returns whether forces are available for this selection.
bool hasForces() const { return sel_->rawPositions_.f != NULL; }
ConstArrayRef<rvec> forces() const
{
GMX_ASSERT(hasForces(), "Forces accessed, but unavailable");
- return ConstArrayRef<rvec>(data().rawPositions_.f, posCount());
+ return constArrayRefFromArray(data().rawPositions_.f, posCount());
}
//! Returns masses for this selection as a continuous array.
ConstArrayRef<real> masses() const
// (and thus the masses and charges are fixed).
GMX_ASSERT(data().posMass_.size() >= static_cast<size_t>(posCount()),
"Internal inconsistency");
- return ConstArrayRef<real>(data().posMass_.begin(),
- data().posMass_.begin() + posCount());
+ return constArrayRefFromVector<real>(data().posMass_.begin(),
+ data().posMass_.begin() + posCount());
}
//! Returns charges for this selection as a continuous array.
ConstArrayRef<real> charges() const
// (and thus the masses and charges are fixed).
GMX_ASSERT(data().posCharge_.size() >= static_cast<size_t>(posCount()),
"Internal inconsistency");
- return ConstArrayRef<real>(data().posCharge_.begin(),
- data().posCharge_.begin() + posCount());
+ return constArrayRefFromVector<real>(data().posCharge_.begin(),
+ data().posCharge_.begin() + posCount());
}
/*! \brief
* Returns reference IDs for this selection as a continuous array.
*/
ConstArrayRef<int> refIds() const
{
- return ConstArrayRef<int>(data().rawPositions_.m.refid, posCount());
+ return constArrayRefFromArray(data().rawPositions_.m.refid, posCount());
}
/*! \brief
* Returns mapped IDs for this selection as a continuous array.
*/
ConstArrayRef<int> mappedIds() const
{
- return ConstArrayRef<int>(data().rawPositions_.m.mapid, posCount());
+ return constArrayRefFromArray(data().rawPositions_.m.mapid, posCount());
}
- /*! \brief
- * Sets the ID for the \p i'th position for use with
- * SelectionPosition::mappedId().
- *
- * \param[in] i Zero-based index
- * \param[in] id Identifier to set.
- *
- * This method is not part of SelectionPosition because that interface
- * only provides access to const data by design.
- *
- * This method can only be called after compilation, before the
- * selection has been evaluated for any frame.
- *
- * \see SelectionPosition::mappedId()
- */
- void setOriginalId(int i, int id) { data().rawPositions_.m.orgid[i] = id; }
-
- //! Deprecated method for direct access to position data.
- const gmx_ana_pos_t *positions() const { return &data().rawPositions_; }
//! Returns whether the covered fraction can change between frames.
bool isCoveredFractionDynamic() const { return data().isCoveredFractionDynamic(); }
//! Returns the covered fraction for the current frame.
real coveredFraction() const { return data().coveredFraction_; }
+
+ /*! \brief
+ * Allows passing a selection directly to neighborhood searching.
+ *
+ * When initialized this way, AnalysisNeighborhoodPair objects return
+ * indices that can be used to index the selection positions with
+ * position().
+ *
+ * Works exactly like if AnalysisNeighborhoodPositions had a
+ * constructor taking a Selection object as a parameter.
+ * See AnalysisNeighborhoodPositions for rationale and additional
+ * discussion.
+ */
+ operator AnalysisNeighborhoodPositions() const;
+
/*! \brief
* Initializes information about covered fractions.
*
{
return data().initCoveredFraction(type);
}
+ /*! \brief
+ * Sets whether this selection evaluates velocities for positions.
+ *
+ * \param[in] bEnabled If true, velocities are evaluated.
+ *
+ * If you request the evaluation, but then evaluate the selection for
+ * a frame that does not contain velocity information, results are
+ * undefined.
+ *
+ * \todo
+ * Implement it such that in the above case, hasVelocities() will
+ * return false for such frames.
+ *
+ * Does not throw.
+ */
+ void setEvaluateVelocities(bool bEnabled)
+ {
+ data().flags_.set(efSelection_EvaluateVelocities, bEnabled);
+ }
+ /*! \brief
+ * Sets whether this selection evaluates forces for positions.
+ *
+ * \param[in] bEnabled If true, forces are evaluated.
+ *
+ * If you request the evaluation, but then evaluate the selection for
+ * a frame that does not contain force information, results are
+ * undefined.
+ *
+ * Does not throw.
+ */
+ void setEvaluateForces(bool bEnabled)
+ {
+ data().flags_.set(efSelection_EvaluateForces, bEnabled);
+ }
+
+ /*! \brief
+ * Sets the ID for the \p i'th position for use with
+ * SelectionPosition::mappedId().
+ *
+ * \param[in] i Zero-based index
+ * \param[in] id Identifier to set.
+ *
+ * This method is not part of SelectionPosition because that interface
+ * only provides access to const data by design.
+ *
+ * This method can only be called after compilation, before the
+ * selection has been evaluated for any frame.
+ *
+ * \see SelectionPosition::mappedId()
+ */
+ void setOriginalId(int i, int id) { data().rawPositions_.m.orgid[i] = id; }
/*! \brief
* Prints out one-line description of the selection.
*
* Currently always returns the same as Selection::type().
*/
- e_index_t type() const { return sel_->rawPositions_.m.type; }
+ e_index_t type() const { return sel_->type(); }
//! Returns coordinates for this position.
const rvec &x() const
{
//! Return atom indices that make up this position.
ConstArrayRef<int> atomIndices() const
{
- if (sel_->rawPositions_.g == NULL)
+ const int *atoms = sel_->rawPositions_.m.mapb.a;
+ if (atoms == NULL)
{
return ConstArrayRef<int>();
}
- int first = sel_->rawPositions_.m.mapb.index[i_];
- return ConstArrayRef<int>(&sel_->rawPositions_.g->index[first],
- atomCount());
+ const int first = sel_->rawPositions_.m.mapb.index[i_];
+ return constArrayRefFromArray(&atoms[first], atomCount());
}
/*! \brief
* Returns whether this position is selected in the current frame.
return sel_->rawPositions_.m.mapid[i_];
}
+ /*! \brief
+ * Allows passing a selection position directly to neighborhood searching.
+ *
+ * When initialized this way, AnalysisNeighborhoodPair objects return
+ * the index that can be used to access this position using
+ * Selection::position().
+ *
+ * Works exactly like if AnalysisNeighborhoodPositions had a
+ * constructor taking a SelectionPosition object as a parameter.
+ * See AnalysisNeighborhoodPositions for rationale and additional
+ * discussion.
+ */
+ operator AnalysisNeighborhoodPositions() const;
+
private:
const internal::SelectionData *sel_;
int i_;