Merge origin/release-4-6 into master
[alexxy/gromacs.git] / src / gromacs / analysisdata / analysisdata.cpp
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 /*! \internal \file
32  * \brief
33  * Implements classes in analysisdata.h.
34  *
35  * \author Teemu Murtola <teemu.murtola@cbr.su.se>
36  * \ingroup module_analysisdata
37  */
38 #include "gromacs/analysisdata/analysisdata.h"
39
40 #include "gromacs/analysisdata/dataframe.h"
41 #include "gromacs/analysisdata/datastorage.h"
42 #include "gromacs/analysisdata/paralleloptions.h"
43 #include "gromacs/utility/exceptions.h"
44 #include "gromacs/utility/gmxassert.h"
45 #include "gromacs/utility/uniqueptr.h"
46
47 namespace gmx
48 {
49
50 /********************************************************************
51  * AnalysisDataHandleImpl
52  */
53
54 namespace internal
55 {
56
57 /*! \internal \brief
58  * Private implementation class for AnalysisDataHandle.
59  *
60  * \ingroup module_analysisdata
61  */
62 class AnalysisDataHandleImpl
63 {
64     public:
65         //! Creates a handle associated with the given data object.
66         explicit AnalysisDataHandleImpl(AnalysisData *data)
67             : data_(*data), currentFrame_(NULL)
68         {
69         }
70
71         //! The data object that this handle belongs to.
72         AnalysisData             &data_;
73         //! Current storage frame object, or NULL if no current frame.
74         AnalysisDataStorageFrame *currentFrame_;
75 };
76
77 } // namespace internal
78
79 /********************************************************************
80  * AnalysisData::Impl
81  */
82
83 /*! \internal \brief
84  * Private implementation class for AnalysisData.
85  *
86  * \ingroup module_analysisdata
87  */
88 class AnalysisData::Impl
89 {
90     public:
91         //! Smart pointer type to manage a data handle implementation.
92         typedef gmx_unique_ptr<internal::AnalysisDataHandleImpl>::type
93                 HandlePointer;
94         //! Shorthand for a list of data handles.
95         typedef std::vector<HandlePointer> HandleList;
96
97         //! Storage implementation.
98         AnalysisDataStorage     storage_;
99         /*! \brief
100          * List of handles for this data object.
101          *
102          * Note that AnalysisDataHandle objects also contain (raw) pointers
103          * to these objects.
104          */
105         HandleList              handles_;
106 };
107
108 /********************************************************************
109  * AnalysisData
110  */
111
112 AnalysisData::AnalysisData()
113     : impl_(new Impl)
114 {
115 }
116
117
118 AnalysisData::~AnalysisData()
119 {
120 }
121
122
123 void
124 AnalysisData::setColumnCount(int ncol)
125 {
126     GMX_RELEASE_ASSERT(ncol > 0, "Number of columns must be positive");
127     GMX_RELEASE_ASSERT(impl_->handles_.empty(),
128                        "Cannot change data dimensionality after creating handles");
129     AbstractAnalysisData::setColumnCount(ncol);
130 }
131
132
133 void
134 AnalysisData::setMultipoint(bool bMultipoint)
135 {
136     GMX_RELEASE_ASSERT(impl_->handles_.empty(),
137                        "Cannot change data type after creating handles");
138     AbstractAnalysisData::setMultipoint(bMultipoint);
139     impl_->storage_.setMultipoint(bMultipoint);
140 }
141
142
143 AnalysisDataHandle
144 AnalysisData::startData(const AnalysisDataParallelOptions &opt)
145 {
146     GMX_RELEASE_ASSERT(impl_->handles_.size() < static_cast<unsigned>(opt.parallelizationFactor()),
147                        "Too many calls to startData() compared to provided options");
148     if (impl_->handles_.empty())
149     {
150         notifyDataStart();
151         impl_->storage_.setParallelOptions(opt);
152         impl_->storage_.startDataStorage(this);
153     }
154     else if (isMultipoint())
155     {
156         GMX_THROW(NotImplementedError("Parallelism not supported for multipoint data"));
157     }
158
159     Impl::HandlePointer handle(new internal::AnalysisDataHandleImpl(this));
160     impl_->handles_.push_back(move(handle));
161     return AnalysisDataHandle(impl_->handles_.back().get());
162 }
163
164
165 void
166 AnalysisData::finishData(AnalysisDataHandle handle)
167 {
168     Impl::HandleList::iterator i;
169
170     for (i = impl_->handles_.begin(); i != impl_->handles_.end(); ++i)
171     {
172         if (i->get() == handle.impl_)
173         {
174             break;
175         }
176     }
177     GMX_RELEASE_ASSERT(i != impl_->handles_.end(),
178                        "finishData() called for an unknown handle");
179
180     impl_->handles_.erase(i);
181
182     if (impl_->handles_.empty())
183     {
184         notifyDataFinish();
185     }
186 }
187
188
189 AnalysisDataFrameRef
190 AnalysisData::tryGetDataFrameInternal(int index) const
191 {
192     return impl_->storage_.tryGetDataFrame(index);
193 }
194
195
196 bool
197 AnalysisData::requestStorageInternal(int nframes)
198 {
199     return impl_->storage_.requestStorage(nframes);
200 }
201
202
203 /********************************************************************
204  * AnalysisDataHandle
205  */
206
207 AnalysisDataHandle::AnalysisDataHandle()
208     : impl_(NULL)
209 {
210 }
211
212
213 AnalysisDataHandle::AnalysisDataHandle(internal::AnalysisDataHandleImpl *impl)
214     : impl_(impl)
215 {
216 }
217
218
219 void
220 AnalysisDataHandle::startFrame(int index, real x, real dx)
221 {
222     GMX_RELEASE_ASSERT(impl_ != NULL, "Invalid data handle used");
223     GMX_RELEASE_ASSERT(impl_->currentFrame_ == NULL,
224                        "startFrame() called twice without calling finishFrame()");
225     impl_->currentFrame_ =
226         &impl_->data_.impl_->storage_.startFrame(index, x, dx);
227 }
228
229
230 void
231 AnalysisDataHandle::setPoint(int column, real value, bool bPresent)
232 {
233     GMX_RELEASE_ASSERT(impl_ != NULL, "Invalid data handle used");
234     GMX_RELEASE_ASSERT(impl_->currentFrame_ != NULL,
235                        "setPoint() called without calling startFrame()");
236     impl_->currentFrame_->setValue(column, value, bPresent);
237 }
238
239
240 void
241 AnalysisDataHandle::setPoint(int column, real value, real error, bool bPresent)
242 {
243     GMX_RELEASE_ASSERT(impl_ != NULL, "Invalid data handle used");
244     GMX_RELEASE_ASSERT(impl_->currentFrame_ != NULL,
245                        "setPoint() called without calling startFrame()");
246     impl_->currentFrame_->setValue(column, value, error, bPresent);
247 }
248
249
250 void
251 AnalysisDataHandle::setPoints(int firstColumn, int count, const real *values)
252 {
253     GMX_RELEASE_ASSERT(impl_ != NULL, "Invalid data handle used");
254     GMX_RELEASE_ASSERT(impl_->currentFrame_ != NULL,
255                        "setPoints() called without calling startFrame()");
256     for (int i = 0; i < count; ++i)
257     {
258         impl_->currentFrame_->setValue(firstColumn + i, values[i]);
259     }
260 }
261
262
263 void
264 AnalysisDataHandle::finishPointSet()
265 {
266     GMX_RELEASE_ASSERT(impl_ != NULL, "Invalid data handle used");
267     GMX_RELEASE_ASSERT(impl_->data_.isMultipoint(),
268                        "finishPointSet() called for non-multipoint data");
269     GMX_RELEASE_ASSERT(impl_->currentFrame_ != NULL,
270                        "finishPointSet() called without calling startFrame()");
271     impl_->currentFrame_->finishPointSet();
272 }
273
274
275 void
276 AnalysisDataHandle::finishFrame()
277 {
278     GMX_RELEASE_ASSERT(impl_ != NULL, "Invalid data handle used");
279     GMX_RELEASE_ASSERT(impl_->currentFrame_ != NULL,
280                        "finishFrame() called without calling startFrame()");
281     int index = impl_->currentFrame_->frameIndex();
282     impl_->currentFrame_ = NULL;
283     impl_->data_.impl_->storage_.finishFrame(index);
284 }
285
286
287 void
288 AnalysisDataHandle::finishData()
289 {
290     GMX_RELEASE_ASSERT(impl_ != NULL, "Invalid data handle used");
291     // Deletes the implementation pointer.
292     impl_->data_.finishData(*this);
293     impl_ = NULL;
294 }
295
296 } // namespace gmx