Use frame objects in AnalysisDataModuleInterface.
authorTeemu Murtola <teemu.murtola@gmail.com>
Mon, 26 Dec 2011 07:17:59 +0000 (09:17 +0200)
committerTeemu Murtola <teemu.murtola@gmail.com>
Wed, 22 Feb 2012 05:37:57 +0000 (07:37 +0200)
Instead of passing raw pointers to the internal data in the public
interface, use wrapper objects where the individual values are accessed
through accessor methods.  This makes it easier and more flexible to
change the internal data representation without any code changes in
classes implementing this interface (recompilation may be necessary
because of inlined functions, though).  Similarly, it is easier to
add/change information that is passed through the interface without
touching existing code.

Also added some additional documentation for functors used in analysis
data unit tests.

Part of issue #827.

Change-Id: I08d5b9719c0a14040c3172de39c8620d870382af

25 files changed:
src/gromacs/analysisdata.h
src/gromacs/analysisdata/CMakeLists.txt
src/gromacs/analysisdata/abstractdata-impl.h
src/gromacs/analysisdata/abstractdata.cpp
src/gromacs/analysisdata/abstractdata.h
src/gromacs/analysisdata/analysisdata.cpp
src/gromacs/analysisdata/arraydata.cpp
src/gromacs/analysisdata/dataframe.cpp [new file with mode: 0644]
src/gromacs/analysisdata/dataframe.h [new file with mode: 0644]
src/gromacs/analysisdata/datamodule.h
src/gromacs/analysisdata/dataproxy.cpp
src/gromacs/analysisdata/dataproxy.h
src/gromacs/analysisdata/modules/average.cpp
src/gromacs/analysisdata/modules/average.h
src/gromacs/analysisdata/modules/displacement.cpp
src/gromacs/analysisdata/modules/displacement.h
src/gromacs/analysisdata/modules/histogram-impl.h
src/gromacs/analysisdata/modules/histogram.cpp
src/gromacs/analysisdata/modules/histogram.h
src/gromacs/analysisdata/modules/plot.cpp
src/gromacs/analysisdata/modules/plot.h
src/gromacs/analysisdata/tests/mock_module-impl.h
src/gromacs/analysisdata/tests/mock_module.cpp
src/gromacs/analysisdata/tests/mock_module.h
src/gromacs/trajectoryanalysis/modules/select.cpp

index 0af48c628c9d991ecfa5c4e6a90d7b622ab1bed8..98a5c83b3ffd1e9d5f019d9b5d4ddb8918081ba9 100644 (file)
@@ -49,6 +49,7 @@
 
 #include "analysisdata/analysisdata.h"
 #include "analysisdata/arraydata.h"
+#include "analysisdata/dataframe.h"
 #include "analysisdata/modules/average.h"
 #include "analysisdata/modules/displacement.h"
 #include "analysisdata/modules/histogram.h"
