Sort all includes in src/gromacs
[alexxy/gromacs.git] / src / gromacs / analysisdata / abstractdata.h
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 /*! \file
36  * \brief
37  * Declares gmx::AbstractAnalysisData.
38  *
39  * \author Teemu Murtola <teemu.murtola@gmail.com>
40  * \inlibraryapi
41  * \ingroup module_analysisdata
42  */
43 #ifndef GMX_ANALYSISDATA_ABSTRACTDATA_H
44 #define GMX_ANALYSISDATA_ABSTRACTDATA_H
45
46 #include <boost/shared_ptr.hpp>
47
48 #include "gromacs/utility/common.h"
49
50 namespace gmx
51 {
52
53 class AnalysisDataModuleInterface;
54 class AnalysisDataModuleManager;
55 class AnalysisDataFrameHeader;
56 class AnalysisDataFrameRef;
57 class AnalysisDataPointSetRef;
58
59 //! Smart pointer for managing a generic analysis data module.
60 typedef boost::shared_ptr<AnalysisDataModuleInterface> AnalysisDataModulePointer;
61
62 /*! \brief
63  * Abstract base class for all objects that provide data.
64  *
65  * The public interface includes methods for querying the data (isMultipoint(),
66  * dataSetCount(), columnCount(), frameCount(), tryGetDataFrame(),
67  * getDataFrame(), requestStorage()) and methods for using modules for
68  * processing the data (addModule(), addColumnModule(), applyModule()).
69  *
70  * Notice that even for non-const objects, the interface does not provide any
71  * means of altering the data.  It is only possible to add modules, making it
72  * relatively safe to return a non-const pointer of this type pointing to an
73  * internal data structure without worrying about possible modifications of the
74  * data.
75  *
76  * \if libapi
77  * This class also provides protected methods for use in derived classes.
78  * The properties returned by isMultipoint(), dataSetCount(), and columnCount()
79  * must be set using setMultipoint(), setDataSetCount(), and setColumnCount().
80  * notify*() methods in the AnalysisDataModuleManager returned by
81  * moduleManager() must be used to report when data becomes available for
82  * modules to process it.
83  * There are also three pure virtual methods that need to be implemented to
84  * provide access to stored data: one public (frameCount()) and two protected
85  * ones (requestStorageInternal() and tryGetDataFrameInternal()).
86  *
87  * It is up to subclasses to ensure that the virtual methods and the
88  * notifications in AnalysisDataModuleManager are called in a
89  * correct sequence (the methods will assert in most incorrect use cases), and
90  * that the data provided through the public interface matches that passed to
91  * the modules with the notify methods.
92  * Helper class AnalysisDataStorage provides a default implementation for
93  * storing data (calls to the pure virtual methods can simply be forwarded to
94  * appropriate methods in the helper class), and takes care of correctly
95  * calling the notification methods when new data is added to the storage.
96  * In most cases, it should be used to implement the derived classes.
97  * \endif
98  *
99  * Currently, it is not possible to continue using the data object if an
100  * attached module throws an exception during data processing; it is only safe
101  * to destroy such data object.
102  *
103  * \todo
104  * Improve the exception-handling semantics.  In most cases, it doesn't make
105  * much sense to continue data processing after one module fails, but having
106  * the alternative would not hurt.
107  *
108  * \inlibraryapi
109  * \ingroup module_analysisdata
110  */
111 class AbstractAnalysisData
112 {
113     public:
114         virtual ~AbstractAnalysisData();
115
116         /*! \brief
117          * Whether the data can have multiple points in the same column
118          * in the same frame.
119          *
120          * \returns \c true if multiple points in the same column are
121          *     allowed within a single frame.
122          *
123          * This kind of data can appear in many histogramming applications
124          * (e.g., RDFs), where each trajectory frame has several data points
125          * (possibly a different number for each frame). The current interface
126          * doesn't support storing such data, but this should rarely be
127          * necessary.
128          *
129          * The returned value does not change after modules have been notified
130          * of data start.
131          * \if libapi
132          * Derived classes can change the type by calling setMultipoint()
133          * subject to the above restriction.
134          * If this is not done, the function always returns false.
135          * \endif
136          *
137          * Does not throw.
138          */
139         bool isMultipoint() const;
140         /*! \brief
141          * Returns the number of data sets in the data object.
142          *
143          * \returns The number of data sets in the data.
144          *
145          * If the number is not yet known, returns 0.
146          * The returned value does not change after modules have been notified
147          * of data start, but may change multiple times before that, depending
148          * on the actual data class.
149          * \if libapi
150          * Derived classes should set the number of columns with
151          * setDataSetCount(), within the above limitations.
152          * \endif
153          *
154          * Does not throw.
155          */
156         int dataSetCount() const;
157         /*! \brief
158          * Returns the number of columns in a data set.
159          *
160          * \param[in] dataSet Zero-based index of the data set to query.
161          * \returns The number of columns in the data.
162          *
163          * If the number of columns is not yet known, returns 0.
164          * The returned value does not change after modules have been notified
165          * of data start, but may change multiple times before that, depending
166          * on the actual data class.
167          * \if libapi
168          * Derived classes should set the number of columns with
169          * setColumnCount(), within the above limitations.
170          * \endif
171          *
172          * Does not throw.
173          */
174         int columnCount(int dataSet) const;
175         /*! \brief
176          * Returns the number of columns in the data.
177          *
178          * \returns The number of columns in the data.
179          *
180          * This is a convenience method for data objects with a single data set.
181          * Can only be called if dataSetCount() == 1.
182          *
183          * Does not throw.
184          *
185          * \see columnCount(int)
186          */
187         int columnCount() const;
188         /*! \brief
189          * Returns the total number of frames in the data.
190          *
191          * \returns The total number of frames in the data.
192          *
193          * This function returns the number of frames that the object has
194          * produced.  If requestStorage() has been successfully called,
195          * tryGetDataframe() or getDataFrame() can be used to access some or
196          * all of these frames.
197          *
198          * Does not throw.
199          *
200          * \if libapi
201          * Derived classes should implement this to return the number of
202          * frames.  The frame count should not be incremented before
203          * tryGetDataFrameInternal() can return the new frame.
204          * The frame count must be incremented before
205          * AnalysisDataModuleManager::notifyFrameFinish() is called.
206          * \endif
207          */
208         virtual int frameCount() const = 0;
209         /*! \brief
210          * Access stored data.
211          *
212          * \param[in] index  Zero-based frame index to access.
213          * \returns   Frame reference to frame \p index, or an invalid
214          *      reference if no such frame is available.
215          *
216          * Does not throw.  Failure to access a frame with the given index is
217          * indicated through the return value.  Negative \p index is allowed,
218          * and will always result in an invalid reference being returned.
219          *
220          * \see requestStorage()
221          * \see getDataFrame()
222          */
223         AnalysisDataFrameRef tryGetDataFrame(int index) const;
224         /*! \brief
225          * Access stored data.
226          *
227          * \param[in] index  Zero-based frame index to access.
228          * \returns   Frame reference to frame \p index.
229          * \throws    APIError if the requested frame is not accessible.
230          *
231          * If the data is not certainly available, use tryGetDataFrame().
232          *
233          * \see requestStorage()
234          * \see tryGetDataFrame()
235          */
236         AnalysisDataFrameRef getDataFrame(int index) const;
237         /*! \brief
238          * Request storage of frames.
239          *
240          * \param[in] nframes  Request storing at least \c nframes previous
241          *     frames (-1 = request storing all). Must be >= -1.
242          * \returns true if the request could be satisfied.
243          *
244          * If called multiple times, the largest request is honored.
245          *
246          * Does not throw.  Failure to honor the request is indicated through
247          * the return value.
248          *
249          * \see getDataFrame()
250          * \see tryGetDataFrame()
251          */
252         bool requestStorage(int nframes);
253
254         /*! \brief
255          * Adds a module to process the data.
256          *
257          * \param     module  Module to add.
258          * \throws    std::bad_alloc if out of memory.
259          * \throws    APIError if
260          *      - \p module is not compatible with the data object
261          *      - data has already been added to the data object and everything
262          *        is not available through getDataFrame().
263          * \throws    unspecified Any exception thrown by \p module in its
264          *      notification methods (if data has been added).
265          *
266          * If data has already been added to the data, the new module
267          * immediately processes all existing data.  APIError is thrown
268          * if all data is not available through getDataFrame().
269          *
270          * The caller can keep a copy of the module pointer if it requires
271          * later access to the module.
272          *
273          * If the method throws, the state of the data object is not changed.
274          * The state of the data module is indeterminate.
275          */
276         void addModule(AnalysisDataModulePointer module);
277         /*! \brief
278          * Adds a module that processes only a subset of the columns.
279          *
280          * \param[in] col     First column.
281          * \param[in] span    Number of columns.
282          * \param     module  Module to add.
283          *
284          * Throws in the same situations as addModule().
285          *
286          * Currently, all data sets are filtered using the same column mask.
287          *
288          * \todo
289          * This method doesn't currently work in all cases with multipoint
290          * data or with multiple data sets.  In particular, if the added module
291          * requests storage and uses getDataFrame(), it will behave
292          * unpredictably (most likely asserts).
293          *
294          * \todo
295          * Generalize this method to multiple data sets (e.g., for adding
296          * modules that only process a single data set).
297          *
298          * \see addModule()
299          */
300         void addColumnModule(int col, int span, AnalysisDataModulePointer module);
301         /*! \brief
302          * Applies a module to process data that is ready.
303          *
304          * \param     module  Module to apply.
305          * \throws    APIError in same situations as addModule().
306          * \throws    unspecified Any exception thrown by \p module in its
307          *      notification methods.
308          *
309          * This function works as addModule(), except that it does not keep a
310          * reference to \p module within the data object after it returns.
311          * Also, it can only be called after the data is ready, and only if
312          * getDataFrame() gives access to all of the data.
313          * It is provided for additional flexibility in postprocessing
314          * in-memory data.
315          *
316          * \todo
317          * Currently, this method may not work correctly if \p module requests
318          * storage (addModule() has the same problem if called after data is
319          * started).
320          */
321         void applyModule(AnalysisDataModuleInterface *module);
322
323     protected:
324         /*! \cond libapi */
325         /*! \brief
326          * Initializes a new analysis data object.
327          *
328          * \throws std::bad_alloc if out of memory.
329          */
330         AbstractAnalysisData();
331
332         /*! \brief
333          * Sets the number of data sets.
334          *
335          * \param[in] dataSetCount  Number of data sets (must be > 0).
336          * \throws    std::bad_alloc if out of memory.
337          * \throws    APIError if modules have been added that are not
338          *      compatible with the new data set count.
339          *
340          * It not called, the data object has a single data set.  Can be called
341          * only before AnalysisDataModuleManager::notifyDataStart().
342          * Multiple calls are allowed before that point; the last call takes
343          * effect.
344          *
345          * Strong exception safety.
346          *
347          * \see dataSetCount()
348          */
349         void setDataSetCount(int dataSetCount);
350         /*! \brief
351          * Sets the number of columns for a data set.
352          *
353          * \param[in] dataSet      Zero-based index of the data set.
354          * \param[in] columnCount  Number of columns in \p dataSet (must be > 0).
355          * \throws    APIError if modules have been added that are not
356          *      compatible with the new column count.
357          *
358          * Must be called at least once for each data set before
359          * AnalysisDataModuleManager::notifyDataStart().  Can be called only
360          * before AnalysisDataModuleManager::notifyDataStart().
361          * Multiple calls are allowed before that point; the last call takes
362          * effect.
363          *
364          * Strong exception safety.
365          *
366          * \see columnCount()
367          */
368         void setColumnCount(int dataSet, int columnCount);
369         /*! \brief
370          * Sets whether the data has multiple points per column in a frame.
371          *
372          * \param[in] bMultipoint  Whether multiple points per column are
373          *     possible.
374          * \throws    APIError if modules have been added that are not
375          *      compatible with the new setting.
376          *
377          * If not called, only a single point per column is allowed.  Can be
378          * called only before AnalysisDataModuleManager::notifyDataStart().
379          * Multiple calls are allowed before that point; the last call takes
380          * effect.
381          *
382          * Strong exception safety.
383          *
384          * \see isMultipoint()
385          */
386         void setMultipoint(bool bMultipoint);
387
388         /*! \brief
389          * Implements access to data frames.
390          *
391          * \param[in] index  Zero-based frame index to access.
392          * \returns   Frame reference to frame \p index, or an invalid
393          *      reference if no such frame is available.
394          *
395          * Must not throw.  Failure to access a frame with the given index is
396          * indicated through the return value.
397          *
398          * Code in derived classes can assume that \p index is non-negative and
399          * less than frameCount().
400          *
401          * Derived classes can choose to return an invalid reference if
402          * requestStorageInternal() has not been called at all, or if the frame
403          * is too old (compared to the value given to requestStorageInternal()).
404          *
405          * This method is called internally by tryGetDataFrame() and
406          * getDataFrame().
407          *
408          * \see AnalysisDataStorage
409          */
410         virtual AnalysisDataFrameRef tryGetDataFrameInternal(int index) const = 0;
411         /*! \brief
412          * Implements storage requests.
413          *
414          * \param[in] nframes  Request storing at least \c nframes previous
415          *     frames (-1 = request storing all). Will be either -1 or >0.
416          * \returns   true if the request could be satisfied.
417          *
418          * Must not throw.  Failure to access a frame with the given index is
419          * indicated through the return value.
420          *
421          * Derived classes should be prepared for any number of calls to this
422          * method before notifyDataStart() is called (and during that call).
423          *
424          * This method is called internally by requestStorage().
425          *
426          * \see AnalysisDataStorage
427          */
428         virtual bool requestStorageInternal(int nframes) = 0;
429
430         //! Returns the module manager to use for calling notification methods.
431         AnalysisDataModuleManager       &moduleManager();
432         //! Returns the module manager to use for calling notification methods.
433         const AnalysisDataModuleManager &moduleManager() const;
434         //! \endcond
435
436     private:
437         class Impl;
438
439         PrivateImplPointer<Impl> impl_;
440 };
441
442 } // namespace gmx
443
444 #endif