3 * This source code is part of
7 * GROningen MAchine for Chemical Simulations
9 * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
10 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
11 * Copyright (c) 2001-2009, The GROMACS development team,
12 * check out http://www.gromacs.org for more information.
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * If you want to redistribute modifications, please consider that
20 * scientific software is very special. Version control is crucial -
21 * bugs must be traceable. We will be happy to consider code for
22 * inclusion in the official distribution, but derived work must not
23 * be called official GROMACS. Details are found in the README & COPYING
24 * files - if they are missing, get the official version at www.gromacs.org.
26 * To help us fund GROMACS development, we humbly ask that you cite
27 * the papers on the package - you can find them in the top README file.
29 * For more info, check our website at http://www.gromacs.org
31 /*! \libinternal \file
33 * Declares gmx::AnalysisDataStorage.
35 * \author Teemu Murtola <teemu.murtola@cbr.su.se>
37 * \ingroup module_analysisdata
39 #ifndef GMX_ANALYSISDATA_DATASTORAGE_H
40 #define GMX_ANALYSISDATA_DATASTORAGE_H
44 #include "../legacyheaders/types/simple.h"
46 #include "../utility/common.h"
47 #include "../utility/gmxassert.h"
49 #include "dataframe.h"
54 class AbstractAnalysisData;
55 class AnalysisDataFrameHeader;
56 class AnalysisDataFrameRef;
57 class AnalysisDataParallelOptions;
59 class AnalysisDataStorage;
61 /*! \libinternal \brief
62 * Stores a single data frame for AnalysisDataStorage.
64 * It also provides access to the frame outside AnalysisDataStorage.
66 * It is implemented such that the frame header is always valid, i.e.,
67 * header().isValid() returns always true.
70 * \ingroup module_analysisdata
72 class AnalysisDataStorageFrame
75 /*! \brief Frees the frame object.
77 * Should not be called outside AnalysisDataStorage.
79 ~AnalysisDataStorageFrame();
81 //! Returns header for the frame.
82 const AnalysisDataFrameHeader &header() const { return header_; }
83 //! Returns zero-based index of the frame.
84 int frameIndex() const { return header().index(); }
85 //! Returns x coordinate for the frame.
86 real x() const { return header().x(); }
87 //! Returns error in x coordinate for the frame if applicable.
88 real dx() const { return header().dx(); }
89 //! Returns number of columns for the frame.
90 int columnCount() const { return values_.size(); }
93 * Returns point set reference to currently set values.
97 AnalysisDataPointSetRef currentPoints() const;
99 * Sets value for a column.
101 * \param[in] column Zero-based column index.
102 * \param[in] value Value to set for the column.
103 * \param[in] bPresent Present flag to set for the column.
105 * If called multiple times for a column (within one point set for
106 * multipoint data), old values are overwritten.
110 void setValue(int column, real value, bool bPresent = true)
112 GMX_ASSERT(column >= 0 && column < columnCount(),
113 "Invalid column index");
114 values_[column].setValue(value, bPresent);
117 * Sets value for a column.
119 * \param[in] column Zero-based column index.
120 * \param[in] value Value to set for the column.
121 * \param[in] error Error estimate to set for the column.
122 * \param[in] bPresent Present flag to set for the column.
124 * If called multiple times for a column (within one point set for
125 * multipoint data), old values are overwritten.
129 void setValue(int column, real value, real error, bool bPresent = true)
131 GMX_ASSERT(column >= 0 && column < columnCount(),
132 "Invalid column index");
133 values_[column].setValue(value, error, bPresent);
136 * Access value for a column.
138 * \param[in] column Zero-based column index.
140 * Should only be called after the column value has been set using
141 * setValue(); assigning a value to \c value(i) does not mark the
146 real &value(int column)
148 GMX_ASSERT(column >= 0 && column < columnCount(),
149 "Invalid column index");
150 return values_[column].value();
153 * Access value for a column.
155 * \param[in] column Zero-based column index.
157 * Should only be called after the column value has been set using
162 real value(int column) const
164 GMX_ASSERT(column >= 0 && column < columnCount(),
165 "Invalid column index");
166 return values_[column].value();
169 * Mark point set as finished for multipoint data.
171 * Must be called after each point set for multipoint data, including
172 * the last (i.e., no values must be set between the last call to this
173 * method and AnalysisDataStorage::finishFrame()).
174 * Must not be called for non-multipoint data.
176 * After this method has been called, all values appear as not set.
178 * Calls AbstractAnalysisData::notifyPointsAdd(), and throws any
179 * exception this method throws.
181 void finishPointSet();
185 * Create a new storage frame.
187 * \param storage Storage object this frame belongs to.
188 * \param[in] columnCount Number of columns for the frame.
189 * \param[in] index Zero-based index for the frame.
191 AnalysisDataStorageFrame(AnalysisDataStorage *storage, int columnCount,
194 //! Clear all column values from the frame.
197 //! Storage object that contains this frame.
198 AnalysisDataStorage &storage_;
199 //! Header for the frame.
200 AnalysisDataFrameHeader header_;
201 //! Values for the frame.
202 std::vector<AnalysisDataValue> values_;
205 * Needed for full write access to the data and for access to
206 * constructor/destructor.
208 friend class AnalysisDataStorage;
210 GMX_DISALLOW_COPY_AND_ASSIGN(AnalysisDataStorageFrame);
213 /*! \libinternal \brief
214 * Helper class that implements storage of data.
216 * This class implements a standard way of storing data to avoid implementing
217 * storage in each class derived from AbstractAnalysisData separately.
218 * To use this class in a class derived from AbstractAnalysisData, a member
219 * variable of this type should be declared and the data storage methods
220 * forwarded to tryGetDataFrame() and requestStorage() in that object.
221 * Storage properties should be set up, and then startDataStorage() called
222 * after calling AbstractAnalysisData::notifyDataStart().
223 * New frames can then be added using startFrame(), currentFrame() and
224 * finishFrame() methods. These methods (and
225 * AnalysisDataStorageFrame::finishPointSet()) take the responsibility of
226 * calling AbstractAnalysisData::notifyFrameStart(),
227 * AbstractAnalysisData::notifyPointsAdd() and
228 * AbstractAnalysisData::notifyFrameFinish() appropriately.
231 * Full support for multipoint data.
232 * Currently, multipoint data is only supported in serial pass-through mode
233 * without any storage.
236 * Proper multi-threaded implementation.
239 * \ingroup module_analysisdata
241 class AnalysisDataStorage
244 //! Constructs a storage object.
245 AnalysisDataStorage();
246 ~AnalysisDataStorage();
249 * Sets whether the data will be multipoint.
251 * \exception APIError if storage has been requested.
253 * It is not mandatory to call this method (the multipoint property is
254 * automatically detected in startDataStorage()), but currently calling
255 * it will produce better diagnostic messages.
256 * When full support for multipoint data has been implemented, this
257 * method can be removed.
259 void setMultipoint(bool bMultipoint);
261 * Set parallelization options for the storage.
263 * \param[in] opt Parallization options to use.
265 * If this method is not called, the storage is set up for serial
270 void setParallelOptions(const AnalysisDataParallelOptions &opt);
273 * Implements access to data frames.
275 * This method is designed such that calls to
276 * AbstractAnalysisData::tryGetDataFrameInternal() can be directly
277 * forwarded to this method. See that method for more documentation.
279 * A valid reference for a frame will be returned after finishFrame()
280 * has been called for that frame.
282 * \see AbstractAnalysisData::tryGetDataFrameInternal()
284 AnalysisDataFrameRef tryGetDataFrame(int index) const;
286 * Implements storage requests.
288 * This method is designed such that calls to
289 * AbstractAnalysisData::requestStorageInternal() can be directly
290 * forwarded to this method. See that method for more documentation.
292 * Currently, multipoint data cannot be stored, but all other storage
293 * request will be honored.
295 * \see AbstractAnalysisData::requestStorageInternal()
297 bool requestStorage(int nframes);
300 * Start storing data.
302 * \param data AbstractAnalysisData object containing this storage.
303 * \exception std::bad_alloc if storage allocation fails.
304 * \exception APIError if storage has been requested and \p data is
307 * Lifetime of \p data must exceed the lifetime of the storage object
308 * (typically, the storage object will be a member in \p data).
309 * The storage object will take responsibility of calling
310 * AbstractAnalysisData::notifyFrameStart(),
311 * AbstractAnalysisData::notifyPointsAdd() and
312 * AbstractAnalysisData::notifyFrameFinish() for \p data appropriately.
314 * AbstractAnalysisData::notifyDataStart() must have been called for
315 * \p data, because that may trigger storage requests from attached
318 void startDataStorage(AbstractAnalysisData *data);
320 * Starts storing a new frame.
322 * \param[in] header Header for the new frame.
323 * \retval Frame object corresponding to the started frame.
324 * \exception std::bad_alloc if storage reallocation fails
325 * (only possible if storage of all frames has been requested).
326 * \exception APIError if frame is too far in the future.
328 * The returned object will be valid until the corresponding
329 * finishFrame() call.
331 * Must be called exactly once for each frame index.
333 * Currently, the implementation only works if the new frame is not too
335 * If \c i is the index of the last frame such that all frames from
336 * 0, ..., \c i have been finished, then \p header().index() should be
337 * at most \c 2*parallelizationFactor-1 larger than \c i, where
338 * parallelizationFactor is the parallelization factor passed to
339 * setParallelOptions().
340 * Throws APIError if this constraint is violated.
342 * Calls AbstractAnalysisData::notifyDataStarted() in certain cases,
343 * and throws any exceptions this method throws.
345 AnalysisDataStorageFrame &startFrame(const AnalysisDataFrameHeader &header);
347 * Convenience method to start storing a new frame.
349 * Identical to \c startFrame(AnalysisDataFrameHeader(index, x, dx));
351 AnalysisDataStorageFrame &startFrame(int index, real x, real dx);
353 * Obtain a frame object for an in-progress frame.
355 * \param[in] index Frame index.
356 * \retval Frame object corresponding to \p index.
358 * startFrame() should have been called for the frame with index
359 * \p index, and finishFrame() should not yet have been called.
360 * Returns the same object as returned by the original startFrame()
361 * call for the same index.
365 AnalysisDataStorageFrame ¤tFrame(int index);
367 * Finish storing a frame.
369 * \param[in] index Frame index.
371 * Must be called exactly once for each startFrame(), after the
372 * corresponding call.
374 * Calls notification methods in AbstractAnalysisData, and throws any
375 * exceptions these methods throw.
377 void finishFrame(int index);
379 * Convenience method for finishing a data frame.
381 * \param[in] frame Frame object to finish.
383 * \p frame should have been previously obtained from startFrame() or
384 * currentFrame(). The \p frame reference is no longer valid after the
387 * Identical to \c finishframe(frame.frameIndex());
389 void finishFrame(const AnalysisDataStorageFrame &frame);
394 PrivateImplPointer<Impl> impl_;
397 * Needed because the frame object needs to trigger notifications.
399 friend void AnalysisDataStorageFrame::finishPointSet();