index 69419af28eb66af9ae1698c3fb912ca9956bf82e..71ca6852fd5ab5d3937ad1975d32d75bb0ee6008 100644 (file)
@@ -5,6 +5,7 @@ set(ANALYSISDATA_PUBLIC_HEADERS
     abstractdata.h
     analysisdata.h
     arraydata.h
+    dataframe.h
     datamodule.h)
 install(FILES ${ANALYSISDATA_PUBLIC_HEADERS}
         DESTINATION ${INCL_INSTALL_DIR}/gromacs/analysisdata
index 31d06252996ac03b37788b2ff6de28c5a85ee602..9b754daba00058c10d4f5836b0ec11e9df4b420e 100644 (file)
@@ -42,7 +42,9 @@
 #include <vector>
 
 #include "types/simple.h"
+
 #include "abstractdata.h"
+#include "dataframe.h"
 
 namespace gmx
 {
@@ -88,10 +90,8 @@ class AbstractAnalysisData::Impl
         bool                    _bInFrame;
         //! true if all modules support missing data.
         bool                    _bAllowMissing;
-        //! x value for the current frame.
-        real                    _currx;
-        //! dx value for the current frame.
-        real                    _currdx;
+        //! Header data for the current frame.
+        AnalysisDataFrameHeader _currHeader;
         /*! \brief
          * Total number of frames in the data.
          *
index de562e5c848cc47cc434316f3b8caa89c3767a5d..9aea45af05016b315a1d469c0a16a820c24c9423 100644 (file)
@@ -46,6 +46,7 @@
 #include "gromacs/fatalerror/gmxassert.h"
 
 #include "abstractdata-impl.h"
+#include "dataframe.h"
 #include "dataproxy.h"
 
 namespace gmx
@@ -99,8 +100,10 @@ AbstractAnalysisData::Impl::presentData(AbstractAnalysisData *data,
                 }
             }
         }
-        module->frameStarted(x, dx);
-        module->pointsAdded(x, dx, 0, ncol, y, dy, present);
+        AnalysisDataFrameHeader header(i, x, dx);
+        module->frameStarted(header);
+        module->pointsAdded(
+                AnalysisDataPointSetRef(header, 0, ncol, y, dy, present));
         module->frameFinished();
     }
     if (!_bInData)
@@ -257,52 +260,56 @@ AbstractAnalysisData::notifyDataStart()
 
 
 void
-AbstractAnalysisData::notifyFrameStart(real x, real dx) const
+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->_currx  = x;
-    _impl->_currdx = dx;
+    _impl->_currHeader = header;
     ++_impl->_nframes;
 
     Impl::ModuleList::const_iterator i;
     for (i = _impl->_modules.begin(); i != _impl->_modules.end(); ++i)
     {
-        (*i)->frameStarted(x, dx);
+        (*i)->frameStarted(header);
     }
 }
 
 
 void
-AbstractAnalysisData::notifyPointsAdd(int firstcol, int n,
-                                      const real *y, const real *dy,
-                                      const bool *present) const
+AbstractAnalysisData::notifyPointsAdd(const AnalysisDataPointSetRef &points) const
 {
     GMX_ASSERT(_impl->_bInData, "notifyDataStart() not called");
     GMX_ASSERT(_impl->_bInFrame, "notifyFrameStart() not called");
-    GMX_ASSERT(firstcol >= 0 && n > 0 && firstcol + n <= _ncol, "Invalid column");
-    if (present && !_impl->_bAllowMissing)
+    GMX_ASSERT(points.lastColumn() < columnCount(), "Invalid columns");
+    GMX_ASSERT(points.frameIndex() == _impl->_currHeader.index(),
+               "Points do not correspond to current frame");
+    if (!_impl->_bAllowMissing && !points.allPresent())
     {
-        for (int i = 0; i < n; ++i)
-        {
-            if (!present[i])
-            {
-                GMX_THROW(APIError("Missing data not supported by a module"));
-            }
-        }
+        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(_impl->_currx, _impl->_currdx, firstcol, n,
-                          y, dy, present);
+        (*i)->pointsAdded(points);
     }
 }
 
 
+void
+AbstractAnalysisData::notifyPointsAdd(int firstcol, int n,
+                                      const real *y, const real *dy,
+                                      const bool *present) const
+{
+    notifyPointsAdd(AnalysisDataPointSetRef(
+            _impl->_currHeader, firstcol, n, y, dy, present));
+}
+
+
 void
 AbstractAnalysisData::notifyFrameFinish() const
 {
@@ -521,7 +528,7 @@ AbstractAnalysisDataStored::startDataStore()
 
 
 void
-AbstractAnalysisDataStored::startNextFrame(real x, real dx)
+AbstractAnalysisDataStored::startNextFrame(const AnalysisDataFrameHeader &header)
 {
     // Start storing the frame if needed.
     if (_impl->_nalloc > 0)
@@ -546,12 +553,13 @@ AbstractAnalysisDataStored::startNextFrame(real x, real dx)
             }
         }
 
-        _impl->_store[_impl->_nextind]->_x  = x;
-        _impl->_store[_impl->_nextind]->_dx = dx;
+        _impl->_store[_impl->_nextind]->_index = header.index();
+        _impl->_store[_impl->_nextind]->_x     = header.x();
+        _impl->_store[_impl->_nextind]->_dx    = header.dx();
     }
 
     // Notify any modules.
-    notifyFrameStart(x, dx);
+    notifyFrameStart(header);
 }
 
 
@@ -596,7 +604,7 @@ void
 AbstractAnalysisDataStored::storeNextFrame(real x, real dx, const real *y,
                                            const real *dy, const bool *present)
 {
-    startNextFrame(x, dx);
+    startNextFrame(AnalysisDataFrameHeader(frameCount(), x, dx));
     storeThisFrame(y, dy, present);
 }
 
index 884ab055182311aaf5c9f4510a19dd720d72465a..0a9b055de1187bcc48602430bef2a0a522f51df2 100644 (file)
@@ -45,6 +45,8 @@ namespace gmx
 {
 
 class AnalysisDataModuleInterface;
+class AnalysisDataFrameHeader;
+class AnalysisDataPointSetRef;
 
 /*! \brief
  * Abstract base class for all objects that provide data.
@@ -275,9 +277,9 @@ class AbstractAnalysisData
          * Notifies attached modules of the start of a frame.
          *
          * Should be called once for each frame, before notifyPointsAdd() calls
-         * for thet frame.
+         * for that frame.
          */
-        void notifyFrameStart(real x, real dx) const;
+        void notifyFrameStart(const AnalysisDataFrameHeader &header) const;
         /*! \brief
          * Notifies attached modules of the addition of points to the
          * current frame.
@@ -290,6 +292,13 @@ class AbstractAnalysisData
          * even the whole frame in a single call rather than calling the method
          * for each column separately.
          */
+        void notifyPointsAdd(const AnalysisDataPointSetRef &points) const;
+        /*! \brief
+         * Deprecated convenience method for not needing to construct a
+         * AnalysisDataPointSetRef object.
+         *
+         * Will be removed as part of future work.
+         */
         void notifyPointsAdd(int firstcol, int n,
                              const real *y, const real *dy,
                              const bool *present) const;
@@ -367,7 +376,7 @@ class AbstractAnalysisDataStored : public AbstractAnalysisData
         //! Start storing data.
         void startDataStore();
         //! Starts storing a next frame.
-        void startNextFrame(real x, real dx);
+        void startNextFrame(const AnalysisDataFrameHeader &header);
         //! Stores the whole frame in a single call after start_next_frame().
         void storeThisFrame(const real *y, const real *dy, const bool *present);
         //! Convenience function for storing a whole frame in a single call.
index 7b756a8a935cd07f2d8719213038c9e1e2c1f02c..b7f18d4c2751f5172ab830af8a0bd1bbd8c5ec88 100644 (file)
@@ -40,6 +40,7 @@
 #include <algorithm>
 #include <memory>
 
+#include "gromacs/analysisdata/dataframe.h"
 #include "gromacs/fatalerror/exceptions.h"
 #include "gromacs/fatalerror/gmxassert.h"
 
@@ -266,7 +267,7 @@ AnalysisDataHandle::startFrame(int index, real x, real dx)
 {
     if (_impl->_data.isMultipoint())
     {
-        _impl->_data.notifyFrameStart(x, dx);
+        _impl->_data.notifyFrameStart(AnalysisDataFrameHeader(index, x, dx));
     }
     else
     {
index 003c8601cacc6953ed2c38148c0c2471d357d7b6..30f5d6f36ad02c39e238d8a011d5496a1c785d54 100644 (file)
@@ -39,6 +39,7 @@
 
 #include <algorithm>
 
+#include "gromacs/analysisdata/dataframe.h"
 #include "gromacs/fatalerror/exceptions.h"
 #include "gromacs/fatalerror/gmxassert.h"
 
@@ -156,9 +157,11 @@ AbstractAnalysisArrayData::valuesReady()
     notifyDataStart();
     for (int i = 0; i < rowCount(); ++i)
     {
-        notifyFrameStart(xvalue(i), 0);
-        notifyPointsAdd(0, columnCount(), &_value[i * columnCount()],
-                        NULL, NULL);
+        AnalysisDataFrameHeader header(i, xvalue(i), 0);
+        notifyFrameStart(header);
+        notifyPointsAdd(AnalysisDataPointSetRef(header, 0, columnCount(),
+                                                &_value[i * columnCount()],
+                                                NULL, NULL));
         notifyFrameFinish();
     }
     notifyDataFinish();
diff --git a/src/gromacs/analysisdata/dataframe.cpp b/src/gromacs/analysisdata/dataframe.cpp
new file mode 100644 (file)
index 0000000..0c8ec1b
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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
+ */
+/*! \internal \file
+ * \brief
+ * Implements classes in dataframe.h.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_analysisdata
+ */
+#include "dataframe.h"
+
+#include "gromacs/fatalerror/gmxassert.h"
+
+namespace gmx
+{
+
+/********************************************************************
+ * AnalysisDataFrameHeader
+ */
+
+AnalysisDataFrameHeader::AnalysisDataFrameHeader()
+    : index_(-1), x_(0.0), dx_(0.0)
+{
+}
+
+
+AnalysisDataFrameHeader::AnalysisDataFrameHeader(int index, real x, real dx)
+    : index_(index), x_(x), dx_(dx)
+{
+    GMX_ASSERT(index >= 0, "Invalid frame index");
+}
+
+
+/********************************************************************
+ * AnalysisDataPointSetRef
+ */
+
+AnalysisDataPointSetRef::AnalysisDataPointSetRef(
+        int index, real x, real dx, int firstColumn, int columnCount,
+        const real *y, const real *dy, const bool *present)
+    : header_(index, x, dx), firstColumn_(firstColumn), columnCount_(columnCount),
+      y_(y), dy_(dy), present_(present)
+{
+    GMX_ASSERT(firstColumn >= 0, "Invalid first column");
+    GMX_ASSERT(columnCount >= 0, "Invalid column count");
+    GMX_ASSERT(columnCount == 0 || y_ != NULL,
+               "Values must be provided if there are columns");
+}
+
+
+AnalysisDataPointSetRef::AnalysisDataPointSetRef(
+        const AnalysisDataFrameHeader &header, int firstColumn, int columnCount,
+        const real *y, const real *dy, const bool *present)
+    : header_(header), firstColumn_(firstColumn), columnCount_(columnCount),
+      y_(y), dy_(dy), present_(present)
+{
+    GMX_ASSERT(firstColumn >= 0, "Invalid first column");
+    GMX_ASSERT(columnCount >= 0, "Invalid column count");
+    GMX_ASSERT(columnCount == 0 || y_ != NULL,
+               "Values must be provided if there are columns");
+}
+
+
+AnalysisDataPointSetRef::AnalysisDataPointSetRef(
+        const AnalysisDataPointSetRef &points, int firstColumn, int columnCount)
+    : header_(points.header()), firstColumn_(0), columnCount_(columnCount),
+      y_(points.y_), dy_(points.dy_), present_(points.present_)
+{
+    GMX_ASSERT(firstColumn >= 0, "Invalid first column");
+    GMX_ASSERT(columnCount >= 0, "Invalid column count");
+    if (points.lastColumn() < firstColumn
+        || points.firstColumn() >= firstColumn + columnCount
+        || columnCount == 0)
+    {
+        columnCount_ = 0;
+        return;
+    }
+    int newFirstColumn = firstColumn - points.firstColumn();
+    if (newFirstColumn > 0)
+    {
+        // Offset pointers if the first column is not the first in points.
+        y_ += newFirstColumn;
+        if (dy_ != NULL)
+        {
+            dy_ += newFirstColumn;
+        }
+        if (present_ != NULL)
+        {
+            present_ += newFirstColumn;
+        }
+        newFirstColumn = 0;
+    }
+    else
+    {
+        // Take into account if first column is before the first in points.
+        columnCount_ -= -newFirstColumn;
+    }
+    // Decrease column count if there are not enough columns in points.
+    if (newFirstColumn + columnCount_ > points.columnCount())
+    {
+        columnCount_ = points.columnCount() - newFirstColumn;
+    }
+}
+
+
+bool AnalysisDataPointSetRef::allPresent() const
+{
+    if (present_ != NULL)
+    {
+        for (int i = 0; i < columnCount(); ++i)
+        {
+            if (!present_[i])
+            {
+                return false;
+            }
+        }
+    }
+    return true;
+}
+
+} // namespace gmx
diff --git a/src/gromacs/analysisdata/dataframe.h b/src/gromacs/analysisdata/dataframe.h
new file mode 100644 (file)
index 0000000..bbff599
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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
+ */
+/*! \file
+ * \brief
+ * Declares classes for accessing data frame information.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \inpublicapi
+ * \ingroup module_analysisdata
+ */
+#ifndef GMX_ANALYSISDATA_DATAFRAME_H
+#define GMX_ANALYSISDATA_DATAFRAME_H
+
+#include <cstddef>
+
+#include "../legacyheaders/types/simple.h"
+
+#include "../fatalerror/gmxassert.h"
+
+namespace gmx
+{
+
+/*! \brief
+ * Value type for storing frame-level information for analysis data.
+ *
+ * Default copy constructor and assignment operator are used and work as
+ * intended.
+ * Typically new objects of this type are only constructed internally by the
+ * library and in classes that are derived from AbstractAnalysisData.
+ *
+ * Methods in this class do not throw, but may contain asserts for incorrect
+ * usage.
+ *
+ * \inpublicapi
+ * \ingroup module_analysisdata
+ */
+class AnalysisDataFrameHeader
+{
+    public:
+        /*! \brief
+         * Constructs an invalid frame header.
+         *
+         * Return values of other methods than isValid() are unspecified for
+         * the constructed object.
+         */
+        AnalysisDataFrameHeader();
+        /*! \brief
+         * Constructs a frame header from given values.
+         *
+         * \param[in] index  Index of the frame. Must be >= 0.
+         * \param[in] x      x coordinate for the frame.
+         * \param[in] dx     Error estimate for x.
+         */
+        AnalysisDataFrameHeader(int index, real x, real dx);
+
+        /*! \brief
+         * Returns whether the frame header corresponds to a valid frame.
+         *
+         * If returns false, return values of other methods are not specified.
+         */
+        bool isValid() const
+        {
+            return index_ >= 0;
+        }
+        /*! \brief
+         * Returns zero-based index of the frame.
+         *
+         * The return value is >= 0 for valid frames.
+         * Should not be called for invalid frames.
+         */
+        int index() const
+        {
+            GMX_ASSERT(isValid(), "Tried to access invalid frame header");
+            return index_;
+        }
+        /*! \brief
+         * Returns the x coordinate for the frame.
+         *
+         * Should not be called for invalid frames.
+         */
+        real x() const
+        {
+            GMX_ASSERT(isValid(), "Tried to access invalid frame header");
+            return x_;
+        }
+        /*! \brief
+         * Returns error in the x coordinate for the frame (if applicable).
+         *
+         * All data do not provide error estimates.
+         * Typically returns zero in those cases.
+         *
+         * Should not be called for invalid frames.
+         */
+        real dx() const
+        {
+            GMX_ASSERT(isValid(), "Tried to access invalid frame header");
+            return dx_;
+        }
+
+    private:
+        int                     index_;
+        real                    x_;
+        real                    dx_;
+};
+
+
+/*! \brief
+ * Value type wrapper for non-mutable access to a set of data column values.
+ *
+ * Default copy constructor and assignment operator are used and work as
+ * intended.
+ * Typically new objects of this type are only constructed internally by the
+ * library and in classes that are derived from AbstractAnalysisData.
+ *
+ * Methods in this class do not throw, but may contain asserts for incorrect
+ * usage.
+ *
+ * \inpublicapi
+ * \ingroup module_analysisdata
+ */
+class AnalysisDataPointSetRef
+{
+    public:
+        /*! \brief
+         * Constructs a point set reference from given values.
+         *
+         * \param[in] index       Index of the frame. Must be >= 0.
+         * \param[in] x           x coordinate for the frame.
+         * \param[in] dx          Error estimate for x.
+         * \param[in] firstColumn Zero-based index of the first column.
+         *     Must be >= 0.
+         * \param[in] columnCount Number of columns to include.
+         * \param[in] y           Array of values for each column.
+         *     Must not be NULL if columnCount > 0.
+         * \param[in] dy          Array of error estimates for corresponding y.
+         *     Can be NULL, in which case errors cannot be accessed.
+         * \param[in] present     Array of flags giving presence of each point.
+         *     Can be NULL, in which case all values are treated as present.
+         *
+         * Arrays \p y, \p dy and \p dy should all have \p columnCount
+         * elements.  The first elements in these arrays should correspond to
+         * \p firstColumn.
+         */
+        AnalysisDataPointSetRef(int index, real x, real dx,
+                                int firstColumn, int columnCount,
+                                const real *y, const real *dy,
+                                const bool *present);
+        /*! \brief
+         * Constructs a point set reference from given values.
+         *
+         * \param[in] header      Header for the frame.
+         * \param[in] firstColumn Zero-based index of the first column.
+         *     Must be >= 0.
+         * \param[in] columnCount Number of columns to include.
+         * \param[in] y           Array of values for each column.
+         *     Must not be NULL if columnCount > 0.
+         * \param[in] dy          Array of error estimates for corresponding y.
+         *     Can be NULL, in which case errors cannot be accessed.
+         * \param[in] present     Array of flags giving presence of each point.
+         *     Can be NULL, in which case all values are treated as present.
+         *
+         * Arrays \p y, \p dy and \p dy should all have \p columnCount
+         * elements.  The first elements in these arrays should correspond to
+         * \p firstColumn.
+         */
+        AnalysisDataPointSetRef(const AnalysisDataFrameHeader &header,
+                                int firstColumn, int columnCount,
+                                const real *y, const real *dy,
+                                const bool *present);
+        /*! \brief
+         * Constructs a point set reference to a subset of columns.
+         *
+         * \param[in] points      Point set to use as source.
+         * \param[in] firstColumn First column index to include.
+         * \param[in] columnCount Number of columns to include.
+         *
+         * Creates a point set that contains \p columnCount columns starting
+         * from \p firstColumn from \p points, or a subset all requested
+         * columns are not present in \p points.  If the requested column range
+         * and the range in \p points do not intersect, the result has
+         * columnCount() == 0.
+         *
+         * \p firstColumn is relative to the whole data set, i.e., not relative
+         * to points.firstColumn().
+         *
+         * Mainly intended for internal use.
+         */
+        AnalysisDataPointSetRef(const AnalysisDataPointSetRef &points,
+                                int firstColumn, int columnCount);
+
+        /*! \brief
+         * Returns the frame header for the frame of this point set.
+         */
+        const AnalysisDataFrameHeader &header() const
+        {
+            return header_;
+        }
+        //! \copydoc AnalysisDataFrameHeader::index()
+        int frameIndex() const
+        {
+            return header_.index();
+        }
+        //! \copydoc AnalysisDataFrameHeader::x()
+        real x() const
+        {
+            return header_.x();
+        }
+        //! \copydoc AnalysisDataFrameHeader::dx()
+        real dx() const
+        {
+            return header_.dx();
+        }
+        //! Returns zero-based index of the first column included in this set.
+        int firstColumn() const
+        {
+            return firstColumn_;
+        }
+        //! Returns the number of columns included in this set.
+        int columnCount() const
+        {
+            return columnCount_;
+        }
+        //! Returns zero-based index of the last column included in this set (inclusive).
+        int lastColumn() const
+        {
+            return firstColumn_ + columnCount_ - 1;
+        }
+        /*! \brief
+         * Returns data value for a column in this set.
+         *
+         * \param[in] i  Zero-based column index relative to firstColumn().
+         *     Should be >= 0 and < columnCount().
+         */
+        real y(int i) const
+        {
+            GMX_ASSERT(i >= 0 && i < columnCount_, "Out of range data access");
+            return y_[i];
+        }
+        /*! \brief
+         * Returns error estimate for a column in this set if applicable.
+         *
+         * \param[in] i  Zero-based column index relative to firstColumn().
+         *     Should be >= 0 and < columnCount().
+         *
+         * Currently, this method either asserts or returns zero if the source
+         * data does not specify errors.
+         */
+        real dy(int i) const
+        {
+            GMX_ASSERT(dy_ != NULL, "Errors not present, but accessed");
+            GMX_ASSERT(i >= 0 && i < columnCount_, "Out of range data access");
+            return dy_[i];
+        }
+        /*! \brief
+         * Returns whether a column is present in this set.
+         *
+         * \param[in] i  Zero-based column index relative to firstColumn().
+         *     Should be >= 0 and < columnCount().
+         *
+         * If present(i) returns false, it is depends on the source data
+         * whether y(i) and/or dy(i) are defined.
+         */
+        bool present(int i) const
+        {
+            GMX_ASSERT(i >= 0 && i < columnCount_, "Out of range data access");
+            return present_ == NULL || present_[i];
+        }
+        /*! \brief
+         * Returns true if all points in this point set are present.
+         *
+         * That is, if present() would return true for all points.
+         */
+        bool allPresent() const;
+
+    private:
+        AnalysisDataFrameHeader header_;
+        int                     firstColumn_;
+        int                     columnCount_;
+        const real             *y_;
+        const real             *dy_;
+        const bool             *present_;
+};
+
+} // namespace gmx
+
+#endif
index 107877fc967a430313e55e7d8bb2fbb80da4496f..3bb262aa0633e1ab73fc8d0ddec5cfdafbe5e7f4 100644 (file)
@@ -45,6 +45,8 @@ namespace gmx
 {
 
 class AbstractAnalysisData;
+class AnalysisDataFrameHeader;
+class AnalysisDataPointSetRef;
 
 /*! \brief
  * Interface for a module that gets notified whenever data is added.
@@ -108,20 +110,11 @@ class AnalysisDataModuleInterface
         /*! \brief
          * Called at the start of each data frame.
          */
-        virtual void frameStarted(real x, real dx) = 0;
+        virtual void frameStarted(const AnalysisDataFrameHeader &frame) = 0;
         /*! \brief
          * Called one or more times during each data frame.
-         *
-         * For convenience, the \p x and \p dx values for the frame are
-         * passed to each call of this function.
-         *
-         * \todo
-         * For more flexibility, this function should take a data row/frame
-         * object, which could be used to access all relevant data.
          */
-        virtual void pointsAdded(real x, real dx, int firstcol, int n,
-                                 const real *y, const real *dy,
-                                 const bool *present) = 0;
+        virtual void pointsAdded(const AnalysisDataPointSetRef &points) = 0;
         /*! \brief
          * Called when a data frame is finished.
          */
index 60828b6a03a154332a856c61dabc56f87c8eae65..a531a561cb0a4dc35aec357d3d26914fdf9552c0 100644 (file)
@@ -37,6 +37,7 @@
  */
 #include "dataproxy.h"
 
+#include "gromacs/analysisdata/dataframe.h"
 #include "gromacs/fatalerror/gmxassert.h"
 
 namespace gmx
@@ -110,44 +111,20 @@ AnalysisDataProxy::dataStarted(AbstractAnalysisData *data)
 
 
 void
-AnalysisDataProxy::frameStarted(real x, real dx)
+AnalysisDataProxy::frameStarted(const AnalysisDataFrameHeader &frame)
 {
-    notifyFrameStart(x, dx);
+    notifyFrameStart(frame);
 }
 
 
 void
-AnalysisDataProxy::pointsAdded(real x, real dx, int firstcol, int n,
-                               const real *y, const real *dy,
-                               const bool *missing)
+AnalysisDataProxy::pointsAdded(const AnalysisDataPointSetRef &points)
 {
-    if (firstcol + n <= _col || firstcol >= _col + _span)
+    AnalysisDataPointSetRef columns(points, _col, _span);
+    if (columns.columnCount() > 0)
     {
-        return;
+        notifyPointsAdd(columns);
     }
-    firstcol -= _col;
-    if (firstcol < 0)
-    {
-        if (y)
-        {
-            y +=  -firstcol;
-        }
-        if (dy)
-        {
-            dy += -firstcol;
-        }
-        if (missing)
-        {
-            missing += -firstcol;
-        }
-        n -= -firstcol;
-        firstcol = 0;
-    }
-    if (firstcol + n > _span)
-    {
-        n = _span - firstcol;
-    }
-    notifyPointsAdd(firstcol, n, y, dy, missing);
 }
 
 
index d9237cf06d54c4801f7f8218def3c0fcf0d3a829..cbd857bb36ba1779b75bc324151ce649a3b5e6c2 100644 (file)
@@ -74,10 +74,8 @@ class AnalysisDataProxy : public AbstractAnalysisData,
         virtual int flags() const;
 
         virtual void dataStarted(AbstractAnalysisData *data);
-        virtual void frameStarted(real x, real dx);
-        virtual void pointsAdded(real x, real dx, int firstcol, int n,
-                                 const real *y, const real *dy,
-                                 const bool *missing);
+        virtual void frameStarted(const AnalysisDataFrameHeader &frame);
+        virtual void pointsAdded(const AnalysisDataPointSetRef &points);
         virtual void frameFinished();
         virtual void dataFinished();
 
index a79ce5ba438c779277776a09cac5fe4db8cc0c63..cc73dd0286d7e6954a0a5266bef1e591ad1ecaa1 100644 (file)
@@ -43,6 +43,7 @@
 #include "smalloc.h"
 
 #include "gromacs/basicmath.h"
+#include "gromacs/analysisdata/dataframe.h"
 
 namespace gmx
 {
@@ -78,22 +79,22 @@ AnalysisDataAverageModule::dataStarted(AbstractAnalysisData *data)
 
 
 void
-AnalysisDataAverageModule::frameStarted(real x, real dx)
+AnalysisDataAverageModule::frameStarted(const AnalysisDataFrameHeader & /*header*/)
 {
 }
 
 
 void
-AnalysisDataAverageModule::pointsAdded(real x, real dx, int firstcol, int n,
-                                       const real *y, const real *dy,
-                                       const bool *present)
+AnalysisDataAverageModule::pointsAdded(const AnalysisDataPointSetRef &points)
 {
-    for (int i = 0; i < n; ++i)
+    int firstcol = points.firstColumn();
+    for (int i = 0; i < points.columnCount(); ++i)
     {
-        if (!present || present[i])
+        if (points.present(i))
         {
-            value(firstcol + i, 0)  += y[i];
-            value(firstcol + i, 1)  += y[i] * y[i];
+            real y = points.y(i);
+            value(firstcol + i, 0)  += y;
+            value(firstcol + i, 1)  += y * y;
             _nsamples[firstcol + i] += 1;
         }
     }
index 644ddaa3af1f39d8007e219315452b12ced115f6..7b2512cce281438706d701353027015225420895 100644 (file)
@@ -72,10 +72,8 @@ class AnalysisDataAverageModule : public AbstractAnalysisArrayData,
         virtual int flags() const;
 
         virtual void dataStarted(AbstractAnalysisData *data);
-        virtual void frameStarted(real x, real dx);
-        virtual void pointsAdded(real x, real dx, int firstcol, int n,
-                                 const real *y, const real *dy,
-                                 const bool *present);
+        virtual void frameStarted(const AnalysisDataFrameHeader &header);
+        virtual void pointsAdded(const AnalysisDataPointSetRef &points);
         virtual void frameFinished();
         virtual void dataFinished();
 
index ffeae34f64ad8431f4c280743693de36fc0b7e62..06dd48bf006b5a744d61466cfde5d0dbfcc3989a 100644 (file)
@@ -44,8 +44,9 @@
 // Legacy include.
 #include "smalloc.h"
 
-#include "gromacs/analysisdata/modules/histogram.h"
 #include "gromacs/basicmath.h"
+#include "gromacs/analysisdata/dataframe.h"
+#include "gromacs/analysisdata/modules/histogram.h"
 #include "gromacs/fatalerror/exceptions.h"
 #include "gromacs/fatalerror/gmxassert.h"
 
@@ -146,16 +147,16 @@ AnalysisDataDisplacementModule::dataStarted(AbstractAnalysisData *data)
 
 
 void
-AnalysisDataDisplacementModule::frameStarted(real x, real dx)
+AnalysisDataDisplacementModule::frameStarted(const AnalysisDataFrameHeader &header)
 {
     // Initialize times.
     if (_impl->bFirst)
     {
-        _impl->t0 = x;
+        _impl->t0 = header.x();
     }
     else if (_impl->dt <= 0)
     {
-        _impl->dt = x - _impl->t0;
+        _impl->dt = header.x() - _impl->t0;
         if (_impl->dt < 0 || gmx_within_tol(_impl->dt, 0.0, GMX_REAL_EPS))
         {
             GMX_THROW(APIError("Identical or decreasing frame times"));
@@ -163,12 +164,12 @@ AnalysisDataDisplacementModule::frameStarted(real x, real dx)
     }
     else
     {
-        if (!gmx_within_tol(x - _impl->t, _impl->dt, GMX_REAL_EPS))
+        if (!gmx_within_tol(header.x() - _impl->t, _impl->dt, GMX_REAL_EPS))
         {
             GMX_THROW(APIError("Frames not evenly spaced"));
         }
     }
-    _impl->t = x;
+    _impl->t = header.x();
 
     // Allocate memory for all the positions once it is possible.
     if (_impl->max_store == -1 && !_impl->bFirst)
@@ -196,17 +197,16 @@ AnalysisDataDisplacementModule::frameStarted(real x, real dx)
 
 
 void
-AnalysisDataDisplacementModule::pointsAdded(real x, real dx, int firstcol, int n,
-                                            const real *y, const real *dy,
-                                            const bool *present)
+AnalysisDataDisplacementModule::pointsAdded(const AnalysisDataPointSetRef &points)
 {
-    if (firstcol % _impl->ndim != 0 || n % _impl->ndim != 0)
+    if (points.firstColumn() % _impl->ndim != 0
+        || points.columnCount() % _impl->ndim != 0)
     {
         GMX_THROW(APIError("Partial data points"));
     }
-    for (int i = firstcol; i < firstcol + n; ++i)
+    for (int i = 0; i < points.columnCount(); ++i)
     {
-        _impl->oldval[_impl->ci + i] = y[i];
+        _impl->oldval[_impl->ci + points.firstColumn() + i] = points.y(i);
     }
 }
 
@@ -231,7 +231,8 @@ AnalysisDataDisplacementModule::frameFinished()
         }
         notifyDataStart();
     }
-    notifyFrameStart(_impl->t, 0);
+    AnalysisDataFrameHeader header(_impl->nstored - 2, _impl->t, 0);
+    notifyFrameStart(header);
 
     for (i = _impl->ci - _impl->nmax, step = 1;
          step < _impl->nstored && i != _impl->ci;
@@ -254,7 +255,8 @@ AnalysisDataDisplacementModule::frameFinished()
             }
             _impl->currd[k] = dist2;
         }
-        notifyPointsAdd(0, k, _impl->currd, NULL, NULL);
+        notifyPointsAdd(AnalysisDataPointSetRef(
+                header, 0, k, _impl->currd, NULL, NULL));
     }
 
     notifyFrameFinish();
index 6a0d9a07722724327e9aa3fdce17d015289464b5..fdc7388efd7f5fb2345a996f554eb7307ea10610 100644 (file)
@@ -87,10 +87,8 @@ class AnalysisDataDisplacementModule : public AbstractAnalysisData,
         virtual int flags() const;
 
         virtual void dataStarted(AbstractAnalysisData *data);
-        virtual void frameStarted(real x, real dx);
-        virtual void pointsAdded(real x, real dx, int firstcol, int n,
-                                 const real *y, const real *dy,
-                                 const bool *present);
+        virtual void frameStarted(const AnalysisDataFrameHeader &header);
+        virtual void pointsAdded(const AnalysisDataPointSetRef &points);
         virtual void frameFinished();
         virtual void dataFinished();
 
index 7b3e497888db975ed3990519d6474690df0c155a..7dc0c6f1e0ff04681c7409691879c00f85b06ec7 100644 (file)
@@ -88,10 +88,8 @@ class BasicAverageHistogramModule : public AbstractAverageHistogram,
         virtual int flags() const;
 
         virtual void dataStarted(AbstractAnalysisData *data);
-        virtual void frameStarted(real x, real dx);
-        virtual void pointsAdded(real x, real dx, int firstcol, int n,
-                                 const real *y, const real *dy,
-                                 const bool *present);
+        virtual void frameStarted(const AnalysisDataFrameHeader &header);
+        virtual void pointsAdded(const AnalysisDataPointSetRef &points);
         virtual void frameFinished();
         virtual void dataFinished();
 
index cc4e3f8c8e418ec4658372c7d5834d9ba7f3249d..25a90727c65bd88a4451e58b722bbfed33b855bd 100644 (file)
@@ -44,6 +44,7 @@
 #include <memory>
 
 #include "gromacs/basicmath.h"
+#include "gromacs/analysisdata/dataframe.h"
 #include "gromacs/fatalerror/exceptions.h"
 #include "gromacs/fatalerror/gmxassert.h"
 
@@ -368,20 +369,20 @@ BasicAverageHistogramModule::dataStarted(AbstractAnalysisData *data)
 
 
 void
-BasicAverageHistogramModule::frameStarted(real /*x*/, real /*dx*/)
+BasicAverageHistogramModule::frameStarted(const AnalysisDataFrameHeader & /*header*/)
 {
 }
 
 
 void
-BasicAverageHistogramModule::pointsAdded(real x, real dx, int firstcol, int n,
-                                         const real *y, const real *dy,
-                                         const bool *present)
+BasicAverageHistogramModule::pointsAdded(const AnalysisDataPointSetRef &points)
 {
-    for (int i = 0; i < n; ++i)
+    int firstcol = points.firstColumn();
+    for (int i = 0; i < points.columnCount(); ++i)
     {
-        value(firstcol + i, 0) += y[i];
-        value(firstcol + i, 1) += y[i] * y[i];
+        real y = points.y(i);
+        value(firstcol + i, 0) += y;
+        value(firstcol + i, 1) += y * y;
     }
 }
 
@@ -512,22 +513,19 @@ AnalysisDataSimpleHistogramModule::dataStarted(AbstractAnalysisData *data)
 
 
 void
-AnalysisDataSimpleHistogramModule::frameStarted(real x, real dx)
+AnalysisDataSimpleHistogramModule::frameStarted(const AnalysisDataFrameHeader &header)
 {
     std::fill(impl_->hist_.begin(), impl_->hist_.end(), 0.0);
-    startNextFrame(x, dx);
+    startNextFrame(header);
 }
 
 
 void
-AnalysisDataSimpleHistogramModule::pointsAdded(real /*x*/, real /*dx*/,
-                                               int /*firstcol*/, int n,
-                                               const real *y, const real * /*dy*/,
-                                               const bool * /*present*/)
+AnalysisDataSimpleHistogramModule::pointsAdded(const AnalysisDataPointSetRef &points)
 {
-    for (int i = 0; i < n; ++i)
+    for (int i = 0; i < points.columnCount(); ++i)
     {
-        int bin = settings().findBin(y[i]);
+        int bin = settings().findBin(points.y(i));
         if (bin != -1)
         {
             impl_->hist_[bin] += 1;
@@ -612,28 +610,26 @@ AnalysisDataWeightedHistogramModule::dataStarted(AbstractAnalysisData *data)
 
 
 void
-AnalysisDataWeightedHistogramModule::frameStarted(real x, real dx)
+AnalysisDataWeightedHistogramModule::frameStarted(const AnalysisDataFrameHeader &header)
 {
     std::fill(impl_->hist_.begin(), impl_->hist_.end(), 0.0);
-    startNextFrame(x, dx);
+    startNextFrame(header);
 }
 
 
 void
-AnalysisDataWeightedHistogramModule::pointsAdded(real x, real dx, int firstcol, int n,
-                                                 const real *y, const real *dy,
-                                                 const bool *present)
+AnalysisDataWeightedHistogramModule::pointsAdded(const AnalysisDataPointSetRef &points)
 {
-    if (firstcol != 0 || n < 2)
+    if (points.firstColumn() != 0 || points.columnCount() < 2)
     {
         GMX_THROW(APIError("Invalid data layout"));
     }
-    int bin = settings().findBin(y[0]);
+    int bin = settings().findBin(points.y(0));
     if (bin != -1)
     {
-        for (int i = 1; i < n; ++i)
+        for (int i = 1; i < points.columnCount(); ++i)
         {
-            impl_->hist_[bin] += y[i];
+            impl_->hist_[bin] += points.y(i);
         }
     }
 }
@@ -704,29 +700,28 @@ AnalysisDataBinAverageModule::dataStarted(AbstractAnalysisData * /*data*/)
 
 
 void
-AnalysisDataBinAverageModule::frameStarted(real /*x*/, real /*dx*/)
+AnalysisDataBinAverageModule::frameStarted(const AnalysisDataFrameHeader & /*header*/)
 {
 }
 
 
 void
-AnalysisDataBinAverageModule::pointsAdded(real x, real dx, int firstcol, int n,
-                                          const real *y, const real *dy,
-                                          const bool *present)
+AnalysisDataBinAverageModule::pointsAdded(const AnalysisDataPointSetRef &points)
 {
-    if (firstcol != 0 || n < 2)
+    if (points.firstColumn() != 0 || points.columnCount() < 2)
     {
         GMX_THROW(APIError("Invalid data layout"));
     }
-    int bin = settings().findBin(y[0]);
+    int bin = settings().findBin(points.y(0));
     if (bin != -1)
     {
-        for (int i = 1; i < n; ++i)
+        for (int i = 1; i < points.columnCount(); ++i)
         {
-            value(bin, 0) += y[i];
-            value(bin, 1) += y[i] * y[i];
+            real y = points.y(i);
+            value(bin, 0) += y;
+            value(bin, 1) += y * y;
         }
-        value(bin, 2) += n - 1;
+        value(bin, 2) += points.columnCount() - 1;
     }
 }
 
index 196c6146dfddc4c33e048d0e9d833c93ce197044..928da06d385ac0226a80cdf6c90bbbcca9f3ecd1 100644 (file)
@@ -352,10 +352,8 @@ class AnalysisDataSimpleHistogramModule : public AbstractAnalysisDataStored,
         virtual int flags() const;
 
         virtual void dataStarted(AbstractAnalysisData *data);
-        virtual void frameStarted(real x, real dx);
-        virtual void pointsAdded(real x, real dx, int firstcol, int n,
-                                 const real *y, const real *dy,
-                                 const bool *present);
+        virtual void frameStarted(const AnalysisDataFrameHeader &header);
+        virtual void pointsAdded(const AnalysisDataPointSetRef &points);
         virtual void frameFinished();
         virtual void dataFinished();
 
@@ -402,10 +400,8 @@ class AnalysisDataWeightedHistogramModule : public AbstractAnalysisDataStored,
         virtual int flags() const;
 
         virtual void dataStarted(AbstractAnalysisData *data);
-        virtual void frameStarted(real x, real dx);
-        virtual void pointsAdded(real x, real dx, int firstcol, int n,
-                                 const real *y, const real *dy,
-                                 const bool *present);
+        virtual void frameStarted(const AnalysisDataFrameHeader &header);
+        virtual void pointsAdded(const AnalysisDataPointSetRef &points);
         virtual void frameFinished();
         virtual void dataFinished();
 
@@ -451,10 +447,8 @@ class AnalysisDataBinAverageModule : public AbstractAnalysisArrayData,
         virtual int flags() const;
 
         virtual void dataStarted(AbstractAnalysisData *data);
-        virtual void frameStarted(real x, real dx);
-        virtual void pointsAdded(real x, real dx, int firstcol, int n,
-                                 const real *y, const real *dy,
-                                 const bool *present);
+        virtual void frameStarted(const AnalysisDataFrameHeader &header);
+        virtual void pointsAdded(const AnalysisDataPointSetRef &points);
         virtual void frameFinished();
         virtual void dataFinished();
 
index ba4aae5c65560596445391673e60f2452af61b83..6c11496aa8b28df764922669b53207b09b568920 100644 (file)
@@ -56,6 +56,7 @@
 #include <xvgr.h>
 
 #include "gromacs/options/basicoptions.h"
+#include "gromacs/analysisdata/dataframe.h"
 #include "gromacs/options/options.h"
 #include "gromacs/options/timeunitmanager.h"
 #include "gromacs/fatalerror/exceptions.h"
@@ -304,7 +305,7 @@ AbstractPlotModule::dataStarted(AbstractAnalysisData *data)
 
 
 void
-AbstractPlotModule::frameStarted(real x, real dx)
+AbstractPlotModule::frameStarted(const AnalysisDataFrameHeader &frame)
 {
     if (!isFileOpen())
     {
@@ -312,7 +313,7 @@ AbstractPlotModule::frameStarted(real x, real dx)
     }
     if (!_impl->bOmitX)
     {
-        std::fprintf(_impl->fp, _impl->xfmt, x * _impl->xscale);
+        std::fprintf(_impl->fp, _impl->xfmt, frame.x() * _impl->xscale);
     }
 }
 
@@ -362,17 +363,15 @@ AnalysisDataPlotModule::AnalysisDataPlotModule(
 
 
 void
-AnalysisDataPlotModule::pointsAdded(real x, real dx, int firstcol, int n,
-                                    const real *y, const real *dy,
-                                    const bool *present)
+AnalysisDataPlotModule::pointsAdded(const AnalysisDataPointSetRef &points)
 {
     if (!isFileOpen())
     {
         return;
     }
-    for (int i = 0; i < n; ++i)
+    for (int i = 0; i < points.columnCount(); ++i)
     {
-        writeValue(y[i]);
+        writeValue(points.y(i));
     }
 }
 
@@ -432,11 +431,9 @@ AnalysisDataVectorPlotModule::setWriteMask(bool bWrite[DIM + 1])
 
 
 void
-AnalysisDataVectorPlotModule::pointsAdded(real x, real dx, int firstcol, int n,
-                                          const real *y, const real *dy,
-                                          const bool *present)
+AnalysisDataVectorPlotModule::pointsAdded(const AnalysisDataPointSetRef &points)
 {
-    if (firstcol % DIM != 0)
+    if (points.firstColumn() % DIM != 0)
     {
         GMX_THROW(APIError("Partial data points"));
     }
@@ -444,18 +441,19 @@ AnalysisDataVectorPlotModule::pointsAdded(real x, real dx, int firstcol, int n,
     {
         return;
     }
-    for (int i = 0; i < n; i += 3)
+    for (int i = 0; i < points.columnCount(); i += 3)
     {
         for (int d = 0; d < DIM; ++d)
         {
             if (_bWrite[i])
             {
-                writeValue(y[i + d]);
+                writeValue(points.y(i + d));
             }
         }
         if (_bWrite[DIM])
         {
-            writeValue(norm(&y[i]));
+            rvec y = { points.y(i), points.y(i + 1), points.y(i + 2) };
+            writeValue(norm(y));
         }
     }
 }
index 224d876213723912a7ae1df315da8b08998f669e..25d01476500051e284a22ba9dd226a35ea48b6d3 100644 (file)
@@ -203,10 +203,8 @@ class AbstractPlotModule : public AnalysisDataModuleInterface
         virtual int flags() const;
 
         virtual void dataStarted(AbstractAnalysisData *data);
-        virtual void frameStarted(real x, real dx);
-        virtual void pointsAdded(real x, real dx, int firstcol, int n,
-                                 const real *y, const real *dy,
-                                 const bool *present) = 0;
+        virtual void frameStarted(const AnalysisDataFrameHeader &header);
+        virtual void pointsAdded(const AnalysisDataPointSetRef &points) = 0;
         virtual void frameFinished();
         virtual void dataFinished();
 
@@ -242,9 +240,7 @@ class AnalysisDataPlotModule : public AbstractPlotModule
     public:
         explicit AnalysisDataPlotModule(const AnalysisDataPlotSettings &settings);
 
-        virtual void pointsAdded(real x, real dx, int firstcol, int n,
-                                 const real *y, const real *dy,
-                                 const bool *present);
+        virtual void pointsAdded(const AnalysisDataPointSetRef &points);
 
         // Copy and assign disallowed by base.
 };
@@ -284,9 +280,7 @@ class AnalysisDataVectorPlotModule : public AbstractPlotModule
          */
         void setWriteMask(bool bWrite[4]);
 
-        virtual void pointsAdded(real x, real dx, int firstcol, int n,
-                                 const real *y, const real *dy,
-                                 const bool *present);
+        virtual void pointsAdded(const AnalysisDataPointSetRef &points);
 
     private:
         bool                    _bWrite[4];
index fb7872c32024a8c64e3a0f4422835367582873fc..e5cc507b2a370c9403f4471dc2b58284057cd4db 100644 (file)
@@ -57,10 +57,8 @@ class MockAnalysisModule::Impl
     public:
         explicit Impl(int flags);
 
-        void startReferenceFrame(real x, real dx);
-        void checkReferencePoints(real x, real dx, int firstcol, int n,
-                                  const real *y, const real *dy,
-                                  const bool *present);
+        void startReferenceFrame(const AnalysisDataFrameHeader &header);
+        void checkReferencePoints(const AnalysisDataPointSetRef &points);
         void finishReferenceFrame();
 
         // Could be scoped_ptrs
index 9b2995c47047366b787274bcb43759dc4d4537a7..279be328454e4bf7ee072e55b93970f72013fa31 100644 (file)
@@ -41,6 +41,7 @@
 #include <gtest/gtest.h>
 
 #include "gromacs/analysisdata/analysisdata.h"
+#include "gromacs/analysisdata/dataframe.h"
 #include "gromacs/fatalerror/gmxassert.h"
 #include "gromacs/utility/format.h"
 
@@ -65,26 +66,32 @@ MockAnalysisModule::Impl::Impl(int flags)
 
 
 void
-MockAnalysisModule::Impl::startReferenceFrame(real x, real dx)
+MockAnalysisModule::Impl::startReferenceFrame(const AnalysisDataFrameHeader &header)
 {
     EXPECT_TRUE(frameChecker_.get() == NULL);
+    EXPECT_EQ(frameIndex_, header.index());
     frameChecker_.reset(new TestReferenceChecker(
         rootChecker_->checkCompound("DataFrame",
                                     formatString("Frame%d", frameIndex_).c_str())));
     ++frameIndex_;
-    frameChecker_->checkReal(x, "X");
+    frameChecker_->checkReal(header.x(), "X");
 }
 
 
 void
-MockAnalysisModule::Impl::checkReferencePoints(real x, real dx, int firstcol, int n,
-                                               const real *y, const real *dy,
-                                               const bool *present)
+MockAnalysisModule::Impl::checkReferencePoints(const AnalysisDataPointSetRef &points)
 {
     EXPECT_TRUE(frameChecker_.get() != NULL);
     if (frameChecker_.get() != NULL)
     {
-        frameChecker_->checkSequenceArray(n, y, "Y");
+        // TODO: Add interface to points to make this easier.
+        std::vector<real> tmp;
+        tmp.reserve(points.columnCount());
+        for (int i = 0; i < points.columnCount(); ++i)
+        {
+            tmp.push_back(points.y(i));
+        }
+        frameChecker_->checkSequenceArray(tmp.size(), &tmp[0], "Y");
     }
 }
 
@@ -104,10 +111,25 @@ MockAnalysisModule::Impl::finishReferenceFrame()
 namespace
 {
 
-void checkFrame(real x, real dx, const AnalysisDataTestInputFrame &frame)
+void checkHeader(const AnalysisDataFrameHeader &header,
+                 const AnalysisDataTestInputFrame &refFrame)
+{
+    EXPECT_EQ(refFrame.index(), header.index());
+    EXPECT_FLOAT_EQ(refFrame.x(), header.x());
+    EXPECT_FLOAT_EQ(refFrame.dx(), header.dx());
+}
+
+void checkPoints(const AnalysisDataPointSetRef &points,
+                 const AnalysisDataTestInputPointSet &refPoints,
+                 int columnOffset)
 {
-    EXPECT_FLOAT_EQ(frame.x(), x);
-    EXPECT_FLOAT_EQ(frame.dx(), dx);
+    for (int i = 0; i < points.columnCount(); ++i)
+    {
+        EXPECT_FLOAT_EQ(refPoints.y(points.firstColumn() + columnOffset + i),
+                        points.y(i))
+            << "  Column: " << i << " (+" << points.firstColumn() << ") / "
+            << points.columnCount();
+    }
 }
 
 void checkPoints(int firstcol, int n, const real *y,
@@ -119,16 +141,66 @@ void checkPoints(int firstcol, int n, const real *y,
     }
 }
 
-void checkFrame(real x, real dx, int firstcol, int n, const real *y,
+void checkFrame(int index, real x, real dx, int firstcol, int n, const real *y,
                 const AnalysisDataTestInputFrame &frame)
 {
-    checkFrame(x, dx, frame);
+    checkHeader(AnalysisDataFrameHeader(index, x, dx), frame);
     checkPoints(firstcol, n, y, frame.points());
 }
 
+/*! \internal \brief
+ * Functor for checking data frame header against static test input data.
+ *
+ * This functor is designed to be invoked as a handled for
+ * AnalysisDataModuleInterface::frameStarted().
+ */
+class StaticDataFrameHeaderChecker
+{
+    public:
+        /*! \brief
+         * Constructs a checker against a given input data frame.
+         *
+         * \param[in] frame Frame to check against.
+         *
+         * \p frame must exist for the lifetime of this object.
+         */
+        StaticDataFrameHeaderChecker(const AnalysisDataTestInputFrame *frame)
+            : frame_(frame)
+        {
+        }
+
+        //! Function call operator for the functor.
+        void operator()(const AnalysisDataFrameHeader &header) const
+        {
+            SCOPED_TRACE(formatString("Frame %d", frame_->index()));
+            checkHeader(header, *frame_);
+        }
+
+    private:
+        const AnalysisDataTestInputFrame *frame_;
+};
+
+/*! \internal \brief
+ * Functor for checking data frame points against static test input data.
+ *
+ * This functor is designed to be invoked as a handled for
+ * AnalysisDataModuleInterface::pointsAdded().
+ */
 class StaticDataPointsChecker
 {
     public:
+        /*! \brief
+         * Constructs a checker against a given input data frame and point set.
+         *
+         * \param[in] frame    Frame to check against.
+         * \param[in] points   Point set in \p frame to check against.
+         * \param[in] firstcol Expected first column.
+         * \param[in] n        Expected number of columns.
+         *
+         * \p firstcol and \p n are used to create a checker that only expects
+         * to be called for a subset of columns.
+         * \p frame and \p points must exist for the lifetime of this object.
+         */
         StaticDataPointsChecker(const AnalysisDataTestInputFrame *frame,
                                 const AnalysisDataTestInputPointSet *points,
                                 int firstcol, int n)
@@ -136,15 +208,14 @@ class StaticDataPointsChecker
         {
         }
 
-        void operator()(real x, real dx, int firstcol, int n,
-                        const real *y, const real *dy,
-                        const bool *present) const
+        //! Function call operator for the functor.
+        void operator()(const AnalysisDataPointSetRef &points) const
         {
             SCOPED_TRACE(formatString("Frame %d", frame_->index()));
-            EXPECT_EQ(0, firstcol);
-            EXPECT_EQ(n_, n);
-            checkFrame(x, dx, *frame_);
-            checkPoints(firstcol_ + firstcol, n, y, *points_);
+            EXPECT_EQ(0, points.firstColumn());
+            EXPECT_EQ(n_, points.columnCount());
+            checkHeader(points.header(), *frame_);
+            checkPoints(points, *points_, firstcol_);
         }
 
     private:
@@ -154,12 +225,26 @@ class StaticDataPointsChecker
         int                     n_;
 };
 
-
+/*! \internal \brief
+ * Functor for requesting data storage.
+ *
+ * This functor is designed to be invoked as a handled for
+ * AnalysisDataModuleInterface::dataStarted().
+ */
 class DataStorageRequester
 {
     public:
+        /*! \brief
+         * Constructs a functor that requests the given amount of storage.
+         *
+         * \param[in] count  Number of frames of storage to request, or
+         *      -1 for all frames.
+         *
+         * \see AbstractAnalysisData::requestStorage()
+         */
         explicit DataStorageRequester(int count) : count_(count) {}
 
+        //! Function call operator for the functor.
         void operator()(AbstractAnalysisData *data) const
         {
             data->requestStorage(count_);
@@ -169,10 +254,32 @@ class DataStorageRequester
         int                     count_;
 };
 
-
+/*! \internal \brief
+ * Functor for checking data frame points and storage against static test input
+ * data.
+ *
+ * This functor is designed to be invoked as a handled for
+ * AnalysisDataModuleInterface::pointsAdded().
+ */
 class StaticDataPointsStorageChecker
 {
     public:
+        /*! \brief
+         * Constructs a checker for a given frame.
+         *
+         * \param[in] source     Data object that is being checked.
+         * \param[in] data       Test input data to check against.
+         * \param[in] frameIndex Frame index for which this functor expects
+         *      to be called.
+         * \param[in] storageCount How many past frames should be checked for
+         *      storage (-1 = check all frames).
+         *
+         * This checker works as StaticDataPointsChecker, but additionally
+         * checks that previous frames can be accessed using access methods
+         * in AbstractAnalysisData and that correct data is returned.
+         *
+         * \p source and \p data must exist for the lifetime of this object.
+         */
         StaticDataPointsStorageChecker(AbstractAnalysisData *source,
                                        const AnalysisDataTestInput *data,
                                        int frameIndex, int storageCount)
@@ -181,14 +288,14 @@ class StaticDataPointsStorageChecker
         {
         }
 
-        void operator()(real x, real dx, int firstcol, int n,
-                        const real *y, const real *dy,
-                        const bool *present) const
+        //! Function call operator for the functor.
+        void operator()(const AnalysisDataPointSetRef &points) const
         {
             SCOPED_TRACE(formatString("Frame %d", frameIndex_));
-            EXPECT_EQ(0, firstcol);
-            EXPECT_EQ(data_->columnCount(), n);
-            checkFrame(x, dx, firstcol, n, y, data_->frame(frameIndex_));
+            EXPECT_EQ(0, points.firstColumn());
+            EXPECT_EQ(data_->columnCount(), points.columnCount());
+            checkHeader(points.header(), data_->frame(frameIndex_));
+            checkPoints(points, data_->frame(frameIndex_).points(), 0);
             for (int past = 0;
                  (storageCount_ < 0 || past <= storageCount_) && past <= frameIndex_;
                  ++past)
@@ -199,13 +306,13 @@ class StaticDataPointsStorageChecker
                 SCOPED_TRACE(formatString("Checking storage of frame %d", index));
                 ASSERT_TRUE(source_->getDataWErr(index,
                                                  &pastx, &pastdx, &pasty, NULL));
-                checkFrame(pastx, pastdx, 0, data_->columnCount(), pasty,
+                checkFrame(index, pastx, pastdx, 0, data_->columnCount(), pasty,
                            data_->frame(index));
                 if (past > 0)
                 {
                     ASSERT_TRUE(source_->getDataWErr(-past,
                                                      &pastx, &pastdx, &pasty, NULL));
-                    checkFrame(pastx, pastdx, 0, data_->columnCount(), pasty,
+                    checkFrame(index, pastx, pastdx, 0, data_->columnCount(), pasty,
                                data_->frame(index));
                 }
             }
@@ -255,12 +362,12 @@ MockAnalysisModule::setupStaticCheck(const AnalysisDataTestInput &data,
     for (int row = 0; row < data.frameCount(); ++row)
     {
         const AnalysisDataTestInputFrame &frame = data.frame(row);
-        EXPECT_CALL(*this, frameStarted(frame.x(), frame.dx()));
+        EXPECT_CALL(*this, frameStarted(_))
+            .WillOnce(Invoke(StaticDataFrameHeaderChecker(&frame)));
         for (int ps = 0; ps < frame.pointSetCount(); ++ps)
         {
             const AnalysisDataTestInputPointSet &points = frame.points(ps);
-            EXPECT_CALL(*this, pointsAdded(frame.x(), frame.dx(), 0,
-                                           points.size(), _, _, _))
+            EXPECT_CALL(*this, pointsAdded(_))
                 .WillOnce(Invoke(StaticDataPointsChecker(&frame, &points, 0,
                                                          data.columnCount())));
         }
@@ -289,11 +396,12 @@ MockAnalysisModule::setupStaticColumnCheck(const AnalysisDataTestInput &data,
     for (int row = 0; row < data.frameCount(); ++row)
     {
         const AnalysisDataTestInputFrame &frame = data.frame(row);
-        EXPECT_CALL(*this, frameStarted(frame.x(), frame.dx()));
+        EXPECT_CALL(*this, frameStarted(_))
+            .WillOnce(Invoke(StaticDataFrameHeaderChecker(&frame)));
         for (int ps = 0; ps < frame.pointSetCount(); ++ps)
         {
             const AnalysisDataTestInputPointSet &points = frame.points(ps);
-            EXPECT_CALL(*this, pointsAdded(frame.x(), frame.dx(), 0, n, _, _, _))
+            EXPECT_CALL(*this, pointsAdded(_))
                 .WillOnce(Invoke(StaticDataPointsChecker(&frame, &points, firstcol, n)));
         }
         EXPECT_CALL(*this, frameFinished());
@@ -322,9 +430,9 @@ MockAnalysisModule::setupStaticStorageCheck(const AnalysisDataTestInput &data,
     for (int row = 0; row < data.frameCount(); ++row)
     {
         const AnalysisDataTestInputFrame &frame = data.frame(row);
-        EXPECT_CALL(*this, frameStarted(frame.x(), frame.dx()));
-        EXPECT_CALL(*this, pointsAdded(frame.x(), frame.dx(), 0,
-                                       data.columnCount(), _, _, _))
+        EXPECT_CALL(*this, frameStarted(_))
+            .WillOnce(Invoke(StaticDataFrameHeaderChecker(&frame)));
+        EXPECT_CALL(*this, pointsAdded(_))
             .WillOnce(Invoke(StaticDataPointsStorageChecker(source, &data, row,
                                                             storageCount)));
         EXPECT_CALL(*this, frameFinished());
@@ -350,10 +458,10 @@ MockAnalysisModule::setupReferenceCheck(const TestReferenceChecker &checker,
     using ::testing::Invoke;
 
     Expectation dataStart = EXPECT_CALL(*this, dataStarted(source));
-    Expectation frameStart = EXPECT_CALL(*this, frameStarted(_, _))
+    Expectation frameStart = EXPECT_CALL(*this, frameStarted(_))
         .After(dataStart)
         .WillRepeatedly(Invoke(impl_, &Impl::startReferenceFrame));
-    Expectation pointsAdd = EXPECT_CALL(*this, pointsAdded(_, _, _, _, _, _, _))
+    Expectation pointsAdd = EXPECT_CALL(*this, pointsAdded(_))
         .After(dataStart)
         .WillRepeatedly(Invoke(impl_, &Impl::checkReferencePoints));
     Expectation frameFinish = EXPECT_CALL(*this, frameFinished())
index ec5afe7b163ee859563ba304d479c48b3ed31802..e7a8a57962b3832d1c4c886286608f7d90a87b30 100644 (file)
@@ -61,10 +61,8 @@ class MockAnalysisModule : public AnalysisDataModuleInterface
         virtual int flags() const;
 
         MOCK_METHOD1(dataStarted, void(AbstractAnalysisData *data));
-        MOCK_METHOD2(frameStarted, void(real x, real dx));
-        MOCK_METHOD7(pointsAdded, void(real x, real dx, int firstcol, int n,
-                                       const real *y, const real *dy,
-                                       const bool *present));
+        MOCK_METHOD1(frameStarted, void(const AnalysisDataFrameHeader &header));
+        MOCK_METHOD1(pointsAdded, void(const AnalysisDataPointSetRef &points));
         MOCK_METHOD0(frameFinished, void());
         MOCK_METHOD0(dataFinished, void());
 
index ed8f48c02a5ce13e1704b97fa9cc0c8934b8362c..09bde172b527afb468f423af9cbf069eed05ada6 100644 (file)
@@ -50,6 +50,7 @@
 #include <smalloc.h>
 
 #include "gromacs/analysisdata/analysisdata.h"
+#include "gromacs/analysisdata/dataframe.h"
 #include "gromacs/analysisdata/datamodule.h"
 #include "gromacs/analysisdata/modules/plot.h"
 #include "gromacs/fatalerror/exceptions.h"
@@ -83,10 +84,8 @@ class IndexFileWriterModule : public AnalysisDataModuleInterface
         virtual int flags() const;
 
         virtual void dataStarted(AbstractAnalysisData *data);
-        virtual void frameStarted(real x, real dx);
-        virtual void pointsAdded(real x, real dx, int firstcol, int n,
-                                 const real *y, const real *dy,
-                                 const bool *present);
+        virtual void frameStarted(const AnalysisDataFrameHeader &header);
+        virtual void pointsAdded(const AnalysisDataPointSetRef &points);
         virtual void frameFinished();
         virtual void dataFinished();
 
@@ -106,7 +105,6 @@ class IndexFileWriterModule : public AnalysisDataModuleInterface
         std::string             _fnm;
         std::vector<GroupInfo>  _groups;
         FILE                   *_fp;
-        int                     _framenr;
         int                     _currentGroup;
         int                     _currentSize;
         bool                    _bAnyWritten;
@@ -116,7 +114,7 @@ class IndexFileWriterModule : public AnalysisDataModuleInterface
  * IndexFileWriterModule
  */
 
-IndexFileWriterModule::IndexFileWriterModule() : _fp(NULL), _framenr(0)
+IndexFileWriterModule::IndexFileWriterModule() : _fp(NULL)
 {
 }
 
@@ -166,7 +164,7 @@ void IndexFileWriterModule::dataStarted(AbstractAnalysisData * /*data*/)
 }
 
 
-void IndexFileWriterModule::frameStarted(real /*x*/, real /*dx*/)
+void IndexFileWriterModule::frameStarted(const AnalysisDataFrameHeader & /*header*/)
 {
     _bAnyWritten = false;
     _currentGroup = -1;
@@ -174,27 +172,26 @@ void IndexFileWriterModule::frameStarted(real /*x*/, real /*dx*/)
 
 
 void
-IndexFileWriterModule::pointsAdded(real x, real /*dx*/, int firstcol, int n,
-                                   const real *y, const real * /*dy*/,
-                                   const bool * /*present*/)
+IndexFileWriterModule::pointsAdded(const AnalysisDataPointSetRef &points)
 {
     if (_fp == NULL)
     {
         return;
     }
-    if (firstcol == 0)
+    bool bFirstFrame = (points.frameIndex() == 0);
+    if (points.firstColumn() == 0)
     {
         ++_currentGroup;
-        if (_framenr == 0 || _groups[_currentGroup].bDynamic)
+        if (bFirstFrame || _groups[_currentGroup].bDynamic)
         {
-            if (_framenr > 0 || _currentGroup > 0)
+            if (!bFirstFrame || _currentGroup > 0)
             {
                 std::fprintf(_fp, "\n\n");
             }
             std::string name = _groups[_currentGroup].name;
             if (_groups[_currentGroup].bDynamic)
             {
-                name += formatString("_f%d_t%.3f", _framenr, x);
+                name += formatString("_f%d_t%.3f", points.frameIndex(), points.x());
             }
             std::fprintf(_fp, "[ %s ]", name.c_str());
             _bAnyWritten = true;
@@ -203,13 +200,13 @@ IndexFileWriterModule::pointsAdded(real x, real /*dx*/, int firstcol, int n,
     }
     else
     {
-        if (_framenr == 0 || _groups[_currentGroup].bDynamic)
+        if (bFirstFrame || _groups[_currentGroup].bDynamic)
         {
             if (_currentSize % 15 == 0)
             {
                 std::fprintf(_fp, "\n");
             }
-            std::fprintf(_fp, "%4d ", static_cast<int>(y[0]));
+            std::fprintf(_fp, "%4d ", static_cast<int>(points.y(0)));
             ++_currentSize;
         }
     }
@@ -218,7 +215,6 @@ IndexFileWriterModule::pointsAdded(real x, real /*dx*/, int firstcol, int n,
 
 void IndexFileWriterModule::frameFinished()
 {
-    ++_framenr;
 }