Apply clang-format to source tree
[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,2014,2019, 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 /*! \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 "gromacs/analysisdata/dataframe.h"
49 #include "gromacs/utility/classhelpers.h"
50 #include "gromacs/utility/gmxassert.h"
51 #include "gromacs/utility/real.h"
52
53 namespace gmx
54 {
55
56 class AbstractAnalysisData;
57 class AnalysisDataFrameHeader;
58 class AnalysisDataFrameRef;
59 class AnalysisDataModuleManager;
60 class AnalysisDataParallelOptions;
61
62 class AnalysisDataStorage;
63
64 namespace internal
65 {
66 class AnalysisDataStorageImpl;
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     /*! \brief
91      * Select data set that all other methods operate on.
92      *
93      * \param[in] index  Zero-based data set index to select.
94      *
95      * With multipoint data, a single point set can only contain values in
96      * a single data set.
97      * With non-multipoint data, arbitrary sequences of selectDataSet() and
98      * setValue() are supported.  The full frame is notified to the modules
99      * once it is finished.
100      *
101      * Does not throw.
102      */
103     void selectDataSet(int index);
104
105     //! Returns number of columns for the frame.
106     int columnCount() const { return columnCount_; }
107
108     /*! \brief
109      * Sets value for a column.
110      *
111      * \param[in] column  Zero-based column index.
112      * \param[in] value   Value to set for the column.
113      * \param[in] bPresent Present flag to set for the column.
114      *
115      * If called multiple times for a column (within one point set for
116      * multipoint data), old values are overwritten.
117      *
118      * Does not throw.
119      */
120     void setValue(int column, real value, bool bPresent = true)
121     {
122         GMX_ASSERT(column >= 0 && column < columnCount(), "Invalid column index");
123         values_[currentOffset_ + column].setValue(value, bPresent);
124         bPointSetInProgress_ = true;
125     }
126     /*! \brief
127      * Sets value for a column.
128      *
129      * \param[in] column  Zero-based column index.
130      * \param[in] value   Value to set for the column.
131      * \param[in] error   Error estimate to set for the column.
132      * \param[in] bPresent Present flag to set for the column.
133      *
134      * If called multiple times for a column (within one point set for
135      * multipoint data), old values are overwritten.
136      *
137      * Does not throw.
138      */
139     void setValue(int column, real value, real error, bool bPresent = true)
140     {
141         GMX_ASSERT(column >= 0 && column < columnCount(), "Invalid column index");
142         values_[currentOffset_ + column].setValue(value, error, bPresent);
143         bPointSetInProgress_ = true;
144     }
145     /*! \brief
146      * Access value for a column.
147      *
148      * \param[in] column  Zero-based column index.
149      *
150      * Should only be called after the column value has been set using
151      * setValue(); assigning a value to \c value(i) does not mark the
152      * column as set.
153      *
154      * Does not throw.
155      */
156     real& value(int column)
157     {
158         GMX_ASSERT(column >= 0 && column < columnCount(), "Invalid column index");
159         return values_[currentOffset_ + column].value();
160     }
161     /*! \brief
162      * Access value for a column.
163      *
164      * \param[in] column  Zero-based column index.
165      *
166      * Should only be called after the column value has been set using
167      * setValue().
168      *
169      * Does not throw.
170      */
171     real value(int column) const
172     {
173         GMX_ASSERT(column >= 0 && column < columnCount(), "Invalid column index");
174         return values_[currentOffset_ + column].value();
175     }
176     /*! \brief
177      * Mark point set as finished for multipoint data.
178      *
179      * Must be called after each point set for multipoint data, including
180      * the last (i.e., no values must be set between the last call to this
181      * method and AnalysisDataStorage::finishFrame()).
182      * Must not be called for non-multipoint data.
183      *
184      * After this method has been called, all values appear as not set.
185      *
186      * May call AnalysisDataModuleManager::notifyPointsAdd() and
187      * AnalysisDataModuleManager::notifyParallelPointsAdd(), and may throw
188      * any exception these methods throw.
189      */
190     void finishPointSet();
191     /*! \brief
192      * Finish storing a frame.
193      *
194      * Must be called exactly once for each frame returned by startFrame(),
195      * after the corresponding call.
196      * The frame object must not be accessed after the call.
197      *
198      * Calls notification methods in AnalysisDataModuleManager, and may
199      * throw any exceptions these methods throw.
200      */
201     void finishFrame();
202
203 private:
204     /*! \brief
205      * Create a new storage frame.
206      *
207      * \param[in] data  Data object for which the frame is for
208      *      (used for data set and column counts).
209      */
210     explicit AnalysisDataStorageFrame(const AbstractAnalysisData& data);
211
212     //! Clear all column values from the frame.
213     void clearValues();
214
215     //! Implementation data.
216     internal::AnalysisDataStorageFrameData* data_;
217     //! Values for the currently in-progress point set.
218     std::vector<AnalysisDataValue> values_;
219
220     //! Index of the currently active dataset.
221     int currentDataSet_;
222     //! Offset of the first value in \a values_ for the current data set.
223     int currentOffset_;
224     //! Number of columns in the current data set.
225     int columnCount_;
226
227     //! Whether any values have been set in the current point set.
228     bool bPointSetInProgress_;
229
230     //! Needed for access to the constructor.
231     friend class internal::AnalysisDataStorageImpl;
232     //! Needed for managing the frame the object points to.
233     friend class internal::AnalysisDataStorageFrameData;
234
235     GMX_DISALLOW_COPY_AND_ASSIGN(AnalysisDataStorageFrame);
236 };
237
238 /*! \libinternal \brief
239  * Helper class that implements storage of data.
240  *
241  * This class implements a standard way of storing data to avoid implementing
242  * storage in each class derived from AbstractAnalysisData separately.
243  * To use this class in a class derived from AbstractAnalysisData, a member
244  * variable of this type should be declared and the pure virtual methods
245  * forwarded to frameCount(), tryGetDataFrame() and requestStorage().
246  * Storage properties should be set up, and then startDataStorage() or
247  * startParallelDataStorage() called.
248  * New frames can then be added using startFrame(), currentFrame(),
249  * finishFrame(), and finishFrameSerial() methods (the last is only necessary
250  * if startParallelDataStorage() is used).  When all frames are ready,
251  * finishDataStorage() must be called.  These methods (and
252  * AnalysisDataStorageFrame::finishPointSet()) take the responsibility of
253  * calling all the notification methods in AnalysisDataModuleManager,
254  *
255  * \todo
256  * Proper multi-threaded implementation.
257  *
258  * \inlibraryapi
259  * \ingroup module_analysisdata
260  */
261 class AnalysisDataStorage
262 {
263 public:
264     //! Constructs a storage object.
265     AnalysisDataStorage();
266     ~AnalysisDataStorage();
267
268     /*! \brief
269      * Returns the number of ready frames.
270      *
271      * This method is designed such that calls to
272      * AbstractAnalysisData::frameCount() can be directly forwarded to this
273      * method.  See that method for more documentation.
274      *
275      * If this method returns N, this means that the first N frames have
276      * all been finished.
277      *
278      * \see AbstractAnalysisData::frameCount()
279      */
280     int frameCount() const;
281     /*! \brief
282      * Implements access to data frames.
283      *
284      * This method is designed such that calls to
285      * AbstractAnalysisData::tryGetDataFrameInternal() can be directly
286      * forwarded to this method.  See that method for more documentation.
287      *
288      * A valid reference for a frame will be returned after finishFrame()
289      * has been called for that frame.
290      *
291      * \see AbstractAnalysisData::tryGetDataFrameInternal()
292      */
293     AnalysisDataFrameRef tryGetDataFrame(int index) const;
294     /*! \brief
295      * Implements storage requests.
296      *
297      * This method is designed such that calls to
298      * AbstractAnalysisData::requestStorageInternal() can be directly
299      * forwarded to this method.  See that method for more documentation.
300      *
301      * \see AbstractAnalysisData::requestStorageInternal()
302      */
303     bool requestStorage(int nframes);
304
305     /*! \brief
306      * Start storing data.
307      *
308      * \param[in] data    AbstractAnalysisData object containing this
309      *      storage.
310      * \param     modules Module manager for \p data.
311      * \exception std::bad_alloc if storage allocation fails.
312      *
313      * Typically called as \c startDataStorage(this, &moduleManager())
314      * from a member of \p data when the data is ready to be started.
315      * The storage object will take responsibility of calling all
316      * module notification methods in AnalysisDataModuleManager using
317      * \p modules.
318      *
319      * Lifetime of \p data and \p modules must exceed the lifetime of the
320      * storage object
321      * (typically, the storage object will be a member in \p data).
322      *
323      * Calls AnalysisDataModuleManager::notifyDataStart(), and throws any
324      * exceptions this method throws.
325      */
326     void startDataStorage(AbstractAnalysisData* data, AnalysisDataModuleManager* modules);
327     /*! \brief
328      * Start storing data in parallel.
329      *
330      * \param[in] data    AbstractAnalysisData object containing this
331      *      storage.
332      * \param[in] options Parallelization options to use.
333      * \param     modules Module manager for \p data.
334      * \exception std::bad_alloc if storage allocation fails.
335      *
336      * Should be called instead of startDataStorage() if the data will be
337      * produced in parallel.  Works as startDataStorage(), but additionally
338      * initializes the storage and the attached modules to prepare for
339      * out-of-order data frames.
340      *
341      * Calls AnalysisDataModuleManager::notifyParallelDataStart(), and
342      * throws any exceptions this method throws.
343      */
344     void startParallelDataStorage(AbstractAnalysisData*              data,
345                                   AnalysisDataModuleManager*         modules,
346                                   const AnalysisDataParallelOptions& options);
347     /*! \brief
348      * Starts storing a new frame.
349      *
350      * \param[in] header  Header for the new frame.
351      * \retval  Frame object corresponding to the started frame.
352      * \exception std::bad_alloc if storage reallocation fails
353      *      (only possible if storage of all frames has been requested).
354      * \exception APIError if frame is too far in the future.
355      *
356      * The returned object will be valid until the corresponding
357      * finishFrame() call.
358      *
359      * Must be called exactly once for each frame index.
360      *
361      * Currently, the implementation only works if the new frame is not too
362      * far in the future:
363      * If \c i is the index of the last frame such that all frames from
364      * 0, ..., \c i have been finished, then \p header().index() should be
365      * at most \c parallelizationFactor larger than \c i, where
366      * parallelizationFactor is the parallelization factor passed to
367      * setParallelOptions().
368      * Throws APIError if this constraint is violated.
369      *
370      * Calls AnalysisDataModuleManager::notifyFrameStart() (in certain
371      * cases) and AnalysisDataModuleManager::notifyParallelFrameStart(),
372      * and throws any exceptions these methods throw.
373      */
374     AnalysisDataStorageFrame& startFrame(const AnalysisDataFrameHeader& header);
375     /*! \brief
376      * Convenience method to start storing a new frame.
377      *
378      * Identical to \c startFrame(AnalysisDataFrameHeader(index, x, dx));
379      */
380     AnalysisDataStorageFrame& startFrame(int index, real x, real dx);
381     /*! \brief
382      * Obtains a frame object for an in-progress frame.
383      *
384      * \param[in] index  Frame index.
385      * \retval  Frame object corresponding to \p index.
386      *
387      * startFrame() should have been called for the frame with index
388      * \p index, and finishFrame() should not yet have been called.
389      * Returns the same object as returned by the original startFrame()
390      * call for the same index.
391      *
392      * Does not throw.
393      */
394     AnalysisDataStorageFrame& currentFrame(int index);
395     /*! \brief
396      * Convenience method for finishing a data frame.
397      *
398      * \param[in] index  Frame index.
399      *
400      * Identical to \c currentFrame(index).finishFrame().
401      *
402      * \see AnalysisDataStorageFrame::finishFrame()
403      */
404     void finishFrame(int index);
405     /*! \brief
406      * Performs in-order sequential processing for a data frame.
407      *
408      * \param[in] index  Frame index.
409      *
410      * If startParallelDataStorage() has been called with options that
411      * indicate parallelism, this method must be called after
412      * `finishFrame(index)` (or the equivalent call in
413      * AnalysisDataStorageFrame), such that it is called in the correct
414      * order sequentially for each frame.
415      *
416      * If there is no parallelism, this method does nothing; the equivalent
417      * processing is done already during finishFrame().
418      */
419     void finishFrameSerial(int index);
420     /*! \brief
421      * Finishes storing data.
422      *
423      * Calls AnalysisDataModuleManager::notifyDataFinish(), and throws any
424      * exceptions this method throws.
425      */
426     void finishDataStorage();
427
428 private:
429     typedef internal::AnalysisDataStorageImpl Impl;
430
431     PrivateImplPointer<Impl> impl_;
432 };
433
434 } // namespace gmx
435
436 #endif