Merge branch release-4-6 into master
[alexxy/gromacs.git] / src / gromacs / analysisdata / datastorage.h
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2012,2013, by the GROMACS development team, led by
5  * David van der Spoel, Berk Hess, Erik Lindahl, and including many
6  * others, as listed in the AUTHORS file in the top-level source
7  * 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 /*! \libinternal \file
36  * \brief
37  * Declares gmx::AnalysisDataStorage.
38  *
39  * \author Teemu Murtola <teemu.murtola@gmail.com>
40  * \inlibraryapi
41  * \ingroup module_analysisdata
42  */
43 #ifndef GMX_ANALYSISDATA_DATASTORAGE_H
44 #define GMX_ANALYSISDATA_DATASTORAGE_H
45
46 #include <vector>
47
48 #include "../legacyheaders/types/simple.h"
49
50 #include "../utility/common.h"
51 #include "../utility/gmxassert.h"
52
53 #include "dataframe.h"
54
55 namespace gmx
56 {
57
58 class AbstractAnalysisData;
59 class AnalysisDataFrameHeader;
60 class AnalysisDataFrameRef;
61 class AnalysisDataParallelOptions;
62
63 class AnalysisDataStorage;
64
65 namespace internal
66 {
67 class AnalysisDataStorageFrameData;
68 }   // namespace internal
69
70 /*! \libinternal \brief
71  * Allows assigning values for a data frame in AnalysisDataStorage.
72  *
73  * This class implements the necessary methods to add new data into the
74  * storage.  AnalysisDataStorage::startFrame() returns an object of this type,
75  * which can be used to add one or more point sets to that data frame.
76  * When all data has been added, finishFrame() needs to be called.
77  *
78  * \inlibraryapi
79  * \ingroup module_analysisdata
80  */
81 class AnalysisDataStorageFrame
82 {
83     public:
84         /*! \brief Frees the frame object.
85          *
86          * Should not be called outside AnalysisDataStorage.
87          */
88         ~AnalysisDataStorageFrame();
89
90         //! Returns number of columns for the frame.
91         int columnCount() const { return values_.size(); }
92
93         /*! \brief
94          * Sets value for a column.
95          *
96          * \param[in] column  Zero-based column index.
97          * \param[in] value   Value to set for the column.
98          * \param[in] bPresent Present flag to set for the column.
99          *
100          * If called multiple times for a column (within one point set for
101          * multipoint data), old values are overwritten.
102          *
103          * Does not throw.
104          */
105         void setValue(int column, real value, bool bPresent = true)
106         {
107             GMX_ASSERT(column >= 0 && column < columnCount(),
108                        "Invalid column index");
109             values_[column].setValue(value, bPresent);
110             bPointSetInProgress_ = true;
111         }
112         /*! \brief
113          * Sets value for a column.
114          *
115          * \param[in] column  Zero-based column index.
116          * \param[in] value   Value to set for the column.
117          * \param[in] error   Error estimate to set for the column.
118          * \param[in] bPresent Present flag to set for the column.
119          *
120          * If called multiple times for a column (within one point set for
121          * multipoint data), old values are overwritten.
122          *
123          * Does not throw.
124          */
125         void setValue(int column, real value, real error, bool bPresent = true)
126         {
127             GMX_ASSERT(column >= 0 && column < columnCount(),
128                        "Invalid column index");
129             values_[column].setValue(value, error, bPresent);
130             bPointSetInProgress_ = true;
131         }
132         /*! \brief
133          * Access value for a column.
134          *
135          * \param[in] column  Zero-based column index.
136          *
137          * Should only be called after the column value has been set using
138          * setValue(); assigning a value to \c value(i) does not mark the
139          * column as set.
140          *
141          * Does not throw.
142          */
143         real &value(int column)
144         {
145             GMX_ASSERT(column >= 0 && column < columnCount(),
146                        "Invalid column index");
147             return values_[column].value();
148         }
149         /*! \brief
150          * Access value for a column.
151          *
152          * \param[in] column  Zero-based column index.
153          *
154          * Should only be called after the column value has been set using
155          * setValue().
156          *
157          * Does not throw.
158          */
159         real value(int column) const
160         {
161             GMX_ASSERT(column >= 0 && column < columnCount(),
162                        "Invalid column index");
163             return values_[column].value();
164         }
165         /*! \brief
166          * Mark point set as finished for multipoint data.
167          *
168          * Must be called after each point set for multipoint data, including
169          * the last (i.e., no values must be set between the last call to this
170          * method and AnalysisDataStorage::finishFrame()).
171          * Must not be called for non-multipoint data.
172          *
173          * After this method has been called, all values appear as not set.
174          *
175          * Calls AbstractAnalysisData::notifyPointsAdd(), and throws any
176          * exception this method throws.
177          */
178         void finishPointSet();
179         /*! \brief
180          * Finish storing a frame.
181          *
182          * Must be called exactly once for each frame returned by startFrame(),
183          * after the corresponding call.
184          * The frame object must not be accessed after the call.
185          *
186          * Calls notification methods in AbstractAnalysisData, and throws any
187          * exceptions these methods throw.
188          */
189         void finishFrame();
190
191     private:
192
193         /*! \brief
194          * Create a new storage frame.
195          *
196          * \param[in] columnCount  Number of columns for the frame.
197          */
198         explicit AnalysisDataStorageFrame(int columnCount);
199
200         //! Clear all column values from the frame.
201         void clearValues();
202
203         //! Implementation data.
204         internal::AnalysisDataStorageFrameData *data_;
205         //! Values for the currently in-progress point set.
206         std::vector<AnalysisDataValue>          values_;
207
208         //! Whether any values have been set in the current point set.
209         bool                                    bPointSetInProgress_;
210
211         //! Needed for access to the constructor.
212         friend class AnalysisDataStorage;
213         //! Needed for managing the frame the object points to.
214         friend class internal::AnalysisDataStorageFrameData;
215
216         GMX_DISALLOW_COPY_AND_ASSIGN(AnalysisDataStorageFrame);
217 };
218
219 /*! \libinternal \brief
220  * Helper class that implements storage of data.
221  *
222  * This class implements a standard way of storing data to avoid implementing
223  * storage in each class derived from AbstractAnalysisData separately.
224  * To use this class in a class derived from AbstractAnalysisData, a member
225  * variable of this type should be declared and the data storage methods
226  * forwarded to tryGetDataFrame() and requestStorage() in that object.
227  * Storage properties should be set up, and then startDataStorage() called
228  * after calling AbstractAnalysisData::notifyDataStart().
229  * New frames can then be added using startFrame(), currentFrame() and
230  * finishFrame() methods.  These methods (and
231  * AnalysisDataStorageFrame::finishPointSet()) take the responsibility of
232  * calling AbstractAnalysisData::notifyFrameStart(),
233  * AbstractAnalysisData::notifyPointsAdd() and
234  * AbstractAnalysisData::notifyFrameFinish() appropriately.
235  *
236  * \todo
237  * Proper multi-threaded implementation.
238  *
239  * \inlibraryapi
240  * \ingroup module_analysisdata
241  */
242 class AnalysisDataStorage
243 {
244     public:
245         //! Constructs a storage object.
246         AnalysisDataStorage();
247         ~AnalysisDataStorage();
248
249         /*! \brief
250          * Set parallelization options for the storage.
251          *
252          * \param[in] opt  Parallization options to use.
253          *
254          * If this method is not called, the storage is set up for serial
255          * storage only.
256          *
257          * Does not throw.
258          */
259         void setParallelOptions(const AnalysisDataParallelOptions &opt);
260
261         /*! \brief
262          * Implements access to data frames.
263          *
264          * This method is designed such that calls to
265          * AbstractAnalysisData::tryGetDataFrameInternal() can be directly
266          * forwarded to this method.  See that method for more documentation.
267          *
268          * A valid reference for a frame will be returned after finishFrame()
269          * has been called for that frame.
270          *
271          * \see AbstractAnalysisData::tryGetDataFrameInternal()
272          */
273         AnalysisDataFrameRef tryGetDataFrame(int index) const;
274         /*! \brief
275          * Implements storage requests.
276          *
277          * This method is designed such that calls to
278          * AbstractAnalysisData::requestStorageInternal() can be directly
279          * forwarded to this method.  See that method for more documentation.
280          *
281          * \see AbstractAnalysisData::requestStorageInternal()
282          */
283         bool requestStorage(int nframes);
284
285         /*! \brief
286          * Start storing data.
287          *
288          * \param  data  AbstractAnalysisData object containing this storage.
289          * \exception std::bad_alloc if storage allocation fails.
290          *
291          * Lifetime of \p data must exceed the lifetime of the storage object
292          * (typically, the storage object will be a member in \p data).
293          * The storage object will take responsibility of calling
294          * AbstractAnalysisData::notifyFrameStart(),
295          * AbstractAnalysisData::notifyPointsAdd() and
296          * AbstractAnalysisData::notifyFrameFinish() for \p data appropriately.
297          *
298          * AbstractAnalysisData::notifyDataStart() must have been called for
299          * \p data, because that may trigger storage requests from attached
300          * modules.
301          */
302         void startDataStorage(AbstractAnalysisData *data);
303         /*! \brief
304          * Starts storing a new frame.
305          *
306          * \param[in] header  Header for the new frame.
307          * \retval  Frame object corresponding to the started frame.
308          * \exception std::bad_alloc if storage reallocation fails
309          *      (only possible if storage of all frames has been requested).
310          * \exception APIError if frame is too far in the future.
311          *
312          * The returned object will be valid until the corresponding
313          * finishFrame() call.
314          *
315          * Must be called exactly once for each frame index.
316          *
317          * Currently, the implementation only works if the new frame is not too
318          * far in the future:
319          * If \c i is the index of the last frame such that all frames from
320          * 0, ..., \c i have been finished, then \p header().index() should be
321          * at most \c 2*parallelizationFactor-1 larger than \c i, where
322          * parallelizationFactor is the parallelization factor passed to
323          * setParallelOptions().
324          * Throws APIError if this constraint is violated.
325          *
326          * Calls AbstractAnalysisData::notifyDataStarted() in certain cases,
327          * and throws any exceptions this method throws.
328          */
329         AnalysisDataStorageFrame &startFrame(const AnalysisDataFrameHeader &header);
330         /*! \brief
331          * Convenience method to start storing a new frame.
332          *
333          * Identical to \c startFrame(AnalysisDataFrameHeader(index, x, dx));
334          */
335         AnalysisDataStorageFrame &startFrame(int index, real x, real dx);
336         /*! \brief
337          * Obtain a frame object for an in-progress frame.
338          *
339          * \param[in] index  Frame index.
340          * \retval  Frame object corresponding to \p index.
341          *
342          * startFrame() should have been called for the frame with index
343          * \p index, and finishFrame() should not yet have been called.
344          * Returns the same object as returned by the original startFrame()
345          * call for the same index.
346          *
347          * Does not throw.
348          */
349         AnalysisDataStorageFrame &currentFrame(int index);
350         /*! \brief
351          * Convenience method for finishing a data frame.
352          *
353          * \param[in] index  Frame index.
354          *
355          * Identical to \c currentFrame(index).finishFrame().
356          *
357          * \see AnalysisDataStorageFrame::finishFrame()
358          */
359         void finishFrame(int index);
360
361     private:
362         class Impl;
363
364         PrivateImplPointer<Impl> impl_;
365
366         //! Needed because the frame needs to access the implementation class.
367         friend class internal::AnalysisDataStorageFrameData;
368 };
369
370 } // namespace gmx
371
372 #endif