2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2010,2011,2012,2013,2014, by the GROMACS development team, led by
5 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6 * and including many others, as listed in the AUTHORS file in the
7 * top-level source directory and at http://www.gromacs.org.
9 * GROMACS is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1
12 * of the License, or (at your option) any later version.
14 * GROMACS is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with GROMACS; if not, see
21 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 * If you want to redistribute modifications to GROMACS, please
25 * consider that scientific software is very special. Version
26 * control is crucial - bugs must be traceable. We will be happy to
27 * consider code for inclusion in the official distribution, but
28 * derived work must not be called official GROMACS. Details are found
29 * in the README & COPYING files - if they are missing, get the
30 * official version at http://www.gromacs.org.
32 * To help us fund GROMACS development, we humbly ask that you cite
33 * the research papers on the package. Check out http://www.gromacs.org.
37 * Tests selection parsing and compilation.
39 * \author Teemu Murtola <teemu.murtola@gmail.com>
40 * \ingroup module_selection
42 #include <gtest/gtest.h>
44 #include "gromacs/options/basicoptions.h"
45 #include "gromacs/options/options.h"
46 #include "gromacs/selection/indexutil.h"
47 #include "gromacs/selection/selectioncollection.h"
48 #include "gromacs/selection/selection.h"
49 #include "gromacs/utility/arrayref.h"
50 #include "gromacs/utility/exceptions.h"
51 #include "gromacs/utility/flags.h"
52 #include "gromacs/utility/gmxregex.h"
53 #include "gromacs/utility/stringutil.h"
55 #include "testutils/refdata.h"
56 #include "testutils/testasserts.h"
57 #include "testutils/testfilemanager.h"
58 #include "testutils/testoptions.h"
65 /********************************************************************
66 * Test fixture for selection testing
69 class SelectionCollectionTest : public ::testing::Test
72 static int s_debugLevel;
74 SelectionCollectionTest();
75 ~SelectionCollectionTest();
77 void setAtomCount(int natoms)
79 ASSERT_NO_THROW_GMX(sc_.setTopology(NULL, natoms));
81 void loadTopology(const char *filename);
83 void loadIndexGroups(const char *filename);
85 gmx::test::TopologyManager topManager_;
86 gmx::SelectionCollection sc_;
87 gmx::SelectionList sel_;
90 gmx_ana_indexgrps_t *grps_;
93 int SelectionCollectionTest::s_debugLevel = 0;
95 // \cond/\endcond do not seem to work here with Doxygen 1.8.5 parser.
97 GMX_TEST_OPTIONS(SelectionCollectionTestOptions, options)
99 options->addOption(gmx::IntegerOption("seldebug")
100 .store(&SelectionCollectionTest::s_debugLevel)
101 .description("Set selection debug level"));
105 SelectionCollectionTest::SelectionCollectionTest()
106 : top_(NULL), frame_(NULL), grps_(NULL)
108 topManager_.requestFrame();
109 sc_.setDebugLevel(s_debugLevel);
110 sc_.setReferencePosType("atom");
111 sc_.setOutputPosType("atom");
114 SelectionCollectionTest::~SelectionCollectionTest()
118 gmx_ana_indexgrps_free(grps_);
123 SelectionCollectionTest::loadTopology(const char *filename)
125 topManager_.loadTopology(filename);
130 SelectionCollectionTest::setTopology()
132 top_ = topManager_.topology();
133 frame_ = topManager_.frame();
135 ASSERT_NO_THROW_GMX(sc_.setTopology(top_, -1));
139 SelectionCollectionTest::loadIndexGroups(const char *filename)
141 GMX_RELEASE_ASSERT(grps_ == NULL,
142 "External groups can only be loaded once");
143 std::string fullpath =
144 gmx::test::TestFileManager::getInputFilePath(filename);
145 gmx_ana_indexgrps_init(&grps_, NULL, fullpath.c_str());
146 sc_.setIndexGroups(grps_);
150 /********************************************************************
151 * Test fixture for selection testing with reference data
154 class SelectionCollectionDataTest : public SelectionCollectionTest
159 efTestEvaluation = 1<<0,
160 efTestPositionAtoms = 1<<1,
161 efTestPositionCoordinates = 1<<2,
162 efTestPositionMapping = 1<<3,
163 efTestPositionMasses = 1<<4,
164 efTestPositionCharges = 1<<5,
165 efTestSelectionNames = 1<<6,
166 efDontTestCompiledAtoms = 1<<8
168 typedef gmx::FlagsTemplate<TestFlag> TestFlags;
170 SelectionCollectionDataTest()
171 : checker_(data_.rootChecker()), count_(0), framenr_(0)
175 void setFlags(TestFlags flags) { flags_ = flags; }
177 void runParser(const gmx::ConstArrayRef<const char *> &selections);
180 void runEvaluateFinal();
182 void runTest(int natoms,
183 const gmx::ConstArrayRef<const char *> &selections);
184 void runTest(const char *filename,
185 const gmx::ConstArrayRef<const char *> &selections);
188 static void checkSelection(gmx::test::TestReferenceChecker *checker,
189 const gmx::Selection &sel, TestFlags flags);
191 void checkCompiled();
193 gmx::test::TestReferenceData data_;
194 gmx::test::TestReferenceChecker checker_;
202 SelectionCollectionDataTest::checkSelection(
203 gmx::test::TestReferenceChecker *checker,
204 const gmx::Selection &sel, TestFlags flags)
206 using gmx::test::TestReferenceChecker;
209 gmx::ConstArrayRef<int> atoms = sel.atomIndices();
210 checker->checkSequence(atoms.begin(), atoms.end(), "Atoms");
212 if (flags.test(efTestPositionAtoms)
213 || flags.test(efTestPositionCoordinates)
214 || flags.test(efTestPositionMapping)
215 || flags.test(efTestPositionMasses)
216 || flags.test(efTestPositionCharges))
218 TestReferenceChecker compound(
219 checker->checkSequenceCompound("Positions", sel.posCount()));
220 for (int i = 0; i < sel.posCount(); ++i)
222 TestReferenceChecker poscompound(compound.checkCompound("Position", NULL));
223 const gmx::SelectionPosition &p = sel.position(i);
224 if (flags.test(efTestPositionAtoms))
226 gmx::ConstArrayRef<int> atoms = p.atomIndices();
227 poscompound.checkSequence(atoms.begin(), atoms.end(), "Atoms");
229 if (flags.test(efTestPositionCoordinates))
231 poscompound.checkVector(p.x(), "Coordinates");
233 if (flags.test(efTestPositionMapping))
235 poscompound.checkInteger(p.refId(), "RefId");
236 poscompound.checkInteger(p.mappedId(), "MappedId");
238 if (flags.test(efTestPositionMasses))
240 poscompound.checkReal(p.mass(), "Mass");
242 if (flags.test(efTestPositionCharges))
244 poscompound.checkReal(p.charge(), "Charge");
252 SelectionCollectionDataTest::runParser(
253 const gmx::ConstArrayRef<const char *> &selections)
255 using gmx::test::TestReferenceChecker;
257 TestReferenceChecker compound(checker_.checkCompound("ParsedSelections", "Parsed"));
260 for (size_t i = 0; i < selections.size(); ++i)
262 SCOPED_TRACE(std::string("Parsing selection \"")
263 + selections[i] + "\"");
264 gmx::SelectionList result;
265 ASSERT_NO_THROW_GMX(result = sc_.parseFromString(selections[i]));
266 sel_.insert(sel_.end(), result.begin(), result.end());
267 if (sel_.size() == count_)
269 std::string id = gmx::formatString("Variable%d", static_cast<int>(varcount + 1));
270 TestReferenceChecker varcompound(
271 compound.checkCompound("ParsedVariable", id.c_str()));
272 varcompound.checkString(selections[i], "Input");
277 std::string id = gmx::formatString("Selection%d", static_cast<int>(count_ + 1));
278 TestReferenceChecker selcompound(
279 compound.checkCompound("ParsedSelection", id.c_str()));
280 selcompound.checkString(selections[i], "Input");
281 if (flags_.test(efTestSelectionNames))
283 selcompound.checkString(sel_[count_].name(), "Name");
285 selcompound.checkString(sel_[count_].selectionText(), "Text");
286 selcompound.checkBoolean(sel_[count_].isDynamic(), "Dynamic");
294 SelectionCollectionDataTest::runCompiler()
296 ASSERT_NO_THROW_GMX(sc_.compile());
297 ASSERT_EQ(count_, sel_.size());
303 SelectionCollectionDataTest::checkCompiled()
305 using gmx::test::TestReferenceChecker;
306 const TestFlags mask = ~TestFlags(efTestPositionCoordinates);
308 TestReferenceChecker compound(checker_.checkCompound("CompiledSelections", "Compiled"));
309 for (size_t i = 0; i < count_; ++i)
311 SCOPED_TRACE(std::string("Checking selection \"") +
312 sel_[i].selectionText() + "\"");
313 std::string id = gmx::formatString("Selection%d", static_cast<int>(i + 1));
314 TestReferenceChecker selcompound(
315 compound.checkCompound("Selection", id.c_str()));
316 if (flags_.test(efTestSelectionNames))
318 selcompound.checkString(sel_[i].name(), "Name");
320 if (!flags_.test(efDontTestCompiledAtoms))
322 checkSelection(&selcompound, sel_[i], flags_ & mask);
329 SelectionCollectionDataTest::runEvaluate()
331 using gmx::test::TestReferenceChecker;
334 ASSERT_NO_THROW_GMX(sc_.evaluate(frame_, NULL));
335 std::string frame = gmx::formatString("Frame%d", framenr_);
336 TestReferenceChecker compound(
337 checker_.checkCompound("EvaluatedSelections", frame.c_str()));
338 for (size_t i = 0; i < count_; ++i)
340 SCOPED_TRACE(std::string("Checking selection \"") +
341 sel_[i].selectionText() + "\"");
342 std::string id = gmx::formatString("Selection%d", static_cast<int>(i + 1));
343 TestReferenceChecker selcompound(
344 compound.checkCompound("Selection", id.c_str()));
345 checkSelection(&selcompound, sel_[i], flags_);
351 SelectionCollectionDataTest::runEvaluateFinal()
353 ASSERT_NO_THROW_GMX(sc_.evaluateFinal(framenr_));
359 SelectionCollectionDataTest::runTest(
360 int natoms, const gmx::ConstArrayRef<const char *> &selections)
362 ASSERT_NO_FATAL_FAILURE(runParser(selections));
363 ASSERT_NO_FATAL_FAILURE(setAtomCount(natoms));
364 ASSERT_NO_FATAL_FAILURE(runCompiler());
369 SelectionCollectionDataTest::runTest(
370 const char *filename, const gmx::ConstArrayRef<const char *> &selections)
372 ASSERT_NO_FATAL_FAILURE(runParser(selections));
373 ASSERT_NO_FATAL_FAILURE(loadTopology(filename));
374 ASSERT_NO_FATAL_FAILURE(runCompiler());
375 if (flags_.test(efTestEvaluation))
377 ASSERT_NO_FATAL_FAILURE(runEvaluate());
378 ASSERT_NO_FATAL_FAILURE(runEvaluateFinal());
383 /********************************************************************
384 * Tests for SelectionCollection functionality without reference data
387 TEST_F(SelectionCollectionTest, HandlesNoSelections)
389 EXPECT_FALSE(sc_.requiresTopology());
390 EXPECT_NO_THROW_GMX(sc_.compile());
393 TEST_F(SelectionCollectionTest, HandlesVelocityAndForceRequests)
395 ASSERT_NO_THROW_GMX(sel_ = sc_.parseFromString("atomnr 1 to 10; none"));
396 ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
397 ASSERT_EQ(2U, sel_.size());
398 ASSERT_NO_THROW_GMX(sel_[0].setEvaluateVelocities(true));
399 ASSERT_NO_THROW_GMX(sel_[1].setEvaluateVelocities(true));
400 ASSERT_NO_THROW_GMX(sel_[0].setEvaluateForces(true));
401 ASSERT_NO_THROW_GMX(sel_[1].setEvaluateForces(true));
402 ASSERT_NO_THROW_GMX(sc_.compile());
403 EXPECT_TRUE(sel_[0].hasVelocities());
404 EXPECT_TRUE(sel_[1].hasVelocities());
405 EXPECT_TRUE(sel_[0].hasForces());
406 EXPECT_TRUE(sel_[1].hasForces());
409 TEST_F(SelectionCollectionTest, ParsesSelectionsFromFile)
411 ASSERT_NO_THROW_GMX(sel_ = sc_.parseFromFile(
412 gmx::test::TestFileManager::getInputFilePath("selfile.dat")));
413 // These should match the contents of selfile.dat
414 ASSERT_EQ(2U, sel_.size());
415 EXPECT_STREQ("resname RA RB", sel_[0].selectionText());
416 EXPECT_STREQ("resname RB RC", sel_[1].selectionText());
419 TEST_F(SelectionCollectionTest, HandlesInvalidRegularExpressions)
421 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
423 sc_.parseFromString("resname ~ \"R[A\"");
425 }, gmx::InvalidInputError);
428 TEST_F(SelectionCollectionTest, HandlesUnsupportedRegularExpressions)
430 if (!gmx::Regex::isSupported())
432 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
434 sc_.parseFromString("resname \"R[AD]\"");
436 }, gmx::InvalidInputError);
440 TEST_F(SelectionCollectionTest, HandlesMissingMethodParamValue)
442 EXPECT_THROW_GMX(sc_.parseFromString("mindist from atomnr 1 cutoff"),
443 gmx::InvalidInputError);
446 TEST_F(SelectionCollectionTest, HandlesMissingMethodParamValue2)
448 EXPECT_THROW_GMX(sc_.parseFromString("within 1 of"),
449 gmx::InvalidInputError);
452 TEST_F(SelectionCollectionTest, HandlesMissingMethodParamValue3)
454 EXPECT_THROW_GMX(sc_.parseFromString("within of atomnr 1"),
455 gmx::InvalidInputError);
458 // TODO: Tests for more parser errors
460 TEST_F(SelectionCollectionTest, HandlesUnknownGroupReferenceParser1)
462 ASSERT_NO_THROW_GMX(sc_.setIndexGroups(NULL));
463 EXPECT_THROW_GMX(sc_.parseFromString("group \"foo\""), gmx::InconsistentInputError);
464 EXPECT_THROW_GMX(sc_.parseFromString("4"), gmx::InconsistentInputError);
467 TEST_F(SelectionCollectionTest, HandlesUnknownGroupReferenceParser2)
469 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
470 EXPECT_THROW_GMX(sc_.parseFromString("group \"foo\""), gmx::InconsistentInputError);
471 EXPECT_THROW_GMX(sc_.parseFromString("4"), gmx::InconsistentInputError);
474 TEST_F(SelectionCollectionTest, HandlesUnknownGroupReferenceDelayed1)
476 ASSERT_NO_THROW_GMX(sc_.parseFromString("group \"foo\""));
477 ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
478 EXPECT_THROW_GMX(sc_.setIndexGroups(NULL), gmx::InconsistentInputError);
479 EXPECT_THROW_GMX(sc_.compile(), gmx::APIError);
482 TEST_F(SelectionCollectionTest, HandlesUnknownGroupReferenceDelayed2)
484 ASSERT_NO_THROW_GMX(sc_.parseFromString("group 4; group \"foo\""));
485 ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
486 EXPECT_THROW_GMX(loadIndexGroups("simple.ndx"), gmx::InconsistentInputError);
487 EXPECT_THROW_GMX(sc_.compile(), gmx::APIError);
490 TEST_F(SelectionCollectionTest, HandlesUnsortedGroupReference)
492 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
493 EXPECT_THROW_GMX(sc_.parseFromString("atomnr 1 to 3 and group \"GrpUnsorted\""),
494 gmx::InconsistentInputError);
495 EXPECT_THROW_GMX(sc_.parseFromString("group 2 or atomnr 2 to 5"),
496 gmx::InconsistentInputError);
497 EXPECT_THROW_GMX(sc_.parseFromString("within 1 of group 2"),
498 gmx::InconsistentInputError);
501 TEST_F(SelectionCollectionTest, HandlesUnsortedGroupReferenceDelayed)
503 ASSERT_NO_THROW_GMX(sc_.parseFromString("atomnr 1 to 3 and group \"GrpUnsorted\""));
504 ASSERT_NO_THROW_GMX(sc_.parseFromString("atomnr 1 to 3 and group 2"));
505 EXPECT_THROW_GMX(loadIndexGroups("simple.ndx"), gmx::InconsistentInputError);
506 // TODO: Add a separate check in the selection compiler for a safer API
507 // (makes sense in the future if the compiler needs the information for
508 // other purposes as well).
509 // EXPECT_THROW_GMX(sc_.compile(), gmx::APIError);
512 TEST_F(SelectionCollectionTest, RecoversFromMissingMoleculeInfo)
514 ASSERT_NO_THROW_GMX(sc_.parseFromString("molindex 1 to 5"));
515 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
516 EXPECT_THROW_GMX(sc_.compile(), gmx::InconsistentInputError);
519 TEST_F(SelectionCollectionTest, RecoversFromMissingAtomTypes)
521 ASSERT_NO_THROW_GMX(sc_.parseFromString("type CA"));
522 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
523 EXPECT_THROW_GMX(sc_.compile(), gmx::InconsistentInputError);
526 TEST_F(SelectionCollectionTest, RecoversFromMissingPDBInfo)
528 ASSERT_NO_THROW_GMX(sc_.parseFromString("altloc A"));
529 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
530 EXPECT_THROW_GMX(sc_.compile(), gmx::InconsistentInputError);
533 TEST_F(SelectionCollectionTest, RecoversFromInvalidPermutation)
535 ASSERT_NO_THROW_GMX(sc_.parseFromString("all permute 1 1"));
536 ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
537 EXPECT_THROW_GMX(sc_.compile(), gmx::InvalidInputError);
540 TEST_F(SelectionCollectionTest, RecoversFromInvalidPermutation2)
542 ASSERT_NO_THROW_GMX(sc_.parseFromString("all permute 3 2 1"));
543 ASSERT_NO_FATAL_FAILURE(setAtomCount(10));
544 EXPECT_THROW_GMX(sc_.compile(), gmx::InconsistentInputError);
547 TEST_F(SelectionCollectionTest, RecoversFromInvalidPermutation3)
549 ASSERT_NO_THROW_GMX(sc_.parseFromString("x < 1.5 permute 3 2 1"));
550 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
551 ASSERT_NO_THROW_GMX(sc_.compile());
552 EXPECT_THROW_GMX(sc_.evaluate(frame_, NULL), gmx::InconsistentInputError);
555 // TODO: Tests for evaluation errors
558 /********************************************************************
559 * Tests for selection keywords
562 TEST_F(SelectionCollectionDataTest, HandlesAllNone)
564 static const char * const selections[] = {
568 runTest(10, selections);
571 TEST_F(SelectionCollectionDataTest, HandlesAtomnr)
573 static const char * const selections[] = {
574 "atomnr 1 to 3 6 to 8",
578 runTest(10, selections);
581 TEST_F(SelectionCollectionDataTest, HandlesResnr)
583 static const char * const selections[] = {
587 runTest("simple.gro", selections);
590 TEST_F(SelectionCollectionDataTest, HandlesResIndex)
592 static const char * const selections[] = {
596 runTest("simple.pdb", selections);
599 TEST_F(SelectionCollectionDataTest, HandlesMolIndex)
601 static const char * const selections[] = {
605 ASSERT_NO_FATAL_FAILURE(runParser(selections));
606 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
607 topManager_.initUniformMolecules(3);
608 ASSERT_NO_FATAL_FAILURE(runCompiler());
611 TEST_F(SelectionCollectionDataTest, HandlesAtomname)
613 static const char * const selections[] = {
617 runTest("simple.gro", selections);
620 TEST_F(SelectionCollectionDataTest, HandlesPdbAtomname)
622 static const char * const selections[] = {
628 runTest("simple.pdb", selections);
632 TEST_F(SelectionCollectionDataTest, HandlesAtomtype)
634 static const char * const selections[] = {
637 ASSERT_NO_FATAL_FAILURE(runParser(selections));
638 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
639 const char *const types[] = { "CA", "SA", "SB" };
640 topManager_.initAtomTypes(types);
641 ASSERT_NO_FATAL_FAILURE(runCompiler());
644 TEST_F(SelectionCollectionDataTest, HandlesChain)
646 static const char * const selections[] = {
650 runTest("simple.pdb", selections);
653 TEST_F(SelectionCollectionDataTest, HandlesMass)
655 static const char * const selections[] = {
658 ASSERT_NO_FATAL_FAILURE(runParser(selections));
659 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
660 for (int i = 0; i < top_->atoms.nr; ++i)
662 top_->atoms.atom[i].m = 1.0 + i;
664 ASSERT_NO_FATAL_FAILURE(runCompiler());
667 TEST_F(SelectionCollectionDataTest, HandlesCharge)
669 static const char * const selections[] = {
672 ASSERT_NO_FATAL_FAILURE(runParser(selections));
673 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
674 for (int i = 0; i < top_->atoms.nr; ++i)
676 top_->atoms.atom[i].q = i / 10.0;
678 ASSERT_NO_FATAL_FAILURE(runCompiler());
681 TEST_F(SelectionCollectionDataTest, HandlesAltLoc)
683 static const char * const selections[] = {
687 runTest("simple.pdb", selections);
690 TEST_F(SelectionCollectionDataTest, HandlesInsertCode)
692 static const char * const selections[] = {
696 runTest("simple.pdb", selections);
699 TEST_F(SelectionCollectionDataTest, HandlesOccupancy)
701 static const char * const selections[] = {
705 runTest("simple.pdb", selections);
708 TEST_F(SelectionCollectionDataTest, HandlesBeta)
710 static const char * const selections[] = {
714 runTest("simple.pdb", selections);
717 TEST_F(SelectionCollectionDataTest, HandlesResname)
719 static const char * const selections[] = {
723 runTest("simple.gro", selections);
726 TEST_F(SelectionCollectionDataTest, HandlesCoordinateKeywords)
728 static const char * const selections[] = {
733 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
734 runTest("simple.gro", selections);
738 TEST_F(SelectionCollectionDataTest, HandlesSameResidue)
740 static const char * const selections[] = {
741 "same residue as atomnr 1 4 12"
743 runTest("simple.gro", selections);
747 TEST_F(SelectionCollectionDataTest, HandlesSameResidueName)
749 static const char * const selections[] = {
750 "same resname as atomnr 1 14"
752 runTest("simple.gro", selections);
756 TEST_F(SelectionCollectionDataTest, HandlesPositionKeywords)
758 static const char * const selections[] = {
760 "res_cog of name CB and resnr 1 3",
761 "whole_res_cog of name CB and resnr 1 3",
762 "part_res_cog of x < 3",
763 "dyn_res_cog of x < 3"
765 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates
766 | efTestPositionAtoms);
767 runTest("simple.gro", selections);
771 TEST_F(SelectionCollectionDataTest, HandlesDistanceKeyword)
773 static const char * const selections[] = {
774 "distance from cog of resnr 1 < 2"
776 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
777 runTest("simple.gro", selections);
781 TEST_F(SelectionCollectionDataTest, HandlesMinDistanceKeyword)
783 static const char * const selections[] = {
784 "mindistance from resnr 1 < 2"
786 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
787 runTest("simple.gro", selections);
791 TEST_F(SelectionCollectionDataTest, HandlesWithinKeyword)
793 static const char * const selections[] = {
794 "within 1 of resnr 2"
796 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
797 runTest("simple.gro", selections);
801 TEST_F(SelectionCollectionDataTest, HandlesInSolidAngleKeyword)
803 // Both of these should evaluate to empty on a correct implementation.
804 static const char * const selections[] = {
805 "resname TP and not insolidangle center cog of resname C span resname R cutoff 20",
806 "resname TN and insolidangle center cog of resname C span resname R cutoff 20"
808 setFlags(TestFlags() | efDontTestCompiledAtoms | efTestEvaluation);
809 runTest("sphere.gro", selections);
813 TEST_F(SelectionCollectionDataTest, HandlesPermuteModifier)
815 static const char * const selections[] = {
817 "res_cog of resnr 1 to 4 permute 2 1",
818 "name CB S1 and res_cog x < 3 permute 2 1"
820 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates
821 | efTestPositionAtoms | efTestPositionMapping);
822 runTest("simple.gro", selections);
826 TEST_F(SelectionCollectionDataTest, HandlesPlusModifier)
828 static const char * const selections[] = {
829 "name S2 plus name S1",
830 "res_cog of resnr 2 plus res_cog of resnr 1 plus res_cog of resnr 3",
831 "name S1 and y < 3 plus res_cog of x < 2.5"
833 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates
834 | efTestPositionAtoms | efTestPositionMapping);
835 runTest("simple.gro", selections);
839 TEST_F(SelectionCollectionDataTest, HandlesMergeModifier)
841 static const char * const selections[] = {
842 "name S2 merge name S1",
843 "resnr 1 2 and name S2 merge resnr 1 2 and name S1 merge res_cog of resnr 1 2",
844 "name S1 and x < 2.5 merge res_cog of x < 2.5"
846 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates
847 | efTestPositionAtoms | efTestPositionMapping);
848 runTest("simple.gro", selections);
852 /********************************************************************
853 * Tests for generic selection evaluation
856 TEST_F(SelectionCollectionDataTest, ComputesMassesAndCharges)
858 static const char * const selections[] = {
863 setFlags(TestFlags() | efTestEvaluation | efTestPositionAtoms
864 | efTestPositionMasses | efTestPositionCharges);
865 ASSERT_NO_FATAL_FAILURE(runParser(selections));
866 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
867 for (int i = 0; i < top_->atoms.nr; ++i)
869 top_->atoms.atom[i].m = 1.0 + i / 100.0;
870 top_->atoms.atom[i].q = -(1.0 + i / 100.0);
872 ASSERT_NO_FATAL_FAILURE(runCompiler());
873 ASSERT_NO_FATAL_FAILURE(runEvaluate());
874 ASSERT_NO_FATAL_FAILURE(runEvaluateFinal());
877 TEST_F(SelectionCollectionDataTest, ComputesMassesAndChargesWithoutTopology)
879 static const char * const selections[] = {
880 "atomnr 1 to 3 8 to 9",
884 setFlags(TestFlags() | efTestPositionAtoms
885 | efTestPositionMasses | efTestPositionCharges);
886 runTest(10, selections);
890 /********************************************************************
891 * Tests for selection syntactic constructs
894 TEST_F(SelectionCollectionDataTest, HandlesSelectionNames)
896 static const char * const selections[] = {
897 "\"GroupSelection\" group \"GrpA\"",
898 "\"DynamicSelection\" x < 5",
901 setFlags(TestFlags() | efTestSelectionNames);
902 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
903 runTest(10, selections);
906 TEST_F(SelectionCollectionDataTest, HandlesIndexGroupsInSelections)
908 static const char * const selections[] = {
912 "group \"GrpB\" and resname RB"
914 setFlags(TestFlags() | efTestSelectionNames);
915 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
916 runTest("simple.gro", selections);
919 TEST_F(SelectionCollectionDataTest, HandlesIndexGroupsInSelectionsDelayed)
921 static const char * const selections[] = {
925 "group \"GrpB\" and resname RB"
927 setFlags(TestFlags() | efTestSelectionNames);
928 ASSERT_NO_FATAL_FAILURE(runParser(selections));
929 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
930 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
931 ASSERT_NO_FATAL_FAILURE(runCompiler());
934 TEST_F(SelectionCollectionDataTest, HandlesUnsortedIndexGroupsInSelections)
936 static const char * const selections[] = {
937 "foo = group \"GrpUnsorted\"",
938 "group \"GrpUnsorted\"",
941 "res_cog of group \"GrpUnsorted\"",
942 "group \"GrpUnsorted\" permute 2 1",
945 setFlags(TestFlags() | efTestPositionAtoms | efTestPositionMapping
946 | efTestSelectionNames);
947 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
948 runTest("simple.gro", selections);
951 TEST_F(SelectionCollectionDataTest, HandlesUnsortedIndexGroupsInSelectionsDelayed)
953 static const char * const selections[] = {
954 "foo = group \"GrpUnsorted\"",
955 "group \"GrpUnsorted\"",
958 "res_cog of group \"GrpUnsorted\"",
959 "group \"GrpUnsorted\" permute 2 1",
962 ASSERT_NO_FATAL_FAILURE(runParser(selections));
963 ASSERT_NO_FATAL_FAILURE(loadTopology("simple.gro"));
964 ASSERT_NO_THROW_GMX(loadIndexGroups("simple.ndx"));
965 ASSERT_NO_FATAL_FAILURE(runCompiler());
968 TEST_F(SelectionCollectionDataTest, HandlesConstantPositions)
970 static const char * const selections[] = {
973 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
974 runTest("simple.gro", selections);
978 TEST_F(SelectionCollectionDataTest, HandlesWithinConstantPositions)
980 static const char * const selections[] = {
981 "within 1 of [2, 1, 0]"
983 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
984 runTest("simple.gro", selections);
988 TEST_F(SelectionCollectionDataTest, HandlesForcedStringMatchingMode)
990 static const char * const selections[] = {
994 runTest("simple.gro", selections);
998 TEST_F(SelectionCollectionDataTest, HandlesWildcardMatching)
1000 static const char * const selections[] = {
1004 runTest("simple.gro", selections);
1008 TEST_F(SelectionCollectionDataTest, HandlesRegexMatching)
1010 static const char * const selections[] = {
1011 "resname \"R[BD]\"",
1012 "resname ~ \"R[BD]\""
1014 if (gmx::Regex::isSupported())
1016 runTest("simple.gro", selections);
1021 TEST_F(SelectionCollectionDataTest, HandlesBasicBoolean)
1023 static const char * const selections[] = {
1024 "atomnr 1 to 5 and atomnr 2 to 7",
1025 "atomnr 1 to 5 or not atomnr 3 to 8",
1026 "not not atomnr 1 to 5 and atomnr 2 to 6 and not not atomnr 3 to 7",
1027 "atomnr 1 to 5 and (atomnr 2 to 7 and atomnr 3 to 6)",
1028 "x < 5 and atomnr 1 to 5 and y < 3 and atomnr 2 to 4"
1030 runTest(10, selections);
1034 TEST_F(SelectionCollectionDataTest, HandlesDynamicAtomValuedParameters)
1036 static const char * const selections[] = {
1037 "same residue as (atomnr 3 5 13 or y > 5)",
1038 "(resnr 1 3 5 or x > 10) and same residue as (atomnr 3 5 13 or z > 5)"
1040 setFlags(TestFlags() | efTestEvaluation);
1041 runTest("simple.gro", selections);
1045 TEST_F(SelectionCollectionDataTest, HandlesEmptySelectionWithUnevaluatedExpressions)
1047 static const char * const selections[] = {
1049 "none and same resname as resnr 2"
1051 runTest("simple.gro", selections);
1055 TEST_F(SelectionCollectionDataTest, HandlesNumericComparisons)
1057 static const char * const selections[] = {
1064 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1065 runTest("simple.gro", selections);
1069 TEST_F(SelectionCollectionDataTest, HandlesArithmeticExpressions)
1071 static const char * const selections[] = {
1077 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1078 runTest("simple.gro", selections);
1082 TEST_F(SelectionCollectionDataTest, HandlesNumericVariables)
1084 static const char * const selections[] = {
1090 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1091 runTest("simple.gro", selections);
1095 TEST_F(SelectionCollectionDataTest, HandlesComplexNumericVariables)
1097 static const char * const selections[] = {
1099 "resname RA and value <= 4",
1100 "resname RA RB and x < 3 and value <= 4",
1102 "resname RA and index < 3",
1103 "resname RB and y < 3 and index < 6"
1105 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1106 runTest("simple.gro", selections);
1110 TEST_F(SelectionCollectionDataTest, HandlesPositionVariables)
1112 static const char * const selections[] = {
1113 "foo = res_cog of resname RA",
1116 "bar = cog of resname RA",
1120 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1121 runTest("simple.gro", selections);
1125 TEST_F(SelectionCollectionDataTest, HandlesConstantPositionInVariable)
1127 static const char * const selections[] = {
1128 "constpos = [1.0, 2.5, 0.5]",
1130 "within 2 of constpos"
1132 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates
1133 | efTestPositionAtoms);
1134 runTest("simple.gro", selections);
1138 TEST_F(SelectionCollectionDataTest, HandlesNumericConstantsInVariables)
1140 static const char * const selections[] = {
1145 "x + constreal1 < constreal2"
1147 setFlags(TestFlags() | efTestEvaluation | efTestPositionCoordinates);
1148 runTest("simple.gro", selections);
1152 /********************************************************************
1153 * Tests for complex boolean syntax
1156 TEST_F(SelectionCollectionDataTest, HandlesBooleanStaticAnalysis)
1158 static const char * const selections[] = {
1159 "atomnr 1 to 5 and atomnr 2 to 7 and x < 2",
1160 "atomnr 1 to 5 and (atomnr 4 to 7 or x < 2)",
1161 "atomnr 1 to 5 and y < 3 and (atomnr 4 to 7 or x < 2)",
1162 "atomnr 1 to 5 and not (atomnr 4 to 7 or x < 2)",
1163 "atomnr 1 to 5 or (atomnr 4 to 6 and (atomnr 5 to 7 or x < 2))"
1165 runTest(10, selections);
1169 TEST_F(SelectionCollectionDataTest, HandlesBooleanStaticAnalysisWithVariables)
1171 static const char * const selections[] = {
1172 "foo = atomnr 4 to 7 or x < 2",
1173 "atomnr 1 to 4 and foo",
1174 "atomnr 2 to 6 and y < 3 and foo",
1175 "atomnr 6 to 10 and not foo"
1177 runTest(10, selections);
1181 TEST_F(SelectionCollectionDataTest, HandlesBooleanStaticAnalysisWithMoreVariables)
1183 static const char * const selections[] = {
1184 "foo = atomnr 4 to 7",
1185 "bar = foo and x < 2",
1186 "bar2 = foo and y < 2",
1187 "atomnr 1 to 4 and bar",
1188 "atomnr 2 to 6 and y < 3 and bar2",
1189 "atomnr 6 to 10 and not foo"
1191 runTest(10, selections);
1195 /********************************************************************
1196 * Tests for complex subexpression cases
1198 * These tests use some knowledge of the implementation to trigger different
1199 * paths in the code.
1202 TEST_F(SelectionCollectionDataTest, HandlesUnusedVariables)
1204 static const char * const selections[] = {
1205 "unused1 = atomnr 1 to 3",
1206 "foo = atomnr 4 to 7",
1207 "atomnr 1 to 6 and foo",
1208 "unused2 = atomnr 3 to 5"
1210 runTest(10, selections);
1214 TEST_F(SelectionCollectionDataTest, HandlesVariablesWithStaticEvaluationGroups)
1216 static const char * const selections[] = {
1217 "foo = atomnr 4 to 7 and x < 2",
1218 "atomnr 1 to 5 and foo",
1219 "atomnr 3 to 7 and foo"
1221 runTest(10, selections);
1225 TEST_F(SelectionCollectionDataTest, HandlesVariablesWithMixedEvaluationGroups)
1227 static const char * const selections[] = {
1228 "foo = atomnr 4 to 7 and x < 2",
1229 "atomnr 1 to 6 and foo",
1233 runTest(10, selections);
1237 TEST_F(SelectionCollectionDataTest, HandlesVariablesWithMixedEvaluationGroups2)
1239 static const char * const selections[] = {
1240 "foo = atomnr 1 to 8 and x < 10",
1241 "atomnr 1 to 5 and y < 10 and foo",
1244 setFlags(TestFlags() | efTestEvaluation);
1245 runTest("simple.gro", selections);