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
44 #include <gtest/gtest.h>
46 #include "gromacs/fileio/trx.h"
47 #include "gromacs/options/basicoptions.h"
48 #include "gromacs/options/options.h"
49 #include "gromacs/selection/indexutil.h"
50 #include "gromacs/selection/selectioncollection.h"
51 #include "gromacs/selection/selection.h"
52 #include "gromacs/topology/topology.h"
53 #include "gromacs/utility/arrayref.h"
54 #include "gromacs/utility/exceptions.h"
55 #include "gromacs/utility/flags.h"
56 #include "gromacs/utility/gmxregex.h"
57 #include "gromacs/utility/stringutil.h"
59 #include "testutils/refdata.h"
60 #include "testutils/testasserts.h"
61 #include "testutils/testfilemanager.h"
62 #include "testutils/testoptions.h"
69 /********************************************************************
70 * Test fixture for selection testing
73 class SelectionCollectionTest : public ::testing::Test
76 static int s_debugLevel;
78 SelectionCollectionTest();
79 ~SelectionCollectionTest();
81 void setAtomCount(int natoms)
83 ASSERT_NO_THROW_GMX(sc_.setTopology(NULL, natoms));
85 void loadTopology(const char *filename);
87 void loadIndexGroups(const char *filename);
89 gmx::test::TopologyManager topManager_;
90 gmx::SelectionCollection sc_;
91 gmx::SelectionList sel_;
94 gmx_ana_indexgrps_t *grps_;
97 int SelectionCollectionTest::s_debugLevel = 0;
99 // \cond/\endcond do not seem to work here with Doxygen 1.8.5 parser.
101 GMX_TEST_OPTIONS(SelectionCollectionTestOptions, options)
103 options->addOption(gmx::IntegerOption("seldebug")
104 .store(&SelectionCollectionTest::s_debugLevel)
105 .description("Set selection debug level"));
109 SelectionCollectionTest::SelectionCollectionTest()
110 : top_(NULL), frame_(NULL), grps_(NULL)
112 topManager_.requestFrame();
113 sc_.setDebugLevel(s_debugLevel);
114 sc_.setReferencePosType("atom");
115 sc_.setOutputPosType("atom");
118 SelectionCollectionTest::~SelectionCollectionTest()
122 gmx_ana_indexgrps_free(grps_);
127 SelectionCollectionTest::loadTopology(const char *filename)
129 topManager_.loadTopology(filename);
134 SelectionCollectionTest::setTopology()
136 top_ = topManager_.topology();
137 frame_ = topManager_.frame();
139 ASSERT_NO_THROW_GMX(sc_.setTopology(top_, -1));
143 SelectionCollectionTest::loadIndexGroups(const char *filename)
145 GMX_RELEASE_ASSERT(grps_ == NULL,
146 "External groups can only be loaded once");
147 std::string fullpath =
148 gmx::test::TestFileManager::getInputFilePath(filename);
149 gmx_ana_indexgrps_init(&grps_, NULL, fullpath.c_str());
150 sc_.setIndexGroups(grps_);
154 /********************************************************************
155 * Test fixture for selection testing with reference data
158 class SelectionCollectionDataTest : public SelectionCollectionTest
163 efTestEvaluation = 1<<0,
164 efTestPositionAtoms = 1<<1,
165 efTestPositionCoordinates = 1<<2,
166 efTestPositionMapping = 1<<3,
167 efTestPositionMasses = 1<<4,
168 efTestPositionCharges = 1<<5,
169 efTestSelectionNames = 1<<6,
170 efDontTestCompiledAtoms = 1<<8
172 typedef gmx::FlagsTemplate<TestFlag> TestFlags;
174 SelectionCollectionDataTest()
175 : checker_(data_.rootChecker()), count_(0), framenr_(0)
179 void setFlags(TestFlags flags) { flags_ = flags; }
181 void runParser(const gmx::ConstArrayRef<const char *> &selections);
184 void runEvaluateFinal();
186 void runTest(int natoms,
187 const gmx::ConstArrayRef<const char *> &selections);
188 void runTest(const char *filename,
189 const gmx::ConstArrayRef<const char *> &selections);
192 static void checkSelection(gmx::test::TestReferenceChecker *checker,
193 const gmx::Selection &sel, TestFlags flags);
195 void checkCompiled();
197 gmx::test::TestReferenceData data_;
198 gmx::test::TestReferenceChecker checker_;
206 SelectionCollectionDataTest::checkSelection(
207 gmx::test::TestReferenceChecker *checker,
208 const gmx::Selection &sel, TestFlags flags)
210 using gmx::test::TestReferenceChecker;
213 gmx::ConstArrayRef<int> atoms = sel.atomIndices();
214 checker->checkSequence(atoms.begin(), atoms.end(), "Atoms");
216 if (flags.test(efTestPositionAtoms)
217 || flags.test(efTestPositionCoordinates)
218 || flags.test(efTestPositionMapping)
219 || flags.test(efTestPositionMasses)
220 || flags.test(efTestPositionCharges))
222 TestReferenceChecker compound(
223 checker->checkSequenceCompound("Positions", sel.posCount()));
224 for (int i = 0; i < sel.posCount(); ++i)
226 TestReferenceChecker poscompound(compound.checkCompound("Position", NULL));
227 const gmx::SelectionPosition &p = sel.position(i);
228 if (flags.test(efTestPositionAtoms))
230 gmx::ConstArrayRef<int> atoms = p.atomIndices();
231 poscompound.checkSequence(atoms.begin(), atoms.end(), "Atoms");
233 if (flags.test(efTestPositionCoordinates))
235 poscompound.checkVector(p.x(), "Coordinates");
237 if (flags.test(efTestPositionMapping))
239 poscompound.checkInteger(p.refId(), "RefId");
240 poscompound.checkInteger(p.mappedId(), "MappedId");
242 if (flags.test(efTestPositionMasses))
244 poscompound.checkReal(p.mass(), "Mass");
246 if (flags.test(efTestPositionCharges))
248 poscompound.checkReal(p.charge(), "Charge");
256 SelectionCollectionDataTest::runParser(
257 const gmx::ConstArrayRef<const char *> &selections)
259 using gmx::test::TestReferenceChecker;
261 TestReferenceChecker compound(checker_.checkCompound("ParsedSelections", "Parsed"));
264 for (size_t i = 0; i < selections.size(); ++i)
266 SCOPED_TRACE(std::string("Parsing selection \"")
267 + selections[i] + "\"");
268 gmx::SelectionList result;
269 ASSERT_NO_THROW_GMX(result = sc_.parseFromString(selections[i]));
270 sel_.insert(sel_.end(), result.begin(), result.end());
271 if (sel_.size() == count_)
273 std::string id = gmx::formatString("Variable%d", static_cast<int>(varcount + 1));
274 TestReferenceChecker varcompound(
275 compound.checkCompound("ParsedVariable", id.c_str()));
276 varcompound.checkString(selections[i], "Input");
281 std::string id = gmx::formatString("Selection%d", static_cast<int>(count_ + 1));
282 TestReferenceChecker selcompound(
283 compound.checkCompound("ParsedSelection", id.c_str()));
284 selcompound.checkString(selections[i], "Input");
285 if (flags_.test(efTestSelectionNames))
287 selcompound.checkString(sel_[count_].name(), "Name");
289 selcompound.checkString(sel_[count_].selectionText(), "Text");
290 selcompound.checkBoolean(sel_[count_].isDynamic(), "Dynamic");
298 SelectionCollectionDataTest::runCompiler()
300 ASSERT_NO_THROW_GMX(sc_.compile());
301 ASSERT_EQ(count_, sel_.size());
307 SelectionCollectionDataTest::checkCompiled()
309 using gmx::test::TestReferenceChecker;
310 const TestFlags mask = ~TestFlags(efTestPositionCoordinates);
312 TestReferenceChecker compound(checker_.checkCompound("CompiledSelections", "Compiled"));
313 for (size_t i = 0; i < count_; ++i)
315 SCOPED_TRACE(std::string("Checking selection \"") +
316 sel_[i].selectionText() + "\"");
317 std::string id = gmx::formatString("Selection%d", static_cast<int>(i + 1));
318 TestReferenceChecker selcompound(
319 compound.checkCompound("Selection", id.c_str()));
320 if (flags_.test(efTestSelectionNames))
322 selcompound.checkString(sel_[i].name(), "Name");
324 if (!flags_.test(efDontTestCompiledAtoms))
326 checkSelection(&selcompound, sel_[i], flags_ & mask);
333 SelectionCollectionDataTest::runEvaluate()
335 using gmx::test::TestReferenceChecker;
338 ASSERT_NO_THROW_GMX(sc_.evaluate(frame_, NULL));
339 std::string frame = gmx::formatString("Frame%d", framenr_);
340 TestReferenceChecker compound(
341 checker_.checkCompound("EvaluatedSelections", frame.c_str()));
342 for (size_t i = 0; i < count_; ++i)
344 SCOPED_TRACE(std::string("Checking selection \"") +
345 sel_[i].selectionText() + "\"");
346 std::string id = gmx::formatString("Selection%d", static_cast<int>(i + 1));
347 TestReferenceChecker selcompound(
348 compound.checkCompound("Selection", id.c_str()));
349 checkSelection(&selcompound, sel_[i], flags_);
355 SelectionCollectionDataTest::runEvaluateFinal()
357 ASSERT_NO_THROW_GMX(sc_.evaluateFinal(framenr_));
363 SelectionCollectionDataTest::runTest(
364 int natoms, const gmx::ConstArrayRef<const char *> &selections)
366 ASSERT_NO_FATAL_FAILURE(runParser(selections));
367 ASSERT_NO_FATAL_FAILURE(setAtomCount(natoms));
368 ASSERT_NO_FATAL_FAILURE(runCompiler());
373 SelectionCollectionDataTest::runTest(
374 const char *filename, const gmx::ConstArrayRef<const char *> &selections)
376 ASSERT_NO_FATAL_FAILURE(runParser(selections));
377 ASSERT_NO_FATAL_FAILURE(loadTopology(filename));
378 ASSERT_NO_FATAL_FAILURE(runCompiler());
379 if (flags_.test(efTestEvaluation))
381 ASSERT_NO_FATAL_FAILURE(runEvaluate());
382 ASSERT_NO_FATAL_FAILURE(runEvaluateFinal());
387 /********************************************************************
388 * Tests for SelectionCollection functionality without reference data
391 TEST_F(SelectionCollectionTest, HandlesNoSelections)
393 EXPECT_FALSE(sc_.requiresTopology());
394 EXPECT_NO_THROW_GMX(sc_.compile());
397 TEST_F(SelectionCollectionTest, HandlesVelocityAndForceRequests)
399 ASSERT_NO_THROW_GMX(sel_ = sc_.parseFromString("atomnr 1 to 10; none"));
400 ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
401 ASSERT_EQ(2U, sel_.size());
402 ASSERT_NO_THROW_GMX(sel_[0].setEvaluateVelocities(true));
403 ASSERT_NO_THROW_GMX(sel_[1].setEvaluateVelocities(true));
404 ASSERT_NO_THROW_GMX(sel_[0].setEvaluateForces(true));
405 ASSERT_NO_THROW_GMX(sel_[1].setEvaluateForces(true));
406 ASSERT_NO_THROW_GMX(sc_.compile());
407 EXPECT_TRUE(sel_[0].hasVelocities());
408 EXPECT_TRUE(sel_[1].hasVelocities());
409 EXPECT_TRUE(sel_[0].hasForces());
410 EXPECT_TRUE(sel_[1].hasForces());
413 TEST_F(SelectionCollectionTest, ParsesSelectionsFromFile)
415 ASSERT_NO_THROW_GMX(sel_ = sc_.parseFromFile(
416 gmx::test::TestFileManager::getInputFilePath("selfile.dat")));
417 // These should match the contents of selfile.dat
418 ASSERT_EQ(2U, sel_.size());
419 EXPECT_STREQ("resname RA RB", sel_[0].selectionText());
420 EXPECT_STREQ("resname RB RC", sel_[1].selectionText());
423 TEST_F(SelectionCollectionTest, HandlesAtypicalWhitespace)
425 ASSERT_NO_THROW_GMX(sel_ = sc_.parseFromString("atomnr\n1\r\nto\t10;\vatomnr 3\f to 14\r"));
426 ASSERT_EQ(2U, sel_.size());
427 EXPECT_STREQ("atomnr 1 to 10", sel_[0].selectionText());
428 // TODO: Get rid of the trailing whitespace.
429 EXPECT_STREQ("atomnr 3 to 14 ", sel_[1].selectionText());
432 TEST_F(SelectionCollectionTest, HandlesInvalidRegularExpressions)
434 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
436 sc_.parseFromString("resname ~ \"R[A\"");
438 }, gmx::InvalidInputError);
441 TEST_F(SelectionCollectionTest, HandlesUnsupportedRegularExpressions)
443 if (!gmx::Regex::isSupported())
445 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
447 sc_.parseFromString("resname \"R[AD]\"");
449 }, gmx::InvalidInputError);
453 TEST_F(SelectionCollectionTest, HandlesMissingMethodParamValue)
455 EXPECT_THROW_GMX(sc_.parseFromString("mindist from atomnr 1 cutoff"),
456 gmx::InvalidInputError);
459 TEST_F(SelectionCollectionTest, HandlesMissingMethodParamValue2)
461 EXPECT_THROW_GMX(sc_.parseFromString("within 1 of"),
462 gmx::InvalidInputError);
465 TEST_F(SelectionCollectionTest, HandlesMissingMethodParamValue3)
467 EXPECT_THROW_GMX(sc_.parseFromString("within of atomnr 1"),
468 gmx::InvalidInputError);
471 // TODO: Tests for more parser errors
473 TEST_F(SelectionCollectionTest, HandlesUnknownGroupReferenceParser1)
475 ASSERT_NO_THROW_GMX(sc_.setIndexGroups(NULL));
476 EXPECT_THROW_GMX(sc_.parseFromString("group \"foo\""), gmx::InconsistentInputError);
477 EXPECT_THROW_GMX(sc_.parseFromString("4"), gmx::InconsistentInputError);
480 TEST_F(SelectionCollectionTest, HandlesUnknownGroupReferenceParser2)
482 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
483 EXPECT_THROW_GMX(sc_.parseFromString("group \"foo\""), gmx::InconsistentInputError);
484 EXPECT_THROW_GMX(sc_.parseFromString("4"), gmx::InconsistentInputError);
487 TEST_F(SelectionCollectionTest, HandlesUnknownGroupReferenceDelayed1)
489 ASSERT_NO_THROW_GMX(sc_.parseFromString("group \"foo\""));
490 ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
491 EXPECT_THROW_GMX(sc_.setIndexGroups(NULL), gmx::InconsistentInputError);
492 EXPECT_THROW_GMX(sc_.compile(), gmx::APIError);
495 TEST_F(SelectionCollectionTest, HandlesUnknownGroupReferenceDelayed2)
497 ASSERT_NO_THROW_GMX(sc_.parseFromString("group 4; group \"foo\""));
498 ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
499 EXPECT_THROW_GMX(loadIndexGroups("simple.ndx"), gmx::InconsistentInputError);
500 EXPECT_THROW_GMX(sc_.compile(), gmx::APIError);
503 TEST_F(SelectionCollectionTest, HandlesUnsortedGroupReference)
505 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
506 EXPECT_THROW_GMX(sc_.parseFromString("atomnr 1 to 3 and group \"GrpUnsorted\""),
507 gmx::InconsistentInputError);
508 EXPECT_THROW_GMX(sc_.parseFromString("group 2 or atomnr 2 to 5"),
509 gmx::InconsistentInputError);
510 EXPECT_THROW_GMX(sc_.parseFromString("within 1 of group 2"),
511 gmx::InconsistentInputError);
514 TEST_F(SelectionCollectionTest, HandlesUnsortedGroupReferenceDelayed)
516 ASSERT_NO_THROW_GMX(sc_.parseFromString("atomnr 1 to 3 and group \"GrpUnsorted\""));
517 ASSERT_NO_THROW_GMX(sc_.parseFromString("atomnr 1 to 3 and group 2"));
518 EXPECT_THROW_GMX(loadIndexGroups("simple.ndx"), gmx::InconsistentInputError);
519 // TODO: Add a separate check in the selection compiler for a safer API
520 // (makes sense in the future if the compiler needs the information for
521 // other purposes as well).
522 // EXPECT_THROW_GMX(sc_.compile(), gmx::APIError);
525 TEST_F(SelectionCollectionTest, HandlesOutOfRangeAtomIndexInGroup)
527 ASSERT_NO_THROW_GMX(sc_.setTopology(NULL, 5));
528 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
529 EXPECT_THROW_GMX(sc_.parseFromString("group \"GrpB\""), gmx::InconsistentInputError);
532 TEST_F(SelectionCollectionTest, HandlesOutOfRangeAtomIndexInGroupDelayed)
534 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
535 ASSERT_NO_THROW_GMX(sc_.parseFromString("group \"GrpB\""));
536 EXPECT_THROW_GMX(sc_.setTopology(NULL, 5), gmx::InconsistentInputError);
539 TEST_F(SelectionCollectionTest, HandlesOutOfRangeAtomIndexInGroupDelayed2)
541 ASSERT_NO_THROW_GMX(sc_.setTopology(NULL, 5));
542 ASSERT_NO_THROW_GMX(sc_.parseFromString("group \"GrpB\""));
543 EXPECT_THROW_GMX(loadIndexGroups("simple.ndx"), gmx::InconsistentInputError);
546 TEST_F(SelectionCollectionTest, RecoversFromMissingMoleculeInfo)
548 ASSERT_NO_THROW_GMX(sc_.parseFromString("molindex 1 to 5"));
549 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
550 EXPECT_THROW_GMX(sc_.compile(), gmx::InconsistentInputError);
553 TEST_F(SelectionCollectionTest, RecoversFromMissingAtomTypes)
555 ASSERT_NO_THROW_GMX(sc_.parseFromString("type CA"));
556 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
557 EXPECT_THROW_GMX(sc_.compile(), gmx::InconsistentInputError);
560 TEST_F(SelectionCollectionTest, RecoversFromMissingPDBInfo)
562 ASSERT_NO_THROW_GMX(sc_.parseFromString("altloc A"));
563 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
564 EXPECT_THROW_GMX(sc_.compile(), gmx::InconsistentInputError);
567 TEST_F(SelectionCollectionTest, RecoversFromInvalidPermutation)
569 ASSERT_NO_THROW_GMX(sc_.parseFromString("all permute 1 1"));
570 ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
571 EXPECT_THROW_GMX(sc_.compile(), gmx::InvalidInputError);
574 TEST_F(SelectionCollectionTest, RecoversFromInvalidPermutation2)
576 ASSERT_NO_THROW_GMX(sc_.parseFromString("all permute 3 2 1"));
577 ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
578 EXPECT_THROW_GMX(sc_.compile(), gmx::InconsistentInputError);
581 TEST_F(SelectionCollectionTest, RecoversFromInvalidPermutation3)
583 ASSERT_NO_THROW_GMX(sc_.parseFromString("x < 1.5 permute 3 2 1"));
584 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
585 ASSERT_NO_THROW_GMX(sc_.compile());
586 EXPECT_THROW_GMX(sc_.evaluate(frame_, NULL), gmx::InconsistentInputError);
589 TEST_F(SelectionCollectionTest, HandlesFramesWithTooSmallAtomSubsets)
591 ASSERT_NO_THROW_GMX(sc_.parseFromString("atomnr 3 to 10"));
592 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
593 ASSERT_NO_THROW_GMX(sc_.compile());
595 EXPECT_THROW_GMX(sc_.evaluate(frame_, NULL), gmx::InconsistentInputError);
598 TEST_F(SelectionCollectionTest, HandlesFramesWithTooSmallAtomSubsets2)
600 // Evaluating the positions will require atoms 1-9.
601 ASSERT_NO_THROW_GMX(sc_.parseFromString("whole_res_com of atomnr 2 5 7"));
602 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
603 ASSERT_NO_THROW_GMX(sc_.compile());
605 EXPECT_THROW_GMX(sc_.evaluate(frame_, NULL), gmx::InconsistentInputError);
608 TEST_F(SelectionCollectionTest, HandlesFramesWithTooSmallAtomSubsets3)
610 ASSERT_NO_THROW_GMX(sc_.parseFromString("mindistance from atomnr 1 to 5 < 2"));
611 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
612 ASSERT_NO_THROW_GMX(sc_.compile());
614 EXPECT_THROW_GMX(sc_.evaluate(frame_, NULL), gmx::InconsistentInputError);
617 // TODO: Tests for more evaluation errors
620 /********************************************************************
621 * Tests for selection keywords
624 TEST_F(SelectionCollectionDataTest, HandlesAllNone)
626 static const char * const selections[] = {
630 runTest(10, selections);
633 TEST_F(SelectionCollectionDataTest, HandlesAtomnr)
635 static const char * const selections[] = {
636 "atomnr 1 to 3 6 to 8",
640 runTest(10, selections);
643 TEST_F(SelectionCollectionDataTest, HandlesResnr)
645 static const char * const selections[] = {
649 runTest("simple.gro", selections);
652 TEST_F(SelectionCollectionDataTest, HandlesResIndex)
654 static const char * const selections[] = {
658 runTest("simple.pdb", selections);
661 TEST_F(SelectionCollectionDataTest, HandlesMolIndex)
663 static const char * const selections[] = {
667 ASSERT_NO_FATAL_FAILURE(runParser(selections));
668 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
669 topManager_.initUniformMolecules(3);
670 ASSERT_NO_FATAL_FAILURE(runCompiler());
673 TEST_F(SelectionCollectionDataTest, HandlesAtomname)
675 static const char * const selections[] = {
679 runTest("simple.gro", selections);
682 TEST_F(SelectionCollectionDataTest, HandlesPdbAtomname)
684 static const char * const selections[] = {
690 runTest("simple.pdb", selections);
694 TEST_F(SelectionCollectionDataTest, HandlesAtomtype)
696 static const char * const selections[] = {
699 ASSERT_NO_FATAL_FAILURE(runParser(selections));
700 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
701 const char *const types[] = { "CA", "SA", "SB" };
702 topManager_.initAtomTypes(types);
703 ASSERT_NO_FATAL_FAILURE(runCompiler());
706 TEST_F(SelectionCollectionDataTest, HandlesChain)
708 static const char * const selections[] = {
712 runTest("simple.pdb", selections);
715 TEST_F(SelectionCollectionDataTest, HandlesMass)
717 static const char * const selections[] = {
720 ASSERT_NO_FATAL_FAILURE(runParser(selections));
721 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
722 for (int i = 0; i < top_->atoms.nr; ++i)
724 top_->atoms.atom[i].m = 1.0 + i;
726 ASSERT_NO_FATAL_FAILURE(runCompiler());
729 TEST_F(SelectionCollectionDataTest, HandlesCharge)
731 static const char * const selections[] = {
734 ASSERT_NO_FATAL_FAILURE(runParser(selections));
735 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
736 for (int i = 0; i < top_->atoms.nr; ++i)
738 top_->atoms.atom[i].q = i / 10.0;
740 ASSERT_NO_FATAL_FAILURE(runCompiler());
743 TEST_F(SelectionCollectionDataTest, HandlesAltLoc)
745 static const char * const selections[] = {
749 runTest("simple.pdb", selections);
752 TEST_F(SelectionCollectionDataTest, HandlesInsertCode)
754 static const char * const selections[] = {
758 runTest("simple.pdb", selections);
761 TEST_F(SelectionCollectionDataTest, HandlesOccupancy)
763 static const char * const selections[] = {
767 runTest("simple.pdb", selections);
770 TEST_F(SelectionCollectionDataTest, HandlesBeta)
772 static const char * const selections[] = {
776 runTest("simple.pdb", selections);
779 TEST_F(SelectionCollectionDataTest, HandlesResname)
781 static const char * const selections[] = {
785 runTest("simple.gro", selections);
788 TEST_F(SelectionCollectionDataTest, HandlesCoordinateKeywords)
790 static const char * const selections[] = {
795 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
796 runTest("simple.gro", selections);
800 TEST_F(SelectionCollectionDataTest, HandlesSameResidue)
802 static const char * const selections[] = {
803 "same residue as atomnr 1 4 12"
805 runTest("simple.gro", selections);
809 TEST_F(SelectionCollectionDataTest, HandlesSameResidueName)
811 static const char * const selections[] = {
812 "same resname as atomnr 1 14"
814 runTest("simple.gro", selections);
818 TEST_F(SelectionCollectionDataTest, HandlesPositionKeywords)
820 static const char * const selections[] = {
822 "res_cog of name CB and resnr 1 3",
823 "whole_res_cog of name CB and resnr 1 3",
824 "part_res_cog of x < 3",
825 "dyn_res_cog of x < 3"
827 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates
828 | efTestPositionAtoms);
829 runTest("simple.gro", selections);
833 TEST_F(SelectionCollectionDataTest, HandlesDistanceKeyword)
835 static const char * const selections[] = {
836 "distance from cog of resnr 1 < 2"
838 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
839 runTest("simple.gro", selections);
843 TEST_F(SelectionCollectionDataTest, HandlesMinDistanceKeyword)
845 static const char * const selections[] = {
846 "mindistance from resnr 1 < 2"
848 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
849 runTest("simple.gro", selections);
853 TEST_F(SelectionCollectionDataTest, HandlesWithinKeyword)
855 static const char * const selections[] = {
856 "within 1 of resnr 2"
858 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
859 runTest("simple.gro", selections);
863 TEST_F(SelectionCollectionDataTest, HandlesInSolidAngleKeyword)
865 // Both of these should evaluate to empty on a correct implementation.
866 static const char * const selections[] = {
867 "resname TP and not insolidangle center cog of resname C span resname R cutoff 20",
868 "resname TN and insolidangle center cog of resname C span resname R cutoff 20"
870 setFlags(TestFlags() | efDontTestCompiledAtoms | efTestEvaluation);
871 runTest("sphere.gro", selections);
875 TEST_F(SelectionCollectionDataTest, HandlesPermuteModifier)
877 static const char * const selections[] = {
879 "res_cog of resnr 1 to 4 permute 2 1",
880 "name CB S1 and res_cog x < 3 permute 2 1"
882 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates
883 | efTestPositionAtoms | efTestPositionMapping);
884 runTest("simple.gro", selections);
888 TEST_F(SelectionCollectionDataTest, HandlesPlusModifier)
890 static const char * const selections[] = {
891 "name S2 plus name S1",
892 "res_cog of resnr 2 plus res_cog of resnr 1 plus res_cog of resnr 3",
893 "name S1 and y < 3 plus res_cog of x < 2.5"
895 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates
896 | efTestPositionAtoms | efTestPositionMapping);
897 runTest("simple.gro", selections);
901 TEST_F(SelectionCollectionDataTest, HandlesMergeModifier)
903 static const char * const selections[] = {
904 "name S2 merge name S1",
905 "resnr 1 2 and name S2 merge resnr 1 2 and name S1 merge res_cog of resnr 1 2",
906 "name S1 and x < 2.5 merge res_cog of x < 2.5"
908 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates
909 | efTestPositionAtoms | efTestPositionMapping);
910 runTest("simple.gro", selections);
914 /********************************************************************
915 * Tests for generic selection evaluation
918 TEST_F(SelectionCollectionDataTest, ComputesMassesAndCharges)
920 static const char * const selections[] = {
925 setFlags(TestFlags() | efTestEvaluation | efTestPositionAtoms
926 | efTestPositionMasses | efTestPositionCharges);
927 ASSERT_NO_FATAL_FAILURE(runParser(selections));
928 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
929 for (int i = 0; i < top_->atoms.nr; ++i)
931 top_->atoms.atom[i].m = 1.0 + i / 100.0;
932 top_->atoms.atom[i].q = -(1.0 + i / 100.0);
934 ASSERT_NO_FATAL_FAILURE(runCompiler());
935 ASSERT_NO_FATAL_FAILURE(runEvaluate());
936 ASSERT_NO_FATAL_FAILURE(runEvaluateFinal());
939 TEST_F(SelectionCollectionDataTest, ComputesMassesAndChargesWithoutTopology)
941 static const char * const selections[] = {
942 "atomnr 1 to 3 8 to 9",
946 setFlags(TestFlags() | efTestPositionAtoms
947 | efTestPositionMasses | efTestPositionCharges);
948 runTest(10, selections);
952 /********************************************************************
953 * Tests for selection syntactic constructs
956 TEST_F(SelectionCollectionDataTest, HandlesSelectionNames)
958 static const char * const selections[] = {
959 "\"GroupSelection\" group \"GrpA\"",
960 "\"DynamicSelection\" x < 5",
963 setFlags(TestFlags() | efTestSelectionNames);
964 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
965 runTest(10, selections);
968 TEST_F(SelectionCollectionDataTest, HandlesIndexGroupsInSelections)
970 static const char * const selections[] = {
974 "group \"GrpB\" and resname RB"
976 setFlags(TestFlags() | efTestSelectionNames);
977 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
978 runTest("simple.gro", selections);
981 TEST_F(SelectionCollectionDataTest, HandlesIndexGroupsInSelectionsDelayed)
983 static const char * const selections[] = {
987 "group \"GrpB\" and resname RB"
989 setFlags(TestFlags() | efTestSelectionNames);
990 ASSERT_NO_FATAL_FAILURE(runParser(selections));
991 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
992 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
993 ASSERT_NO_FATAL_FAILURE(runCompiler());
996 TEST_F(SelectionCollectionDataTest, HandlesUnsortedIndexGroupsInSelections)
998 static const char * const selections[] = {
999 "foo = group \"GrpUnsorted\"",
1000 "group \"GrpUnsorted\"",
1003 "res_cog of group \"GrpUnsorted\"",
1004 "group \"GrpUnsorted\" permute 2 1",
1007 setFlags(TestFlags() | efTestPositionAtoms | efTestPositionMapping
1008 | efTestSelectionNames);
1009 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
1010 runTest("simple.gro", selections);
1013 TEST_F(SelectionCollectionDataTest, HandlesUnsortedIndexGroupsInSelectionsDelayed)
1015 static const char * const selections[] = {
1016 "foo = group \"GrpUnsorted\"",
1017 "group \"GrpUnsorted\"",
1020 "res_cog of group \"GrpUnsorted\"",
1021 "group \"GrpUnsorted\" permute 2 1",
1024 ASSERT_NO_FATAL_FAILURE(runParser(selections));
1025 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
1026 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
1027 ASSERT_NO_FATAL_FAILURE(runCompiler());
1030 TEST_F(SelectionCollectionDataTest, HandlesConstantPositions)
1032 static const char * const selections[] = {
1035 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1036 runTest("simple.gro", selections);
1040 TEST_F(SelectionCollectionDataTest, HandlesWithinConstantPositions)
1042 static const char * const selections[] = {
1043 "within 1 of [2, 1, 0]"
1045 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1046 runTest("simple.gro", selections);
1050 TEST_F(SelectionCollectionDataTest, HandlesForcedStringMatchingMode)
1052 static const char * const selections[] = {
1056 runTest("simple.gro", selections);
1060 TEST_F(SelectionCollectionDataTest, HandlesWildcardMatching)
1062 static const char * const selections[] = {
1066 runTest("simple.gro", selections);
1070 TEST_F(SelectionCollectionDataTest, HandlesRegexMatching)
1072 static const char * const selections[] = {
1073 "resname \"R[BD]\"",
1074 "resname ~ \"R[BD]\""
1076 if (gmx::Regex::isSupported())
1078 runTest("simple.gro", selections);
1083 TEST_F(SelectionCollectionDataTest, HandlesBasicBoolean)
1085 static const char * const selections[] = {
1086 "atomnr 1 to 5 and atomnr 2 to 7",
1087 "atomnr 1 to 5 or not atomnr 3 to 8",
1088 "not not atomnr 1 to 5 and atomnr 2 to 6 and not not atomnr 3 to 7",
1089 "atomnr 1 to 5 and (atomnr 2 to 7 and atomnr 3 to 6)",
1090 "x < 5 and atomnr 1 to 5 and y < 3 and atomnr 2 to 4"
1092 runTest(10, selections);
1096 TEST_F(SelectionCollectionDataTest, HandlesDynamicAtomValuedParameters)
1098 static const char * const selections[] = {
1099 "same residue as (atomnr 3 5 13 or y > 5)",
1100 "(resnr 1 3 5 or x > 10) and same residue as (atomnr 3 5 13 or z > 5)"
1102 setFlags(TestFlags() | efTestEvaluation);
1103 runTest("simple.gro", selections);
1107 TEST_F(SelectionCollectionDataTest, HandlesEmptySelectionWithUnevaluatedExpressions)
1109 static const char * const selections[] = {
1111 "none and same resname as resnr 2"
1113 runTest("simple.gro", selections);
1117 TEST_F(SelectionCollectionDataTest, HandlesNumericComparisons)
1119 static const char * const selections[] = {
1126 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1127 runTest("simple.gro", selections);
1131 TEST_F(SelectionCollectionDataTest, HandlesArithmeticExpressions)
1133 static const char * const selections[] = {
1139 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1140 runTest("simple.gro", selections);
1144 TEST_F(SelectionCollectionDataTest, HandlesNumericVariables)
1146 static const char * const selections[] = {
1152 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1153 runTest("simple.gro", selections);
1157 TEST_F(SelectionCollectionDataTest, HandlesComplexNumericVariables)
1159 static const char * const selections[] = {
1161 "resname RA and value <= 4",
1162 "resname RA RB and x < 3 and value <= 4",
1164 "resname RA and index < 3",
1165 "resname RB and y < 3 and index < 6"
1167 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1168 runTest("simple.gro", selections);
1172 TEST_F(SelectionCollectionDataTest, HandlesPositionVariables)
1174 static const char * const selections[] = {
1175 "foo = res_cog of resname RA",
1178 "bar = cog of resname RA",
1182 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1183 runTest("simple.gro", selections);
1187 TEST_F(SelectionCollectionDataTest, HandlesConstantPositionInVariable)
1189 static const char * const selections[] = {
1190 "constpos = [1.0, 2.5, 0.5]",
1192 "within 2 of constpos"
1194 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates
1195 | efTestPositionAtoms);
1196 runTest("simple.gro", selections);
1200 TEST_F(SelectionCollectionDataTest, HandlesNumericConstantsInVariables)
1202 static const char * const selections[] = {
1207 "x + constreal1 < constreal2"
1209 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1210 runTest("simple.gro", selections);
1214 /********************************************************************
1215 * Tests for complex boolean syntax
1218 TEST_F(SelectionCollectionDataTest, HandlesBooleanStaticAnalysis)
1220 static const char * const selections[] = {
1221 "atomnr 1 to 5 and atomnr 2 to 7 and x < 2",
1222 "atomnr 1 to 5 and (atomnr 4 to 7 or x < 2)",
1223 "atomnr 1 to 5 and y < 3 and (atomnr 4 to 7 or x < 2)",
1224 "atomnr 1 to 5 and not (atomnr 4 to 7 or x < 2)",
1225 "atomnr 1 to 5 or (atomnr 4 to 6 and (atomnr 5 to 7 or x < 2))"
1227 runTest(10, selections);
1231 TEST_F(SelectionCollectionDataTest, HandlesBooleanStaticAnalysisWithVariables)
1233 static const char * const selections[] = {
1234 "foo = atomnr 4 to 7 or x < 2",
1235 "atomnr 1 to 4 and foo",
1236 "atomnr 2 to 6 and y < 3 and foo",
1237 "atomnr 6 to 10 and not foo"
1239 runTest(10, selections);
1243 TEST_F(SelectionCollectionDataTest, HandlesBooleanStaticAnalysisWithMoreVariables)
1245 static const char * const selections[] = {
1246 "foo = atomnr 4 to 7",
1247 "bar = foo and x < 2",
1248 "bar2 = foo and y < 2",
1249 "atomnr 1 to 4 and bar",
1250 "atomnr 2 to 6 and y < 3 and bar2",
1251 "atomnr 6 to 10 and not foo"
1253 runTest(10, selections);
1257 /********************************************************************
1258 * Tests for complex subexpression cases
1260 * These tests use some knowledge of the implementation to trigger different
1261 * paths in the code.
1264 TEST_F(SelectionCollectionDataTest, HandlesUnusedVariables)
1266 static const char * const selections[] = {
1267 "unused1 = atomnr 1 to 3",
1268 "foo = atomnr 4 to 7",
1269 "atomnr 1 to 6 and foo",
1270 "unused2 = atomnr 3 to 5"
1272 runTest(10, selections);
1276 TEST_F(SelectionCollectionDataTest, HandlesVariablesWithStaticEvaluationGroups)
1278 static const char * const selections[] = {
1279 "foo = atomnr 4 to 7 and x < 2",
1280 "atomnr 1 to 5 and foo",
1281 "atomnr 3 to 7 and foo"
1283 runTest(10, selections);
1287 TEST_F(SelectionCollectionDataTest, HandlesVariablesWithMixedEvaluationGroups)
1289 static const char * const selections[] = {
1290 "foo = atomnr 4 to 7 and x < 2",
1291 "atomnr 1 to 6 and foo",
1295 runTest(10, selections);
1299 TEST_F(SelectionCollectionDataTest, HandlesVariablesWithMixedEvaluationGroups2)
1301 static const char * const selections[] = {
1302 "foo = atomnr 1 to 8 and x < 10",
1303 "atomnr 1 to 5 and y < 10 and foo",
1306 setFlags(TestFlags() | efTestEvaluation);
1307 runTest("simple.gro", selections);