Merge branch 'release-4-6' into release-5-0
[alexxy/gromacs.git] / src / gromacs / analysisdata / modules / frameaverager.h
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2013, by the GROMACS development team, led by
5  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6  * and including many others, as listed in the AUTHORS file in the
7  * top-level source directory and at http://www.gromacs.org.
8  *
9  * GROMACS is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1
12  * of the License, or (at your option) any later version.
13  *
14  * GROMACS is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with GROMACS; if not, see
21  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
23  *
24  * If you want to redistribute modifications to GROMACS, please
25  * consider that scientific software is very special. Version
26  * control is crucial - bugs must be traceable. We will be happy to
27  * consider code for inclusion in the official distribution, but
28  * derived work must not be called official GROMACS. Details are found
29  * in the README & COPYING files - if they are missing, get the
30  * official version at http://www.gromacs.org.
31  *
32  * To help us fund GROMACS development, we humbly ask that you cite
33  * the research papers on the package. Check out http://www.gromacs.org.
34  */
35 /*! \internal \file
36  * \brief
37  * Declares gmx::AnalysisDataFrameAverager.
38  *
39  * \author Teemu Murtola <teemu.murtola@gmail.com>
40  * \ingroup module_analysisdata
41  */
42 #ifndef GMX_ANALYSISDATA_MODULES_FRAMEAVERAGER_H
43 #define GMX_ANALYSISDATA_MODULES_FRAMEAVERAGER_H
44
45 #include <vector>
46
47 #include "../../legacyheaders/types/simple.h"
48
49 #include "../../utility/gmxassert.h"
50
51 namespace gmx
52 {
53
54 class AnalysisDataPointSetRef;
55
56 /*! \internal
57  * \brief
58  * Helper class for modules that average values over frames.
59  *
60  * This class implements common functionality for analysis data modules that
61  * need to average a set of values over frames.  Currently, it is designed for
62  * computing averages for each input column independently, but should be
63  * relatively easy to make more general if required.
64  *
65  * This class takes care of accumulating the values and computing their
66  * variance.  It allows different number of samples for each input column.
67  * Accumulation is always in double precision and uses a formula that is
68  * relatively stable numerically.  For now, does nothing fancy,
69  * but provides ground for other implementation (e.g., related to
70  * parallelization) that would benefit all such modules.
71  *
72  * Methods in this class do not throw unless otherwise indicated.
73  *
74  * \ingroup module_analysisdata
75  */
76 class AnalysisDataFrameAverager
77 {
78     public:
79         AnalysisDataFrameAverager() : bFinished_(false) {}
80
81         /*! \brief
82          * Returns the number of columns in this averager.
83          */
84         int columnCount() const { return values_.size(); }
85
86         /*! \brief
87          * Sets the number of columns in the input data.
88          *
89          * \throws std::bad_alloc if out of memory.
90          *
91          * Typically called from AnalysisDataModuleInterface::dataStarted().
92          *
93          * Must be called exactly once, before setting calling any other method
94          * in the class.
95          */
96         void setColumnCount(int columnCount);
97         /*! \brief
98          * Adds a single value to the average for a given column.
99          *
100          * \param[in] index  Index of the column to add the value to.
101          * \param[in] value  Value to add to the sample.
102          */
103         void addValue(int index, real value);
104         /*! \brief
105          * Accumulates data from a given point set into the average.
106          *
107          * Typically called from AnalysisDataModuleInterface::pointsAdded().
108          *
109          * Each call accumulates the values for those columns that are present
110          * in the point set.  Can be called multiple times for a frame, and
111          * does not need to be called for every frame.
112          */
113         void addPoints(const AnalysisDataPointSetRef &points);
114         /*! \brief
115          * Finalizes the calculation of the averages and variances.
116          *
117          * Does any computation that is not done during the accumulation in
118          * addPoints().  Currently, does nothing, but provided as a placeholder
119          * for more complex implementation.
120          *
121          * Typically called from AnalysisDataModuleInterface::dataFinished().
122          */
123         void finish();
124
125         /*! \brief
126          * Returns the computed average for a given column.
127          *
128          * If called before finish(), the results are undefined.
129          */
130         real average(int index) const
131         {
132             GMX_ASSERT(index >= 0 && index < columnCount(),
133                        "Invalid column index");
134             GMX_ASSERT(bFinished_,
135                        "Values available only after finished() has been called");
136             return values_[index].average;
137         }
138         /*! \brief
139          * Returns the computed (sample) variance for a given column.
140          *
141          * If called before finish(), the results are undefined.
142          */
143         real variance(int index) const
144         {
145             GMX_ASSERT(index >= 0 && index < columnCount(),
146                        "Invalid column index");
147             GMX_ASSERT(bFinished_,
148                        "Values available only after finished() has been called");
149             const AverageItem &item = values_[index];
150             return item.samples > 1 ? item.squaredSum / (item.samples - 1) : 0.0;
151         }
152         /*! \brief
153          * Returns the number of samples for a given column.
154          *
155          * If called before finish(), the results are undefined.
156          */
157         int sampleCount(int index) const
158         {
159             GMX_ASSERT(index >= 0 && index <= static_cast<int>(values_.size()),
160                        "Invalid column index");
161             GMX_ASSERT(bFinished_,
162                        "Values available only after finished() has been called");
163             return values_[index].samples;
164         }
165
166     private:
167         struct AverageItem
168         {
169             AverageItem() : average(0.0), squaredSum(0.0), samples(0) {}
170
171             //! Average of the values so far.
172             double               average;
173             //! Sum of squared deviations from the average for values so far.
174             double               squaredSum;
175             //! Number of values so far.
176             int                  samples;
177         };
178
179         std::vector<AverageItem> values_;
180         bool                     bFinished_;
181 };
182
183 } // namespace gmx
184
185 #endif