Merge release-5-0 into master
[alexxy/gromacs.git] / src / gromacs / analysisdata / modules / average.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2010,2011,2012,2013,2014, 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  * Implements gmx::AnalysisDataAverageModule.
38  *
39  * \author Teemu Murtola <teemu.murtola@gmail.com>
40  * \ingroup module_analysisdata
41  */
42 #include "gmxpre.h"
43
44 #include "average.h"
45
46 #include <cmath>
47
48 #include <algorithm>
49 #include <vector>
50
51 #include "gromacs/analysisdata/dataframe.h"
52 #include "gromacs/analysisdata/datastorage.h"
53
54 #include "frameaverager.h"
55
56 namespace gmx
57 {
58
59 /********************************************************************
60  * AnalysisDataAverageModule
61  */
62
63 class AnalysisDataAverageModule::Impl
64 {
65     public:
66         Impl() : bDataSets_(false) {}
67
68         //! Averaging helper objects for each input data set.
69         std::vector<AnalysisDataFrameAverager>  averagers_;
70         //! Whether to average all columns in a data set into a single value.
71         bool                                    bDataSets_;
72 };
73
74 AnalysisDataAverageModule::AnalysisDataAverageModule()
75     : impl_(new Impl())
76 {
77 }
78
79 AnalysisDataAverageModule::~AnalysisDataAverageModule()
80 {
81 }
82
83 void AnalysisDataAverageModule::setAverageDataSets(bool bDataSets)
84 {
85     impl_->bDataSets_ = bDataSets;
86 }
87
88 int AnalysisDataAverageModule::flags() const
89 {
90     return efAllowMultipoint | efAllowMulticolumn | efAllowMissing
91            | efAllowMultipleDataSets;
92 }
93
94 void
95 AnalysisDataAverageModule::dataStarted(AbstractAnalysisData *data)
96 {
97     if (impl_->bDataSets_)
98     {
99         setColumnCount(1);
100         setRowCount(data->dataSetCount());
101         impl_->averagers_.resize(1);
102         impl_->averagers_[0].setColumnCount(data->dataSetCount());
103     }
104     else
105     {
106         setColumnCount(data->dataSetCount());
107         impl_->averagers_.resize(data->dataSetCount());
108         int rowCount = 0;
109         for (int i = 0; i < data->dataSetCount(); ++i)
110         {
111             impl_->averagers_[i].setColumnCount(data->columnCount(i));
112             rowCount = std::max(rowCount, data->columnCount(i));
113         }
114         setRowCount(rowCount);
115     }
116 }
117
118 void
119 AnalysisDataAverageModule::frameStarted(const AnalysisDataFrameHeader & /*header*/)
120 {
121 }
122
123 void
124 AnalysisDataAverageModule::pointsAdded(const AnalysisDataPointSetRef &points)
125 {
126     if (impl_->bDataSets_)
127     {
128         const int dataSet = points.dataSetIndex();
129         for (int i = 0; i < points.columnCount(); ++i)
130         {
131             if (points.present(i))
132             {
133                 impl_->averagers_[0].addValue(dataSet, points.y(i));
134             }
135         }
136     }
137     else
138     {
139         impl_->averagers_[points.dataSetIndex()].addPoints(points);
140     }
141 }
142
143 void
144 AnalysisDataAverageModule::frameFinished(const AnalysisDataFrameHeader & /*header*/)
145 {
146 }
147
148 void
149 AnalysisDataAverageModule::dataFinished()
150 {
151     allocateValues();
152     for (int i = 0; i < columnCount(); ++i)
153     {
154         impl_->averagers_[i].finish();
155         int j = 0;
156         for (; j < impl_->averagers_[i].columnCount(); ++j)
157         {
158             value(j, i).setValue(impl_->averagers_[i].average(j),
159                                  std::sqrt(impl_->averagers_[i].variance(j)));
160         }
161         for (; j < rowCount(); ++j)
162         {
163             value(j, i).setValue(0.0, 0.0, false);
164         }
165     }
166     valuesReady();
167 }
168
169 real AnalysisDataAverageModule::average(int dataSet, int column) const
170 {
171     if (impl_->bDataSets_)
172     {
173         GMX_ASSERT(column == 0,
174                    "Column should be zero with setAverageDataSets(true)");
175         std::swap(dataSet, column);
176     }
177     return value(column, dataSet).value();
178 }
179
180 real AnalysisDataAverageModule::standardDeviation(int dataSet, int column) const
181 {
182     if (impl_->bDataSets_)
183     {
184         GMX_ASSERT(column == 0,
185                    "Column should be zero with setAverageDataSets(true)");
186         std::swap(dataSet, column);
187     }
188     return value(column, dataSet).error();
189 }
190
191 int AnalysisDataAverageModule::sampleCount(int dataSet, int column) const
192 {
193     if (impl_->bDataSets_)
194     {
195         GMX_ASSERT(column == 0,
196                    "Column should be zero with setAverageDataSets(true)");
197         std::swap(dataSet, column);
198     }
199     return impl_->averagers_[dataSet].sampleCount(column);
200 }
201
202
203 /********************************************************************
204  * AnalysisDataFrameAverageModule
205  */
206
207 class AnalysisDataFrameAverageModule::Impl
208 {
209     public:
210         //! Storage implementation object.
211         AnalysisDataStorage     storage_;
212         //! Number of samples in a frame for each data set.
213         std::vector<int>        sampleCount_;
214 };
215
216 AnalysisDataFrameAverageModule::AnalysisDataFrameAverageModule()
217     : impl_(new Impl())
218 {
219 }
220
221 AnalysisDataFrameAverageModule::~AnalysisDataFrameAverageModule()
222 {
223 }
224
225 int
226 AnalysisDataFrameAverageModule::frameCount() const
227 {
228     return impl_->storage_.frameCount();
229 }
230
231 int
232 AnalysisDataFrameAverageModule::flags() const
233 {
234     return efAllowMultipoint | efAllowMulticolumn | efAllowMissing
235            | efAllowMultipleDataSets;
236 }
237
238 void
239 AnalysisDataFrameAverageModule::dataStarted(AbstractAnalysisData *data)
240 {
241     setColumnCount(0, data->dataSetCount());
242     impl_->sampleCount_.resize(data->dataSetCount());
243     impl_->storage_.startDataStorage(this, &moduleManager());
244 }
245
246 void
247 AnalysisDataFrameAverageModule::frameStarted(const AnalysisDataFrameHeader &header)
248 {
249     AnalysisDataStorageFrame &frame = impl_->storage_.startFrame(header);
250     for (int i = 0; i < columnCount(); ++i)
251     {
252         impl_->sampleCount_[i] = 0;
253         frame.setValue(i, 0.0);
254     }
255 }
256
257 void
258 AnalysisDataFrameAverageModule::pointsAdded(const AnalysisDataPointSetRef &points)
259 {
260     const int                 dataSet = points.dataSetIndex();
261     AnalysisDataStorageFrame &frame   =
262         impl_->storage_.currentFrame(points.frameIndex());
263     for (int i = 0; i < points.columnCount(); ++i)
264     {
265         if (points.present(i))
266         {
267             // TODO: Consider using AnalysisDataFrameAverager
268             const real y     = points.y(i);
269             const real delta = y - frame.value(dataSet);
270             impl_->sampleCount_[dataSet] += 1;
271             frame.value(dataSet)         += delta / impl_->sampleCount_[dataSet];
272         }
273     }
274 }
275
276 void
277 AnalysisDataFrameAverageModule::frameFinished(const AnalysisDataFrameHeader &header)
278 {
279     impl_->storage_.finishFrame(header.index());
280 }
281
282 void
283 AnalysisDataFrameAverageModule::dataFinished()
284 {
285     impl_->storage_.finishDataStorage();
286 }
287
288 AnalysisDataFrameRef
289 AnalysisDataFrameAverageModule::tryGetDataFrameInternal(int index) const
290 {
291     return impl_->storage_.tryGetDataFrame(index);
292 }
293
294 bool
295 AnalysisDataFrameAverageModule::requestStorageInternal(int nframes)
296 {
297     return impl_->storage_.requestStorage(nframes);
298 }
299
300 } // namespace gmx