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/basicmath.h"
45 #include "gromacs/analysisdata/dataframe.h"
46 #include "gromacs/analysisdata/datastorage.h"
47 #include "gromacs/fatalerror/exceptions.h"
48 #include "gromacs/fatalerror/gmxassert.h"
50 #include "histogram-impl.h"
52 static const real UNDEFINED = std::numeric_limits<real>::max();
53 static bool isDefined(real value)
55 return value != UNDEFINED;
61 /********************************************************************
62 * AnalysisHistogramSettingsInitializer
65 AnalysisHistogramSettingsInitializer::AnalysisHistogramSettingsInitializer()
66 : min_(UNDEFINED), max_(UNDEFINED), binWidth_(UNDEFINED),
67 binCount_(0), bIntegerBins_(false), bRoundRange_(false),
73 /********************************************************************
74 * AnalysisHistogramSettings
77 AnalysisHistogramSettings::AnalysisHistogramSettings()
78 : firstEdge_(0.0), lastEdge_(0.0), binWidth_(0.0), inverseBinWidth_(0.0),
79 binCount_(0), bAll_(false)
84 AnalysisHistogramSettings::AnalysisHistogramSettings(
85 const AnalysisHistogramSettingsInitializer &settings)
87 GMX_RELEASE_ASSERT(isDefined(settings.min_),
88 "Histogram start value must be defined");
89 GMX_RELEASE_ASSERT(!isDefined(settings.max_) || settings.max_ > settings.min_,
90 "Histogram end value must be larger than start value");
91 GMX_RELEASE_ASSERT(!isDefined(settings.binWidth_) || settings.binWidth_ > 0.0,
92 "Histogram bin width must be positive");
93 GMX_RELEASE_ASSERT(settings.binCount_ >= 0,
94 "Histogram bin count must be positive");
96 if (!isDefined(settings.max_))
98 GMX_RELEASE_ASSERT(isDefined(settings.binWidth_) && settings.binCount_ > 0,
99 "Not all required values provided");
100 GMX_RELEASE_ASSERT(!settings.bRoundRange_,
101 "Rounding only supported for min/max ranges");
103 firstEdge_ = settings.min_;
104 binCount_ = settings.binCount_;
105 binWidth_ = settings.binWidth_;
106 if (settings.bIntegerBins_)
108 firstEdge_ -= 0.5 * binWidth_;
110 lastEdge_ = firstEdge_ + binCount_ * binWidth_;
114 GMX_RELEASE_ASSERT(!(isDefined(settings.binWidth_) && settings.binCount_ > 0),
115 "Conflicting histogram bin specifications");
116 GMX_RELEASE_ASSERT(isDefined(settings.binWidth_) || settings.binCount_ > 0,
117 "Not all required values provided");
119 if (settings.bRoundRange_)
121 GMX_RELEASE_ASSERT(!settings.bIntegerBins_,
122 "Rounding and integer bins cannot be combined");
123 GMX_RELEASE_ASSERT(isDefined(settings.binWidth_),
124 "Rounding only makes sense with defined binwidth");
125 binWidth_ = settings.binWidth_;
126 firstEdge_ = binWidth_ * floor(settings.min_ / binWidth_);
127 lastEdge_ = binWidth_ * ceil(settings.max_ / binWidth_);
128 binCount_ = static_cast<int>((lastEdge_ - firstEdge_) / binWidth_ + 0.5);
132 firstEdge_ = settings.min_;
133 lastEdge_ = settings.max_;
134 if (settings.binCount_ > 0)
136 binCount_ = settings.binCount_;
137 if (settings.bIntegerBins_)
139 GMX_RELEASE_ASSERT(settings.binCount_ > 1,
140 "Bin count must be at least two with integer bins");
141 binWidth_ = (lastEdge_ - firstEdge_) / (binCount_ - 1);
142 firstEdge_ -= 0.5 * binWidth_;
143 lastEdge_ += 0.5 * binWidth_;
147 binWidth_ = (lastEdge_ - firstEdge_) / binCount_;
152 binWidth_ = settings.binWidth_;
153 binCount_ = static_cast<int>((lastEdge_ - firstEdge_) / binWidth_ + 0.5);
154 if (settings.bIntegerBins_)
156 firstEdge_ -= 0.5 * binWidth_;
159 lastEdge_ = firstEdge_ + binCount_ * binWidth_;
164 inverseBinWidth_ = 1.0 / binWidth_;
165 bAll_ = settings.bIncludeAll_;
170 AnalysisHistogramSettings::findBin(real y) const
174 return bAll_ ? 0 : -1;
176 int bin = static_cast<int>((y - firstEdge_) * inverseBinWidth_);
177 if (bin >= binCount_)
179 return bAll_ ? binCount_ - 1 : -1;
185 /********************************************************************
186 * AbstractAverageHistogram
189 AbstractAverageHistogram::AbstractAverageHistogram()
194 AbstractAverageHistogram::AbstractAverageHistogram(
195 const AnalysisHistogramSettings &settings)
196 : settings_(settings)
198 setRowCount(settings.binCount());
199 setXAxis(settings.firstEdge() + 0.5 * settings.binWidth(),
200 settings.binWidth());
204 AbstractAverageHistogram::~AbstractAverageHistogram()
210 AbstractAverageHistogram::init(const AnalysisHistogramSettings &settings)
212 settings_ = settings;
213 setRowCount(settings.binCount());
214 setXAxis(settings.firstEdge() + 0.5 * settings.binWidth(),
215 settings.binWidth());
219 AverageHistogramPointer
220 AbstractAverageHistogram::resampleDoubleBinWidth(bool bIntegerBins) const
225 nbins = (rowCount() + 1) / 2;
229 nbins = rowCount() / 2;
232 real minx = xstart();
233 AverageHistogramPointer dest(
234 new internal::StaticAverageHistogram(
235 histogramFromBins(xstart(), nbins, 2*xstep())
236 .integerBins(bIntegerBins)));
237 dest->setColumnCount(columnCount());
238 dest->allocateValues();
241 for (i = j = 0; i < nbins; ++i)
243 const bool bFirstHalfBin = (bIntegerBins && i == 0);
244 for (int c = 0; c < columnCount(); ++c)
255 v2 = value(j + 1, c);
259 dest->setValue(i, c, sqrt(v1 * v1 + v2 * v2));
263 dest->setValue(i, c, v1 + v2);
279 AverageHistogramPointer
280 AbstractAverageHistogram::clone() const
282 AverageHistogramPointer dest(new internal::StaticAverageHistogram());
283 copyContents(this, dest.get());
289 AbstractAverageHistogram::normalizeProbability()
292 for (int i = 0; i < rowCount(); ++i)
296 scale(1.0 / (sum * xstep()));
301 AbstractAverageHistogram::scale(real norm)
303 for (int i = 0; i < rowCount(); ++i)
312 AbstractAverageHistogram::scaleVector(real norm[])
314 for (int i = 0; i < rowCount(); ++i)
316 value(i, 0) *= norm[i];
317 value(i, 1) *= norm[i];
322 /********************************************************************
323 * StaticAverageHistogram
329 StaticAverageHistogram::StaticAverageHistogram()
334 StaticAverageHistogram::StaticAverageHistogram(
335 const AnalysisHistogramSettings &settings)
336 : AbstractAverageHistogram(settings)
341 /********************************************************************
342 * BasicAverageHistogramModule
345 BasicAverageHistogramModule::BasicAverageHistogramModule()
352 BasicAverageHistogramModule::BasicAverageHistogramModule(
353 const AnalysisHistogramSettings &settings)
354 : AbstractAverageHistogram(settings), frameCount_(0)
361 BasicAverageHistogramModule::flags() const
363 return efAllowMulticolumn;
368 BasicAverageHistogramModule::dataStarted(AbstractAnalysisData *data)
370 GMX_RELEASE_ASSERT(rowCount() == data->columnCount(),
371 "Inconsistent data sizes, something is wrong in the initialization");
377 BasicAverageHistogramModule::frameStarted(const AnalysisDataFrameHeader & /*header*/)
383 BasicAverageHistogramModule::pointsAdded(const AnalysisDataPointSetRef &points)
385 int firstcol = points.firstColumn();
386 for (int i = 0; i < points.columnCount(); ++i)
388 real y = points.y(i);
389 value(firstcol + i, 0) += y;
390 value(firstcol + i, 1) += y * y;
396 BasicAverageHistogramModule::frameFinished(const AnalysisDataFrameHeader & /*header*/)
403 BasicAverageHistogramModule::dataFinished()
405 for (int i = 0; i < rowCount(); ++i)
407 real ave = value(i, 0) / frameCount_;
408 real std = sqrt(value(i, 1) / frameCount_ - ave * ave);
415 /********************************************************************
419 BasicHistogramImpl::BasicHistogramImpl()
420 : averager_(new BasicAverageHistogramModule())
425 BasicHistogramImpl::BasicHistogramImpl(const AnalysisHistogramSettings &settings)
426 : settings_(settings), averager_(new BasicAverageHistogramModule(settings))
431 BasicHistogramImpl::~BasicHistogramImpl()
436 void BasicHistogramImpl::init(const AnalysisHistogramSettings &settings)
438 settings_ = settings;
439 averager_->init(settings);
444 BasicHistogramImpl::initFrame(AnalysisDataStorageFrame *frame)
446 for (int i = 0; i < frame->columnCount(); ++i)
448 frame->setValue(i, 0.0);
452 } // namespace internal
455 /********************************************************************
456 * AnalysisDataSimpleHistogramModule
459 AnalysisDataSimpleHistogramModule::AnalysisDataSimpleHistogramModule()
460 : impl_(new internal::BasicHistogramImpl())
465 AnalysisDataSimpleHistogramModule::AnalysisDataSimpleHistogramModule(
466 const AnalysisHistogramSettings &settings)
467 : impl_(new internal::BasicHistogramImpl(settings))
472 AnalysisDataSimpleHistogramModule::~AnalysisDataSimpleHistogramModule()
477 void AnalysisDataSimpleHistogramModule::init(const AnalysisHistogramSettings &settings)
479 impl_->init(settings);
483 AbstractAverageHistogram &
484 AnalysisDataSimpleHistogramModule::averager()
486 return *impl_->averager_;
490 const AnalysisHistogramSettings &
491 AnalysisDataSimpleHistogramModule::settings() const
493 return impl_->settings_;
498 AnalysisDataSimpleHistogramModule::flags() const
500 return efAllowMulticolumn | efAllowMultipoint;
505 AnalysisDataSimpleHistogramModule::dataStarted(AbstractAnalysisData *data)
507 addModule(impl_->averager_);
508 setColumnCount(settings().binCount());
510 impl_->storage_.startDataStorage(this);
515 AnalysisDataSimpleHistogramModule::frameStarted(const AnalysisDataFrameHeader &header)
517 AnalysisDataStorageFrame &frame = impl_->storage_.startFrame(header);
518 impl_->initFrame(&frame);
523 AnalysisDataSimpleHistogramModule::pointsAdded(const AnalysisDataPointSetRef &points)
525 AnalysisDataStorageFrame &frame =
526 impl_->storage_.currentFrame(points.frameIndex());
527 for (int i = 0; i < points.columnCount(); ++i)
529 int bin = settings().findBin(points.y(i));
532 frame.value(bin) += 1;
539 AnalysisDataSimpleHistogramModule::frameFinished(const AnalysisDataFrameHeader &header)
541 impl_->storage_.finishFrame(header.index());
546 AnalysisDataSimpleHistogramModule::dataFinished()
553 AnalysisDataSimpleHistogramModule::tryGetDataFrameInternal(int index) const
555 return impl_->storage_.tryGetDataFrame(index);
560 AnalysisDataSimpleHistogramModule::requestStorageInternal(int nframes)
562 return impl_->storage_.requestStorage(nframes);
566 /********************************************************************
567 * AnalysisDataWeightedHistogramModule
570 AnalysisDataWeightedHistogramModule::AnalysisDataWeightedHistogramModule()
571 : impl_(new internal::BasicHistogramImpl())
576 AnalysisDataWeightedHistogramModule::AnalysisDataWeightedHistogramModule(
577 const AnalysisHistogramSettings &settings)
578 : impl_(new internal::BasicHistogramImpl(settings))
583 AnalysisDataWeightedHistogramModule::~AnalysisDataWeightedHistogramModule()
588 void AnalysisDataWeightedHistogramModule::init(const AnalysisHistogramSettings &settings)
590 impl_->init(settings);
594 AbstractAverageHistogram &
595 AnalysisDataWeightedHistogramModule::averager()
597 return *impl_->averager_;
601 const AnalysisHistogramSettings &
602 AnalysisDataWeightedHistogramModule::settings() const
604 return impl_->settings_;
609 AnalysisDataWeightedHistogramModule::flags() const
611 return efAllowMulticolumn | efAllowMultipoint;
616 AnalysisDataWeightedHistogramModule::dataStarted(AbstractAnalysisData *data)
618 addModule(impl_->averager_);
619 setColumnCount(settings().binCount());
621 impl_->storage_.startDataStorage(this);
626 AnalysisDataWeightedHistogramModule::frameStarted(const AnalysisDataFrameHeader &header)
628 AnalysisDataStorageFrame &frame = impl_->storage_.startFrame(header);
629 impl_->initFrame(&frame);
634 AnalysisDataWeightedHistogramModule::pointsAdded(const AnalysisDataPointSetRef &points)
636 if (points.firstColumn() != 0 || points.columnCount() < 2)
638 GMX_THROW(APIError("Invalid data layout"));
640 int bin = settings().findBin(points.y(0));
643 AnalysisDataStorageFrame &frame =
644 impl_->storage_.currentFrame(points.frameIndex());
645 for (int i = 1; i < points.columnCount(); ++i)
647 frame.value(bin) += points.y(i);
654 AnalysisDataWeightedHistogramModule::frameFinished(const AnalysisDataFrameHeader &header)
656 impl_->storage_.finishFrame(header.index());
661 AnalysisDataWeightedHistogramModule::dataFinished()
668 AnalysisDataWeightedHistogramModule::tryGetDataFrameInternal(int index) const
670 return impl_->storage_.tryGetDataFrame(index);
675 AnalysisDataWeightedHistogramModule::requestStorageInternal(int nframes)
677 return impl_->storage_.requestStorage(nframes);
681 /********************************************************************
682 * AnalysisDataBinAverageModule
685 AnalysisDataBinAverageModule::AnalysisDataBinAverageModule()
691 AnalysisDataBinAverageModule::AnalysisDataBinAverageModule(
692 const AnalysisHistogramSettings &settings)
693 : settings_(settings)
696 setRowCount(settings.binCount());
697 setXAxis(settings.firstEdge() + 0.5 * settings.binWidth(),
698 settings.binWidth());
702 AnalysisDataBinAverageModule::~AnalysisDataBinAverageModule()
708 AnalysisDataBinAverageModule::init(const AnalysisHistogramSettings &settings)
710 settings_ = settings;
711 setRowCount(settings.binCount());
712 setXAxis(settings.firstEdge() + 0.5 * settings.binWidth(),
713 settings.binWidth());
718 AnalysisDataBinAverageModule::flags() const
720 return efAllowMulticolumn | efAllowMultipoint;
725 AnalysisDataBinAverageModule::dataStarted(AbstractAnalysisData * /*data*/)
732 AnalysisDataBinAverageModule::frameStarted(const AnalysisDataFrameHeader & /*header*/)
738 AnalysisDataBinAverageModule::pointsAdded(const AnalysisDataPointSetRef &points)
740 if (points.firstColumn() != 0 || points.columnCount() < 2)
742 GMX_THROW(APIError("Invalid data layout"));
744 int bin = settings().findBin(points.y(0));
747 for (int i = 1; i < points.columnCount(); ++i)
749 real y = points.y(i);
751 value(bin, 1) += y * y;
753 value(bin, 2) += points.columnCount() - 1;
759 AnalysisDataBinAverageModule::frameFinished(const AnalysisDataFrameHeader & /*header*/)
765 AnalysisDataBinAverageModule::dataFinished()
767 for (int i = 0; i < settings().binCount(); ++i)
769 real n = value(i, 2);
772 real ave = value(i, 0) / n;
773 real std = sqrt(value(i, 1) / n - ave * ave);