Tidy: modernize-use-nullptr
[alexxy/gromacs.git] / src / gromacs / selection / tests / indexutil.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2013,2014,2015,2016,2017, 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.
8  *
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.
13  *
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.
18  *
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.
23  *
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.
31  *
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.
34  */
35 /*! \internal \file
36  * \brief
37  * Tests the index group handling in the selection engine.
38  *
39  * \todo
40  * Tests for other functions, at least the set operations.
41  *
42  * \author Teemu Murtola <teemu.murtola@gmail.com>
43  * \ingroup module_selection
44  */
45 #include "gmxpre.h"
46
47 #include "gromacs/selection/indexutil.h"
48
49 #include <gtest/gtest.h>
50
51 #include "gromacs/topology/block.h"
52 #include "gromacs/utility/arrayref.h"
53
54 #include "testutils/refdata.h"
55
56 #include "toputils.h"
57
58 namespace
59 {
60
61 //! Helper for creating groups from an array.
62 gmx_ana_index_t initGroup(gmx::ArrayRef<int> index)
63 {
64     gmx_ana_index_t g = { static_cast<int>(index.size()), index.data(), 0 };
65     return g;
66 }
67
68 TEST(IndexGroupTest, RemovesDuplicates)
69 {
70     int             index[]    = { 1, 1, 2, 3, 4, 4 };
71     int             expected[] = { 1, 2, 3, 4 };
72     gmx_ana_index_t g          = initGroup(index);
73     gmx_ana_index_t e          = initGroup(expected);
74     gmx_ana_index_remove_duplicates(&g);
75     EXPECT_TRUE(gmx_ana_index_equals(&g, &e));
76 }
77
78 /********************************************************************
79  * IndexBlockTest
80  */
81
82 class IndexBlockTest : public ::testing::Test
83 {
84     public:
85         IndexBlockTest();
86         ~IndexBlockTest();
87
88         void setGroup(int count, const int atoms[]);
89         template <int count>
90         void setGroup(const int (&atoms)[count])
91         {
92             setGroup(count, atoms);
93         }
94
95         void checkBlocka();
96
97         gmx::test::TestReferenceData    data_;
98         gmx::test::TopologyManager      topManager_;
99         gmx_ana_index_t                 g_;
100         t_blocka                        blocka_;
101 };
102
103 IndexBlockTest::IndexBlockTest()
104 {
105     blocka_.nr           = 0;
106     blocka_.index        = nullptr;
107     blocka_.nalloc_index = 0;
108     blocka_.nra          = 0;
109     blocka_.a            = nullptr;
110     blocka_.nalloc_a     = 0;
111     gmx_ana_index_clear(&g_);
112 }
113
114 IndexBlockTest::~IndexBlockTest()
115 {
116     done_blocka(&blocka_);
117 }
118
119 void IndexBlockTest::setGroup(int count, const int atoms[])
120 {
121     g_.isize = count;
122     g_.index = const_cast<int *>(atoms);
123 }
124
125 void IndexBlockTest::checkBlocka()
126 {
127     gmx::test::TestReferenceChecker compound(
128             data_.rootChecker().checkCompound("BlockAtoms", "Block"));
129     compound.checkSequenceArray(g_.isize, g_.index, "Input");
130     compound.checkInteger(blocka_.nr, "Count");
131     for (int i = 0; i < blocka_.nr; ++i)
132     {
133         gmx::test::TestReferenceChecker blockCompound(
134                 compound.checkCompound("Block", nullptr));
135         blockCompound.checkSequence(&blocka_.a[blocka_.index[i]],
136                                     &blocka_.a[blocka_.index[i+1]],
137                                     "Atoms");
138     }
139 }
140
141 /********************************************************************
142  * gmx_ana_index_make_block() tests
143  */
144
145 TEST_F(IndexBlockTest, CreatesUnknownBlock)
146 {
147     gmx_ana_index_make_block(&blocka_, nullptr, nullptr, INDEX_UNKNOWN, false);
148     checkBlocka();
149     done_blocka(&blocka_);
150     gmx_ana_index_make_block(&blocka_, nullptr, nullptr, INDEX_UNKNOWN, false);
151     checkBlocka();
152 }
153
154 TEST_F(IndexBlockTest, CreatesAtomBlock)
155 {
156     const int group[] = { 0, 1, 3, 4, 6 };
157     setGroup(group);
158     gmx_ana_index_make_block(&blocka_, nullptr, &g_, INDEX_ATOM, false);
159     checkBlocka();
160     done_blocka(&blocka_);
161     gmx_ana_index_make_block(&blocka_, nullptr, &g_, INDEX_ATOM, true);
162     checkBlocka();
163 }
164
165 TEST_F(IndexBlockTest, CreatesResidueBlock)
166 {
167     const int group[] = { 0, 1, 3, 6, 7 };
168     topManager_.initAtoms(9);
169     topManager_.initUniformResidues(3);
170     setGroup(group);
171     gmx_ana_index_make_block(&blocka_, topManager_.topology(), &g_,
172                              INDEX_RES, false);
173     checkBlocka();
174 }
175
176 TEST_F(IndexBlockTest, CreatesMoleculeBlock)
177 {
178     const int group[] = { 3, 4, 7, 8, 13 };
179     topManager_.initAtoms(18);
180     topManager_.initUniformMolecules(3);
181     setGroup(group);
182     gmx_ana_index_make_block(&blocka_, topManager_.topology(), &g_,
183                              INDEX_MOL, false);
184     checkBlocka();
185 }
186
187 TEST_F(IndexBlockTest, CreatesResidueBlockWithCompletion)
188 {
189     const int group[] = { 3, 4, 7, 8, 13 };
190     topManager_.initAtoms(18);
191     topManager_.initUniformResidues(3);
192     setGroup(group);
193     gmx_ana_index_make_block(&blocka_, topManager_.topology(), &g_,
194                              INDEX_RES, true);
195     checkBlocka();
196 }
197
198 TEST_F(IndexBlockTest, CreatesMoleculeBlockWithCompletion)
199 {
200     const int group[] = { 3, 4, 7, 8, 13 };
201     topManager_.initAtoms(18);
202     topManager_.initUniformMolecules(3);
203     setGroup(group);
204     gmx_ana_index_make_block(&blocka_, topManager_.topology(), &g_,
205                              INDEX_MOL, true);
206     checkBlocka();
207 }
208
209 TEST_F(IndexBlockTest, CreatesSingleBlock)
210 {
211     const int group[] = { 0, 1, 3, 4, 6 };
212     setGroup(group);
213     gmx_ana_index_make_block(&blocka_, nullptr, &g_, INDEX_ALL, false);
214     checkBlocka();
215     done_blocka(&blocka_);
216     gmx_ana_index_make_block(&blocka_, nullptr, &g_, INDEX_ALL, true);
217     checkBlocka();
218 }
219
220 /********************************************************************
221  * gmx_ana_index_has_full_ablocks() tests
222  */
223
224 TEST_F(IndexBlockTest, ChecksGroupForFullBlocksPositive)
225 {
226     const int maxGroup[] = {
227         0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17
228     };
229     const int testGroup[] = { 3, 4, 5, 6, 7, 8, 12, 13, 14 };
230     topManager_.initAtoms(18);
231     topManager_.initUniformResidues(3);
232     setGroup(maxGroup);
233     gmx_ana_index_make_block(&blocka_, topManager_.topology(), &g_,
234                              INDEX_RES, false);
235     setGroup(testGroup);
236     EXPECT_TRUE(gmx_ana_index_has_full_ablocks(&g_, &blocka_));
237 }
238
239 TEST_F(IndexBlockTest, ChecksOutOfOrderGroupForFullBlocksPositive)
240 {
241     const int maxGroup[] = {
242         15, 16, 17, 2, 1, 0, 12, 13, 14, 5, 4, 3, 9, 10, 11, 8, 7, 6
243     };
244     const int testGroup[] = { 2, 1, 0, 5, 4, 3, 8, 7, 6, };
245     topManager_.initAtoms(18);
246     topManager_.initUniformResidues(3);
247     setGroup(maxGroup);
248     gmx_ana_index_make_block(&blocka_, topManager_.topology(), &g_,
249                              INDEX_RES, false);
250     setGroup(testGroup);
251     EXPECT_TRUE(gmx_ana_index_has_full_ablocks(&g_, &blocka_));
252 }
253
254 TEST_F(IndexBlockTest, ChecksGroupForFullBlocksNegative)
255 {
256     const int maxGroup[] = {
257         0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17
258     };
259     const int testGroup1[] = { 3, 4, 5, 6, 7, 8, 12, 13 };
260     const int testGroup2[] = { 3, 4, 5, 6, 7, 12, 13, 14 };
261     const int testGroup3[] = { 4, 5, 6, 7, 8, 12, 13, 14 };
262
263     topManager_.initAtoms(18);
264     topManager_.initUniformResidues(3);
265     setGroup(maxGroup);
266     gmx_ana_index_make_block(&blocka_, topManager_.topology(), &g_,
267                              INDEX_RES, false);
268
269     setGroup(testGroup1);
270     EXPECT_FALSE(gmx_ana_index_has_full_ablocks(&g_, &blocka_));
271
272     setGroup(testGroup2);
273     EXPECT_FALSE(gmx_ana_index_has_full_ablocks(&g_, &blocka_));
274
275     setGroup(testGroup3);
276     EXPECT_FALSE(gmx_ana_index_has_full_ablocks(&g_, &blocka_));
277 }
278
279 /********************************************************************
280  * gmx_ana_index_has_complete_elems() tests
281  */
282
283 TEST_F(IndexBlockTest, ChecksGroupForCompleteElementsTrivial)
284 {
285     const int group[] = { 0, 1, 2 };
286     setGroup(group);
287     EXPECT_TRUE(gmx_ana_index_has_complete_elems(&g_, INDEX_ATOM, nullptr));
288     EXPECT_FALSE(gmx_ana_index_has_complete_elems(&g_, INDEX_ALL, nullptr));
289     EXPECT_FALSE(gmx_ana_index_has_complete_elems(&g_, INDEX_UNKNOWN, nullptr));
290 }
291
292 TEST_F(IndexBlockTest, ChecksGroupForCompleteResiduesPositive)
293 {
294     const int group1[] = { 0, 1, 2, 6, 7, 8, 12, 13, 14 };
295     const int group2[] = { 3, 4, 5, 6, 7, 8 };
296
297     topManager_.initAtoms(15);
298     topManager_.initUniformResidues(3);
299     gmx_mtop_t *top = topManager_.topology();
300
301     setGroup(group1);
302     EXPECT_TRUE(gmx_ana_index_has_complete_elems(&g_, INDEX_RES, top));
303
304     setGroup(group2);
305     EXPECT_TRUE(gmx_ana_index_has_complete_elems(&g_, INDEX_RES, top));
306 }
307
308 TEST_F(IndexBlockTest, ChecksGroupForCompleteResiduesNegative)
309 {
310     const int group1[] = { 3, 4, 5, 6, 7, 8, 12, 13 };
311     const int group2[] = { 3, 4, 5, 6, 7, 12, 13, 14 };
312     const int group3[] = { 4, 5, 6, 7, 8, 12, 13, 14 };
313     const int group4[] = { 3, 4, 5, 6, 8, 12, 13, 14 };
314
315     topManager_.initAtoms(18);
316     topManager_.initUniformResidues(3);
317     gmx_mtop_t *top = topManager_.topology();
318
319     setGroup(group1);
320     EXPECT_FALSE(gmx_ana_index_has_complete_elems(&g_, INDEX_RES, top));
321
322     setGroup(group2);
323     EXPECT_FALSE(gmx_ana_index_has_complete_elems(&g_, INDEX_RES, top));
324
325     setGroup(group3);
326     EXPECT_FALSE(gmx_ana_index_has_complete_elems(&g_, INDEX_RES, top));
327
328     setGroup(group4);
329     EXPECT_FALSE(gmx_ana_index_has_complete_elems(&g_, INDEX_RES, top));
330 }
331
332 TEST_F(IndexBlockTest, ChecksGroupForCompleteMoleculesPositive)
333 {
334     const int group[] = { 0, 1, 2, 6, 7, 8, 12, 13, 14 };
335
336     topManager_.initAtoms(15);
337     topManager_.initUniformMolecules(3);
338     gmx_mtop_t *top = topManager_.topology();
339
340     setGroup(group);
341     EXPECT_TRUE(gmx_ana_index_has_complete_elems(&g_, INDEX_MOL, top));
342 }
343
344 TEST_F(IndexBlockTest, ChecksGroupForCompleteMoleculesNegative)
345 {
346     const int group1[] = { 3, 4, 5, 6, 7, 8, 12, 13 };
347     const int group2[] = { 3, 4, 5, 6, 7, 12, 13, 14 };
348     const int group3[] = { 4, 5, 6, 7, 8, 12, 13, 14 };
349
350     topManager_.initAtoms(18);
351     topManager_.initUniformMolecules(3);
352     gmx_mtop_t *top = topManager_.topology();
353
354     setGroup(group1);
355     EXPECT_FALSE(gmx_ana_index_has_complete_elems(&g_, INDEX_MOL, top));
356
357     setGroup(group2);
358     EXPECT_FALSE(gmx_ana_index_has_complete_elems(&g_, INDEX_MOL, top));
359
360     setGroup(group3);
361     EXPECT_FALSE(gmx_ana_index_has_complete_elems(&g_, INDEX_MOL, top));
362 }
363
364 /********************************************************************
365  * IndexMapTest
366  */
367
368 class IndexMapTest : public ::testing::Test
369 {
370     public:
371         IndexMapTest();
372         ~IndexMapTest();
373
374         void testInit(int atomCount, const int atoms[], e_index_t type);
375         void testUpdate(int atomCount, const int atoms[], bool bMaskOnly,
376                         const char *name);
377         void testOrgIdGroup(e_index_t type, const char *name);
378         template <int count>
379         void testInit(const int (&atoms)[count], e_index_t type)
380         {
381             testInit(count, atoms, type);
382         }
383         template <int count>
384         void testUpdate(const int (&atoms)[count], bool bMaskOnly,
385                         const char *name)
386         {
387             testUpdate(count, atoms, bMaskOnly, name);
388         }
389
390         void checkMapping(int atomCount, const int atoms[], const char *name);
391
392         gmx::test::TestReferenceData    data_;
393         gmx::test::TestReferenceChecker checker_;
394         gmx::test::TopologyManager      topManager_;
395         gmx_ana_indexmap_t              map_;
396
397     private:
398         gmx_ana_index_t                 initGroup_;
399 };
400
401 IndexMapTest::IndexMapTest()
402     : checker_(data_.rootChecker())
403 {
404     gmx_ana_indexmap_clear(&map_);
405     gmx_ana_index_clear(&initGroup_);
406 }
407
408 IndexMapTest::~IndexMapTest()
409 {
410     gmx_ana_indexmap_deinit(&map_);
411 }
412
413 void IndexMapTest::testInit(int atomCount, const int atoms[], e_index_t type)
414 {
415     initGroup_.isize = atomCount;
416     initGroup_.index = const_cast<int *>(atoms);
417     gmx_ana_indexmap_init(&map_, &initGroup_, topManager_.topology(), type);
418     EXPECT_EQ(type, map_.type);
419     checkMapping(atomCount, atoms, "Initialized");
420 }
421
422 void IndexMapTest::testUpdate(int atomCount, const int atoms[], bool bMaskOnly,
423                               const char *name)
424 {
425     gmx_ana_index_t g;
426     g.isize = atomCount;
427     g.index = const_cast<int *>(atoms);
428     gmx_ana_indexmap_update(&map_, &g, bMaskOnly);
429     if (name == nullptr)
430     {
431         name = "Updated";
432     }
433     if (bMaskOnly)
434     {
435         checkMapping(initGroup_.isize, initGroup_.index, name);
436     }
437     else
438     {
439         checkMapping(atomCount, atoms, name);
440     }
441 }
442
443 void IndexMapTest::testOrgIdGroup(e_index_t type, const char *name)
444 {
445     gmx::test::TestReferenceChecker compound(
446             checker_.checkCompound("OrgIdGroups", name));
447     const int count
448         = gmx_ana_indexmap_init_orgid_group(&map_, topManager_.topology(), type);
449     compound.checkInteger(count, "GroupCount");
450     compound.checkSequenceArray(map_.mapb.nr, map_.orgid, "OrgId");
451     for (int i = 0; i < map_.mapb.nr; ++i)
452     {
453         EXPECT_EQ(map_.orgid[i], map_.mapid[i]);
454     }
455 }
456
457 void IndexMapTest::checkMapping(int atomCount, const int atoms[],
458                                 const char *name)
459 {
460     gmx::test::TestReferenceChecker compound(
461             checker_.checkCompound("IndexMapping", name));
462     compound.checkSequenceArray(atomCount, atoms, "Input");
463     compound.checkInteger(map_.mapb.nr, "Count");
464     for (int i = 0; i < map_.mapb.nr; ++i)
465     {
466         gmx::test::TestReferenceChecker blockCompound(
467                 compound.checkCompound("Block", nullptr));
468         blockCompound.checkSequence(&atoms[map_.mapb.index[i]],
469                                     &atoms[map_.mapb.index[i+1]],
470                                     "Atoms");
471         blockCompound.checkInteger(map_.refid[i], "RefId");
472         blockCompound.checkInteger(map_.mapid[i], "MapId");
473         int originalIdIndex = (map_.refid[i] != -1 ? map_.refid[i] : i);
474         EXPECT_EQ(map_.orgid[originalIdIndex], map_.mapid[i]);
475     }
476 }
477
478 /********************************************************************
479  * gmx_ana_indexmap_t tests
480  */
481
482 TEST_F(IndexMapTest, InitializesAtomBlock)
483 {
484     const int maxGroup[] = { 1, 2, 4, 5 };
485     testInit(maxGroup, INDEX_ATOM);
486 }
487
488 TEST_F(IndexMapTest, InitializesOrgIdGroupAtom)
489 {
490     const int maxGroup[] = { 2, 5, 7 };
491     testInit(maxGroup, INDEX_ATOM);
492     testOrgIdGroup(INDEX_ATOM, "Atoms");
493 }
494
495 TEST_F(IndexMapTest, InitializesOrgIdGroupSingle)
496 {
497     const int maxGroup[] = { 3, 4, 7, 8, 13 };
498     topManager_.initAtoms(18);
499     topManager_.initUniformResidues(3);
500     testInit(maxGroup, INDEX_RES);
501     testOrgIdGroup(INDEX_ATOM, "Single");
502 }
503
504 TEST_F(IndexMapTest, InitializesOrgIdGroupResidue)
505 {
506     const int maxGroup[] = { 3, 4, 7, 8, 13 };
507     topManager_.initAtoms(18);
508     topManager_.initUniformResidues(3);
509     testInit(maxGroup, INDEX_ATOM);
510     testOrgIdGroup(INDEX_RES, "Residues");
511 }
512
513 TEST_F(IndexMapTest, InitializesOrgIdGroupMolecule)
514 {
515     const int maxGroup[] = { 1, 2, 3, 4, 7, 8, 13 };
516     topManager_.initAtoms(18);
517     topManager_.initUniformResidues(3);
518     topManager_.initUniformMolecules(6);
519     testInit(maxGroup, INDEX_RES);
520     testOrgIdGroup(INDEX_MOL, "Molecules");
521 }
522
523 TEST_F(IndexMapTest, InitializesOrgIdGroupAll)
524 {
525     const int maxGroup[] = { 3, 4, 7, 8, 13 };
526     testInit(maxGroup, INDEX_ATOM);
527     testOrgIdGroup(INDEX_ALL, "All");
528 }
529
530 TEST_F(IndexMapTest, InitializesMoleculeBlock)
531 {
532     const int maxGroup[] = { 3, 4, 7, 8, 13 };
533     topManager_.initAtoms(18);
534     topManager_.initUniformMolecules(3);
535     testInit(maxGroup, INDEX_MOL);
536 }
537
538 TEST_F(IndexMapTest, MapsSingleBlock)
539 {
540     const int maxGroup[]  = { 0, 1, 2, 3 };
541     const int evalGroup[] = { 0, 2 };
542     testInit(maxGroup, INDEX_ALL);
543     testUpdate(evalGroup, false, nullptr);
544 }
545
546 TEST_F(IndexMapTest, MapsResidueBlocks)
547 {
548     const int maxGroup[] = {
549         0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17
550     };
551     const int evalGroup[] = { 3, 4, 7, 8, 13 };
552     topManager_.initAtoms(18);
553     topManager_.initUniformResidues(3);
554     testInit(maxGroup, INDEX_RES);
555     testUpdate(evalGroup, false, nullptr);
556 }
557
558 TEST_F(IndexMapTest, MapsResidueBlocksWithMask)
559 {
560     const int maxGroup[] = {
561         0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17
562     };
563     const int evalGroup[] = { 3, 4, 7, 8, 13 };
564     topManager_.initAtoms(18);
565     topManager_.initUniformResidues(3);
566     testInit(maxGroup, INDEX_RES);
567     testUpdate(evalGroup, true, nullptr);
568 }
569
570 TEST_F(IndexMapTest, HandlesMultipleRequests)
571 {
572     const int maxGroup[] = {
573         0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17
574     };
575     const int evalGroup[] = { 3, 4, 7, 8, 13 };
576     topManager_.initAtoms(18);
577     topManager_.initUniformResidues(3);
578     testInit(maxGroup, INDEX_RES);
579     testUpdate(evalGroup, false, "EvaluatedNoMask");
580     testUpdate(evalGroup, true, "EvaluatedMask");
581     testUpdate(maxGroup, true, "Initialized");
582     testUpdate(evalGroup, true, "EvaluatedMask");
583     testUpdate(evalGroup, false, "EvaluatedNoMask");
584     testUpdate(maxGroup, false, "Initialized");
585 }
586
587 } // namespace