More precise analysisdata histogram accumulation
[alexxy/gromacs.git] / src / gromacs / analysisdata / datastorage.cpp
index 431f2b6c767f5305e910db5023899187ef82d900..370c7b4ab7c4cb876214d37060e0138d9105d00f 100644 (file)
@@ -1,10 +1,10 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 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) 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
@@ -39,6 +39,8 @@
  * \author Teemu Murtola <teemu.murtola@gmail.com>
  * \ingroup module_analysisdata
  */
+#include "gmxpre.h"
+
 #include "datastorage.h"
 
 #include <algorithm>
@@ -176,6 +178,22 @@ class AnalysisDataStorageImpl
         {
             return isMultipoint() && storageLimit_ == 0 && pendingLimit_ == 1;
         }
+        /*! \brief
+         * Returns whether data needs to be stored at all.
+         *
+         * This is used to optimize multipoint handling for parallel cases
+         * (where shouldNotifyImmediately() returns false),
+         * where it is not necessary to store even a single frame.
+         *
+         * \todo
+         * This could be extended to non-multipoint data as well.
+         *
+         * Does not throw.
+         */
+        bool needStorage() const
+        {
+            return storageLimit_ > 0 || (pendingLimit_ > 1 && modules_->hasSerialModules());
+        }
         /*! \brief
          * Calls notification methods for new frames.
          *
@@ -208,6 +226,9 @@ class AnalysisDataStorageImpl
          *
          * Should always be at least one.
          *
+         * \todo
+         * Get rid of this alltogether, as it is no longer used much.
+         *
          * \see AnalysisDataStorage::startFrame()
          */
         int                     pendingLimit_;
@@ -263,7 +284,8 @@ class AnalysisDataStorageImpl
  * AnalysisDataStorageFrameImpl declaration
  */
 
-/*! \internal \brief
+/*! \internal
+ * \brief
  * Internal representation for a single stored frame.
  *
  * It is implemented such that the frame header is always valid, i.e.,
@@ -536,6 +558,7 @@ AnalysisDataStorageImpl::finishFrame(int index)
     GMX_RELEASE_ASSERT(storedFrame.frameIndex() == index,
                        "Inconsistent internal frame indexing");
     builders_.push_back(storedFrame.finishFrame(isMultipoint()));
+    modules_->notifyParallelFrameFinish(storedFrame.header());
     if (shouldNotifyImmediately())
     {
         ++firstUnnotifiedIndex_;
@@ -610,16 +633,17 @@ void
 AnalysisDataStorageFrameData::addPointSet(int dataSetIndex, int firstColumn,
                                           ValueIterator begin, ValueIterator end)
 {
-    const int valueCount  = end - begin;
+    const int                valueCount = end - begin;
+    AnalysisDataPointSetInfo pointSetInfo(0, valueCount,
+                                          dataSetIndex, firstColumn);
+    AnalysisDataPointSetRef  pointSet(header(), pointSetInfo,
+                                      constArrayRefFromVector<AnalysisDataValue>(begin, end));
+    storageImpl().modules_->notifyParallelPointsAdd(pointSet);
     if (storageImpl().shouldNotifyImmediately())
     {
-        AnalysisDataPointSetInfo pointSetInfo(0, valueCount,
-                                              dataSetIndex, firstColumn);
-        storageImpl().modules_->notifyPointsAdd(
-                AnalysisDataPointSetRef(header(), pointSetInfo,
-                                        AnalysisDataValuesRef(begin, end)));
+        storageImpl().modules_->notifyPointsAdd(pointSet);
     }
-    else
+    else if (storageImpl().needStorage())
     {
         pointSets_.push_back(
                 AnalysisDataPointSetInfo(values_.size(), valueCount,
@@ -639,6 +663,10 @@ AnalysisDataStorageFrameData::finishFrame(bool bMultipoint)
                            "Point sets created for non-multipoint data");
         values_ = builder_->values_;
         builder_->clearValues();
+        for (int i = 0; i < pointSetCount(); ++i)
+        {
+            storageImpl().modules_->notifyParallelPointsAdd(pointSet(i));
+        }
     }
     else
     {
@@ -658,7 +686,7 @@ AnalysisDataStorageFrameData::pointSet(int index) const
                "Invalid point set index");
     return AnalysisDataPointSetRef(
             header_, pointSets_[index],
-            AnalysisDataValuesRef(values_.begin(), values_.end()));
+            constArrayRefFromVector<AnalysisDataValue>(values_.begin(), values_.end()));
 }
 
 }   // namespace internal
@@ -776,13 +804,6 @@ AnalysisDataStorage::~AnalysisDataStorage()
 }
 
 
-void
-AnalysisDataStorage::setParallelOptions(const AnalysisDataParallelOptions &opt)
-{
-    impl_->pendingLimit_ = 2 * opt.parallelizationFactor() - 1;
-}
-
-
 int
 AnalysisDataStorage::frameCount() const
 {
@@ -837,7 +858,27 @@ AnalysisDataStorage::startDataStorage(AbstractAnalysisData      *data,
     impl_->modules_ = modules;
     if (!impl_->storeAll())
     {
-        impl_->extendBuffer(impl_->storageLimit_ + impl_->pendingLimit_ + 1);
+        // 2 = pending limit (1) + 1
+        impl_->extendBuffer(impl_->storageLimit_ + 2);
+    }
+}
+
+
+void
+AnalysisDataStorage::startParallelDataStorage(
+        AbstractAnalysisData              *data,
+        AnalysisDataModuleManager         *modules,
+        const AnalysisDataParallelOptions &options)
+{
+    const int pendingLimit = options.parallelizationFactor();
+    impl_->pendingLimit_   = pendingLimit;
+    modules->notifyParallelDataStart(data, options);
+    // Data needs to be set before calling extendBuffer()
+    impl_->data_    = data;
+    impl_->modules_ = modules;
+    if (!impl_->storeAll())
+    {
+        impl_->extendBuffer(impl_->storageLimit_ + pendingLimit + 1);
     }
 }
 
@@ -870,6 +911,7 @@ AnalysisDataStorage::startFrame(const AnalysisDataFrameHeader &header)
     GMX_RELEASE_ASSERT(storedFrame->frameIndex() == header.index(),
                        "Inconsistent internal frame indexing");
     storedFrame->startFrame(header, impl_->getFrameBuilder());
+    impl_->modules_->notifyParallelFrameStart(header);
     if (impl_->shouldNotifyImmediately())
     {
         impl_->modules_->notifyFrameStart(header);