2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2010,2011,2012,2013,2014, by the GROMACS development team, led by
5 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6 * and including many others, as listed in the AUTHORS file in the
7 * top-level source directory and at http://www.gromacs.org.
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.
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.
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.
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.
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.
37 * Tests selection parsing and compilation.
39 * \author Teemu Murtola <teemu.murtola@gmail.com>
40 * \ingroup module_selection
42 #include <gtest/gtest.h>
44 #include "gromacs/options/basicoptions.h"
45 #include "gromacs/options/options.h"
46 #include "gromacs/selection/indexutil.h"
47 #include "gromacs/selection/selectioncollection.h"
48 #include "gromacs/selection/selection.h"
49 #include "gromacs/utility/arrayref.h"
50 #include "gromacs/utility/exceptions.h"
51 #include "gromacs/utility/flags.h"
52 #include "gromacs/utility/gmxregex.h"
53 #include "gromacs/utility/stringutil.h"
55 #include "testutils/refdata.h"
56 #include "testutils/testasserts.h"
57 #include "testutils/testfilemanager.h"
58 #include "testutils/testoptions.h"
65 /********************************************************************
66 * Test fixture for selection testing
69 class SelectionCollectionTest : public ::testing::Test
72 static int s_debugLevel;
74 SelectionCollectionTest();
75 ~SelectionCollectionTest();
77 void setAtomCount(int natoms)
79 ASSERT_NO_THROW_GMX(sc_.setTopology(NULL, natoms));
81 void loadTopology(const char *filename);
83 void loadIndexGroups(const char *filename);
85 gmx::test::TopologyManager topManager_;
86 gmx::SelectionCollection sc_;
87 gmx::SelectionList sel_;
90 gmx_ana_indexgrps_t *grps_;
93 int SelectionCollectionTest::s_debugLevel = 0;
95 GMX_TEST_OPTIONS(SelectionCollectionTestOptions, options)
97 options->addOption(gmx::IntegerOption("seldebug")
98 .store(&SelectionCollectionTest::s_debugLevel)
99 .description("Set selection debug level"));
102 SelectionCollectionTest::SelectionCollectionTest()
103 : top_(NULL), frame_(NULL), grps_(NULL)
105 topManager_.requestFrame();
106 sc_.setDebugLevel(s_debugLevel);
107 sc_.setReferencePosType("atom");
108 sc_.setOutputPosType("atom");
111 SelectionCollectionTest::~SelectionCollectionTest()
115 gmx_ana_indexgrps_free(grps_);
120 SelectionCollectionTest::loadTopology(const char *filename)
122 topManager_.loadTopology(filename);
127 SelectionCollectionTest::setTopology()
129 top_ = topManager_.topology();
130 frame_ = topManager_.frame();
132 ASSERT_NO_THROW_GMX(sc_.setTopology(top_, -1));
136 SelectionCollectionTest::loadIndexGroups(const char *filename)
138 GMX_RELEASE_ASSERT(grps_ == NULL,
139 "External groups can only be loaded once");
140 std::string fullpath =
141 gmx::test::TestFileManager::getInputFilePath(filename);
142 gmx_ana_indexgrps_init(&grps_, NULL, fullpath.c_str());
143 sc_.setIndexGroups(grps_);
147 /********************************************************************
148 * Test fixture for selection testing with reference data
151 class SelectionCollectionDataTest : public SelectionCollectionTest
156 efTestEvaluation = 1<<0,
157 efTestPositionAtoms = 1<<1,
158 efTestPositionCoordinates = 1<<2,
159 efTestPositionMapping = 1<<3,
160 efTestPositionMasses = 1<<4,
161 efTestPositionCharges = 1<<5,
162 efTestSelectionNames = 1<<6,
163 efDontTestCompiledAtoms = 1<<8
165 typedef gmx::FlagsTemplate<TestFlag> TestFlags;
167 SelectionCollectionDataTest()
168 : checker_(data_.rootChecker()), count_(0), framenr_(0)
172 void setFlags(TestFlags flags) { flags_ = flags; }
174 void runParser(const gmx::ConstArrayRef<const char *> &selections);
177 void runEvaluateFinal();
179 void runTest(int natoms,
180 const gmx::ConstArrayRef<const char *> &selections);
181 void runTest(const char *filename,
182 const gmx::ConstArrayRef<const char *> &selections);
185 static void checkSelection(gmx::test::TestReferenceChecker *checker,
186 const gmx::Selection &sel, TestFlags flags);
188 void checkCompiled();
190 gmx::test::TestReferenceData data_;
191 gmx::test::TestReferenceChecker checker_;
199 SelectionCollectionDataTest::checkSelection(
200 gmx::test::TestReferenceChecker *checker,
201 const gmx::Selection &sel, TestFlags flags)
203 using gmx::test::TestReferenceChecker;
206 gmx::ConstArrayRef<int> atoms = sel.atomIndices();
207 checker->checkSequence(atoms.begin(), atoms.end(), "Atoms");
209 if (flags.test(efTestPositionAtoms)
210 || flags.test(efTestPositionCoordinates)
211 || flags.test(efTestPositionMapping)
212 || flags.test(efTestPositionMasses)
213 || flags.test(efTestPositionCharges))
215 TestReferenceChecker compound(
216 checker->checkSequenceCompound("Positions", sel.posCount()));
217 for (int i = 0; i < sel.posCount(); ++i)
219 TestReferenceChecker poscompound(compound.checkCompound("Position", NULL));
220 const gmx::SelectionPosition &p = sel.position(i);
221 if (flags.test(efTestPositionAtoms))
223 gmx::ConstArrayRef<int> atoms = p.atomIndices();
224 poscompound.checkSequence(atoms.begin(), atoms.end(), "Atoms");
226 if (flags.test(efTestPositionCoordinates))
228 poscompound.checkVector(p.x(), "Coordinates");
230 if (flags.test(efTestPositionMapping))
232 poscompound.checkInteger(p.refId(), "RefId");
233 poscompound.checkInteger(p.mappedId(), "MappedId");
235 if (flags.test(efTestPositionMasses))
237 poscompound.checkReal(p.mass(), "Mass");
239 if (flags.test(efTestPositionCharges))
241 poscompound.checkReal(p.charge(), "Charge");
249 SelectionCollectionDataTest::runParser(
250 const gmx::ConstArrayRef<const char *> &selections)
252 using gmx::test::TestReferenceChecker;
254 TestReferenceChecker compound(checker_.checkCompound("ParsedSelections", "Parsed"));
257 for (size_t i = 0; i < selections.size(); ++i)
259 SCOPED_TRACE(std::string("Parsing selection \"")
260 + selections[i] + "\"");
261 gmx::SelectionList result;
262 ASSERT_NO_THROW_GMX(result = sc_.parseFromString(selections[i]));
263 sel_.insert(sel_.end(), result.begin(), result.end());
264 if (sel_.size() == count_)
266 std::string id = gmx::formatString("Variable%d", static_cast<int>(varcount + 1));
267 TestReferenceChecker varcompound(
268 compound.checkCompound("ParsedVariable", id.c_str()));
269 varcompound.checkString(selections[i], "Input");
274 std::string id = gmx::formatString("Selection%d", static_cast<int>(count_ + 1));
275 TestReferenceChecker selcompound(
276 compound.checkCompound("ParsedSelection", id.c_str()));
277 selcompound.checkString(selections[i], "Input");
278 if (flags_.test(efTestSelectionNames))
280 selcompound.checkString(sel_[count_].name(), "Name");
282 selcompound.checkString(sel_[count_].selectionText(), "Text");
283 selcompound.checkBoolean(sel_[count_].isDynamic(), "Dynamic");
291 SelectionCollectionDataTest::runCompiler()
293 ASSERT_NO_THROW_GMX(sc_.compile());
294 ASSERT_EQ(count_, sel_.size());
300 SelectionCollectionDataTest::checkCompiled()
302 using gmx::test::TestReferenceChecker;
303 const TestFlags mask = ~TestFlags(efTestPositionCoordinates);
305 TestReferenceChecker compound(checker_.checkCompound("CompiledSelections", "Compiled"));
306 for (size_t i = 0; i < count_; ++i)
308 SCOPED_TRACE(std::string("Checking selection \"") +
309 sel_[i].selectionText() + "\"");
310 std::string id = gmx::formatString("Selection%d", static_cast<int>(i + 1));
311 TestReferenceChecker selcompound(
312 compound.checkCompound("Selection", id.c_str()));
313 if (flags_.test(efTestSelectionNames))
315 selcompound.checkString(sel_[i].name(), "Name");
317 if (!flags_.test(efDontTestCompiledAtoms))
319 checkSelection(&selcompound, sel_[i], flags_ & mask);
326 SelectionCollectionDataTest::runEvaluate()
328 using gmx::test::TestReferenceChecker;
331 ASSERT_NO_THROW_GMX(sc_.evaluate(frame_, NULL));
332 std::string frame = gmx::formatString("Frame%d", framenr_);
333 TestReferenceChecker compound(
334 checker_.checkCompound("EvaluatedSelections", frame.c_str()));
335 for (size_t i = 0; i < count_; ++i)
337 SCOPED_TRACE(std::string("Checking selection \"") +
338 sel_[i].selectionText() + "\"");
339 std::string id = gmx::formatString("Selection%d", static_cast<int>(i + 1));
340 TestReferenceChecker selcompound(
341 compound.checkCompound("Selection", id.c_str()));
342 checkSelection(&selcompound, sel_[i], flags_);
348 SelectionCollectionDataTest::runEvaluateFinal()
350 ASSERT_NO_THROW_GMX(sc_.evaluateFinal(framenr_));
356 SelectionCollectionDataTest::runTest(
357 int natoms, const gmx::ConstArrayRef<const char *> &selections)
359 ASSERT_NO_FATAL_FAILURE(runParser(selections));
360 ASSERT_NO_FATAL_FAILURE(setAtomCount(natoms));
361 ASSERT_NO_FATAL_FAILURE(runCompiler());
366 SelectionCollectionDataTest::runTest(
367 const char *filename, const gmx::ConstArrayRef<const char *> &selections)
369 ASSERT_NO_FATAL_FAILURE(runParser(selections));
370 ASSERT_NO_FATAL_FAILURE(loadTopology(filename));
371 ASSERT_NO_FATAL_FAILURE(runCompiler());
372 if (flags_.test(efTestEvaluation))
374 ASSERT_NO_FATAL_FAILURE(runEvaluate());
375 ASSERT_NO_FATAL_FAILURE(runEvaluateFinal());
380 /********************************************************************
381 * Tests for SelectionCollection functionality without reference data
384 TEST_F(SelectionCollectionTest, HandlesNoSelections)
386 EXPECT_FALSE(sc_.requiresTopology());
387 EXPECT_NO_THROW_GMX(sc_.compile());
390 TEST_F(SelectionCollectionTest, HandlesVelocityAndForceRequests)
392 ASSERT_NO_THROW_GMX(sel_ = sc_.parseFromString("atomnr 1 to 10; none"));
393 ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
394 ASSERT_EQ(2U, sel_.size());
395 ASSERT_NO_THROW_GMX(sel_[0].setEvaluateVelocities(true));
396 ASSERT_NO_THROW_GMX(sel_[1].setEvaluateVelocities(true));
397 ASSERT_NO_THROW_GMX(sel_[0].setEvaluateForces(true));
398 ASSERT_NO_THROW_GMX(sel_[1].setEvaluateForces(true));
399 ASSERT_NO_THROW_GMX(sc_.compile());
400 EXPECT_TRUE(sel_[0].hasVelocities());
401 EXPECT_TRUE(sel_[1].hasVelocities());
402 EXPECT_TRUE(sel_[0].hasForces());
403 EXPECT_TRUE(sel_[1].hasForces());
406 TEST_F(SelectionCollectionTest, ParsesSelectionsFromFile)
408 ASSERT_NO_THROW_GMX(sel_ = sc_.parseFromFile(
409 gmx::test::TestFileManager::getInputFilePath("selfile.dat")));
410 // These should match the contents of selfile.dat
411 ASSERT_EQ(2U, sel_.size());
412 EXPECT_STREQ("resname RA RB", sel_[0].selectionText());
413 EXPECT_STREQ("resname RB RC", sel_[1].selectionText());
416 TEST_F(SelectionCollectionTest, HandlesInvalidRegularExpressions)
418 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
420 sc_.parseFromString("resname ~ \"R[A\"");
422 }, gmx::InvalidInputError);
425 TEST_F(SelectionCollectionTest, HandlesUnsupportedRegularExpressions)
427 if (!gmx::Regex::isSupported())
429 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
431 sc_.parseFromString("resname \"R[AD]\"");
433 }, gmx::InvalidInputError);
437 TEST_F(SelectionCollectionTest, HandlesMissingMethodParamValue)
439 EXPECT_THROW_GMX(sc_.parseFromString("mindist from atomnr 1 cutoff"),
440 gmx::InvalidInputError);
443 TEST_F(SelectionCollectionTest, HandlesMissingMethodParamValue2)
445 EXPECT_THROW_GMX(sc_.parseFromString("within 1 of"),
446 gmx::InvalidInputError);
449 TEST_F(SelectionCollectionTest, HandlesMissingMethodParamValue3)
451 EXPECT_THROW_GMX(sc_.parseFromString("within of atomnr 1"),
452 gmx::InvalidInputError);
455 TEST_F(SelectionCollectionTest, HandlesHelpKeywordInInvalidContext)
457 EXPECT_THROW_GMX(sc_.parseFromString("resname help"),
458 gmx::InvalidInputError);
461 // TODO: Tests for more parser errors
463 TEST_F(SelectionCollectionTest, HandlesUnknownGroupReferenceParser1)
465 ASSERT_NO_THROW_GMX(sc_.setIndexGroups(NULL));
466 EXPECT_THROW_GMX(sc_.parseFromString("group \"foo\""), gmx::InconsistentInputError);
467 EXPECT_THROW_GMX(sc_.parseFromString("4"), gmx::InconsistentInputError);
470 TEST_F(SelectionCollectionTest, HandlesUnknownGroupReferenceParser2)
472 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
473 EXPECT_THROW_GMX(sc_.parseFromString("group \"foo\""), gmx::InconsistentInputError);
474 EXPECT_THROW_GMX(sc_.parseFromString("4"), gmx::InconsistentInputError);
477 TEST_F(SelectionCollectionTest, HandlesUnknownGroupReferenceDelayed1)
479 ASSERT_NO_THROW_GMX(sc_.parseFromString("group \"foo\""));
480 ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
481 EXPECT_THROW_GMX(sc_.setIndexGroups(NULL), gmx::InconsistentInputError);
482 EXPECT_THROW_GMX(sc_.compile(), gmx::APIError);
485 TEST_F(SelectionCollectionTest, HandlesUnknownGroupReferenceDelayed2)
487 ASSERT_NO_THROW_GMX(sc_.parseFromString("group 4; group \"foo\""));
488 ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
489 EXPECT_THROW_GMX(loadIndexGroups("simple.ndx"), gmx::InconsistentInputError);
490 EXPECT_THROW_GMX(sc_.compile(), gmx::APIError);
493 TEST_F(SelectionCollectionTest, HandlesUnsortedGroupReference)
495 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
496 EXPECT_THROW_GMX(sc_.parseFromString("group \"GrpUnsorted\""),
497 gmx::InconsistentInputError);
498 EXPECT_THROW_GMX(sc_.parseFromString("2"), gmx::InconsistentInputError);
501 TEST_F(SelectionCollectionTest, HandlesUnsortedGroupReferenceDelayed)
503 ASSERT_NO_THROW_GMX(sc_.parseFromString("group 2; group \"GrpUnsorted\""));
504 EXPECT_THROW_GMX(loadIndexGroups("simple.ndx"), gmx::InconsistentInputError);
505 EXPECT_THROW_GMX(sc_.compile(), gmx::APIError);
508 TEST_F(SelectionCollectionTest, RecoversFromMissingMoleculeInfo)
510 ASSERT_NO_THROW_GMX(sc_.parseFromString("molindex 1 to 5"));
511 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
512 EXPECT_THROW_GMX(sc_.compile(), gmx::InconsistentInputError);
515 TEST_F(SelectionCollectionTest, RecoversFromMissingAtomTypes)
517 ASSERT_NO_THROW_GMX(sc_.parseFromString("type CA"));
518 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
519 EXPECT_THROW_GMX(sc_.compile(), gmx::InconsistentInputError);
522 TEST_F(SelectionCollectionTest, RecoversFromMissingPDBInfo)
524 ASSERT_NO_THROW_GMX(sc_.parseFromString("altloc A"));
525 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
526 EXPECT_THROW_GMX(sc_.compile(), gmx::InconsistentInputError);
529 TEST_F(SelectionCollectionTest, RecoversFromInvalidPermutation)
531 ASSERT_NO_THROW_GMX(sc_.parseFromString("all permute 1 1"));
532 ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
533 EXPECT_THROW_GMX(sc_.compile(), gmx::InvalidInputError);
536 TEST_F(SelectionCollectionTest, RecoversFromInvalidPermutation2)
538 ASSERT_NO_THROW_GMX(sc_.parseFromString("all permute 3 2 1"));
539 ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
540 EXPECT_THROW_GMX(sc_.compile(), gmx::InconsistentInputError);
543 TEST_F(SelectionCollectionTest, RecoversFromInvalidPermutation3)
545 ASSERT_NO_THROW_GMX(sc_.parseFromString("x < 1.5 permute 3 2 1"));
546 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
547 ASSERT_NO_THROW_GMX(sc_.compile());
548 EXPECT_THROW_GMX(sc_.evaluate(frame_, NULL), gmx::InconsistentInputError);
551 // TODO: Tests for evaluation errors
554 /********************************************************************
555 * Tests for selection keywords
558 TEST_F(SelectionCollectionDataTest, HandlesAllNone)
560 static const char * const selections[] = {
564 runTest(10, selections);
567 TEST_F(SelectionCollectionDataTest, HandlesAtomnr)
569 static const char * const selections[] = {
570 "atomnr 1 to 3 6 to 8",
574 runTest(10, selections);
577 TEST_F(SelectionCollectionDataTest, HandlesResnr)
579 static const char * const selections[] = {
583 runTest("simple.gro", selections);
586 TEST_F(SelectionCollectionDataTest, HandlesResIndex)
588 static const char * const selections[] = {
592 runTest("simple.pdb", selections);
595 TEST_F(SelectionCollectionDataTest, HandlesMolIndex)
597 static const char * const selections[] = {
601 ASSERT_NO_FATAL_FAILURE(runParser(selections));
602 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
603 topManager_.initUniformMolecules(3);
604 ASSERT_NO_FATAL_FAILURE(runCompiler());
607 TEST_F(SelectionCollectionDataTest, HandlesAtomname)
609 static const char * const selections[] = {
613 runTest("simple.gro", selections);
616 TEST_F(SelectionCollectionDataTest, HandlesPdbAtomname)
618 static const char * const selections[] = {
624 runTest("simple.pdb", selections);
628 TEST_F(SelectionCollectionDataTest, HandlesAtomtype)
630 static const char * const selections[] = {
633 ASSERT_NO_FATAL_FAILURE(runParser(selections));
634 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
635 const char *const types[] = { "CA", "SA", "SB" };
636 topManager_.initAtomTypes(types);
637 ASSERT_NO_FATAL_FAILURE(runCompiler());
640 TEST_F(SelectionCollectionDataTest, HandlesChain)
642 static const char * const selections[] = {
646 runTest("simple.pdb", selections);
649 TEST_F(SelectionCollectionDataTest, HandlesMass)
651 static const char * const selections[] = {
654 ASSERT_NO_FATAL_FAILURE(runParser(selections));
655 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
656 for (int i = 0; i < top_->atoms.nr; ++i)
658 top_->atoms.atom[i].m = 1.0 + i;
660 ASSERT_NO_FATAL_FAILURE(runCompiler());
663 TEST_F(SelectionCollectionDataTest, HandlesCharge)
665 static const char * const selections[] = {
668 ASSERT_NO_FATAL_FAILURE(runParser(selections));
669 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
670 for (int i = 0; i < top_->atoms.nr; ++i)
672 top_->atoms.atom[i].q = i / 10.0;
674 ASSERT_NO_FATAL_FAILURE(runCompiler());
677 TEST_F(SelectionCollectionDataTest, HandlesAltLoc)
679 static const char * const selections[] = {
683 runTest("simple.pdb", selections);
686 TEST_F(SelectionCollectionDataTest, HandlesInsertCode)
688 static const char * const selections[] = {
692 runTest("simple.pdb", selections);
695 TEST_F(SelectionCollectionDataTest, HandlesOccupancy)
697 static const char * const selections[] = {
701 runTest("simple.pdb", selections);
704 TEST_F(SelectionCollectionDataTest, HandlesBeta)
706 static const char * const selections[] = {
710 runTest("simple.pdb", selections);
713 TEST_F(SelectionCollectionDataTest, HandlesResname)
715 static const char * const selections[] = {
719 runTest("simple.gro", selections);
722 TEST_F(SelectionCollectionDataTest, HandlesCoordinateKeywords)
724 static const char * const selections[] = {
729 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
730 runTest("simple.gro", selections);
734 TEST_F(SelectionCollectionDataTest, HandlesSameResidue)
736 static const char * const selections[] = {
737 "same residue as atomnr 1 4 12"
739 runTest("simple.gro", selections);
743 TEST_F(SelectionCollectionDataTest, HandlesSameResidueName)
745 static const char * const selections[] = {
746 "same resname as atomnr 1 14"
748 runTest("simple.gro", selections);
752 TEST_F(SelectionCollectionDataTest, HandlesPositionKeywords)
754 static const char * const selections[] = {
756 "res_cog of name CB and resnr 1 3",
757 "whole_res_cog of name CB and resnr 1 3",
758 "part_res_cog of x < 3",
759 "dyn_res_cog of x < 3"
761 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates
762 | efTestPositionAtoms);
763 runTest("simple.gro", selections);
767 TEST_F(SelectionCollectionDataTest, HandlesDistanceKeyword)
769 static const char * const selections[] = {
770 "distance from cog of resnr 1 < 2"
772 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
773 runTest("simple.gro", selections);
777 TEST_F(SelectionCollectionDataTest, HandlesMinDistanceKeyword)
779 static const char * const selections[] = {
780 "mindistance from resnr 1 < 2"
782 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
783 runTest("simple.gro", selections);
787 TEST_F(SelectionCollectionDataTest, HandlesWithinKeyword)
789 static const char * const selections[] = {
790 "within 1 of resnr 2"
792 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
793 runTest("simple.gro", selections);
797 TEST_F(SelectionCollectionDataTest, HandlesInSolidAngleKeyword)
799 // Both of these should evaluate to empty on a correct implementation.
800 static const char * const selections[] = {
801 "resname TP and not insolidangle center cog of resname C span resname R cutoff 20",
802 "resname TN and insolidangle center cog of resname C span resname R cutoff 20"
804 setFlags(TestFlags() | efDontTestCompiledAtoms | efTestEvaluation);
805 runTest("sphere.gro", selections);
809 TEST_F(SelectionCollectionDataTest, HandlesPermuteModifier)
811 static const char * const selections[] = {
813 "res_cog of resnr 1 to 4 permute 2 1",
814 "name CB S1 and res_cog x < 3 permute 2 1"
816 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates
817 | efTestPositionAtoms | efTestPositionMapping);
818 runTest("simple.gro", selections);
822 TEST_F(SelectionCollectionDataTest, HandlesPlusModifier)
824 static const char * const selections[] = {
825 "name S2 plus name S1",
826 "res_cog of resnr 2 plus res_cog of resnr 1 plus res_cog of resnr 3",
827 "name S1 and y < 3 plus res_cog of x < 2.5"
829 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates
830 | efTestPositionAtoms | efTestPositionMapping);
831 runTest("simple.gro", selections);
835 TEST_F(SelectionCollectionDataTest, HandlesMergeModifier)
837 static const char * const selections[] = {
838 "name S2 merge name S1",
839 "resnr 1 2 and name S2 merge resnr 1 2 and name S1 merge res_cog of resnr 1 2",
840 "name S1 and x < 2.5 merge res_cog of x < 2.5"
842 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates
843 | efTestPositionAtoms | efTestPositionMapping);
844 runTest("simple.gro", selections);
848 /********************************************************************
849 * Tests for generic selection evaluation
852 TEST_F(SelectionCollectionDataTest, ComputesMassesAndCharges)
854 static const char * const selections[] = {
859 setFlags(TestFlags() | efTestEvaluation | efTestPositionAtoms
860 | efTestPositionMasses | efTestPositionCharges);
861 ASSERT_NO_FATAL_FAILURE(runParser(selections));
862 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
863 for (int i = 0; i < top_->atoms.nr; ++i)
865 top_->atoms.atom[i].m = 1.0 + i / 100.0;
866 top_->atoms.atom[i].q = -(1.0 + i / 100.0);
868 ASSERT_NO_FATAL_FAILURE(runCompiler());
869 ASSERT_NO_FATAL_FAILURE(runEvaluate());
870 ASSERT_NO_FATAL_FAILURE(runEvaluateFinal());
873 TEST_F(SelectionCollectionDataTest, ComputesMassesAndChargesWithoutTopology)
875 static const char * const selections[] = {
876 "atomnr 1 to 3 8 to 9",
880 setFlags(TestFlags() | efTestPositionAtoms
881 | efTestPositionMasses | efTestPositionCharges);
882 runTest(10, selections);
886 /********************************************************************
887 * Tests for selection syntactic constructs
890 TEST_F(SelectionCollectionDataTest, HandlesSelectionNames)
892 static const char * const selections[] = {
893 "\"GroupSelection\" group \"GrpA\"",
894 "\"DynamicSelection\" x < 5",
897 setFlags(TestFlags() | efTestSelectionNames);
898 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
899 runTest(10, selections);
902 TEST_F(SelectionCollectionDataTest, HandlesIndexGroupsInSelections)
904 static const char * const selections[] = {
908 "group \"GrpB\" and resname RB"
910 setFlags(TestFlags() | efTestSelectionNames);
911 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
912 runTest("simple.gro", selections);
915 TEST_F(SelectionCollectionDataTest, HandlesIndexGroupsInSelectionsDelayed)
917 static const char * const selections[] = {
921 "group \"GrpB\" and resname RB"
923 setFlags(TestFlags() | efTestSelectionNames);
924 ASSERT_NO_FATAL_FAILURE(runParser(selections));
925 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
926 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
927 ASSERT_NO_FATAL_FAILURE(runCompiler());
930 TEST_F(SelectionCollectionDataTest, HandlesConstantPositions)
932 static const char * const selections[] = {
935 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
936 runTest("simple.gro", selections);
940 TEST_F(SelectionCollectionDataTest, HandlesWithinConstantPositions)
942 static const char * const selections[] = {
943 "within 1 of [2, 1, 0]"
945 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
946 runTest("simple.gro", selections);
950 TEST_F(SelectionCollectionDataTest, HandlesForcedStringMatchingMode)
952 static const char * const selections[] = {
956 runTest("simple.gro", selections);
960 TEST_F(SelectionCollectionDataTest, HandlesWildcardMatching)
962 static const char * const selections[] = {
966 runTest("simple.gro", selections);
970 TEST_F(SelectionCollectionDataTest, HandlesRegexMatching)
972 static const char * const selections[] = {
974 "resname ~ \"R[BD]\""
976 if (gmx::Regex::isSupported())
978 runTest("simple.gro", selections);
983 TEST_F(SelectionCollectionDataTest, HandlesBasicBoolean)
985 static const char * const selections[] = {
986 "atomnr 1 to 5 and atomnr 2 to 7",
987 "atomnr 1 to 5 or not atomnr 3 to 8",
988 "not not atomnr 1 to 5 and atomnr 2 to 6 and not not atomnr 3 to 7",
989 "atomnr 1 to 5 and (atomnr 2 to 7 and atomnr 3 to 6)",
990 "x < 5 and atomnr 1 to 5 and y < 3 and atomnr 2 to 4"
992 runTest(10, selections);
996 TEST_F(SelectionCollectionDataTest, HandlesDynamicAtomValuedParameters)
998 static const char * const selections[] = {
999 "same residue as (atomnr 3 5 13 or y > 5)",
1000 "(resnr 1 3 5 or x > 10) and same residue as (atomnr 3 5 13 or z > 5)"
1002 setFlags(TestFlags() | efTestEvaluation);
1003 runTest("simple.gro", selections);
1007 TEST_F(SelectionCollectionDataTest, HandlesEmptySelectionWithUnevaluatedExpressions)
1009 static const char * const selections[] = {
1011 "none and same resname as resnr 2"
1013 runTest("simple.gro", selections);
1017 TEST_F(SelectionCollectionDataTest, HandlesNumericComparisons)
1019 static const char * const selections[] = {
1026 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1027 runTest("simple.gro", selections);
1031 TEST_F(SelectionCollectionDataTest, HandlesArithmeticExpressions)
1033 static const char * const selections[] = {
1039 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1040 runTest("simple.gro", selections);
1044 TEST_F(SelectionCollectionDataTest, HandlesNumericVariables)
1046 static const char * const selections[] = {
1052 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1053 runTest("simple.gro", selections);
1057 TEST_F(SelectionCollectionDataTest, HandlesComplexNumericVariables)
1059 static const char * const selections[] = {
1061 "resname RA and value <= 4",
1062 "resname RA RB and x < 3 and value <= 4",
1064 "resname RA and index < 3",
1065 "resname RB and y < 3 and index < 6"
1067 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1068 runTest("simple.gro", selections);
1072 TEST_F(SelectionCollectionDataTest, HandlesPositionVariables)
1074 static const char * const selections[] = {
1075 "foo = res_cog of resname RA",
1078 "bar = cog of resname RA",
1082 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1083 runTest("simple.gro", selections);
1087 TEST_F(SelectionCollectionDataTest, HandlesConstantPositionInVariable)
1089 static const char * const selections[] = {
1090 "constpos = [1.0, 2.5, 0.5]",
1092 "within 2 of constpos"
1094 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates
1095 | efTestPositionAtoms);
1096 runTest("simple.gro", selections);
1100 TEST_F(SelectionCollectionDataTest, HandlesNumericConstantsInVariables)
1102 static const char * const selections[] = {
1107 "x + constreal1 < constreal2"
1109 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1110 runTest("simple.gro", selections);
1114 /********************************************************************
1115 * Tests for complex boolean syntax
1118 TEST_F(SelectionCollectionDataTest, HandlesBooleanStaticAnalysis)
1120 static const char * const selections[] = {
1121 "atomnr 1 to 5 and atomnr 2 to 7 and x < 2",
1122 "atomnr 1 to 5 and (atomnr 4 to 7 or x < 2)",
1123 "atomnr 1 to 5 and y < 3 and (atomnr 4 to 7 or x < 2)",
1124 "atomnr 1 to 5 and not (atomnr 4 to 7 or x < 2)",
1125 "atomnr 1 to 5 or (atomnr 4 to 6 and (atomnr 5 to 7 or x < 2))"
1127 runTest(10, selections);
1131 TEST_F(SelectionCollectionDataTest, HandlesBooleanStaticAnalysisWithVariables)
1133 static const char * const selections[] = {
1134 "foo = atomnr 4 to 7 or x < 2",
1135 "atomnr 1 to 4 and foo",
1136 "atomnr 2 to 6 and y < 3 and foo",
1137 "atomnr 6 to 10 and not foo"
1139 runTest(10, selections);
1143 TEST_F(SelectionCollectionDataTest, HandlesBooleanStaticAnalysisWithMoreVariables)
1145 static const char * const selections[] = {
1146 "foo = atomnr 4 to 7",
1147 "bar = foo and x < 2",
1148 "bar2 = foo and y < 2",
1149 "atomnr 1 to 4 and bar",
1150 "atomnr 2 to 6 and y < 3 and bar2",
1151 "atomnr 6 to 10 and not foo"
1153 runTest(10, selections);
1157 /********************************************************************
1158 * Tests for complex subexpression cases
1160 * These tests use some knowledge of the implementation to trigger different
1161 * paths in the code.
1164 TEST_F(SelectionCollectionDataTest, HandlesUnusedVariables)
1166 static const char * const selections[] = {
1167 "unused1 = atomnr 1 to 3",
1168 "foo = atomnr 4 to 7",
1169 "atomnr 1 to 6 and foo",
1170 "unused2 = atomnr 3 to 5"
1172 runTest(10, selections);
1176 TEST_F(SelectionCollectionDataTest, HandlesVariablesWithStaticEvaluationGroups)
1178 static const char * const selections[] = {
1179 "foo = atomnr 4 to 7 and x < 2",
1180 "atomnr 1 to 5 and foo",
1181 "atomnr 3 to 7 and foo"
1183 runTest(10, selections);
1187 TEST_F(SelectionCollectionDataTest, HandlesVariablesWithMixedEvaluationGroups)
1189 static const char * const selections[] = {
1190 "foo = atomnr 4 to 7 and x < 2",
1191 "atomnr 1 to 6 and foo",
1195 runTest(10, selections);
1199 TEST_F(SelectionCollectionDataTest, HandlesVariablesWithMixedEvaluationGroups2)
1201 static const char * const selections[] = {
1202 "foo = atomnr 1 to 8 and x < 10",
1203 "atomnr 1 to 5 and y < 10 and foo",
1206 setFlags(TestFlags() | efTestEvaluation);
1207 runTest("simple.gro", selections);