*/
#include "gromacs/analysisdata/arraydata.h"
-// Legacy header.
-#include "smalloc.h"
+#include <algorithm>
#include "gromacs/fatalerror/exceptions.h"
#include "gromacs/fatalerror/gmxassert.h"
{
AbstractAnalysisArrayData::AbstractAnalysisArrayData()
- : _nrows(0), _value(NULL), _xstart(0.0), _xstep(1.0), _bReady(false)
+ : _nrows(0), _xstart(0.0), _xstep(1.0), _bReady(false)
{
}
AbstractAnalysisArrayData::~AbstractAnalysisArrayData()
{
- sfree(_value);
}
{
if (index < 0)
{
- index += _nrows;
+ index += frameCount() - 1;
if (index < 0)
{
return false;
}
if (x != NULL)
{
- *x = _xstart + index * _xstep;
+ *x = xvalue(index);
}
if (dx != NULL)
{
}
if (y != NULL)
{
- *y = _value + (index * columnCount());
+ *y = &_value[index * columnCount()];
}
if (dy != NULL)
{
void
AbstractAnalysisArrayData::setColumnCount(int ncols)
{
- GMX_RELEASE_ASSERT(!_value,
+ GMX_RELEASE_ASSERT(!isAllocated(),
"Cannot change column count after data has been allocated");
AbstractAnalysisData::setColumnCount(ncols);
}
AbstractAnalysisArrayData::setRowCount(int nrows)
{
GMX_RELEASE_ASSERT(nrows > 0, "Invalid number of rows");
- GMX_RELEASE_ASSERT(!_value,
+ GMX_RELEASE_ASSERT(!isAllocated(),
"Cannot change row count after data has been allocated");
_nrows = nrows;
}
void
AbstractAnalysisArrayData::allocateValues()
{
- GMX_RELEASE_ASSERT(_value == NULL, "Can only allocate values once");
+ GMX_RELEASE_ASSERT(!isAllocated(), "Can only allocate values once");
GMX_RELEASE_ASSERT(rowCount() > 0 && columnCount() > 0,
"Row and column counts must be set before allocating values");
- snew(_value, rowCount() * columnCount());
+ _value.resize(rowCount() * columnCount());
}
void
AbstractAnalysisArrayData::valuesReady()
{
- GMX_RELEASE_ASSERT(columnCount() > 0 && _nrows > 0 && _value,
- "There must be some data");
+ GMX_RELEASE_ASSERT(isAllocated(), "There must be some data");
if (_bReady)
{
return;
_bReady = true;
notifyDataStart();
- for (int i = 0; i < _nrows; ++i)
+ for (int i = 0; i < rowCount(); ++i)
{
- notifyFrameStart(_xstart + i * _xstep, 0);
- notifyPointsAdd(0, columnCount(), _value + (i * columnCount()),
+ notifyFrameStart(xvalue(i), 0);
+ notifyPointsAdd(0, columnCount(), &_value[i * columnCount()],
NULL, NULL);
notifyFrameFinish();
}
AbstractAnalysisArrayData::copyContents(const AbstractAnalysisArrayData *src,
AbstractAnalysisArrayData *dest)
{
- GMX_RELEASE_ASSERT(src->columnCount() > 0 && src->_nrows > 0 && src->_value,
- "Source data must not be empty");
- GMX_RELEASE_ASSERT(!dest->_value, "Destination data must not be allocated");
+ GMX_RELEASE_ASSERT(src->isAllocated(), "Source data must not be empty");
+ GMX_RELEASE_ASSERT(!dest->isAllocated(),
+ "Destination data must not be allocated");
dest->setColumnCount(src->columnCount());
- dest->setRowCount(src->_nrows);
+ dest->setRowCount(src->rowCount());
dest->allocateValues();
- dest->setXAxis(src->_xstart, src->_xstep);
- for (int i = 0; i < src->_nrows * src->columnCount(); ++i)
- {
- dest->_value[i] = src->_value[i];
- }
+ dest->setXAxis(src->xstart(), src->xstep());
+ std::copy(src->_value.begin(), src->_value.end(), dest->_value.begin());
}
} // namespace gmx
#include <cstddef>
+#include <vector>
+
#include "../fatalerror/gmxassert.h"
#include "abstractdata.h"
const bool **present = 0) const;
virtual bool requestStorage(int nframes = -1);
- protected:
- AbstractAnalysisArrayData();
-
/*! \brief
* Returns the number of rows in the data array.
*
* returns 0 before valuesReady() has been called.
*/
int rowCount() const { return _nrows; }
+ //! Returns true if values have been allocated.
+ bool isAllocated() const { return !_value.empty(); }
+ //! Returns the x value of the first frame.
+ real xstart() const { return _xstart; }
+ //! Returns the step between frame x values.
+ real xstep() const { return _xstep; }
+ //! Returns the x value of a row.
+ real xvalue(int row) const
+ {
+ GMX_ASSERT(row >= 0 && row < rowCount(), "Row index out of range");
+ return xstart() + row * xstep();
+ }
+ //! Returns a given array element.
+ real value(int row, int col) const
+ {
+ GMX_ASSERT(row >= 0 && row < rowCount(), "Row index out of range");
+ GMX_ASSERT(col >= 0 && col < columnCount(), "Column index out of range");
+ GMX_ASSERT(isAllocated(), "Data array not allocated");
+ return _value[row * columnCount() + col];
+ }
+
+ protected:
+ AbstractAnalysisArrayData();
+
/*! \brief
* Sets the number of columns in the data array.
*
* setColumnCount() and setRowCount() must have been called.
*/
void allocateValues();
- //! Returns the x value of the first frame.
- real xstart() const { return _xstart; }
- //! Returns the step between frame x values.
- real xstep() const { return _xstep; }
/*! \brief
* Sets the values reported as x values for frames.
*/
//! Returns a reference to a given array element.
real &value(int row, int col)
{
- GMX_ASSERT(row >= 0 && row < _nrows, "Row index out of range");
- GMX_ASSERT(col >= 0 && col < columnCount(), "Column index out of range");
- GMX_ASSERT(_value != NULL, "Data array not allocated");
- return _value[row * columnCount() + col];
- }
- //! Returns a given array element.
- const real &value(int row, int col) const
- {
- GMX_ASSERT(row >= 0 && row < _nrows, "Row index out of range");
+ GMX_ASSERT(row >= 0 && row < rowCount(), "Row index out of range");
GMX_ASSERT(col >= 0 && col < columnCount(), "Column index out of range");
- GMX_ASSERT(_value != NULL, "Data array not allocated");
+ GMX_ASSERT(isAllocated(), "Data array not allocated");
return _value[row * columnCount() + col];
}
/*! \brief
private:
int _nrows;
- real *_value;
+ std::vector<real> _value;
real _xstart;
real _xstep;
bool _bReady;
// TODO: These statements cause Doxygen to generate confusing
// documentation.
- using AbstractAnalysisArrayData::rowCount;
using AbstractAnalysisArrayData::setColumnCount;
using AbstractAnalysisArrayData::setRowCount;
using AbstractAnalysisArrayData::allocateValues;
- using AbstractAnalysisArrayData::xstart;
- using AbstractAnalysisArrayData::xstep;
using AbstractAnalysisArrayData::setXAxis;
using AbstractAnalysisArrayData::value;
using AbstractAnalysisArrayData::setValue;
if (TESTUTILS_HAVE_REFDATA)
add_gmock_test(AnalysisDataUnitTests analysisdata-test
- analysisdata.cpp average.cpp datatest.cpp histogram.cpp
+ analysisdata.cpp arraydata.cpp
+ average.cpp datatest.cpp histogram.cpp
mock_module.cpp)
endif ()
--- /dev/null
+/*
+ *
+ * This source code is part of
+ *
+ * G R O M A C S
+ *
+ * GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, please consider that
+ * scientific software is very special. Version control is crucial -
+ * bugs must be traceable. We will be happy to consider code for
+ * inclusion in the official distribution, but derived work must not
+ * be called official GROMACS. Details are found in the README & COPYING
+ * files - if they are missing, get the official version at www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Tests for gmx::AnalysisArrayData functionality.
+ *
+ * These tests check the functionality of gmx::AnalysisArrayData and its base
+ * class gmx::AbstractAnalysisArrayData.
+ * Checking is done using gmx::test::AnalysisDataTestFixture and mock
+ * modules that implement gmx::AnalysisDataModuleInterface.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_analysisdata
+ */
+#include <memory>
+
+#include <gtest/gtest.h>
+
+#include "gromacs/analysisdata/arraydata.h"
+
+#include "datatest.h"
+
+namespace
+{
+
+/********************************************************************
+ * Tests for gmx::AnalysisArrayData.
+ */
+
+typedef gmx::test::AnalysisDataTestFixture AnalysisArrayDataTest;
+
+using gmx::test::END_OF_DATA;
+using gmx::test::END_OF_FRAME;
+static const real inputdata[] = {
+ 1.0, 0.0, 1.0, 2.0, END_OF_FRAME,
+ 2.0, 1.0, 1.0, 1.0, END_OF_FRAME,
+ 3.0, 2.0, 0.0, 0.0, END_OF_FRAME,
+ 4.0, 3.0, 2.0, 1.0, END_OF_FRAME,
+ END_OF_DATA
+};
+
+TEST_F(AnalysisArrayDataTest, CallsModuleCorrectly)
+{
+ gmx::test::AnalysisDataTestInput input(inputdata);
+ gmx::AnalysisArrayData data;
+ data.setXAxis(1.0, 1.0);
+ setupArrayData(input, &data);
+
+ ASSERT_NO_THROW(addStaticCheckerModule(input, &data));
+ ASSERT_NO_THROW(addStaticCheckerModule(input, &data));
+ ASSERT_NO_THROW(data.valuesReady());
+}
+
+TEST_F(AnalysisArrayDataTest, StorageWorks)
+{
+ gmx::test::AnalysisDataTestInput input(inputdata);
+ gmx::AnalysisArrayData data;
+ data.setXAxis(1.0, 1.0);
+ setupArrayData(input, &data);
+
+ ASSERT_NO_THROW(addStaticStorageCheckerModule(input, -1, &data));
+ ASSERT_NO_THROW(data.valuesReady());
+}
+
+} // namespace
* presentAllData() and presentDataFrame() are provided to push data from an
* AnalysisDataTestInput into an AnalysisData object. In typical tests, most
* checks are done during the these methods, by the added mock modules.
+ * setupArrayData() performs the same function for classes derived from
+ * AbstractAnalysisArrayData. In that case, the test should separately ensure
+ * that AbstractAnalysisArrayData::valuesReady() gets called.
*
* \todo
* Support for errors and for arbitrary multipoint data.
*/
static void presentDataFrame(const AnalysisDataTestInput &input, int row,
AnalysisDataHandle *handle);
+ /*! \brief
+ * Initializes an array data object from AnalysisDataTestInput.
+ *
+ * \tparam ArrayData Class derived from AbstractAnalysisArrayData.
+ *
+ * The ArrayData class should expose the setter methods
+ * (setColumnCount(), setRowCount(), allocateValues(), setValue())
+ * publicly or declare the fixture class as a friend.
+ * The X axis in \p data must be configured to match \p input before
+ * calling this method.
+ *
+ * Does not call AbstractAnalysisArrayData::valuesReady().
+ * The test must ensure that this method gets called, otherwise the
+ * mock modules never get called.
+ */
+ template <class ArrayData>
+ static void setupArrayData(const AnalysisDataTestInput &input,
+ ArrayData *data);
/*! \brief
* Adds a mock module that verifies output against
gmx::test::TestReferenceData data_;
};
+
+template <class ArrayData>
+void AnalysisDataTestFixture::setupArrayData(const AnalysisDataTestInput &input,
+ ArrayData *data)
+{
+ GMX_RELEASE_ASSERT(!input.isMultipoint(),
+ "Array data cannot be initialized from multipoint data");
+ GMX_RELEASE_ASSERT(data->columnCount() == 0 || data->columnCount() == input.columnCount(),
+ "Mismatching input and target data");
+ GMX_RELEASE_ASSERT(data->rowCount() == 0 || data->rowCount() == input.frameCount(),
+ "Mismatching input and target data");
+ data->setColumnCount(input.columnCount());
+ data->setRowCount(input.frameCount());
+ data->allocateValues();
+ for (int row = 0; row < input.frameCount(); ++row)
+ {
+ const AnalysisDataTestInputFrame &frame = input.frame(row);
+ EXPECT_FLOAT_EQ(frame.x(), data->xvalue(row));
+ const AnalysisDataTestInputPointSet &points = frame.points();
+ for (int column = 0; column < input.columnCount(); ++column)
+ {
+ data->setValue(row, column, points.y(column));
+ }
+ }
+}
+
} // namespace test
} // namespace gmx
* \author Teemu Murtola <teemu.murtola@cbr.su.se>
* \ingroup module_analysisdata
*/
+#include <memory>
+
#include <gtest/gtest.h>
#include "gromacs/analysisdata/analysisdata.h"
ASSERT_NO_THROW(presentAllData(input, &data));
}
+
+/********************************************************************
+ * Tests for gmx::AbstractAverageHistogram.
+ *
+ * This class derives from gmx::AbstractAnalysisArrayData, and is tested using
+ * corresponding facilities in gmx::test::AnalysisDataTestFixture.
+ */
+
+typedef gmx::test::AnalysisDataTestFixture AbstractAverageHistogramTest;
+
+// Input data for average histogram tests.
+static const real averageinputdata[] = {
+ 1.0, 2.0, 1.0, END_OF_FRAME,
+ 1.5, 1.0, 1.0, END_OF_FRAME,
+ 2.0, 3.0, 2.0, END_OF_FRAME,
+ 2.5, 4.0, 2.0, END_OF_FRAME,
+ 3.0, 2.0, 1.0, END_OF_FRAME,
+ 3.5, 0.0, 3.0, END_OF_FRAME,
+ 4.0, 1.0, 3.0, END_OF_FRAME,
+ END_OF_DATA
+};
+
+/*! \internal \brief
+ * Mock object for testing gmx::AbstractAverageHistogram.
+ *
+ * Exposes necessary methods from gmx::AbstractAverageHistogram to use with
+ * gmx::test::AnalysisDataTestFixture::setupArrayData().
+ */
+class MockAverageHistogram : public gmx::AbstractAverageHistogram
+{
+ public:
+ MockAverageHistogram() {}
+ explicit MockAverageHistogram(const gmx::AnalysisHistogramSettings &settings)
+ : AbstractAverageHistogram(settings)
+ {
+ }
+
+ using AbstractAverageHistogram::init;
+ using AbstractAverageHistogram::setColumnCount;
+ using AbstractAverageHistogram::setRowCount;
+ using AbstractAverageHistogram::allocateValues;
+ using AbstractAverageHistogram::setValue;
+};
+
+
+TEST_F(AbstractAverageHistogramTest, ClonesCorrectly)
+{
+ gmx::test::AnalysisDataTestInput input(averageinputdata);
+ MockAverageHistogram data(
+ gmx::histogramFromBins(1.0, input.frameCount(), 0.5).integerBins());
+ setupArrayData(input, &data);
+
+ ASSERT_NO_THROW(addStaticCheckerModule(input, &data));
+ std::auto_ptr<gmx::AbstractAverageHistogram> copy(data.clone());
+ ASSERT_NO_THROW(addStaticCheckerModule(input, copy.get()));
+ ASSERT_NO_THROW(copy->done());
+ ASSERT_NO_THROW(data.done());
+ std::auto_ptr<gmx::AbstractAverageHistogram> copy2(data.clone());
+ ASSERT_NO_THROW(addStaticCheckerModule(input, copy2.get()));
+ ASSERT_NO_THROW(copy2->done());
+}
+
+
+TEST_F(AbstractAverageHistogramTest, ResamplesAtDoubleBinWidth)
+{
+ gmx::test::AnalysisDataTestInput input(averageinputdata);
+ MockAverageHistogram data(
+ gmx::histogramFromBins(1.0, input.frameCount(), 0.5).integerBins());
+ setupArrayData(input, &data);
+
+ ASSERT_NO_THROW(addStaticCheckerModule(input, &data));
+ ASSERT_NO_THROW(addReferenceCheckerModule("InputData", &data));
+ std::auto_ptr<gmx::AbstractAverageHistogram> resampled(
+ data.resampleDoubleBinWidth(false));
+ ASSERT_NO_THROW(addReferenceCheckerModule("ResampledHistogram", resampled.get()));
+ ASSERT_NO_THROW(data.done());
+ ASSERT_NO_THROW(resampled->done());
+}
+
+
+TEST_F(AbstractAverageHistogramTest, ResamplesAtDoubleBinWidthWithIntegerBins)
+{
+ gmx::test::AnalysisDataTestInput input(averageinputdata);
+ MockAverageHistogram data(
+ gmx::histogramFromBins(1.0, input.frameCount(), 0.5).integerBins());
+ setupArrayData(input, &data);
+
+ ASSERT_NO_THROW(addStaticCheckerModule(input, &data));
+ ASSERT_NO_THROW(addReferenceCheckerModule("InputData", &data));
+ std::auto_ptr<gmx::AbstractAverageHistogram> resampled(
+ data.resampleDoubleBinWidth(true));
+ ASSERT_NO_THROW(addReferenceCheckerModule("ResampledHistogram", resampled.get()));
+ ASSERT_NO_THROW(data.done());
+ ASSERT_NO_THROW(resampled->done());
+}
+
} // namespace
--- /dev/null
+<?xml version="1.0"?>
+<ReferenceData>
+ <Compound Name="InputData" Subtype="AnalysisData">
+ <Compound Name="Frame0" Subtype="DataFrame">
+ <Real Name="X">1.000000</Real>
+ <Compound Name="Y" Subtype="SequenceReal">
+ <Int Name="Length">2</Int>
+ <Real>2.000000</Real>
+ <Real>1.000000</Real>
+ </Compound>
+ </Compound>
+ <Compound Name="Frame1" Subtype="DataFrame">
+ <Real Name="X">1.500000</Real>
+ <Compound Name="Y" Subtype="SequenceReal">
+ <Int Name="Length">2</Int>
+ <Real>1.000000</Real>
+ <Real>1.000000</Real>
+ </Compound>
+ </Compound>
+ <Compound Name="Frame2" Subtype="DataFrame">
+ <Real Name="X">2.000000</Real>
+ <Compound Name="Y" Subtype="SequenceReal">
+ <Int Name="Length">2</Int>
+ <Real>3.000000</Real>
+ <Real>2.000000</Real>
+ </Compound>
+ </Compound>
+ <Compound Name="Frame3" Subtype="DataFrame">
+ <Real Name="X">2.500000</Real>
+ <Compound Name="Y" Subtype="SequenceReal">
+ <Int Name="Length">2</Int>
+ <Real>4.000000</Real>
+ <Real>2.000000</Real>
+ </Compound>
+ </Compound>
+ <Compound Name="Frame4" Subtype="DataFrame">
+ <Real Name="X">3.000000</Real>
+ <Compound Name="Y" Subtype="SequenceReal">
+ <Int Name="Length">2</Int>
+ <Real>2.000000</Real>
+ <Real>1.000000</Real>
+ </Compound>
+ </Compound>
+ <Compound Name="Frame5" Subtype="DataFrame">
+ <Real Name="X">3.500000</Real>
+ <Compound Name="Y" Subtype="SequenceReal">
+ <Int Name="Length">2</Int>
+ <Real>0.000000</Real>
+ <Real>3.000000</Real>
+ </Compound>
+ </Compound>
+ <Compound Name="Frame6" Subtype="DataFrame">
+ <Real Name="X">4.000000</Real>
+ <Compound Name="Y" Subtype="SequenceReal">
+ <Int Name="Length">2</Int>
+ <Real>1.000000</Real>
+ <Real>3.000000</Real>
+ </Compound>
+ </Compound>
+ </Compound>
+ <Compound Name="ResampledHistogram" Subtype="AnalysisData">
+ <Compound Name="Frame0" Subtype="DataFrame">
+ <Real Name="X">1.500000</Real>
+ <Compound Name="Y" Subtype="SequenceReal">
+ <Int Name="Length">2</Int>
+ <Real>3.000000</Real>
+ <Real>1.414214</Real>
+ </Compound>
+ </Compound>
+ <Compound Name="Frame1" Subtype="DataFrame">
+ <Real Name="X">2.500000</Real>
+ <Compound Name="Y" Subtype="SequenceReal">
+ <Int Name="Length">2</Int>
+ <Real>7.000000</Real>
+ <Real>2.828427</Real>
+ </Compound>
+ </Compound>
+ <Compound Name="Frame2" Subtype="DataFrame">
+ <Real Name="X">3.500000</Real>
+ <Compound Name="Y" Subtype="SequenceReal">
+ <Int Name="Length">2</Int>
+ <Real>2.000000</Real>
+ <Real>3.162278</Real>
+ </Compound>
+ </Compound>
+ </Compound>
+</ReferenceData>
--- /dev/null
+<?xml version="1.0"?>
+<ReferenceData>
+ <Compound Name="InputData" Subtype="AnalysisData">
+ <Compound Name="Frame0" Subtype="DataFrame">
+ <Real Name="X">1.000000</Real>
+ <Compound Name="Y" Subtype="SequenceReal">
+ <Int Name="Length">2</Int>
+ <Real>2.000000</Real>
+ <Real>1.000000</Real>
+ </Compound>
+ </Compound>
+ <Compound Name="Frame1" Subtype="DataFrame">
+ <Real Name="X">1.500000</Real>
+ <Compound Name="Y" Subtype="SequenceReal">
+ <Int Name="Length">2</Int>
+ <Real>1.000000</Real>
+ <Real>1.000000</Real>
+ </Compound>
+ </Compound>
+ <Compound Name="Frame2" Subtype="DataFrame">
+ <Real Name="X">2.000000</Real>
+ <Compound Name="Y" Subtype="SequenceReal">
+ <Int Name="Length">2</Int>
+ <Real>3.000000</Real>
+ <Real>2.000000</Real>
+ </Compound>
+ </Compound>
+ <Compound Name="Frame3" Subtype="DataFrame">
+ <Real Name="X">2.500000</Real>
+ <Compound Name="Y" Subtype="SequenceReal">
+ <Int Name="Length">2</Int>
+ <Real>4.000000</Real>
+ <Real>2.000000</Real>
+ </Compound>
+ </Compound>
+ <Compound Name="Frame4" Subtype="DataFrame">
+ <Real Name="X">3.000000</Real>
+ <Compound Name="Y" Subtype="SequenceReal">
+ <Int Name="Length">2</Int>
+ <Real>2.000000</Real>
+ <Real>1.000000</Real>
+ </Compound>
+ </Compound>
+ <Compound Name="Frame5" Subtype="DataFrame">
+ <Real Name="X">3.500000</Real>
+ <Compound Name="Y" Subtype="SequenceReal">
+ <Int Name="Length">2</Int>
+ <Real>0.000000</Real>
+ <Real>3.000000</Real>
+ </Compound>
+ </Compound>
+ <Compound Name="Frame6" Subtype="DataFrame">
+ <Real Name="X">4.000000</Real>
+ <Compound Name="Y" Subtype="SequenceReal">
+ <Int Name="Length">2</Int>
+ <Real>1.000000</Real>
+ <Real>3.000000</Real>
+ </Compound>
+ </Compound>
+ </Compound>
+ <Compound Name="ResampledHistogram" Subtype="AnalysisData">
+ <Compound Name="Frame0" Subtype="DataFrame">
+ <Real Name="X">1.000000</Real>
+ <Compound Name="Y" Subtype="SequenceReal">
+ <Int Name="Length">2</Int>
+ <Real>2.000000</Real>
+ <Real>1.000000</Real>
+ </Compound>
+ </Compound>
+ <Compound Name="Frame1" Subtype="DataFrame">
+ <Real Name="X">2.000000</Real>
+ <Compound Name="Y" Subtype="SequenceReal">
+ <Int Name="Length">2</Int>
+ <Real>4.000000</Real>
+ <Real>2.236068</Real>
+ </Compound>
+ </Compound>
+ <Compound Name="Frame2" Subtype="DataFrame">
+ <Real Name="X">3.000000</Real>
+ <Compound Name="Y" Subtype="SequenceReal">
+ <Int Name="Length">2</Int>
+ <Real>6.000000</Real>
+ <Real>2.236068</Real>
+ </Compound>
+ </Compound>
+ <Compound Name="Frame3" Subtype="DataFrame">
+ <Real Name="X">4.000000</Real>
+ <Compound Name="Y" Subtype="SequenceReal">
+ <Int Name="Length">2</Int>
+ <Real>1.000000</Real>
+ <Real>4.242640</Real>
+ </Compound>
+ </Compound>
+ </Compound>
+</ReferenceData>