* \author Teemu Murtola <teemu.murtola@cbr.su.se>
* \ingroup module_analysisdata
*/
-#include "gromacs/analysisdata/modules/average.h"
+#include "average.h"
#include <cmath>
#include "gromacs/analysisdata/dataframe.h"
+#include "gromacs/analysisdata/datastorage.h"
namespace gmx
{
+/********************************************************************
+ * AnalysisDataAverageModule
+ */
+
AnalysisDataAverageModule::AnalysisDataAverageModule()
{
setColumnCount(2);
}
-
AnalysisDataAverageModule::~AnalysisDataAverageModule()
{
}
-
int
AnalysisDataAverageModule::flags() const
{
return efAllowMultipoint | efAllowMulticolumn | efAllowMissing;
}
-
void
AnalysisDataAverageModule::dataStarted(AbstractAnalysisData *data)
{
nsamples_.resize(nrows);
}
-
void
AnalysisDataAverageModule::frameStarted(const AnalysisDataFrameHeader & /*header*/)
{
}
-
void
AnalysisDataAverageModule::pointsAdded(const AnalysisDataPointSetRef &points)
{
}
}
-
void
AnalysisDataAverageModule::frameFinished(const AnalysisDataFrameHeader & /*header*/)
{
}
-
void
AnalysisDataAverageModule::dataFinished()
{
valuesReady();
}
-
real
AnalysisDataAverageModule::average(int index) const
{
return value(index, 0);
}
-
real
AnalysisDataAverageModule::stddev(int index) const
{
return value(index, 1);
}
+
+/********************************************************************
+ * AnalysisDataFrameAverageModule
+ */
+
+class AnalysisDataFrameAverageModule::Impl
+{
+ public:
+ //! Storage implementation object.
+ AnalysisDataStorage storage_;
+ //! Number of samples in a frame.
+ int sampleCount_;
+};
+
+AnalysisDataFrameAverageModule::AnalysisDataFrameAverageModule()
+ : impl_(new Impl())
+{
+ setColumnCount(1);
+}
+
+AnalysisDataFrameAverageModule::~AnalysisDataFrameAverageModule()
+{
+}
+
+int
+AnalysisDataFrameAverageModule::flags() const
+{
+ return efAllowMultipoint | efAllowMulticolumn | efAllowMissing;
+}
+
+void
+AnalysisDataFrameAverageModule::dataStarted(AbstractAnalysisData *data)
+{
+ notifyDataStart();
+ impl_->storage_.startDataStorage(this);
+}
+
+void
+AnalysisDataFrameAverageModule::frameStarted(const AnalysisDataFrameHeader &header)
+{
+ impl_->sampleCount_ = 0;
+ AnalysisDataStorageFrame &frame = impl_->storage_.startFrame(header);
+ frame.setValue(0, 0.0);
+}
+
+void
+AnalysisDataFrameAverageModule::pointsAdded(const AnalysisDataPointSetRef &points)
+{
+ AnalysisDataStorageFrame &frame =
+ impl_->storage_.currentFrame(points.frameIndex());
+ for (int i = 0; i < points.columnCount(); ++i)
+ {
+ if (points.present(i))
+ {
+ const real y = points.y(i);
+ frame.value(0) += y;
+ impl_->sampleCount_ += 1;
+ }
+ }
+}
+
+void
+AnalysisDataFrameAverageModule::frameFinished(const AnalysisDataFrameHeader &header)
+{
+ AnalysisDataStorageFrame &frame =
+ impl_->storage_.currentFrame(header.index());
+ const int samples = impl_->sampleCount_;
+ if (samples > 0)
+ {
+ frame.value(0) /= samples;
+ }
+ impl_->storage_.finishFrame(header.index());
+}
+
+void
+AnalysisDataFrameAverageModule::dataFinished()
+{
+ notifyDataFinish();
+}
+
+AnalysisDataFrameRef
+AnalysisDataFrameAverageModule::tryGetDataFrameInternal(int index) const
+{
+ return impl_->storage_.tryGetDataFrame(index);
+}
+
+bool
+AnalysisDataFrameAverageModule::requestStorageInternal(int nframes)
+{
+ return impl_->storage_.requestStorage(nframes);
+}
+
} // namespace gmx
#include <vector>
+#include "../abstractdata.h"
#include "../arraydata.h"
#include "../datamodule.h"
+#include "../../utility/common.h"
namespace gmx
{
typedef boost::shared_ptr<AnalysisDataAverageModule>
AnalysisDataAverageModulePointer;
+/*! \brief
+ * Data module for averaging of columns for each frame.
+ *
+ * Output data has the same number of frames as the input data, but only one
+ * column.
+ * Each frame in the output contains the average of the column values in the
+ * corresponding frame of the input data.
+ *
+ * Multipoint data and missing data points are both supported. The average
+ * is always calculated over all data points present in a column.
+ *
+ * \inpublicapi
+ * \ingroup module_analysisdata
+ */
+class AnalysisDataFrameAverageModule : public AbstractAnalysisData,
+ public AnalysisDataModuleInterface
+{
+ public:
+ AnalysisDataFrameAverageModule();
+ virtual ~AnalysisDataFrameAverageModule();
+
+ virtual int flags() const;
+
+ virtual void dataStarted(AbstractAnalysisData *data);
+ virtual void frameStarted(const AnalysisDataFrameHeader &header);
+ virtual void pointsAdded(const AnalysisDataPointSetRef &points);
+ virtual void frameFinished(const AnalysisDataFrameHeader &header);
+ virtual void dataFinished();
+
+ private:
+ virtual AnalysisDataFrameRef tryGetDataFrameInternal(int index) const;
+ virtual bool requestStorageInternal(int nframes);
+
+ class Impl;
+
+ PrivateImplPointer<Impl> impl_;
+};
+
+//! Smart pointer to manage an AnalysisDataFrameAverageModule object.
+typedef boost::shared_ptr<AnalysisDataFrameAverageModule>
+ AnalysisDataFrameAverageModulePointer;
+
} // namespace gmx
#endif
*/
/*! \internal \file
* \brief
- * Tests for functionality of gmx::AnalysisDataAverageModule
+ * Tests for functionality of analysis data averaging modules.
*
- * These tests check that gmx::AnalysisDataAverageModule computes averages
- * correctly with simple input data.
+ * These tests check that gmx::AnalysisDataAverageModule and
+ * gmx::AnalysisDataFrameAverageModule compute averages correctly with simple
+ * input data.
* Checking is done using gmx::test::AnalysisDataTestFixture and reference
* data. Also the input data is written to the reference data to catch
* out-of-date reference.
namespace
{
-/********************************************************************
- * Tests for gmx::AnalysisDataAverageModule.
- */
-
-//! Test fixture for gmx::AnalysisDataAverageModule.
-typedef gmx::test::AnalysisDataTestFixture AverageModuleTest;
-
using gmx::test::END_OF_FRAME;
+using gmx::test::MPSTOP;
//! Input data for gmx::AnalysisDataAverageModule tests.
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
};
+//! Multipoint input data for gmx::AnalysisDataAverageModule tests.
+const real mpinputdata[] = {
+ 1.0, 0.0, 1.0, 2.0, MPSTOP,
+ 1.0, 0.0, MPSTOP,
+ 2.0, END_OF_FRAME,
+ 2.0, 1.0, 1.0, MPSTOP,
+ 2.0, END_OF_FRAME,
+ 3.0, 2.0, 0.0, 0.0, END_OF_FRAME
+};
+
+
+/********************************************************************
+ * Tests for gmx::AnalysisDataAverageModule.
+ */
+
+//! Test fixture for gmx::AnalysisDataAverageModule.
+typedef gmx::test::AnalysisDataTestFixture AverageModuleTest;
TEST_F(AverageModuleTest, BasicTest)
{
ASSERT_NO_THROW(presentAllData(input, &data));
}
+TEST_F(AverageModuleTest, HandlesMultipointData)
+{
+ gmx::test::AnalysisDataTestInput input(mpinputdata);
+ gmx::AnalysisData data;
+ data.setColumnCount(input.columnCount());
+ data.setMultipoint(true);
+ gmx::AnalysisDataAverageModulePointer module(
+ new gmx::AnalysisDataAverageModule);
+ data.addModule(module);
+
+ ASSERT_NO_THROW(addStaticCheckerModule(input, &data));
+ ASSERT_NO_THROW(addReferenceCheckerModule("InputData", &data));
+ ASSERT_NO_THROW(addReferenceCheckerModule("Average", module.get()));
+ ASSERT_NO_THROW(presentAllData(input, &data));
+}
+
TEST_F(AverageModuleTest, CanCustomizeXAxis)
{
gmx::test::AnalysisDataTestInput input(inputdata);
ASSERT_NO_THROW(presentAllData(input, &data));
}
+/********************************************************************
+ * Tests for gmx::AnalysisDataFrameAverageModule.
+ */
+
+//! Test fixture for gmx::AnalysisDataFrameAverageModule.
+typedef gmx::test::AnalysisDataTestFixture FrameAverageModuleTest;
+
+TEST_F(FrameAverageModuleTest, BasicTest)
+{
+ gmx::test::AnalysisDataTestInput input(inputdata);
+ gmx::AnalysisData data;
+ data.setColumnCount(input.columnCount());
+ gmx::AnalysisDataFrameAverageModulePointer module(
+ new gmx::AnalysisDataFrameAverageModule);
+ data.addModule(module);
+
+ ASSERT_NO_THROW(addStaticCheckerModule(input, &data));
+ ASSERT_NO_THROW(addReferenceCheckerModule("InputData", &data));
+ ASSERT_NO_THROW(addReferenceCheckerModule("FrameAverage", module.get()));
+ ASSERT_NO_THROW(presentAllData(input, &data));
+}
+
} // namespace
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <AnalysisData Name="InputData">
+ <DataFrame Name="Frame0">
+ <Real Name="X">1.000000</Real>
+ <Sequence Name="Y">
+ <Int Name="Length">3</Int>
+ <DataValue>
+ <Real Name="Value">0.000000</Real>
+ <Real Name="Error">0.000000</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">1.000000</Real>
+ <Real Name="Error">0.000000</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">2.000000</Real>
+ <Real Name="Error">0.000000</Real>
+ </DataValue>
+ </Sequence>
+ <Sequence Name="Y">
+ <Int Name="Length">2</Int>
+ <Int Name="FirstColumn">0</Int>
+ <Int Name="LastColumn">1</Int>
+ <DataValue>
+ <Real Name="Value">1.000000</Real>
+ <Real Name="Error">0.000000</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">0.000000</Real>
+ <Real Name="Error">0.000000</Real>
+ </DataValue>
+ </Sequence>
+ <Sequence Name="Y">
+ <Int Name="Length">1</Int>
+ <Int Name="FirstColumn">0</Int>
+ <Int Name="LastColumn">0</Int>
+ <DataValue>
+ <Real Name="Value">2.000000</Real>
+ <Real Name="Error">0.000000</Real>
+ </DataValue>
+ </Sequence>
+ </DataFrame>
+ <DataFrame Name="Frame1">
+ <Real Name="X">2.000000</Real>
+ <Sequence Name="Y">
+ <Int Name="Length">2</Int>
+ <Int Name="FirstColumn">0</Int>
+ <Int Name="LastColumn">1</Int>
+ <DataValue>
+ <Real Name="Value">1.000000</Real>
+ <Real Name="Error">0.000000</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">1.000000</Real>
+ <Real Name="Error">0.000000</Real>
+ </DataValue>
+ </Sequence>
+ <Sequence Name="Y">
+ <Int Name="Length">1</Int>
+ <Int Name="FirstColumn">0</Int>
+ <Int Name="LastColumn">0</Int>
+ <DataValue>
+ <Real Name="Value">2.000000</Real>
+ <Real Name="Error">0.000000</Real>
+ </DataValue>
+ </Sequence>
+ </DataFrame>
+ <DataFrame Name="Frame2">
+ <Real Name="X">3.000000</Real>
+ <Sequence Name="Y">
+ <Int Name="Length">3</Int>
+ <DataValue>
+ <Real Name="Value">2.000000</Real>
+ <Real Name="Error">0.000000</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">0.000000</Real>
+ <Real Name="Error">0.000000</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">0.000000</Real>
+ <Real Name="Error">0.000000</Real>
+ </DataValue>
+ </Sequence>
+ </DataFrame>
+ </AnalysisData>
+ <AnalysisData Name="Average">
+ <DataFrame Name="Frame0">
+ <Real Name="X">0.000000</Real>
+ <Sequence Name="Y">
+ <Int Name="Length">2</Int>
+ <DataValue>
+ <Real Name="Value">1.333333</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">0.745356</Real>
+ </DataValue>
+ </Sequence>
+ </DataFrame>
+ <DataFrame Name="Frame1">
+ <Real Name="X">1.000000</Real>
+ <Sequence Name="Y">
+ <Int Name="Length">2</Int>
+ <DataValue>
+ <Real Name="Value">0.500000</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">0.500000</Real>
+ </DataValue>
+ </Sequence>
+ </DataFrame>
+ <DataFrame Name="Frame2">
+ <Real Name="X">2.000000</Real>
+ <Sequence Name="Y">
+ <Int Name="Length">2</Int>
+ <DataValue>
+ <Real Name="Value">1.000000</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">1.000000</Real>
+ </DataValue>
+ </Sequence>
+ </DataFrame>
+ </AnalysisData>
+</ReferenceData>
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <AnalysisData Name="InputData">
+ <DataFrame Name="Frame0">
+ <Real Name="X">1.000000</Real>
+ <Sequence Name="Y">
+ <Int Name="Length">3</Int>
+ <DataValue>
+ <Real Name="Value">0.000000</Real>
+ <Real Name="Error">0.000000</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">1.000000</Real>
+ <Real Name="Error">0.000000</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">2.000000</Real>
+ <Real Name="Error">0.000000</Real>
+ </DataValue>
+ </Sequence>
+ </DataFrame>
+ <DataFrame Name="Frame1">
+ <Real Name="X">2.000000</Real>
+ <Sequence Name="Y">
+ <Int Name="Length">3</Int>
+ <DataValue>
+ <Real Name="Value">1.000000</Real>
+ <Real Name="Error">0.000000</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">1.000000</Real>
+ <Real Name="Error">0.000000</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">1.000000</Real>
+ <Real Name="Error">0.000000</Real>
+ </DataValue>
+ </Sequence>
+ </DataFrame>
+ <DataFrame Name="Frame2">
+ <Real Name="X">3.000000</Real>
+ <Sequence Name="Y">
+ <Int Name="Length">3</Int>
+ <DataValue>
+ <Real Name="Value">2.000000</Real>
+ <Real Name="Error">0.000000</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">0.000000</Real>
+ <Real Name="Error">0.000000</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">0.000000</Real>
+ <Real Name="Error">0.000000</Real>
+ </DataValue>
+ </Sequence>
+ </DataFrame>
+ </AnalysisData>
+ <AnalysisData Name="FrameAverage">
+ <DataFrame Name="Frame0">
+ <Real Name="X">1.000000</Real>
+ <Sequence Name="Y">
+ <Int Name="Length">1</Int>
+ <DataValue>
+ <Real Name="Value">1.000000</Real>
+ </DataValue>
+ </Sequence>
+ </DataFrame>
+ <DataFrame Name="Frame1">
+ <Real Name="X">2.000000</Real>
+ <Sequence Name="Y">
+ <Int Name="Length">1</Int>
+ <DataValue>
+ <Real Name="Value">1.000000</Real>
+ </DataValue>
+ </Sequence>
+ </DataFrame>
+ <DataFrame Name="Frame2">
+ <Real Name="X">3.000000</Real>
+ <Sequence Name="Y">
+ <Int Name="Length">1</Int>
+ <DataValue>
+ <Real Name="Value">0.666667</Real>
+ </DataValue>
+ </Sequence>
+ </DataFrame>
+ </AnalysisData>
+</ReferenceData>
*/
#include "angle.h"
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "pbc.h"
-#include "vec.h"
+#include "gromacs/legacyheaders/pbc.h"
+#include "gromacs/legacyheaders/vec.h"
#include "gromacs/analysisdata/analysisdata.h"
#include "gromacs/analysisdata/modules/plot.h"
Angle::Angle()
: TrajectoryAnalysisModule(name, shortDescription),
- sel1info_(NULL), sel2info_(NULL),
- bSplit1_(false), bSplit2_(false), bMulti_(false), bAll_(false),
- bDumpDist_(false), natoms1_(0), natoms2_(0), vt0_(NULL)
+ sel1info_(NULL), sel2info_(NULL), natoms1_(0), natoms2_(0)
{
- registerAnalysisDataset(&data_, "angle");
+ averageModule_.reset(new AnalysisDataFrameAverageModule());
+ angles_.addModule(averageModule_);
+
+ registerAnalysisDataset(&angles_, "angle");
+ registerBasicDataset(averageModule_.get(), "average");
}
Angle::~Angle()
{
- delete[] vt0_;
+ for (size_t g = 0; g < vt0_.size(); ++g)
+ {
+ delete [] vt0_[g];
+ }
}
"The type of the angle is specified with [TT]-g1[tt] and [TT]-g2[tt].",
"If [TT]-g1[tt] is [TT]angle[tt] or [TT]dihedral[tt], [TT]-g2[tt]",
"should not be specified.",
- "In this case, one selection is required, and it should contain",
- "triplets or quartets of positions that define the angles to be",
- "calculated.",
- "If [TT]-g1[tt] is not [TT]angle[tt] or [TT]dihedral[tt], [TT]-g2[tt]",
- "should not be [TT]none[tt], and the two options define two vectors",
- "for the calculation. For vectors ([TT]vector[tt]), a selection with",
- "pairs of positions is required, and for planes ([TT]plane[tt]),",
- "triplets of positions are required.",
- "If both vectors are specified by positions, the number of vectors",
- "should be the same in both selections.",
- "[TT]-g2 sphnorm[tt] requires a reference selection that defines",
- "the center of the sphere.",
- "[TT]-g2 z[tt] does not require any selection.[PAR]",
- "With [TT]-split1[tt], the positions for [TT]-g1[tt] are specified",
- "using N separate selections with M positions each, instead of the",
- "default M*N positions in one selection.",
- "[TT]-split2[tt] does the same for [TT]-g2[tt].[PAR]",
+ "In this case, [TT]-group1[tt] should specify one selection,",
+ "and it should contain triplets or quartets of positions that define",
+ "the angles to be calculated.[PAR]",
+ "If [TT]-g1[tt] is [TT]vector[tt] or [TT]plane[tt], [TT]-group1[tt]",
+ "should specify a selection that has either pairs ([TT]vector[tt])",
+ "or triplets ([TT]plane[tt]) of positions. For vectors, the positions",
+ "set the endpoints of the vector, and for planes, the three positions",
+ "are used to calculate the normal of the plane. In both cases,",
+ "[TT]-g2[tt] specifies the other vector to use (see below).[PAR]",
+ "With [TT]-g2 vector[tt] or [TT]-g2 plane[tt], [TT]-group2[tt] should",
+ "specify another set of vectors. Both selections should specify the",
+ "same number of vectors.[PAR]",
+ "With [TT]-g2 sphnorm[tt], [TT]-group2[tt] should specify a single",
+ "position that is the center of the sphere. The second vector is then",
+ "calculated as the vector from the center to the midpoint of the",
+ "positions specified by [TT]-group1[tt].[PAR]",
+ "With [TT]-g2 z[tt], [TT]-group2[tt] is not necessary, and angles",
+ "between the first vectors and the positive Z axis are calculated.[PAR]",
+ "With [TT]-g2 t0[tt], [TT]-group2[tt] is not necessary, and angles",
+ "are calculated from the vectors as they are in the first frame.[PAR]",
"There are two options for output:",
- "[TT]-o[tt] writes an xvgr file with the time and the average angle",
+ "[TT]-oav[tt] writes an xvgr file with the time and the average angle",
"for each frame.",
- "With [TT]-all[tt], also the individual angles are written (only",
- "supported for static selections).",
+ "[TT]-oall[tt] writes all the individual angles."
+ /* TODO: Consider if the dump option is necessary and how to best
+ * implement it.
"[TT]-od[tt] can be used to dump all the individual angles,",
"each on a separate line. This format is better suited for",
"further processing, e.g., if angles from multiple runs are needed."
+ */
};
static const char *const cGroup1TypeEnum[] =
{ "angle", "dihedral", "vector", "plane", NULL };
options->setDescription(concatenateStrings(desc));
- options->addOption(FileNameOption("o").filetype(eftPlot).outputFile()
- .store(&fnAngle_).defaultBasename("angle")
- .description("Computed angles"));
- options->addOption(FileNameOption("od").filetype(eftPlot).outputFile()
- .store(&fnDump_).defaultBasename("angdump")
- .description("Individual angles on separate lines"));
+ options->addOption(FileNameOption("oav").filetype(eftPlot).outputFile()
+ .store(&fnAverage_).defaultBasename("angaver")
+ .description("Average angles as a function of time"));
+ options->addOption(FileNameOption("oall").filetype(eftPlot).outputFile()
+ .store(&fnAll_).defaultBasename("angles")
+ .description("All angles as a function of time"));
+ // TODO: Add histogram output.
options->addOption(StringOption("g1").enumValue(cGroup1TypeEnum)
.defaultEnumIndex(0).store(&g1type_)
options->addOption(StringOption("g2").enumValue(cGroup2TypeEnum)
.defaultEnumIndex(0).store(&g2type_)
.description("Type of second vector group"));
- options->addOption(BooleanOption("split1").store(&bSplit1_)
- .description("Each position of first group in separate selection"));
- options->addOption(BooleanOption("split2").store(&bSplit2_)
- .description("Each position of second group in separate selection"));
- options->addOption(BooleanOption("multi").store(&bMulti_)
- .description("Analyze multiple sets of angles/dihedrals"));
- options->addOption(BooleanOption("all").store(&bAll_)
- .description("Print individual angles together with the average"));
- options->addOption(BooleanOption("dumpd").store(&bDumpDist_)
- .description("Write also distances with -od"));
-
- sel1info_ = options->addOption(SelectionOption("group1").multiValue()
- .required().dynamicOnlyWhole().storeVector(&sel1_)
+
+ // TODO: Allow multiple angles to be computed in one invocation.
+ // Most of the code already supports it, but requires a solution for
+ // Redmine issue #1010.
+ // TODO: Consider what is the best way to support dynamic selections.
+ // Again, most of the code already supports it, but it needs to be
+ // considered how should -oall work, and additional checks should be added.
+ sel1info_ = options->addOption(SelectionOption("group1")
+ .required().onlyStatic().storeVector(&sel1_)
.description("First analysis/vector selection"));
- sel2info_ = options->addOption(SelectionOption("group2").multiValue()
- .dynamicOnlyWhole().storeVector(&sel2_)
+ sel2info_ = options->addOption(SelectionOption("group2")
+ .onlyStatic().storeVector(&sel2_)
.description("Second analysis/vector selection"));
}
void
Angle::optionsFinished(Options *options, TrajectoryAnalysisSettings *settings)
{
- // Validity checks.
bool bSingle = (g1type_[0] == 'a' || g1type_[0] == 'd');
if (bSingle && g2type_[0] != 'n')
GMX_THROW(InconsistentInputError("Should specify a second group (-g2) "
"if the first group is not an angle or a dihedral"));
}
- if (bSingle && bDumpDist_)
- {
- GMX_THROW(InconsistentInputError("Cannot calculate distances with -g1 angle or dihedral"));
- // bDumpDist_ = false;
- }
- if (bMulti_ && !bSingle)
- {
- GMX_THROW(InconsistentInputError("-mult can only be combined with -g1 angle or dihedral"));
- }
- if (bMulti_ && bSplit1_)
- {
- GMX_THROW(InconsistentInputError("-mult can not be combined with -split1"));
- }
- if (bMulti_ && bAll_)
- {
- GMX_THROW(InconsistentInputError("-mult and -all are mutually exclusive options"));
- }
-
- if (bAll_)
- {
- sel1info_->setOnlyStatic(true);
- }
// Set up the number of positions per angle.
switch (g1type_[0])
{
GMX_THROW(InconsistentInputError("Cannot provide a second selection (-group2) with -g2 t0 or z"));
}
-
- if (!bMulti_)
- {
- sel1info_->setValueCount(bSplit1_ ? natoms1_ : 1);
- }
- if (natoms2_ > 0)
- {
- sel2info_->setValueCount(bSplit2_ ? natoms2_ : 1);
- }
}
Angle::checkSelections(const SelectionList &sel1,
const SelectionList &sel2) const
{
- if (bMulti_)
- {
- for (size_t g = 0; g < sel1.size(); ++g)
- {
- if (sel1[g].posCount() % natoms1_ != 0)
- {
- GMX_THROW(InconsistentInputError(formatString(
- "Number of positions in selection %d not divisible by %d",
- static_cast<int>(g + 1), natoms1_)));
- }
- }
- return;
- }
-
- int na1 = sel1[0].posCount();
- int na2 = (natoms2_ > 0) ? sel2[0].posCount() : 0;
-
- if (!bSplit1_ && natoms1_ > 1 && na1 % natoms1_ != 0)
+ if (natoms2_ > 0 && sel1.size() != sel2.size())
{
- GMX_THROW(InconsistentInputError(formatString(
- "Number of positions in the first group not divisible by %d",
- natoms1_)));
- }
- if (!bSplit2_ && natoms2_ > 1 && na2 % natoms2_ != 0)
- {
- GMX_THROW(InconsistentInputError(formatString(
- "Number of positions in the second group not divisible by %d",
- natoms2_)));
+ GMX_THROW(InconsistentInputError(
+ "-group1 and -group2 should specify the same number of selections"));
}
- if (bSplit1_)
+ for (size_t g = 0; g < sel1.size(); ++g)
{
- for (int g = 1; g < natoms1_; ++g)
+ int na1 = sel1[g].posCount();
+ int na2 = (natoms2_ > 0) ? sel2[g].posCount() : 0;
+ if (natoms1_ > 1 && na1 % natoms1_ != 0)
{
- if (sel1[g].posCount() != na1)
- {
- GMX_THROW(InconsistentInputError(
- "All selections in the first group should contain "
- "the same number of positions"));
- }
+ GMX_THROW(InconsistentInputError(formatString(
+ "Number of positions in selection %d in the first group not divisible by %d",
+ static_cast<int>(g + 1), natoms1_)));
}
- }
- else
- {
- na1 /= natoms1_;
- }
- if (natoms2_ > 1)
- {
- if (bSplit2_)
+ if (natoms2_ > 1 && na2 % natoms2_ != 0)
{
- for (int g = 1; g < natoms2_; ++g)
- {
- if (sel2[g].posCount() != na2)
- {
- GMX_THROW(InconsistentInputError(
- "All selections in the second group should contain "
- "the same number of positions"));
- }
- }
+ GMX_THROW(InconsistentInputError(formatString(
+ "Number of positions in selection %d in the second group not divisible by %d",
+ static_cast<int>(g + 1), natoms2_)));
}
- else
+ if (natoms1_ > 0 && natoms2_ > 1 && na1 / natoms1_ != na2 / natoms2_)
{
- na2 /= natoms2_;
+ GMX_THROW(InconsistentInputError(
+ "Number of vectors defined by the two groups are not the same"));
+ }
+ if (g2type_[0] == 's' && sel2[g].posCount() != 1)
+ {
+ GMX_THROW(InconsistentInputError(
+ "The second group should contain a single position with -g2 sphnorm"));
}
- }
- if (natoms1_ > 0 && natoms2_ > 1 && na1 != na2)
- {
- GMX_THROW(InconsistentInputError(
- "Number of vectors defined by the two groups are not the same"));
- }
- if (g2type_[0] == 's' && sel2[0].posCount() != 1)
- {
- GMX_THROW(InconsistentInputError(
- "The second group should contain a single position with -g2 sphnorm"));
}
}
{
checkSelections(sel1_, sel2_);
- if (bMulti_)
- {
- data_.setColumnCount(sel1_.size());
- }
- else if (bAll_)
+ angles_.setColumnCount(sel1_[0].posCount() / natoms1_);
+
+ if (g2type_ == "t0")
{
- int na = sel1_[0].posCount();
- if (!bSplit1_)
+ vt0_.resize(sel1_.size());
+ for (size_t g = 0; g < sel1_.size(); ++g)
{
- na /= natoms1_;
+ vt0_[g] = new rvec[sel1_[g].posCount() / natoms1_];
}
- data_.setColumnCount(na + 1);
}
- else
+
+ if (!fnAverage_.empty())
{
- data_.setColumnCount(1);
+ AnalysisDataPlotModulePointer plotm(
+ new AnalysisDataPlotModule(settings.plotSettings()));
+ plotm->setFileName(fnAverage_);
+ plotm->setTitle("Average angle");
+ plotm->setXAxisIsTime();
+ plotm->setYLabel("Angle (degrees)");
+ // TODO: Add legends
+ averageModule_->addModule(plotm);
}
- if (g2type_ == "t0")
+ if (!fnAll_.empty())
{
- int na = sel1_[0].posCount();
- if (!bSplit1_)
- {
- na /= natoms1_;
- }
- vt0_ = new rvec[na];
+ AnalysisDataPlotModulePointer plotm(
+ new AnalysisDataPlotModule(settings.plotSettings()));
+ plotm->setFileName(fnAll_);
+ plotm->setTitle("Angle");
+ plotm->setXAxisIsTime();
+ plotm->setYLabel("Angle (degrees)");
+ // TODO: Add legends? (there can be a massive amount of columns)
+ angles_.addModule(plotm);
}
-
- AnalysisDataPlotModulePointer plotm(
- new AnalysisDataPlotModule(settings.plotSettings()));
- plotm->setFileName(fnAngle_);
- plotm->setTitle("Angle");
- plotm->setXAxisIsTime();
- plotm->setYLabel("Angle (degrees)");
- data_.addModule(plotm);
}
//! Helper method to process selections into an array of coordinates.
static void
-copy_pos(const SelectionList &sel, bool bSplit, int natoms,
- int firstg, int first, rvec x[])
+copy_pos(const SelectionList &sel, int natoms, int g, int first, rvec x[])
{
- if (bSplit)
+ for (int k = 0; k < natoms; ++k)
{
- for (int k = 0; k < natoms; ++k)
- {
- copy_rvec(sel[firstg + k].position(first).x(), x[k]);
- }
- }
- else
- {
- for (int k = 0; k < natoms; ++k)
- {
- copy_rvec(sel[firstg].position(first + k).x(), x[k]);
- }
+ copy_rvec(sel[g].position(first + k).x(), x[k]);
}
}
-//! Helper method to calculate a vector from two or three positions..
+//! Helper method to calculate a vector from two or three positions.
static void
calc_vec(int natoms, rvec x[], t_pbc *pbc, rvec xout, rvec cout)
{
Angle::analyzeFrame(int frnr, const t_trxframe &fr, t_pbc *pbc,
TrajectoryAnalysisModuleData *pdata)
{
- AnalysisDataHandle dh = pdata->dataHandle(data_);
+ AnalysisDataHandle dh = pdata->dataHandle(angles_);
const SelectionList &sel1 = pdata->parallelSelections(sel1_);
const SelectionList &sel2 = pdata->parallelSelections(sel2_);
checkSelections(sel1, sel2);
- rvec v1, v2;
- rvec c1, c2;
- switch (g2type_[0])
- {
- case 'z':
- clear_rvec(v2);
- v2[ZZ] = 1.0;
- clear_rvec(c2);
- break;
- case 's':
- copy_rvec(sel2_[0].position(0).x(), c2);
- break;
- }
-
dh.startFrame(frnr, fr.time);
- int incr1 = bSplit1_ ? 1 : natoms1_;
- int incr2 = bSplit2_ ? 1 : natoms2_;
- int ngrps = bMulti_ ? sel1_.size() : 1;
-
- for (int g = 0; g < ngrps; ++g)
+ for (size_t g = 0; g < sel1_.size(); ++g)
{
- real ave = 0.0;
- int n = 0;
- int i, j;
- for (i = j = 0; i < sel1[g].posCount(); i += incr1)
+ rvec v1, v2;
+ rvec c1, c2;
+ switch (g2type_[0])
+ {
+ case 'z':
+ clear_rvec(v2);
+ v2[ZZ] = 1.0;
+ clear_rvec(c2);
+ break;
+ case 's':
+ copy_rvec(sel2_[g].position(0).x(), c2);
+ break;
+ }
+ for (int i = 0, j = 0, n = 0;
+ i < sel1[g].posCount();
+ i += natoms1_, j += natoms2_, ++n)
{
rvec x[4];
real angle;
- copy_pos(sel1, bSplit1_, natoms1_, g, i, x);
+ copy_pos(sel1, natoms1_, g, i, x);
switch (g1type_[0])
{
case 'a':
{
case 'v':
case 'p':
- copy_pos(sel2, bSplit2_, natoms2_, 0, j, x);
+ copy_pos(sel2, natoms2_, 0, j, x);
calc_vec(natoms2_, x, pbc, v2, c2);
- j += incr2;
break;
case 't':
// FIXME: This is not parallelizable.
if (frnr == 0)
{
- copy_rvec(v1, vt0_[n]);
+ copy_rvec(v1, vt0_[g][n]);
}
- copy_rvec(vt0_[n], v2);
+ copy_rvec(vt0_[g][n], v2);
break;
case 'z':
c1[XX] = c1[YY] = 0.0;
default:
GMX_THROW(InternalError("invalid -g1 value"));
}
- angle *= RAD2DEG;
- /* TODO: add support for -od and -dumpd
+ /* TODO: Should we also calculate distances like g_sgangle?
+ * Could be better to leave that for a separate tool.
real dist = 0.0;
if (bDumpDist_)
{
}
}
*/
- if (bAll_)
- {
- dh.setPoint(n + 1, angle);
- }
- ave += angle;
- ++n;
- }
- if (n > 0)
- {
- ave /= n;
+ dh.setPoint(n, angle * RAD2DEG);
}
- dh.setPoint(g, ave);
}
dh.finishFrame();
}
#define GMX_TRAJECTORYANALYSIS_MODULES_ANGLE_H
#include <string>
+#include <vector>
#include "../analysismodule.h"
#include "gromacs/analysisdata/analysisdata.h"
+#include "gromacs/analysisdata/modules/average.h"
#include "gromacs/selection/selection.h"
namespace gmx
SelectionList sel2_;
SelectionOptionInfo *sel1info_;
SelectionOptionInfo *sel2info_;
- std::string fnAngle_;
- std::string fnDump_;
+ std::string fnAverage_;
+ std::string fnAll_;
std::string g1type_;
std::string g2type_;
- bool bSplit1_;
- bool bSplit2_;
- bool bMulti_;
- bool bAll_;
- bool bDumpDist_;
- AnalysisData data_;
+ AnalysisData angles_;
+ AnalysisDataFrameAverageModulePointer averageModule_;
int natoms1_;
int natoms2_;
- rvec *vt0_;
+ // TODO: It is not possible to put rvec into a container.
+ std::vector<rvec *> vt0_;
// Copy and assign disallowed by base.
};
gmx_add_unit_test(TrajectoryAnalysisUnitTests trajectoryanalysis-test
moduletest.cpp
+ angle.cpp
select.cpp)
add_executable(test_selection test_selection.cpp)
--- /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 functionality of the "angle" trajectory analysis module.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_trajectoryanalysis
+ */
+#include <gtest/gtest.h>
+
+#include "gromacs/trajectoryanalysis/modules/angle.h"
+
+#include "testutils/cmdlinetest.h"
+
+#include "moduletest.h"
+
+namespace
+{
+
+using gmx::test::CommandLine;
+
+/********************************************************************
+ * Tests for gmx::analysismodules::Angle.
+ */
+
+//! Test fixture for the angle analysis module.
+typedef gmx::test::TrajectoryAnalysisModuleTestFixture<gmx::analysismodules::Angle>
+ AngleModuleTest;
+
+TEST_F(AngleModuleTest, ComputesSimpleAngles)
+{
+ const char *const cmdline[] = {
+ "angle",
+ "-g1", "angle", "-group1", "resname RA1 RA2 and name A1 A2 A3"
+ };
+ setTopology("angle.gro");
+ runTest(CommandLine::create(cmdline));
+}
+
+TEST_F(AngleModuleTest, ComputesDihedrals)
+{
+ const char *const cmdline[] = {
+ "angle",
+ "-g1", "dihedral", "-group1", "resname RD1 RD2 RD3 and name A1 A2 A3 A4"
+ };
+ setTopology("angle.gro");
+ runTest(CommandLine::create(cmdline));
+}
+
+TEST_F(AngleModuleTest, ComputesVectorPairAngles)
+{
+ const char *const cmdline[] = {
+ "angle",
+ "-g1", "vector", "-group1", "resname RV1 RV2 and name A1 A2",
+ "-g2", "vector", "-group2", "resname RV3 RV4 and name A1 A2"
+ };
+ setTopology("angle.gro");
+ runTest(CommandLine::create(cmdline));
+}
+
+TEST_F(AngleModuleTest, ComputesVectorPlanePairAngles)
+{
+ const char *const cmdline[] = {
+ "angle",
+ "-g1", "vector", "-group1", "resname RV1 RV2 and name A1 A2",
+ "-g2", "plane", "-group2", "resname RP1 RP2 and name A1 A2 A3"
+ };
+ setTopology("angle.gro");
+ runTest(CommandLine::create(cmdline));
+}
+
+TEST_F(AngleModuleTest, ComputesPlaneZAxisAngles)
+{
+ const char *const cmdline[] = {
+ "angle",
+ "-g1", "plane", "-group1", "resname RP1 RP2 and name A1 A2 A3",
+ "-g2", "z"
+ };
+ setTopology("angle.gro");
+ runTest(CommandLine::create(cmdline));
+}
+
+TEST_F(AngleModuleTest, ComputesVectorSphereNormalZAxisAngles)
+{
+ const char *const cmdline[] = {
+ "angle",
+ "-g1", "vector", "-group1", "resname RV1 RV2 and name A1 A2",
+ "-g2", "sphnorm", "-group2", "cog of resname RS"
+ };
+ setTopology("angle.gro");
+ runTest(CommandLine::create(cmdline));
+}
+
+TEST_F(AngleModuleTest, ComputesVectorTimeZeroAngles)
+{
+ const char *const cmdline[] = {
+ "angle",
+ "-g1", "vector", "-group1", "resname RV1 RV2 RV3 RV4 and name A1 A2",
+ "-g2", "t0"
+ };
+ setTopology("angle.gro");
+ setTrajectory("angle.gro");
+ runTest(CommandLine::create(cmdline));
+}
+
+} // namespace
--- /dev/null
+Test system for different angles
+ 33
+ 1RA1 A1 1 0.000 0.000 0.000
+ 1RA1 A2 2 1.000 0.000 0.000
+ 1RA1 A3 3 1.500 0.500 0.000
+ 2RA2 A1 4 0.000 0.000 1.000
+ 2RA2 A2 5 1.000 0.000 1.000
+ 2RA2 A3 6 0.500 0.500 1.000
+ 3RD1 A1 7 0.000 0.000 2.000
+ 3RD1 A2 8 1.000 1.000 2.000
+ 3RD1 A3 9 2.000 1.000 2.000
+ 3RD1 A4 10 3.000 1.500 2.500
+ 4RD2 A1 11 0.000 0.000 3.000
+ 4RD2 A2 12 1.000 1.000 3.000
+ 4RD2 A3 13 2.000 1.000 3.000
+ 4RD2 A4 14 3.000 0.500 2.500
+ 5RD3 A1 15 0.000 0.000 4.000
+ 5RD3 A2 16 1.000 1.000 4.000
+ 5RD3 A3 17 2.000 1.000 4.000
+ 5RD3 A4 18 3.000 2.000 4.000
+ 6RV1 A1 19 7.000 5.000 5.000
+ 6RV1 A2 20 8.000 6.000 5.000
+ 7RV2 A1 21 7.000 7.000 5.000
+ 7RV2 A2 22 7.000 7.000 6.000
+ 8RV3 A1 23 6.000 5.000 7.000
+ 8RV3 A2 24 6.000 6.000 7.000
+ 9RV4 A1 25 8.000 8.000 7.000
+ 9RV4 A2 26 8.000 9.000 7.000
+ 10RP1 A1 27 4.000 4.000 8.000
+ 10RP1 A2 28 4.000 5.000 8.000
+ 10RP1 A3 29 5.000 4.000 8.000
+ 11RP2 A1 30 6.000 6.000 8.000
+ 11RP2 A2 31 7.000 6.000 8.000
+ 11RP2 A3 32 6.000 7.000 9.000
+ 12RS CC 33 5.000 5.000 5.000
+ 10.00000 10.00000 10.00000
+Test system for different angles
+ 33
+ 1RA1 A1 1 0.000 0.000 0.000
+ 1RA1 A2 2 1.000 0.000 0.000
+ 1RA1 A3 3 1.500 0.500 0.000
+ 2RA2 A1 4 0.000 0.000 1.000
+ 2RA2 A2 5 1.000 0.000 1.000
+ 2RA2 A3 6 0.500 0.500 1.000
+ 3RD1 A1 7 0.000 0.000 2.000
+ 3RD1 A2 8 1.000 1.000 2.000
+ 3RD1 A3 9 2.000 1.000 2.000
+ 3RD1 A4 10 3.000 1.500 2.500
+ 4RD2 A1 11 0.000 0.000 3.000
+ 4RD2 A2 12 1.000 1.000 3.000
+ 4RD2 A3 13 2.000 1.000 3.000
+ 4RD2 A4 14 3.000 0.500 2.500
+ 5RD3 A1 15 0.000 0.000 4.000
+ 5RD3 A2 16 1.000 1.000 4.000
+ 5RD3 A3 17 2.000 1.000 4.000
+ 5RD3 A4 18 3.000 2.000 4.000
+ 6RV1 A1 19 6.000 4.000 4.000
+ 6RV1 A2 20 7.000 5.000 4.000
+ 7RV2 A1 21 7.000 7.000 5.000
+ 7RV2 A2 22 8.000 7.000 6.000
+ 8RV3 A1 23 6.000 5.000 7.000
+ 8RV3 A2 24 6.000 4.000 7.000
+ 9RV4 A1 25 8.000 8.000 7.000
+ 9RV4 A2 26 9.000 8.000 7.000
+ 10RP1 A1 27 4.000 4.000 8.000
+ 10RP1 A2 28 4.000 5.000 8.000
+ 10RP1 A3 29 5.000 4.000 8.000
+ 11RP2 A1 30 6.000 6.000 8.000
+ 11RP2 A2 31 7.000 6.000 8.000
+ 11RP2 A3 32 6.000 7.000 9.000
+ 12RS CC 33 5.000 5.000 5.000
+ 10.00000 10.00000 10.00000
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <String Name="CommandLine">angle -g1 dihedral -group1 'resname RD1 RD2 RD3 and name A1 A2 A3 A4'</String>
+ <OutputData Name="Data">
+ <AnalysisData Name="angle">
+ <DataFrame Name="Frame0">
+ <Real Name="X">0.000000</Real>
+ <Sequence Name="Y">
+ <Int Name="Length">3</Int>
+ <DataValue>
+ <Real Name="Value">-135.000000</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">45.000000</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">180.000000</Real>
+ </DataValue>
+ </Sequence>
+ </DataFrame>
+ </AnalysisData>
+ <AnalysisData Name="average">
+ <DataFrame Name="Frame0">
+ <Real Name="X">0.000000</Real>
+ <Sequence Name="Y">
+ <Int Name="Length">1</Int>
+ <DataValue>
+ <Real Name="Value">30.000000</Real>
+ </DataValue>
+ </Sequence>
+ </DataFrame>
+ </AnalysisData>
+ </OutputData>
+</ReferenceData>
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <String Name="CommandLine">angle -g1 plane -group1 'resname RP1 RP2 and name A1 A2 A3' -g2 z</String>
+ <OutputData Name="Data">
+ <AnalysisData Name="angle">
+ <DataFrame Name="Frame0">
+ <Real Name="X">0.000000</Real>
+ <Sequence Name="Y">
+ <Int Name="Length">2</Int>
+ <DataValue>
+ <Real Name="Value">180.000000</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">45.000000</Real>
+ </DataValue>
+ </Sequence>
+ </DataFrame>
+ </AnalysisData>
+ <AnalysisData Name="average">
+ <DataFrame Name="Frame0">
+ <Real Name="X">0.000000</Real>
+ <Sequence Name="Y">
+ <Int Name="Length">1</Int>
+ <DataValue>
+ <Real Name="Value">112.500000</Real>
+ </DataValue>
+ </Sequence>
+ </DataFrame>
+ </AnalysisData>
+ </OutputData>
+</ReferenceData>
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <String Name="CommandLine">angle -g1 angle -group1 'resname RA1 RA2 and name A1 A2 A3'</String>
+ <OutputData Name="Data">
+ <AnalysisData Name="angle">
+ <DataFrame Name="Frame0">
+ <Real Name="X">0.000000</Real>
+ <Sequence Name="Y">
+ <Int Name="Length">2</Int>
+ <DataValue>
+ <Real Name="Value">135.000000</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">45.000000</Real>
+ </DataValue>
+ </Sequence>
+ </DataFrame>
+ </AnalysisData>
+ <AnalysisData Name="average">
+ <DataFrame Name="Frame0">
+ <Real Name="X">0.000000</Real>
+ <Sequence Name="Y">
+ <Int Name="Length">1</Int>
+ <DataValue>
+ <Real Name="Value">90.000000</Real>
+ </DataValue>
+ </Sequence>
+ </DataFrame>
+ </AnalysisData>
+ </OutputData>
+</ReferenceData>
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <String Name="CommandLine">angle -g1 vector -group1 'resname RV1 RV2 and name A1 A2' -g2 vector -group2 'resname RV3 RV4 and name A1 A2'</String>
+ <OutputData Name="Data">
+ <AnalysisData Name="angle">
+ <DataFrame Name="Frame0">
+ <Real Name="X">0.000000</Real>
+ <Sequence Name="Y">
+ <Int Name="Length">2</Int>
+ <DataValue>
+ <Real Name="Value">45.000000</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">90.000000</Real>
+ </DataValue>
+ </Sequence>
+ </DataFrame>
+ </AnalysisData>
+ <AnalysisData Name="average">
+ <DataFrame Name="Frame0">
+ <Real Name="X">0.000000</Real>
+ <Sequence Name="Y">
+ <Int Name="Length">1</Int>
+ <DataValue>
+ <Real Name="Value">67.500000</Real>
+ </DataValue>
+ </Sequence>
+ </DataFrame>
+ </AnalysisData>
+ </OutputData>
+</ReferenceData>
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <String Name="CommandLine">angle -g1 vector -group1 'resname RV1 RV2 and name A1 A2' -g2 plane -group2 'resname RP1 RP2 and name A1 A2 A3'</String>
+ <OutputData Name="Data">
+ <AnalysisData Name="angle">
+ <DataFrame Name="Frame0">
+ <Real Name="X">0.000000</Real>
+ <Sequence Name="Y">
+ <Int Name="Length">2</Int>
+ <DataValue>
+ <Real Name="Value">90.000000</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">45.000000</Real>
+ </DataValue>
+ </Sequence>
+ </DataFrame>
+ </AnalysisData>
+ <AnalysisData Name="average">
+ <DataFrame Name="Frame0">
+ <Real Name="X">0.000000</Real>
+ <Sequence Name="Y">
+ <Int Name="Length">1</Int>
+ <DataValue>
+ <Real Name="Value">67.500000</Real>
+ </DataValue>
+ </Sequence>
+ </DataFrame>
+ </AnalysisData>
+ </OutputData>
+</ReferenceData>
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <String Name="CommandLine">angle -g1 vector -group1 'resname RV1 RV2 and name A1 A2' -g2 sphnorm -group2 'cog of resname RS'</String>
+ <OutputData Name="Data">
+ <AnalysisData Name="angle">
+ <DataFrame Name="Frame0">
+ <Real Name="X">0.000000</Real>
+ <Sequence Name="Y">
+ <Int Name="Length">2</Int>
+ <DataValue>
+ <Real Name="Value">33.690067</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">79.975014</Real>
+ </DataValue>
+ </Sequence>
+ </DataFrame>
+ </AnalysisData>
+ <AnalysisData Name="average">
+ <DataFrame Name="Frame0">
+ <Real Name="X">0.000000</Real>
+ <Sequence Name="Y">
+ <Int Name="Length">1</Int>
+ <DataValue>
+ <Real Name="Value">56.832542</Real>
+ </DataValue>
+ </Sequence>
+ </DataFrame>
+ </AnalysisData>
+ </OutputData>
+</ReferenceData>
--- /dev/null
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+ <String Name="CommandLine">angle -g1 vector -group1 'resname RV1 RV2 RV3 RV4 and name A1 A2' -g2 t0</String>
+ <OutputData Name="Data">
+ <AnalysisData Name="angle">
+ <DataFrame Name="Frame0">
+ <Real Name="X">0.000000</Real>
+ <Sequence Name="Y">
+ <Int Name="Length">4</Int>
+ <DataValue>
+ <Real Name="Value">0.000000</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">0.000000</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">0.000000</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">0.000000</Real>
+ </DataValue>
+ </Sequence>
+ </DataFrame>
+ <DataFrame Name="Frame1">
+ <Real Name="X">0.000000</Real>
+ <Sequence Name="Y">
+ <Int Name="Length">4</Int>
+ <DataValue>
+ <Real Name="Value">0.000000</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">45.000000</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">180.000000</Real>
+ </DataValue>
+ <DataValue>
+ <Real Name="Value">90.000000</Real>
+ </DataValue>
+ </Sequence>
+ </DataFrame>
+ </AnalysisData>
+ <AnalysisData Name="average">
+ <DataFrame Name="Frame0">
+ <Real Name="X">0.000000</Real>
+ <Sequence Name="Y">
+ <Int Name="Length">1</Int>
+ <DataValue>
+ <Real Name="Value">0.000000</Real>
+ </DataValue>
+ </Sequence>
+ </DataFrame>
+ <DataFrame Name="Frame1">
+ <Real Name="X">0.000000</Real>
+ <Sequence Name="Y">
+ <Int Name="Length">1</Int>
+ <DataValue>
+ <Real Name="Value">78.750000</Real>
+ </DataValue>
+ </Sequence>
+ </DataFrame>
+ </AnalysisData>
+ </OutputData>
+</ReferenceData>
const AnalysisDataTestInputPointSet &points = frame.points(ps);
EXPECT_CALL(*this, pointsAdded(_))
.WillOnce(Invoke(StaticDataPointsChecker(&frame, &points, 0,
- data.columnCount())));
+ points.size())));
}
EXPECT_CALL(*this, frameFinished(_))
.WillOnce(Invoke(StaticDataFrameHeaderChecker(&frame)));