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 classes in datastorage.h and paralleloptions.h.
35 * \author Teemu Murtola <teemu.murtola@cbr.su.se>
36 * \ingroup module_analysisdata
38 #include "datastorage.h"
42 #include "gromacs/analysisdata/abstractdata.h"
43 #include "gromacs/analysisdata/dataframe.h"
44 #include "gromacs/analysisdata/paralleloptions.h"
45 #include "gromacs/fatalerror/exceptions.h"
46 #include "gromacs/fatalerror/gmxassert.h"
48 #include "datastorage-impl.h"
53 /********************************************************************
54 * AnalysisDataParallelOptions
57 AnalysisDataParallelOptions::AnalysisDataParallelOptions()
58 : parallelizationFactor_(1)
63 AnalysisDataParallelOptions::AnalysisDataParallelOptions(int parallelizationFactor)
64 : parallelizationFactor_(parallelizationFactor)
66 GMX_RELEASE_ASSERT(parallelizationFactor >= 1,
67 "Invalid parallelization factor");
71 /********************************************************************
72 * AnalysisDataStorageFrame
75 AnalysisDataStorageFrame::AnalysisDataStorageFrame(AnalysisDataStorage *storage,
76 int columnCount, int index)
77 : storage_(storage), header_(index, 0.0, 0.0), values_(columnCount)
82 AnalysisDataStorageFrame::~AnalysisDataStorageFrame()
87 AnalysisDataPointSetRef
88 AnalysisDataStorageFrame::currentPoints() const
90 std::vector<AnalysisDataValue>::const_iterator begin = values_.begin();
91 std::vector<AnalysisDataValue>::const_iterator end = values_.end();
92 while (begin != end && !begin->isSet())
96 while (end != begin && !(end-1)->isSet())
100 int firstColumn = (begin != end) ? begin - values_.begin() : 0;
101 return AnalysisDataPointSetRef(header_, firstColumn,
102 AnalysisDataValuesRef(begin, end));
107 AnalysisDataStorageFrame::clearValues()
109 std::vector<AnalysisDataValue>::iterator i;
110 for (i = values_.begin(); i != values_.end(); ++i)
118 AnalysisDataStorageFrame::finishPointSet()
120 storage_->impl_->notifyPointSet(currentPoints());
125 /********************************************************************
126 * AnalysisDataStorage::Impl
129 AnalysisDataStorage::Impl::Impl()
130 : data_(NULL), bMultipoint_(false),
131 storageLimit_(0), pendingLimit_(1), firstFrameLocation_(0), nextIndex_(0)
136 AnalysisDataStorage::Impl::~Impl()
138 FrameList::const_iterator i;
139 for (i = frames_.begin(); i != frames_.end(); ++i)
147 AnalysisDataStorage::Impl::columnCount() const
149 GMX_ASSERT(data_ != NULL, "columnCount() called too early");
150 return data_->columnCount();
155 AnalysisDataStorage::Impl::isMultipoint() const
162 AnalysisDataStorage::Impl::firstStoredIndex() const
164 return frames_[firstFrameLocation_].frame->frameIndex();
169 AnalysisDataStorage::Impl::computeStorageLocation(int index) const
171 if (index < firstStoredIndex() || index >= nextIndex_)
175 return index % frames_.size();
180 AnalysisDataStorage::Impl::endStorageLocation() const
184 return frames_.size();
186 if (frames_[0].frame->frameIndex() == 0 || firstFrameLocation_ == 0)
188 return frames_.size() - 1;
190 return firstFrameLocation_ - 1;
195 AnalysisDataStorage::Impl::extendBuffer(AnalysisDataStorage *storage,
198 frames_.reserve(newSize);
199 while (frames_.size() < newSize)
201 AnalysisDataStorageFrame *frame =
202 new AnalysisDataStorageFrame(storage, columnCount(), nextIndex_);
203 frames_.push_back(StoredFrame(frame));
206 // The unused frame should not be included in the count.
215 AnalysisDataStorage::Impl::rotateBuffer()
217 GMX_ASSERT(!storeAll(),
218 "No need to rotate internal buffer if everything is stored");
219 size_t prevFirst = firstFrameLocation_;
220 size_t nextFirst = prevFirst + 1;
221 if (nextFirst == frames_.size())
225 firstFrameLocation_ = nextFirst;
226 StoredFrame &prevFrame = frames_[prevFirst];
227 prevFrame.status = StoredFrame::eMissing;
228 prevFrame.frame->header_ = AnalysisDataFrameHeader(nextIndex_ + 1, 0.0, 0.0);
229 prevFrame.frame->clearValues();
235 AnalysisDataStorage::Impl::notifyPointSet(const AnalysisDataPointSetRef &points)
237 data_->notifyPointsAdd(points);
242 AnalysisDataStorage::Impl::notifyNextFrames(size_t firstLocation)
244 if (firstLocation != firstFrameLocation_)
246 // firstLocation can only be zero here if !storeAll() because
247 // firstFrameLocation_ is always zero for storeAll()
249 (firstLocation == 0 ? frames_.size() - 1 : firstLocation - 1);
250 if (!frames_[prevIndex].isNotified())
255 size_t i = firstLocation;
256 size_t end = endStorageLocation();
259 Impl::StoredFrame &storedFrame = frames_[i];
260 if (!storedFrame.isFinished())
264 if (storedFrame.status == StoredFrame::eFinished)
266 data_->notifyFrameStart(storedFrame.frame->header());
267 data_->notifyPointsAdd(storedFrame.frame->currentPoints());
268 data_->notifyFrameFinish(storedFrame.frame->header());
269 storedFrame.status = StoredFrame::eNotified;
270 if (storedFrame.frame->frameIndex() >= storageLimit_)
276 if (!storeAll() && i >= frames_.size())
284 /********************************************************************
285 * AnalysisDataStorage
288 AnalysisDataStorage::AnalysisDataStorage()
294 AnalysisDataStorage::~AnalysisDataStorage()
300 AnalysisDataStorage::setMultipoint(bool bMultipoint)
302 if (bMultipoint && impl_->storageLimit_ > 0)
304 GMX_THROW(APIError("Storage of multipoint data not supported"));
306 impl_->bMultipoint_ = bMultipoint;
311 AnalysisDataStorage::setParallelOptions(const AnalysisDataParallelOptions &opt)
313 impl_->pendingLimit_ = 2 * opt.parallelizationFactor() - 1;
318 AnalysisDataStorage::tryGetDataFrame(int index) const
320 if (impl_->isMultipoint())
322 return AnalysisDataFrameRef();
324 int storageIndex = impl_->computeStorageLocation(index);
325 if (storageIndex == -1)
327 return AnalysisDataFrameRef();
329 const Impl::StoredFrame &storedFrame = impl_->frames_[storageIndex];
330 if (!storedFrame.isAvailable())
332 return AnalysisDataFrameRef();
334 const AnalysisDataStorageFrame *frame = storedFrame.frame;
335 return AnalysisDataFrameRef(frame->header(), frame->values_);
340 AnalysisDataStorage::requestStorage(int nframes)
342 if (impl_->isMultipoint())
347 // Handle the case when everything needs to be stored.
350 impl_->storageLimit_ = std::numeric_limits<int>::max();
353 // Check whether an earlier call has requested more storage.
354 if (nframes < impl_->storageLimit_)
358 impl_->storageLimit_ = nframes;
364 AnalysisDataStorage::startDataStorage(AbstractAnalysisData *data)
366 // Data needs to be set before calling extendBuffer()
368 setMultipoint(data->isMultipoint());
369 if (!impl_->storeAll())
371 impl_->extendBuffer(this, impl_->storageLimit_ + impl_->pendingLimit_ + 1);
376 AnalysisDataStorageFrame &
377 AnalysisDataStorage::startFrame(const AnalysisDataFrameHeader &header)
379 GMX_ASSERT(header.isValid(), "Invalid header");
380 Impl::StoredFrame *storedFrame;
381 if (impl_->storeAll())
383 size_t size = header.index() + 1;
384 if (impl_->frames_.size() < size)
386 impl_->extendBuffer(this, size);
388 storedFrame = &impl_->frames_[header.index()];
392 int storageIndex = impl_->computeStorageLocation(header.index());
393 if (storageIndex == -1)
395 GMX_THROW(APIError("Out of bounds frame index"));
397 storedFrame = &impl_->frames_[storageIndex];
399 GMX_RELEASE_ASSERT(!storedFrame->isStarted(),
400 "startFrame() called twice for the same frame");
401 GMX_RELEASE_ASSERT(storedFrame->frame->frameIndex() == header.index(),
402 "Inconsistent internal frame indexing");
403 storedFrame->status = Impl::StoredFrame::eStarted;
404 storedFrame->frame->header_ = header;
405 if (impl_->isMultipoint())
407 impl_->data_->notifyFrameStart(header);
409 return *storedFrame->frame;
413 AnalysisDataStorageFrame &
414 AnalysisDataStorage::startFrame(int index, real x, real dx)
416 return startFrame(AnalysisDataFrameHeader(index, x, dx));
420 AnalysisDataStorageFrame &
421 AnalysisDataStorage::currentFrame(int index)
423 int storageIndex = impl_->computeStorageLocation(index);
424 GMX_RELEASE_ASSERT(storageIndex >= 0, "Out of bounds frame index");
425 Impl::StoredFrame &storedFrame = impl_->frames_[storageIndex];
426 GMX_RELEASE_ASSERT(storedFrame.isStarted(),
427 "currentFrame() called for frame before startFrame()");
428 GMX_RELEASE_ASSERT(!storedFrame.isFinished(),
429 "currentFrame() called for frame after finishFrame()");
430 GMX_RELEASE_ASSERT(storedFrame.frame->frameIndex() == index,
431 "Inconsistent internal frame indexing");
432 return *storedFrame.frame;
437 AnalysisDataStorage::finishFrame(int index)
439 int storageIndex = impl_->computeStorageLocation(index);
440 GMX_RELEASE_ASSERT(storageIndex >= 0, "Out of bounds frame index");
441 Impl::StoredFrame &storedFrame = impl_->frames_[storageIndex];
442 GMX_RELEASE_ASSERT(storedFrame.isStarted(),
443 "finishFrame() called for frame before startFrame()");
444 GMX_RELEASE_ASSERT(!storedFrame.isFinished(),
445 "finishFrame() called twice for the same frame");
446 GMX_RELEASE_ASSERT(storedFrame.frame->frameIndex() == index,
447 "Inconsistent internal frame indexing");
448 storedFrame.status = Impl::StoredFrame::eFinished;
449 if (impl_->isMultipoint())
451 // TODO: Check that the last point set has been finished
452 impl_->data_->notifyFrameFinish(storedFrame.frame->header());
453 if (storedFrame.frame->frameIndex() >= impl_->storageLimit_)
455 impl_->rotateBuffer();
460 impl_->notifyNextFrames(storageIndex);
466 AnalysisDataStorage::finishFrame(const AnalysisDataStorageFrame &frame)
468 finishFrame(frame.frameIndex());