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