From 6440dff61a2400a0522c845b3a70f7033b77ff7d Mon Sep 17 00:00:00 2001
From: Gennady Pospelov <g.pospelov@fz-juelich.de>
Date: Tue, 15 Sep 2015 12:22:41 +0200
Subject: [PATCH] New CumulativeValue class to have on-the-fly average and rms
 calculations.

---
 Core/Tools/inc/CumulativeValue.h              | 94 +++++++++++++++++++
 .../UnitTests/TestCore/CumulativeValueTest.h  | 80 ++++++++++++++++
 2 files changed, 174 insertions(+)
 create mode 100644 Core/Tools/inc/CumulativeValue.h
 create mode 100644 Tests/UnitTests/TestCore/CumulativeValueTest.h

diff --git a/Core/Tools/inc/CumulativeValue.h b/Core/Tools/inc/CumulativeValue.h
new file mode 100644
index 00000000000..25c5b79627e
--- /dev/null
+++ b/Core/Tools/inc/CumulativeValue.h
@@ -0,0 +1,94 @@
+// ************************************************************************** //
+//
+//  BornAgain: simulate and fit scattering at grazing incidence
+//
+//! @file      Algorithms/inc/CumulativeValue.h
+//! @brief     Defines class CumulativeValue.
+//!
+//! @homepage  http://www.bornagainproject.org
+//! @license   GNU General Public License v3 or higher (see COPYING)
+//! @copyright Forschungszentrum Jülich GmbH 2015
+//! @authors   Scientific Computing Group at MLZ Garching
+//! @authors   C. Durniak, M. Ganeva, G. Pospelov, W. Van Herck, J. Wuttke
+//
+// ************************************************************************** //
+
+#ifndef CUMULATIVE_VALUE_H
+#define CUMULATIVE_VALUE_H
+
+#include "WinDllMacros.h"
+
+//! @class CumulativeValue
+//! @ingroup tools
+//! @brief The cumulative value with average and rms on-the-flight calculations.
+
+class BA_CORE_API_ CumulativeValue
+{
+public:
+    CumulativeValue();
+
+    int getNumberOfEntries() const;
+
+    double getValue() const;
+
+    double getAverage() const;
+
+    double getRMS() const;
+
+    void add(double value, double weight=1.0);
+
+    void clear();
+
+private:
+    int m_n_entries;
+    double m_sum;
+    double m_average;
+    double m_rms2;
+    double m_sum_of_weights;
+};
+
+CumulativeValue::CumulativeValue()
+{
+    clear();
+}
+
+int CumulativeValue::getNumberOfEntries() const
+{
+    return m_n_entries;
+}
+
+double CumulativeValue::getValue() const
+{
+    return m_sum;
+}
+
+double CumulativeValue::getAverage() const
+{
+    return m_average;
+}
+
+double CumulativeValue::getRMS() const
+{
+    return std::sqrt(m_rms2);
+}
+
+void CumulativeValue::add(double value, double weight)
+{
+    m_n_entries++;
+    m_sum += value;
+    m_rms2 = (m_sum_of_weights/(m_sum_of_weights+weight))*
+            (m_rms2+(weight/(m_sum_of_weights+weight))*(value-m_average)*(value-m_average));
+    m_average = m_average+(value-m_average)*weight/(m_sum_of_weights+weight);
+    m_sum_of_weights += weight;
+}
+
+void CumulativeValue::clear()
+{
+    m_n_entries = 0;
+    m_sum = 0.0;
+    m_average = 0.0;
+    m_rms2 = 0.0;
+    m_sum_of_weights = 0.0;
+}
+
+#endif
diff --git a/Tests/UnitTests/TestCore/CumulativeValueTest.h b/Tests/UnitTests/TestCore/CumulativeValueTest.h
new file mode 100644
index 00000000000..f3390ee7d26
--- /dev/null
+++ b/Tests/UnitTests/TestCore/CumulativeValueTest.h
@@ -0,0 +1,80 @@
+#ifndef CUMULATIVEVALUETEST_H
+#define CUMULATIVEVALUETEST_H
+
+#include "CumulativeValue.h"
+
+#include "gtest/gtest.h"
+
+class CumulativeValueTest : public ::testing::Test
+{
+ protected:
+    CumulativeValueTest(){}
+    virtual ~CumulativeValueTest(){}
+};
+
+TEST_F(CumulativeValueTest, InitialState)
+{
+    CumulativeValue cv;
+    EXPECT_EQ(0, cv.getNumberOfEntries());
+    EXPECT_EQ(0.0, cv.getValue());
+    EXPECT_EQ(0.0, cv.getAverage());
+    EXPECT_EQ(0.0, cv.getRMS());
+}
+
+TEST_F(CumulativeValueTest, AddValue)
+{
+    CumulativeValue cv1;
+    cv1.add(1.0);
+    EXPECT_EQ(1, cv1.getNumberOfEntries());
+    EXPECT_EQ(1.0, cv1.getValue());
+    EXPECT_EQ(1.0, cv1.getAverage());
+    EXPECT_EQ(0.0, cv1.getRMS());
+
+    // adding value with weight, all number should stay the same
+    CumulativeValue cv2;
+    cv2.add(1.0, 10.0);
+    EXPECT_EQ(1, cv2.getNumberOfEntries());
+    EXPECT_EQ(1.0, cv2.getValue());
+    EXPECT_EQ(1.0, cv2.getAverage());
+    EXPECT_EQ(0.0, cv2.getRMS());
+
+}
+
+TEST_F(CumulativeValueTest, AddValues)
+{
+    CumulativeValue cv1;
+    cv1.add(1.0);
+    cv1.add(3.0);
+    EXPECT_EQ(2, cv1.getNumberOfEntries());
+    EXPECT_DOUBLE_EQ(4.0, cv1.getValue());
+    EXPECT_DOUBLE_EQ(2.0, cv1.getAverage());
+    EXPECT_DOUBLE_EQ(1.0, cv1.getRMS());
+
+    cv1.clear();
+    EXPECT_EQ(0, cv1.getNumberOfEntries());
+    EXPECT_EQ(0.0, cv1.getValue());
+    EXPECT_EQ(0.0, cv1.getAverage());
+    EXPECT_EQ(0.0, cv1.getRMS());
+}
+
+TEST_F(CumulativeValueTest, AddValuesWithWeights)
+{
+    CumulativeValue cv1;
+    cv1.add(1.0, 3.0);
+    cv1.add(3.0);
+    EXPECT_EQ(2, cv1.getNumberOfEntries());
+    EXPECT_DOUBLE_EQ(4.0, cv1.getValue());
+    EXPECT_DOUBLE_EQ(1.5, cv1.getAverage());
+    EXPECT_FLOAT_EQ(0.75, cv1.getRMS()*cv1.getRMS());
+
+    cv1.add(3.0);
+    cv1.add(3.0);
+    EXPECT_EQ(4, cv1.getNumberOfEntries());
+    EXPECT_DOUBLE_EQ(10.0, cv1.getValue());
+    EXPECT_DOUBLE_EQ(2.0, cv1.getAverage());
+    EXPECT_FLOAT_EQ(1.0, cv1.getRMS());
+
+}
+
+
+#endif
-- 
GitLab