2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2010,2011,2012, by the GROMACS development team, led by
5 * David van der Spoel, Berk Hess, Erik Lindahl, and including many
6 * others, as listed in the AUTHORS file in the top-level source
7 * directory and at http://www.gromacs.org.
9 * GROMACS is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1
12 * of the License, or (at your option) any later version.
14 * GROMACS is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with GROMACS; if not, see
21 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 * If you want to redistribute modifications to GROMACS, please
25 * consider that scientific software is very special. Version
26 * control is crucial - bugs must be traceable. We will be happy to
27 * consider code for inclusion in the official distribution, but
28 * derived work must not be called official GROMACS. Details are found
29 * in the README & COPYING files - if they are missing, get the
30 * official version at http://www.gromacs.org.
32 * To help us fund GROMACS development, we humbly ask that you cite
33 * the research papers on the package. Check out http://www.gromacs.org.
37 * Implements classes in histogram.h.
39 * \author Teemu Murtola <teemu.murtola@gmail.com>
40 * \ingroup module_analysisdata
42 #include "gromacs/analysisdata/modules/histogram.h"
48 #include "gromacs/analysisdata/dataframe.h"
49 #include "gromacs/analysisdata/datastorage.h"
50 #include "gromacs/utility/exceptions.h"
51 #include "gromacs/utility/gmxassert.h"
56 //! Value used to signify that a real-valued histogram setting is not set.
57 const real UNDEFINED = std::numeric_limits<real>::max();
58 //! Checks whether \p value is defined.
59 bool isDefined(real value)
61 return value != UNDEFINED;
69 /********************************************************************
70 * AnalysisHistogramSettingsInitializer
73 AnalysisHistogramSettingsInitializer::AnalysisHistogramSettingsInitializer()
74 : min_(UNDEFINED), max_(UNDEFINED), binWidth_(UNDEFINED),
75 binCount_(0), bIntegerBins_(false), bRoundRange_(false),
81 /********************************************************************
82 * AnalysisHistogramSettings
85 AnalysisHistogramSettings::AnalysisHistogramSettings()
86 : firstEdge_(0.0), lastEdge_(0.0), binWidth_(0.0), inverseBinWidth_(0.0),
87 binCount_(0), bAll_(false)
92 AnalysisHistogramSettings::AnalysisHistogramSettings(
93 const AnalysisHistogramSettingsInitializer &settings)
95 GMX_RELEASE_ASSERT(isDefined(settings.min_),
96 "Histogram start value must be defined");
97 GMX_RELEASE_ASSERT(!isDefined(settings.max_) || settings.max_ > settings.min_,
98 "Histogram end value must be larger than start value");
99 GMX_RELEASE_ASSERT(!isDefined(settings.binWidth_) || settings.binWidth_ > 0.0,
100 "Histogram bin width must be positive");
101 GMX_RELEASE_ASSERT(settings.binCount_ >= 0,
102 "Histogram bin count must be positive");
104 if (!isDefined(settings.max_))
106 GMX_RELEASE_ASSERT(isDefined(settings.binWidth_) && settings.binCount_ > 0,
107 "Not all required values provided");
108 GMX_RELEASE_ASSERT(!settings.bRoundRange_,
109 "Rounding only supported for min/max ranges");
111 firstEdge_ = settings.min_;
112 binCount_ = settings.binCount_;
113 binWidth_ = settings.binWidth_;
114 if (settings.bIntegerBins_)
116 firstEdge_ -= 0.5 * binWidth_;
118 lastEdge_ = firstEdge_ + binCount_ * binWidth_;
122 GMX_RELEASE_ASSERT(!(isDefined(settings.binWidth_) && settings.binCount_ > 0),
123 "Conflicting histogram bin specifications");
124 GMX_RELEASE_ASSERT(isDefined(settings.binWidth_) || settings.binCount_ > 0,
125 "Not all required values provided");
127 if (settings.bRoundRange_)
129 GMX_RELEASE_ASSERT(!settings.bIntegerBins_,
130 "Rounding and integer bins cannot be combined");
131 GMX_RELEASE_ASSERT(isDefined(settings.binWidth_),
132 "Rounding only makes sense with defined binwidth");
133 binWidth_ = settings.binWidth_;
134 firstEdge_ = binWidth_ * floor(settings.min_ / binWidth_);
135 lastEdge_ = binWidth_ * ceil(settings.max_ / binWidth_);
136 binCount_ = static_cast<int>((lastEdge_ - firstEdge_) / binWidth_ + 0.5);
140 firstEdge_ = settings.min_;
141 lastEdge_ = settings.max_;
142 if (settings.binCount_ > 0)
144 binCount_ = settings.binCount_;
145 if (settings.bIntegerBins_)
147 GMX_RELEASE_ASSERT(settings.binCount_ > 1,
148 "Bin count must be at least two with integer bins");
149 binWidth_ = (lastEdge_ - firstEdge_) / (binCount_ - 1);
150 firstEdge_ -= 0.5 * binWidth_;
151 lastEdge_ += 0.5 * binWidth_;
155 binWidth_ = (lastEdge_ - firstEdge_) / binCount_;
160 binWidth_ = settings.binWidth_;
161 binCount_ = static_cast<int>((lastEdge_ - firstEdge_) / binWidth_ + 0.5);
162 if (settings.bIntegerBins_)
164 firstEdge_ -= 0.5 * binWidth_;
167 lastEdge_ = firstEdge_ + binCount_ * binWidth_;
172 inverseBinWidth_ = 1.0 / binWidth_;
173 bAll_ = settings.bIncludeAll_;
178 AnalysisHistogramSettings::findBin(real y) const
182 return bAll_ ? 0 : -1;
184 int bin = static_cast<int>((y - firstEdge_) * inverseBinWidth_);
185 if (bin >= binCount_)
187 return bAll_ ? binCount_ - 1 : -1;
193 /********************************************************************
194 * StaticAverageHistogram
201 * Represents copies of average histograms.
203 * Methods in AbstractAverageHistogram that return new histogram instances
204 * return objects of this class.
205 * Initialization of values is handled in those methods.
207 * \ingroup module_analysisdata
209 class StaticAverageHistogram : public AbstractAverageHistogram
212 StaticAverageHistogram();
213 //! Creates an average histogram module with defined bin parameters.
214 explicit StaticAverageHistogram(const AnalysisHistogramSettings &settings);
216 // Copy and assign disallowed by base.
219 StaticAverageHistogram::StaticAverageHistogram()
224 StaticAverageHistogram::StaticAverageHistogram(
225 const AnalysisHistogramSettings &settings)
226 : AbstractAverageHistogram(settings)
233 /********************************************************************
234 * AbstractAverageHistogram
237 AbstractAverageHistogram::AbstractAverageHistogram()
242 AbstractAverageHistogram::AbstractAverageHistogram(
243 const AnalysisHistogramSettings &settings)
244 : settings_(settings)
246 setRowCount(settings.binCount());
247 setXAxis(settings.firstEdge() + 0.5 * settings.binWidth(),
248 settings.binWidth());
252 AbstractAverageHistogram::~AbstractAverageHistogram()
258 AbstractAverageHistogram::init(const AnalysisHistogramSettings &settings)
260 settings_ = settings;
261 setRowCount(settings.binCount());
262 setXAxis(settings.firstEdge() + 0.5 * settings.binWidth(),
263 settings.binWidth());
267 AverageHistogramPointer
268 AbstractAverageHistogram::resampleDoubleBinWidth(bool bIntegerBins) const
273 nbins = (rowCount() + 1) / 2;
277 nbins = rowCount() / 2;
280 AverageHistogramPointer dest(
281 new StaticAverageHistogram(
282 histogramFromBins(xstart(), nbins, 2*xstep())
283 .integerBins(bIntegerBins)));
284 dest->setColumnCount(columnCount());
285 dest->allocateValues();
288 for (i = j = 0; i < nbins; ++i)
290 const bool bFirstHalfBin = (bIntegerBins && i == 0);
291 for (int c = 0; c < columnCount(); ++c)
302 v2 = value(j + 1, c);
306 dest->setValue(i, c, sqrt(v1 * v1 + v2 * v2));
310 dest->setValue(i, c, v1 + v2);
326 AverageHistogramPointer
327 AbstractAverageHistogram::clone() const
329 AverageHistogramPointer dest(new StaticAverageHistogram());
330 copyContents(this, dest.get());
336 AbstractAverageHistogram::normalizeProbability()
339 for (int i = 0; i < rowCount(); ++i)
343 scale(1.0 / (sum * xstep()));
348 AbstractAverageHistogram::scale(real norm)
350 for (int i = 0; i < rowCount(); ++i)
359 AbstractAverageHistogram::scaleVector(real norm[])
361 for (int i = 0; i < rowCount(); ++i)
363 value(i, 0) *= norm[i];
364 value(i, 1) *= norm[i];
369 /********************************************************************
370 * BasicAverageHistogramModule
377 * Implements average histogram module that averages per-frame histograms.
379 * This class is used for accumulating average histograms in per-frame
380 * histogram modules (those that use BasicHistogramImpl as their implementation
382 * There are two columns, first for the average and second for standard
385 * \ingroup module_analysisdata
387 class BasicAverageHistogramModule : public AbstractAverageHistogram,
388 public AnalysisDataModuleInterface
391 BasicAverageHistogramModule();
392 //! Creates an average histogram module with defined bin parameters.
393 explicit BasicAverageHistogramModule(const AnalysisHistogramSettings &settings);
395 using AbstractAverageHistogram::init;
397 virtual int flags() const;
399 virtual void dataStarted(AbstractAnalysisData *data);
400 virtual void frameStarted(const AnalysisDataFrameHeader &header);
401 virtual void pointsAdded(const AnalysisDataPointSetRef &points);
402 virtual void frameFinished(const AnalysisDataFrameHeader &header);
403 virtual void dataFinished();
406 //! Number of frames accumulated so far.
409 // Copy and assign disallowed by base.
412 BasicAverageHistogramModule::BasicAverageHistogramModule()
419 BasicAverageHistogramModule::BasicAverageHistogramModule(
420 const AnalysisHistogramSettings &settings)
421 : AbstractAverageHistogram(settings), frameCount_(0)
428 BasicAverageHistogramModule::flags() const
430 return efAllowMulticolumn;
435 BasicAverageHistogramModule::dataStarted(AbstractAnalysisData *data)
437 GMX_RELEASE_ASSERT(rowCount() == data->columnCount(),
438 "Inconsistent data sizes, something is wrong in the initialization");
444 BasicAverageHistogramModule::frameStarted(const AnalysisDataFrameHeader & /*header*/)
450 BasicAverageHistogramModule::pointsAdded(const AnalysisDataPointSetRef &points)
452 int firstcol = points.firstColumn();
453 for (int i = 0; i < points.columnCount(); ++i)
455 real y = points.y(i);
456 value(firstcol + i, 0) += y;
457 value(firstcol + i, 1) += y * y;
463 BasicAverageHistogramModule::frameFinished(const AnalysisDataFrameHeader & /*header*/)
470 BasicAverageHistogramModule::dataFinished()
472 for (int i = 0; i < rowCount(); ++i)
474 real ave = value(i, 0) / frameCount_;
475 real std = sqrt(value(i, 1) / frameCount_ - ave * ave);
482 /********************************************************************
487 * Private implementation class for AnalysisDataSimpleHistogramModule and
488 * AnalysisDataWeightedHistogramModule.
490 * \ingroup module_analysisdata
492 class BasicHistogramImpl
495 //! Smart pointer to manage an BasicAverageHistogramModule object.
496 typedef boost::shared_ptr<BasicAverageHistogramModule>
497 BasicAverageHistogramModulePointer;
499 BasicHistogramImpl();
500 //! Creates an histogram impl with defined bin parameters.
501 explicit BasicHistogramImpl(const AnalysisHistogramSettings &settings);
502 ~BasicHistogramImpl();
505 * (Re)initializes the histogram from settings.
507 void init(const AnalysisHistogramSettings &settings);
509 * Initializes data storage frame when a new frame starts.
511 void initFrame(AnalysisDataStorageFrame *frame);
513 //! Storage implementation object.
514 AnalysisDataStorage storage_;
515 //! Settings for the histogram object.
516 AnalysisHistogramSettings settings_;
518 BasicAverageHistogramModulePointer averager_;
521 BasicHistogramImpl::BasicHistogramImpl()
522 : averager_(new BasicAverageHistogramModule())
527 BasicHistogramImpl::BasicHistogramImpl(const AnalysisHistogramSettings &settings)
528 : settings_(settings), averager_(new BasicAverageHistogramModule(settings))
533 BasicHistogramImpl::~BasicHistogramImpl()
538 void BasicHistogramImpl::init(const AnalysisHistogramSettings &settings)
540 settings_ = settings;
541 averager_->init(settings);
546 BasicHistogramImpl::initFrame(AnalysisDataStorageFrame *frame)
548 for (int i = 0; i < frame->columnCount(); ++i)
550 frame->setValue(i, 0.0);
554 } // namespace internal
557 /********************************************************************
558 * AnalysisDataSimpleHistogramModule
561 AnalysisDataSimpleHistogramModule::AnalysisDataSimpleHistogramModule()
562 : impl_(new internal::BasicHistogramImpl())
567 AnalysisDataSimpleHistogramModule::AnalysisDataSimpleHistogramModule(
568 const AnalysisHistogramSettings &settings)
569 : impl_(new internal::BasicHistogramImpl(settings))
574 AnalysisDataSimpleHistogramModule::~AnalysisDataSimpleHistogramModule()
579 void AnalysisDataSimpleHistogramModule::init(const AnalysisHistogramSettings &settings)
581 impl_->init(settings);
585 AbstractAverageHistogram &
586 AnalysisDataSimpleHistogramModule::averager()
588 return *impl_->averager_;
592 const AnalysisHistogramSettings &
593 AnalysisDataSimpleHistogramModule::settings() const
595 return impl_->settings_;
600 AnalysisDataSimpleHistogramModule::flags() const
602 return efAllowMulticolumn | efAllowMultipoint;
607 AnalysisDataSimpleHistogramModule::dataStarted(AbstractAnalysisData *data)
609 addModule(impl_->averager_);
610 setColumnCount(settings().binCount());
612 impl_->storage_.startDataStorage(this);
617 AnalysisDataSimpleHistogramModule::frameStarted(const AnalysisDataFrameHeader &header)
619 AnalysisDataStorageFrame &frame = impl_->storage_.startFrame(header);
620 impl_->initFrame(&frame);
625 AnalysisDataSimpleHistogramModule::pointsAdded(const AnalysisDataPointSetRef &points)
627 AnalysisDataStorageFrame &frame =
628 impl_->storage_.currentFrame(points.frameIndex());
629 for (int i = 0; i < points.columnCount(); ++i)
631 int bin = settings().findBin(points.y(i));
634 frame.value(bin) += 1;
641 AnalysisDataSimpleHistogramModule::frameFinished(const AnalysisDataFrameHeader &header)
643 impl_->storage_.finishFrame(header.index());
648 AnalysisDataSimpleHistogramModule::dataFinished()
655 AnalysisDataSimpleHistogramModule::tryGetDataFrameInternal(int index) const
657 return impl_->storage_.tryGetDataFrame(index);
662 AnalysisDataSimpleHistogramModule::requestStorageInternal(int nframes)
664 return impl_->storage_.requestStorage(nframes);
668 /********************************************************************
669 * AnalysisDataWeightedHistogramModule
672 AnalysisDataWeightedHistogramModule::AnalysisDataWeightedHistogramModule()
673 : impl_(new internal::BasicHistogramImpl())
678 AnalysisDataWeightedHistogramModule::AnalysisDataWeightedHistogramModule(
679 const AnalysisHistogramSettings &settings)
680 : impl_(new internal::BasicHistogramImpl(settings))
685 AnalysisDataWeightedHistogramModule::~AnalysisDataWeightedHistogramModule()
690 void AnalysisDataWeightedHistogramModule::init(const AnalysisHistogramSettings &settings)
692 impl_->init(settings);
696 AbstractAverageHistogram &
697 AnalysisDataWeightedHistogramModule::averager()
699 return *impl_->averager_;
703 const AnalysisHistogramSettings &
704 AnalysisDataWeightedHistogramModule::settings() const
706 return impl_->settings_;
711 AnalysisDataWeightedHistogramModule::flags() const
713 return efAllowMulticolumn | efAllowMultipoint;
718 AnalysisDataWeightedHistogramModule::dataStarted(AbstractAnalysisData *data)
720 addModule(impl_->averager_);
721 setColumnCount(settings().binCount());
723 impl_->storage_.startDataStorage(this);
728 AnalysisDataWeightedHistogramModule::frameStarted(const AnalysisDataFrameHeader &header)
730 AnalysisDataStorageFrame &frame = impl_->storage_.startFrame(header);
731 impl_->initFrame(&frame);
736 AnalysisDataWeightedHistogramModule::pointsAdded(const AnalysisDataPointSetRef &points)
738 if (points.firstColumn() != 0 || points.columnCount() < 2)
740 GMX_THROW(APIError("Invalid data layout"));
742 int bin = settings().findBin(points.y(0));
745 AnalysisDataStorageFrame &frame =
746 impl_->storage_.currentFrame(points.frameIndex());
747 for (int i = 1; i < points.columnCount(); ++i)
749 frame.value(bin) += points.y(i);
756 AnalysisDataWeightedHistogramModule::frameFinished(const AnalysisDataFrameHeader &header)
758 impl_->storage_.finishFrame(header.index());
763 AnalysisDataWeightedHistogramModule::dataFinished()
770 AnalysisDataWeightedHistogramModule::tryGetDataFrameInternal(int index) const
772 return impl_->storage_.tryGetDataFrame(index);
777 AnalysisDataWeightedHistogramModule::requestStorageInternal(int nframes)
779 return impl_->storage_.requestStorage(nframes);
783 /********************************************************************
784 * AnalysisDataBinAverageModule
787 AnalysisDataBinAverageModule::AnalysisDataBinAverageModule()
793 AnalysisDataBinAverageModule::AnalysisDataBinAverageModule(
794 const AnalysisHistogramSettings &settings)
795 : settings_(settings)
798 setRowCount(settings.binCount());
799 setXAxis(settings.firstEdge() + 0.5 * settings.binWidth(),
800 settings.binWidth());
804 AnalysisDataBinAverageModule::~AnalysisDataBinAverageModule()
810 AnalysisDataBinAverageModule::init(const AnalysisHistogramSettings &settings)
812 settings_ = settings;
813 setRowCount(settings.binCount());
814 setXAxis(settings.firstEdge() + 0.5 * settings.binWidth(),
815 settings.binWidth());
820 AnalysisDataBinAverageModule::flags() const
822 return efAllowMulticolumn | efAllowMultipoint;
827 AnalysisDataBinAverageModule::dataStarted(AbstractAnalysisData * /*data*/)
834 AnalysisDataBinAverageModule::frameStarted(const AnalysisDataFrameHeader & /*header*/)
840 AnalysisDataBinAverageModule::pointsAdded(const AnalysisDataPointSetRef &points)
842 if (points.firstColumn() != 0 || points.columnCount() < 2)
844 GMX_THROW(APIError("Invalid data layout"));
846 int bin = settings().findBin(points.y(0));
849 for (int i = 1; i < points.columnCount(); ++i)
851 real y = points.y(i);
853 value(bin, 1) += y * y;
855 value(bin, 2) += points.columnCount() - 1;
861 AnalysisDataBinAverageModule::frameFinished(const AnalysisDataFrameHeader & /*header*/)
867 AnalysisDataBinAverageModule::dataFinished()
869 for (int i = 0; i < settings().binCount(); ++i)
871 real n = value(i, 2);
874 real ave = value(i, 0) / n;
875 real std = sqrt(value(i, 1) / n - ave * ave);