Sort all includes in src/gromacs
[alexxy/gromacs.git] / src / gromacs / analysisdata / abstractdata.cpp
index 301665f0a18fd44db3b1446d312f4077752665b2..9d21ccad6c9c8d890e3d43fedea8db140b02017a 100644 (file)
@@ -1,10 +1,10 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * 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.
+ * Copyright (c) 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_analysisdata
  */
-#include "gromacs/analysisdata/abstractdata.h"
+#include "gmxpre.h"
+
+#include "abstractdata.h"
 
 #include <vector>
 
+#include "gromacs/analysisdata/dataframe.h"
 #include "gromacs/analysisdata/datamodule.h"
+#include "gromacs/analysisdata/datamodulemanager.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/uniqueptr.h"
 
-#include "dataframe.h"
 #include "dataproxy.h"
 
 namespace gmx
@@ -66,138 +69,22 @@ namespace gmx
 class AbstractAnalysisData::Impl
 {
     public:
-        //! Shorthand for list of modules added to the data.
-        typedef std::vector<AnalysisDataModulePointer> ModuleList;
-
         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.
-         * \throws    APIError if all data is not available through
-         *      getDataFrame().
-         * \throws    unspecified Any exception thrown by \p module in its data
-         *      notification methods.
-         *
-         * Uses getDataFrame() in \p data to access all data in the object, and
-         * calls the notification functions in \p module as if the module had
-         * been registered to the data object when the data was added.
-         */
-        void presentData(AbstractAnalysisData        *data,
-                         AnalysisDataModuleInterface *module);
-
         //! Column counts for each data set in the data.
-        std::vector<int>        columnCounts_;
+        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.
-        bool                    bAllowMissing_;
-        //! Whether notifyDataStart() has been called.
-        mutable bool            bDataStart_;
-        //! Whether new data is being added.
-        mutable bool            bInData_;
-        //! Whether data for a frame is being added.
-        mutable bool            bInFrame_;
-        //! Index of the currently active frame.
-        mutable int             currIndex_;
-        /*! \brief
-         * Total number of frames in the data.
-         *
-         * The counter is incremented in notifyFrameFinish().
-         */
-        int                     nframes_;
+        bool                       bMultipoint_;
+        //! Manager for the added modules.
+        AnalysisDataModuleManager  modules_;
 };
 
 AbstractAnalysisData::Impl::Impl()
-    : bMultipoint_(false), bAllowMissing_(true),
-      bDataStart_(false), bInData_(false), bInFrame_(false),
-      currIndex_(-1), nframes_(0)
+    : bMultipoint_(false)
 {
     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,
-                                        AnalysisDataModuleInterface *module)
-{
-    module->dataStarted(data);
-    bool bCheckMissing = bAllowMissing_
-        && !(module->flags() & AnalysisDataModuleInterface::efAllowMissing);
-    for (int i = 0; i < data->frameCount(); ++i)
-    {
-        AnalysisDataFrameRef frame = data->getDataFrame(i);
-        GMX_RELEASE_ASSERT(frame.isValid(), "Invalid data frame returned");
-        // TODO: Check all frames before doing anything for slightly better
-        // exception behavior.
-        if (bCheckMissing && !frame.allPresent())
-        {
-            GMX_THROW(APIError("Missing data not supported by a module"));
-        }
-        module->frameStarted(frame.header());
-        for (int j = 0; j < frame.pointSetCount(); ++j)
-        {
-            module->pointsAdded(frame.pointSet(j));
-        }
-        module->frameFinished(frame.header());
-    }
-    if (!bInData_)
-    {
-        module->dataFinished();
-    }
-}
-
 
 /********************************************************************
  * AbstractAnalysisData
@@ -241,12 +128,6 @@ AbstractAnalysisData::columnCount() const
     return columnCount(0);
 }
 
-int
-AbstractAnalysisData::frameCount() const
-{
-    return impl_->nframes_;
-}
-
 
 AnalysisDataFrameRef
 AbstractAnalysisData::tryGetDataFrame(int index) const
@@ -286,19 +167,7 @@ AbstractAnalysisData::requestStorage(int nframes)
 void
 AbstractAnalysisData::addModule(AnalysisDataModulePointer module)
 {
-    impl_->checkModuleProperties(*module);
-
-    if (impl_->bDataStart_)
-    {
-        GMX_RELEASE_ASSERT(!impl_->bInFrame_,
-                           "Cannot add data modules in mid-frame");
-        impl_->presentData(this, module.get());
-    }
-    if (!(module->flags() & AnalysisDataModuleInterface::efAllowMissing))
-    {
-        impl_->bAllowMissing_ = false;
-    }
-    impl_->modules_.push_back(module);
+    impl_->modules_.addModule(this, module);
 }
 
 
@@ -308,11 +177,6 @@ AbstractAnalysisData::addColumnModule(int col, int span,
 {
     GMX_RELEASE_ASSERT(col >= 0 && span >= 1,
                        "Invalid columns specified for a column module");
-    if (impl_->bDataStart_)
-    {
-        GMX_THROW(NotImplementedError("Cannot add column modules after data"));
-    }
-
     boost::shared_ptr<AnalysisDataProxy> proxy(
             new AnalysisDataProxy(col, span, this));
     proxy->addModule(module);
@@ -323,11 +187,7 @@ AbstractAnalysisData::addColumnModule(int col, int span,
 void
 AbstractAnalysisData::applyModule(AnalysisDataModuleInterface *module)
 {
-    impl_->checkModuleProperties(*module);
-    GMX_RELEASE_ASSERT(impl_->bDataStart_ && !impl_->bInData_,
-                       "Data module can only be applied to ready data");
-
-    impl_->presentData(this, module);
+    impl_->modules_.applyModule(this, module);
 }
 
 /*! \cond libapi */
