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
46 #include "analysisdata-impl.h"
47
48 namespace gmx
49 {
50
51 /********************************************************************
52  * AnalysisData::Impl
53  */
54
55 AnalysisData::Impl::Impl()
56 {
57 }
58
59
60 AnalysisData::Impl::~Impl()
61 {
62 }
63
64
65 /********************************************************************
66  * AnalysisData
67  */
68
69 AnalysisData::AnalysisData()
70     : impl_(new Impl)
71 {
72 }
73
74
75 AnalysisData::~AnalysisData()
76 {
77 }
78
79
80 void
81 AnalysisData::setColumnCount(int ncol)
82 {
83     GMX_RELEASE_ASSERT(ncol > 0, "Number of columns must be positive");
84     GMX_RELEASE_ASSERT(impl_->handles_.empty(),
85                        "Cannot change data dimensionality after creating handles");
86     AbstractAnalysisData::setColumnCount(ncol);
87 }
88
89
90 void
91 AnalysisData::setMultipoint(bool bMultipoint)
92 {
93     GMX_RELEASE_ASSERT(impl_->handles_.empty(),
94                        "Cannot change data type after creating handles");
95     AbstractAnalysisData::setMultipoint(bMultipoint);
96     impl_->storage_.setMultipoint(bMultipoint);
97 }
98
99
100 AnalysisDataHandle
101 AnalysisData::startData(const AnalysisDataParallelOptions &opt)
102 {
103     GMX_RELEASE_ASSERT(impl_->handles_.size() < static_cast<unsigned>(opt.parallelizationFactor()),
104                        "Too many calls to startData() compared to provided options");
105     if (impl_->handles_.empty())
106     {
107         notifyDataStart();
108         impl_->storage_.setParallelOptions(opt);
109         impl_->storage_.startDataStorage(this);
110     }
111     else if (isMultipoint())
112     {
113         GMX_THROW(NotImplementedError("Parallelism not supported for multipoint data"));
114     }
115
116     Impl::HandlePointer handle(new internal::AnalysisDataHandleImpl(this));
117     impl_->handles_.push_back(move(handle));
118     return AnalysisDataHandle(impl_->handles_.back().get());
119 }
120
121
122 void
123 AnalysisData::finishData(AnalysisDataHandle handle)
124 {
125     Impl::HandleList::iterator i;
126
127     for (i = impl_->handles_.begin(); i != impl_->handles_.end(); ++i)
128     {
129         if (i->get() == handle.impl_)
130         {
131             break;
132         }
133     }
134     GMX_RELEASE_ASSERT(i != impl_->handles_.end(),
135                        "finishData() called for an unknown handle");
136
137     impl_->handles_.erase(i);
138
139     if (impl_->handles_.empty())
140     {
141         notifyDataFinish();
142     }
143 }
144
145
146 AnalysisDataFrameRef
147 AnalysisData::tryGetDataFrameInternal(int index) const
148 {
149     return impl_->storage_.tryGetDataFrame(index);
150 }
151
152
153 bool
154 AnalysisData::requestStorageInternal(int nframes)
155 {
156     return impl_->storage_.requestStorage(nframes);
157 }
158
159
160 /********************************************************************
161  * AnalysisDataHandleImpl
162  */
163
164 internal::AnalysisDataHandleImpl::AnalysisDataHandleImpl(AnalysisData *data)
165     : data_(*data), currentFrame_(NULL)
166 {
167 }
168
169
170 /********************************************************************
171  * AnalysisDataHandle
172  */
173
174 AnalysisDataHandle::AnalysisDataHandle()
175     : impl_(NULL)
176 {
177 }
178
179
180 AnalysisDataHandle::AnalysisDataHandle(internal::AnalysisDataHandleImpl *impl)
181     : impl_(impl)
182 {
183 }
184
185
186 void
187 AnalysisDataHandle::startFrame(int index, real x, real dx)
188 {
189     GMX_RELEASE_ASSERT(impl_ != NULL, "Invalid data handle used");
190     GMX_RELEASE_ASSERT(impl_->currentFrame_ == NULL,
191                        "startFrame() called twice without calling finishFrame()");
192     impl_->currentFrame_ =
193         &impl_->data_.impl_->storage_.startFrame(index, x, dx);
194 }
195
196
197 void
198 AnalysisDataHandle::setPoint(int column, real value, bool bPresent)
199 {
200     GMX_RELEASE_ASSERT(impl_ != NULL, "Invalid data handle used");
201     GMX_RELEASE_ASSERT(impl_->currentFrame_ != NULL,
202                        "setPoint() called without calling startFrame()");
203     impl_->currentFrame_->setValue(column, value, bPresent);
204 }
205
206
207 void
208 AnalysisDataHandle::setPoint(int column, real value, real error, bool bPresent)
209 {
210     GMX_RELEASE_ASSERT(impl_ != NULL, "Invalid data handle used");
211     GMX_RELEASE_ASSERT(impl_->currentFrame_ != NULL,
212                        "setPoint() called without calling startFrame()");
213     impl_->currentFrame_->setValue(column, value, error, bPresent);
214 }
215
216
217 void
218 AnalysisDataHandle::setPoints(int firstColumn, int count, const real *values)
219 {
220     GMX_RELEASE_ASSERT(impl_ != NULL, "Invalid data handle used");
221     GMX_RELEASE_ASSERT(impl_->currentFrame_ != NULL,
222                        "setPoints() called without calling startFrame()");
223     for (int i = 0; i < count; ++i)
224     {
225         impl_->currentFrame_->setValue(firstColumn + i, values[i]);
226     }
227 }
228
229
230 void
231 AnalysisDataHandle::finishPointSet()
232 {
233     GMX_RELEASE_ASSERT(impl_ != NULL, "Invalid data handle used");
234     GMX_RELEASE_ASSERT(impl_->data_.isMultipoint(),
235                        "finishPointSet() called for non-multipoint data");
236     GMX_RELEASE_ASSERT(impl_->currentFrame_ != NULL,
237                        "finishPointSet() called without calling startFrame()");
238     impl_->currentFrame_->finishPointSet();
239 }
240
241
242 void
243 AnalysisDataHandle::finishFrame()
244 {
245     GMX_RELEASE_ASSERT(impl_ != NULL, "Invalid data handle used");
246     GMX_RELEASE_ASSERT(impl_->currentFrame_ != NULL,
247                        "finishFrame() called without calling startFrame()");
248     int index = impl_->currentFrame_->frameIndex();
249     impl_->currentFrame_ = NULL;
250     impl_->data_.impl_->storage_.finishFrame(index);
251 }
252
253
254 void
255 AnalysisDataHandle::finishData()
256 {
257     GMX_RELEASE_ASSERT(impl_ != NULL, "Invalid data handle used");
258     // Deletes the implementation pointer.
259     impl_->data_.finishData(*this);
260     impl_ = NULL;
261 }
262
263 } // namespace gmx