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/topology/topology.h"
50 #include "gromacs/utility/arrayref.h"
51 #include "gromacs/utility/exceptions.h"
52 #include "gromacs/utility/flags.h"
53 #include "gromacs/utility/gmxregex.h"
54 #include "gromacs/utility/stringutil.h"
56 #include "testutils/refdata.h"
57 #include "testutils/testasserts.h"
58 #include "testutils/testfilemanager.h"
59 #include "testutils/testoptions.h"
66 /********************************************************************
67 * Test fixture for selection testing
70 class SelectionCollectionTest : public ::testing::Test
73 static int s_debugLevel;
75 SelectionCollectionTest();
76 ~SelectionCollectionTest();
78 void setAtomCount(int natoms)
80 ASSERT_NO_THROW_GMX(sc_.setTopology(NULL, natoms));
82 void loadTopology(const char *filename);
84 void loadIndexGroups(const char *filename);
86 gmx::test::TopologyManager topManager_;
87 gmx::SelectionCollection sc_;
88 gmx::SelectionList sel_;
91 gmx_ana_indexgrps_t *grps_;
94 int SelectionCollectionTest::s_debugLevel = 0;
96 // \cond/\endcond do not seem to work here with Doxygen 1.8.5 parser.
98 GMX_TEST_OPTIONS(SelectionCollectionTestOptions, options)
100 options->addOption(gmx::IntegerOption("seldebug")
101 .store(&SelectionCollectionTest::s_debugLevel)
102 .description("Set selection debug level"));
106 SelectionCollectionTest::SelectionCollectionTest()
107 : top_(NULL), frame_(NULL), grps_(NULL)
109 topManager_.requestFrame();
110 sc_.setDebugLevel(s_debugLevel);
111 sc_.setReferencePosType("atom");
112 sc_.setOutputPosType("atom");
115 SelectionCollectionTest::~SelectionCollectionTest()
119 gmx_ana_indexgrps_free(grps_);
124 SelectionCollectionTest::loadTopology(const char *filename)
126 topManager_.loadTopology(filename);
131 SelectionCollectionTest::setTopology()
133 top_ = topManager_.topology();
134 frame_ = topManager_.frame();
136 ASSERT_NO_THROW_GMX(sc_.setTopology(top_, -1));
140 SelectionCollectionTest::loadIndexGroups(const char *filename)
142 GMX_RELEASE_ASSERT(grps_ == NULL,
143 "External groups can only be loaded once");
144 std::string fullpath =
145 gmx::test::TestFileManager::getInputFilePath(filename);
146 gmx_ana_indexgrps_init(&grps_, NULL, fullpath.c_str());
147 sc_.setIndexGroups(grps_);
151 /********************************************************************
152 * Test fixture for selection testing with reference data
155 class SelectionCollectionDataTest : public SelectionCollectionTest
160 efTestEvaluation = 1<<0,
161 efTestPositionAtoms = 1<<1,
162 efTestPositionCoordinates = 1<<2,
163 efTestPositionMapping = 1<<3,
164 efTestPositionMasses = 1<<4,
165 efTestPositionCharges = 1<<5,
166 efTestSelectionNames = 1<<6,
167 efDontTestCompiledAtoms = 1<<8
169 typedef gmx::FlagsTemplate<TestFlag> TestFlags;
171 SelectionCollectionDataTest()
172 : checker_(data_.rootChecker()), count_(0), framenr_(0)
176 void setFlags(TestFlags flags) { flags_ = flags; }
178 void runParser(const gmx::ConstArrayRef<const char *> &selections);
181 void runEvaluateFinal();
183 void runTest(int natoms,
184 const gmx::ConstArrayRef<const char *> &selections);
185 void runTest(const char *filename,
186 const gmx::ConstArrayRef<const char *> &selections);
189 static void checkSelection(gmx::test::TestReferenceChecker *checker,
190 const gmx::Selection &sel, TestFlags flags);
192 void checkCompiled();
194 gmx::test::TestReferenceData data_;
195 gmx::test::TestReferenceChecker checker_;
203 SelectionCollectionDataTest::checkSelection(
204 gmx::test::TestReferenceChecker *checker,
205 const gmx::Selection &sel, TestFlags flags)
207 using gmx::test::TestReferenceChecker;
210 gmx::ConstArrayRef<int> atoms = sel.atomIndices();
211 checker->checkSequence(atoms.begin(), atoms.end(), "Atoms");
213 if (flags.test(efTestPositionAtoms)
214 || flags.test(efTestPositionCoordinates)
215 || flags.test(efTestPositionMapping)
216 || flags.test(efTestPositionMasses)
217 || flags.test(efTestPositionCharges))
219 TestReferenceChecker compound(
220 checker->checkSequenceCompound("Positions", sel.posCount()));
221 for (int i = 0; i < sel.posCount(); ++i)
223 TestReferenceChecker poscompound(compound.checkCompound("Position", NULL));
224 const gmx::SelectionPosition &p = sel.position(i);
225 if (flags.test(efTestPositionAtoms))
227 gmx::ConstArrayRef<int> atoms = p.atomIndices();
228 poscompound.checkSequence(atoms.begin(), atoms.end(), "Atoms");
230 if (flags.test(efTestPositionCoordinates))
232 poscompound.checkVector(p.x(), "Coordinates");
234 if (flags.test(efTestPositionMapping))
236 poscompound.checkInteger(p.refId(), "RefId");
237 poscompound.checkInteger(p.mappedId(), "MappedId");
239 if (flags.test(efTestPositionMasses))
241 poscompound.checkReal(p.mass(), "Mass");
243 if (flags.test(efTestPositionCharges))
245 poscompound.checkReal(p.charge(), "Charge");
253 SelectionCollectionDataTest::runParser(
254 const gmx::ConstArrayRef<const char *> &selections)
256 using gmx::test::TestReferenceChecker;
258 TestReferenceChecker compound(checker_.checkCompound("ParsedSelections", "Parsed"));
261 for (size_t i = 0; i < selections.size(); ++i)
263 SCOPED_TRACE(std::string("Parsing selection \"")
264 + selections[i] + "\"");
265 gmx::SelectionList result;
266 ASSERT_NO_THROW_GMX(result = sc_.parseFromString(selections[i]));
267 sel_.insert(sel_.end(), result.begin(), result.end());
268 if (sel_.size() == count_)
270 std::string id = gmx::formatString("Variable%d", static_cast<int>(varcount + 1));
271 TestReferenceChecker varcompound(
272 compound.checkCompound("ParsedVariable", id.c_str()));
273 varcompound.checkString(selections[i], "Input");
278 std::string id = gmx::formatString("Selection%d", static_cast<int>(count_ + 1));
279 TestReferenceChecker selcompound(
280 compound.checkCompound("ParsedSelection", id.c_str()));
281 selcompound.checkString(selections[i], "Input");
282 if (flags_.test(efTestSelectionNames))
284 selcompound.checkString(sel_[count_].name(), "Name");
286 selcompound.checkString(sel_[count_].selectionText(), "Text");
287 selcompound.checkBoolean(sel_[count_].isDynamic(), "Dynamic");
295 SelectionCollectionDataTest::runCompiler()
297 ASSERT_NO_THROW_GMX(sc_.compile());
298 ASSERT_EQ(count_, sel_.size());
304 SelectionCollectionDataTest::checkCompiled()
306 using gmx::test::TestReferenceChecker;
307 const TestFlags mask = ~TestFlags(efTestPositionCoordinates);
309 TestReferenceChecker compound(checker_.checkCompound("CompiledSelections", "Compiled"));
310 for (size_t i = 0; i < count_; ++i)
312 SCOPED_TRACE(std::string("Checking selection \"") +
313 sel_[i].selectionText() + "\"");
314 std::string id = gmx::formatString("Selection%d", static_cast<int>(i + 1));
315 TestReferenceChecker selcompound(
316 compound.checkCompound("Selection", id.c_str()));
317 if (flags_.test(efTestSelectionNames))
319 selcompound.checkString(sel_[i].name(), "Name");
321 if (!flags_.test(efDontTestCompiledAtoms))
323 checkSelection(&selcompound, sel_[i], flags_ & mask);
330 SelectionCollectionDataTest::runEvaluate()
332 using gmx::test::TestReferenceChecker;
335 ASSERT_NO_THROW_GMX(sc_.evaluate(frame_, NULL));
336 std::string frame = gmx::formatString("Frame%d", framenr_);
337 TestReferenceChecker compound(
338 checker_.checkCompound("EvaluatedSelections", frame.c_str()));
339 for (size_t i = 0; i < count_; ++i)
341 SCOPED_TRACE(std::string("Checking selection \"") +
342 sel_[i].selectionText() + "\"");
343 std::string id = gmx::formatString("Selection%d", static_cast<int>(i + 1));
344 TestReferenceChecker selcompound(
345 compound.checkCompound("Selection", id.c_str()));
346 checkSelection(&selcompound, sel_[i], flags_);
352 SelectionCollectionDataTest::runEvaluateFinal()
354 ASSERT_NO_THROW_GMX(sc_.evaluateFinal(framenr_));
360 SelectionCollectionDataTest::runTest(
361 int natoms, const gmx::ConstArrayRef<const char *> &selections)
363 ASSERT_NO_FATAL_FAILURE(runParser(selections));
364 ASSERT_NO_FATAL_FAILURE(setAtomCount(natoms));
365 ASSERT_NO_FATAL_FAILURE(runCompiler());
370 SelectionCollectionDataTest::runTest(
371 const char *filename, const gmx::ConstArrayRef<const char *> &selections)
373 ASSERT_NO_FATAL_FAILURE(runParser(selections));
374 ASSERT_NO_FATAL_FAILURE(loadTopology(filename));
375 ASSERT_NO_FATAL_FAILURE(runCompiler());
376 if (flags_.test(efTestEvaluation))
378 ASSERT_NO_FATAL_FAILURE(runEvaluate());
379 ASSERT_NO_FATAL_FAILURE(runEvaluateFinal());
384 /********************************************************************
385 * Tests for SelectionCollection functionality without reference data
388 TEST_F(SelectionCollectionTest, HandlesNoSelections)
390 EXPECT_FALSE(sc_.requiresTopology());
391 EXPECT_NO_THROW_GMX(sc_.compile());
394 TEST_F(SelectionCollectionTest, HandlesVelocityAndForceRequests)
396 ASSERT_NO_THROW_GMX(sel_ = sc_.parseFromString("atomnr 1 to 10; none"));
397 ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
398 ASSERT_EQ(2U, sel_.size());
399 ASSERT_NO_THROW_GMX(sel_[0].setEvaluateVelocities(true));
400 ASSERT_NO_THROW_GMX(sel_[1].setEvaluateVelocities(true));
401 ASSERT_NO_THROW_GMX(sel_[0].setEvaluateForces(true));
402 ASSERT_NO_THROW_GMX(sel_[1].setEvaluateForces(true));
403 ASSERT_NO_THROW_GMX(sc_.compile());
404 EXPECT_TRUE(sel_[0].hasVelocities());
405 EXPECT_TRUE(sel_[1].hasVelocities());
406 EXPECT_TRUE(sel_[0].hasForces());
407 EXPECT_TRUE(sel_[1].hasForces());
410 TEST_F(SelectionCollectionTest, ParsesSelectionsFromFile)
412 ASSERT_NO_THROW_GMX(sel_ = sc_.parseFromFile(
413 gmx::test::TestFileManager::getInputFilePath("selfile.dat")));
414 // These should match the contents of selfile.dat
415 ASSERT_EQ(2U, sel_.size());
416 EXPECT_STREQ("resname RA RB", sel_[0].selectionText());
417 EXPECT_STREQ("resname RB RC", sel_[1].selectionText());
420 TEST_F(SelectionCollectionTest, HandlesAtypicalWhitespace)
422 ASSERT_NO_THROW_GMX(sel_ = sc_.parseFromString("atomnr\n1\r\nto\t10;\vatomnr 3\f to 14\r"));
423 ASSERT_EQ(2U, sel_.size());
424 EXPECT_STREQ("atomnr 1 to 10", sel_[0].selectionText());
425 // TODO: Get rid of the trailing whitespace.
426 EXPECT_STREQ("atomnr 3 to 14 ", sel_[1].selectionText());
429 TEST_F(SelectionCollectionTest, HandlesInvalidRegularExpressions)
431 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
433 sc_.parseFromString("resname ~ \"R[A\"");
435 }, gmx::InvalidInputError);
438 TEST_F(SelectionCollectionTest, HandlesUnsupportedRegularExpressions)
440 if (!gmx::Regex::isSupported())
442 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
444 sc_.parseFromString("resname \"R[AD]\"");
446 }, gmx::InvalidInputError);
450 TEST_F(SelectionCollectionTest, HandlesMissingMethodParamValue)
452 EXPECT_THROW_GMX(sc_.parseFromString("mindist from atomnr 1 cutoff"),
453 gmx::InvalidInputError);
456 TEST_F(SelectionCollectionTest, HandlesMissingMethodParamValue2)
458 EXPECT_THROW_GMX(sc_.parseFromString("within 1 of"),
459 gmx::InvalidInputError);
462 TEST_F(SelectionCollectionTest, HandlesMissingMethodParamValue3)
464 EXPECT_THROW_GMX(sc_.parseFromString("within of atomnr 1"),
465 gmx::InvalidInputError);
468 // TODO: Tests for more parser errors
470 TEST_F(SelectionCollectionTest, HandlesUnknownGroupReferenceParser1)
472 ASSERT_NO_THROW_GMX(sc_.setIndexGroups(NULL));
473 EXPECT_THROW_GMX(sc_.parseFromString("group \"foo\""), gmx::InconsistentInputError);
474 EXPECT_THROW_GMX(sc_.parseFromString("4"), gmx::InconsistentInputError);
477 TEST_F(SelectionCollectionTest, HandlesUnknownGroupReferenceParser2)
479 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
480 EXPECT_THROW_GMX(sc_.parseFromString("group \"foo\""), gmx::InconsistentInputError);
481 EXPECT_THROW_GMX(sc_.parseFromString("4"), gmx::InconsistentInputError);
484 TEST_F(SelectionCollectionTest, HandlesUnknownGroupReferenceDelayed1)
486 ASSERT_NO_THROW_GMX(sc_.parseFromString("group \"foo\""));
487 ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
488 EXPECT_THROW_GMX(sc_.setIndexGroups(NULL), gmx::InconsistentInputError);
489 EXPECT_THROW_GMX(sc_.compile(), gmx::APIError);
492 TEST_F(SelectionCollectionTest, HandlesUnknownGroupReferenceDelayed2)
494 ASSERT_NO_THROW_GMX(sc_.parseFromString("group 4; group \"foo\""));
495 ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
496 EXPECT_THROW_GMX(loadIndexGroups("simple.ndx"), gmx::InconsistentInputError);
497 EXPECT_THROW_GMX(sc_.compile(), gmx::APIError);
500 TEST_F(SelectionCollectionTest, HandlesUnsortedGroupReference)
502 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
503 EXPECT_THROW_GMX(sc_.parseFromString("atomnr 1 to 3 and group \"GrpUnsorted\""),
504 gmx::InconsistentInputError);
505 EXPECT_THROW_GMX(sc_.parseFromString("group 2 or atomnr 2 to 5"),
506 gmx::InconsistentInputError);
507 EXPECT_THROW_GMX(sc_.parseFromString("within 1 of group 2"),
508 gmx::InconsistentInputError);
511 TEST_F(SelectionCollectionTest, HandlesUnsortedGroupReferenceDelayed)
513 ASSERT_NO_THROW_GMX(sc_.parseFromString("atomnr 1 to 3 and group \"GrpUnsorted\""));
514 ASSERT_NO_THROW_GMX(sc_.parseFromString("atomnr 1 to 3 and group 2"));
515 EXPECT_THROW_GMX(loadIndexGroups("simple.ndx"), gmx::InconsistentInputError);
516 // TODO: Add a separate check in the selection compiler for a safer API
517 // (makes sense in the future if the compiler needs the information for
518 // other purposes as well).
519 // EXPECT_THROW_GMX(sc_.compile(), gmx::APIError);
522 TEST_F(SelectionCollectionTest, HandlesOutOfRangeAtomIndexInGroup)
524 ASSERT_NO_THROW_GMX(sc_.setTopology(NULL, 5));
525 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
526 EXPECT_THROW_GMX(sc_.parseFromString("group \"GrpB\""), gmx::InconsistentInputError);
529 TEST_F(SelectionCollectionTest, HandlesOutOfRangeAtomIndexInGroupDelayed)
531 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
532 ASSERT_NO_THROW_GMX(sc_.parseFromString("group \"GrpB\""));
533 EXPECT_THROW_GMX(sc_.setTopology(NULL, 5), gmx::InconsistentInputError);
536 TEST_F(SelectionCollectionTest, HandlesOutOfRangeAtomIndexInGroupDelayed2)
538 ASSERT_NO_THROW_GMX(sc_.setTopology(NULL, 5));
539 ASSERT_NO_THROW_GMX(sc_.parseFromString("group \"GrpB\""));
540 EXPECT_THROW_GMX(loadIndexGroups("simple.ndx"), gmx::InconsistentInputError);
543 TEST_F(SelectionCollectionTest, RecoversFromMissingMoleculeInfo)
545 ASSERT_NO_THROW_GMX(sc_.parseFromString("molindex 1 to 5"));
546 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
547 EXPECT_THROW_GMX(sc_.compile(), gmx::InconsistentInputError);
550 TEST_F(SelectionCollectionTest, RecoversFromMissingAtomTypes)
552 ASSERT_NO_THROW_GMX(sc_.parseFromString("type CA"));
553 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
554 EXPECT_THROW_GMX(sc_.compile(), gmx::InconsistentInputError);
557 TEST_F(SelectionCollectionTest, RecoversFromMissingPDBInfo)
559 ASSERT_NO_THROW_GMX(sc_.parseFromString("altloc A"));
560 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
561 EXPECT_THROW_GMX(sc_.compile(), gmx::InconsistentInputError);
564 TEST_F(SelectionCollectionTest, RecoversFromInvalidPermutation)
566 ASSERT_NO_THROW_GMX(sc_.parseFromString("all permute 1 1"));
567 ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
568 EXPECT_THROW_GMX(sc_.compile(), gmx::InvalidInputError);
571 TEST_F(SelectionCollectionTest, RecoversFromInvalidPermutation2)
573 ASSERT_NO_THROW_GMX(sc_.parseFromString("all permute 3 2 1"));
574 ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
575 EXPECT_THROW_GMX(sc_.compile(), gmx::InconsistentInputError);
578 TEST_F(SelectionCollectionTest, RecoversFromInvalidPermutation3)
580 ASSERT_NO_THROW_GMX(sc_.parseFromString("x < 1.5 permute 3 2 1"));
581 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
582 ASSERT_NO_THROW_GMX(sc_.compile());
583 EXPECT_THROW_GMX(sc_.evaluate(frame_, NULL), gmx::InconsistentInputError);
586 // TODO: Tests for evaluation errors
589 /********************************************************************
590 * Tests for selection keywords
593 TEST_F(SelectionCollectionDataTest, HandlesAllNone)
595 static const char * const selections[] = {
599 runTest(10, selections);
602 TEST_F(SelectionCollectionDataTest, HandlesAtomnr)
604 static const char * const selections[] = {
605 "atomnr 1 to 3 6 to 8",
609 runTest(10, selections);
612 TEST_F(SelectionCollectionDataTest, HandlesResnr)
614 static const char * const selections[] = {
618 runTest("simple.gro", selections);
621 TEST_F(SelectionCollectionDataTest, HandlesResIndex)
623 static const char * const selections[] = {
627 runTest("simple.pdb", selections);
630 TEST_F(SelectionCollectionDataTest, HandlesMolIndex)
632 static const char * const selections[] = {
636 ASSERT_NO_FATAL_FAILURE(runParser(selections));
637 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
638 topManager_.initUniformMolecules(3);
639 ASSERT_NO_FATAL_FAILURE(runCompiler());
642 TEST_F(SelectionCollectionDataTest, HandlesAtomname)
644 static const char * const selections[] = {
648 runTest("simple.gro", selections);
651 TEST_F(SelectionCollectionDataTest, HandlesPdbAtomname)
653 static const char * const selections[] = {
659 runTest("simple.pdb", selections);
663 TEST_F(SelectionCollectionDataTest, HandlesAtomtype)
665 static const char * const selections[] = {
668 ASSERT_NO_FATAL_FAILURE(runParser(selections));
669 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
670 const char *const types[] = { "CA", "SA", "SB" };
671 topManager_.initAtomTypes(types);
672 ASSERT_NO_FATAL_FAILURE(runCompiler());
675 TEST_F(SelectionCollectionDataTest, HandlesChain)
677 static const char * const selections[] = {
681 runTest("simple.pdb", selections);
684 TEST_F(SelectionCollectionDataTest, HandlesMass)
686 static const char * const selections[] = {
689 ASSERT_NO_FATAL_FAILURE(runParser(selections));
690 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
691 for (int i = 0; i < top_->atoms.nr; ++i)
693 top_->atoms.atom[i].m = 1.0 + i;
695 ASSERT_NO_FATAL_FAILURE(runCompiler());
698 TEST_F(SelectionCollectionDataTest, HandlesCharge)
700 static const char * const selections[] = {
703 ASSERT_NO_FATAL_FAILURE(runParser(selections));
704 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
705 for (int i = 0; i < top_->atoms.nr; ++i)
707 top_->atoms.atom[i].q = i / 10.0;
709 ASSERT_NO_FATAL_FAILURE(runCompiler());
712 TEST_F(SelectionCollectionDataTest, HandlesAltLoc)
714 static const char * const selections[] = {
718 runTest("simple.pdb", selections);
721 TEST_F(SelectionCollectionDataTest, HandlesInsertCode)
723 static const char * const selections[] = {
727 runTest("simple.pdb", selections);
730 TEST_F(SelectionCollectionDataTest, HandlesOccupancy)
732 static const char * const selections[] = {
736 runTest("simple.pdb", selections);
739 TEST_F(SelectionCollectionDataTest, HandlesBeta)
741 static const char * const selections[] = {
745 runTest("simple.pdb", selections);
748 TEST_F(SelectionCollectionDataTest, HandlesResname)
750 static const char * const selections[] = {
754 runTest("simple.gro", selections);
757 TEST_F(SelectionCollectionDataTest, HandlesCoordinateKeywords)
759 static const char * const selections[] = {
764 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
765 runTest("simple.gro", selections);
769 TEST_F(SelectionCollectionDataTest, HandlesSameResidue)
771 static const char * const selections[] = {
772 "same residue as atomnr 1 4 12"
774 runTest("simple.gro", selections);
778 TEST_F(SelectionCollectionDataTest, HandlesSameResidueName)
780 static const char * const selections[] = {
781 "same resname as atomnr 1 14"
783 runTest("simple.gro", selections);
787 TEST_F(SelectionCollectionDataTest, HandlesPositionKeywords)
789 static const char * const selections[] = {
791 "res_cog of name CB and resnr 1 3",
792 "whole_res_cog of name CB and resnr 1 3",
793 "part_res_cog of x < 3",
794 "dyn_res_cog of x < 3"
796 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates
797 | efTestPositionAtoms);
798 runTest("simple.gro", selections);
802 TEST_F(SelectionCollectionDataTest, HandlesDistanceKeyword)
804 static const char * const selections[] = {
805 "distance from cog of resnr 1 < 2"
807 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
808 runTest("simple.gro", selections);
812 TEST_F(SelectionCollectionDataTest, HandlesMinDistanceKeyword)
814 static const char * const selections[] = {
815 "mindistance from resnr 1 < 2"
817 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
818 runTest("simple.gro", selections);
822 TEST_F(SelectionCollectionDataTest, HandlesWithinKeyword)
824 static const char * const selections[] = {
825 "within 1 of resnr 2"
827 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
828 runTest("simple.gro", selections);
832 TEST_F(SelectionCollectionDataTest, HandlesInSolidAngleKeyword)
834 // Both of these should evaluate to empty on a correct implementation.
835 static const char * const selections[] = {
836 "resname TP and not insolidangle center cog of resname C span resname R cutoff 20",
837 "resname TN and insolidangle center cog of resname C span resname R cutoff 20"
839 setFlags(TestFlags() | efDontTestCompiledAtoms | efTestEvaluation);
840 runTest("sphere.gro", selections);
844 TEST_F(SelectionCollectionDataTest, HandlesPermuteModifier)
846 static const char * const selections[] = {
848 "res_cog of resnr 1 to 4 permute 2 1",
849 "name CB S1 and res_cog x < 3 permute 2 1"
851 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates
852 | efTestPositionAtoms | efTestPositionMapping);
853 runTest("simple.gro", selections);
857 TEST_F(SelectionCollectionDataTest, HandlesPlusModifier)
859 static const char * const selections[] = {
860 "name S2 plus name S1",
861 "res_cog of resnr 2 plus res_cog of resnr 1 plus res_cog of resnr 3",
862 "name S1 and y < 3 plus res_cog of x < 2.5"
864 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates
865 | efTestPositionAtoms | efTestPositionMapping);
866 runTest("simple.gro", selections);
870 TEST_F(SelectionCollectionDataTest, HandlesMergeModifier)
872 static const char * const selections[] = {
873 "name S2 merge name S1",
874 "resnr 1 2 and name S2 merge resnr 1 2 and name S1 merge res_cog of resnr 1 2",
875 "name S1 and x < 2.5 merge res_cog of x < 2.5"
877 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates
878 | efTestPositionAtoms | efTestPositionMapping);
879 runTest("simple.gro", selections);
883 /********************************************************************
884 * Tests for generic selection evaluation
887 TEST_F(SelectionCollectionDataTest, ComputesMassesAndCharges)
889 static const char * const selections[] = {
894 setFlags(TestFlags() | efTestEvaluation | efTestPositionAtoms
895 | efTestPositionMasses | efTestPositionCharges);
896 ASSERT_NO_FATAL_FAILURE(runParser(selections));
897 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
898 for (int i = 0; i < top_->atoms.nr; ++i)
900 top_->atoms.atom[i].m = 1.0 + i / 100.0;
901 top_->atoms.atom[i].q = -(1.0 + i / 100.0);
903 ASSERT_NO_FATAL_FAILURE(runCompiler());
904 ASSERT_NO_FATAL_FAILURE(runEvaluate());
905 ASSERT_NO_FATAL_FAILURE(runEvaluateFinal());
908 TEST_F(SelectionCollectionDataTest, ComputesMassesAndChargesWithoutTopology)
910 static const char * const selections[] = {
911 "atomnr 1 to 3 8 to 9",
915 setFlags(TestFlags() | efTestPositionAtoms
916 | efTestPositionMasses | efTestPositionCharges);
917 runTest(10, selections);
921 /********************************************************************
922 * Tests for selection syntactic constructs
925 TEST_F(SelectionCollectionDataTest, HandlesSelectionNames)
927 static const char * const selections[] = {
928 "\"GroupSelection\" group \"GrpA\"",
929 "\"DynamicSelection\" x < 5",
932 setFlags(TestFlags() | efTestSelectionNames);
933 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
934 runTest(10, selections);
937 TEST_F(SelectionCollectionDataTest, HandlesIndexGroupsInSelections)
939 static const char * const selections[] = {
943 "group \"GrpB\" and resname RB"
945 setFlags(TestFlags() | efTestSelectionNames);
946 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
947 runTest("simple.gro", selections);
950 TEST_F(SelectionCollectionDataTest, HandlesIndexGroupsInSelectionsDelayed)
952 static const char * const selections[] = {
956 "group \"GrpB\" and resname RB"
958 setFlags(TestFlags() | efTestSelectionNames);
959 ASSERT_NO_FATAL_FAILURE(runParser(selections));
960 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
961 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
962 ASSERT_NO_FATAL_FAILURE(runCompiler());
965 TEST_F(SelectionCollectionDataTest, HandlesUnsortedIndexGroupsInSelections)
967 static const char * const selections[] = {
968 "foo = group \"GrpUnsorted\"",
969 "group \"GrpUnsorted\"",
972 "res_cog of group \"GrpUnsorted\"",
973 "group \"GrpUnsorted\" permute 2 1",
976 setFlags(TestFlags() | efTestPositionAtoms | efTestPositionMapping
977 | efTestSelectionNames);
978 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
979 runTest("simple.gro", selections);
982 TEST_F(SelectionCollectionDataTest, HandlesUnsortedIndexGroupsInSelectionsDelayed)
984 static const char * const selections[] = {
985 "foo = group \"GrpUnsorted\"",
986 "group \"GrpUnsorted\"",
989 "res_cog of group \"GrpUnsorted\"",
990 "group \"GrpUnsorted\" permute 2 1",
993 ASSERT_NO_FATAL_FAILURE(runParser(selections));
994 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
995 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
996 ASSERT_NO_FATAL_FAILURE(runCompiler());
999 TEST_F(SelectionCollectionDataTest, HandlesConstantPositions)
1001 static const char * const selections[] = {
1004 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1005 runTest("simple.gro", selections);
1009 TEST_F(SelectionCollectionDataTest, HandlesWithinConstantPositions)
1011 static const char * const selections[] = {
1012 "within 1 of [2, 1, 0]"
1014 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1015 runTest("simple.gro", selections);
1019 TEST_F(SelectionCollectionDataTest, HandlesForcedStringMatchingMode)
1021 static const char * const selections[] = {
1025 runTest("simple.gro", selections);
1029 TEST_F(SelectionCollectionDataTest, HandlesWildcardMatching)
1031 static const char * const selections[] = {
1035 runTest("simple.gro", selections);
1039 TEST_F(SelectionCollectionDataTest, HandlesRegexMatching)
1041 static const char * const selections[] = {
1042 "resname \"R[BD]\"",
1043 "resname ~ \"R[BD]\""
1045 if (gmx::Regex::isSupported())
1047 runTest("simple.gro", selections);
1052 TEST_F(SelectionCollectionDataTest, HandlesBasicBoolean)
1054 static const char * const selections[] = {
1055 "atomnr 1 to 5 and atomnr 2 to 7",
1056 "atomnr 1 to 5 or not atomnr 3 to 8",
1057 "not not atomnr 1 to 5 and atomnr 2 to 6 and not not atomnr 3 to 7",
1058 "atomnr 1 to 5 and (atomnr 2 to 7 and atomnr 3 to 6)",
1059 "x < 5 and atomnr 1 to 5 and y < 3 and atomnr 2 to 4"
1061 runTest(10, selections);
1065 TEST_F(SelectionCollectionDataTest, HandlesDynamicAtomValuedParameters)
1067 static const char * const selections[] = {
1068 "same residue as (atomnr 3 5 13 or y > 5)",
1069 "(resnr 1 3 5 or x > 10) and same residue as (atomnr 3 5 13 or z > 5)"
1071 setFlags(TestFlags() | efTestEvaluation);
1072 runTest("simple.gro", selections);
1076 TEST_F(SelectionCollectionDataTest, HandlesEmptySelectionWithUnevaluatedExpressions)
1078 static const char * const selections[] = {
1080 "none and same resname as resnr 2"
1082 runTest("simple.gro", selections);
1086 TEST_F(SelectionCollectionDataTest, HandlesNumericComparisons)
1088 static const char * const selections[] = {
1095 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1096 runTest("simple.gro", selections);
1100 TEST_F(SelectionCollectionDataTest, HandlesArithmeticExpressions)
1102 static const char * const selections[] = {
1108 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1109 runTest("simple.gro", selections);
1113 TEST_F(SelectionCollectionDataTest, HandlesNumericVariables)
1115 static const char * const selections[] = {
1121 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1122 runTest("simple.gro", selections);
1126 TEST_F(SelectionCollectionDataTest, HandlesComplexNumericVariables)
1128 static const char * const selections[] = {
1130 "resname RA and value <= 4",
1131 "resname RA RB and x < 3 and value <= 4",
1133 "resname RA and index < 3",
1134 "resname RB and y < 3 and index < 6"
1136 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1137 runTest("simple.gro", selections);
1141 TEST_F(SelectionCollectionDataTest, HandlesPositionVariables)
1143 static const char * const selections[] = {
1144 "foo = res_cog of resname RA",
1147 "bar = cog of resname RA",
1151 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1152 runTest("simple.gro", selections);
1156 TEST_F(SelectionCollectionDataTest, HandlesConstantPositionInVariable)
1158 static const char * const selections[] = {
1159 "constpos = [1.0, 2.5, 0.5]",
1161 "within 2 of constpos"
1163 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates
1164 | efTestPositionAtoms);
1165 runTest("simple.gro", selections);
1169 TEST_F(SelectionCollectionDataTest, HandlesNumericConstantsInVariables)
1171 static const char * const selections[] = {
1176 "x + constreal1 < constreal2"
1178 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1179 runTest("simple.gro", selections);
1183 /********************************************************************
1184 * Tests for complex boolean syntax
1187 TEST_F(SelectionCollectionDataTest, HandlesBooleanStaticAnalysis)
1189 static const char * const selections[] = {
1190 "atomnr 1 to 5 and atomnr 2 to 7 and x < 2",
1191 "atomnr 1 to 5 and (atomnr 4 to 7 or x < 2)",
1192 "atomnr 1 to 5 and y < 3 and (atomnr 4 to 7 or x < 2)",
1193 "atomnr 1 to 5 and not (atomnr 4 to 7 or x < 2)",
1194 "atomnr 1 to 5 or (atomnr 4 to 6 and (atomnr 5 to 7 or x < 2))"
1196 runTest(10, selections);
1200 TEST_F(SelectionCollectionDataTest, HandlesBooleanStaticAnalysisWithVariables)
1202 static const char * const selections[] = {
1203 "foo = atomnr 4 to 7 or x < 2",
1204 "atomnr 1 to 4 and foo",
1205 "atomnr 2 to 6 and y < 3 and foo",
1206 "atomnr 6 to 10 and not foo"
1208 runTest(10, selections);
1212 TEST_F(SelectionCollectionDataTest, HandlesBooleanStaticAnalysisWithMoreVariables)
1214 static const char * const selections[] = {
1215 "foo = atomnr 4 to 7",
1216 "bar = foo and x < 2",
1217 "bar2 = foo and y < 2",
1218 "atomnr 1 to 4 and bar",
1219 "atomnr 2 to 6 and y < 3 and bar2",
1220 "atomnr 6 to 10 and not foo"
1222 runTest(10, selections);
1226 /********************************************************************
1227 * Tests for complex subexpression cases
1229 * These tests use some knowledge of the implementation to trigger different
1230 * paths in the code.
1233 TEST_F(SelectionCollectionDataTest, HandlesUnusedVariables)
1235 static const char * const selections[] = {
1236 "unused1 = atomnr 1 to 3",
1237 "foo = atomnr 4 to 7",
1238 "atomnr 1 to 6 and foo",
1239 "unused2 = atomnr 3 to 5"
1241 runTest(10, selections);
1245 TEST_F(SelectionCollectionDataTest, HandlesVariablesWithStaticEvaluationGroups)
1247 static const char * const selections[] = {
1248 "foo = atomnr 4 to 7 and x < 2",
1249 "atomnr 1 to 5 and foo",
1250 "atomnr 3 to 7 and foo"
1252 runTest(10, selections);
1256 TEST_F(SelectionCollectionDataTest, HandlesVariablesWithMixedEvaluationGroups)
1258 static const char * const selections[] = {
1259 "foo = atomnr 4 to 7 and x < 2",
1260 "atomnr 1 to 6 and foo",
1264 runTest(10, selections);
1268 TEST_F(SelectionCollectionDataTest, HandlesVariablesWithMixedEvaluationGroups2)
1270 static const char * const selections[] = {
1271 "foo = atomnr 1 to 8 and x < 10",
1272 "atomnr 1 to 5 and y < 10 and foo",
1275 setFlags(TestFlags() | efTestEvaluation);
1276 runTest("simple.gro", selections);