@@ -335,8 +195,8 @@ void
 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_->modules_.dataPropertyAboutToChange(
+            AnalysisDataModuleManager::eMultipleDataSets, dataSetCount > 1);
     impl_->columnCounts_.resize(dataSetCount);
 }
 
@@ -346,121 +206,36 @@ 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(!impl_->bDataStart_,
-                       "Data column count cannot be changed after data has been added");
-    impl_->columnCounts_[dataSet] = columnCount;
-}
-
-void
-AbstractAnalysisData::setMultipoint(bool multipoint)
-{
-    GMX_RELEASE_ASSERT(!impl_->bDataStart_,
-                       "Data type cannot be changed after data has been added");
-    impl_->bMultipoint_ = multipoint;
-}
-
-
-/*! \internal
- * This method is not const because the dataStarted() methods of the attached
- * modules can request storage of the data.
- */
-void
-AbstractAnalysisData::notifyDataStart()
-{
-    GMX_RELEASE_ASSERT(!impl_->bDataStart_,
-                       "notifyDataStart() called more than once");
-    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)
-    {
-        impl_->checkModuleProperties(**i);
-        (*i)->dataStarted(this);
-    }
-}
-
 
-void
-AbstractAnalysisData::notifyFrameStart(const AnalysisDataFrameHeader &header) const
-{
-    GMX_ASSERT(impl_->bInData_, "notifyDataStart() not called");
-    GMX_ASSERT(!impl_->bInFrame_,
-               "notifyFrameStart() called while inside a frame");
-    GMX_ASSERT(header.index() == impl_->nframes_,
-               "Out of order frames");
-    impl_->bInFrame_  = true;
-    impl_->currIndex_ = header.index();
-
-    Impl::ModuleList::const_iterator i;
-    for (i = impl_->modules_.begin(); i != impl_->modules_.end(); ++i)
+    bool bMultipleColumns = columnCount > 1;
+    for (int i = 0; i < dataSetCount() && !bMultipleColumns; ++i)
     {
-        (*i)->frameStarted(header);
+        if (i != dataSet && this->columnCount(i) > 1)
+        {
+            bMultipleColumns = true;
+        }
     }
+    impl_->modules_.dataPropertyAboutToChange(
+            AnalysisDataModuleManager::eMultipleColumns, bMultipleColumns);
+    impl_->columnCounts_[dataSet] = columnCount;
 }
 
-
 void
-AbstractAnalysisData::notifyPointsAdd(const AnalysisDataPointSetRef &points) const
+AbstractAnalysisData::setMultipoint(bool bMultipoint)
 {
-    GMX_ASSERT(impl_->bInData_, "notifyDataStart() not called");
-    GMX_ASSERT(impl_->bInFrame_, "notifyFrameStart() not called");
-    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())
-    {
-        GMX_THROW(APIError("Missing data not supported by a module"));
-    }
-
-    Impl::ModuleList::const_iterator i;
-    for (i = impl_->modules_.begin(); i != impl_->modules_.end(); ++i)
-    {
-        (*i)->pointsAdded(points);
-    }
+    impl_->modules_.dataPropertyAboutToChange(
+            AnalysisDataModuleManager::eMultipoint, bMultipoint);
+    impl_->bMultipoint_ = bMultipoint;
 }
 
-
-void
-AbstractAnalysisData::notifyFrameFinish(const AnalysisDataFrameHeader &header)
+AnalysisDataModuleManager &AbstractAnalysisData::moduleManager()
 {
-    GMX_ASSERT(impl_->bInData_, "notifyDataStart() not called");
-    GMX_ASSERT(impl_->bInFrame_, "notifyFrameStart() not called");
-    GMX_ASSERT(header.index() == impl_->currIndex_,
-               "Header does not correspond to current frame");
-    impl_->bInFrame_  = false;
-    impl_->currIndex_ = -1;
-
-    // Increment the counter before notifications to allow frame access from
-    // modules.
-    ++impl_->nframes_;
-
-    Impl::ModuleList::const_iterator i;
-    for (i = impl_->modules_.begin(); i != impl_->modules_.end(); ++i)
-    {
-        (*i)->frameFinished(header);
-    }
+    return impl_->modules_;
 }
 
-
-void
-AbstractAnalysisData::notifyDataFinish() const
+const AnalysisDataModuleManager &AbstractAnalysisData::moduleManager() const
 {
-    GMX_RELEASE_ASSERT(impl_->bInData_, "notifyDataStart() not called");
-    GMX_RELEASE_ASSERT(!impl_->bInFrame_,
-                       "notifyDataFinish() called while inside a frame");
-    impl_->bInData_ = false;
-
-    Impl::ModuleList::const_iterator i;
-    for (i = impl_->modules_.begin(); i != impl_->modules_.end(); ++i)
-    {
-        (*i)->dataFinished();
-    }
+    return impl_->modules_;
 }
 //! \endcond