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