Merge remote-tracking branch 'origin/release-4-6' into HEAD
[alexxy/gromacs.git] / src / gromacs / analysisdata / dataframe.h
1 /*
2  *
3  *                This source code is part of
4  *
5  *                 G   R   O   M   A   C   S
6  *
7  *          GROningen MAchine for Chemical Simulations
8  *
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.
13
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.
18  *
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.
25  *
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.
28  *
29  * For more info, check our website at http://www.gromacs.org
30  */
31 /*! \file
32  * \brief
33  * Declares classes for accessing data frame information.
34  *
35  * \author Teemu Murtola <teemu.murtola@cbr.su.se>
36  * \inpublicapi
37  * \ingroup module_analysisdata
38  */
39 #ifndef GMX_ANALYSISDATA_DATAFRAME_H
40 #define GMX_ANALYSISDATA_DATAFRAME_H
41
42 #include <vector>
43
44 #include "../legacyheaders/types/simple.h"
45
46 #include "../utility/arrayref.h"
47 #include "../utility/flags.h"
48 #include "../utility/gmxassert.h"
49
50 namespace gmx
51 {
52
53 /*! \brief
54  * Value type for representing a single value in analysis data objects.
55  *
56  * Default copy constructor and assignment operator are used and work as
57  * intended.
58  *
59  * Methods in this class do not throw.
60  *
61  * Non-const methods are provided for use within the library only; currently
62  * it is not possible to access a non-const AnalysisDataValue through the
63  * public interface.
64  *
65  * \inpublicapi
66  * \ingroup module_analysisdata
67  */
68 class AnalysisDataValue
69 {
70     public:
71         /*! \brief
72          * Constructs an unset value.
73          */
74         AnalysisDataValue() : value_(0.0), error_(0.0) {}
75         /*! \brief
76          * Constructs a value object with the given value.
77          *
78          * The constructed object is marked as set and present.
79          */
80         explicit AnalysisDataValue(real value)
81             : value_(value), error_(0.0)
82         {
83             flags_.set(efSet);
84             flags_.set(efPresent);
85         }
86
87         /*! \brief
88          * Direct access to the value.
89          *
90          * Assigning a value to this does not mark the value as set; setValue()
91          * must be used for this.
92          */
93         real &value() { return value_; }
94         /*! \brief
95          * Direct access to the error estimate.
96          *
97          * Assigning a value to this does not mark the error estimate as set;
98          * setValue() must be used for this.
99          */
100         real &error() { return error_; }
101         //! Returns the value for this value.
102         real value() const { return value_; }
103         //! Returns the error estimate for this value, or zero if not set.
104         real error() const { return error_; }
105         /*! \brief
106          * Returns whether this value has been set.
107          *
108          * If this method returns false, the return value of value() and
109          * error() are undefined.
110          */
111         bool isSet() const { return flags_.test(efSet); }
112         /*! \brief
113          * Returns whether the error estimate for this value has been set.
114          *
115          * If this method returns false, but isSet() returns true, error()
116          * returns zero.
117          */
118         bool hasError() const { return flags_.test(efErrorSet); }
119         /*! \brief
120          * Returns whether this value has been marked as present.
121          *
122          * If this method returns false, it is up to the source data to define
123          * whether isSet() may return true.
124          */
125         bool isPresent() const { return flags_.test(efPresent); }
126
127         //! Clears and unsets this value.
128         void clear()
129         {
130             *this = AnalysisDataValue();
131         }
132         //! Sets this value.
133         void setValue(real value, bool bPresent = true)
134         {
135             value_ = value;
136             flags_.set(efSet);
137             flags_.set(efPresent, bPresent);
138         }
139         //! Sets this value and its error estimate.
140         void setValue(real value, real error, bool bPresent = true)
141         {
142             value_ = value;
143             error_ = error;
144             flags_.set(efSet);
145             flags_.set(efErrorSet);
146             flags_.set(efPresent, bPresent);
147         }
148         //! Set only error estimate for this value.
149         void setError(real error)
150         {
151             error_ = error;
152             flags_.set(efErrorSet);
153         }
154
155     private:
156         //! Possible flags for \a flags_.
157         enum Flag
158         {
159             efSet       = 1<<0, //!< Value has been set.
160             efErrorSet  = 1<<1, //!< Error estimate has been set.
161             efPresent   = 1<<2  //!< Value is set as present.
162         };
163
164         //! Value for this value.
165         real                    value_;
166         //! Error estimate for this value, zero if not set.
167         real                    error_;
168         //! Status flags for thise value.
169         FlagsTemplate<Flag>     flags_;
170 };
171
172 //! Shorthand for reference to an array of data values.
173 typedef ConstArrayRef<AnalysisDataValue> AnalysisDataValuesRef;
174
175
176 /*! \brief
177  * Value type for storing frame-level information for analysis data.
178  *
179  * Default copy constructor and assignment operator are used and work as
180  * intended.
181  * Typically new objects of this type are only constructed internally by the
182  * library and in classes that are derived from AbstractAnalysisData.
183  *
184  * Methods in this class do not throw, but may contain asserts for incorrect
185  * usage.
186  *
187  * Note that it is not possible to change the contents of an initialized
188  * object, except by assigning a new object to replace it completely.
189  *
190  * \inpublicapi
191  * \ingroup module_analysisdata
192  */
193 class AnalysisDataFrameHeader
194 {
195     public:
196         /*! \brief
197          * Constructs an invalid frame header.
198          *
199          * Return values of other methods than isValid() are unspecified for
200          * the constructed object.
201          */
202         AnalysisDataFrameHeader();
203         /*! \brief
204          * Constructs a frame header from given values.
205          *
206          * \param[in] index  Index of the frame. Must be >= 0.
207          * \param[in] x      x coordinate for the frame.
208          * \param[in] dx     Error estimate for x.
209          */
210         AnalysisDataFrameHeader(int index, real x, real dx);
211
212         /*! \brief
213          * Returns whether the frame header corresponds to a valid frame.
214          *
215          * If returns false, return values of other methods are not specified.
216          */
217         bool isValid() const
218         {
219             return index_ >= 0;
220         }
221         /*! \brief
222          * Returns zero-based index of the frame.
223          *
224          * The return value is >= 0 for valid frames.
225          * Should not be called for invalid frames.
226          */
227         int index() const
228         {
229             GMX_ASSERT(isValid(), "Tried to access invalid frame header");
230             return index_;
231         }
232         /*! \brief
233          * Returns the x coordinate for the frame.
234          *
235          * Should not be called for invalid frames.
236          */
237         real x() const
238         {
239             GMX_ASSERT(isValid(), "Tried to access invalid frame header");
240             return x_;
241         }
242         /*! \brief
243          * Returns error in the x coordinate for the frame (if applicable).
244          *
245          * All data do not provide error estimates.
246          * Typically returns zero in those cases.
247          *
248          * Should not be called for invalid frames.
249          */
250         real dx() const
251         {
252             GMX_ASSERT(isValid(), "Tried to access invalid frame header");
253             return dx_;
254         }
255
256     private:
257         int                     index_;
258         real                    x_;
259         real                    dx_;
260 };
261
262
263 /*! \brief
264  * Value type wrapper for non-mutable access to a set of data column values.
265  *
266  * Default copy constructor and assignment operator are used and work as
267  * intended.
268  * Typically new objects of this type are only constructed internally by the
269  * library and in classes that are derived from AbstractAnalysisData.
270  *
271  * Methods in this class do not throw, but may contain asserts for incorrect
272  * usage.
273  *
274  * The design of the interfaces is such that all objects of this type should be
275  * valid, i.e., header().isValid() should always return true.
276  *
277  * Note that it is not possible to change the contents of an initialized
278  * object, except by assigning a new object to replace it completely.
279  *
280  * \inpublicapi
281  * \ingroup module_analysisdata
282  */
283 class AnalysisDataPointSetRef
284 {
285     public:
286         /*! \brief
287          * Constructs a point set reference from given values.
288          *
289          * \param[in] header      Header for the frame.
290          * \param[in] firstColumn Zero-based index of the first column.
291          *     Must be >= 0.
292          * \param[in] values      Values for each column.
293          *
294          * The first element in \p values should correspond to \p firstColumn.
295          */
296         AnalysisDataPointSetRef(const AnalysisDataFrameHeader &header,
297                                 int firstColumn,
298                                 const AnalysisDataValuesRef &values);
299         /*! \brief
300          * Constructs a point set reference from given values.
301          *
302          * \param[in] header      Header for the frame.
303          * \param[in] values      Values for each column.
304          *
305          * The first element in \p values should correspond to the first
306          * column.
307          */
308         AnalysisDataPointSetRef(const AnalysisDataFrameHeader &header,
309                                 const std::vector<AnalysisDataValue> &values);
310         /*! \brief
311          * Constructs a point set reference to a subset of columns.
312          *
313          * \param[in] points      Point set to use as source.
314          * \param[in] firstColumn First column index to include.
315          * \param[in] columnCount Number of columns to include.
316          *
317          * Creates a point set that contains \p columnCount columns starting
318          * from \p firstColumn from \p points, or a subset if all requested
319          * columns are not present in \p points.  If the requested column range
320          * and the range in \p points do not intersect, the result has
321          * columnCount() == 0.
322          *
323          * \p firstColumn is relative to the whole data set, i.e., not relative
324          * to points.firstColumn().
325          *
326          * Mainly intended for internal use.
327          */
328         AnalysisDataPointSetRef(const AnalysisDataPointSetRef &points,
329                                 int firstColumn, int columnCount);
330
331         /*! \brief
332          * Returns the frame header for the frame of this point set.
333          */
334         const AnalysisDataFrameHeader &header() const
335         {
336             return header_;
337         }
338         //! \copydoc AnalysisDataFrameHeader::index()
339         int frameIndex() const
340         {
341             return header_.index();
342         }
343         //! \copydoc AnalysisDataFrameHeader::x()
344         real x() const
345         {
346             return header_.x();
347         }
348         //! \copydoc AnalysisDataFrameHeader::dx()
349         real dx() const
350         {
351             return header_.dx();
352         }
353         //! Returns zero-based index of the first column included in this set.
354         int firstColumn() const
355         {
356             return firstColumn_;
357         }
358         //! Returns the number of columns included in this set.
359         int columnCount() const
360         {
361             return values().size();
362         }
363         //! Returns zero-based index of the last column included in this set (inclusive).
364         int lastColumn() const
365         {
366             return firstColumn_ + columnCount() - 1;
367         }
368         /*! \brief
369          * Returns reference container for all values.
370          *
371          * First value in the returned container corresponds to firstColumn().
372          */
373         const AnalysisDataValuesRef &values() const
374         {
375             return values_;
376         }
377         /*! \brief
378          * Returns data value for a column in this set.
379          *
380          * \param[in] i  Zero-based column index relative to firstColumn().
381          *     Should be >= 0 and < columnCount().
382          */
383         real y(int i) const
384         {
385             GMX_ASSERT(i >= 0 && i < columnCount(), "Out of range data access");
386             return values()[i].value();
387         }
388         /*! \brief
389          * Returns error estimate for a column in this set if applicable.
390          *
391          * \param[in] i  Zero-based column index relative to firstColumn().
392          *     Should be >= 0 and < columnCount().
393          *
394          * Currently, this method returns zero if the source data does not
395          * specify errors.
396          */
397         real dy(int i) const
398         {
399             GMX_ASSERT(i >= 0 && i < columnCount(), "Out of range data access");
400             return values()[i].error();
401         }
402         /*! \brief
403          * Returns whether a column is present in this set.
404          *
405          * \param[in] i  Zero-based column index relative to firstColumn().
406          *     Should be >= 0 and < columnCount().
407          *
408          * If present(i) returns false, it is depends on the source data
409          * whether y(i) and/or dy(i) are defined.
410          */
411         bool present(int i) const
412         {
413             GMX_ASSERT(i >= 0 && i < columnCount(), "Out of range data access");
414             return values()[i].isPresent();
415         }
416         /*! \brief
417          * Returns true if all points in this point set are present.
418          *
419          * That is, if present() would return true for all points.
420          */
421         bool allPresent() const;
422
423     private:
424         AnalysisDataFrameHeader header_;
425         int                     firstColumn_;
426         AnalysisDataValuesRef   values_;
427 };
428
429
430 /*! \brief
431  * Value type wrapper for non-mutable access to a data frame.
432  *
433  * Default copy constructor and assignment operator are used and work as
434  * intended.
435  * Typically new objects of this type are only constructed internally by the
436  * library and in classes that are derived from AbstractAnalysisData.
437  *
438  * Methods in this class do not throw, but may contain asserts for incorrect
439  * usage.
440  *
441  * Note that it is not possible to change the contents of an initialized
442  * object, except by assigning a new object to replace it completely.
443  *
444  * \todo
445  * Support for multipoint data.
446  *
447  * \inpublicapi
448  * \ingroup module_analysisdata
449  */
450 class AnalysisDataFrameRef
451 {
452     public:
453         /*! \brief
454          * Constructs an invalid frame reference.
455          *
456          * Return values of other methods than isValid() are unspecified for
457          * the constructed object.
458          */
459         AnalysisDataFrameRef();
460         /*! \brief
461          * Constructs a frame reference from given values.
462          *
463          * \param[in] header      Header for the frame.
464          * \param[in] values      Values for each column.
465          */
466         AnalysisDataFrameRef(const AnalysisDataFrameHeader &header,
467                              const AnalysisDataValuesRef &values);
468         /*! \brief
469          * Constructs a frame reference from given values.
470          *
471          * \param[in] header      Header for the frame.
472          * \param[in] values      Values for each column.
473          */
474         AnalysisDataFrameRef(const AnalysisDataFrameHeader &header,
475                              const std::vector<AnalysisDataValue> &values);
476         /*! \brief
477          * Constructs a frame reference to a subset of columns.
478          *
479          * \param[in] frame       Frame to use as source.
480          * \param[in] firstColumn First column index to include.
481          * \param[in] columnCount Number of columns to include.
482          *
483          * Creates a frame reference that contains \p columnCount columns
484          * starting from \p firstColumn from \p frame, or a subset if all
485          * requested columns are not present in \p frame.
486          *
487          * Mainly intended for internal use.
488          */
489         AnalysisDataFrameRef(const AnalysisDataFrameRef &frame,
490                              int firstColumn, int columnCount);
491
492         /*! \brief
493          * Returns whether the object refers to a valid frame.
494          *
495          * If returns false, return values of other methods are not specified.
496          */
497         bool isValid() const
498         {
499             return header().isValid();
500         }
501         //! Returns the header for this frame.
502         const AnalysisDataFrameHeader &header() const
503         {
504             return header_;
505         }
506         //! \copydoc AnalysisDataFrameHeader::index()
507         int frameIndex() const
508         {
509             return header().index();
510         }
511         //! \copydoc AnalysisDataFrameHeader::x()
512         real x() const
513         {
514             return header().x();
515         }
516         //! \copydoc AnalysisDataFrameHeader::dx()
517         real dx() const
518         {
519             return header().dx();
520         }
521         /*! \brief
522          * Returns point set reference to the column values of this frame.
523          *
524          * Should not be called for invalid frames.
525          */
526         AnalysisDataPointSetRef points() const
527         {
528             GMX_ASSERT(isValid(), "Invalid data frame accessed");
529             return AnalysisDataPointSetRef(header_, 0, values_);
530         }
531         /*! \brief
532          * Returns number of columns in this frame.
533          *
534          * Returns zero for an invalid frame.
535          */
536         int columnCount() const
537         {
538             return values_.size();
539         }
540         /*! \brief
541          * Returns reference container for all column values.
542          */
543         const AnalysisDataValuesRef &values() const
544         {
545             return values_;
546         }
547         /*! \brief
548          * Convenience method for accessing a column value.
549          *
550          * \copydetails AnalysisDataPointSetRef::y()
551          */
552         real y(int i) const
553         {
554             GMX_ASSERT(isValid(), "Invalid data frame accessed");
555             GMX_ASSERT(i >= 0 && i < columnCount(), "Out of range data access");
556             return values_[i].value();
557         }
558         /*! \brief
559          * Convenience method for accessing error for a column value.
560          *
561          * \copydetails AnalysisDataPointSetRef::dy()
562          */
563         real dy(int i) const
564         {
565             GMX_ASSERT(isValid(), "Invalid data frame accessed");
566             GMX_ASSERT(i >= 0 && i < columnCount(), "Out of range data access");
567             return values_[i].error();
568         }
569         /*! \brief
570          * Convenience method for accessing present status for a column.
571          *
572          * \copydetails AnalysisDataPointSetRef::present()
573          */
574         bool present(int i) const
575         {
576             GMX_ASSERT(isValid(), "Invalid data frame accessed");
577             GMX_ASSERT(i >= 0 && i < columnCount(), "Out of range data access");
578             return values_[i].isPresent();
579         }
580         /*! \brief
581          * Returns true if all points in this frame are present.
582          */
583         bool allPresent() const;
584
585     private:
586         AnalysisDataFrameHeader header_;
587         AnalysisDataValuesRef   values_;
588 };
589
590 } // namespace gmx
591
592 #endif