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/utility/exceptions.h"
46 #include "gromacs/utility/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()
142 AnalysisDataStorage::Impl::columnCount() const
144 GMX_ASSERT(data_ != NULL, "columnCount() called too early");
145 return data_->columnCount();
150 AnalysisDataStorage::Impl::isMultipoint() const
157 AnalysisDataStorage::Impl::firstStoredIndex() const
159 return frames_[firstFrameLocation_].frame->frameIndex();
164 AnalysisDataStorage::Impl::computeStorageLocation(int index) const
166 if (index < firstStoredIndex() || index >= nextIndex_)
170 return index % frames_.size();
175 AnalysisDataStorage::Impl::endStorageLocation() const
179 return frames_.size();
181 if (frames_[0].frame->frameIndex() == 0 || firstFrameLocation_ == 0)
183 return frames_.size() - 1;
185 return firstFrameLocation_ - 1;
190 AnalysisDataStorage::Impl::extendBuffer(AnalysisDataStorage *storage,
193 frames_.reserve(newSize);
194 while (frames_.size() < newSize)
196 frames_.push_back(StoredFrame(
197 new AnalysisDataStorageFrame(storage, columnCount(), nextIndex_)));
200 // The unused frame should not be included in the count.
209 AnalysisDataStorage::Impl::rotateBuffer()
211 GMX_ASSERT(!storeAll(),
212 "No need to rotate internal buffer if everything is stored");
213 size_t prevFirst = firstFrameLocation_;
214 size_t nextFirst = prevFirst + 1;
215 if (nextFirst == frames_.size())
219 firstFrameLocation_ = nextFirst;
220 StoredFrame &prevFrame = frames_[prevFirst];
221 prevFrame.status = StoredFrame::eMissing;
222 prevFrame.frame->header_ = AnalysisDataFrameHeader(nextIndex_ + 1, 0.0, 0.0);
223 prevFrame.frame->clearValues();
229 AnalysisDataStorage::Impl::notifyPointSet(const AnalysisDataPointSetRef &points)
231 data_->notifyPointsAdd(points);
236 AnalysisDataStorage::Impl::notifyNextFrames(size_t firstLocation)
238 if (firstLocation != firstFrameLocation_)
240 // firstLocation can only be zero here if !storeAll() because
241 // firstFrameLocation_ is always zero for storeAll()
243 (firstLocation == 0 ? frames_.size() - 1 : firstLocation - 1);
244 if (!frames_[prevIndex].isNotified())
249 size_t i = firstLocation;
250 size_t end = endStorageLocation();
253 Impl::StoredFrame &storedFrame = frames_[i];
254 if (!storedFrame.isFinished())
258 if (storedFrame.status == StoredFrame::eFinished)
260 data_->notifyFrameStart(storedFrame.frame->header());
261 data_->notifyPointsAdd(storedFrame.frame->currentPoints());
262 data_->notifyFrameFinish(storedFrame.frame->header());
263 storedFrame.status = StoredFrame::eNotified;
264 if (storedFrame.frame->frameIndex() >= storageLimit_)
270 if (!storeAll() && i >= frames_.size())
278 /********************************************************************
279 * AnalysisDataStorage
282 AnalysisDataStorage::AnalysisDataStorage()
288 AnalysisDataStorage::~AnalysisDataStorage()
294 AnalysisDataStorage::setMultipoint(bool bMultipoint)
296 if (bMultipoint && impl_->storageLimit_ > 0)
298 GMX_THROW(APIError("Storage of multipoint data not supported"));
300 impl_->bMultipoint_ = bMultipoint;
305 AnalysisDataStorage::setParallelOptions(const AnalysisDataParallelOptions &opt)
307 impl_->pendingLimit_ = 2 * opt.parallelizationFactor() - 1;
312 AnalysisDataStorage::tryGetDataFrame(int index) const
314 if (impl_->isMultipoint())
316 return AnalysisDataFrameRef();
318 int storageIndex = impl_->computeStorageLocation(index);
319 if (storageIndex == -1)
321 return AnalysisDataFrameRef();
323 const Impl::StoredFrame &storedFrame = impl_->frames_[storageIndex];
324 if (!storedFrame.isAvailable())
326 return AnalysisDataFrameRef();
328 const Impl::FramePointer &frame = storedFrame.frame;
329 return AnalysisDataFrameRef(frame->header(), frame->values_);
334 AnalysisDataStorage::requestStorage(int nframes)
336 if (impl_->isMultipoint())
341 // Handle the case when everything needs to be stored.
344 impl_->storageLimit_ = std::numeric_limits<int>::max();
347 // Check whether an earlier call has requested more storage.
348 if (nframes < impl_->storageLimit_)
352 impl_->storageLimit_ = nframes;
358 AnalysisDataStorage::startDataStorage(AbstractAnalysisData *data)
360 // Data needs to be set before calling extendBuffer()
362 setMultipoint(data->isMultipoint());
363 if (!impl_->storeAll())
365 impl_->extendBuffer(this, impl_->storageLimit_ + impl_->pendingLimit_ + 1);
370 AnalysisDataStorageFrame &
371 AnalysisDataStorage::startFrame(const AnalysisDataFrameHeader &header)
373 GMX_ASSERT(header.isValid(), "Invalid header");
374 Impl::StoredFrame *storedFrame;
375 if (impl_->storeAll())
377 size_t size = header.index() + 1;
378 if (impl_->frames_.size() < size)
380 impl_->extendBuffer(this, size);
382 storedFrame = &impl_->frames_[header.index()];
386 int storageIndex = impl_->computeStorageLocation(header.index());
387 if (storageIndex == -1)
389 GMX_THROW(APIError("Out of bounds frame index"));
391 storedFrame = &impl_->frames_[storageIndex];
393 GMX_RELEASE_ASSERT(!storedFrame->isStarted(),
394 "startFrame() called twice for the same frame");
395 GMX_RELEASE_ASSERT(storedFrame->frame->frameIndex() == header.index(),
396 "Inconsistent internal frame indexing");
397 storedFrame->status = Impl::StoredFrame::eStarted;
398 storedFrame->frame->header_ = header;
399 if (impl_->isMultipoint())
401 impl_->data_->notifyFrameStart(header);
403 return *storedFrame->frame;
407 AnalysisDataStorageFrame &
408 AnalysisDataStorage::startFrame(int index, real x, real dx)
410 return startFrame(AnalysisDataFrameHeader(index, x, dx));
414 AnalysisDataStorageFrame &
415 AnalysisDataStorage::currentFrame(int index)
417 int storageIndex = impl_->computeStorageLocation(index);
418 GMX_RELEASE_ASSERT(storageIndex >= 0, "Out of bounds frame index");
419 Impl::StoredFrame &storedFrame = impl_->frames_[storageIndex];
420 GMX_RELEASE_ASSERT(storedFrame.isStarted(),
421 "currentFrame() called for frame before startFrame()");
422 GMX_RELEASE_ASSERT(!storedFrame.isFinished(),
423 "currentFrame() called for frame after finishFrame()");
424 GMX_RELEASE_ASSERT(storedFrame.frame->frameIndex() == index,
425 "Inconsistent internal frame indexing");
426 return *storedFrame.frame;
431 AnalysisDataStorage::finishFrame(int index)
433 int storageIndex = impl_->computeStorageLocation(index);
434 GMX_RELEASE_ASSERT(storageIndex >= 0, "Out of bounds frame index");
435 Impl::StoredFrame &storedFrame = impl_->frames_[storageIndex];
436 GMX_RELEASE_ASSERT(storedFrame.isStarted(),
437 "finishFrame() called for frame before startFrame()");
438 GMX_RELEASE_ASSERT(!storedFrame.isFinished(),
439 "finishFrame() called twice for the same frame");
440 GMX_RELEASE_ASSERT(storedFrame.frame->frameIndex() == index,
441 "Inconsistent internal frame indexing");
442 storedFrame.status = Impl::StoredFrame::eFinished;
443 if (impl_->isMultipoint())
445 // TODO: Check that the last point set has been finished
446 impl_->data_->notifyFrameFinish(storedFrame.frame->header());
447 if (storedFrame.frame->frameIndex() >= impl_->storageLimit_)
449 impl_->rotateBuffer();
454 impl_->notifyNextFrames(storageIndex);
460 AnalysisDataStorage::finishFrame(const AnalysisDataStorageFrame &frame)
462 finishFrame(frame.frameIndex());