Merge branch release-4-6 into release-5-0
[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,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::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         //! Returns whether this data handle is valid.
246         bool isValid() const { return impl_ != NULL; }
247
248         /*! \brief
249          * Start data for a new frame.
250          *
251          * \param[in] index  Zero-based index for the frame to start.
252          * \param[in] x      x value for the frame.
253          * \param[in] dx     Error in x for the frame if applicable.
254          *
255          * \throws    unspecified  Any exception thrown by attached data
256          *      modules in AnalysisDataModuleInterface::frameStarted().
257          *
258          * Each \p index value 0, 1, ..., N (where N is the total number of
259          * frames) should be started exactly once by exactly one handle of an
260          * AnalysisData object.  The frames may be started out of order, but
261          * currently the implementation places some limitations on how far
262          * the index can be in the future (as counted from the first frame that
263          * is not finished).
264          */
265         void startFrame(int index, real x, real dx = 0.0);
266         /*! \brief
267          * Selects a data set for subsequent setPoint()/setPoints() calls.
268          *
269          * \param[in] index  Zero-based data set index.
270          *
271          * After startFrame(), the first data set is always selected.
272          * The set value is remembered until the end of the current frame, also
273          * across finishPointSet() calls.
274          *
275          * Does not throw.
276          */
277         void selectDataSet(int index);
278         /*! \brief
279          * Set a value for a single column for the current frame.
280          *
281          * \param[in] column  Zero-based column index.
282          * \param[in] value   Value to set for the column.
283          * \param[in] bPresent Present flag to set for the column.
284          *
285          * If called multiple times for a column (within one point set for
286          * multipoint data), old values are overwritten.
287          *
288          * Does not throw.
289          */
290         void setPoint(int column, real value, bool bPresent = true);
291         /*! \brief
292          * Set a value and its error estimate for a single column for the
293          * current frame.
294          *
295          * \param[in] column  Zero-based column index.
296          * \param[in] value   Value to set for the column.
297          * \param[in] error   Error estimate to set for the column.
298          * \param[in] bPresent Present flag to set for the column.
299          *
300          * If called multiple times for a column (within one point set for
301          * multipoint data), old values are overwritten.
302          *
303          * Does not throw.
304          */
305         void setPoint(int column, real value, real error, bool bPresent = true);
306         /*! \brief
307          * Set values for consecutive columns for the current frame.
308          *
309          * \param[in] firstColumn  Zero-based column index.
310          * \param[in] count        Number of columns to set.
311          * \param[in] values       Value array of \p column items.
312          *
313          * Equivalent to calling setPoint(firstColumn + i, values[i]) for
314          * i from 0 to count.
315          *
316          * Does not throw.
317          */
318         void setPoints(int firstColumn, int count, const real *values);
319         /*! \brief
320          * Finish data for the current point set.
321          *
322          * \throws    APIError if any attached data module is not compatible.
323          * \throws    unspecified  Any exception thrown by attached data
324          *      modules in AnalysisDataModuleInterface::pointsAdded().
325          *
326          * Must be called after each point set for multipoint data, including
327          * the last (i.e., no values must be set between the last call to this
328          * method and AnalysisDataStorage::finishFrame()).
329          * Must not be called for non-multipoint data.
330          */
331         void finishPointSet();
332         /*! \brief
333          * Finish data for the current frame.
334          *
335          * \throws    APIError if any attached data module is not compatible.
336          * \throws    unspecified  Any exception thrown by attached data
337          *      modules in frame notification methods.
338          */
339         void finishFrame();
340         //! Calls AnalysisData::finishData() for this handle.
341         void finishData();
342
343     private:
344         /*! \brief
345          * Creates a new data handle associated with \p data.
346          *
347          * \param  impl Data to associate the handle with.
348          *
349          * The constructor is private because data handles should only be
350          * constructed through AnalysisData::startData().
351          *
352          * Does not throw.
353          */
354         explicit AnalysisDataHandle(internal::AnalysisDataHandleImpl *impl);
355
356         /*! \brief
357          * Pointer to the internal implementation class.
358          *
359          * The memory for this object is managed by the AnalysisData object,
360          * and AnalysisDataHandle simply provides a public interface for
361          * accessing the implementation.
362          */
363         internal::AnalysisDataHandleImpl *impl_;
364
365         /*! \brief
366          * Needed to access the non-public implementation.
367          */
368         friend class AnalysisData;
369 };
370
371 } // namespace gmx
372
373 #endif