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 histogram.h.
35 * \author Teemu Murtola <teemu.murtola@cbr.su.se>
36 * \ingroup module_analysisdata
38 #include "gromacs/analysisdata/modules/histogram.h"
44 #include "gromacs/analysisdata/dataframe.h"
45 #include "gromacs/analysisdata/datastorage.h"
46 #include "gromacs/utility/exceptions.h"
47 #include "gromacs/utility/gmxassert.h"
49 #include "histogram-impl.h"
51 static const real UNDEFINED = std::numeric_limits<real>::max();
52 static bool isDefined(real value)
54 return value != UNDEFINED;
60 /********************************************************************
61 * AnalysisHistogramSettingsInitializer
64 AnalysisHistogramSettingsInitializer::AnalysisHistogramSettingsInitializer()
65 : min_(UNDEFINED), max_(UNDEFINED), binWidth_(UNDEFINED),
66 binCount_(0), bIntegerBins_(false), bRoundRange_(false),
72 /********************************************************************
73 * AnalysisHistogramSettings
76 AnalysisHistogramSettings::AnalysisHistogramSettings()
77 : firstEdge_(0.0), lastEdge_(0.0), binWidth_(0.0), inverseBinWidth_(0.0),
78 binCount_(0), bAll_(false)
83 AnalysisHistogramSettings::AnalysisHistogramSettings(
84 const AnalysisHistogramSettingsInitializer &settings)
86 GMX_RELEASE_ASSERT(isDefined(settings.min_),
87 "Histogram start value must be defined");
88 GMX_RELEASE_ASSERT(!isDefined(settings.max_) || settings.max_ > settings.min_,
89 "Histogram end value must be larger than start value");
90 GMX_RELEASE_ASSERT(!isDefined(settings.binWidth_) || settings.binWidth_ > 0.0,
91 "Histogram bin width must be positive");
92 GMX_RELEASE_ASSERT(settings.binCount_ >= 0,
93 "Histogram bin count must be positive");
95 if (!isDefined(settings.max_))
97 GMX_RELEASE_ASSERT(isDefined(settings.binWidth_) && settings.binCount_ > 0,
98 "Not all required values provided");
99 GMX_RELEASE_ASSERT(!settings.bRoundRange_,
100 "Rounding only supported for min/max ranges");
102 firstEdge_ = settings.min_;
103 binCount_ = settings.binCount_;
104 binWidth_ = settings.binWidth_;
105 if (settings.bIntegerBins_)
107 firstEdge_ -= 0.5 * binWidth_;
109 lastEdge_ = firstEdge_ + binCount_ * binWidth_;
113 GMX_RELEASE_ASSERT(!(isDefined(settings.binWidth_) && settings.binCount_ > 0),
114 "Conflicting histogram bin specifications");
115 GMX_RELEASE_ASSERT(isDefined(settings.binWidth_) || settings.binCount_ > 0,
116 "Not all required values provided");
118 if (settings.bRoundRange_)
120 GMX_RELEASE_ASSERT(!settings.bIntegerBins_,
121 "Rounding and integer bins cannot be combined");
122 GMX_RELEASE_ASSERT(isDefined(settings.binWidth_),
123 "Rounding only makes sense with defined binwidth");
124 binWidth_ = settings.binWidth_;
125 firstEdge_ = binWidth_ * floor(settings.min_ / binWidth_);
126 lastEdge_ = binWidth_ * ceil(settings.max_ / binWidth_);
127 binCount_ = static_cast<int>((lastEdge_ - firstEdge_) / binWidth_ + 0.5);
131 firstEdge_ = settings.min_;
132 lastEdge_ = settings.max_;
133 if (settings.binCount_ > 0)
135 binCount_ = settings.binCount_;
136 if (settings.bIntegerBins_)
138 GMX_RELEASE_ASSERT(settings.binCount_ > 1,
139 "Bin count must be at least two with integer bins");
140 binWidth_ = (lastEdge_ - firstEdge_) / (binCount_ - 1);
141 firstEdge_ -= 0.5 * binWidth_;
142 lastEdge_ += 0.5 * binWidth_;
146 binWidth_ = (lastEdge_ - firstEdge_) / binCount_;
151 binWidth_ = settings.binWidth_;
152 binCount_ = static_cast<int>((lastEdge_ - firstEdge_) / binWidth_ + 0.5);
153 if (settings.bIntegerBins_)
155 firstEdge_ -= 0.5 * binWidth_;
158 lastEdge_ = firstEdge_ + binCount_ * binWidth_;
163 inverseBinWidth_ = 1.0 / binWidth_;
164 bAll_ = settings.bIncludeAll_;
169 AnalysisHistogramSettings::findBin(real y) const
173 return bAll_ ? 0 : -1;
175 int bin = static_cast<int>((y - firstEdge_) * inverseBinWidth_);
176 if (bin >= binCount_)
178 return bAll_ ? binCount_ - 1 : -1;
184 /********************************************************************
185 * AbstractAverageHistogram
188 AbstractAverageHistogram::AbstractAverageHistogram()
193 AbstractAverageHistogram::AbstractAverageHistogram(
194 const AnalysisHistogramSettings &settings)
195 : settings_(settings)
197 setRowCount(settings.binCount());
198 setXAxis(settings.firstEdge() + 0.5 * settings.binWidth(),
199 settings.binWidth());
203 AbstractAverageHistogram::~AbstractAverageHistogram()
209 AbstractAverageHistogram::init(const AnalysisHistogramSettings &settings)
211 settings_ = settings;
212 setRowCount(settings.binCount());
213 setXAxis(settings.firstEdge() + 0.5 * settings.binWidth(),
214 settings.binWidth());
218 AverageHistogramPointer
219 AbstractAverageHistogram::resampleDoubleBinWidth(bool bIntegerBins) const
224 nbins = (rowCount() + 1) / 2;
228 nbins = rowCount() / 2;
231 AverageHistogramPointer dest(
232 new internal::StaticAverageHistogram(
233 histogramFromBins(xstart(), nbins, 2*xstep())
234 .integerBins(bIntegerBins)));
235 dest->setColumnCount(columnCount());
236 dest->allocateValues();
239 for (i = j = 0; i < nbins; ++i)
241 const bool bFirstHalfBin = (bIntegerBins && i == 0);
242 for (int c = 0; c < columnCount(); ++c)
253 v2 = value(j + 1, c);
257 dest->setValue(i, c, sqrt(v1 * v1 + v2 * v2));
261 dest->setValue(i, c, v1 + v2);
277 AverageHistogramPointer
278 AbstractAverageHistogram::clone() const
280 AverageHistogramPointer dest(new internal::StaticAverageHistogram());
281 copyContents(this, dest.get());
287 AbstractAverageHistogram::normalizeProbability()
290 for (int i = 0; i < rowCount(); ++i)
294 scale(1.0 / (sum * xstep()));
299 AbstractAverageHistogram::scale(real norm)
301 for (int i = 0; i < rowCount(); ++i)
310 AbstractAverageHistogram::scaleVector(real norm[])
312 for (int i = 0; i < rowCount(); ++i)
314 value(i, 0) *= norm[i];
315 value(i, 1) *= norm[i];
320 /********************************************************************
321 * StaticAverageHistogram
327 StaticAverageHistogram::StaticAverageHistogram()
332 StaticAverageHistogram::StaticAverageHistogram(
333 const AnalysisHistogramSettings &settings)
334 : AbstractAverageHistogram(settings)
339 /********************************************************************
340 * BasicAverageHistogramModule
343 BasicAverageHistogramModule::BasicAverageHistogramModule()
350 BasicAverageHistogramModule::BasicAverageHistogramModule(
351 const AnalysisHistogramSettings &settings)
352 : AbstractAverageHistogram(settings), frameCount_(0)
359 BasicAverageHistogramModule::flags() const
361 return efAllowMulticolumn;
366 BasicAverageHistogramModule::dataStarted(AbstractAnalysisData *data)
368 GMX_RELEASE_ASSERT(rowCount() == data->columnCount(),
369 "Inconsistent data sizes, something is wrong in the initialization");
375 BasicAverageHistogramModule::frameStarted(const AnalysisDataFrameHeader & /*header*/)
381 BasicAverageHistogramModule::pointsAdded(const AnalysisDataPointSetRef &points)
383 int firstcol = points.firstColumn();
384 for (int i = 0; i < points.columnCount(); ++i)
386 real y = points.y(i);
387 value(firstcol + i, 0) += y;
388 value(firstcol + i, 1) += y * y;
394 BasicAverageHistogramModule::frameFinished(const AnalysisDataFrameHeader & /*header*/)
401 BasicAverageHistogramModule::dataFinished()
403 for (int i = 0; i < rowCount(); ++i)
405 real ave = value(i, 0) / frameCount_;
406 real std = sqrt(value(i, 1) / frameCount_ - ave * ave);
413 /********************************************************************
417 BasicHistogramImpl::BasicHistogramImpl()
418 : averager_(new BasicAverageHistogramModule())
423 BasicHistogramImpl::BasicHistogramImpl(const AnalysisHistogramSettings &settings)
424 : settings_(settings), averager_(new BasicAverageHistogramModule(settings))
429 BasicHistogramImpl::~BasicHistogramImpl()
434 void BasicHistogramImpl::init(const AnalysisHistogramSettings &settings)
436 settings_ = settings;
437 averager_->init(settings);
442 BasicHistogramImpl::initFrame(AnalysisDataStorageFrame *frame)
444 for (int i = 0; i < frame->columnCount(); ++i)
446 frame->setValue(i, 0.0);
450 } // namespace internal
453 /********************************************************************
454 * AnalysisDataSimpleHistogramModule
457 AnalysisDataSimpleHistogramModule::AnalysisDataSimpleHistogramModule()
458 : impl_(new internal::BasicHistogramImpl())
463 AnalysisDataSimpleHistogramModule::AnalysisDataSimpleHistogramModule(
464 const AnalysisHistogramSettings &settings)
465 : impl_(new internal::BasicHistogramImpl(settings))
470 AnalysisDataSimpleHistogramModule::~AnalysisDataSimpleHistogramModule()
475 void AnalysisDataSimpleHistogramModule::init(const AnalysisHistogramSettings &settings)
477 impl_->init(settings);
481 AbstractAverageHistogram &
482 AnalysisDataSimpleHistogramModule::averager()
484 return *impl_->averager_;
488 const AnalysisHistogramSettings &
489 AnalysisDataSimpleHistogramModule::settings() const
491 return impl_->settings_;
496 AnalysisDataSimpleHistogramModule::flags() const
498 return efAllowMulticolumn | efAllowMultipoint;
503 AnalysisDataSimpleHistogramModule::dataStarted(AbstractAnalysisData *data)
505 addModule(impl_->averager_);
506 setColumnCount(settings().binCount());
508 impl_->storage_.startDataStorage(this);
513 AnalysisDataSimpleHistogramModule::frameStarted(const AnalysisDataFrameHeader &header)
515 AnalysisDataStorageFrame &frame = impl_->storage_.startFrame(header);
516 impl_->initFrame(&frame);
521 AnalysisDataSimpleHistogramModule::pointsAdded(const AnalysisDataPointSetRef &points)
523 AnalysisDataStorageFrame &frame =
524 impl_->storage_.currentFrame(points.frameIndex());
525 for (int i = 0; i < points.columnCount(); ++i)
527 int bin = settings().findBin(points.y(i));
530 frame.value(bin) += 1;
537 AnalysisDataSimpleHistogramModule::frameFinished(const AnalysisDataFrameHeader &header)
539 impl_->storage_.finishFrame(header.index());
544 AnalysisDataSimpleHistogramModule::dataFinished()
551 AnalysisDataSimpleHistogramModule::tryGetDataFrameInternal(int index) const
553 return impl_->storage_.tryGetDataFrame(index);
558 AnalysisDataSimpleHistogramModule::requestStorageInternal(int nframes)
560 return impl_->storage_.requestStorage(nframes);
564 /********************************************************************
565 * AnalysisDataWeightedHistogramModule
568 AnalysisDataWeightedHistogramModule::AnalysisDataWeightedHistogramModule()
569 : impl_(new internal::BasicHistogramImpl())
574 AnalysisDataWeightedHistogramModule::AnalysisDataWeightedHistogramModule(
575 const AnalysisHistogramSettings &settings)
576 : impl_(new internal::BasicHistogramImpl(settings))
581 AnalysisDataWeightedHistogramModule::~AnalysisDataWeightedHistogramModule()
586 void AnalysisDataWeightedHistogramModule::init(const AnalysisHistogramSettings &settings)
588 impl_->init(settings);
592 AbstractAverageHistogram &
593 AnalysisDataWeightedHistogramModule::averager()
595 return *impl_->averager_;
599 const AnalysisHistogramSettings &
600 AnalysisDataWeightedHistogramModule::settings() const
602 return impl_->settings_;
607 AnalysisDataWeightedHistogramModule::flags() const
609 return efAllowMulticolumn | efAllowMultipoint;
614 AnalysisDataWeightedHistogramModule::dataStarted(AbstractAnalysisData *data)
616 addModule(impl_->averager_);
617 setColumnCount(settings().binCount());
619 impl_->storage_.startDataStorage(this);
624 AnalysisDataWeightedHistogramModule::frameStarted(const AnalysisDataFrameHeader &header)
626 AnalysisDataStorageFrame &frame = impl_->storage_.startFrame(header);
627 impl_->initFrame(&frame);
632 AnalysisDataWeightedHistogramModule::pointsAdded(const AnalysisDataPointSetRef &points)
634 if (points.firstColumn() != 0 || points.columnCount() < 2)
636 GMX_THROW(APIError("Invalid data layout"));
638 int bin = settings().findBin(points.y(0));
641 AnalysisDataStorageFrame &frame =
642 impl_->storage_.currentFrame(points.frameIndex());
643 for (int i = 1; i < points.columnCount(); ++i)
645 frame.value(bin) += points.y(i);
652 AnalysisDataWeightedHistogramModule::frameFinished(const AnalysisDataFrameHeader &header)
654 impl_->storage_.finishFrame(header.index());
659 AnalysisDataWeightedHistogramModule::dataFinished()
666 AnalysisDataWeightedHistogramModule::tryGetDataFrameInternal(int index) const
668 return impl_->storage_.tryGetDataFrame(index);
673 AnalysisDataWeightedHistogramModule::requestStorageInternal(int nframes)
675 return impl_->storage_.requestStorage(nframes);
679 /********************************************************************
680 * AnalysisDataBinAverageModule
683 AnalysisDataBinAverageModule::AnalysisDataBinAverageModule()
689 AnalysisDataBinAverageModule::AnalysisDataBinAverageModule(
690 const AnalysisHistogramSettings &settings)
691 : settings_(settings)
694 setRowCount(settings.binCount());
695 setXAxis(settings.firstEdge() + 0.5 * settings.binWidth(),
696 settings.binWidth());
700 AnalysisDataBinAverageModule::~AnalysisDataBinAverageModule()
706 AnalysisDataBinAverageModule::init(const AnalysisHistogramSettings &settings)
708 settings_ = settings;
709 setRowCount(settings.binCount());
710 setXAxis(settings.firstEdge() + 0.5 * settings.binWidth(),
711 settings.binWidth());
716 AnalysisDataBinAverageModule::flags() const
718 return efAllowMulticolumn | efAllowMultipoint;
723 AnalysisDataBinAverageModule::dataStarted(AbstractAnalysisData * /*data*/)
730 AnalysisDataBinAverageModule::frameStarted(const AnalysisDataFrameHeader & /*header*/)
736 AnalysisDataBinAverageModule::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 for (int i = 1; i < points.columnCount(); ++i)
747 real y = points.y(i);
749 value(bin, 1) += y * y;
751 value(bin, 2) += points.columnCount() - 1;
757 AnalysisDataBinAverageModule::frameFinished(const AnalysisDataFrameHeader & /*header*/)
763 AnalysisDataBinAverageModule::dataFinished()
765 for (int i = 0; i < settings().binCount(); ++i)
767 real n = value(i, 2);
770 real ave = value(i, 0) / n;
771 real std = sqrt(value(i, 1) / n - ave * ave);