Merge release-4-6 into master
[alexxy/gromacs.git] / src / gromacs / analysisdata / datastorage.h
1 /*
2  *
3  *                This source code is part of
4  *
5  *                 G   R   O   M   A   C   S
6  *
7  *          GROningen MAchine for Chemical Simulations
8  *
9  * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
10  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
11  * Copyright (c) 2001-2009, The GROMACS development team,
12  * check out http://www.gromacs.org for more information.
13
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  *
19  * If you want to redistribute modifications, please consider that
20  * scientific software is very special. Version control is crucial -
21  * bugs must be traceable. We will be happy to consider code for
22  * inclusion in the official distribution, but derived work must not
23  * be called official GROMACS. Details are found in the README & COPYING
24  * files - if they are missing, get the official version at www.gromacs.org.
25  *
26  * To help us fund GROMACS development, we humbly ask that you cite
27  * the papers on the package - you can find them in the top README file.
28  *
29  * For more info, check our website at http://www.gromacs.org
30  */
31 /*! \libinternal \file
32  * \brief
33  * Declares gmx::AnalysisDataStorage.
34  *
35  * \author Teemu Murtola <teemu.murtola@cbr.su.se>
36  * \inlibraryapi
37  * \ingroup module_analysisdata
38  */
39 #ifndef GMX_ANALYSISDATA_DATASTORAGE_H
40 #define GMX_ANALYSISDATA_DATASTORAGE_H
41
42 #include <vector>
43
44 #include "../legacyheaders/types/simple.h"
45
46 #include "../utility/common.h"
47 #include "../utility/gmxassert.h"
48
49 #include "dataframe.h"
50
51 namespace gmx
52 {
53
54 class AbstractAnalysisData;
55 class AnalysisDataFrameHeader;
56 class AnalysisDataFrameRef;
57 class AnalysisDataParallelOptions;
58
59 class AnalysisDataStorage;
60
61 /*! \libinternal \brief
62  * Stores a single data frame for AnalysisDataStorage.
63  *
64  * It also provides access to the frame outside AnalysisDataStorage.
65  *
66  * It is implemented such that the frame header is always valid, i.e.,
67  * header().isValid() returns always true.
68  *
69  * \inlibraryapi
70  * \ingroup module_analysisdata
71  */
72 class AnalysisDataStorageFrame
73 {
74     public:
75         /*! \brief Frees the frame object.
76          *
77          * Should not be called outside AnalysisDataStorage.
78          */
79         ~AnalysisDataStorageFrame();
80
81         //! Returns header for the frame.
82         const AnalysisDataFrameHeader &header() const { return header_; }
83         //! Returns zero-based index of the frame.
84         int frameIndex() const { return header().index(); }
85         //! Returns x coordinate for the frame.
86         real x() const { return header().x(); }
87         //! Returns error in x coordinate for the frame if applicable.
88         real dx() const { return header().dx(); }
89         //! Returns number of columns for the frame.
90         int columnCount() const { return values_.size(); }
91
92         /*! \brief
93          * Returns point set reference to currently set values.
94          *
95          * Does not throw.
96          */
97         AnalysisDataPointSetRef currentPoints() const;
98         /*! \brief
99          * Sets value for a column.
100          *
101          * \param[in] column  Zero-based column index.
102          * \param[in] value   Value to set for the column.
103          * \param[in] bPresent Present flag to set for the column.
104          *
105          * If called multiple times for a column (within one point set for
106          * multipoint data), old values are overwritten.
107          *
108          * Does not throw.
109          */
110         void setValue(int column, real value, bool bPresent = true)
111         {
112             GMX_ASSERT(column >= 0 && column < columnCount(),
113                        "Invalid column index");
114             values_[column].setValue(value, bPresent);
115         }
116         /*! \brief
117          * Sets value for a column.
118          *
119          * \param[in] column  Zero-based column index.
120          * \param[in] value   Value to set for the column.
121          * \param[in] error   Error estimate to set for the column.
122          * \param[in] bPresent Present flag to set for the column.
123          *
124          * If called multiple times for a column (within one point set for
125          * multipoint data), old values are overwritten.
126          *
127          * Does not throw.
128          */
129         void setValue(int column, real value, real error, bool bPresent = true)
130         {
131             GMX_ASSERT(column >= 0 && column < columnCount(),
132                        "Invalid column index");
133             values_[column].setValue(value, error, bPresent);
134         }
135         /*! \brief
136          * Access value for a column.
137          *
138          * \param[in] column  Zero-based column index.
139          *
140          * Should only be called after the column value has been set using
141          * setValue(); assigning a value to \c value(i) does not mark the
142          * column as set.
143          *
144          * Does not throw.
145          */
146         real &value(int column)
147         {
148             GMX_ASSERT(column >= 0 && column < columnCount(),
149                        "Invalid column index");
150             return values_[column].value();
151         }
152         /*! \brief
153          * Access value for a column.
154          *
155          * \param[in] column  Zero-based column index.
156          *
157          * Should only be called after the column value has been set using
158          * setValue().
159          *
160          * Does not throw.
161          */
162         real value(int column) const
163         {
164             GMX_ASSERT(column >= 0 && column < columnCount(),
165                        "Invalid column index");
166             return values_[column].value();
167         }
168         /*! \brief
169          * Mark point set as finished for multipoint data.
170          *
171          * Must be called after each point set for multipoint data, including
172          * the last (i.e., no values must be set between the last call to this
173          * method and AnalysisDataStorage::finishFrame()).
174          * Must not be called for non-multipoint data.
175          *
176          * After this method has been called, all values appear as not set.
177          *
178          * Calls AbstractAnalysisData::notifyPointsAdd(), and throws any
179          * exception this method throws.
180          */
181         void finishPointSet();
182
183     private:
184         /*! \brief
185          * Create a new storage frame.
186          *
187          * \param     storage      Storage object this frame belongs to.
188          * \param[in] columnCount  Number of columns for the frame.
189          * \param[in] index        Zero-based index for the frame.
190          */
191         AnalysisDataStorageFrame(AnalysisDataStorage *storage, int columnCount,
192                                  int index);
193
194         //! Clear all column values from the frame.
195         void clearValues();
196
197         //! Storage object that contains this frame.
198         AnalysisDataStorage    &storage_;
199         //! Header for the frame.
200         AnalysisDataFrameHeader header_;
201         //! Values for the frame.
202         std::vector<AnalysisDataValue> values_;
203
204         /*! \brief
205          * Needed for full write access to the data and for access to
206          * constructor/destructor.
207          */
208         friend class AnalysisDataStorage;
209
210         GMX_DISALLOW_COPY_AND_ASSIGN(AnalysisDataStorageFrame);
211 };
212
213 /*! \libinternal \brief
214  * Helper class that implements storage of data.
215  *
216  * This class implements a standard way of storing data to avoid implementing
217  * storage in each class derived from AbstractAnalysisData separately.
218  * To use this class in a class derived from AbstractAnalysisData, a member
219  * variable of this type should be declared and the data storage methods
220  * forwarded to tryGetDataFrame() and requestStorage() in that object.
221  * Storage properties should be set up, and then startDataStorage() called
222  * after calling AbstractAnalysisData::notifyDataStart().
223  * New frames can then be added using startFrame(), currentFrame() and
224  * finishFrame() methods.  These methods (and
225  * AnalysisDataStorageFrame::finishPointSet()) take the responsibility of
226  * calling AbstractAnalysisData::notifyFrameStart(),
227  * AbstractAnalysisData::notifyPointsAdd() and
228  * AbstractAnalysisData::notifyFrameFinish() appropriately.
229  *
230  * \todo
231  * Full support for multipoint data.
232  * Currently, multipoint data is only supported in serial pass-through mode
233  * without any storage.
234  *
235  * \todo
236  * Proper multi-threaded implementation.
237  *
238  * \inlibraryapi
239  * \ingroup module_analysisdata
240  */
241 class AnalysisDataStorage
242 {
243     public:
244         //! Constructs a storage object.
245         AnalysisDataStorage();
246         ~AnalysisDataStorage();
247
248         /*! \brief
249          * Sets whether the data will be multipoint.
250          *
251          * \exception APIError if storage has been requested.
252          *
253          * It is not mandatory to call this method (the multipoint property is
254          * automatically detected in startDataStorage()), but currently calling
255          * it will produce better diagnostic messages.
256          * When full support for multipoint data has been implemented, this
257          * method can be removed.
258          */
259         void setMultipoint(bool bMultipoint);
260         /*! \brief
261          * Set parallelization options for the storage.
262          *
263          * \param[in] opt  Parallization options to use.
264          *
265          * If this method is not called, the storage is set up for serial
266          * storage only.
267          *
268          * Does not throw.
269          */
270         void setParallelOptions(const AnalysisDataParallelOptions &opt);
271
272         /*! \brief
273          * Implements access to data frames.
274          *
275          * This method is designed such that calls to
276          * AbstractAnalysisData::tryGetDataFrameInternal() can be directly
277          * forwarded to this method.  See that method for more documentation.
278          *
279          * A valid reference for a frame will be returned after finishFrame()
280          * has been called for that frame.
281          *
282          * \see AbstractAnalysisData::tryGetDataFrameInternal()
283          */
284         AnalysisDataFrameRef tryGetDataFrame(int index) const;
285         /*! \brief
286          * Implements storage requests.
287          *
288          * This method is designed such that calls to
289          * AbstractAnalysisData::requestStorageInternal() can be directly
290          * forwarded to this method.  See that method for more documentation.
291          *
292          * Currently, multipoint data cannot be stored, but all other storage
293          * request will be honored.
294          *
295          * \see AbstractAnalysisData::requestStorageInternal()
296          */
297         bool requestStorage(int nframes);
298
299         /*! \brief
300          * Start storing data.
301          *
302          * \param  data  AbstractAnalysisData object containing this storage.
303          * \exception std::bad_alloc if storage allocation fails.
304          * \exception APIError if storage has been requested and \p data is
305          *      multipoint.
306          *
307          * Lifetime of \p data must exceed the lifetime of the storage object
308          * (typically, the storage object will be a member in \p data).
309          * The storage object will take responsibility of calling
310          * AbstractAnalysisData::notifyFrameStart(),
311          * AbstractAnalysisData::notifyPointsAdd() and
312          * AbstractAnalysisData::notifyFrameFinish() for \p data appropriately.
313          *
314          * AbstractAnalysisData::notifyDataStart() must have been called for
315          * \p data, because that may trigger storage requests from attached
316          * modules.
317          */
318         void startDataStorage(AbstractAnalysisData *data);
319         /*! \brief
320          * Starts storing a new frame.
321          *
322          * \param[in] header  Header for the new frame.
323          * \retval  Frame object corresponding to the started frame.
324          * \exception std::bad_alloc if storage reallocation fails
325          *      (only possible if storage of all frames has been requested).
326          * \exception APIError if frame is too far in the future.
327          *
328          * The returned object will be valid until the corresponding
329          * finishFrame() call.
330          *
331          * Must be called exactly once for each frame index.
332          *
333          * Currently, the implementation only works if the new frame is not too
334          * far in the future:
335          * If \c i is the index of the last frame such that all frames from
336          * 0, ..., \c i have been finished, then \p header().index() should be
337          * at most \c 2*parallelizationFactor-1 larger than \c i, where
338          * parallelizationFactor is the parallelization factor passed to
339          * setParallelOptions().
340          * Throws APIError if this constraint is violated.
341          *
342          * Calls AbstractAnalysisData::notifyDataStarted() in certain cases,
343          * and throws any exceptions this method throws.
344          */
345         AnalysisDataStorageFrame &startFrame(const AnalysisDataFrameHeader &header);
346         /*! \brief
347          * Convenience method to start storing a new frame.
348          *
349          * Identical to \c startFrame(AnalysisDataFrameHeader(index, x, dx));
350          */
351         AnalysisDataStorageFrame &startFrame(int index, real x, real dx);
352         /*! \brief
353          * Obtain a frame object for an in-progress frame.
354          *
355          * \param[in] index  Frame index.
356          * \retval  Frame object corresponding to \p index.
357          *
358          * startFrame() should have been called for the frame with index
359          * \p index, and finishFrame() should not yet have been called.
360          * Returns the same object as returned by the original startFrame()
361          * call for the same index.
362          *
363          * Does not throw.
364          */
365         AnalysisDataStorageFrame &currentFrame(int index);
366         /*! \brief
367          * Finish storing a frame.
368          *
369          * \param[in] index  Frame index.
370          *
371          * Must be called exactly once for each startFrame(), after the
372          * corresponding call.
373          *
374          * Calls notification methods in AbstractAnalysisData, and throws any
375          * exceptions these methods throw.
376          */
377         void finishFrame(int index);
378         /*! \brief
379          * Convenience method for finishing a data frame.
380          *
381          * \param[in] frame  Frame object to finish.
382          *
383          * \p frame should have been previously obtained from startFrame() or
384          * currentFrame().  The \p frame reference is no longer valid after the
385          * call.
386          *
387          * Identical to \c finishframe(frame.frameIndex());
388          */
389         void finishFrame(const AnalysisDataStorageFrame &frame);
390
391     private:
392         class Impl;
393
394         PrivateImplPointer<Impl> impl_;
395
396         /*! \brief
397          * Needed because the frame object needs to trigger notifications.
398          */
399         friend void AnalysisDataStorageFrame::finishPointSet();
400 };
401
402 } // namespace gmx
403
404 #endif