3 * This source code is part of
7 * GROningen MAchine for Chemical Simulations
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.
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.
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.
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.
29 * For more info, check our website at http://www.gromacs.org
33 * Implements gmx::AbstractAnalysisData.
35 * \author Teemu Murtola <teemu.murtola@cbr.su.se>
36 * \ingroup module_analysisdata
38 #include "gromacs/analysisdata/abstractdata.h"
40 #include "gromacs/utility/exceptions.h"
41 #include "gromacs/utility/gmxassert.h"
43 #include "abstractdata-impl.h"
44 #include "dataframe.h"
45 #include "dataproxy.h"
50 /********************************************************************
51 * AbstractAnalysisData::Impl
54 AbstractAnalysisData::Impl::Impl()
55 : _bAllowMissing(true), _bDataStart(false), _bInData(false), _bInFrame(false),
56 _currIndex(-1), _nframes(0)
60 AbstractAnalysisData::Impl::~Impl()
66 AbstractAnalysisData::Impl::presentData(AbstractAnalysisData *data,
67 AnalysisDataModuleInterface *module)
69 module->dataStarted(data);
70 bool bCheckMissing = _bAllowMissing
71 && !(module->flags() & AnalysisDataModuleInterface::efAllowMissing);
72 for (int i = 0; i < data->frameCount(); ++i)
74 AnalysisDataFrameRef frame = data->getDataFrame(i);
75 GMX_RELEASE_ASSERT(frame.isValid(), "Invalid data frame returned");
76 // TODO: Check all frames before doing anything for slightly better
77 // exception behavior.
78 if (bCheckMissing && !frame.allPresent())
80 GMX_THROW(APIError("Missing data not supported by a module"));
82 module->frameStarted(frame.header());
83 module->pointsAdded(frame.points());
84 module->frameFinished(frame.header());
88 module->dataFinished();
93 /********************************************************************
94 * AbstractAnalysisData
97 AbstractAnalysisData::AbstractAnalysisData()
98 : _impl(new Impl()), _ncol(0), _bMultiPoint(false)
103 AbstractAnalysisData::~AbstractAnalysisData()
109 AbstractAnalysisData::frameCount() const
111 return _impl->_nframes;
116 AbstractAnalysisData::tryGetDataFrame(int index) const
118 if (index < 0 || index >= frameCount())
120 return AnalysisDataFrameRef();
122 return tryGetDataFrameInternal(index);
127 AbstractAnalysisData::getDataFrame(int index) const
129 AnalysisDataFrameRef frame = tryGetDataFrame(index);
130 if (!frame.isValid())
132 GMX_THROW(APIError("Invalid frame accessed"));
139 AbstractAnalysisData::requestStorage(int nframes)
141 GMX_RELEASE_ASSERT(nframes >= -1, "Invalid number of frames requested");
146 return requestStorageInternal(nframes);
151 AbstractAnalysisData::addModule(AnalysisDataModulePointer module)
153 if ((columnCount() > 1 && !(module->flags() & AnalysisDataModuleInterface::efAllowMulticolumn))
154 || (isMultipoint() && !(module->flags() & AnalysisDataModuleInterface::efAllowMultipoint))
155 || (!isMultipoint() && (module->flags() & AnalysisDataModuleInterface::efOnlyMultipoint)))
157 GMX_THROW(APIError("Data module not compatible with data object properties"));
160 if (_impl->_bDataStart)
162 GMX_RELEASE_ASSERT(!_impl->_bInFrame,
163 "Cannot add data modules in mid-frame");
164 _impl->presentData(this, module.get());
166 if (!(module->flags() & AnalysisDataModuleInterface::efAllowMissing))
168 _impl->_bAllowMissing = false;
170 _impl->_modules.push_back(move(module));
175 AbstractAnalysisData::addColumnModule(int col, int span,
176 AnalysisDataModulePointer module)
178 GMX_RELEASE_ASSERT(col >= 0 && span >= 1 && col + span <= _ncol,
179 "Invalid columns specified for a column module");
180 if (_impl->_bDataStart)
182 GMX_THROW(NotImplementedError("Cannot add column modules after data"));
185 boost::shared_ptr<AnalysisDataProxy> proxy(
186 new AnalysisDataProxy(col, span, this));
187 proxy->addModule(module);
193 AbstractAnalysisData::applyModule(AnalysisDataModuleInterface *module)
195 if ((columnCount() > 1 && !(module->flags() & AnalysisDataModuleInterface::efAllowMulticolumn))
196 || (isMultipoint() && !(module->flags() & AnalysisDataModuleInterface::efAllowMultipoint))
197 || (!isMultipoint() && (module->flags() & AnalysisDataModuleInterface::efOnlyMultipoint)))
199 GMX_THROW(APIError("Data module not compatible with data object properties"));
201 GMX_RELEASE_ASSERT(_impl->_bDataStart && !_impl->_bInData,
202 "Data module can only be applied to ready data");
204 _impl->presentData(this, module);
209 AbstractAnalysisData::setColumnCount(int ncol)
211 GMX_RELEASE_ASSERT(ncol > 0, "Invalid data column count");
212 GMX_RELEASE_ASSERT(_ncol == 0 || _impl->_modules.empty(),
213 "Data column count cannot be changed after modules are added");
214 GMX_RELEASE_ASSERT(!_impl->_bDataStart,
215 "Data column count cannot be changed after data has been added");
221 AbstractAnalysisData::setMultipoint(bool multipoint)
223 GMX_RELEASE_ASSERT(_impl->_modules.empty(),
224 "Data type cannot be changed after modules are added");
225 GMX_RELEASE_ASSERT(!_impl->_bDataStart,
226 "Data type cannot be changed after data has been added");
227 _bMultiPoint = multipoint;
232 * This method is not const because the dataStarted() methods of the attached
233 * modules can request storage of the data.
236 AbstractAnalysisData::notifyDataStart()
238 GMX_RELEASE_ASSERT(!_impl->_bDataStart,
239 "notifyDataStart() called more than once");
240 GMX_RELEASE_ASSERT(_ncol > 0, "Data column count is not set");
241 _impl->_bDataStart = _impl->_bInData = true;
243 Impl::ModuleList::const_iterator i;
244 for (i = _impl->_modules.begin(); i != _impl->_modules.end(); ++i)
246 if (_ncol > 1 && !((*i)->flags() & AnalysisDataModuleInterface::efAllowMulticolumn))
248 GMX_THROW(APIError("Data module not compatible with data object properties"));
250 (*i)->dataStarted(this);
256 AbstractAnalysisData::notifyFrameStart(const AnalysisDataFrameHeader &header) const
258 GMX_ASSERT(_impl->_bInData, "notifyDataStart() not called");
259 GMX_ASSERT(!_impl->_bInFrame,
260 "notifyFrameStart() called while inside a frame");
261 GMX_ASSERT(header.index() == _impl->_nframes,
262 "Out of order frames");
263 _impl->_bInFrame = true;
264 _impl->_currIndex = header.index();
266 Impl::ModuleList::const_iterator i;
267 for (i = _impl->_modules.begin(); i != _impl->_modules.end(); ++i)
269 (*i)->frameStarted(header);
275 AbstractAnalysisData::notifyPointsAdd(const AnalysisDataPointSetRef &points) const
277 GMX_ASSERT(_impl->_bInData, "notifyDataStart() not called");
278 GMX_ASSERT(_impl->_bInFrame, "notifyFrameStart() not called");
279 GMX_ASSERT(points.lastColumn() < columnCount(), "Invalid columns");
280 GMX_ASSERT(points.frameIndex() == _impl->_currIndex,
281 "Points do not correspond to current frame");
282 if (!_impl->_bAllowMissing && !points.allPresent())
284 GMX_THROW(APIError("Missing data not supported by a module"));
287 Impl::ModuleList::const_iterator i;
288 for (i = _impl->_modules.begin(); i != _impl->_modules.end(); ++i)
290 (*i)->pointsAdded(points);
296 AbstractAnalysisData::notifyFrameFinish(const AnalysisDataFrameHeader &header)
298 GMX_ASSERT(_impl->_bInData, "notifyDataStart() not called");
299 GMX_ASSERT(_impl->_bInFrame, "notifyFrameStart() not called");
300 GMX_ASSERT(header.index() == _impl->_currIndex,
301 "Header does not correspond to current frame");
302 _impl->_bInFrame = false;
303 _impl->_currIndex = -1;
305 // Increment the counter before notifications to allow frame access from
309 Impl::ModuleList::const_iterator i;
310 for (i = _impl->_modules.begin(); i != _impl->_modules.end(); ++i)
312 (*i)->frameFinished(header);
318 AbstractAnalysisData::notifyDataFinish() const
320 GMX_RELEASE_ASSERT(_impl->_bInData, "notifyDataStart() not called");
321 GMX_RELEASE_ASSERT(!_impl->_bInFrame,
322 "notifyDataFinish() called while inside a frame");
323 _impl->_bInData = false;
325 Impl::ModuleList::const_iterator i;
326 for (i = _impl->_modules.begin(); i != _impl->_modules.end(); ++i)
328 (*i)->dataFinished();