Added unit tests for array data and minor improvements.
[alexxy/gromacs.git] / src / gromacs / analysisdata / tests / histogram.cpp
1 /*
2  *
3  *                This source code is part of
4  *
5  *                 G   R   O   M   A   C   S
6  *
7  *          GROningen MAchine for Chemical Simulations
8  *
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.
13
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.
18  *
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.
25  *
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.
28  *
29  * For more info, check our website at http://www.gromacs.org
30  */
31 /*! \internal \file
32  * \brief
33  * Tests for functionality of analysis data histogram modules.
34  *
35  * These tests check that classes in histogram.h compute histograms correctly
36  * with simple input data.  Also different ways of initializing the histograms
37  * are tested.
38  * Checking is done using gmx::test::AnalysisDataTestFixture and reference
39  * data.  Also the input data is written to the reference data to catch
40  * out-of-date reference.
41  *
42  * \author Teemu Murtola <teemu.murtola@cbr.su.se>
43  * \ingroup module_analysisdata
44  */
45 #include <memory>
46
47 #include <gtest/gtest.h>
48
49 #include "gromacs/analysisdata/analysisdata.h"
50 #include "gromacs/analysisdata/modules/histogram.h"
51
52 #include "datatest.h"
53
54 namespace
55 {
56
57 /********************************************************************
58  * Tests for gmx::AnalysisHistogramSettings.
59  *
60  * These tests check that gmx::AnalysisHistogramSettings objects can be
61  * initialized from various types of values, and that the bin positions are
62  * computed correctly based on the input values.
63  */
64
65 TEST(AnalysisHistogramSettingsTest, InitializesFromBins)
66 {
67     gmx::AnalysisHistogramSettings settings(
68         gmx::histogramFromBins(1.0, 5, 0.5));
69     EXPECT_FLOAT_EQ(1.0, settings.firstEdge());
70     EXPECT_EQ(5, settings.binCount());
71     EXPECT_FLOAT_EQ(0.5, settings.binWidth());
72     EXPECT_FLOAT_EQ(3.5, settings.lastEdge());
73 }
74
75
76 TEST(AnalysisHistogramSettingsTest, InitializesFromBinsWithIntegerBins)
77 {
78     gmx::AnalysisHistogramSettings settings(
79         gmx::histogramFromBins(1.0, 5, 0.5).integerBins());
80     EXPECT_FLOAT_EQ(0.75, settings.firstEdge());
81     EXPECT_EQ(5, settings.binCount());
82     EXPECT_FLOAT_EQ(0.5, settings.binWidth());
83     EXPECT_FLOAT_EQ(3.25, settings.lastEdge());
84 }
85
86
87 TEST(AnalysisHistogramSettingsTest, InitializesFromRangeWithBinCount)
88 {
89     gmx::AnalysisHistogramSettings settings(
90         gmx::histogramFromRange(1.0, 4.0).binCount(6));
91     EXPECT_FLOAT_EQ(1.0, settings.firstEdge());
92     EXPECT_FLOAT_EQ(4.0, settings.lastEdge());
93     EXPECT_EQ(6, settings.binCount());
94     EXPECT_FLOAT_EQ(0.5, settings.binWidth());
95 }
96
97
98 TEST(AnalysisHistogramSettingsTest, InitializesFromRangeWithBinWidth)
99 {
100     gmx::AnalysisHistogramSettings settings(
101         gmx::histogramFromRange(1.0, 4.0).binWidth(0.5));
102     EXPECT_FLOAT_EQ(1.0, settings.firstEdge());
103     EXPECT_FLOAT_EQ(4.0, settings.lastEdge());
104     EXPECT_FLOAT_EQ(0.5, settings.binWidth());
105     EXPECT_EQ(6, settings.binCount());
106 }
107
108
109 TEST(AnalysisHistogramSettingsTest, InitializesFromRangeWithBinCountAndIntegerBins)
110 {
111     gmx::AnalysisHistogramSettings settings(
112         gmx::histogramFromRange(1.0, 4.0).binCount(7).integerBins());
113     EXPECT_FLOAT_EQ(0.75, settings.firstEdge());
114     EXPECT_FLOAT_EQ(4.25, settings.lastEdge());
115     EXPECT_EQ(7, settings.binCount());
116     EXPECT_FLOAT_EQ(0.5, settings.binWidth());
117 }
118
119
120 TEST(AnalysisHistogramSettingsTest, InitializesFromRangeWithBinWidthAndIntegerBins)
121 {
122     gmx::AnalysisHistogramSettings settings(
123         gmx::histogramFromRange(1.0, 4.0).binWidth(0.5).integerBins());
124     EXPECT_FLOAT_EQ(0.75, settings.firstEdge());
125     EXPECT_FLOAT_EQ(4.25, settings.lastEdge());
126     EXPECT_FLOAT_EQ(0.5, settings.binWidth());
127     EXPECT_EQ(7, settings.binCount());
128 }
129
130
131 TEST(AnalysisHistogramSettingsTest, InitializesFromRangeWithRoundedRange)
132 {
133     gmx::AnalysisHistogramSettings settings(
134         gmx::histogramFromRange(1.2, 3.8).binWidth(0.5).roundRange());
135     EXPECT_FLOAT_EQ(1.0, settings.firstEdge());
136     EXPECT_FLOAT_EQ(4.0, settings.lastEdge());
137     EXPECT_FLOAT_EQ(0.5, settings.binWidth());
138     EXPECT_EQ(6, settings.binCount());
139 }
140
141
142 /********************************************************************
143  * Tests for gmx::AnalysisDataSimpleHistogramModule.
144  */
145
146 typedef gmx::test::AnalysisDataTestFixture SimpleHistogramModuleTest;
147
148 // Input data for the tests below.
149 using gmx::test::END_OF_DATA;
150 using gmx::test::END_OF_FRAME;
151 using gmx::test::MPSTOP;
152 static const real simpleinputdata[] = {
153     1.0,  0.7, MPSTOP, 1.1, MPSTOP, 2.3, MPSTOP, 2.9, END_OF_FRAME,
154     2.0,  1.3, MPSTOP, 2.2, END_OF_FRAME,
155     3.0,  3.3, MPSTOP, 1.2, MPSTOP, 1.3, END_OF_FRAME,
156     END_OF_DATA
157 };
158
159 TEST_F(SimpleHistogramModuleTest, ComputesCorrectly)
160 {
161     gmx::test::AnalysisDataTestInput input(simpleinputdata);
162     gmx::AnalysisData data;
163     data.setColumns(input.columnCount(), true);
164     gmx::AnalysisDataSimpleHistogramModule *module =
165         new gmx::AnalysisDataSimpleHistogramModule(
166                 gmx::histogramFromRange(1.0, 3.0).binCount(4));
167     data.addModule(module);
168
169     ASSERT_NO_THROW(addStaticCheckerModule(input, &data));
170     ASSERT_NO_THROW(addReferenceCheckerModule("InputData", &data));
171     ASSERT_NO_THROW(addReferenceCheckerModule("Histogram", module));
172     ASSERT_NO_THROW(addReferenceCheckerModule("HistogramAverage",
173                                               module->averager()));
174     ASSERT_NO_THROW(presentAllData(input, &data));
175     ASSERT_NO_THROW(module->averager()->done());
176 }
177
178
179 TEST_F(SimpleHistogramModuleTest, ComputesCorrectlyWithAll)
180 {
181     gmx::test::AnalysisDataTestInput input(simpleinputdata);
182     gmx::AnalysisData data;
183     data.setColumns(input.columnCount(), true);
184     gmx::AnalysisDataSimpleHistogramModule *module =
185         new gmx::AnalysisDataSimpleHistogramModule(
186                 gmx::histogramFromRange(1.0, 3.0).binCount(4).includeAll());
187     data.addModule(module);
188
189     ASSERT_NO_THROW(addStaticCheckerModule(input, &data));
190     ASSERT_NO_THROW(addReferenceCheckerModule("InputData", &data));
191     ASSERT_NO_THROW(addReferenceCheckerModule("Histogram", module));
192     ASSERT_NO_THROW(addReferenceCheckerModule("HistogramAverage",
193                                               module->averager()));
194     ASSERT_NO_THROW(presentAllData(input, &data));
195     ASSERT_NO_THROW(module->averager()->done());
196 }
197
198
199 /********************************************************************
200  * Tests for gmx::AnalysisDataWeightedHistogramModule.
201  */
202
203 typedef gmx::test::AnalysisDataTestFixture WeightedHistogramModuleTest;
204
205 // Input data for the tests below (both weighted and bin average modules).
206 static const real weightedinputdata[] = {
207     1.0,  0.7, 0.5, MPSTOP, 1.1, 1.0, MPSTOP, 2.3, 1.0, MPSTOP, 2.9, 2.0, END_OF_FRAME,
208     2.0,  1.3, 1.0, MPSTOP, 2.2, 3.0, END_OF_FRAME,
209     3.0,  3.3, 0.5, MPSTOP, 1.2, 2.0, MPSTOP, 1.3, 1.0, END_OF_FRAME,
210     END_OF_DATA
211 };
212
213 TEST_F(WeightedHistogramModuleTest, ComputesCorrectly)
214 {
215     gmx::test::AnalysisDataTestInput input(weightedinputdata);
216     gmx::AnalysisData data;
217     data.setColumns(input.columnCount(), true);
218     gmx::AnalysisDataWeightedHistogramModule *module =
219         new gmx::AnalysisDataWeightedHistogramModule(
220                 gmx::histogramFromRange(1.0, 3.0).binCount(4));
221     data.addModule(module);
222
223     ASSERT_NO_THROW(addStaticCheckerModule(input, &data));
224     ASSERT_NO_THROW(addReferenceCheckerModule("InputData", &data));
225     ASSERT_NO_THROW(addReferenceCheckerModule("Histogram", module));
226     ASSERT_NO_THROW(addReferenceCheckerModule("HistogramAverage",
227                                               module->averager()));
228     ASSERT_NO_THROW(presentAllData(input, &data));
229     ASSERT_NO_THROW(module->averager()->done());
230 }
231
232
233 TEST_F(WeightedHistogramModuleTest, ComputesCorrectlyWithAll)
234 {
235     gmx::test::AnalysisDataTestInput input(weightedinputdata);
236     gmx::AnalysisData data;
237     data.setColumns(input.columnCount(), true);
238     gmx::AnalysisDataWeightedHistogramModule *module =
239         new gmx::AnalysisDataWeightedHistogramModule(
240                 gmx::histogramFromRange(1.0, 3.0).binCount(4).includeAll());
241     data.addModule(module);
242
243     ASSERT_NO_THROW(addStaticCheckerModule(input, &data));
244     ASSERT_NO_THROW(addReferenceCheckerModule("InputData", &data));
245     ASSERT_NO_THROW(addReferenceCheckerModule("Histogram", module));
246     ASSERT_NO_THROW(addReferenceCheckerModule("HistogramAverage",
247                                               module->averager()));
248     ASSERT_NO_THROW(presentAllData(input, &data));
249     ASSERT_NO_THROW(module->averager()->done());
250 }
251
252
253 /********************************************************************
254  * Tests for gmx::AnalysisDataBinAverageModule.
255  */
256
257 typedef gmx::test::AnalysisDataTestFixture BinAverageModuleTest;
258
259 TEST_F(BinAverageModuleTest, ComputesCorrectly)
260 {
261     gmx::test::AnalysisDataTestInput input(weightedinputdata);
262     gmx::AnalysisData data;
263     data.setColumns(input.columnCount(), true);
264     gmx::AnalysisDataBinAverageModule *module =
265         new gmx::AnalysisDataBinAverageModule(
266                 gmx::histogramFromRange(1.0, 3.0).binCount(4));
267     data.addModule(module);
268
269     ASSERT_NO_THROW(addStaticCheckerModule(input, &data));
270     ASSERT_NO_THROW(addReferenceCheckerModule("InputData", &data));
271     ASSERT_NO_THROW(addReferenceCheckerModule("HistogramAverage", module));
272     ASSERT_NO_THROW(presentAllData(input, &data));
273 }
274
275
276 TEST_F(BinAverageModuleTest, ComputesCorrectlyWithAll)
277 {
278     gmx::test::AnalysisDataTestInput input(weightedinputdata);
279     gmx::AnalysisData data;
280     data.setColumns(input.columnCount(), true);
281     gmx::AnalysisDataBinAverageModule *module =
282         new gmx::AnalysisDataBinAverageModule(
283                 gmx::histogramFromRange(1.0, 3.0).binCount(4).includeAll());
284     data.addModule(module);
285
286     ASSERT_NO_THROW(addStaticCheckerModule(input, &data));
287     ASSERT_NO_THROW(addReferenceCheckerModule("InputData", &data));
288     ASSERT_NO_THROW(addReferenceCheckerModule("HistogramAverage", module));
289     ASSERT_NO_THROW(presentAllData(input, &data));
290 }
291
292
293 /********************************************************************
294  * Tests for gmx::AbstractAverageHistogram.
295  *
296  * This class derives from gmx::AbstractAnalysisArrayData, and is tested using
297  * corresponding facilities in gmx::test::AnalysisDataTestFixture.
298  */
299
300 typedef gmx::test::AnalysisDataTestFixture AbstractAverageHistogramTest;
301
302 // Input data for average histogram tests.
303 static const real averageinputdata[] = {
304     1.0, 2.0, 1.0, END_OF_FRAME,
305     1.5, 1.0, 1.0, END_OF_FRAME,
306     2.0, 3.0, 2.0, END_OF_FRAME,
307     2.5, 4.0, 2.0, END_OF_FRAME,
308     3.0, 2.0, 1.0, END_OF_FRAME,
309     3.5, 0.0, 3.0, END_OF_FRAME,
310     4.0, 1.0, 3.0, END_OF_FRAME,
311     END_OF_DATA
312 };
313
314 /*! \internal \brief
315  * Mock object for testing gmx::AbstractAverageHistogram.
316  *
317  * Exposes necessary methods from gmx::AbstractAverageHistogram to use with
318  * gmx::test::AnalysisDataTestFixture::setupArrayData().
319  */
320 class MockAverageHistogram : public gmx::AbstractAverageHistogram
321 {
322     public:
323         MockAverageHistogram() {}
324         explicit MockAverageHistogram(const gmx::AnalysisHistogramSettings &settings)
325             : AbstractAverageHistogram(settings)
326         {
327         }
328
329         using AbstractAverageHistogram::init;
330         using AbstractAverageHistogram::setColumnCount;
331         using AbstractAverageHistogram::setRowCount;
332         using AbstractAverageHistogram::allocateValues;
333         using AbstractAverageHistogram::setValue;
334 };
335
336
337 TEST_F(AbstractAverageHistogramTest, ClonesCorrectly)
338 {
339     gmx::test::AnalysisDataTestInput input(averageinputdata);
340     MockAverageHistogram data(
341             gmx::histogramFromBins(1.0, input.frameCount(), 0.5).integerBins());
342     setupArrayData(input, &data);
343
344     ASSERT_NO_THROW(addStaticCheckerModule(input, &data));
345     std::auto_ptr<gmx::AbstractAverageHistogram> copy(data.clone());
346     ASSERT_NO_THROW(addStaticCheckerModule(input, copy.get()));
347     ASSERT_NO_THROW(copy->done());
348     ASSERT_NO_THROW(data.done());
349     std::auto_ptr<gmx::AbstractAverageHistogram> copy2(data.clone());
350     ASSERT_NO_THROW(addStaticCheckerModule(input, copy2.get()));
351     ASSERT_NO_THROW(copy2->done());
352 }
353
354
355 TEST_F(AbstractAverageHistogramTest, ResamplesAtDoubleBinWidth)
356 {
357     gmx::test::AnalysisDataTestInput input(averageinputdata);
358     MockAverageHistogram data(
359             gmx::histogramFromBins(1.0, input.frameCount(), 0.5).integerBins());
360     setupArrayData(input, &data);
361
362     ASSERT_NO_THROW(addStaticCheckerModule(input, &data));
363     ASSERT_NO_THROW(addReferenceCheckerModule("InputData", &data));
364     std::auto_ptr<gmx::AbstractAverageHistogram> resampled(
365             data.resampleDoubleBinWidth(false));
366     ASSERT_NO_THROW(addReferenceCheckerModule("ResampledHistogram", resampled.get()));
367     ASSERT_NO_THROW(data.done());
368     ASSERT_NO_THROW(resampled->done());
369 }
370
371
372 TEST_F(AbstractAverageHistogramTest, ResamplesAtDoubleBinWidthWithIntegerBins)
373 {
374     gmx::test::AnalysisDataTestInput input(averageinputdata);
375     MockAverageHistogram data(
376             gmx::histogramFromBins(1.0, input.frameCount(), 0.5).integerBins());
377     setupArrayData(input, &data);
378
379     ASSERT_NO_THROW(addStaticCheckerModule(input, &data));
380     ASSERT_NO_THROW(addReferenceCheckerModule("InputData", &data));
381     std::auto_ptr<gmx::AbstractAverageHistogram> resampled(
382             data.resampleDoubleBinWidth(true));
383     ASSERT_NO_THROW(addReferenceCheckerModule("ResampledHistogram", resampled.get()));
384     ASSERT_NO_THROW(data.done());
385     ASSERT_NO_THROW(resampled->done());
386 }
387
388 } // namespace