Use proper doxygen tags in modular simulator
[gromacs.git] / src / gromacs / analysisdata / datastorage.h
blob789e6fc1260550da3e69fd59f4d2c06ebf4c7039
1 /*
2 * This file is part of the GROMACS molecular simulation package.
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.
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.
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.
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.
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.
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.
35 /*! \libinternal \file
36 * \brief
37 * Declares gmx::AnalysisDataStorage.
39 * \author Teemu Murtola <teemu.murtola@gmail.com>
40 * \inlibraryapi
41 * \ingroup module_analysisdata
43 #ifndef GMX_ANALYSISDATA_DATASTORAGE_H
44 #define GMX_ANALYSISDATA_DATASTORAGE_H
46 #include <vector>
48 #include "gromacs/analysisdata/dataframe.h"
49 #include "gromacs/utility/classhelpers.h"
50 #include "gromacs/utility/gmxassert.h"
51 #include "gromacs/utility/real.h"
53 namespace gmx
56 class AbstractAnalysisData;
57 class AnalysisDataFrameHeader;
58 class AnalysisDataFrameRef;
59 class AnalysisDataModuleManager;
60 class AnalysisDataParallelOptions;
62 class AnalysisDataStorage;
64 namespace internal
66 class AnalysisDataStorageImpl;
67 class AnalysisDataStorageFrameData;
68 } // namespace internal
70 /*! \libinternal \brief
71 * Allows assigning values for a data frame in AnalysisDataStorage.
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.
78 * \inlibraryapi
79 * \ingroup module_analysisdata
81 class AnalysisDataStorageFrame
83 public:
84 /*! \brief Frees the frame object.
86 * Should not be called outside AnalysisDataStorage.
88 ~AnalysisDataStorageFrame();
90 /*! \brief
91 * Select data set that all other methods operate on.
93 * \param[in] index Zero-based data set index to select.
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.
101 * Does not throw.
103 void selectDataSet(int index);
105 //! Returns number of columns for the frame.
106 int columnCount() const { return columnCount_; }
108 /*! \brief
109 * Sets value for a column.
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.
115 * If called multiple times for a column (within one point set for
116 * multipoint data), old values are overwritten.
118 * Does not throw.
120 void setValue(int column, real value, bool bPresent = true)
122 GMX_ASSERT(column >= 0 && column < columnCount(), "Invalid column index");
123 values_[currentOffset_ + column].setValue(value, bPresent);
124 bPointSetInProgress_ = true;
126 /*! \brief
127 * Sets value for a column.
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.
134 * If called multiple times for a column (within one point set for
135 * multipoint data), old values are overwritten.
137 * Does not throw.
139 void setValue(int column, real value, real error, bool bPresent = true)
141 GMX_ASSERT(column >= 0 && column < columnCount(), "Invalid column index");
142 values_[currentOffset_ + column].setValue(value, error, bPresent);
143 bPointSetInProgress_ = true;
145 /*! \brief
146 * Access value for a column.
148 * \param[in] column Zero-based column index.
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.
154 * Does not throw.
156 real& value(int column)
158 GMX_ASSERT(column >= 0 && column < columnCount(), "Invalid column index");
159 return values_[currentOffset_ + column].value();
161 /*! \brief
162 * Access value for a column.
164 * \param[in] column Zero-based column index.
166 * Should only be called after the column value has been set using
167 * setValue().
169 * Does not throw.
171 real value(int column) const
173 GMX_ASSERT(column >= 0 && column < columnCount(), "Invalid column index");
174 return values_[currentOffset_ + column].value();
176 /*! \brief
177 * Mark point set as finished for multipoint data.
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.
184 * After this method has been called, all values appear as not set.
186 * May call AnalysisDataModuleManager::notifyPointsAdd() and
187 * AnalysisDataModuleManager::notifyParallelPointsAdd(), and may throw
188 * any exception these methods throw.
190 void finishPointSet();
191 /*! \brief
192 * Finish storing a frame.
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.
198 * Calls notification methods in AnalysisDataModuleManager, and may
199 * throw any exceptions these methods throw.
201 void finishFrame();
203 private:
204 /*! \brief
205 * Create a new storage frame.
207 * \param[in] data Data object for which the frame is for
208 * (used for data set and column counts).
210 explicit AnalysisDataStorageFrame(const AbstractAnalysisData& data);
212 //! Clear all column values from the frame.
213 void clearValues();
215 //! Implementation data.
216 internal::AnalysisDataStorageFrameData* data_;
217 //! Values for the currently in-progress point set.
218 std::vector<AnalysisDataValue> values_;
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_;
227 //! Whether any values have been set in the current point set.
228 bool bPointSetInProgress_;
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;
235 GMX_DISALLOW_COPY_AND_ASSIGN(AnalysisDataStorageFrame);
238 /*! \libinternal \brief
239 * Helper class that implements storage of data.
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,
255 * \todo
256 * Proper multi-threaded implementation.
258 * \inlibraryapi
259 * \ingroup module_analysisdata
261 class AnalysisDataStorage
263 public:
264 //! Constructs a storage object.
265 AnalysisDataStorage();
266 ~AnalysisDataStorage();
268 /*! \brief
269 * Returns the number of ready frames.
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.
275 * If this method returns N, this means that the first N frames have
276 * all been finished.
278 * \see AbstractAnalysisData::frameCount()
280 int frameCount() const;
281 /*! \brief
282 * Implements access to data frames.
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.
288 * A valid reference for a frame will be returned after finishFrame()
289 * has been called for that frame.
291 * \see AbstractAnalysisData::tryGetDataFrameInternal()
293 AnalysisDataFrameRef tryGetDataFrame(int index) const;
294 /*! \brief
295 * Implements storage requests.
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.
301 * \see AbstractAnalysisData::requestStorageInternal()
303 bool requestStorage(int nframes);
305 /*! \brief
306 * Start storing data.
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.
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.
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).
323 * Calls AnalysisDataModuleManager::notifyDataStart(), and throws any
324 * exceptions this method throws.
326 void startDataStorage(AbstractAnalysisData* data, AnalysisDataModuleManager* modules);
327 /*! \brief
328 * Start storing data in parallel.
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.
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.
341 * Calls AnalysisDataModuleManager::notifyParallelDataStart(), and
342 * throws any exceptions this method throws.
344 void startParallelDataStorage(AbstractAnalysisData* data,
345 AnalysisDataModuleManager* modules,
346 const AnalysisDataParallelOptions& options);
347 /*! \brief
348 * Starts storing a new frame.
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.
356 * The returned object will be valid until the corresponding
357 * finishFrame() call.
359 * Must be called exactly once for each frame index.
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.
370 * Calls AnalysisDataModuleManager::notifyFrameStart() (in certain
371 * cases) and AnalysisDataModuleManager::notifyParallelFrameStart(),
372 * and throws any exceptions these methods throw.
374 AnalysisDataStorageFrame& startFrame(const AnalysisDataFrameHeader& header);
375 /*! \brief
376 * Convenience method to start storing a new frame.
378 * Identical to \c startFrame(AnalysisDataFrameHeader(index, x, dx));
380 AnalysisDataStorageFrame& startFrame(int index, real x, real dx);
381 /*! \brief
382 * Obtains a frame object for an in-progress frame.
384 * \param[in] index Frame index.
385 * \retval Frame object corresponding to \p index.
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.
392 * Does not throw.
394 AnalysisDataStorageFrame& currentFrame(int index);
395 /*! \brief
396 * Convenience method for finishing a data frame.
398 * \param[in] index Frame index.
400 * Identical to \c currentFrame(index).finishFrame().
402 * \see AnalysisDataStorageFrame::finishFrame()
404 void finishFrame(int index);
405 /*! \brief
406 * Performs in-order sequential processing for a data frame.
408 * \param[in] index Frame index.
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.
416 * If there is no parallelism, this method does nothing; the equivalent
417 * processing is done already during finishFrame().
419 void finishFrameSerial(int index);
420 /*! \brief
421 * Finishes storing data.
423 * Calls AnalysisDataModuleManager::notifyDataFinish(), and throws any
424 * exceptions this method throws.
426 void finishDataStorage();
428 private:
429 typedef internal::AnalysisDataStorageImpl Impl;
431 PrivateImplPointer<Impl> impl_;
434 } // namespace gmx
436 #endif