Fix copyright notices for new C++ code.
[alexxy/gromacs.git] / src / gromacs / analysisdata / modules / histogram.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
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.
8  *
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.
13  *
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.
18  *
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.
23  *
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.
31  *
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.
34  */
35 /*! \internal \file
36  * \brief
37  * Implements classes in histogram.h.
38  *
39  * \author Teemu Murtola <teemu.murtola@gmail.com>
40  * \ingroup module_analysisdata
41  */
42 #include "gromacs/analysisdata/modules/histogram.h"
43
44 #include <cmath>
45
46 #include <limits>
47
48 #include "gromacs/analysisdata/dataframe.h"
49 #include "gromacs/analysisdata/datastorage.h"
50 #include "gromacs/utility/exceptions.h"
51 #include "gromacs/utility/gmxassert.h"
52
53 namespace
54 {
55
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)
60 {
61     return value != UNDEFINED;
62 }
63
64 } // namespace
65
66 namespace gmx
67 {
68
69 /********************************************************************
70  * AnalysisHistogramSettingsInitializer
71  */
72
73 AnalysisHistogramSettingsInitializer::AnalysisHistogramSettingsInitializer()
74     : min_(UNDEFINED), max_(UNDEFINED), binWidth_(UNDEFINED),
75       binCount_(0), bIntegerBins_(false), bRoundRange_(false),
76       bIncludeAll_(false)
77 {
78 }
79
80
81 /********************************************************************
82  * AnalysisHistogramSettings
83  */
84
85 AnalysisHistogramSettings::AnalysisHistogramSettings()
86     : firstEdge_(0.0), lastEdge_(0.0), binWidth_(0.0), inverseBinWidth_(0.0),
87       binCount_(0), bAll_(false)
88 {
89 }
90
91
92 AnalysisHistogramSettings::AnalysisHistogramSettings(
93         const AnalysisHistogramSettingsInitializer &settings)
94 {
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");
103
104     if (!isDefined(settings.max_))
105     {
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");
110
111         firstEdge_ = settings.min_;
112         binCount_  = settings.binCount_;
113         binWidth_  = settings.binWidth_;
114         if (settings.bIntegerBins_)
115         {
116             firstEdge_ -= 0.5 * binWidth_;
117         }
118         lastEdge_ = firstEdge_ + binCount_ * binWidth_;
119     }
120     else
121     {
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");
126
127         if (settings.bRoundRange_)
128         {
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);
137         }
138         else
139         {
140             firstEdge_     = settings.min_;
141             lastEdge_      = settings.max_;
142             if (settings.binCount_ > 0)
143             {
144                 binCount_ = settings.binCount_;
145                 if (settings.bIntegerBins_)
146                 {
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_;
152                 }
153                 else
154                 {
155                     binWidth_ = (lastEdge_ - firstEdge_) / binCount_;
156                 }
157             }
158             else
159             {
160                 binWidth_ = settings.binWidth_;
161                 binCount_ = static_cast<int>((lastEdge_ - firstEdge_) / binWidth_ + 0.5);
162                 if (settings.bIntegerBins_)
163                 {
164                     firstEdge_ -= 0.5 * binWidth_;
165                     ++binCount_;
166                 }
167                 lastEdge_ = firstEdge_ + binCount_ * binWidth_;
168             }
169         }
170     }
171
172     inverseBinWidth_ = 1.0 / binWidth_;
173     bAll_            = settings.bIncludeAll_;
174 }
175
176
177 int
178 AnalysisHistogramSettings::findBin(real y) const
179 {
180     if (y < firstEdge_)
181     {
182         return bAll_ ? 0 : -1;
183     }
184     int bin = static_cast<int>((y - firstEdge_) * inverseBinWidth_);
185     if (bin >= binCount_)
186     {
187         return bAll_ ? binCount_ - 1 : -1;
188     }
189     return bin;
190 }
191
192
193 /********************************************************************
194  * StaticAverageHistogram
195  */
196
197 namespace
198 {
199
200 /*! \internal \brief
201  * Represents copies of average histograms.
202  *
203  * Methods in AbstractAverageHistogram that return new histogram instances
204  * return objects of this class.
205  * Initialization of values is handled in those methods.
206  *
207  * \ingroup module_analysisdata
208  */
209 class StaticAverageHistogram : public AbstractAverageHistogram
210 {
211     public:
212         StaticAverageHistogram();
213         //! Creates an average histogram module with defined bin parameters.
214         explicit StaticAverageHistogram(const AnalysisHistogramSettings &settings);
215
216         // Copy and assign disallowed by base.
217 };
218
219 StaticAverageHistogram::StaticAverageHistogram()
220 {
221 }
222
223
224 StaticAverageHistogram::StaticAverageHistogram(
225         const AnalysisHistogramSettings &settings)
226     : AbstractAverageHistogram(settings)
227 {
228 }
229
230 }   // namespace
231
232
233 /********************************************************************
234  * AbstractAverageHistogram
235  */
236
237 AbstractAverageHistogram::AbstractAverageHistogram()
238 {
239 }
240
241
242 AbstractAverageHistogram::AbstractAverageHistogram(
243         const AnalysisHistogramSettings &settings)
244     : settings_(settings)
245 {
246     setRowCount(settings.binCount());
247     setXAxis(settings.firstEdge() + 0.5 * settings.binWidth(),
248              settings.binWidth());
249 }
250
251
252 AbstractAverageHistogram::~AbstractAverageHistogram()
253 {
254 }
255
256
257 void
258 AbstractAverageHistogram::init(const AnalysisHistogramSettings &settings)
259 {
260     settings_ = settings;
261     setRowCount(settings.binCount());
262     setXAxis(settings.firstEdge() + 0.5 * settings.binWidth(),
263              settings.binWidth());
264 }
265
266
267 AverageHistogramPointer
268 AbstractAverageHistogram::resampleDoubleBinWidth(bool bIntegerBins) const
269 {
270     int nbins;
271     if (bIntegerBins)
272     {
273         nbins = (rowCount() + 1) / 2;
274     }
275     else
276     {
277         nbins = rowCount() / 2;
278     }
279
280     AverageHistogramPointer dest(
281             new StaticAverageHistogram(
282                     histogramFromBins(xstart(), nbins, 2*xstep())
283                         .integerBins(bIntegerBins)));
284     dest->setColumnCount(columnCount());
285     dest->allocateValues();
286
287     int  i, j;
288     for (i = j = 0; i < nbins; ++i)
289     {
290         const bool bFirstHalfBin = (bIntegerBins && i == 0);
291         for (int c = 0; c < columnCount(); ++c)
292         {
293             real  v1, v2;
294             if (bFirstHalfBin)
295             {
296                 v1 = value(0, c);
297                 v2 = 0;
298             }
299             else
300             {
301                 v1 = value(j, c);
302                 v2 = value(j + 1, c);
303             }
304             if (c == 1)
305             {
306                 dest->setValue(i, c, sqrt(v1 * v1 + v2 * v2));
307             }
308             else
309             {
310                 dest->setValue(i, c, v1 + v2);
311             }
312         }
313         if (bFirstHalfBin)
314         {
315             ++j;
316         }
317         else
318         {
319             j += 2;
320         }
321     }
322     return dest;
323 }
324
325
326 AverageHistogramPointer
327 AbstractAverageHistogram::clone() const
328 {
329     AverageHistogramPointer dest(new StaticAverageHistogram());
330     copyContents(this, dest.get());
331     return dest;
332 }
333
334
335 void
336 AbstractAverageHistogram::normalizeProbability()
337 {
338     real sum = 0;
339     for (int i = 0; i < rowCount(); ++i)
340     {
341         sum += value(i, 0);
342     }
343     scale(1.0 / (sum * xstep()));
344 }
345
346
347 void
348 AbstractAverageHistogram::scale(real norm)
349 {
350     for (int i = 0; i < rowCount(); ++i)
351     {
352         value(i, 0) *= norm;
353         value(i, 1) *= norm;
354     }
355 }
356
357
358 void
359 AbstractAverageHistogram::scaleVector(real norm[])
360 {
361     for (int i = 0; i < rowCount(); ++i)
362     {
363         value(i, 0) *= norm[i];
364         value(i, 1) *= norm[i];
365     }
366 }
367
368
369 /********************************************************************
370  * BasicAverageHistogramModule
371  */
372
373 namespace internal
374 {
375
376 /*! \internal \brief
377  * Implements average histogram module that averages per-frame histograms.
378  *
379  * This class is used for accumulating average histograms in per-frame
380  * histogram modules (those that use BasicHistogramImpl as their implementation
381  * class).
382  * There are two columns, first for the average and second for standard
383  * deviation.
384  *
385  * \ingroup module_analysisdata
386  */
387 class BasicAverageHistogramModule : public AbstractAverageHistogram,
388                                     public AnalysisDataModuleInterface
389 {
390     public:
391         BasicAverageHistogramModule();
392         //! Creates an average histogram module with defined bin parameters.
393         explicit BasicAverageHistogramModule(const AnalysisHistogramSettings &settings);
394
395         using AbstractAverageHistogram::init;
396
397         virtual int flags() const;
398
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();
404
405     private:
406         //! Number of frames accumulated so far.
407         int                     frameCount_;
408
409         // Copy and assign disallowed by base.
410 };
411
412 BasicAverageHistogramModule::BasicAverageHistogramModule()
413     : frameCount_(0)
414 {
415     setColumnCount(2);
416 }
417
418
419 BasicAverageHistogramModule::BasicAverageHistogramModule(
420         const AnalysisHistogramSettings &settings)
421     : AbstractAverageHistogram(settings), frameCount_(0)
422 {
423     setColumnCount(2);
424 }
425
426
427 int
428 BasicAverageHistogramModule::flags() const
429 {
430     return efAllowMulticolumn;
431 }
432
433
434 void
435 BasicAverageHistogramModule::dataStarted(AbstractAnalysisData *data)
436 {
437     GMX_RELEASE_ASSERT(rowCount() == data->columnCount(),
438                        "Inconsistent data sizes, something is wrong in the initialization");
439     allocateValues();
440 }
441
442
443 void
444 BasicAverageHistogramModule::frameStarted(const AnalysisDataFrameHeader & /*header*/)
445 {
446 }
447
448
449 void
450 BasicAverageHistogramModule::pointsAdded(const AnalysisDataPointSetRef &points)
451 {
452     int firstcol = points.firstColumn();
453     for (int i = 0; i < points.columnCount(); ++i)
454     {
455         real y = points.y(i);
456         value(firstcol + i, 0) += y;
457         value(firstcol + i, 1) += y * y;
458     }
459 }
460
461
462 void
463 BasicAverageHistogramModule::frameFinished(const AnalysisDataFrameHeader & /*header*/)
464 {
465     ++frameCount_;
466 }
467
468
469 void
470 BasicAverageHistogramModule::dataFinished()
471 {
472     for (int i = 0; i < rowCount(); ++i)
473     {
474         real ave = value(i, 0) / frameCount_;
475         real std = sqrt(value(i, 1) / frameCount_ - ave * ave);
476         setValue(i, 0, ave);
477         setValue(i, 1, std);
478     }
479 }
480
481
482 /********************************************************************
483  * BasicHistogramImpl
484  */
485
486 /*! \internal \brief
487  * Private implementation class for AnalysisDataSimpleHistogramModule and
488  * AnalysisDataWeightedHistogramModule.
489  *
490  * \ingroup module_analysisdata
491  */
492 class BasicHistogramImpl
493 {
494     public:
495         //! Smart pointer to manage an BasicAverageHistogramModule object.
496         typedef boost::shared_ptr<BasicAverageHistogramModule>
497             BasicAverageHistogramModulePointer;
498
499         BasicHistogramImpl();
500         //! Creates an histogram impl with defined bin parameters.
501         explicit BasicHistogramImpl(const AnalysisHistogramSettings &settings);
502         ~BasicHistogramImpl();
503
504         /*! \brief
505          * (Re)initializes the histogram from settings.
506          */
507         void init(const AnalysisHistogramSettings &settings);
508         /*! \brief
509          * Initializes data storage frame when a new frame starts.
510          */
511         void initFrame(AnalysisDataStorageFrame *frame);
512
513         //! Storage implementation object.
514         AnalysisDataStorage                  storage_;
515         //! Settings for the histogram object.
516         AnalysisHistogramSettings            settings_;
517         //! Averager module.
518         BasicAverageHistogramModulePointer   averager_;
519 };
520
521 BasicHistogramImpl::BasicHistogramImpl()
522     : averager_(new BasicAverageHistogramModule())
523 {
524 }
525
526
527 BasicHistogramImpl::BasicHistogramImpl(const AnalysisHistogramSettings &settings)
528     : settings_(settings), averager_(new BasicAverageHistogramModule(settings))
529 {
530 }
531
532
533 BasicHistogramImpl::~BasicHistogramImpl()
534 {
535 }
536
537
538 void BasicHistogramImpl::init(const AnalysisHistogramSettings &settings)
539 {
540     settings_ = settings;
541     averager_->init(settings);
542 }
543
544
545 void
546 BasicHistogramImpl::initFrame(AnalysisDataStorageFrame *frame)
547 {
548     for (int i = 0; i < frame->columnCount(); ++i)
549     {
550         frame->setValue(i, 0.0);
551     }
552 }
553
554 }   // namespace internal
555
556
557 /********************************************************************
558  * AnalysisDataSimpleHistogramModule
559  */
560
561 AnalysisDataSimpleHistogramModule::AnalysisDataSimpleHistogramModule()
562     : impl_(new internal::BasicHistogramImpl())
563 {
564 }
565
566
567 AnalysisDataSimpleHistogramModule::AnalysisDataSimpleHistogramModule(
568         const AnalysisHistogramSettings &settings)
569     : impl_(new internal::BasicHistogramImpl(settings))
570 {
571 }
572
573
574 AnalysisDataSimpleHistogramModule::~AnalysisDataSimpleHistogramModule()
575 {
576 }
577
578
579 void AnalysisDataSimpleHistogramModule::init(const AnalysisHistogramSettings &settings)
580 {
581     impl_->init(settings);
582 }
583
584
585 AbstractAverageHistogram &
586 AnalysisDataSimpleHistogramModule::averager()
587 {
588     return *impl_->averager_;
589 }
590
591
592 const AnalysisHistogramSettings &
593 AnalysisDataSimpleHistogramModule::settings() const
594 {
595     return impl_->settings_;
596 }
597
598
599 int
600 AnalysisDataSimpleHistogramModule::flags() const
601 {
602     return efAllowMulticolumn | efAllowMultipoint;
603 }
604
605
606 void
607 AnalysisDataSimpleHistogramModule::dataStarted(AbstractAnalysisData *data)
608 {
609     addModule(impl_->averager_);
610     setColumnCount(settings().binCount());
611     notifyDataStart();
612     impl_->storage_.startDataStorage(this);
613 }
614
615
616 void
617 AnalysisDataSimpleHistogramModule::frameStarted(const AnalysisDataFrameHeader &header)
618 {
619     AnalysisDataStorageFrame &frame = impl_->storage_.startFrame(header);
620     impl_->initFrame(&frame);
621 }
622
623
624 void
625 AnalysisDataSimpleHistogramModule::pointsAdded(const AnalysisDataPointSetRef &points)
626 {
627     AnalysisDataStorageFrame &frame =
628         impl_->storage_.currentFrame(points.frameIndex());
629     for (int i = 0; i < points.columnCount(); ++i)
630     {
631         int bin = settings().findBin(points.y(i));
632         if (bin != -1)
633         {
634             frame.value(bin) += 1;
635         }
636     }
637 }
638
639
640 void
641 AnalysisDataSimpleHistogramModule::frameFinished(const AnalysisDataFrameHeader &header)
642 {
643     impl_->storage_.finishFrame(header.index());
644 }
645
646
647 void
648 AnalysisDataSimpleHistogramModule::dataFinished()
649 {
650     notifyDataFinish();
651 }
652
653
654 AnalysisDataFrameRef
655 AnalysisDataSimpleHistogramModule::tryGetDataFrameInternal(int index) const
656 {
657     return impl_->storage_.tryGetDataFrame(index);
658 }
659
660
661 bool
662 AnalysisDataSimpleHistogramModule::requestStorageInternal(int nframes)
663 {
664     return impl_->storage_.requestStorage(nframes);
665 }
666
667
668 /********************************************************************
669  * AnalysisDataWeightedHistogramModule
670  */
671
672 AnalysisDataWeightedHistogramModule::AnalysisDataWeightedHistogramModule()
673     : impl_(new internal::BasicHistogramImpl())
674 {
675 }
676
677
678 AnalysisDataWeightedHistogramModule::AnalysisDataWeightedHistogramModule(
679         const AnalysisHistogramSettings &settings)
680     : impl_(new internal::BasicHistogramImpl(settings))
681 {
682 }
683
684
685 AnalysisDataWeightedHistogramModule::~AnalysisDataWeightedHistogramModule()
686 {
687 }
688
689
690 void AnalysisDataWeightedHistogramModule::init(const AnalysisHistogramSettings &settings)
691 {
692     impl_->init(settings);
693 }
694
695
696 AbstractAverageHistogram &
697 AnalysisDataWeightedHistogramModule::averager()
698 {
699     return *impl_->averager_;
700 }
701
702
703 const AnalysisHistogramSettings &
704 AnalysisDataWeightedHistogramModule::settings() const
705 {
706     return impl_->settings_;
707 }
708
709
710 int
711 AnalysisDataWeightedHistogramModule::flags() const
712 {
713     return efAllowMulticolumn | efAllowMultipoint;
714 }
715
716
717 void
718 AnalysisDataWeightedHistogramModule::dataStarted(AbstractAnalysisData *data)
719 {
720     addModule(impl_->averager_);
721     setColumnCount(settings().binCount());
722     notifyDataStart();
723     impl_->storage_.startDataStorage(this);
724 }
725
726
727 void
728 AnalysisDataWeightedHistogramModule::frameStarted(const AnalysisDataFrameHeader &header)
729 {
730     AnalysisDataStorageFrame &frame = impl_->storage_.startFrame(header);
731     impl_->initFrame(&frame);
732 }
733
734
735 void
736 AnalysisDataWeightedHistogramModule::pointsAdded(const AnalysisDataPointSetRef &points)
737 {
738     if (points.firstColumn() != 0 || points.columnCount() < 2)
739     {
740         GMX_THROW(APIError("Invalid data layout"));
741     }
742     int bin = settings().findBin(points.y(0));
743     if (bin != -1)
744     {
745         AnalysisDataStorageFrame &frame =
746             impl_->storage_.currentFrame(points.frameIndex());
747         for (int i = 1; i < points.columnCount(); ++i)
748         {
749             frame.value(bin) += points.y(i);
750         }
751     }
752 }
753
754
755 void
756 AnalysisDataWeightedHistogramModule::frameFinished(const AnalysisDataFrameHeader &header)
757 {
758     impl_->storage_.finishFrame(header.index());
759 }
760
761
762 void
763 AnalysisDataWeightedHistogramModule::dataFinished()
764 {
765     notifyDataFinish();
766 }
767
768
769 AnalysisDataFrameRef
770 AnalysisDataWeightedHistogramModule::tryGetDataFrameInternal(int index) const
771 {
772     return impl_->storage_.tryGetDataFrame(index);
773 }
774
775
776 bool
777 AnalysisDataWeightedHistogramModule::requestStorageInternal(int nframes)
778 {
779     return impl_->storage_.requestStorage(nframes);
780 }
781
782
783 /********************************************************************
784  * AnalysisDataBinAverageModule
785  */
786
787 AnalysisDataBinAverageModule::AnalysisDataBinAverageModule()
788 {
789     setColumnCount(3);
790 }
791
792
793 AnalysisDataBinAverageModule::AnalysisDataBinAverageModule(
794         const AnalysisHistogramSettings &settings)
795     : settings_(settings)
796 {
797     setColumnCount(3);
798     setRowCount(settings.binCount());
799     setXAxis(settings.firstEdge() + 0.5 * settings.binWidth(),
800              settings.binWidth());
801 }
802
803
804 AnalysisDataBinAverageModule::~AnalysisDataBinAverageModule()
805 {
806 }
807
808
809 void
810 AnalysisDataBinAverageModule::init(const AnalysisHistogramSettings &settings)
811 {
812     settings_ = settings;
813     setRowCount(settings.binCount());
814     setXAxis(settings.firstEdge() + 0.5 * settings.binWidth(),
815              settings.binWidth());
816 }
817
818
819 int
820 AnalysisDataBinAverageModule::flags() const
821 {
822     return efAllowMulticolumn | efAllowMultipoint;
823 }
824
825
826 void
827 AnalysisDataBinAverageModule::dataStarted(AbstractAnalysisData * /*data*/)
828 {
829     allocateValues();
830 }
831
832
833 void
834 AnalysisDataBinAverageModule::frameStarted(const AnalysisDataFrameHeader & /*header*/)
835 {
836 }
837
838
839 void
840 AnalysisDataBinAverageModule::pointsAdded(const AnalysisDataPointSetRef &points)
841 {
842     if (points.firstColumn() != 0 || points.columnCount() < 2)
843     {
844         GMX_THROW(APIError("Invalid data layout"));
845     }
846     int bin = settings().findBin(points.y(0));
847     if (bin != -1)
848     {
849         for (int i = 1; i < points.columnCount(); ++i)
850         {
851             real y = points.y(i);
852             value(bin, 0) += y;
853             value(bin, 1) += y * y;
854         }
855         value(bin, 2) += points.columnCount() - 1;
856     }
857 }
858
859
860 void
861 AnalysisDataBinAverageModule::frameFinished(const AnalysisDataFrameHeader & /*header*/)
862 {
863 }
864
865
866 void
867 AnalysisDataBinAverageModule::dataFinished()
868 {
869     for (int i = 0; i < settings().binCount(); ++i)
870     {
871         real n = value(i, 2);
872         if (n > 0)
873         {
874             real ave = value(i, 0) / n;
875             real std = sqrt(value(i, 1) / n - ave * ave);
876             setValue(i, 0, ave);
877             setValue(i, 1, std);
878         }
879     }
880     valuesReady();
881 }
882
883 } // namespace gmx