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/fileio/trx.h"
45 #include "gromacs/options/basicoptions.h"
46 #include "gromacs/options/options.h"
47 #include "gromacs/selection/indexutil.h"
48 #include "gromacs/selection/selectioncollection.h"
49 #include "gromacs/selection/selection.h"
50 #include "gromacs/topology/topology.h"
51 #include "gromacs/utility/arrayref.h"
52 #include "gromacs/utility/exceptions.h"
53 #include "gromacs/utility/flags.h"
54 #include "gromacs/utility/gmxregex.h"
55 #include "gromacs/utility/stringutil.h"
57 #include "testutils/refdata.h"
58 #include "testutils/testasserts.h"
59 #include "testutils/testfilemanager.h"
60 #include "testutils/testoptions.h"
67 /********************************************************************
68 * Test fixture for selection testing
71 class SelectionCollectionTest : public ::testing::Test
74 static int s_debugLevel;
76 SelectionCollectionTest();
77 ~SelectionCollectionTest();
79 void setAtomCount(int natoms)
81 ASSERT_NO_THROW_GMX(sc_.setTopology(NULL, natoms));
83 void loadTopology(const char *filename);
85 void loadIndexGroups(const char *filename);
87 gmx::test::TopologyManager topManager_;
88 gmx::SelectionCollection sc_;
89 gmx::SelectionList sel_;
92 gmx_ana_indexgrps_t *grps_;
95 int SelectionCollectionTest::s_debugLevel = 0;
97 // \cond/\endcond do not seem to work here with Doxygen 1.8.5 parser.
99 GMX_TEST_OPTIONS(SelectionCollectionTestOptions, options)
101 options->addOption(gmx::IntegerOption("seldebug")
102 .store(&SelectionCollectionTest::s_debugLevel)
103 .description("Set selection debug level"));
107 SelectionCollectionTest::SelectionCollectionTest()
108 : top_(NULL), frame_(NULL), grps_(NULL)
110 topManager_.requestFrame();
111 sc_.setDebugLevel(s_debugLevel);
112 sc_.setReferencePosType("atom");
113 sc_.setOutputPosType("atom");
116 SelectionCollectionTest::~SelectionCollectionTest()
120 gmx_ana_indexgrps_free(grps_);
125 SelectionCollectionTest::loadTopology(const char *filename)
127 topManager_.loadTopology(filename);
132 SelectionCollectionTest::setTopology()
134 top_ = topManager_.topology();
135 frame_ = topManager_.frame();
137 ASSERT_NO_THROW_GMX(sc_.setTopology(top_, -1));
141 SelectionCollectionTest::loadIndexGroups(const char *filename)
143 GMX_RELEASE_ASSERT(grps_ == NULL,
144 "External groups can only be loaded once");
145 std::string fullpath =
146 gmx::test::TestFileManager::getInputFilePath(filename);
147 gmx_ana_indexgrps_init(&grps_, NULL, fullpath.c_str());
148 sc_.setIndexGroups(grps_);
152 /********************************************************************
153 * Test fixture for selection testing with reference data
156 class SelectionCollectionDataTest : public SelectionCollectionTest
161 efTestEvaluation = 1<<0,
162 efTestPositionAtoms = 1<<1,
163 efTestPositionCoordinates = 1<<2,
164 efTestPositionMapping = 1<<3,
165 efTestPositionMasses = 1<<4,
166 efTestPositionCharges = 1<<5,
167 efTestSelectionNames = 1<<6,
168 efDontTestCompiledAtoms = 1<<8
170 typedef gmx::FlagsTemplate<TestFlag> TestFlags;
172 SelectionCollectionDataTest()
173 : checker_(data_.rootChecker()), count_(0), framenr_(0)
177 void setFlags(TestFlags flags) { flags_ = flags; }
179 void runParser(const gmx::ConstArrayRef<const char *> &selections);
182 void runEvaluateFinal();
184 void runTest(int natoms,
185 const gmx::ConstArrayRef<const char *> &selections);
186 void runTest(const char *filename,
187 const gmx::ConstArrayRef<const char *> &selections);
190 static void checkSelection(gmx::test::TestReferenceChecker *checker,
191 const gmx::Selection &sel, TestFlags flags);
193 void checkCompiled();
195 gmx::test::TestReferenceData data_;
196 gmx::test::TestReferenceChecker checker_;
204 SelectionCollectionDataTest::checkSelection(
205 gmx::test::TestReferenceChecker *checker,
206 const gmx::Selection &sel, TestFlags flags)
208 using gmx::test::TestReferenceChecker;
211 gmx::ConstArrayRef<int> atoms = sel.atomIndices();
212 checker->checkSequence(atoms.begin(), atoms.end(), "Atoms");
214 if (flags.test(efTestPositionAtoms)
215 || flags.test(efTestPositionCoordinates)
216 || flags.test(efTestPositionMapping)
217 || flags.test(efTestPositionMasses)
218 || flags.test(efTestPositionCharges))
220 TestReferenceChecker compound(
221 checker->checkSequenceCompound("Positions", sel.posCount()));
222 for (int i = 0; i < sel.posCount(); ++i)
224 TestReferenceChecker poscompound(compound.checkCompound("Position", NULL));
225 const gmx::SelectionPosition &p = sel.position(i);
226 if (flags.test(efTestPositionAtoms))
228 gmx::ConstArrayRef<int> atoms = p.atomIndices();
229 poscompound.checkSequence(atoms.begin(), atoms.end(), "Atoms");
231 if (flags.test(efTestPositionCoordinates))
233 poscompound.checkVector(p.x(), "Coordinates");
235 if (flags.test(efTestPositionMapping))
237 poscompound.checkInteger(p.refId(), "RefId");
238 poscompound.checkInteger(p.mappedId(), "MappedId");
240 if (flags.test(efTestPositionMasses))
242 poscompound.checkReal(p.mass(), "Mass");
244 if (flags.test(efTestPositionCharges))
246 poscompound.checkReal(p.charge(), "Charge");
254 SelectionCollectionDataTest::runParser(
255 const gmx::ConstArrayRef<const char *> &selections)
257 using gmx::test::TestReferenceChecker;
259 TestReferenceChecker compound(checker_.checkCompound("ParsedSelections", "Parsed"));
262 for (size_t i = 0; i < selections.size(); ++i)
264 SCOPED_TRACE(std::string("Parsing selection \"")
265 + selections[i] + "\"");
266 gmx::SelectionList result;
267 ASSERT_NO_THROW_GMX(result = sc_.parseFromString(selections[i]));
268 sel_.insert(sel_.end(), result.begin(), result.end());
269 if (sel_.size() == count_)
271 std::string id = gmx::formatString("Variable%d", static_cast<int>(varcount + 1));
272 TestReferenceChecker varcompound(
273 compound.checkCompound("ParsedVariable", id.c_str()));
274 varcompound.checkString(selections[i], "Input");
279 std::string id = gmx::formatString("Selection%d", static_cast<int>(count_ + 1));
280 TestReferenceChecker selcompound(
281 compound.checkCompound("ParsedSelection", id.c_str()));
282 selcompound.checkString(selections[i], "Input");
283 if (flags_.test(efTestSelectionNames))
285 selcompound.checkString(sel_[count_].name(), "Name");
287 selcompound.checkString(sel_[count_].selectionText(), "Text");
288 selcompound.checkBoolean(sel_[count_].isDynamic(), "Dynamic");
296 SelectionCollectionDataTest::runCompiler()
298 ASSERT_NO_THROW_GMX(sc_.compile());
299 ASSERT_EQ(count_, sel_.size());
305 SelectionCollectionDataTest::checkCompiled()
307 using gmx::test::TestReferenceChecker;
308 const TestFlags mask = ~TestFlags(efTestPositionCoordinates);
310 TestReferenceChecker compound(checker_.checkCompound("CompiledSelections", "Compiled"));
311 for (size_t i = 0; i < count_; ++i)
313 SCOPED_TRACE(std::string("Checking selection \"") +
314 sel_[i].selectionText() + "\"");
315 std::string id = gmx::formatString("Selection%d", static_cast<int>(i + 1));
316 TestReferenceChecker selcompound(
317 compound.checkCompound("Selection", id.c_str()));
318 if (flags_.test(efTestSelectionNames))
320 selcompound.checkString(sel_[i].name(), "Name");
322 if (!flags_.test(efDontTestCompiledAtoms))
324 checkSelection(&selcompound, sel_[i], flags_ & mask);
331 SelectionCollectionDataTest::runEvaluate()
333 using gmx::test::TestReferenceChecker;
336 ASSERT_NO_THROW_GMX(sc_.evaluate(frame_, NULL));
337 std::string frame = gmx::formatString("Frame%d", framenr_);
338 TestReferenceChecker compound(
339 checker_.checkCompound("EvaluatedSelections", frame.c_str()));
340 for (size_t i = 0; i < count_; ++i)
342 SCOPED_TRACE(std::string("Checking selection \"") +
343 sel_[i].selectionText() + "\"");
344 std::string id = gmx::formatString("Selection%d", static_cast<int>(i + 1));
345 TestReferenceChecker selcompound(
346 compound.checkCompound("Selection", id.c_str()));
347 checkSelection(&selcompound, sel_[i], flags_);
353 SelectionCollectionDataTest::runEvaluateFinal()
355 ASSERT_NO_THROW_GMX(sc_.evaluateFinal(framenr_));
361 SelectionCollectionDataTest::runTest(
362 int natoms, const gmx::ConstArrayRef<const char *> &selections)
364 ASSERT_NO_FATAL_FAILURE(runParser(selections));
365 ASSERT_NO_FATAL_FAILURE(setAtomCount(natoms));
366 ASSERT_NO_FATAL_FAILURE(runCompiler());
371 SelectionCollectionDataTest::runTest(
372 const char *filename, const gmx::ConstArrayRef<const char *> &selections)
374 ASSERT_NO_FATAL_FAILURE(runParser(selections));
375 ASSERT_NO_FATAL_FAILURE(loadTopology(filename));
376 ASSERT_NO_FATAL_FAILURE(runCompiler());
377 if (flags_.test(efTestEvaluation))
379 ASSERT_NO_FATAL_FAILURE(runEvaluate());
380 ASSERT_NO_FATAL_FAILURE(runEvaluateFinal());
385 /********************************************************************
386 * Tests for SelectionCollection functionality without reference data
389 TEST_F(SelectionCollectionTest, HandlesNoSelections)
391 EXPECT_FALSE(sc_.requiresTopology());
392 EXPECT_NO_THROW_GMX(sc_.compile());
395 TEST_F(SelectionCollectionTest, HandlesVelocityAndForceRequests)
397 ASSERT_NO_THROW_GMX(sel_ = sc_.parseFromString("atomnr 1 to 10; none"));
398 ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
399 ASSERT_EQ(2U, sel_.size());
400 ASSERT_NO_THROW_GMX(sel_[0].setEvaluateVelocities(true));
401 ASSERT_NO_THROW_GMX(sel_[1].setEvaluateVelocities(true));
402 ASSERT_NO_THROW_GMX(sel_[0].setEvaluateForces(true));
403 ASSERT_NO_THROW_GMX(sel_[1].setEvaluateForces(true));
404 ASSERT_NO_THROW_GMX(sc_.compile());
405 EXPECT_TRUE(sel_[0].hasVelocities());
406 EXPECT_TRUE(sel_[1].hasVelocities());
407 EXPECT_TRUE(sel_[0].hasForces());
408 EXPECT_TRUE(sel_[1].hasForces());
411 TEST_F(SelectionCollectionTest, ParsesSelectionsFromFile)
413 ASSERT_NO_THROW_GMX(sel_ = sc_.parseFromFile(
414 gmx::test::TestFileManager::getInputFilePath("selfile.dat")));
415 // These should match the contents of selfile.dat
416 ASSERT_EQ(2U, sel_.size());
417 EXPECT_STREQ("resname RA RB", sel_[0].selectionText());
418 EXPECT_STREQ("resname RB RC", sel_[1].selectionText());
421 TEST_F(SelectionCollectionTest, HandlesAtypicalWhitespace)
423 ASSERT_NO_THROW_GMX(sel_ = sc_.parseFromString("atomnr\n1\r\nto\t10;\vatomnr 3\f to 14\r"));
424 ASSERT_EQ(2U, sel_.size());
425 EXPECT_STREQ("atomnr 1 to 10", sel_[0].selectionText());
426 // TODO: Get rid of the trailing whitespace.
427 EXPECT_STREQ("atomnr 3 to 14 ", sel_[1].selectionText());
430 TEST_F(SelectionCollectionTest, HandlesInvalidRegularExpressions)
432 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
434 sc_.parseFromString("resname ~ \"R[A\"");
436 }, gmx::InvalidInputError);
439 TEST_F(SelectionCollectionTest, HandlesUnsupportedRegularExpressions)
441 if (!gmx::Regex::isSupported())
443 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
445 sc_.parseFromString("resname \"R[AD]\"");
447 }, gmx::InvalidInputError);
451 TEST_F(SelectionCollectionTest, HandlesMissingMethodParamValue)
453 EXPECT_THROW_GMX(sc_.parseFromString("mindist from atomnr 1 cutoff"),
454 gmx::InvalidInputError);
457 TEST_F(SelectionCollectionTest, HandlesMissingMethodParamValue2)
459 EXPECT_THROW_GMX(sc_.parseFromString("within 1 of"),
460 gmx::InvalidInputError);
463 TEST_F(SelectionCollectionTest, HandlesMissingMethodParamValue3)
465 EXPECT_THROW_GMX(sc_.parseFromString("within of atomnr 1"),
466 gmx::InvalidInputError);
469 // TODO: Tests for more parser errors
471 TEST_F(SelectionCollectionTest, HandlesUnknownGroupReferenceParser1)
473 ASSERT_NO_THROW_GMX(sc_.setIndexGroups(NULL));
474 EXPECT_THROW_GMX(sc_.parseFromString("group \"foo\""), gmx::InconsistentInputError);
475 EXPECT_THROW_GMX(sc_.parseFromString("4"), gmx::InconsistentInputError);
478 TEST_F(SelectionCollectionTest, HandlesUnknownGroupReferenceParser2)
480 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
481 EXPECT_THROW_GMX(sc_.parseFromString("group \"foo\""), gmx::InconsistentInputError);
482 EXPECT_THROW_GMX(sc_.parseFromString("4"), gmx::InconsistentInputError);
485 TEST_F(SelectionCollectionTest, HandlesUnknownGroupReferenceDelayed1)
487 ASSERT_NO_THROW_GMX(sc_.parseFromString("group \"foo\""));
488 ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
489 EXPECT_THROW_GMX(sc_.setIndexGroups(NULL), gmx::InconsistentInputError);
490 EXPECT_THROW_GMX(sc_.compile(), gmx::APIError);
493 TEST_F(SelectionCollectionTest, HandlesUnknownGroupReferenceDelayed2)
495 ASSERT_NO_THROW_GMX(sc_.parseFromString("group 4; group \"foo\""));
496 ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
497 EXPECT_THROW_GMX(loadIndexGroups("simple.ndx"), gmx::InconsistentInputError);
498 EXPECT_THROW_GMX(sc_.compile(), gmx::APIError);
501 TEST_F(SelectionCollectionTest, HandlesUnsortedGroupReference)
503 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
504 EXPECT_THROW_GMX(sc_.parseFromString("atomnr 1 to 3 and group \"GrpUnsorted\""),
505 gmx::InconsistentInputError);
506 EXPECT_THROW_GMX(sc_.parseFromString("group 2 or atomnr 2 to 5"),
507 gmx::InconsistentInputError);
508 EXPECT_THROW_GMX(sc_.parseFromString("within 1 of group 2"),
509 gmx::InconsistentInputError);
512 TEST_F(SelectionCollectionTest, HandlesUnsortedGroupReferenceDelayed)
514 ASSERT_NO_THROW_GMX(sc_.parseFromString("atomnr 1 to 3 and group \"GrpUnsorted\""));
515 ASSERT_NO_THROW_GMX(sc_.parseFromString("atomnr 1 to 3 and group 2"));
516 EXPECT_THROW_GMX(loadIndexGroups("simple.ndx"), gmx::InconsistentInputError);
517 // TODO: Add a separate check in the selection compiler for a safer API
518 // (makes sense in the future if the compiler needs the information for
519 // other purposes as well).
520 // EXPECT_THROW_GMX(sc_.compile(), gmx::APIError);
523 TEST_F(SelectionCollectionTest, HandlesOutOfRangeAtomIndexInGroup)
525 ASSERT_NO_THROW_GMX(sc_.setTopology(NULL, 5));
526 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
527 EXPECT_THROW_GMX(sc_.parseFromString("group \"GrpB\""), gmx::InconsistentInputError);
530 TEST_F(SelectionCollectionTest, HandlesOutOfRangeAtomIndexInGroupDelayed)
532 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
533 ASSERT_NO_THROW_GMX(sc_.parseFromString("group \"GrpB\""));
534 EXPECT_THROW_GMX(sc_.setTopology(NULL, 5), gmx::InconsistentInputError);
537 TEST_F(SelectionCollectionTest, HandlesOutOfRangeAtomIndexInGroupDelayed2)
539 ASSERT_NO_THROW_GMX(sc_.setTopology(NULL, 5));
540 ASSERT_NO_THROW_GMX(sc_.parseFromString("group \"GrpB\""));
541 EXPECT_THROW_GMX(loadIndexGroups("simple.ndx"), gmx::InconsistentInputError);
544 TEST_F(SelectionCollectionTest, RecoversFromMissingMoleculeInfo)
546 ASSERT_NO_THROW_GMX(sc_.parseFromString("molindex 1 to 5"));
547 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
548 EXPECT_THROW_GMX(sc_.compile(), gmx::InconsistentInputError);
551 TEST_F(SelectionCollectionTest, RecoversFromMissingAtomTypes)
553 ASSERT_NO_THROW_GMX(sc_.parseFromString("type CA"));
554 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
555 EXPECT_THROW_GMX(sc_.compile(), gmx::InconsistentInputError);
558 TEST_F(SelectionCollectionTest, RecoversFromMissingPDBInfo)
560 ASSERT_NO_THROW_GMX(sc_.parseFromString("altloc A"));
561 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
562 EXPECT_THROW_GMX(sc_.compile(), gmx::InconsistentInputError);
565 TEST_F(SelectionCollectionTest, RecoversFromInvalidPermutation)
567 ASSERT_NO_THROW_GMX(sc_.parseFromString("all permute 1 1"));
568 ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
569 EXPECT_THROW_GMX(sc_.compile(), gmx::InvalidInputError);
572 TEST_F(SelectionCollectionTest, RecoversFromInvalidPermutation2)
574 ASSERT_NO_THROW_GMX(sc_.parseFromString("all permute 3 2 1"));
575 ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
576 EXPECT_THROW_GMX(sc_.compile(), gmx::InconsistentInputError);
579 TEST_F(SelectionCollectionTest, RecoversFromInvalidPermutation3)
581 ASSERT_NO_THROW_GMX(sc_.parseFromString("x < 1.5 permute 3 2 1"));
582 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
583 ASSERT_NO_THROW_GMX(sc_.compile());
584 EXPECT_THROW_GMX(sc_.evaluate(frame_, NULL), gmx::InconsistentInputError);
587 TEST_F(SelectionCollectionTest, HandlesFramesWithTooSmallAtomSubsets)
589 ASSERT_NO_THROW_GMX(sc_.parseFromString("atomnr 3 to 10"));
590 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
591 ASSERT_NO_THROW_GMX(sc_.compile());
593 EXPECT_THROW_GMX(sc_.evaluate(frame_, NULL), gmx::InconsistentInputError);
596 TEST_F(SelectionCollectionTest, HandlesFramesWithTooSmallAtomSubsets2)
598 // Evaluating the positions will require atoms 1-9.
599 ASSERT_NO_THROW_GMX(sc_.parseFromString("whole_res_com of atomnr 2 5 7"));
600 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
601 ASSERT_NO_THROW_GMX(sc_.compile());
603 EXPECT_THROW_GMX(sc_.evaluate(frame_, NULL), gmx::InconsistentInputError);
606 TEST_F(SelectionCollectionTest, HandlesFramesWithTooSmallAtomSubsets3)
608 ASSERT_NO_THROW_GMX(sc_.parseFromString("mindistance from atomnr 1 to 5 < 2"));
609 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
610 ASSERT_NO_THROW_GMX(sc_.compile());
612 EXPECT_THROW_GMX(sc_.evaluate(frame_, NULL), gmx::InconsistentInputError);
615 // TODO: Tests for more evaluation errors
618 /********************************************************************
619 * Tests for selection keywords
622 TEST_F(SelectionCollectionDataTest, HandlesAllNone)
624 static const char * const selections[] = {
628 runTest(10, selections);
631 TEST_F(SelectionCollectionDataTest, HandlesAtomnr)
633 static const char * const selections[] = {
634 "atomnr 1 to 3 6 to 8",
638 runTest(10, selections);
641 TEST_F(SelectionCollectionDataTest, HandlesResnr)
643 static const char * const selections[] = {
647 runTest("simple.gro", selections);
650 TEST_F(SelectionCollectionDataTest, HandlesResIndex)
652 static const char * const selections[] = {
656 runTest("simple.pdb", selections);
659 TEST_F(SelectionCollectionDataTest, HandlesMolIndex)
661 static const char * const selections[] = {
665 ASSERT_NO_FATAL_FAILURE(runParser(selections));
666 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
667 topManager_.initUniformMolecules(3);
668 ASSERT_NO_FATAL_FAILURE(runCompiler());
671 TEST_F(SelectionCollectionDataTest, HandlesAtomname)
673 static const char * const selections[] = {
677 runTest("simple.gro", selections);
680 TEST_F(SelectionCollectionDataTest, HandlesPdbAtomname)
682 static const char * const selections[] = {
688 runTest("simple.pdb", selections);
692 TEST_F(SelectionCollectionDataTest, HandlesAtomtype)
694 static const char * const selections[] = {
697 ASSERT_NO_FATAL_FAILURE(runParser(selections));
698 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
699 const char *const types[] = { "CA", "SA", "SB" };
700 topManager_.initAtomTypes(types);
701 ASSERT_NO_FATAL_FAILURE(runCompiler());
704 TEST_F(SelectionCollectionDataTest, HandlesChain)
706 static const char * const selections[] = {
710 runTest("simple.pdb", selections);
713 TEST_F(SelectionCollectionDataTest, HandlesMass)
715 static const char * const selections[] = {
718 ASSERT_NO_FATAL_FAILURE(runParser(selections));
719 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
720 for (int i = 0; i < top_->atoms.nr; ++i)
722 top_->atoms.atom[i].m = 1.0 + i;
724 ASSERT_NO_FATAL_FAILURE(runCompiler());
727 TEST_F(SelectionCollectionDataTest, HandlesCharge)
729 static const char * const selections[] = {
732 ASSERT_NO_FATAL_FAILURE(runParser(selections));
733 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
734 for (int i = 0; i < top_->atoms.nr; ++i)
736 top_->atoms.atom[i].q = i / 10.0;
738 ASSERT_NO_FATAL_FAILURE(runCompiler());
741 TEST_F(SelectionCollectionDataTest, HandlesAltLoc)
743 static const char * const selections[] = {
747 runTest("simple.pdb", selections);
750 TEST_F(SelectionCollectionDataTest, HandlesInsertCode)
752 static const char * const selections[] = {
756 runTest("simple.pdb", selections);
759 TEST_F(SelectionCollectionDataTest, HandlesOccupancy)
761 static const char * const selections[] = {
765 runTest("simple.pdb", selections);
768 TEST_F(SelectionCollectionDataTest, HandlesBeta)
770 static const char * const selections[] = {
774 runTest("simple.pdb", selections);
777 TEST_F(SelectionCollectionDataTest, HandlesResname)
779 static const char * const selections[] = {
783 runTest("simple.gro", selections);
786 TEST_F(SelectionCollectionDataTest, HandlesCoordinateKeywords)
788 static const char * const selections[] = {
793 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
794 runTest("simple.gro", selections);
798 TEST_F(SelectionCollectionDataTest, HandlesSameResidue)
800 static const char * const selections[] = {
801 "same residue as atomnr 1 4 12"
803 runTest("simple.gro", selections);
807 TEST_F(SelectionCollectionDataTest, HandlesSameResidueName)
809 static const char * const selections[] = {
810 "same resname as atomnr 1 14"
812 runTest("simple.gro", selections);
816 TEST_F(SelectionCollectionDataTest, HandlesPositionKeywords)
818 static const char * const selections[] = {
820 "res_cog of name CB and resnr 1 3",
821 "whole_res_cog of name CB and resnr 1 3",
822 "part_res_cog of x < 3",
823 "dyn_res_cog of x < 3"
825 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates
826 | efTestPositionAtoms);
827 runTest("simple.gro", selections);
831 TEST_F(SelectionCollectionDataTest, HandlesDistanceKeyword)
833 static const char * const selections[] = {
834 "distance from cog of resnr 1 < 2"
836 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
837 runTest("simple.gro", selections);
841 TEST_F(SelectionCollectionDataTest, HandlesMinDistanceKeyword)
843 static const char * const selections[] = {
844 "mindistance from resnr 1 < 2"
846 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
847 runTest("simple.gro", selections);
851 TEST_F(SelectionCollectionDataTest, HandlesWithinKeyword)
853 static const char * const selections[] = {
854 "within 1 of resnr 2"
856 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
857 runTest("simple.gro", selections);
861 TEST_F(SelectionCollectionDataTest, HandlesInSolidAngleKeyword)
863 // Both of these should evaluate to empty on a correct implementation.
864 static const char * const selections[] = {
865 "resname TP and not insolidangle center cog of resname C span resname R cutoff 20",
866 "resname TN and insolidangle center cog of resname C span resname R cutoff 20"
868 setFlags(TestFlags() | efDontTestCompiledAtoms | efTestEvaluation);
869 runTest("sphere.gro", selections);
873 TEST_F(SelectionCollectionDataTest, HandlesPermuteModifier)
875 static const char * const selections[] = {
877 "res_cog of resnr 1 to 4 permute 2 1",
878 "name CB S1 and res_cog x < 3 permute 2 1"
880 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates
881 | efTestPositionAtoms | efTestPositionMapping);
882 runTest("simple.gro", selections);
886 TEST_F(SelectionCollectionDataTest, HandlesPlusModifier)
888 static const char * const selections[] = {
889 "name S2 plus name S1",
890 "res_cog of resnr 2 plus res_cog of resnr 1 plus res_cog of resnr 3",
891 "name S1 and y < 3 plus res_cog of x < 2.5"
893 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates
894 | efTestPositionAtoms | efTestPositionMapping);
895 runTest("simple.gro", selections);
899 TEST_F(SelectionCollectionDataTest, HandlesMergeModifier)
901 static const char * const selections[] = {
902 "name S2 merge name S1",
903 "resnr 1 2 and name S2 merge resnr 1 2 and name S1 merge res_cog of resnr 1 2",
904 "name S1 and x < 2.5 merge res_cog of x < 2.5"
906 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates
907 | efTestPositionAtoms | efTestPositionMapping);
908 runTest("simple.gro", selections);
912 /********************************************************************
913 * Tests for generic selection evaluation
916 TEST_F(SelectionCollectionDataTest, ComputesMassesAndCharges)
918 static const char * const selections[] = {
923 setFlags(TestFlags() | efTestEvaluation | efTestPositionAtoms
924 | efTestPositionMasses | efTestPositionCharges);
925 ASSERT_NO_FATAL_FAILURE(runParser(selections));
926 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
927 for (int i = 0; i < top_->atoms.nr; ++i)
929 top_->atoms.atom[i].m = 1.0 + i / 100.0;
930 top_->atoms.atom[i].q = -(1.0 + i / 100.0);
932 ASSERT_NO_FATAL_FAILURE(runCompiler());
933 ASSERT_NO_FATAL_FAILURE(runEvaluate());
934 ASSERT_NO_FATAL_FAILURE(runEvaluateFinal());
937 TEST_F(SelectionCollectionDataTest, ComputesMassesAndChargesWithoutTopology)
939 static const char * const selections[] = {
940 "atomnr 1 to 3 8 to 9",
944 setFlags(TestFlags() | efTestPositionAtoms
945 | efTestPositionMasses | efTestPositionCharges);
946 runTest(10, selections);
950 /********************************************************************
951 * Tests for selection syntactic constructs
954 TEST_F(SelectionCollectionDataTest, HandlesSelectionNames)
956 static const char * const selections[] = {
957 "\"GroupSelection\" group \"GrpA\"",
958 "\"DynamicSelection\" x < 5",
961 setFlags(TestFlags() | efTestSelectionNames);
962 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
963 runTest(10, selections);
966 TEST_F(SelectionCollectionDataTest, HandlesIndexGroupsInSelections)
968 static const char * const selections[] = {
972 "group \"GrpB\" and resname RB"
974 setFlags(TestFlags() | efTestSelectionNames);
975 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
976 runTest("simple.gro", selections);
979 TEST_F(SelectionCollectionDataTest, HandlesIndexGroupsInSelectionsDelayed)
981 static const char * const selections[] = {
985 "group \"GrpB\" and resname RB"
987 setFlags(TestFlags() | efTestSelectionNames);
988 ASSERT_NO_FATAL_FAILURE(runParser(selections));
989 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
990 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
991 ASSERT_NO_FATAL_FAILURE(runCompiler());
994 TEST_F(SelectionCollectionDataTest, HandlesUnsortedIndexGroupsInSelections)
996 static const char * const selections[] = {
997 "foo = group \"GrpUnsorted\"",
998 "group \"GrpUnsorted\"",
1001 "res_cog of group \"GrpUnsorted\"",
1002 "group \"GrpUnsorted\" permute 2 1",
1005 setFlags(TestFlags() | efTestPositionAtoms | efTestPositionMapping
1006 | efTestSelectionNames);
1007 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
1008 runTest("simple.gro", selections);
1011 TEST_F(SelectionCollectionDataTest, HandlesUnsortedIndexGroupsInSelectionsDelayed)
1013 static const char * const selections[] = {
1014 "foo = group \"GrpUnsorted\"",
1015 "group \"GrpUnsorted\"",
1018 "res_cog of group \"GrpUnsorted\"",
1019 "group \"GrpUnsorted\" permute 2 1",
1022 ASSERT_NO_FATAL_FAILURE(runParser(selections));
1023 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
1024 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
1025 ASSERT_NO_FATAL_FAILURE(runCompiler());
1028 TEST_F(SelectionCollectionDataTest, HandlesConstantPositions)
1030 static const char * const selections[] = {
1033 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1034 runTest("simple.gro", selections);
1038 TEST_F(SelectionCollectionDataTest, HandlesWithinConstantPositions)
1040 static const char * const selections[] = {
1041 "within 1 of [2, 1, 0]"
1043 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1044 runTest("simple.gro", selections);
1048 TEST_F(SelectionCollectionDataTest, HandlesForcedStringMatchingMode)
1050 static const char * const selections[] = {
1054 runTest("simple.gro", selections);
1058 TEST_F(SelectionCollectionDataTest, HandlesWildcardMatching)
1060 static const char * const selections[] = {
1064 runTest("simple.gro", selections);
1068 TEST_F(SelectionCollectionDataTest, HandlesRegexMatching)
1070 static const char * const selections[] = {
1071 "resname \"R[BD]\"",
1072 "resname ~ \"R[BD]\""
1074 if (gmx::Regex::isSupported())
1076 runTest("simple.gro", selections);
1081 TEST_F(SelectionCollectionDataTest, HandlesBasicBoolean)
1083 static const char * const selections[] = {
1084 "atomnr 1 to 5 and atomnr 2 to 7",
1085 "atomnr 1 to 5 or not atomnr 3 to 8",
1086 "not not atomnr 1 to 5 and atomnr 2 to 6 and not not atomnr 3 to 7",
1087 "atomnr 1 to 5 and (atomnr 2 to 7 and atomnr 3 to 6)",
1088 "x < 5 and atomnr 1 to 5 and y < 3 and atomnr 2 to 4"
1090 runTest(10, selections);
1094 TEST_F(SelectionCollectionDataTest, HandlesDynamicAtomValuedParameters)
1096 static const char * const selections[] = {
1097 "same residue as (atomnr 3 5 13 or y > 5)",
1098 "(resnr 1 3 5 or x > 10) and same residue as (atomnr 3 5 13 or z > 5)"
1100 setFlags(TestFlags() | efTestEvaluation);
1101 runTest("simple.gro", selections);
1105 TEST_F(SelectionCollectionDataTest, HandlesEmptySelectionWithUnevaluatedExpressions)
1107 static const char * const selections[] = {
1109 "none and same resname as resnr 2"
1111 runTest("simple.gro", selections);
1115 TEST_F(SelectionCollectionDataTest, HandlesNumericComparisons)
1117 static const char * const selections[] = {
1124 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1125 runTest("simple.gro", selections);
1129 TEST_F(SelectionCollectionDataTest, HandlesArithmeticExpressions)
1131 static const char * const selections[] = {
1137 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1138 runTest("simple.gro", selections);
1142 TEST_F(SelectionCollectionDataTest, HandlesNumericVariables)
1144 static const char * const selections[] = {
1150 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1151 runTest("simple.gro", selections);
1155 TEST_F(SelectionCollectionDataTest, HandlesComplexNumericVariables)
1157 static const char * const selections[] = {
1159 "resname RA and value <= 4",
1160 "resname RA RB and x < 3 and value <= 4",
1162 "resname RA and index < 3",
1163 "resname RB and y < 3 and index < 6"
1165 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1166 runTest("simple.gro", selections);
1170 TEST_F(SelectionCollectionDataTest, HandlesPositionVariables)
1172 static const char * const selections[] = {
1173 "foo = res_cog of resname RA",
1176 "bar = cog of resname RA",
1180 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1181 runTest("simple.gro", selections);
1185 TEST_F(SelectionCollectionDataTest, HandlesConstantPositionInVariable)
1187 static const char * const selections[] = {
1188 "constpos = [1.0, 2.5, 0.5]",
1190 "within 2 of constpos"
1192 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates
1193 | efTestPositionAtoms);
1194 runTest("simple.gro", selections);
1198 TEST_F(SelectionCollectionDataTest, HandlesNumericConstantsInVariables)
1200 static const char * const selections[] = {
1205 "x + constreal1 < constreal2"
1207 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1208 runTest("simple.gro", selections);
1212 /********************************************************************
1213 * Tests for complex boolean syntax
1216 TEST_F(SelectionCollectionDataTest, HandlesBooleanStaticAnalysis)
1218 static const char * const selections[] = {
1219 "atomnr 1 to 5 and atomnr 2 to 7 and x < 2",
1220 "atomnr 1 to 5 and (atomnr 4 to 7 or x < 2)",
1221 "atomnr 1 to 5 and y < 3 and (atomnr 4 to 7 or x < 2)",
1222 "atomnr 1 to 5 and not (atomnr 4 to 7 or x < 2)",
1223 "atomnr 1 to 5 or (atomnr 4 to 6 and (atomnr 5 to 7 or x < 2))"
1225 runTest(10, selections);
1229 TEST_F(SelectionCollectionDataTest, HandlesBooleanStaticAnalysisWithVariables)
1231 static const char * const selections[] = {
1232 "foo = atomnr 4 to 7 or x < 2",
1233 "atomnr 1 to 4 and foo",
1234 "atomnr 2 to 6 and y < 3 and foo",
1235 "atomnr 6 to 10 and not foo"
1237 runTest(10, selections);
1241 TEST_F(SelectionCollectionDataTest, HandlesBooleanStaticAnalysisWithMoreVariables)
1243 static const char * const selections[] = {
1244 "foo = atomnr 4 to 7",
1245 "bar = foo and x < 2",
1246 "bar2 = foo and y < 2",
1247 "atomnr 1 to 4 and bar",
1248 "atomnr 2 to 6 and y < 3 and bar2",
1249 "atomnr 6 to 10 and not foo"
1251 runTest(10, selections);
1255 /********************************************************************
1256 * Tests for complex subexpression cases
1258 * These tests use some knowledge of the implementation to trigger different
1259 * paths in the code.
1262 TEST_F(SelectionCollectionDataTest, HandlesUnusedVariables)
1264 static const char * const selections[] = {
1265 "unused1 = atomnr 1 to 3",
1266 "foo = atomnr 4 to 7",
1267 "atomnr 1 to 6 and foo",
1268 "unused2 = atomnr 3 to 5"
1270 runTest(10, selections);
1274 TEST_F(SelectionCollectionDataTest, HandlesVariablesWithStaticEvaluationGroups)
1276 static const char * const selections[] = {
1277 "foo = atomnr 4 to 7 and x < 2",
1278 "atomnr 1 to 5 and foo",
1279 "atomnr 3 to 7 and foo"
1281 runTest(10, selections);
1285 TEST_F(SelectionCollectionDataTest, HandlesVariablesWithMixedEvaluationGroups)
1287 static const char * const selections[] = {
1288 "foo = atomnr 4 to 7 and x < 2",
1289 "atomnr 1 to 6 and foo",
1293 runTest(10, selections);
1297 TEST_F(SelectionCollectionDataTest, HandlesVariablesWithMixedEvaluationGroups2)
1299 static const char * const selections[] = {
1300 "foo = atomnr 1 to 8 and x < 10",
1301 "atomnr 1 to 5 and y < 10 and foo",
1304 setFlags(TestFlags() | efTestEvaluation);
1305 runTest("simple.gro", selections);