void
gmx_ana_pos_reserve(gmx_ana_pos_t *pos, int n, int isize)
{
+ GMX_RELEASE_ASSERT(n >= 0, "Invalid position allocation count");
+ // Always reserve at least one entry to make NULL checks against pos->x
+ // and gmx_ana_pos_reserve_velocities/forces() work as expected in the case
+ // that there are actually no positions.
+ if (n == 0)
+ {
+ n = 1;
+ }
if (pos->nalloc_x < n)
{
pos->nalloc_x = n;
* \param[in,out] pos Position data structure.
*
* Currently, this function can only be called after gmx_ana_pos_reserve()
- * has been called at least once with a \p n > 0.
+ * has been called at least once with a \p n >= 0.
*/
void
gmx_ana_pos_reserve_velocities(gmx_ana_pos_t *pos)
* \param[in,out] pos Position data structure.
*
* Currently, this function can only be called after gmx_ana_pos_reserve()
- * has been called at least once with a \p n > 0.
+ * has been called at least once with a \p n >= 0.
*/
void
gmx_ana_pos_reserve_forces(gmx_ana_pos_t *pos)
* 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
{
return ConstArrayRef<int>(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_; }
bool isCoveredFractionDynamic() const { return data().isCoveredFractionDynamic(); }
//! Returns the covered fraction for the current frame.
real coveredFraction() const { return data().coveredFraction_; }
+
/*! \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.
/*! \brief
* Request velocity evaluation for output positions.
*
- * Note that even with this flag set, velocities may not be available,
- * in which case Selection::hasVelocities() returns false.
+ * \see Selection::setEvaluateVelocities()
*/
MyClass &evaluateVelocities()
{ selectionFlags_.set(efSelection_EvaluateVelocities); return me(); }
/*! \brief
* Request force evaluation for output positions.
*
- * Note that even with this flag set, forces may not be available,
- * in which case Selection::hasForces() returns false.
+ * \see Selection::setEvaluateForces()
*/
MyClass &evaluateForces()
{ selectionFlags_.set(efSelection_EvaluateForces); return me(); }
*
* Does not throw.
*
- * \see SelectionOption::evaluateVelocities()
+ * \see Selection::setEvaluateVelocities()
*/
void setEvaluateVelocities(bool bEnabled);
/*! \brief
*
* Does not throw.
*
- * \see SelectionOption::evaluateForces()
+ * \see Selection::setEvaluateForces()
*/
void setEvaluateForces(bool bEnabled);
/*! \brief
EXPECT_NO_THROW(sc_.compile());
}
+TEST_F(SelectionCollectionTest, HandlesVelocityAndForceRequests)
+{
+ ASSERT_NO_THROW(sel_ = sc_.parseFromString("atomnr 1 to 10; none"));
+ ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
+ ASSERT_EQ(2U, sel_.size());
+ ASSERT_NO_THROW(sel_[0].setEvaluateVelocities(true));
+ ASSERT_NO_THROW(sel_[1].setEvaluateVelocities(true));
+ ASSERT_NO_THROW(sel_[0].setEvaluateForces(true));
+ ASSERT_NO_THROW(sel_[1].setEvaluateForces(true));
+ ASSERT_NO_THROW(sc_.compile());
+ EXPECT_TRUE(sel_[0].hasVelocities());
+ EXPECT_TRUE(sel_[1].hasVelocities());
+ EXPECT_TRUE(sel_[0].hasForces());
+ EXPECT_TRUE(sel_[1].hasForces());
+}
+
TEST_F(SelectionCollectionTest, ParsesSelectionsFromFile)
{
ASSERT_NO_THROW(sel_ = sc_.parseFromFile(