Merge branch release-4-6
[alexxy/gromacs.git] / src / gromacs / analysisdata / analysisdata.h
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2010,2011,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 /*! \file
36  * \brief
37  * Declares gmx::AnalysisData and gmx::AnalysisDataHandle.
38  *
39  * \author Teemu Murtola <teemu.murtola@gmail.com>
40  * \inpublicapi
41  * \ingroup module_analysisdata
42  */
43 #ifndef GMX_ANALYSISDATA_ANALYSISDATA_H
44 #define GMX_ANALYSISDATA_ANALYSISDATA_H
45
46 #include "abstractdata.h"
47
48 namespace gmx
49 {
50
51 class AnalysisDataHandle;
52 class AnalysisDataParallelOptions;
53
54 /*! \brief
55  * Parallelizable data container for raw data.
56  *
57  * This is the main class used to implement parallelizable data processing in
58  * analysis tools.  It is used by first creating an object and setting its
59  * properties using setDataSetCount(), setColumnCount() and setMultipoint(),
60  * and attaching necessary modules using addModule() etc.  Then one or more
61  * AnalysisDataHandle objects can be created using startData().  Each data
62  * handle can then be independently used to provide data frames (each frame
63  * must be provided by a single handle, but different frames can be freely
64  * mixed between the handles).  When all data has been provided, the handles
65  * are destroyed using finishData() (or AnalysisDataHandle::finishData()).
66  * The AnalysisData object takes care of internally sorting the frames and
67  * passing them to the attached modules in the order in which the modules
68  * expect them.
69  *
70  * \todo
71  * Parallel implementation is not complete.
72  *
73  * \if internal
74  * Special note for MPI implementation: assuming that the initialization of
75  * data objects is identical in all processes, associating the data objects
76  * in different MPI processes should be possible without changes in the
77  * interface.
78  * Alternative, more robust implementation could get a unique ID as parameter
79  * to the constructor or a separate function, but would require all tools to
80  * provide it.  With the current registration mechanism in
81  * TrajectoryAnalysisModule, this should be straightforward.
82  * \endif
83  *
84  * \inpublicapi
85  * \ingroup module_analysisdata
86  */
87 class AnalysisData : public AbstractAnalysisData
88 {
89     public:
90         /*! \brief
91          * Creates an empty analysis data object.
92          *
93          * \throws std::bad_alloc if out of memory.
94          */
95         AnalysisData();
96         virtual ~AnalysisData();
97
98         /*! \brief
99          * Sets the number of data sets.
100          *
101          * \param[in] dataSetCount  Number of data sets (must be > 0).
102          * \throws    std::bad_alloc if out of memory.
103          * \throws    APIError if modules have been added that are not
104          *      compatible with the new data set count.
105          *
106          * Must not be called after startData() has been called.
107          * If not called, a single data set is assumed.
108          * If called multiple times, the last call takes effect.
109          */
110         void setDataSetCount(int dataSetCount);
111         /*! \brief
112          * Sets the number of columns in a data set.
113          *
114          * \param[in] dataSet      Zero-based data set index.
115          * \param[in] columnCount  Number of columns in the data (must be > 0).
116          * \throws    APIError if modules have been added that are not
117          *      compatible with the new column count.
118          *
119          * Must be called before startData() for each data set.
120          * Must not be called after startData() has been called.
121          * If called multiple times for a data set, the last call takes effect.
122          */
123         void setColumnCount(int dataSet, int columnCount);
124         /*! \brief
125          * Sets whether the data contains multiple points per column per frame.
126          *
127          * \param[in] bMultipoint  Whether the data will allow multiple points
128          *      per column within a single frame.
129          * \throws    APIError if modules have been added that are not
130          *      compatible with the new setting.
131          *
132          * If this method is not called, the data is not multipoint.
133          *
134          * Must not be called after startData() has been called.
135          *
136          * \see isMultipoint()
137          */
138         void setMultipoint(bool bMultipoint);
139
140         virtual int frameCount() const;
141
142         /*! \brief
143          * Create a handle for adding data.
144          *
145          * \param[in]  opt     Options for setting how this handle will be
146          *     used.
147          * \returns The created handle.
148          * \throws  std::bad_alloc if out of memory.
149          * \throws  APIError if any attached data module is not compatible.
150          * \throws  unspecified  Any exception thrown by attached data modules
151          *      in AnalysisDataModuleInterface::dataStarted().
152          *
153          * The caller should retain the returned handle (or a copy of it), and
154          * pass it to finishData() after successfully adding all data.
155          * The caller should discard the returned handle if an error occurs;
156          * memory allocated for the handle will be freed when the AnalysisData
157          * object is destroyed.
158          *
159          * The \p opt options should be the same for all calls to this method,
160          * and the number of calls should match the parallelization factor
161          * defined in \p opt.
162          */
163         AnalysisDataHandle startData(const AnalysisDataParallelOptions &opt);
164         /*! \brief
165          * Destroy a handle after all data has been added.
166          *
167          * \param[in]  handle  Handle to destroy.
168          * \throws  unspecified  Any exception thrown by attached data modules
169          *      in AnalysisDataModuleInterface::dataFinished().
170          *
171          * \p handle must have been obtained from startData() of this object.
172          * The order of the calls with respect to the corresponding startData()
173          * calls is not important.
174          *
175          * The \p handle (and any copies) are invalid after the call.
176          */
177         void finishData(AnalysisDataHandle handle);
178
179     private:
180         virtual AnalysisDataFrameRef tryGetDataFrameInternal(int index) const;
181         virtual bool requestStorageInternal(int nframes);
182
183         class Impl;
184
185         PrivateImplPointer<Impl> impl_;
186
187         friend class AnalysisDataHandle;
188 };
189
190 namespace internal
191 {
192 class AnalysisDataHandleImpl;
193 }   // namespace internal
194
195 /*! \brief
196  * Handle for inserting data into AnalysisData.
197  *
198  * This class provides an interface for adding data frames into an AnalysisData
199  * object.  After a handle is obtained from AnalysisData::startData(), new
200  * frames can be added using startFrame().  Then values for that frame are set
201  * using provided methods (see below), and finishFrame() is called.  After all
202  * frames have been added, finishData() (or AnalysisData::finishData()) must be
203  * called.
204  *
205  * For simple (non-multipoint) data, within a frame values can be set using
206  * selectDataSet(), setPoint() and setPoints().  Setting the same column in the
207  * same data set multiple times overrides previously set values.
208  * When the frame is finished, attached modules are notified.
209  *
210  * Multipoint data works otherwise similarly, but requires finishPointSet() to
211  * be called for each set of points for which the modules need to be notified.
212  * Each point set starts empty (after startFrame() or finishPointSet()), and
213  * values can be set using setPoint()/setPoints().
214  * A single point set can contain values only for a single data set, which must
215  * be selected with selectDataSet() before setting any values.
216  * finishPointSet() must also be called for the last point set just before
217  * finishFrame().
218  *
219  * This class works like a pointer type: copying and assignment is lightweight,
220  * and all copies work interchangeably, accessing the same internal handle.
221  * However, normally you should only keep one copy of a handle, i.e., treat
222  * this type as movable.
223  * Several handles created from the same AnalysisData object can exist
224  * concurrently, but must currently operate on separate frames.
225  *
226  * \inpublicapi
227  * \ingroup module_analysisdata
228  */
229 class AnalysisDataHandle
230 {
231     public:
232         /*! \brief
233          * Constructs an invalid data handle.
234          *
235          * This constructor is provided for convenience in cases where it is
236          * easiest to declare an AnalysisDataHandle without immediately
237          * assigning a value to it.  Any attempt to call methods without first
238          * assigning a value from AnalysisData::startData() to the handle
239          * causes an assert.
240          *
241          * Does not throw.
242          */
243         AnalysisDataHandle();
244
245         /*! \brief
246          * Start data for a new frame.
247          *
248          * \param[in] index  Zero-based index for the frame to start.
249          * \param[in] x      x value for the frame.
250          * \param[in] dx     Error in x for the frame if applicable.
251          *
252          * \throws    unspecified  Any exception thrown by attached data
253          *      modules in AnalysisDataModuleInterface::frameStarted().
254          *
255          * Each \p index value 0, 1, ..., N (where N is the total number of
256          * frames) should be started exactly once by exactly one handle of an
257          * AnalysisData object.  The frames may be started out of order, but
258          * currently the implementation places some limitations on how far
259          * the index can be in the future (as counted from the first frame that
260          * is not finished).
261          */
262         void startFrame(int index, real x, real dx = 0.0);
263         /*! \brief
264          * Selects a data set for subsequent setPoint()/setPoints() calls.
265          *
266          * \param[in] index  Zero-based data set index.
267          *
268          * After startFrame(), the first data set is always selected.
269          * The set value is remembered until the end of the current frame, also
270          * across finishPointSet() calls.
271          *
272          * Does not throw.
273          */
274         void selectDataSet(int index);
275         /*! \brief
276          * Set a value for a single column for the current frame.
277          *
278          * \param[in] column  Zero-based column index.
279          * \param[in] value   Value to set for the column.
280          * \param[in] bPresent Present flag to set for the column.
281          *
282          * If called multiple times for a column (within one point set for
283          * multipoint data), old values are overwritten.
284          *
285          * Does not throw.
286          */
287         void setPoint(int column, real value, bool bPresent = true);
288         /*! \brief
289          * Set a value and its error estimate for a single column for the
290          * current frame.
291          *
292          * \param[in] column  Zero-based column index.
293          * \param[in] value   Value to set for the column.
294          * \param[in] error   Error estimate to set for the column.
295          * \param[in] bPresent Present flag to set for the column.
296          *
297          * If called multiple times for a column (within one point set for
298          * multipoint data), old values are overwritten.
299          *
300          * Does not throw.
301          */
302         void setPoint(int column, real value, real error, bool bPresent = true);
303         /*! \brief
304          * Set values for consecutive columns for the current frame.
305          *
306          * \param[in] firstColumn  Zero-based column index.
307          * \param[in] count        Number of columns to set.
308          * \param[in] values       Value array of \p column items.
309          *
310          * Equivalent to calling setPoint(firstColumn + i, values[i]) for
311          * i from 0 to count.
312          *
313          * Does not throw.
314          */
315         void setPoints(int firstColumn, int count, const real *values);
316         /*! \brief
317          * Finish data for the current point set.
318          *
319          * \throws    APIError if any attached data module is not compatible.
320          * \throws    unspecified  Any exception thrown by attached data
321          *      modules in AnalysisDataModuleInterface::pointsAdded().
322          *
323          * Must be called after each point set for multipoint data, including
324          * the last (i.e., no values must be set between the last call to this
325          * method and AnalysisDataStorage::finishFrame()).
326          * Must not be called for non-multipoint data.
327          */
328         void finishPointSet();
329         /*! \brief
330          * Finish data for the current frame.
331          *
332          * \throws    APIError if any attached data module is not compatible.
333          * \throws    unspecified  Any exception thrown by attached data
334          *      modules in frame notification methods.
335          */
336         void finishFrame();
337         //! Calls AnalysisData::finishData() for this handle.
338         void finishData();
339
340     private:
341         /*! \brief
342          * Creates a new data handle associated with \p data.
343          *
344          * \param  data Data to associate the handle with.
345          *
346          * The constructor is private because data handles should only be
347          * constructed through AnalysisData::startData().
348          *
349          * Does not throw.
350          */
351         explicit AnalysisDataHandle(internal::AnalysisDataHandleImpl *impl);
352
353         /*! \brief
354          * Pointer to the internal implementation class.
355          *
356          * The memory for this object is managed by the AnalysisData object,
357          * and AnalysisDataHandle simply provides a public interface for
358          * accessing the implementation.
359          */
360         internal::AnalysisDataHandleImpl *impl_;
361
362         /*! \brief
363          * Needed to access the non-public implementation.
364          */
365         friend class AnalysisData;
366 };
367
368 } // namespace gmx
369
370 #endif