Add nblib backend: Part 1 of 2
[alexxy/gromacs.git] / api / nblib / tests / topology.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2020, 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  * This implements topology setup tests
38  *
39  * \author Victor Holanda <victor.holanda@cscs.ch>
40  * \author Joe Jordan <ejjordan@kth.se>
41  * \author Prashanth Kanduri <kanduri@cscs.ch>
42  * \author Sebastian Keller <keller@cscs.ch>
43  */
44 #include <gmock/gmock.h>
45 #include <gtest/gtest.h>
46
47 #include "gromacs/topology/exclusionblocks.h"
48 #include "nblib/exception.h"
49 #include "nblib/particletype.h"
50 #include "nblib/tests/testsystems.h"
51 #include "nblib/topology.h"
52
53 namespace nblib
54 {
55 namespace test
56 {
57 namespace
58 {
59
60 using ::testing::Eq;
61 using ::testing::Pointwise;
62
63 //! Compares all element between two lists of lists
64 //! Todo: unify this with the identical function in nbkernelsystem test make this a method
65 //!       of ListOfLists<>
66 template<typename T>
67 void compareLists(const gmx::ListOfLists<T>& list, const std::vector<std::vector<T>>& v)
68 {
69     ASSERT_EQ(list.size(), v.size());
70     for (std::size_t i = 0; i < list.size(); i++)
71     {
72         ASSERT_EQ(list[i].size(), v[i].size());
73         EXPECT_THAT(list[i], Pointwise(Eq(), v[i]));
74     }
75 }
76
77 // This is defined in src/gromacs/mdtypes/forcerec.h but there is also a
78 // legacy C6 macro defined there that conflicts with the nblib C6 type.
79 // Todo: Once that C6 has been refactored into a regular function, this
80 //       file can just include forcerec.h
81 //! Macro to marks particles to have Van der Waals interactions
82 #define SET_CGINFO_HAS_VDW(cgi) (cgi) = ((cgi) | (1 << 23))
83
84 TEST(NBlibTest, TopologyHasNumParticles)
85 {
86     WaterTopologyBuilder waters;
87     Topology             watersTopology = waters.buildTopology(2);
88     const int            test           = watersTopology.numParticles();
89     const int            ref            = 6;
90     EXPECT_EQ(ref, test);
91 }
92
93 TEST(NBlibTest, TopologyHasCharges)
94 {
95     WaterTopologyBuilder     waters;
96     Topology                 watersTopology = waters.buildTopology(2);
97     const std::vector<real>& test           = watersTopology.getCharges();
98     const std::vector<real>& ref = { Charges.at("Ow"), Charges.at("Hw"), Charges.at("Hw"),
99                                      Charges.at("Ow"), Charges.at("Hw"), Charges.at("Hw") };
100     EXPECT_EQ(ref, test);
101 }
102
103 TEST(NBlibTest, TopologyHasMasses)
104 {
105     WaterTopologyBuilder waters;
106     Topology             watersTopology = waters.buildTopology(2);
107
108     const Mass              refOwMass = waters.water().at("Ow").mass();
109     const Mass              refHwMass = waters.water().at("H").mass();
110     const std::vector<Mass> ref = { refOwMass, refHwMass, refHwMass, refOwMass, refHwMass, refHwMass };
111     const std::vector<Mass> test = expandQuantity(watersTopology, &ParticleType::mass);
112     EXPECT_EQ(ref, test);
113 }
114
115 TEST(NBlibTest, TopologyHasParticleTypes)
116 {
117     WaterTopologyBuilder             waters;
118     Topology                         watersTopology = waters.buildTopology(2);
119     const std::vector<ParticleType>& test           = watersTopology.getParticleTypes();
120     const ParticleType               refOw          = waters.water().at("Ow");
121     const ParticleType               refHw          = waters.water().at("H");
122     const std::vector<ParticleType>& ref            = { refOw, refHw };
123     const std::vector<ParticleType>& ref2           = { refHw, refOw };
124     EXPECT_TRUE(ref == test || ref2 == test);
125 }
126
127 TEST(NBlibTest, TopologyHasParticleTypeIds)
128 {
129     WaterTopologyBuilder waters;
130     Topology             watersTopology = waters.buildTopology(2);
131
132     const std::vector<int>&          testIds   = watersTopology.getParticleTypeIdOfAllParticles();
133     const std::vector<ParticleType>& testTypes = watersTopology.getParticleTypes();
134
135     std::vector<ParticleType> testTypesExpanded;
136     testTypesExpanded.reserve(testTypes.size());
137     for (int i : testIds)
138     {
139         testTypesExpanded.push_back(testTypes[i]);
140     }
141
142     const ParticleType              refOw = waters.water().at("Ow");
143     const ParticleType              refHw = waters.water().at("H");
144     const std::vector<ParticleType> ref   = { refOw, refHw, refHw, refOw, refHw, refHw };
145
146     EXPECT_TRUE(ref == testTypesExpanded);
147 }
148
149 TEST(NBlibTest, TopologyThrowsIdenticalParticleType)
150 {
151     //! User error: Two different ParticleTypes with the same name
152     ParticleType U235(ParticleTypeName("Uranium"), Mass(235));
153     ParticleType U238(ParticleTypeName("Uranium"), Mass(238));
154
155     Molecule ud235(MoleculeName("UraniumDimer235"));
156     ud235.addParticle(ParticleName("U1"), U235);
157     ud235.addParticle(ParticleName("U2"), U235);
158
159     Molecule ud238(MoleculeName("UraniumDimer238"));
160     ud238.addParticle(ParticleName("U1"), U238);
161     ud238.addParticle(ParticleName("U2"), U238);
162
163     TopologyBuilder topologyBuilder;
164     topologyBuilder.addMolecule(ud235, 1);
165     EXPECT_THROW(topologyBuilder.addMolecule(ud238, 1), InputException);
166 }
167
168 TEST(NBlibTest, TopologyHasExclusions)
169 {
170     WaterTopologyBuilder         waters;
171     Topology                     watersTopology = waters.buildTopology(2);
172     const gmx::ListOfLists<int>& testExclusions = watersTopology.getGmxExclusions();
173
174     const std::vector<std::vector<int>>& refExclusions = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
175                                                            { 3, 4, 5 }, { 3, 4, 5 }, { 3, 4, 5 } };
176
177     compareLists(testExclusions, refExclusions);
178 }
179
180 TEST(NBlibTest, TopologyHasSequencing)
181 {
182     WaterTopologyBuilder waters;
183     Topology             watersTopology = waters.buildTopology(2);
184
185     EXPECT_EQ(0, watersTopology.sequenceID(MoleculeName("SOL"), 0, ResidueName("SOL"),
186                                            ParticleName("Oxygen")));
187     EXPECT_EQ(1, watersTopology.sequenceID(MoleculeName("SOL"), 0, ResidueName("SOL"), ParticleName("H1")));
188     EXPECT_EQ(2, watersTopology.sequenceID(MoleculeName("SOL"), 0, ResidueName("SOL"), ParticleName("H2")));
189     EXPECT_EQ(3, watersTopology.sequenceID(MoleculeName("SOL"), 1, ResidueName("SOL"),
190                                            ParticleName("Oxygen")));
191     EXPECT_EQ(4, watersTopology.sequenceID(MoleculeName("SOL"), 1, ResidueName("SOL"), ParticleName("H1")));
192     EXPECT_EQ(5, watersTopology.sequenceID(MoleculeName("SOL"), 1, ResidueName("SOL"), ParticleName("H2")));
193 }
194
195 TEST(NBlibTest, toGmxExclusionBlockWorks)
196 {
197     std::vector<std::tuple<int, int>> testInput{ { 0, 0 }, { 0, 1 }, { 0, 2 }, { 1, 0 }, { 1, 1 },
198                                                  { 1, 2 }, { 2, 0 }, { 2, 1 }, { 2, 2 } };
199
200     std::vector<gmx::ExclusionBlock> reference;
201
202     gmx::ExclusionBlock localBlock;
203     localBlock.atomNumber.push_back(0);
204     localBlock.atomNumber.push_back(1);
205     localBlock.atomNumber.push_back(2);
206
207     reference.push_back(localBlock);
208     reference.push_back(localBlock);
209     reference.push_back(localBlock);
210
211     std::vector<gmx::ExclusionBlock> probe = detail::toGmxExclusionBlock(testInput);
212
213     ASSERT_EQ(reference.size(), probe.size());
214     for (size_t i = 0; i < reference.size(); ++i)
215     {
216         ASSERT_EQ(reference[i].atomNumber.size(), probe[i].atomNumber.size());
217         for (size_t j = 0; j < reference[i].atomNumber.size(); ++j)
218         {
219             EXPECT_EQ(reference[i].atomNumber[j], probe[i].atomNumber[j]);
220         }
221     }
222 }
223
224 } // namespace
225 } // namespace test
226 } // namespace nblib