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