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