{
nb_.setCutoff(cutoff_);
- data_.setColumnCount(sel_.size());
+ data_.setColumnCount(0, sel_.size());
avem_.reset(new AnalysisDataAverageModule());
data_.addModule(avem_);
Impl();
+ //! Returns whether any data set has more than one column.
+ bool isMultiColumn() const;
+
+ /*! \brief
+ * Checks whether a module is compatible with the data properties.
+ *
+ * \param[in] module Module to check.
+ * \throws APIError if \p module is not compatible with the data.
+ *
+ * Does not check the actual data (e.g., missing values), but only the
+ * dimensionality and other preset properties of the data.
+ */
+ void checkModuleProperties(const AnalysisDataModuleInterface &module) const;
+
/*! \brief
* Present data already added to the data object to a module.
*
* \param[in] data Data object to read data from.
* \param[in] module Module to present the data to.
- * \throws APIError if \p module is not compatible with the data
- * object.
+ * \throws APIError if \p module is not compatible with the data.
* \throws APIError if all data is not available through
* getDataFrame().
* \throws unspecified Any exception thrown by \p module in its data
void presentData(AbstractAnalysisData *data,
AnalysisDataModuleInterface *module);
+ //! Column counts for each data set in the data.
+ std::vector<int> columnCounts_;
+ //! Whether the data is multipoint.
+ bool bMultipoint_;
//! List of modules added to the data.
ModuleList modules_;
//! true if all modules support missing data.
};
AbstractAnalysisData::Impl::Impl()
- : bAllowMissing_(true), bDataStart_(false), bInData_(false), bInFrame_(false),
+ : bMultipoint_(false), bAllowMissing_(true),
+ bDataStart_(false), bInData_(false), bInFrame_(false),
currIndex_(-1), nframes_(0)
{
+ columnCounts_.push_back(0);
+}
+
+bool
+AbstractAnalysisData::Impl::isMultiColumn() const
+{
+ std::vector<int>::const_iterator i;
+ for (i = columnCounts_.begin(); i != columnCounts_.end(); ++i)
+ {
+ if (*i > 1)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+//! Helper macro for testing module flags.
+#define TEST_MODULE_FLAG(flags, flagname) \
+ ((flags) & AnalysisDataModuleInterface::flagname)
+void
+AbstractAnalysisData::Impl::checkModuleProperties(
+ const AnalysisDataModuleInterface &module) const
+{
+ const int flags = module.flags();
+ if ((!TEST_MODULE_FLAG(flags, efAllowMulticolumn) && isMultiColumn()) ||
+ (!TEST_MODULE_FLAG(flags, efAllowMultipoint) && bMultipoint_) ||
+ ( TEST_MODULE_FLAG(flags, efOnlyMultipoint) && !bMultipoint_) ||
+ (!TEST_MODULE_FLAG(flags, efAllowMultipleDataSets)
+ && columnCounts_.size() > 1U))
+ {
+ GMX_THROW(APIError("Data module not compatible with data object properties"));
+ }
}
+#undef TEST_MODULE_FLAGS
void
AbstractAnalysisData::Impl::presentData(AbstractAnalysisData *data,
*/
/*! \cond libapi */
AbstractAnalysisData::AbstractAnalysisData()
- : impl_(new Impl()), columnCount_(0), bMultiPoint_(false)
+ : impl_(new Impl())
{
}
//! \endcond
{
}
+bool
+AbstractAnalysisData::isMultipoint() const
+{
+ return impl_->bMultipoint_;
+}
+
+int
+AbstractAnalysisData::dataSetCount() const
+{
+ return impl_->columnCounts_.size();
+}
+
+int
+AbstractAnalysisData::columnCount(int dataSet) const
+{
+ GMX_ASSERT(dataSet >= 0 && dataSet < dataSetCount(),
+ "Out of range data set index");
+ return impl_->columnCounts_[dataSet];
+}
+
+int
+AbstractAnalysisData::columnCount() const
+{
+ GMX_ASSERT(dataSetCount() == 1,
+ "Convenience method not available for multiple data sets");
+ return columnCount(0);
+}
int
AbstractAnalysisData::frameCount() const
void
AbstractAnalysisData::addModule(AnalysisDataModulePointer module)
{
- if ((columnCount() > 1 && !(module->flags() & AnalysisDataModuleInterface::efAllowMulticolumn))
- || (isMultipoint() && !(module->flags() & AnalysisDataModuleInterface::efAllowMultipoint))
- || (!isMultipoint() && (module->flags() & AnalysisDataModuleInterface::efOnlyMultipoint)))
- {
- GMX_THROW(APIError("Data module not compatible with data object properties"));
- }
+ impl_->checkModuleProperties(*module);
if (impl_->bDataStart_)
{
AbstractAnalysisData::addColumnModule(int col, int span,
AnalysisDataModulePointer module)
{
- GMX_RELEASE_ASSERT(col >= 0 && span >= 1 && col + span <= columnCount_,
+ GMX_RELEASE_ASSERT(col >= 0 && span >= 1,
"Invalid columns specified for a column module");
if (impl_->bDataStart_)
{
void
AbstractAnalysisData::applyModule(AnalysisDataModuleInterface *module)
{
- if ((columnCount() > 1 && !(module->flags() & AnalysisDataModuleInterface::efAllowMulticolumn))
- || (isMultipoint() && !(module->flags() & AnalysisDataModuleInterface::efAllowMultipoint))
- || (!isMultipoint() && (module->flags() & AnalysisDataModuleInterface::efOnlyMultipoint)))
- {
- GMX_THROW(APIError("Data module not compatible with data object properties"));
- }
+ impl_->checkModuleProperties(*module);
GMX_RELEASE_ASSERT(impl_->bDataStart_ && !impl_->bInData_,
"Data module can only be applied to ready data");
/*! \cond libapi */
void
-AbstractAnalysisData::setColumnCount(int columnCount)
+AbstractAnalysisData::setDataSetCount(int dataSetCount)
{
+ GMX_RELEASE_ASSERT(dataSetCount > 0, "Invalid data column count");
+ GMX_RELEASE_ASSERT(!impl_->bDataStart_,
+ "Data set count cannot be changed after data has been added");
+ impl_->columnCounts_.resize(dataSetCount);
+}
+
+void
+AbstractAnalysisData::setColumnCount(int dataSet, int columnCount)
+{
+ GMX_RELEASE_ASSERT(dataSet >= 0 && dataSet < dataSetCount(),
+ "Out of range data set index");
GMX_RELEASE_ASSERT(columnCount > 0, "Invalid data column count");
- GMX_RELEASE_ASSERT(columnCount_ == 0 || impl_->modules_.empty(),
- "Data column count cannot be changed after modules are added");
GMX_RELEASE_ASSERT(!impl_->bDataStart_,
"Data column count cannot be changed after data has been added");
- columnCount_ = columnCount;
+ impl_->columnCounts_[dataSet] = columnCount;
}
-
void
AbstractAnalysisData::setMultipoint(bool multipoint)
{
- GMX_RELEASE_ASSERT(impl_->modules_.empty(),
- "Data type cannot be changed after modules are added");
GMX_RELEASE_ASSERT(!impl_->bDataStart_,
"Data type cannot be changed after data has been added");
- bMultiPoint_ = multipoint;
+ impl_->bMultipoint_ = multipoint;
}
{
GMX_RELEASE_ASSERT(!impl_->bDataStart_,
"notifyDataStart() called more than once");
- GMX_RELEASE_ASSERT(columnCount_ > 0, "Data column count is not set");
+ for (int d = 0; d < dataSetCount(); ++d)
+ {
+ GMX_RELEASE_ASSERT(columnCount(d) > 0,
+ "Data column count is not set");
+ }
impl_->bDataStart_ = impl_->bInData_ = true;
Impl::ModuleList::const_iterator i;
for (i = impl_->modules_.begin(); i != impl_->modules_.end(); ++i)
{
- if (columnCount_ > 1 && !((*i)->flags() & AnalysisDataModuleInterface::efAllowMulticolumn))
- {
- GMX_THROW(APIError("Data module not compatible with data object properties"));
- }
+ impl_->checkModuleProperties(**i);
(*i)->dataStarted(this);
}
}
{
GMX_ASSERT(impl_->bInData_, "notifyDataStart() not called");
GMX_ASSERT(impl_->bInFrame_, "notifyFrameStart() not called");
- GMX_ASSERT(points.lastColumn() < columnCount(), "Invalid columns");
+ GMX_ASSERT(points.lastColumn() < columnCount(points.dataSetIndex()),
+ "Invalid columns");
GMX_ASSERT(points.frameIndex() == impl_->currIndex_,
"Points do not correspond to current frame");
if (!impl_->bAllowMissing_ && !points.allPresent())
* Abstract base class for all objects that provide data.
*
* The public interface includes methods for querying the data (isMultipoint(),
- * columnCount(), frameCount(), tryGetDataFrame(), getDataFrame(),
- * requestStorage()) and methods for using modules for processing the data
- * (addModule(), addColumnModule(), applyModule()).
+ * dataSetCount(), columnCount(), frameCount(), tryGetDataFrame(),
+ * getDataFrame(), requestStorage()) and methods for using modules for
+ * processing the data (addModule(), addColumnModule(), applyModule()).
*
* Notice that even for non-const objects, the interface does not provide any
* means of altering the data. It is only possible to add modules, making it
*
* \if libapi
* This class also provides protected methods for use in derived classes.
- * The properties returned by isMultipoint() and columnCount() must be set using
- * setMultipoint() and setColumnCount(), and notify*() methods must be used to
- * report when data becomes available for modules to process it.
+ * The properties returned by isMultipoint(), dataSetCount(), and columnCount()
+ * must be set using setMultipoint(), setDataSetCount(), and setColumnCount(),
+ * and notify*() methods must be used to report when data becomes available for
+ * modules to process it.
* There are also two protected pure virtual methods that need to be
* implemented to provide access to stored data: requestStorageInternal() and
* tryGetDataFrameInternal().
*
* Does not throw.
*/
- bool isMultipoint() const { return bMultiPoint_; }
+ bool isMultipoint() const;
/*! \brief
- * Returns the number of columns in the data.
+ * Returns the number of data sets in the data object.
+ *
+ * \returns The number of data sets in the data.
+ *
+ * If the number is not yet known, returns 0.
+ * The returned value does not change after modules have been notified
+ * of data start, but may change multiple times before that, depending
+ * on the actual data class.
+ * \if libapi
+ * Derived classes should set the number of columns with
+ * setDataSetCount(), within the above limitations.
+ * \endif
*
+ * Does not throw.
+ */
+ int dataSetCount() const;
+ /*! \brief
+ * Returns the number of columns in a data set.
+ *
+ * \param[in] dataSet Zero-based index of the data set to query.
* \returns The number of columns in the data.
*
- * If the number of columns is yet known, returns 0.
+ * If the number of columns is not yet known, returns 0.
* The returned value does not change after modules have been notified
* of data start, but may change multiple times before that, depending
* on the actual data class.
*
* Does not throw.
*/
- int columnCount() const { return columnCount_; }
+ int columnCount(int dataSet) const;
+ /*! \brief
+ * Returns the number of columns in the data.
+ *
+ * \returns The number of columns in the data.
+ *
+ * This is a convenience method for data objects with a single data set.
+ * Can only be called if dataSetCount() == 1.
+ *
+ * Does not throw.
+ *
+ * \see columnCount(int)
+ */
+ int columnCount() const;
/*! \brief
* Returns the total number of frames in the data.
*
* \param module Module to add.
* \throws APIError in same situations as addModule().
*
+ * Currently, all data sets are filtered using the same column mask.
+ *
* \todo
* This method doesn't currently work in all cases with multipoint
- * data. In particular, if the added module requests storage and uses
- * getDataFrame(), it will behave unpredictably (most likely asserts).
+ * data or with multiple data sets. In particular, if the added module
+ * requests storage and uses getDataFrame(), it will behave
+ * unpredictably (most likely asserts).
+ *
+ * \todo
+ * Generalize this method to multiple data sets (e.g., for adding
+ * modules that only process a single data set).
*
* \see addModule()
*/
AbstractAnalysisData();
/*! \brief
- * Sets the number of columns.
+ * Sets the number of data sets.
+ *
+ * \param[in] dataSetCount Number of data sets (must be > 0).
+ *
+ * It not called, the data object has a single data set.
+ * Can be called only before notifyDataStart().
+ * Multiple calls are allowed before that point; the last call takes
+ * effect.
+ *
+ * Does not throw, but this may change with the todo item in
+ * setColumnCount().
+ *
+ * \see dataSetCount()
+ */
+ void setDataSetCount(int dataSetCount);
+ /*! \brief
+ * Sets the number of columns for a data set.
*
- * \param[in] columnCount Number of columns in the data (must be > 0).
+ * \param[in] dataSet Zero-based index of the data set.
+ * \param[in] columnCount Number of columns in \p dataSet (must be > 0).
*
- * Can be called only before notifyDataStart(), otherwise asserts.
- * Multiple calls are only allowed if all of them occur before
- * addModule() has been called, otherwise asserts (a single call
- * can occur after addModule() if no calls have been made earlier).
+ * Must be called at least once before notifyDataStart() for each data
+ * set.
+ * Can be called only before notifyDataStart().
+ * Multiple calls are allowed before that point; the last call takes
+ * effect.
*
* Does not throw, but this may change with the below todo item.
*
* \todo
- * Consider whether the semantics with respect to addModule() and
- * notifyDataStart(), and the performed checks, are suitable for all
- * purposes.
+ * Consider whether the call should check the modules that have already
+ * been added (currently it is only done in notifyDataStart()).
*
* \see columnCount()
*/
- void setColumnCount(int columnCount);
+ void setColumnCount(int dataSet, int columnCount);
/*! \brief
* Sets whether the data has multiple points per column in a frame.
*
* \param[in] multipoint Whether multiple points per column are
* possible.
*
- * Can be called only before addModule() or notifyDataStart(),
- * otherwise asserts.
+ * If not called, only a single point per column is allowed.
+ * Can be called only before notifyDataStart().
+ * Multiple calls are allowed before that point; the last call takes
+ * effect.
*
* Does not throw, but this may change with the todo item in
* setColumnCount().
class Impl;
PrivateImplPointer<Impl> impl_;
- int columnCount_;
- bool bMultiPoint_;
/*! \brief
* Needed to provide access to notification methods.
void
-AnalysisData::setColumnCount(int ncol)
+AnalysisData::setDataSetCount(int dataSetCount)
{
- GMX_RELEASE_ASSERT(ncol > 0, "Number of columns must be positive");
GMX_RELEASE_ASSERT(impl_->handles_.empty(),
"Cannot change data dimensionality after creating handles");
- AbstractAnalysisData::setColumnCount(ncol);
+ AbstractAnalysisData::setDataSetCount(dataSetCount);
+}
+
+
+void
+AnalysisData::setColumnCount(int dataSet, int columnCount)
+{
+ GMX_RELEASE_ASSERT(impl_->handles_.empty(),
+ "Cannot change data dimensionality after creating handles");
+ AbstractAnalysisData::setColumnCount(dataSet, columnCount);
}
}
+void
+AnalysisDataHandle::selectDataSet(int index)
+{
+ GMX_RELEASE_ASSERT(impl_ != NULL, "Invalid data handle used");
+ GMX_RELEASE_ASSERT(impl_->currentFrame_ != NULL,
+ "selectDataSet() called without calling startFrame()");
+ impl_->currentFrame_->selectDataSet(index);
+}
+
+
void
AnalysisDataHandle::setPoint(int column, real value, bool bPresent)
{
*
* This is the main class used to implement parallelizable data processing in
* analysis tools. It is used by first creating an object and setting its
- * properties using setColumnCount() and setMultipoint(), and attaching
- * necessary modules using addModule() etc. Then one or more
+ * properties using setDataSetCount(), setColumnCount() and setMultipoint(),
+ * and attaching necessary modules using addModule() etc. Then one or more
* AnalysisDataHandle objects can be created using startData(). Each data
* handle can then be independently used to provide data frames (each frame
* must be provided by a single handle, but different frames can be freely
virtual ~AnalysisData();
/*! \brief
- * Sets the number of columns in the data.
+ * Sets the number of data sets.
*
- * \param[in] ncol Number of columns in the data (must be > 0).
+ * \param[in] dataSetCount Number of data sets (must be > 0).
*
- * Must be called before startData(), and can be called multiple times
- * before modules are added.
* Must not be called after startData() has been called.
+ * If not called, a single data set is assumed.
+ * If called multiple times, the last call takes effect.
*
* Does not currently throw, but this may change for the case that
* modules have already been added.
*/
- void setColumnCount(int ncol);
+ void setDataSetCount(int dataSetCount);
+ /*! \brief
+ * Sets the number of columns in a data set.
+ *
+ * \param[in] dataSet Zero-based data set index.
+ * \param[in] columnCount Number of columns in the data (must be > 0).
+ *
+ * Must be called before startData() for each data set.
+ * Must not be called after startData() has been called.
+ * If called multiple times for a data set, the last call takes effect.
+ *
+ * Does not currently throw, but this may change for the case that
+ * modules have already been added.
+ */
+ void setColumnCount(int dataSet, int columnCount);
/*! \brief
* Sets whether the data contains multiple points per column per frame.
*
*
* If this method is not called, the data is not multipoint.
*
- * Must not be called after modules have been added or startData() has
- * been called.
+ * Must not be called after startData() has been called.
*
* Does not currently throw, but this may change for the case that
* modules have already been added.
* called.
*
* For simple (non-multipoint) data, within a frame values can be set using
- * setPoint() and setPoints(). Setting the same column multiple times
- * overrides previously set values. When the frame is finished, attached
- * modules are notified.
+ * selectDataSet(), setPoint() and setPoints(). Setting the same column in the
+ * same data set multiple times overrides previously set values.
+ * When the frame is finished, attached modules are notified.
*
* Multipoint data works otherwise similarly, but requires finishPointSet() to
* be called for each set of points for which the modules need to be notified.
* Each point set starts empty (after startFrame() or finishPointSet()), and
- * values can be set using setPoint()/setPoints(). finishPointSet() must also
- * be called for the last point set just before finishFrame().
+ * values can be set using setPoint()/setPoints().
+ * A single point set can contain values only for a single data set, which must
+ * be selected with selectDataSet() before setting any values.
+ * finishPointSet() must also be called for the last point set just before
+ * finishFrame().
*
* This class works like a pointer type: copying and assignment is lightweight,
* and all copies work interchangeably, accessing the same internal handle.
* is not finished).
*/
void startFrame(int index, real x, real dx = 0.0);
+ /*! \brief
+ * Selects a data set for subsequent setPoint()/setPoints() calls.
+ *
+ * \param[in] index Zero-based data set index.
+ *
+ * After startFrame(), the first data set is always selected.
+ * The set value is remembered until the end of the current frame, also
+ * across finishPointSet() calls.
+ *
+ * Does not throw.
+ */
+ void selectDataSet(int index);
/*! \brief
* Set a value for a single column for the current frame.
*
{
AbstractAnalysisArrayData::AbstractAnalysisArrayData()
- : rowCount_(0), pointSetInfo_(0, 0, 0), xstart_(0.0), xstep_(1.0),
+ : rowCount_(0), pointSetInfo_(0, 0, 0, 0), xstart_(0.0), xstep_(1.0),
bReady_(false)
{
}
{
GMX_RELEASE_ASSERT(!isAllocated(),
"Cannot change column count after data has been allocated");
- AbstractAnalysisData::setColumnCount(ncols);
- pointSetInfo_ = AnalysisDataPointSetInfo(0, ncols, 0);
+ AbstractAnalysisData::setColumnCount(0, ncols);
+ pointSetInfo_ = AnalysisDataPointSetInfo(0, ncols, 0, 0);
}
* \todo
* Add methods to take full advantage of AnalysisDataValue features.
*
+ * \todo
+ * Add support for multiple data sets.
+ *
* \inlibraryapi
* \ingroup module_analysisdata
*/
const AnalysisDataFrameHeader &header,
const AnalysisDataPointSetInfo &pointSetInfo,
const AnalysisDataValuesRef &values)
- : header_(header), firstColumn_(pointSetInfo.firstColumn()),
+ : header_(header),
+ dataSetIndex_(pointSetInfo.dataSetIndex()),
+ firstColumn_(pointSetInfo.firstColumn()),
values_(&*values.begin() + pointSetInfo.valueOffset(),
pointSetInfo.valueCount())
{
AnalysisDataPointSetRef::AnalysisDataPointSetRef(
const AnalysisDataFrameHeader &header,
const std::vector<AnalysisDataValue> &values)
- : header_(header), firstColumn_(0), values_(values.begin(), values.end())
+ : header_(header), dataSetIndex_(0), firstColumn_(0),
+ values_(values.begin(), values.end())
{
GMX_ASSERT(header_.isValid(),
"Invalid point set reference should not be constructed");
AnalysisDataPointSetRef::AnalysisDataPointSetRef(
const AnalysisDataPointSetRef &points, int firstColumn, int columnCount)
- : header_(points.header()), firstColumn_(0)
+ : header_(points.header()), dataSetIndex_(points.dataSetIndex()),
+ firstColumn_(0)
{
GMX_ASSERT(firstColumn >= 0, "Invalid first column");
GMX_ASSERT(columnCount >= 0, "Invalid column count");
public:
//! Construct point set data object with the given values.
AnalysisDataPointSetInfo(int valueOffset, int valueCount,
- int firstColumn)
+ int dataSetIndex, int firstColumn)
: valueOffset_(valueOffset), valueCount_(valueCount),
- firstColumn_(firstColumn)
+ dataSetIndex_(dataSetIndex), firstColumn_(firstColumn)
{
- GMX_ASSERT(valueOffset >= 0, "Negative value offsets are invalid");
- GMX_ASSERT(valueCount >= 0, "Negative value counts are invalid");
- GMX_ASSERT(firstColumn >= 0, "Negative column indices are invalid");
+ GMX_ASSERT(valueOffset >= 0, "Negative value offsets are invalid");
+ GMX_ASSERT(valueCount >= 0, "Negative value counts are invalid");
+ GMX_ASSERT(dataSetIndex >= 0, "Negative data set indices are invalid");
+ GMX_ASSERT(firstColumn >= 0, "Negative column indices are invalid");
}
//! Returns the offset of the first value in the referenced value array.
int valueOffset() const { return valueOffset_; }
//! Returns the number of values in this point set.
int valueCount() const { return valueCount_; }
+ //! Returns the data set index for this point set.
+ int dataSetIndex() const { return dataSetIndex_; }
//! Returns the index of the first column in this point set.
int firstColumn() const { return firstColumn_; }
private:
int valueOffset_;
int valueCount_;
+ int dataSetIndex_;
int firstColumn_;
};
{
return header_.dx();
}
+ //! Returns zero-based index of the dataset that this set is part of.
+ int dataSetIndex() const
+ {
+ return dataSetIndex_;
+ }
//! Returns zero-based index of the first column included in this set.
int firstColumn() const
{
private:
AnalysisDataFrameHeader header_;
+ int dataSetIndex_;
int firstColumn_;
AnalysisDataValuesRef values_;
};
/*
* This file is part of the GROMACS molecular simulation package.
*
- * Copyright (c) 2010,2011,2012, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013, 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.
*/
enum {
//! The module can process multipoint data.
- efAllowMultipoint = 0x01,
+ efAllowMultipoint = 1<<0,
//! The module does not make sense for non-multipoint data.
- efOnlyMultipoint = 0x02,
+ efOnlyMultipoint = 1<<1,
//! The module can process data with more than one column.
- efAllowMulticolumn = 0x04,
+ efAllowMulticolumn = 1<<2,
//! The module can process data with missing points.
- efAllowMissing = 0x08,
+ efAllowMissing = 1<<3,
+ //! The module can process data with multiple data sets.
+ efAllowMultipleDataSets = 1<<4
};
virtual ~AnalysisDataModuleInterface() {};
/*
* This file is part of the GROMACS molecular simulation package.
*
- * Copyright (c) 2010,2011,2012, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013, 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.
AbstractAnalysisData *data)
: source_(*data), firstColumn_(firstColumn), columnSpan_(columnSpan)
{
- GMX_RELEASE_ASSERT(data, "Source data must not be NULL");
+ GMX_RELEASE_ASSERT(data != NULL, "Source data must not be NULL");
GMX_RELEASE_ASSERT(firstColumn >= 0 && columnSpan > 0, "Invalid proxy column");
- setColumnCount(columnSpan);
setMultipoint(source_.isMultipoint());
}
int
AnalysisDataProxy::flags() const
{
- return efAllowMultipoint | efAllowMulticolumn | efAllowMissing;
+ return efAllowMultipoint | efAllowMulticolumn | efAllowMissing
+ | efAllowMultipleDataSets;
}
AnalysisDataProxy::dataStarted(AbstractAnalysisData *data)
{
GMX_RELEASE_ASSERT(data == &source_, "Source data mismatch");
- GMX_RELEASE_ASSERT(firstColumn_ + columnSpan_ <= source_.columnCount(),
- "Invalid column(s) specified");
+ setDataSetCount(data->dataSetCount());
+ for (int i = 0; i < data->dataSetCount(); ++i)
+ {
+ setColumnCount(i, columnSpan_);
+ }
notifyDataStart();
}
Impl();
- //! Returns the number of columns in the attached data.
- int columnCount() const;
//! Returns whether the storage is set to use multipoint data.
bool isMultipoint() const;
/*! \brief
/*! \brief
* Adds a new point set to this frame.
*/
- void addPointSet(int firstColumn, ValueIterator begin, ValueIterator end);
+ void addPointSet(int dataSetIndex, int firstColumn,
+ ValueIterator begin, ValueIterator end);
/*! \brief
* Finalizes the frame during AnalysisDataStorage::finishFrame().
*
}
-int
-AnalysisDataStorage::Impl::columnCount() const
-{
- GMX_ASSERT(data_ != NULL, "columnCount() called too early");
- return data_->columnCount();
-}
-
-
bool
AnalysisDataStorage::Impl::isMultipoint() const
{
{
if (builders_.empty())
{
- return FrameBuilderPointer(new AnalysisDataStorageFrame(columnCount()));
+ return FrameBuilderPointer(new AnalysisDataStorageFrame(*data_));
}
FrameBuilderPointer builder(move(builders_.back()));
builders_.pop_back();
// so initialize it only once here.
if (!baseData().isMultipoint())
{
- int columnCount = baseData().columnCount();
- pointSets_.push_back(AnalysisDataPointSetInfo(0, columnCount, 0));
+ int offset = 0;
+ for (int i = 0; i < baseData().dataSetCount(); ++i)
+ {
+ int columnCount = baseData().columnCount(i);
+ pointSets_.push_back(
+ AnalysisDataPointSetInfo(offset, columnCount, i, 0));
+ offset += columnCount;
+ }
}
}
header_ = header;
builder_ = move(builder);
builder_->data_ = this;
+ builder_->selectDataSet(0);
}
void
-AnalysisDataStorageFrameData::addPointSet(int firstColumn,
+AnalysisDataStorageFrameData::addPointSet(int dataSetIndex, int firstColumn,
ValueIterator begin, ValueIterator end)
{
const int valueCount = end - begin;
if (storageImpl().shouldNotifyImmediately())
{
- AnalysisDataPointSetInfo pointSetInfo(0, valueCount, firstColumn);
+ AnalysisDataPointSetInfo pointSetInfo(0, valueCount,
+ dataSetIndex, firstColumn);
storageImpl().notifyPointSet(
AnalysisDataPointSetRef(header(), pointSetInfo,
AnalysisDataValuesRef(begin, end)));
else
{
pointSets_.push_back(
- AnalysisDataPointSetInfo(values_.size(), valueCount, firstColumn));
+ AnalysisDataPointSetInfo(values_.size(), valueCount,
+ dataSetIndex, firstColumn));
std::copy(begin, end, std::back_inserter(values_));
}
}
status_ = eFinished;
if (!bMultipoint)
{
- GMX_RELEASE_ASSERT(pointSets_.size() == 1U,
+ GMX_RELEASE_ASSERT(static_cast<int>(pointSets_.size()) == baseData().dataSetCount(),
"Point sets created for non-multipoint data");
values_ = builder_->values_;
builder_->clearValues();
* AnalysisDataStorageFrame
*/
-AnalysisDataStorageFrame::AnalysisDataStorageFrame(int columnCount)
- : data_(NULL), values_(columnCount), bPointSetInProgress_(false)
+AnalysisDataStorageFrame::AnalysisDataStorageFrame(
+ const AbstractAnalysisData &data)
+ : data_(NULL), currentDataSet_(0), currentOffset_(0),
+ columnCount_(data.columnCount(0)), bPointSetInProgress_(false)
{
+ int totalColumnCount = 0;
+ for (int i = 0; i < data.dataSetCount(); ++i)
+ {
+ totalColumnCount += data.columnCount(i);
+ }
+ values_.resize(totalColumnCount);
}
}
+void
+AnalysisDataStorageFrame::selectDataSet(int index)
+{
+ GMX_RELEASE_ASSERT(data_ != NULL, "Invalid frame accessed");
+ const AbstractAnalysisData &baseData = data_->baseData();
+ GMX_RELEASE_ASSERT(index >= 0 && index < baseData.dataSetCount(),
+ "Out of range data set index");
+ GMX_RELEASE_ASSERT(!baseData.isMultipoint() || !bPointSetInProgress_,
+ "Point sets in multipoint data cannot span data sets");
+ currentDataSet_ = index;
+ currentOffset_ = 0;
+ // TODO: Consider precalculating.
+ for (int i = 0; i < index; ++i)
+ {
+ currentOffset_ += baseData.columnCount(i);
+ }
+ columnCount_ = baseData.columnCount(index);
+}
+
+
void
AnalysisDataStorageFrame::finishPointSet()
{
"Should not be called for non-multipoint data");
if (bPointSetInProgress_)
{
- std::vector<AnalysisDataValue>::const_iterator begin = values_.begin();
- std::vector<AnalysisDataValue>::const_iterator end = values_.end();
+ std::vector<AnalysisDataValue>::const_iterator begin
+ = values_.begin() + currentOffset_;
+ std::vector<AnalysisDataValue>::const_iterator end
+ = begin + columnCount_;
+ int firstColumn = 0;
while (begin != end && !begin->isSet())
{
++begin;
+ ++firstColumn;
}
while (end != begin && !(end-1)->isSet())
{
--end;
}
- int firstColumn = (begin != end) ? begin - values_.begin() : 0;
- data_->addPointSet(firstColumn, begin, end);
+ if (begin == end)
+ {
+ firstColumn = 0;
+ }
+ data_->addPointSet(currentDataSet_, firstColumn, begin, end);
}
clearValues();
}
*/
~AnalysisDataStorageFrame();
+ /*! \brief
+ * Select data set that all other methods operate on.
+ *
+ * \param[in] index Zero-based data set index to select.
+ *
+ * With multipoint data, a single point set can only contain values in
+ * a single data set.
+ * With non-multipoint data, arbitrary sequences of selectDataSet() and
+ * setValue() are supported. The full frame is notified to the modules
+ * once it is finished.
+ *
+ * Does not throw.
+ */
+ void selectDataSet(int index);
+
//! Returns number of columns for the frame.
- int columnCount() const { return values_.size(); }
+ int columnCount() const { return columnCount_; }
/*! \brief
* Sets value for a column.
{
GMX_ASSERT(column >= 0 && column < columnCount(),
"Invalid column index");
- values_[column].setValue(value, bPresent);
+ values_[currentOffset_ + column].setValue(value, bPresent);
bPointSetInProgress_ = true;
}
/*! \brief
{
GMX_ASSERT(column >= 0 && column < columnCount(),
"Invalid column index");
- values_[column].setValue(value, error, bPresent);
+ values_[currentOffset_ + column].setValue(value, error, bPresent);
bPointSetInProgress_ = true;
}
/*! \brief
{
GMX_ASSERT(column >= 0 && column < columnCount(),
"Invalid column index");
- return values_[column].value();
+ return values_[currentOffset_ + column].value();
}
/*! \brief
* Access value for a column.
{
GMX_ASSERT(column >= 0 && column < columnCount(),
"Invalid column index");
- return values_[column].value();
+ return values_[currentOffset_ + column].value();
}
/*! \brief
* Mark point set as finished for multipoint data.
/*! \brief
* Create a new storage frame.
*
- * \param[in] columnCount Number of columns for the frame.
+ * \param[in] data Data object for which the frame is for
+ * (used for data set and column counts).
*/
- explicit AnalysisDataStorageFrame(int columnCount);
+ explicit AnalysisDataStorageFrame(const AbstractAnalysisData &data);
//! Clear all column values from the frame.
void clearValues();
//! Values for the currently in-progress point set.
std::vector<AnalysisDataValue> values_;
+ //! Index of the currently active dataset.
+ int currentDataSet_;
+ //! Offset of the first value in \a values_ for the current data set.
+ int currentOffset_;
+ //! Number of columns in the current data set.
+ int columnCount_;
+
//! Whether any values have been set in the current point set.
bool bPointSetInProgress_;
AnalysisDataFrameAverageModule::AnalysisDataFrameAverageModule()
: impl_(new Impl())
{
- setColumnCount(1);
+ setColumnCount(0, 1);
}
AnalysisDataFrameAverageModule::~AnalysisDataFrameAverageModule()
int ncol = _impl->nmax / _impl->ndim + 1;
_impl->currValues_.reserve(ncol);
- setColumnCount(ncol);
+ setColumnCount(0, ncol);
}
AnalysisDataSimpleHistogramModule::dataStarted(AbstractAnalysisData *data)
{
addModule(impl_->averager_);
- setColumnCount(settings().binCount());
+ setColumnCount(0, settings().binCount());
notifyDataStart();
impl_->storage_.startDataStorage(this);
}
AnalysisDataWeightedHistogramModule::dataStarted(AbstractAnalysisData *data)
{
addModule(impl_->averager_);
- setColumnCount(settings().binCount());
+ setColumnCount(0, settings().binCount());
notifyDataStart();
impl_->storage_.startDataStorage(this);
}
TEST(AnalysisDataInitializationTest, BasicInitialization)
{
gmx::AnalysisData data;
+ EXPECT_EQ(1, data.dataSetCount());
+ EXPECT_EQ(0, data.columnCount(0));
EXPECT_EQ(0, data.columnCount());
EXPECT_FALSE(data.isMultipoint());
EXPECT_EQ(0, data.frameCount());
- data.setColumnCount(1);
+ data.setColumnCount(0, 1);
+ EXPECT_EQ(1, data.columnCount(0));
EXPECT_EQ(1, data.columnCount());
EXPECT_FALSE(data.isMultipoint());
- data.setColumnCount(3);
+ data.setDataSetCount(2);
+ EXPECT_EQ(2, data.dataSetCount());
+ data.setColumnCount(0, 3);
+ EXPECT_EQ(3, data.columnCount(0));
+ EXPECT_EQ(0, data.columnCount(1));
+ data.setColumnCount(1, 2);
+ EXPECT_EQ(3, data.columnCount(0));
+ EXPECT_EQ(2, data.columnCount(1));
+
+ data.setDataSetCount(1);
+ EXPECT_EQ(1, data.dataSetCount());
data.setMultipoint(true);
EXPECT_EQ(3, data.columnCount());
EXPECT_TRUE(data.isMultipoint());
- data.setColumnCount(1);
+ data.setColumnCount(0, 1);
EXPECT_EQ(1, data.columnCount());
EXPECT_TRUE(data.isMultipoint());
}
TEST(AnalysisDataInitializationTest, ChecksMultiColumnModules)
{
gmx::AnalysisData data;
- data.setColumnCount(2);
+ data.setColumnCount(0, 2);
MockAnalysisDataModulePointer mod1(new MockAnalysisDataModule(0));
EXPECT_THROW_GMX(data.addModule(mod1), gmx::APIError);
* Tests that checking for compatibility of modules with multipoint data
* works.
*/
-TEST(AnalysisDataInitializationTest, ChecksMultiPointModules)
+TEST(AnalysisDataInitializationTest, ChecksMultipointModules)
{
gmx::AnalysisData data;
- data.setColumnCount(1);
+ data.setColumnCount(0, 1);
data.setMultipoint(true);
MockAnalysisDataModulePointer mod1(new MockAnalysisDataModule(0));
return singleton.data_;
}
- SimpleInputData() : data_(3, false)
+ SimpleInputData() : data_(1, false)
{
+ data_.setColumnCount(0, 3);
data_.addFrameWithValues(1.0, 0.0, 1.0, 2.0);
data_.addFrameWithValues(2.0, 1.0, 1.0, 1.0);
data_.addFrameWithValues(3.0, 2.0, 0.0, 0.0);
AnalysisDataTestInput data_;
};
+// Input data with multiple data sets for gmx::AnalysisData tests.
+class DataSetsInputData
+{
+ public:
+ static const AnalysisDataTestInput &get()
+ {
+ static DataSetsInputData singleton;
+ return singleton.data_;
+ }
+
+ DataSetsInputData() : data_(2, false)
+ {
+ using gmx::test::AnalysisDataTestInputFrame;
+ data_.setColumnCount(0, 3);
+ data_.setColumnCount(1, 2);
+ AnalysisDataTestInputFrame &frame1 = data_.addFrame(1.0);
+ frame1.addPointSetWithValues(0, 0, 0.0, 1.0, 2.0);
+ frame1.addPointSetWithValues(1, 0, 2.1, 1.1);
+ AnalysisDataTestInputFrame &frame2 = data_.addFrame(2.0);
+ frame2.addPointSetWithValues(0, 0, 1.0, 1.0, 1.0);
+ frame2.addPointSetWithValues(1, 0, 0.1, 2.1);
+ AnalysisDataTestInputFrame &frame3 = data_.addFrame(3.0);
+ frame3.addPointSetWithValues(0, 0, 2.0, 0.0, 0.0);
+ frame3.addPointSetWithValues(1, 0, 1.1, 1.1);
+ }
+
+ private:
+ AnalysisDataTestInput data_;
+};
+
// Input data for multipoint gmx::AnalysisData tests.
class MultipointInputData
{
return singleton.data_;
}
- MultipointInputData() : data_(3, true)
+ MultipointInputData() : data_(1, true)
+ {
+ using gmx::test::AnalysisDataTestInputFrame;
+ data_.setColumnCount(0, 3);
+ AnalysisDataTestInputFrame &frame1 = data_.addFrame(1.0);
+ frame1.addPointSetWithValues(0, 0, 0.0, 1.0, 2.0);
+ frame1.addPointSetWithValues(0, 0, 1.1, 2.1, 1.1);
+ frame1.addPointSetWithValues(0, 0, 2.2, 1.2, 0.2);
+ AnalysisDataTestInputFrame &frame2 = data_.addFrame(2.0);
+ frame2.addPointSetWithValues(0, 1, 1.0, 1.0);
+ frame2.addPointSetWithValues(0, 0, 2.1, 1.1, 0.1);
+ frame2.addPointSetWithValues(0, 2, 1.2);
+ AnalysisDataTestInputFrame &frame3 = data_.addFrame(3.0);
+ frame3.addPointSetWithValues(0, 0, 2.0, 0.0, 0.0);
+ frame3.addPointSetWithValues(0, 0, 3.1, 2.1);
+ frame3.addPointSetWithValues(0, 1, 2.2, 1.2);
+ }
+
+ private:
+ AnalysisDataTestInput data_;
+};
+
+// Input data with multiple multipoint data sets for gmx::AnalysisData tests.
+class MultipointDataSetsInputData
+{
+ public:
+ static const AnalysisDataTestInput &get()
+ {
+ static MultipointDataSetsInputData singleton;
+ return singleton.data_;
+ }
+
+ MultipointDataSetsInputData() : data_(2, true)
{
using gmx::test::AnalysisDataTestInputFrame;
+ data_.setColumnCount(0, 3);
+ data_.setColumnCount(1, 2);
AnalysisDataTestInputFrame &frame1 = data_.addFrame(1.0);
- frame1.addPointSetWithValues(0, 0.0, 1.0, 2.0);
- frame1.addPointSetWithValues(0, 1.1, 2.1, 1.1);
- frame1.addPointSetWithValues(0, 2.2, 1.2, 0.2);
+ frame1.addPointSetWithValues(0, 0, 0.0, 1.0, 2.0);
+ frame1.addPointSetWithValues(0, 1, 2.1, 1.1);
+ frame1.addPointSetWithValues(1, 0, 2.01, 1.01);
+ frame1.addPointSetWithValues(1, 1, 0.11);
AnalysisDataTestInputFrame &frame2 = data_.addFrame(2.0);
- frame2.addPointSetWithValues(1, 1.0, 1.0);
- frame2.addPointSetWithValues(0, 2.1, 1.1, 0.1);
- frame2.addPointSetWithValues(2, 1.2);
+ frame2.addPointSetWithValues(0, 0, 1.0, 1.0, 1.0);
+ frame2.addPointSetWithValues(0, 0, 0.1, 2.1);
+ frame2.addPointSetWithValues(1, 1, 1.01);
AnalysisDataTestInputFrame &frame3 = data_.addFrame(3.0);
- frame3.addPointSetWithValues(0, 2.0, 0.0, 0.0);
- frame3.addPointSetWithValues(0, 3.1, 2.1);
- frame3.addPointSetWithValues(1, 2.2, 1.2);
+ frame3.addPointSetWithValues(0, 0, 2.0, 0.0, 0.0);
+ frame3.addPointSetWithValues(0, 1, 1.1);
}
private:
//! Test fixture for tests that are only applicable to multipoint data.
typedef AnalysisDataCommonTest<MultipointInputData> AnalysisDataMultipointTest;
//! List of input data types for tests applicable to all types of data.
-typedef ::testing::Types<SimpleInputData, MultipointInputData> AllInputDataTypes;
+typedef ::testing::Types<SimpleInputData,
+ DataSetsInputData,
+ MultipointInputData,
+ MultipointDataSetsInputData>
+ AllInputDataTypes;
TYPED_TEST_CASE(AnalysisDataCommonTest, AllInputDataTypes);
/*
return singleton.data_;
}
- SimpleInputData() : data_(3, false)
+ SimpleInputData() : data_(1, false)
{
+ data_.setColumnCount(0, 3);
data_.addFrameWithValues(1.0, 0.0, 1.0, 2.0);
data_.addFrameWithValues(2.0, 1.0, 1.0, 1.0);
data_.addFrameWithValues(3.0, 2.0, 0.0, 0.0);
return singleton.data_;
}
- SimpleInputData() : data_(3, false)
+ SimpleInputData() : data_(1, false)
{
+ data_.setColumnCount(0, 3);
data_.addFrameWithValues(1.0, 0.0, 1.0, 2.0);
data_.addFrameWithValues(2.0, 1.0, 1.0, 1.0);
data_.addFrameWithValues(3.0, 2.0, 0.0, 0.0);
return singleton.data_;
}
- MultipointInputData() : data_(3, true)
+ MultipointInputData() : data_(1, true)
{
using gmx::test::AnalysisDataTestInputFrame;
+ data_.setColumnCount(0, 3);
AnalysisDataTestInputFrame &frame1 = data_.addFrame(1.0);
- frame1.addPointSetWithValues(0, 0.0, 1.0, 2.0);
- frame1.addPointSetWithValues(0, 1.0, 0.0);
- frame1.addPointSetWithValues(0, 2.0);
+ frame1.addPointSetWithValues(0, 0, 0.0, 1.0, 2.0);
+ frame1.addPointSetWithValues(0, 0, 1.0, 0.0);
+ frame1.addPointSetWithValues(0, 0, 2.0);
AnalysisDataTestInputFrame &frame2 = data_.addFrame(2.0);
- frame2.addPointSetWithValues(0, 1.0, 1.0);
- frame2.addPointSetWithValues(0, 2.0);
+ frame2.addPointSetWithValues(0, 0, 1.0, 1.0);
+ frame2.addPointSetWithValues(0, 0, 2.0);
AnalysisDataTestInputFrame &frame3 = data_.addFrame(3.0);
- frame3.addPointSetWithValues(0, 2.0, 0.0, 0.0);
+ frame3.addPointSetWithValues(0, 0, 2.0, 0.0, 0.0);
}
private:
SimpleInputData() : data_(1, true)
{
using gmx::test::AnalysisDataTestInputFrame;
+ data_.setColumnCount(0, 1);
AnalysisDataTestInputFrame &frame1 = data_.addFrame(1.0);
- frame1.addPointSetWithValues(0, 0.7);
- frame1.addPointSetWithValues(0, 1.1);
- frame1.addPointSetWithValues(0, 2.3);
- frame1.addPointSetWithValues(0, 2.9);
+ frame1.addPointSetWithValues(0, 0, 0.7);
+ frame1.addPointSetWithValues(0, 0, 1.1);
+ frame1.addPointSetWithValues(0, 0, 2.3);
+ frame1.addPointSetWithValues(0, 0, 2.9);
AnalysisDataTestInputFrame &frame2 = data_.addFrame(2.0);
- frame2.addPointSetWithValues(0, 1.3);
- frame2.addPointSetWithValues(0, 2.2);
+ frame2.addPointSetWithValues(0, 0, 1.3);
+ frame2.addPointSetWithValues(0, 0, 2.2);
AnalysisDataTestInputFrame &frame3 = data_.addFrame(3.0);
- frame3.addPointSetWithValues(0, 3.3);
- frame3.addPointSetWithValues(0, 1.2);
- frame3.addPointSetWithValues(0, 1.3);
+ frame3.addPointSetWithValues(0, 0, 3.3);
+ frame3.addPointSetWithValues(0, 0, 1.2);
+ frame3.addPointSetWithValues(0, 0, 1.3);
}
private:
return singleton.data_;
}
- WeightedInputData() : data_(2, true)
+ WeightedInputData() : data_(1, true)
{
using gmx::test::AnalysisDataTestInputFrame;
+ data_.setColumnCount(0, 2);
AnalysisDataTestInputFrame &frame1 = data_.addFrame(1.0);
- frame1.addPointSetWithValues(0, 0.7, 0.5);
- frame1.addPointSetWithValues(0, 1.1, 1.0);
- frame1.addPointSetWithValues(0, 2.3, 1.0);
- frame1.addPointSetWithValues(0, 2.9, 2.0);
+ frame1.addPointSetWithValues(0, 0, 0.7, 0.5);
+ frame1.addPointSetWithValues(0, 0, 1.1, 1.0);
+ frame1.addPointSetWithValues(0, 0, 2.3, 1.0);
+ frame1.addPointSetWithValues(0, 0, 2.9, 2.0);
AnalysisDataTestInputFrame &frame2 = data_.addFrame(2.0);
- frame2.addPointSetWithValues(0, 1.3, 1.0);
- frame2.addPointSetWithValues(0, 2.2, 3.0);
+ frame2.addPointSetWithValues(0, 0, 1.3, 1.0);
+ frame2.addPointSetWithValues(0, 0, 2.2, 3.0);
AnalysisDataTestInputFrame &frame3 = data_.addFrame(3.0);
- frame3.addPointSetWithValues(0, 3.3, 0.5);
- frame3.addPointSetWithValues(0, 1.2, 2.0);
- frame3.addPointSetWithValues(0, 1.3, 1.0);
+ frame3.addPointSetWithValues(0, 0, 3.3, 0.5);
+ frame3.addPointSetWithValues(0, 0, 1.2, 2.0);
+ frame3.addPointSetWithValues(0, 0, 1.3, 1.0);
}
private:
return singleton.data_;
}
- AverageInputData() : data_(2, false)
+ AverageInputData() : data_(1, false)
{
+ data_.setColumnCount(0, 2);
data_.addFrameWithValues(1.0, 2.0, 1.0);
data_.addFrameWithValues(1.5, 1.0, 1.0);
data_.addFrameWithValues(2.0, 3.0, 2.0);
{
checkSelections(sel1_, sel2_);
- angles_.setColumnCount(sel1_[0].posCount() / natoms1_);
+ angles_.setColumnCount(0, sel1_[0].posCount() / natoms1_);
double histogramMin = (g1type_ == "dihedral" ? -180.0 : 0);
histogramModule_->init(histogramFromRange(histogramMin, 180.0)
.binWidth(binWidth_).includeAll());
/*
* This file is part of the GROMACS molecular simulation package.
*
- * Copyright (c) 2010,2011,2012, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013, 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.
: TrajectoryAnalysisModule(name, shortDescription),
avem_(new AnalysisDataAverageModule())
{
- data_.setColumnCount(4);
+ data_.setColumnCount(0, 4);
registerAnalysisDataset(&data_, "distance");
}
adata_(new AnalysisDataAverageModule())
{
// We only compute two numbers per frame
- data_.setColumnCount(2);
+ data_.setColumnCount(0, 2);
// Tell the analysis framework that this component exists
registerAnalysisDataset(&data_, "freevolume");
rng_ = NULL;
{
registerAnalysisDataset(&sdata_, "size");
registerAnalysisDataset(&cdata_, "cfrac");
- idata_.setColumnCount(2);
+ idata_.setColumnCount(0, 2);
idata_.setMultipoint(true);
registerAnalysisDataset(&idata_, "index");
registerAnalysisDataset(&mdata_, "mask");
}
// TODO: For large systems, a float may not have enough precision
- sdata_.setColumnCount(sel_.size());
+ sdata_.setColumnCount(0, sel_.size());
totsize_.reserve(sel_.size());
for (size_t g = 0; g < sel_.size(); ++g)
{
sdata_.addModule(plot);
}
- cdata_.setColumnCount(sel_.size());
+ cdata_.setColumnCount(0, sel_.size());
if (!fnFrac_.empty())
{
AnalysisDataPlotModulePointer plot(
idata_.addModule(writer);
}
- mdata_.setColumnCount(sel_[0].posCount());
+ mdata_.setColumnCount(0, sel_[0].posCount());
mdata_.addModule(occupancyModule_);
if (!fnMask_.empty())
{
*/
AnalysisDataTestInputPointSet::AnalysisDataTestInputPointSet(
- int index, int firstColumn)
- : index_(index), firstColumn_(firstColumn)
+ int index, int dataSetIndex, int firstColumn)
+ : index_(index), dataSetIndex_(dataSetIndex), firstColumn_(firstColumn)
{
}
}
AnalysisDataTestInputPointSet &
-AnalysisDataTestInputFrame::addPointSet(int firstColumn)
+AnalysisDataTestInputFrame::addPointSet(int dataSet, int firstColumn)
{
- pointSets_.push_back(AnalysisDataTestInputPointSet(pointSets_.size(), firstColumn));
+ pointSets_.push_back(
+ AnalysisDataTestInputPointSet(pointSets_.size(),
+ dataSet, firstColumn));
return pointSets_.back();
}
-void AnalysisDataTestInputFrame::addPointSetWithValues(int firstColumn, real y1)
+void AnalysisDataTestInputFrame::addPointSetWithValues(
+ int dataSet, int firstColumn, real y1)
{
- AnalysisDataTestInputPointSet &pointSet = addPointSet(firstColumn);
+ AnalysisDataTestInputPointSet &pointSet = addPointSet(dataSet, firstColumn);
pointSet.addValue(y1);
}
-void AnalysisDataTestInputFrame::addPointSetWithValues(int firstColumn, real y1,
- real y2)
+void AnalysisDataTestInputFrame::addPointSetWithValues(
+ int dataSet, int firstColumn, real y1, real y2)
{
- AnalysisDataTestInputPointSet &pointSet = addPointSet(firstColumn);
+ AnalysisDataTestInputPointSet &pointSet = addPointSet(dataSet, firstColumn);
pointSet.addValue(y1);
pointSet.addValue(y2);
}
-void AnalysisDataTestInputFrame::addPointSetWithValues(int firstColumn, real y1,
- real y2, real y3)
+void AnalysisDataTestInputFrame::addPointSetWithValues(
+ int dataSet, int firstColumn, real y1, real y2, real y3)
{
- AnalysisDataTestInputPointSet &pointSet = addPointSet(firstColumn);
+ AnalysisDataTestInputPointSet &pointSet = addPointSet(dataSet, firstColumn);
pointSet.addValue(y1);
pointSet.addValue(y2);
pointSet.addValue(y3);
* AnalysisDataTestInput
*/
-AnalysisDataTestInput::AnalysisDataTestInput(int columnCount, bool bMultipoint)
- : columnCount_(columnCount), bMultipoint_(bMultipoint)
+AnalysisDataTestInput::AnalysisDataTestInput(int dataSetCount, bool bMultipoint)
+ : columnCounts_(dataSetCount), bMultipoint_(bMultipoint)
{
}
}
+void AnalysisDataTestInput::setColumnCount(int dataSet, int columnCount)
+{
+ GMX_RELEASE_ASSERT(dataSet >= 0 && dataSet < dataSetCount(),
+ "Out-of-range data set index");
+ columnCounts_[dataSet] = columnCount;
+}
+
+
AnalysisDataTestInputFrame &AnalysisDataTestInput::addFrame(real x)
{
frames_.push_back(AnalysisDataTestInputFrame(frames_.size(), x));
void AnalysisDataTestInput::addFrameWithValues(real x, real y1)
{
AnalysisDataTestInputFrame &frame = addFrame(x);
- frame.addPointSetWithValues(0, y1);
+ frame.addPointSetWithValues(0, 0, y1);
}
void AnalysisDataTestInput::addFrameWithValues(real x, real y1, real y2)
{
AnalysisDataTestInputFrame &frame = addFrame(x);
- frame.addPointSetWithValues(0, y1, y2);
+ frame.addPointSetWithValues(0, 0, y1, y2);
}
void AnalysisDataTestInput::addFrameWithValues(real x, real y1, real y2, real y3)
{
AnalysisDataTestInputFrame &frame = addFrame(x);
- frame.addPointSetWithValues(0, y1, y2, y3);
+ frame.addPointSetWithValues(0, 0, y1, y2, y3);
}
void AnalysisDataTestFixture::setupDataObject(const AnalysisDataTestInput &input,
AnalysisData *data)
{
- data->setColumnCount(input.columnCount());
+ data->setDataSetCount(input.dataSetCount());
+ for (int i = 0; i < input.dataSetCount(); ++i)
+ {
+ data->setColumnCount(i, input.columnCount(i));
+ }
data->setMultipoint(input.isMultipoint());
}
for (int i = 0; i < frame.pointSetCount(); ++i)
{
const AnalysisDataTestInputPointSet &points = frame.pointSet(i);
+ handle.selectDataSet(points.dataSetIndex());
for (int j = 0; j < points.size(); ++j)
{
handle.setPoint(j + points.firstColumn(),
public:
//! Returns zero-based index of this point set in its frame.
int index() const { return index_; }
+ //! Returns zero-based index of the data set of this point set.
+ int dataSetIndex() const { return dataSetIndex_; }
//! Returns zero-based index of the first column in this point set.
int firstColumn() const { return firstColumn_; }
//! Returns zero-based index of the last column in this point set.
private:
//! Creates an empty point set.
- AnalysisDataTestInputPointSet(int index, int firstColumn);
+ AnalysisDataTestInputPointSet(int index, int dataSetIndex,
+ int firstColumn);
int index_;
+ int dataSetIndex_;
int firstColumn_;
std::vector<real> y_;
}
//! Appends an empty point set to this frame.
- AnalysisDataTestInputPointSet &addPointSet(int firstColumn);
+ AnalysisDataTestInputPointSet &addPointSet(int dataSet, int firstColumn);
//! Adds a point set with given values to this frame.
- void addPointSetWithValues(int firstColumn, real y1);
+ void addPointSetWithValues(int dataSet, int firstColumn, real y1);
//! Adds a point set with given values to this frame.
- void addPointSetWithValues(int firstColumn, real y1, real y2);
+ void addPointSetWithValues(int dataSet, int firstColumn,
+ real y1, real y2);
//! Adds a point set with given values to this frame.
- void addPointSetWithValues(int firstColumn, real y1, real y2, real y3);
+ void addPointSetWithValues(int dataSet, int firstColumn,
+ real y1, real y2, real y3);
private:
//! Constructs a new frame object with the given values.
/*! \brief
* Constructs empty input data.
*
- * \param[in] columnCount Number of columns in the data.
+ * \param[in] dataSetCount Number of data sets in the data.
* \param[in] bMultipoint Whether the data will be multipoint.
+ *
+ * The column count for each data set must be set with
+ * setColumnCount().
*/
- AnalysisDataTestInput(int columnCount, bool bMultipoint);
+ AnalysisDataTestInput(int dataSetCount, bool bMultipoint);
~AnalysisDataTestInput();
//! Whether the input data is multipoint.
bool isMultipoint() const { return bMultipoint_; }
- //! Returns the number of columns in the input data.
- int columnCount() const { return columnCount_; }
+ //! Returns the number of data sets in the input data.
+ int dataSetCount() const { return columnCounts_.size(); }
+ //! Returns the number of columns in a given data set.
+ int columnCount(int dataSet) const { return columnCounts_[dataSet]; }
//! Returns the number of frames in the input data.
int frameCount() const { return frames_.size(); }
//! Returns a frame object for the given input frame.
const AnalysisDataTestInputFrame &frame(int index) const;
+ //! Sets the number of columns in a data set.
+ void setColumnCount(int dataSet, int columnCount);
//! Appends an empty frame to this data.
AnalysisDataTestInputFrame &addFrame(real x);
//! Adds a frame with a single point set and the given values.
void addFrameWithValues(real x, real y1, real y2, real y3);
private:
- int columnCount_;
+ std::vector<int> columnCounts_;
bool bMultipoint_;
std::vector<AnalysisDataTestInputFrame> frames_;
};
{
GMX_RELEASE_ASSERT(!input.isMultipoint(),
"Array data cannot be initialized from multipoint data");
- GMX_RELEASE_ASSERT(data->columnCount() == 0 || data->columnCount() == input.columnCount(),
+ GMX_RELEASE_ASSERT(input.dataSetCount() == 1,
+ "Array data cannot be initialized from multiple data sets");
+ GMX_RELEASE_ASSERT(data->columnCount() == 0 || data->columnCount() == input.columnCount(0),
"Mismatching input and target data");
GMX_RELEASE_ASSERT(data->rowCount() == 0 || data->rowCount() == input.frameCount(),
"Mismatching input and target data");
- data->setColumnCount(input.columnCount());
+ data->setColumnCount(input.columnCount(0));
data->setRowCount(input.frameCount());
data->allocateValues();
for (int row = 0; row < input.frameCount(); ++row)
{
SCOPED_TRACE(formatString("Frame %d, point set %d",
frame_->index(), points_->index()));
+ EXPECT_EQ(points_->dataSetIndex(), points.dataSetIndex());
const int expectedFirstColumn
= std::max(0, points_->firstColumn() - firstcol_);
const int expectedLastColumn
MockAnalysisDataModule::setupStaticCheck(const AnalysisDataTestInput &data,
AbstractAnalysisData *source)
{
- GMX_RELEASE_ASSERT(data.columnCount() == source->columnCount(),
- "Mismatching data column count");
- impl_->flags_ |= efAllowMulticolumn | efAllowMultipoint;
+ impl_->flags_ |= efAllowMulticolumn | efAllowMultipoint | efAllowMultipleDataSets;
::testing::InSequence dummy;
using ::testing::_;
for (int ps = 0; ps < frame.pointSetCount(); ++ps)
{
const AnalysisDataTestInputPointSet &points = frame.pointSet(ps);
- EXPECT_CALL(*this, pointsAdded(_))
- .WillOnce(Invoke(StaticDataPointsChecker(&frame, &points, 0,
- data.columnCount())));
+ StaticDataPointsChecker checker(&frame, &points, 0,
+ data.columnCount(points.dataSetIndex()));
+ EXPECT_CALL(*this, pointsAdded(_)).WillOnce(Invoke(checker));
}
EXPECT_CALL(*this, frameFinished(_))
.WillOnce(Invoke(StaticDataFrameHeaderChecker(&frame)));
const AnalysisDataTestInput &data,
int firstcol, int n, AbstractAnalysisData *source)
{
- GMX_RELEASE_ASSERT(data.columnCount() == source->columnCount(),
- "Mismatching data column count");
- GMX_RELEASE_ASSERT(firstcol >= 0 && n > 0 && firstcol + n <= data.columnCount(),
- "Out-of-range columns");
- impl_->flags_ |= efAllowMulticolumn | efAllowMultipoint;
+ impl_->flags_ |= efAllowMulticolumn | efAllowMultipoint | efAllowMultipleDataSets;
::testing::InSequence dummy;
using ::testing::_;
const AnalysisDataTestInput &data,
int storageCount, AbstractAnalysisData *source)
{
- GMX_RELEASE_ASSERT(data.columnCount() == source->columnCount(),
- "Mismatching data column count");
GMX_RELEASE_ASSERT(data.isMultipoint() == source->isMultipoint(),
"Mismatching multipoint properties");
- impl_->flags_ |= efAllowMulticolumn | efAllowMultipoint;
+ impl_->flags_ |= efAllowMulticolumn | efAllowMultipoint | efAllowMultipleDataSets;
::testing::InSequence dummy;
using ::testing::_;