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 "gromacs/selection/selectioncollection.h"
46 #include <gtest/gtest.h>
48 #include "gromacs/fileio/trx.h"
49 #include "gromacs/options/basicoptions.h"
50 #include "gromacs/options/options.h"
51 #include "gromacs/selection/indexutil.h"
52 #include "gromacs/selection/selection.h"
53 #include "gromacs/topology/topology.h"
54 #include "gromacs/utility/arrayref.h"
55 #include "gromacs/utility/exceptions.h"
56 #include "gromacs/utility/flags.h"
57 #include "gromacs/utility/gmxregex.h"
58 #include "gromacs/utility/stringutil.h"
60 #include "testutils/refdata.h"
61 #include "testutils/testasserts.h"
62 #include "testutils/testfilemanager.h"
63 #include "testutils/testoptions.h"
70 /********************************************************************
71 * Test fixture for selection testing
74 class SelectionCollectionTest : public ::testing::Test
77 static int s_debugLevel;
79 SelectionCollectionTest();
80 ~SelectionCollectionTest();
82 void setAtomCount(int natoms)
84 ASSERT_NO_THROW_GMX(sc_.setTopology(NULL, natoms));
86 void loadTopology(const char *filename);
88 void loadIndexGroups(const char *filename);
90 gmx::test::TopologyManager topManager_;
91 gmx::SelectionCollection sc_;
92 gmx::SelectionList sel_;
95 gmx_ana_indexgrps_t *grps_;
98 int SelectionCollectionTest::s_debugLevel = 0;
100 // \cond/\endcond do not seem to work here with Doxygen 1.8.5 parser.
102 GMX_TEST_OPTIONS(SelectionCollectionTestOptions, options)
104 options->addOption(gmx::IntegerOption("seldebug")
105 .store(&SelectionCollectionTest::s_debugLevel)
106 .description("Set selection debug level"));
110 SelectionCollectionTest::SelectionCollectionTest()
111 : top_(NULL), frame_(NULL), grps_(NULL)
113 topManager_.requestFrame();
114 sc_.setDebugLevel(s_debugLevel);
115 sc_.setReferencePosType("atom");
116 sc_.setOutputPosType("atom");
119 SelectionCollectionTest::~SelectionCollectionTest()
123 gmx_ana_indexgrps_free(grps_);
128 SelectionCollectionTest::loadTopology(const char *filename)
130 topManager_.loadTopology(filename);
135 SelectionCollectionTest::setTopology()
137 top_ = topManager_.topology();
138 frame_ = topManager_.frame();
140 ASSERT_NO_THROW_GMX(sc_.setTopology(top_, -1));
144 SelectionCollectionTest::loadIndexGroups(const char *filename)
146 GMX_RELEASE_ASSERT(grps_ == NULL,
147 "External groups can only be loaded once");
148 std::string fullpath =
149 gmx::test::TestFileManager::getInputFilePath(filename);
150 gmx_ana_indexgrps_init(&grps_, NULL, fullpath.c_str());
151 sc_.setIndexGroups(grps_);
155 /********************************************************************
156 * Test fixture for selection testing with reference data
159 class SelectionCollectionDataTest : public SelectionCollectionTest
164 efTestEvaluation = 1<<0,
165 efTestPositionAtoms = 1<<1,
166 efTestPositionCoordinates = 1<<2,
167 efTestPositionMapping = 1<<3,
168 efTestPositionMasses = 1<<4,
169 efTestPositionCharges = 1<<5,
170 efTestSelectionNames = 1<<6,
171 efDontTestCompiledAtoms = 1<<8
173 typedef gmx::FlagsTemplate<TestFlag> TestFlags;
175 SelectionCollectionDataTest()
176 : checker_(data_.rootChecker()), count_(0), framenr_(0)
180 void setFlags(TestFlags flags) { flags_ = flags; }
182 void runParser(const gmx::ConstArrayRef<const char *> &selections);
185 void runEvaluateFinal();
187 void runTest(int natoms,
188 const gmx::ConstArrayRef<const char *> &selections);
189 void runTest(const char *filename,
190 const gmx::ConstArrayRef<const char *> &selections);
193 static void checkSelection(gmx::test::TestReferenceChecker *checker,
194 const gmx::Selection &sel, TestFlags flags);
196 void checkCompiled();
198 gmx::test::TestReferenceData data_;
199 gmx::test::TestReferenceChecker checker_;
207 SelectionCollectionDataTest::checkSelection(
208 gmx::test::TestReferenceChecker *checker,
209 const gmx::Selection &sel, TestFlags flags)
211 using gmx::test::TestReferenceChecker;
214 gmx::ConstArrayRef<int> atoms = sel.atomIndices();
215 checker->checkSequence(atoms.begin(), atoms.end(), "Atoms");
217 if (flags.test(efTestPositionAtoms)
218 || flags.test(efTestPositionCoordinates)
219 || flags.test(efTestPositionMapping)
220 || flags.test(efTestPositionMasses)
221 || flags.test(efTestPositionCharges))
223 TestReferenceChecker compound(
224 checker->checkSequenceCompound("Positions", sel.posCount()));
225 for (int i = 0; i < sel.posCount(); ++i)
227 TestReferenceChecker poscompound(compound.checkCompound("Position", NULL));
228 const gmx::SelectionPosition &p = sel.position(i);
229 if (flags.test(efTestPositionAtoms))
231 gmx::ConstArrayRef<int> atoms = p.atomIndices();
232 poscompound.checkSequence(atoms.begin(), atoms.end(), "Atoms");
234 if (flags.test(efTestPositionCoordinates))
236 poscompound.checkVector(p.x(), "Coordinates");
238 if (flags.test(efTestPositionMapping))
240 poscompound.checkInteger(p.refId(), "RefId");
241 poscompound.checkInteger(p.mappedId(), "MappedId");
243 if (flags.test(efTestPositionMasses))
245 poscompound.checkReal(p.mass(), "Mass");
247 if (flags.test(efTestPositionCharges))
249 poscompound.checkReal(p.charge(), "Charge");
257 SelectionCollectionDataTest::runParser(
258 const gmx::ConstArrayRef<const char *> &selections)
260 using gmx::test::TestReferenceChecker;
262 TestReferenceChecker compound(checker_.checkCompound("ParsedSelections", "Parsed"));
265 for (size_t i = 0; i < selections.size(); ++i)
267 SCOPED_TRACE(std::string("Parsing selection \"")
268 + selections[i] + "\"");
269 gmx::SelectionList result;
270 ASSERT_NO_THROW_GMX(result = sc_.parseFromString(selections[i]));
271 sel_.insert(sel_.end(), result.begin(), result.end());
272 if (sel_.size() == count_)
274 std::string id = gmx::formatString("Variable%d", static_cast<int>(varcount + 1));
275 TestReferenceChecker varcompound(
276 compound.checkCompound("ParsedVariable", id.c_str()));
277 varcompound.checkString(selections[i], "Input");
282 std::string id = gmx::formatString("Selection%d", static_cast<int>(count_ + 1));
283 TestReferenceChecker selcompound(
284 compound.checkCompound("ParsedSelection", id.c_str()));
285 selcompound.checkString(selections[i], "Input");
286 if (flags_.test(efTestSelectionNames))
288 selcompound.checkString(sel_[count_].name(), "Name");
290 selcompound.checkString(sel_[count_].selectionText(), "Text");
291 selcompound.checkBoolean(sel_[count_].isDynamic(), "Dynamic");
299 SelectionCollectionDataTest::runCompiler()
301 ASSERT_NO_THROW_GMX(sc_.compile());
302 ASSERT_EQ(count_, sel_.size());
308 SelectionCollectionDataTest::checkCompiled()
310 using gmx::test::TestReferenceChecker;
311 const TestFlags mask = ~TestFlags(efTestPositionCoordinates);
313 TestReferenceChecker compound(checker_.checkCompound("CompiledSelections", "Compiled"));
314 for (size_t i = 0; i < count_; ++i)
316 SCOPED_TRACE(std::string("Checking selection \"") +
317 sel_[i].selectionText() + "\"");
318 std::string id = gmx::formatString("Selection%d", static_cast<int>(i + 1));
319 TestReferenceChecker selcompound(
320 compound.checkCompound("Selection", id.c_str()));
321 if (flags_.test(efTestSelectionNames))
323 selcompound.checkString(sel_[i].name(), "Name");
325 if (!flags_.test(efDontTestCompiledAtoms))
327 checkSelection(&selcompound, sel_[i], flags_ & mask);
334 SelectionCollectionDataTest::runEvaluate()
336 using gmx::test::TestReferenceChecker;
339 ASSERT_NO_THROW_GMX(sc_.evaluate(frame_, NULL));
340 std::string frame = gmx::formatString("Frame%d", framenr_);
341 TestReferenceChecker compound(
342 checker_.checkCompound("EvaluatedSelections", frame.c_str()));
343 for (size_t i = 0; i < count_; ++i)
345 SCOPED_TRACE(std::string("Checking selection \"") +
346 sel_[i].selectionText() + "\"");
347 std::string id = gmx::formatString("Selection%d", static_cast<int>(i + 1));
348 TestReferenceChecker selcompound(
349 compound.checkCompound("Selection", id.c_str()));
350 checkSelection(&selcompound, sel_[i], flags_);
356 SelectionCollectionDataTest::runEvaluateFinal()
358 ASSERT_NO_THROW_GMX(sc_.evaluateFinal(framenr_));
364 SelectionCollectionDataTest::runTest(
365 int natoms, const gmx::ConstArrayRef<const char *> &selections)
367 ASSERT_NO_FATAL_FAILURE(runParser(selections));
368 ASSERT_NO_FATAL_FAILURE(setAtomCount(natoms));
369 ASSERT_NO_FATAL_FAILURE(runCompiler());
374 SelectionCollectionDataTest::runTest(
375 const char *filename, const gmx::ConstArrayRef<const char *> &selections)
377 ASSERT_NO_FATAL_FAILURE(runParser(selections));
378 ASSERT_NO_FATAL_FAILURE(loadTopology(filename));
379 ASSERT_NO_FATAL_FAILURE(runCompiler());
380 if (flags_.test(efTestEvaluation))
382 ASSERT_NO_FATAL_FAILURE(runEvaluate());
383 ASSERT_NO_FATAL_FAILURE(runEvaluateFinal());
388 /********************************************************************
389 * Tests for SelectionCollection functionality without reference data
392 TEST_F(SelectionCollectionTest, HandlesNoSelections)
394 EXPECT_FALSE(sc_.requiresTopology());
395 EXPECT_NO_THROW_GMX(sc_.compile());
398 TEST_F(SelectionCollectionTest, HandlesVelocityAndForceRequests)
400 ASSERT_NO_THROW_GMX(sel_ = sc_.parseFromString("atomnr 1 to 10; none"));
401 ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
402 ASSERT_EQ(2U, sel_.size());
403 ASSERT_NO_THROW_GMX(sel_[0].setEvaluateVelocities(true));
404 ASSERT_NO_THROW_GMX(sel_[1].setEvaluateVelocities(true));
405 ASSERT_NO_THROW_GMX(sel_[0].setEvaluateForces(true));
406 ASSERT_NO_THROW_GMX(sel_[1].setEvaluateForces(true));
407 ASSERT_NO_THROW_GMX(sc_.compile());
408 EXPECT_TRUE(sel_[0].hasVelocities());
409 EXPECT_TRUE(sel_[1].hasVelocities());
410 EXPECT_TRUE(sel_[0].hasForces());
411 EXPECT_TRUE(sel_[1].hasForces());
414 TEST_F(SelectionCollectionTest, ParsesSelectionsFromFile)
416 ASSERT_NO_THROW_GMX(sel_ = sc_.parseFromFile(
417 gmx::test::TestFileManager::getInputFilePath("selfile.dat")));
418 // These should match the contents of selfile.dat
419 ASSERT_EQ(2U, sel_.size());
420 EXPECT_STREQ("resname RA RB", sel_[0].selectionText());
421 EXPECT_STREQ("resname RB RC", sel_[1].selectionText());
424 TEST_F(SelectionCollectionTest, HandlesAtypicalWhitespace)
426 ASSERT_NO_THROW_GMX(sel_ = sc_.parseFromString("atomnr\n1\r\nto\t10;\vatomnr 3\f to 14\r"));
427 ASSERT_EQ(2U, sel_.size());
428 EXPECT_STREQ("atomnr 1 to 10", sel_[0].selectionText());
429 // TODO: Get rid of the trailing whitespace.
430 EXPECT_STREQ("atomnr 3 to 14 ", sel_[1].selectionText());
433 TEST_F(SelectionCollectionTest, HandlesInvalidRegularExpressions)
435 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
437 sc_.parseFromString("resname ~ \"R[A\"");
439 }, gmx::InvalidInputError);
442 TEST_F(SelectionCollectionTest, HandlesUnsupportedRegularExpressions)
444 if (!gmx::Regex::isSupported())
446 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
448 sc_.parseFromString("resname \"R[AD]\"");
450 }, gmx::InvalidInputError);
454 TEST_F(SelectionCollectionTest, HandlesMissingMethodParamValue)
456 EXPECT_THROW_GMX(sc_.parseFromString("mindist from atomnr 1 cutoff"),
457 gmx::InvalidInputError);
460 TEST_F(SelectionCollectionTest, HandlesMissingMethodParamValue2)
462 EXPECT_THROW_GMX(sc_.parseFromString("within 1 of"),
463 gmx::InvalidInputError);
466 TEST_F(SelectionCollectionTest, HandlesMissingMethodParamValue3)
468 EXPECT_THROW_GMX(sc_.parseFromString("within of atomnr 1"),
469 gmx::InvalidInputError);
472 // TODO: Tests for more parser errors
474 TEST_F(SelectionCollectionTest, HandlesUnknownGroupReferenceParser1)
476 ASSERT_NO_THROW_GMX(sc_.setIndexGroups(NULL));
477 EXPECT_THROW_GMX(sc_.parseFromString("group \"foo\""), gmx::InconsistentInputError);
478 EXPECT_THROW_GMX(sc_.parseFromString("4"), gmx::InconsistentInputError);
481 TEST_F(SelectionCollectionTest, HandlesUnknownGroupReferenceParser2)
483 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
484 EXPECT_THROW_GMX(sc_.parseFromString("group \"foo\""), gmx::InconsistentInputError);
485 EXPECT_THROW_GMX(sc_.parseFromString("4"), gmx::InconsistentInputError);
488 TEST_F(SelectionCollectionTest, HandlesUnknownGroupReferenceDelayed1)
490 ASSERT_NO_THROW_GMX(sc_.parseFromString("group \"foo\""));
491 ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
492 EXPECT_THROW_GMX(sc_.setIndexGroups(NULL), gmx::InconsistentInputError);
493 EXPECT_THROW_GMX(sc_.compile(), gmx::APIError);
496 TEST_F(SelectionCollectionTest, HandlesUnknownGroupReferenceDelayed2)
498 ASSERT_NO_THROW_GMX(sc_.parseFromString("group 4; group \"foo\""));
499 ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
500 EXPECT_THROW_GMX(loadIndexGroups("simple.ndx"), gmx::InconsistentInputError);
501 EXPECT_THROW_GMX(sc_.compile(), gmx::APIError);
504 TEST_F(SelectionCollectionTest, HandlesUnsortedGroupReference)
506 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
507 EXPECT_THROW_GMX(sc_.parseFromString("atomnr 1 to 3 and group \"GrpUnsorted\""),
508 gmx::InconsistentInputError);
509 EXPECT_THROW_GMX(sc_.parseFromString("group 2 or atomnr 2 to 5"),
510 gmx::InconsistentInputError);
511 EXPECT_THROW_GMX(sc_.parseFromString("within 1 of group 2"),
512 gmx::InconsistentInputError);
515 TEST_F(SelectionCollectionTest, HandlesUnsortedGroupReferenceDelayed)
517 ASSERT_NO_THROW_GMX(sc_.parseFromString("atomnr 1 to 3 and group \"GrpUnsorted\""));
518 ASSERT_NO_THROW_GMX(sc_.parseFromString("atomnr 1 to 3 and group 2"));
519 EXPECT_THROW_GMX(loadIndexGroups("simple.ndx"), gmx::InconsistentInputError);
520 // TODO: Add a separate check in the selection compiler for a safer API
521 // (makes sense in the future if the compiler needs the information for
522 // other purposes as well).
523 // EXPECT_THROW_GMX(sc_.compile(), gmx::APIError);
526 TEST_F(SelectionCollectionTest, HandlesOutOfRangeAtomIndexInGroup)
528 ASSERT_NO_THROW_GMX(sc_.setTopology(NULL, 5));
529 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
530 EXPECT_THROW_GMX(sc_.parseFromString("group \"GrpB\""), gmx::InconsistentInputError);
533 TEST_F(SelectionCollectionTest, HandlesOutOfRangeAtomIndexInGroupDelayed)
535 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
536 ASSERT_NO_THROW_GMX(sc_.parseFromString("group \"GrpB\""));
537 EXPECT_THROW_GMX(sc_.setTopology(NULL, 5), gmx::InconsistentInputError);
540 TEST_F(SelectionCollectionTest, HandlesOutOfRangeAtomIndexInGroupDelayed2)
542 ASSERT_NO_THROW_GMX(sc_.setTopology(NULL, 5));
543 ASSERT_NO_THROW_GMX(sc_.parseFromString("group \"GrpB\""));
544 EXPECT_THROW_GMX(loadIndexGroups("simple.ndx"), gmx::InconsistentInputError);
547 TEST_F(SelectionCollectionTest, RecoversFromMissingMoleculeInfo)
549 ASSERT_NO_THROW_GMX(sc_.parseFromString("molindex 1 to 5"));
550 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
551 EXPECT_THROW_GMX(sc_.compile(), gmx::InconsistentInputError);
554 TEST_F(SelectionCollectionTest, RecoversFromMissingAtomTypes)
556 ASSERT_NO_THROW_GMX(sc_.parseFromString("type CA"));
557 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
558 EXPECT_THROW_GMX(sc_.compile(), gmx::InconsistentInputError);
561 TEST_F(SelectionCollectionTest, RecoversFromMissingPDBInfo)
563 ASSERT_NO_THROW_GMX(sc_.parseFromString("altloc A"));
564 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
565 EXPECT_THROW_GMX(sc_.compile(), gmx::InconsistentInputError);
568 TEST_F(SelectionCollectionTest, RecoversFromInvalidPermutation)
570 ASSERT_NO_THROW_GMX(sc_.parseFromString("all permute 1 1"));
571 ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
572 EXPECT_THROW_GMX(sc_.compile(), gmx::InvalidInputError);
575 TEST_F(SelectionCollectionTest, RecoversFromInvalidPermutation2)
577 ASSERT_NO_THROW_GMX(sc_.parseFromString("all permute 3 2 1"));
578 ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
579 EXPECT_THROW_GMX(sc_.compile(), gmx::InconsistentInputError);
582 TEST_F(SelectionCollectionTest, RecoversFromInvalidPermutation3)
584 ASSERT_NO_THROW_GMX(sc_.parseFromString("x < 1.5 permute 3 2 1"));
585 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
586 ASSERT_NO_THROW_GMX(sc_.compile());
587 EXPECT_THROW_GMX(sc_.evaluate(frame_, NULL), gmx::InconsistentInputError);
590 TEST_F(SelectionCollectionTest, HandlesFramesWithTooSmallAtomSubsets)
592 ASSERT_NO_THROW_GMX(sc_.parseFromString("atomnr 3 to 10"));
593 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
594 ASSERT_NO_THROW_GMX(sc_.compile());
596 EXPECT_THROW_GMX(sc_.evaluate(frame_, NULL), gmx::InconsistentInputError);
599 TEST_F(SelectionCollectionTest, HandlesFramesWithTooSmallAtomSubsets2)
601 // Evaluating the positions will require atoms 1-9.
602 ASSERT_NO_THROW_GMX(sc_.parseFromString("whole_res_com of atomnr 2 5 7"));
603 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
604 ASSERT_NO_THROW_GMX(sc_.compile());
606 EXPECT_THROW_GMX(sc_.evaluate(frame_, NULL), gmx::InconsistentInputError);
609 TEST_F(SelectionCollectionTest, HandlesFramesWithTooSmallAtomSubsets3)
611 ASSERT_NO_THROW_GMX(sc_.parseFromString("mindistance from atomnr 1 to 5 < 2"));
612 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
613 ASSERT_NO_THROW_GMX(sc_.compile());
615 EXPECT_THROW_GMX(sc_.evaluate(frame_, NULL), gmx::InconsistentInputError);
618 // TODO: Tests for more evaluation errors
621 /********************************************************************
622 * Tests for selection keywords
625 TEST_F(SelectionCollectionDataTest, HandlesAllNone)
627 static const char * const selections[] = {
631 runTest(10, selections);
634 TEST_F(SelectionCollectionDataTest, HandlesAtomnr)
636 static const char * const selections[] = {
637 "atomnr 1 to 3 6 to 8",
641 runTest(10, selections);
644 TEST_F(SelectionCollectionDataTest, HandlesResnr)
646 static const char * const selections[] = {
650 runTest("simple.gro", selections);
653 TEST_F(SelectionCollectionDataTest, HandlesResIndex)
655 static const char * const selections[] = {
659 runTest("simple.pdb", selections);
662 TEST_F(SelectionCollectionDataTest, HandlesMolIndex)
664 static const char * const selections[] = {
668 ASSERT_NO_FATAL_FAILURE(runParser(selections));
669 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
670 topManager_.initUniformMolecules(3);
671 ASSERT_NO_FATAL_FAILURE(runCompiler());
674 TEST_F(SelectionCollectionDataTest, HandlesAtomname)
676 static const char * const selections[] = {
680 runTest("simple.gro", selections);
683 TEST_F(SelectionCollectionDataTest, HandlesPdbAtomname)
685 static const char * const selections[] = {
691 runTest("simple.pdb", selections);
695 TEST_F(SelectionCollectionDataTest, HandlesAtomtype)
697 static const char * const selections[] = {
700 ASSERT_NO_FATAL_FAILURE(runParser(selections));
701 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
702 const char *const types[] = { "CA", "SA", "SB" };
703 topManager_.initAtomTypes(types);
704 ASSERT_NO_FATAL_FAILURE(runCompiler());
707 TEST_F(SelectionCollectionDataTest, HandlesChain)
709 static const char * const selections[] = {
713 runTest("simple.pdb", selections);
716 TEST_F(SelectionCollectionDataTest, HandlesMass)
718 static const char * const selections[] = {
721 ASSERT_NO_FATAL_FAILURE(runParser(selections));
722 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
723 for (int i = 0; i < top_->atoms.nr; ++i)
725 top_->atoms.atom[i].m = 1.0 + i;
727 ASSERT_NO_FATAL_FAILURE(runCompiler());
730 TEST_F(SelectionCollectionDataTest, HandlesCharge)
732 static const char * const selections[] = {
735 ASSERT_NO_FATAL_FAILURE(runParser(selections));
736 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
737 for (int i = 0; i < top_->atoms.nr; ++i)
739 top_->atoms.atom[i].q = i / 10.0;
741 ASSERT_NO_FATAL_FAILURE(runCompiler());
744 TEST_F(SelectionCollectionDataTest, HandlesAltLoc)
746 static const char * const selections[] = {
750 runTest("simple.pdb", selections);
753 TEST_F(SelectionCollectionDataTest, HandlesInsertCode)
755 static const char * const selections[] = {
759 runTest("simple.pdb", selections);
762 TEST_F(SelectionCollectionDataTest, HandlesOccupancy)
764 static const char * const selections[] = {
768 runTest("simple.pdb", selections);
771 TEST_F(SelectionCollectionDataTest, HandlesBeta)
773 static const char * const selections[] = {
777 runTest("simple.pdb", selections);
780 TEST_F(SelectionCollectionDataTest, HandlesResname)
782 static const char * const selections[] = {
786 runTest("simple.gro", selections);
789 TEST_F(SelectionCollectionDataTest, HandlesCoordinateKeywords)
791 static const char * const selections[] = {
796 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
797 runTest("simple.gro", selections);
801 TEST_F(SelectionCollectionDataTest, HandlesSameResidue)
803 static const char * const selections[] = {
804 "same residue as atomnr 1 4 12"
806 runTest("simple.gro", selections);
810 TEST_F(SelectionCollectionDataTest, HandlesSameResidueName)
812 static const char * const selections[] = {
813 "same resname as atomnr 1 14"
815 runTest("simple.gro", selections);
819 TEST_F(SelectionCollectionDataTest, HandlesPositionKeywords)
821 static const char * const selections[] = {
823 "res_cog of name CB and resnr 1 3",
824 "whole_res_cog of name CB and resnr 1 3",
825 "part_res_cog of x < 3",
826 "dyn_res_cog of x < 3"
828 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates
829 | efTestPositionAtoms);
830 runTest("simple.gro", selections);
834 TEST_F(SelectionCollectionDataTest, HandlesDistanceKeyword)
836 static const char * const selections[] = {
837 "distance from cog of resnr 1 < 2"
839 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
840 runTest("simple.gro", selections);
844 TEST_F(SelectionCollectionDataTest, HandlesMinDistanceKeyword)
846 static const char * const selections[] = {
847 "mindistance from resnr 1 < 2"
849 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
850 runTest("simple.gro", selections);
854 TEST_F(SelectionCollectionDataTest, HandlesWithinKeyword)
856 static const char * const selections[] = {
857 "within 1 of resnr 2"
859 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
860 runTest("simple.gro", selections);
864 TEST_F(SelectionCollectionDataTest, HandlesInSolidAngleKeyword)
866 // Both of these should evaluate to empty on a correct implementation.
867 static const char * const selections[] = {
868 "resname TP and not insolidangle center cog of resname C span resname R cutoff 20",
869 "resname TN and insolidangle center cog of resname C span resname R cutoff 20"
871 setFlags(TestFlags() | efDontTestCompiledAtoms | efTestEvaluation);
872 runTest("sphere.gro", selections);
876 TEST_F(SelectionCollectionDataTest, HandlesPermuteModifier)
878 static const char * const selections[] = {
880 "res_cog of resnr 1 to 4 permute 2 1",
881 "name CB S1 and res_cog x < 3 permute 2 1"
883 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates
884 | efTestPositionAtoms | efTestPositionMapping);
885 runTest("simple.gro", selections);
889 TEST_F(SelectionCollectionDataTest, HandlesPlusModifier)
891 static const char * const selections[] = {
892 "name S2 plus name S1",
893 "res_cog of resnr 2 plus res_cog of resnr 1 plus res_cog of resnr 3",
894 "name S1 and y < 3 plus res_cog of x < 2.5"
896 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates
897 | efTestPositionAtoms | efTestPositionMapping);
898 runTest("simple.gro", selections);
902 TEST_F(SelectionCollectionDataTest, HandlesMergeModifier)
904 static const char * const selections[] = {
905 "name S2 merge name S1",
906 "resnr 1 2 and name S2 merge resnr 1 2 and name S1 merge res_cog of resnr 1 2",
907 "name S1 and x < 2.5 merge res_cog of x < 2.5"
909 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates
910 | efTestPositionAtoms | efTestPositionMapping);
911 runTest("simple.gro", selections);
915 /********************************************************************
916 * Tests for generic selection evaluation
919 TEST_F(SelectionCollectionDataTest, ComputesMassesAndCharges)
921 static const char * const selections[] = {
926 setFlags(TestFlags() | efTestEvaluation | efTestPositionAtoms
927 | efTestPositionMasses | efTestPositionCharges);
928 ASSERT_NO_FATAL_FAILURE(runParser(selections));
929 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
930 for (int i = 0; i < top_->atoms.nr; ++i)
932 top_->atoms.atom[i].m = 1.0 + i / 100.0;
933 top_->atoms.atom[i].q = -(1.0 + i / 100.0);
935 ASSERT_NO_FATAL_FAILURE(runCompiler());
936 ASSERT_NO_FATAL_FAILURE(runEvaluate());
937 ASSERT_NO_FATAL_FAILURE(runEvaluateFinal());
940 TEST_F(SelectionCollectionDataTest, ComputesMassesAndChargesWithoutTopology)
942 static const char * const selections[] = {
943 "atomnr 1 to 3 8 to 9",
947 setFlags(TestFlags() | efTestPositionAtoms
948 | efTestPositionMasses | efTestPositionCharges);
949 runTest(10, selections);
953 /********************************************************************
954 * Tests for selection syntactic constructs
957 TEST_F(SelectionCollectionDataTest, HandlesSelectionNames)
959 static const char * const selections[] = {
960 "\"GroupSelection\" group \"GrpA\"",
961 "\"DynamicSelection\" x < 5",
964 setFlags(TestFlags() | efTestSelectionNames);
965 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
966 runTest(10, selections);
969 TEST_F(SelectionCollectionDataTest, HandlesIndexGroupsInSelections)
971 static const char * const selections[] = {
975 "group \"GrpB\" and resname RB"
977 setFlags(TestFlags() | efTestSelectionNames);
978 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
979 runTest("simple.gro", selections);
982 TEST_F(SelectionCollectionDataTest, HandlesIndexGroupsInSelectionsDelayed)
984 static const char * const selections[] = {
988 "group \"GrpB\" and resname RB"
990 setFlags(TestFlags() | efTestSelectionNames);
991 ASSERT_NO_FATAL_FAILURE(runParser(selections));
992 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
993 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
994 ASSERT_NO_FATAL_FAILURE(runCompiler());
997 TEST_F(SelectionCollectionDataTest, HandlesUnsortedIndexGroupsInSelections)
999 static const char * const selections[] = {
1000 "foo = group \"GrpUnsorted\"",
1001 "group \"GrpUnsorted\"",
1004 "res_cog of group \"GrpUnsorted\"",
1005 "group \"GrpUnsorted\" permute 2 1",
1008 setFlags(TestFlags() | efTestPositionAtoms | efTestPositionMapping
1009 | efTestSelectionNames);
1010 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
1011 runTest("simple.gro", selections);
1014 TEST_F(SelectionCollectionDataTest, HandlesUnsortedIndexGroupsInSelectionsDelayed)
1016 static const char * const selections[] = {
1017 "foo = group \"GrpUnsorted\"",
1018 "group \"GrpUnsorted\"",
1021 "res_cog of group \"GrpUnsorted\"",
1022 "group \"GrpUnsorted\" permute 2 1",
1025 ASSERT_NO_FATAL_FAILURE(runParser(selections));
1026 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
1027 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
1028 ASSERT_NO_FATAL_FAILURE(runCompiler());
1031 TEST_F(SelectionCollectionDataTest, HandlesConstantPositions)
1033 static const char * const selections[] = {
1036 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1037 runTest("simple.gro", selections);
1041 TEST_F(SelectionCollectionDataTest, HandlesWithinConstantPositions)
1043 static const char * const selections[] = {
1044 "within 1 of [2, 1, 0]"
1046 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1047 runTest("simple.gro", selections);
1051 TEST_F(SelectionCollectionDataTest, HandlesForcedStringMatchingMode)
1053 static const char * const selections[] = {
1057 runTest("simple.gro", selections);
1061 TEST_F(SelectionCollectionDataTest, HandlesWildcardMatching)
1063 static const char * const selections[] = {
1067 runTest("simple.gro", selections);
1071 TEST_F(SelectionCollectionDataTest, HandlesRegexMatching)
1073 static const char * const selections[] = {
1074 "resname \"R[BD]\"",
1075 "resname ~ \"R[BD]\""
1077 if (gmx::Regex::isSupported())
1079 runTest("simple.gro", selections);
1084 TEST_F(SelectionCollectionDataTest, HandlesBasicBoolean)
1086 static const char * const selections[] = {
1087 "atomnr 1 to 5 and atomnr 2 to 7",
1088 "atomnr 1 to 5 or not atomnr 3 to 8",
1089 "not not atomnr 1 to 5 and atomnr 2 to 6 and not not atomnr 3 to 7",
1090 "atomnr 1 to 5 and (atomnr 2 to 7 and atomnr 3 to 6)",
1091 "x < 5 and atomnr 1 to 5 and y < 3 and atomnr 2 to 4"
1093 runTest(10, selections);
1097 TEST_F(SelectionCollectionDataTest, HandlesDynamicAtomValuedParameters)
1099 static const char * const selections[] = {
1100 "same residue as (atomnr 3 5 13 or y > 5)",
1101 "(resnr 1 3 5 or x > 10) and same residue as (atomnr 3 5 13 or z > 5)"
1103 setFlags(TestFlags() | efTestEvaluation);
1104 runTest("simple.gro", selections);
1108 TEST_F(SelectionCollectionDataTest, HandlesEmptySelectionWithUnevaluatedExpressions)
1110 static const char * const selections[] = {
1112 "none and same resname as resnr 2"
1114 runTest("simple.gro", selections);
1118 TEST_F(SelectionCollectionDataTest, HandlesNumericComparisons)
1120 static const char * const selections[] = {
1127 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1128 runTest("simple.gro", selections);
1132 TEST_F(SelectionCollectionDataTest, HandlesArithmeticExpressions)
1134 static const char * const selections[] = {
1140 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1141 runTest("simple.gro", selections);
1145 TEST_F(SelectionCollectionDataTest, HandlesNumericVariables)
1147 static const char * const selections[] = {
1153 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1154 runTest("simple.gro", selections);
1158 TEST_F(SelectionCollectionDataTest, HandlesComplexNumericVariables)
1160 static const char * const selections[] = {
1162 "resname RA and value <= 4",
1163 "resname RA RB and x < 3 and value <= 4",
1165 "resname RA and index < 3",
1166 "resname RB and y < 3 and index < 6"
1168 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1169 runTest("simple.gro", selections);
1173 TEST_F(SelectionCollectionDataTest, HandlesPositionVariables)
1175 static const char * const selections[] = {
1176 "foo = res_cog of resname RA",
1179 "bar = cog of resname RA",
1183 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1184 runTest("simple.gro", selections);
1188 TEST_F(SelectionCollectionDataTest, HandlesConstantPositionInVariable)
1190 static const char * const selections[] = {
1191 "constpos = [1.0, 2.5, 0.5]",
1193 "within 2 of constpos"
1195 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates
1196 | efTestPositionAtoms);
1197 runTest("simple.gro", selections);
1201 TEST_F(SelectionCollectionDataTest, HandlesNumericConstantsInVariables)
1203 static const char * const selections[] = {
1208 "x + constreal1 < constreal2"
1210 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1211 runTest("simple.gro", selections);
1215 /********************************************************************
1216 * Tests for complex boolean syntax
1219 TEST_F(SelectionCollectionDataTest, HandlesBooleanStaticAnalysis)
1221 static const char * const selections[] = {
1222 "atomnr 1 to 5 and atomnr 2 to 7 and x < 2",
1223 "atomnr 1 to 5 and (atomnr 4 to 7 or x < 2)",
1224 "atomnr 1 to 5 and y < 3 and (atomnr 4 to 7 or x < 2)",
1225 "atomnr 1 to 5 and not (atomnr 4 to 7 or x < 2)",
1226 "atomnr 1 to 5 or (atomnr 4 to 6 and (atomnr 5 to 7 or x < 2))"
1228 runTest(10, selections);
1232 TEST_F(SelectionCollectionDataTest, HandlesBooleanStaticAnalysisWithVariables)
1234 static const char * const selections[] = {
1235 "foo = atomnr 4 to 7 or x < 2",
1236 "atomnr 1 to 4 and foo",
1237 "atomnr 2 to 6 and y < 3 and foo",
1238 "atomnr 6 to 10 and not foo"
1240 runTest(10, selections);
1244 TEST_F(SelectionCollectionDataTest, HandlesBooleanStaticAnalysisWithMoreVariables)
1246 static const char * const selections[] = {
1247 "foo = atomnr 4 to 7",
1248 "bar = foo and x < 2",
1249 "bar2 = foo and y < 2",
1250 "atomnr 1 to 4 and bar",
1251 "atomnr 2 to 6 and y < 3 and bar2",
1252 "atomnr 6 to 10 and not foo"
1254 runTest(10, selections);
1258 /********************************************************************
1259 * Tests for complex subexpression cases
1261 * These tests use some knowledge of the implementation to trigger different
1262 * paths in the code.
1265 TEST_F(SelectionCollectionDataTest, HandlesUnusedVariables)
1267 static const char * const selections[] = {
1268 "unused1 = atomnr 1 to 3",
1269 "foo = atomnr 4 to 7",
1270 "atomnr 1 to 6 and foo",
1271 "unused2 = atomnr 3 to 5"
1273 runTest(10, selections);
1277 TEST_F(SelectionCollectionDataTest, HandlesVariablesWithStaticEvaluationGroups)
1279 static const char * const selections[] = {
1280 "foo = atomnr 4 to 7 and x < 2",
1281 "atomnr 1 to 5 and foo",
1282 "atomnr 3 to 7 and foo"
1284 runTest(10, selections);
1288 TEST_F(SelectionCollectionDataTest, HandlesVariablesWithMixedEvaluationGroups)
1290 static const char * const selections[] = {
1291 "foo = atomnr 4 to 7 and x < 2",
1292 "atomnr 1 to 6 and foo",
1296 runTest(10, selections);
1300 TEST_F(SelectionCollectionDataTest, HandlesVariablesWithMixedEvaluationGroups2)
1302 static const char * const selections[] = {
1303 "foo = atomnr 1 to 8 and x < 10",
1304 "atomnr 1 to 5 and y < 10 and foo",
1307 setFlags(TestFlags() | efTestEvaluation);
1308 runTest("simple.gro", selections);