2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2010,2011,2012,2013,2014 by the GROMACS development team.
5 * Copyright (c) 2015,2018,2019,2020, by the GROMACS development team, led by
6 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
7 * and including many others, as listed in the AUTHORS file in the
8 * top-level source directory and at http://www.gromacs.org.
10 * GROMACS is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public License
12 * as published by the Free Software Foundation; either version 2.1
13 * of the License, or (at your option) any later version.
15 * GROMACS is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with GROMACS; if not, see
22 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
23 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 * If you want to redistribute modifications to GROMACS, please
26 * consider that scientific software is very special. Version
27 * control is crucial - bugs must be traceable. We will be happy to
28 * consider code for inclusion in the official distribution, but
29 * derived work must not be called official GROMACS. Details are found
30 * in the README & COPYING files - if they are missing, get the
31 * official version at http://www.gromacs.org.
33 * To help us fund GROMACS development, we humbly ask that you cite
34 * the research papers on the package. Check out http://www.gromacs.org.
38 * Implements classes in histogram.h.
40 * \author Teemu Murtola <teemu.murtola@gmail.com>
41 * \ingroup module_analysisdata
45 #include "histogram.h"
52 #include "gromacs/analysisdata/dataframe.h"
53 #include "gromacs/analysisdata/datastorage.h"
54 #include "gromacs/analysisdata/framelocaldata.h"
55 #include "gromacs/math/functions.h"
56 #include "gromacs/utility/basedefinitions.h"
57 #include "gromacs/utility/exceptions.h"
58 #include "gromacs/utility/gmxassert.h"
60 #include "frameaverager.h"
65 //! Value used to signify that a real-valued histogram setting is not set.
66 const real UNDEFINED = std::numeric_limits<real>::max();
67 //! Checks whether \p value is defined.
68 bool isDefined(real value)
70 return value != UNDEFINED;
78 /********************************************************************
79 * AnalysisHistogramSettingsInitializer
82 AnalysisHistogramSettingsInitializer::AnalysisHistogramSettingsInitializer() :
94 /********************************************************************
95 * AnalysisHistogramSettings
98 AnalysisHistogramSettings::AnalysisHistogramSettings() :
102 inverseBinWidth_(0.0),
109 AnalysisHistogramSettings::AnalysisHistogramSettings(const AnalysisHistogramSettingsInitializer& settings)
111 GMX_RELEASE_ASSERT(isDefined(settings.min_), "Histogram start value must be defined");
112 GMX_RELEASE_ASSERT(!isDefined(settings.max_) || settings.max_ > settings.min_,
113 "Histogram end value must be larger than start value");
114 GMX_RELEASE_ASSERT(!isDefined(settings.binWidth_) || settings.binWidth_ > 0.0,
115 "Histogram bin width must be positive");
116 GMX_RELEASE_ASSERT(settings.binCount_ >= 0, "Histogram bin count must be positive");
118 if (!isDefined(settings.max_))
120 GMX_RELEASE_ASSERT(isDefined(settings.binWidth_) && settings.binCount_ > 0,
121 "Not all required values provided");
122 GMX_RELEASE_ASSERT(!settings.bRoundRange_, "Rounding only supported for min/max ranges");
124 firstEdge_ = settings.min_;
125 binCount_ = settings.binCount_;
126 binWidth_ = settings.binWidth_;
127 if (settings.bIntegerBins_)
129 firstEdge_ -= 0.5 * binWidth_;
131 lastEdge_ = firstEdge_ + binCount_ * binWidth_;
135 GMX_RELEASE_ASSERT(!(isDefined(settings.binWidth_) && settings.binCount_ > 0),
136 "Conflicting histogram bin specifications");
137 GMX_RELEASE_ASSERT(isDefined(settings.binWidth_) || settings.binCount_ > 0,
138 "Not all required values provided");
140 if (settings.bRoundRange_)
142 GMX_RELEASE_ASSERT(!settings.bIntegerBins_,
143 "Rounding and integer bins cannot be combined");
144 GMX_RELEASE_ASSERT(isDefined(settings.binWidth_),
145 "Rounding only makes sense with defined binwidth");
146 binWidth_ = settings.binWidth_;
147 firstEdge_ = binWidth_ * std::floor(settings.min_ / binWidth_);
148 lastEdge_ = binWidth_ * std::ceil(settings.max_ / binWidth_);
149 binCount_ = gmx::roundToInt((lastEdge_ - firstEdge_) / binWidth_);
153 firstEdge_ = settings.min_;
154 lastEdge_ = settings.max_;
155 if (settings.binCount_ > 0)
157 binCount_ = settings.binCount_;
158 if (settings.bIntegerBins_)
160 GMX_RELEASE_ASSERT(settings.binCount_ > 1,
161 "Bin count must be at least two with integer bins");
162 binWidth_ = (lastEdge_ - firstEdge_) / (binCount_ - 1);
163 firstEdge_ -= 0.5 * binWidth_;
164 lastEdge_ += 0.5 * binWidth_;
168 binWidth_ = (lastEdge_ - firstEdge_) / binCount_;
173 binWidth_ = settings.binWidth_;
174 binCount_ = gmx::roundToInt((lastEdge_ - firstEdge_) / binWidth_);
175 if (settings.bIntegerBins_)
177 firstEdge_ -= 0.5 * binWidth_;
180 lastEdge_ = firstEdge_ + binCount_ * binWidth_;
185 inverseBinWidth_ = 1.0 / binWidth_;
186 bAll_ = settings.bIncludeAll_;
190 int AnalysisHistogramSettings::findBin(real y) const
194 return bAll_ ? 0 : -1;
196 int bin = static_cast<int>((y - firstEdge_) * inverseBinWidth_);
197 if (bin >= binCount_)
199 return bAll_ ? binCount_ - 1 : -1;
205 /********************************************************************
206 * StaticAverageHistogram
213 * Represents copies of average histograms.
215 * Methods in AbstractAverageHistogram that return new histogram instances
216 * return objects of this class.
217 * Initialization of values is handled in those methods.
219 * \ingroup module_analysisdata
221 class StaticAverageHistogram : public AbstractAverageHistogram
224 StaticAverageHistogram();
225 //! Creates an average histogram module with defined bin parameters.
226 explicit StaticAverageHistogram(const AnalysisHistogramSettings& settings);
228 // Copy and assign disallowed by base.
231 StaticAverageHistogram::StaticAverageHistogram() {}
234 StaticAverageHistogram::StaticAverageHistogram(const AnalysisHistogramSettings& settings) :
235 AbstractAverageHistogram(settings)
242 /********************************************************************
243 * AbstractAverageHistogram
246 AbstractAverageHistogram::AbstractAverageHistogram() {}
249 AbstractAverageHistogram::AbstractAverageHistogram(const AnalysisHistogramSettings& settings) :
252 setRowCount(settings.binCount());
253 setXAxis(settings.firstEdge() + 0.5 * settings.binWidth(), settings.binWidth());
257 AbstractAverageHistogram::~AbstractAverageHistogram() {}
260 void AbstractAverageHistogram::init(const AnalysisHistogramSettings& settings)
262 settings_ = settings;
263 setRowCount(settings.binCount());
264 setXAxis(settings.firstEdge() + 0.5 * settings.binWidth(), settings.binWidth());
268 AverageHistogramPointer AbstractAverageHistogram::resampleDoubleBinWidth(bool bIntegerBins) const
273 nbins = (rowCount() + 1) / 2;
277 nbins = rowCount() / 2;
280 AverageHistogramPointer dest(new StaticAverageHistogram(
281 histogramFromBins(settings().firstEdge(), nbins, 2 * xstep()).integerBins(bIntegerBins)));
282 dest->setColumnCount(columnCount());
283 dest->allocateValues();
286 for (i = j = 0; i < nbins; ++i)
288 const bool bFirstHalfBin = (bIntegerBins && i == 0);
289 for (int c = 0; c < columnCount(); ++c)
295 v1 = value(0, c).value();
296 e1 = value(0, c).error();
302 v1 = value(j, c).value();
303 e1 = value(j, c).error();
304 v2 = value(j + 1, c).value();
305 e2 = value(j + 1, c).error();
307 dest->value(i, c).setValue(v1 + v2, std::sqrt(e1 * e1 + e2 * e2));
322 AverageHistogramPointer AbstractAverageHistogram::clone() const
324 AverageHistogramPointer dest(new StaticAverageHistogram());
325 copyContents(this, dest.get());
326 dest->settings_ = settings_;
331 void AbstractAverageHistogram::normalizeProbability()
333 for (int c = 0; c < columnCount(); ++c)
336 for (int i = 0; i < rowCount(); ++i)
338 sum += value(i, c).value();
342 scaleSingle(c, 1.0 / (sum * xstep()));
347 void AbstractAverageHistogram::makeCumulative()
349 for (int c = 0; c < columnCount(); ++c)
352 for (int i = 0; i < rowCount(); ++i)
354 sum += value(i, c).value();
355 // Clear the error, as we don't cumulate that.
357 value(i, c).setValue(sum);
360 setXAxis(settings().firstEdge() + settings().binWidth(), settings().binWidth());
364 void AbstractAverageHistogram::scaleSingle(int index, real factor)
366 for (int i = 0; i < rowCount(); ++i)
368 value(i, index).value() *= factor;
369 value(i, index).error() *= factor;
374 void AbstractAverageHistogram::scaleAll(real factor)
376 for (int i = 0; i < columnCount(); ++i)
378 scaleSingle(i, factor);
383 void AbstractAverageHistogram::scaleAllByVector(const real factor[])
385 for (int c = 0; c < columnCount(); ++c)
387 for (int i = 0; i < rowCount(); ++i)
389 value(i, c).value() *= factor[i];
390 value(i, c).error() *= factor[i];
396 /********************************************************************
397 * BasicAverageHistogramModule
405 * Implements average histogram module that averages per-frame histograms.
407 * This class is used for accumulating average histograms in per-frame
408 * histogram modules (those that use BasicHistogramImpl as their implementation
410 * There are two columns, first for the average and second for standard
413 * \ingroup module_analysisdata
415 class BasicAverageHistogramModule : public AbstractAverageHistogram, public AnalysisDataModuleSerial
418 BasicAverageHistogramModule();
419 //! Creates an average histogram module with defined bin parameters.
420 explicit BasicAverageHistogramModule(const AnalysisHistogramSettings& settings);
422 using AbstractAverageHistogram::init;
424 int flags() const override;
426 void dataStarted(AbstractAnalysisData* data) override;
427 void frameStarted(const AnalysisDataFrameHeader& header) override;
428 void pointsAdded(const AnalysisDataPointSetRef& points) override;
429 void frameFinished(const AnalysisDataFrameHeader& header) override;
430 void dataFinished() override;
433 //! Averaging helper objects for each input data set.
434 std::vector<AnalysisDataFrameAverager> averagers_;
436 // Copy and assign disallowed by base.
439 BasicAverageHistogramModule::BasicAverageHistogramModule() {}
442 BasicAverageHistogramModule::BasicAverageHistogramModule(const AnalysisHistogramSettings& settings) :
443 AbstractAverageHistogram(settings)
448 int BasicAverageHistogramModule::flags() const
450 return efAllowMulticolumn | efAllowMultipleDataSets;
454 void BasicAverageHistogramModule::dataStarted(AbstractAnalysisData* data)
456 setColumnCount(data->dataSetCount());
457 averagers_.resize(data->dataSetCount());
458 for (int i = 0; i < data->dataSetCount(); ++i)
460 GMX_RELEASE_ASSERT(rowCount() == data->columnCount(i),
461 "Inconsistent data sizes, something is wrong in the initialization");
462 averagers_[i].setColumnCount(data->columnCount(i));
467 void BasicAverageHistogramModule::frameStarted(const AnalysisDataFrameHeader& /*header*/) {}
470 void BasicAverageHistogramModule::pointsAdded(const AnalysisDataPointSetRef& points)
472 averagers_[points.dataSetIndex()].addPoints(points);
476 void BasicAverageHistogramModule::frameFinished(const AnalysisDataFrameHeader& /*header*/) {}
479 void BasicAverageHistogramModule::dataFinished()
482 for (int i = 0; i < columnCount(); ++i)
484 averagers_[i].finish();
485 for (int j = 0; j < rowCount(); ++j)
487 value(j, i).setValue(averagers_[i].average(j), std::sqrt(averagers_[i].variance(j)));
493 /********************************************************************
499 * Base class for private implementation classes for histogram modules.
501 * Actual implementation classes are derived from this and add an accumulation
502 * data member that is specific to the histogram type in question.
503 * This is done like this to keep implementation details out of the header, and
504 * to not unnecessarily duplicate code.
506 * \ingroup module_analysisdata
508 class BasicHistogramImpl
511 //! Smart pointer to manage an BasicAverageHistogramModule object.
512 typedef std::shared_ptr<BasicAverageHistogramModule> BasicAverageHistogramModulePointer;
514 BasicHistogramImpl();
515 //! Creates an histogram impl with defined bin parameters.
516 explicit BasicHistogramImpl(const AnalysisHistogramSettings& settings);
517 // Virtual only for simplicity.
518 virtual ~BasicHistogramImpl();
521 * (Re)initializes the histogram from settings.
523 void init(const AnalysisHistogramSettings& settings);
525 //! Storage implementation object.
526 AnalysisDataStorage storage_;
527 //! Settings for the histogram object.
528 AnalysisHistogramSettings settings_;
530 BasicAverageHistogramModulePointer averager_;
533 BasicHistogramImpl::BasicHistogramImpl() : averager_(new BasicAverageHistogramModule()) {}
536 BasicHistogramImpl::BasicHistogramImpl(const AnalysisHistogramSettings& settings) :
538 averager_(new BasicAverageHistogramModule(settings))
543 BasicHistogramImpl::~BasicHistogramImpl() {}
546 void BasicHistogramImpl::init(const AnalysisHistogramSettings& settings)
548 settings_ = settings;
549 averager_->init(settings);
552 } // namespace internal
555 /********************************************************************
556 * AnalysisDataSimpleHistogramModule
560 * Private implementation class for AnalysisDataSimpleHistogramModule.
562 * \ingroup module_analysisdata
564 class AnalysisDataSimpleHistogramModule::Impl : public internal::BasicHistogramImpl
567 //! Shorthand for the per-frame accumulation data structure type.
568 typedef AnalysisDataFrameLocalData<int64_t> FrameLocalData;
571 //! Creates an histogram impl with defined bin parameters.
572 explicit Impl(const AnalysisHistogramSettings& settings) : BasicHistogramImpl(settings) {}
574 //! Accumulates the histogram within a frame.
575 FrameLocalData accumulator_;
578 AnalysisDataSimpleHistogramModule::AnalysisDataSimpleHistogramModule() : impl_(new Impl()) {}
581 AnalysisDataSimpleHistogramModule::AnalysisDataSimpleHistogramModule(const AnalysisHistogramSettings& settings) :
582 impl_(new Impl(settings))
587 AnalysisDataSimpleHistogramModule::~AnalysisDataSimpleHistogramModule() {}
590 void AnalysisDataSimpleHistogramModule::init(const AnalysisHistogramSettings& settings)
592 impl_->init(settings);
596 AbstractAverageHistogram& AnalysisDataSimpleHistogramModule::averager()
598 return *impl_->averager_;
602 const AnalysisHistogramSettings& AnalysisDataSimpleHistogramModule::settings() const
604 return impl_->settings_;
608 int AnalysisDataSimpleHistogramModule::frameCount() const
610 return impl_->storage_.frameCount();
614 int AnalysisDataSimpleHistogramModule::flags() const
616 return efAllowMulticolumn | efAllowMultipoint | efAllowMissing | efAllowMultipleDataSets;
620 bool AnalysisDataSimpleHistogramModule::parallelDataStarted(AbstractAnalysisData* data,
621 const AnalysisDataParallelOptions& options)
623 addModule(impl_->averager_);
624 const int dataSetCount = data->dataSetCount();
625 const int columnCount = settings().binCount();
626 setDataSetCount(dataSetCount);
627 impl_->accumulator_.setDataSetCount(dataSetCount);
628 for (int i = 0; i < dataSetCount; ++i)
630 setColumnCount(i, columnCount);
631 impl_->accumulator_.setColumnCount(i, columnCount);
633 impl_->accumulator_.init(options);
634 impl_->storage_.startParallelDataStorage(this, &moduleManager(), options);
639 void AnalysisDataSimpleHistogramModule::frameStarted(const AnalysisDataFrameHeader& header)
641 impl_->accumulator_.frameData(header.index()).clear();
645 void AnalysisDataSimpleHistogramModule::pointsAdded(const AnalysisDataPointSetRef& points)
647 Impl::FrameLocalData::DataSetHandle handle =
648 impl_->accumulator_.frameDataSet(points.frameIndex(), points.dataSetIndex());
649 for (int i = 0; i < points.columnCount(); ++i)
651 if (points.present(i))
653 const int bin = settings().findBin(points.y(i));
656 handle.value(bin) += 1;
663 void AnalysisDataSimpleHistogramModule::frameFinished(const AnalysisDataFrameHeader& header)
665 Impl::FrameLocalData::FrameHandle handle = impl_->accumulator_.frameData(header.index());
666 AnalysisDataStorageFrame& frame = impl_->storage_.startFrame(header);
667 const int columnCount = settings().binCount();
668 for (int s = 0; s < dataSetCount(); ++s)
670 Impl::FrameLocalData::DataSetHandle dataSet = handle.dataSet(s);
671 frame.selectDataSet(s);
672 for (int i = 0; i < columnCount; ++i)
674 frame.setValue(i, dataSet.value(i));
681 void AnalysisDataSimpleHistogramModule::frameFinishedSerial(int frameIndex)
683 impl_->storage_.finishFrameSerial(frameIndex);
687 void AnalysisDataSimpleHistogramModule::dataFinished()
689 impl_->storage_.finishDataStorage();
693 AnalysisDataFrameRef AnalysisDataSimpleHistogramModule::tryGetDataFrameInternal(int index) const
695 return impl_->storage_.tryGetDataFrame(index);
699 bool AnalysisDataSimpleHistogramModule::requestStorageInternal(int nframes)
701 return impl_->storage_.requestStorage(nframes);
705 /********************************************************************
706 * AnalysisDataWeightedHistogramModule
710 * Private implementation class for AnalysisDataWeightedHistogramModule.
712 * \ingroup module_analysisdata
714 class AnalysisDataWeightedHistogramModule::Impl : public internal::BasicHistogramImpl
717 //! Shorthand for the per-frame accumulation data structure type.
718 typedef AnalysisDataFrameLocalData<double> FrameLocalData;
721 //! Creates an histogram impl with defined bin parameters.
722 explicit Impl(const AnalysisHistogramSettings& settings) : BasicHistogramImpl(settings) {}
724 //! Accumulates the histogram within a frame.
725 FrameLocalData accumulator_;
728 AnalysisDataWeightedHistogramModule::AnalysisDataWeightedHistogramModule() : impl_(new Impl()) {}
731 AnalysisDataWeightedHistogramModule::AnalysisDataWeightedHistogramModule(const AnalysisHistogramSettings& settings) :
732 impl_(new Impl(settings))
737 AnalysisDataWeightedHistogramModule::~AnalysisDataWeightedHistogramModule() {}
740 void AnalysisDataWeightedHistogramModule::init(const AnalysisHistogramSettings& settings)
742 impl_->init(settings);
746 AbstractAverageHistogram& AnalysisDataWeightedHistogramModule::averager()
748 return *impl_->averager_;
752 const AnalysisHistogramSettings& AnalysisDataWeightedHistogramModule::settings() const
754 return impl_->settings_;
758 int AnalysisDataWeightedHistogramModule::frameCount() const
760 return impl_->storage_.frameCount();
764 int AnalysisDataWeightedHistogramModule::flags() const
766 return efAllowMulticolumn | efAllowMultipoint | efAllowMultipleDataSets;
770 bool AnalysisDataWeightedHistogramModule::parallelDataStarted(AbstractAnalysisData* data,
771 const AnalysisDataParallelOptions& options)
773 addModule(impl_->averager_);
774 const int dataSetCount = data->dataSetCount();
775 const int columnCount = settings().binCount();
776 setDataSetCount(dataSetCount);
777 impl_->accumulator_.setDataSetCount(dataSetCount);
778 for (int i = 0; i < dataSetCount; ++i)
780 setColumnCount(i, columnCount);
781 impl_->accumulator_.setColumnCount(i, columnCount);
783 impl_->accumulator_.init(options);
784 impl_->storage_.startParallelDataStorage(this, &moduleManager(), options);
789 void AnalysisDataWeightedHistogramModule::frameStarted(const AnalysisDataFrameHeader& header)
791 impl_->accumulator_.frameData(header.index()).clear();
795 void AnalysisDataWeightedHistogramModule::pointsAdded(const AnalysisDataPointSetRef& points)
797 if (points.firstColumn() != 0 || points.columnCount() < 2)
799 GMX_THROW(APIError("Invalid data layout"));
801 int bin = settings().findBin(points.y(0));
804 Impl::FrameLocalData::DataSetHandle handle =
805 impl_->accumulator_.frameDataSet(points.frameIndex(), points.dataSetIndex());
806 for (int i = 1; i < points.columnCount(); ++i)
808 handle.value(bin) += points.y(i);
814 void AnalysisDataWeightedHistogramModule::frameFinished(const AnalysisDataFrameHeader& header)
816 Impl::FrameLocalData::FrameHandle handle = impl_->accumulator_.frameData(header.index());
817 AnalysisDataStorageFrame& frame = impl_->storage_.startFrame(header);
818 const int columnCount = settings().binCount();
819 for (int s = 0; s < dataSetCount(); ++s)
821 Impl::FrameLocalData::DataSetHandle dataSet = handle.dataSet(s);
822 frame.selectDataSet(s);
823 for (int i = 0; i < columnCount; ++i)
825 frame.setValue(i, dataSet.value(i));
832 void AnalysisDataWeightedHistogramModule::frameFinishedSerial(int frameIndex)
834 impl_->storage_.finishFrameSerial(frameIndex);
838 void AnalysisDataWeightedHistogramModule::dataFinished()
840 impl_->storage_.finishDataStorage();
844 AnalysisDataFrameRef AnalysisDataWeightedHistogramModule::tryGetDataFrameInternal(int index) const
846 return impl_->storage_.tryGetDataFrame(index);
850 bool AnalysisDataWeightedHistogramModule::requestStorageInternal(int nframes)
852 return impl_->storage_.requestStorage(nframes);
856 /********************************************************************
857 * AnalysisDataBinAverageModule
860 class AnalysisDataBinAverageModule::Impl
864 explicit Impl(const AnalysisHistogramSettings& settings) : settings_(settings) {}
866 //! Histogram settings.
867 AnalysisHistogramSettings settings_;
868 //! Averaging helper objects for each input data set.
869 std::vector<AnalysisDataFrameAverager> averagers_;
872 AnalysisDataBinAverageModule::AnalysisDataBinAverageModule() : impl_(new Impl())
878 AnalysisDataBinAverageModule::AnalysisDataBinAverageModule(const AnalysisHistogramSettings& settings) :
879 impl_(new Impl(settings))
881 setRowCount(settings.binCount());
882 setXAxis(settings.firstEdge() + 0.5 * settings.binWidth(), settings.binWidth());
886 AnalysisDataBinAverageModule::~AnalysisDataBinAverageModule() {}
889 void AnalysisDataBinAverageModule::init(const AnalysisHistogramSettings& settings)
891 impl_->settings_ = settings;
892 setRowCount(settings.binCount());
893 setXAxis(settings.firstEdge() + 0.5 * settings.binWidth(), settings.binWidth());
897 const AnalysisHistogramSettings& AnalysisDataBinAverageModule::settings() const
899 return impl_->settings_;
903 int AnalysisDataBinAverageModule::flags() const
905 return efAllowMulticolumn | efAllowMultipoint | efAllowMultipleDataSets;
909 void AnalysisDataBinAverageModule::dataStarted(AbstractAnalysisData* data)
911 setColumnCount(data->dataSetCount());
912 impl_->averagers_.resize(data->dataSetCount());
913 for (int i = 0; i < data->dataSetCount(); ++i)
915 impl_->averagers_[i].setColumnCount(rowCount());
920 void AnalysisDataBinAverageModule::frameStarted(const AnalysisDataFrameHeader& /*header*/) {}
923 void AnalysisDataBinAverageModule::pointsAdded(const AnalysisDataPointSetRef& points)
925 if (points.firstColumn() != 0 || points.columnCount() < 2)
927 GMX_THROW(APIError("Invalid data layout"));
929 int bin = settings().findBin(points.y(0));
932 AnalysisDataFrameAverager& averager = impl_->averagers_[points.dataSetIndex()];
933 for (int i = 1; i < points.columnCount(); ++i)
935 averager.addValue(bin, points.y(i));
941 void AnalysisDataBinAverageModule::frameFinished(const AnalysisDataFrameHeader& /*header*/) {}
944 void AnalysisDataBinAverageModule::dataFinished()
947 for (int i = 0; i < columnCount(); ++i)
949 AnalysisDataFrameAverager& averager = impl_->averagers_[i];
951 for (int j = 0; j < rowCount(); ++j)
953 value(j, i).setValue(averager.average(j), std::sqrt(averager.variance(j)));