2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2020,2021, 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 * Implements nblib Molecule
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 * \author Artem Zhmurov <zhmurov@gmail.com>
48 #include "nblib/exception.h"
49 #include "nblib/molecules.h"
50 #include "nblib/particletype.h"
55 Molecule::Molecule(MoleculeName moleculeName) : name_(std::move(moleculeName)) {}
57 MoleculeName Molecule::name() const
62 Molecule& Molecule::addParticle(const ParticleName& particleName,
63 const ResidueName& residueName,
65 ParticleType const& particleType)
67 auto found = particleTypes_.find(particleType.name());
68 if (found == particleTypes_.end())
70 particleTypes_.insert(std::make_pair(particleType.name(), particleType));
74 if (!(found->second == particleType))
77 "Differing ParticleTypes with identical names encountered in the same "
82 particles_.emplace_back(ParticleData{ particleName, residueName, particleType.name(), charge });
84 // Add self exclusion. We just added the particle, so we know its index and that the exclusion doesn't exist yet
85 std::size_t id = particles_.size() - 1;
86 exclusions_.emplace_back(id, id);
91 Molecule& Molecule::addParticle(const ParticleName& particleName,
92 const ResidueName& residueName,
93 ParticleType const& particleType)
95 addParticle(particleName, residueName, Charge(0), particleType);
100 Molecule& Molecule::addParticle(const ParticleName& particleName,
101 const Charge& charge,
102 ParticleType const& particleType)
104 addParticle(particleName, ResidueName(name_), charge, particleType);
109 Molecule& Molecule::addParticle(const ParticleName& particleName, const ParticleType& particleType)
111 addParticle(particleName, ResidueName(name_), Charge(0), particleType);
116 ResidueName Molecule::residueName(const ParticleIdentifier& particleIdentifier)
118 return (particleIdentifier.residueName() == ResidueName{}) ? ResidueName(name_)
119 : particleIdentifier.residueName();
122 template<class ListedVariant, class... ParticleIdentifiers>
123 void Molecule::addInteractionImpl(const ListedVariant& interaction, const ParticleIdentifiers&... particles)
125 auto storeInteraction = [&](const auto& interaction_) {
126 using Interaction = std::decay_t<decltype(interaction_)>;
128 auto& interactionContainer = pickType<Interaction>(interactionData_);
129 interactionContainer.interactions_.emplace_back(particles...);
130 interactionContainer.interactionTypes_.push_back(interaction_);
133 // add the interaction to the correct location in interactionData_
134 std::visit(storeInteraction, interaction);
137 void Molecule::addInteraction(const ParticleIdentifier& particleI,
138 const ParticleIdentifier& particleJ,
139 const TwoCenterInteraction& interaction)
141 if (particleI == particleJ)
143 throw InputException(std::string("Cannot add interaction of particle ")
144 + particleI.particleName().value() + " with itself in molecule "
148 addInteractionImpl(interaction, particleI.particleName(), residueName(particleI),
149 particleJ.particleName(), residueName(particleJ));
152 void Molecule::addInteraction(const ParticleIdentifier& particleI,
153 const ParticleIdentifier& particleJ,
154 const ParticleIdentifier& particleK,
155 const ThreeCenterInteraction& interaction)
157 if (particleI == particleJ and particleJ == particleK)
159 throw InputException(std::string("Cannot add interaction of particle ")
160 + particleI.particleName().value() + " with itself in molecule "
164 addInteractionImpl(interaction, particleI.particleName(), residueName(particleI),
165 particleJ.particleName(), residueName(particleJ), particleK.particleName(),
166 residueName(particleK));
169 void Molecule::addInteraction(const ParticleIdentifier& particleI,
170 const ParticleIdentifier& particleJ,
171 const ParticleIdentifier& particleK,
172 const ParticleIdentifier& particleL,
173 const FourCenterInteraction& interaction)
175 if (particleI == particleJ and particleJ == particleK and particleK == particleL)
177 throw InputException(std::string("Cannot add interaction of particle ")
178 + particleI.particleName().value() + " with itself in molecule "
182 addInteractionImpl(interaction, particleI.particleName(), residueName(particleI),
183 particleJ.particleName(), residueName(particleJ), particleK.particleName(),
184 residueName(particleK), particleL.particleName(), residueName(particleL));
187 void Molecule::addInteraction(const ParticleIdentifier& particleI,
188 const ParticleIdentifier& particleJ,
189 const ParticleIdentifier& particleK,
190 const ParticleIdentifier& particleL,
191 const ParticleIdentifier& particleM,
192 const FiveCenterInteraction& interaction)
194 if (particleI == particleJ and particleJ == particleK and particleK == particleL and particleL == particleM)
196 throw InputException(std::string("Cannot add interaction of particle ")
197 + particleI.particleName().value() + " with itself in molecule "
201 addInteractionImpl(interaction, particleI.particleName(), residueName(particleI),
202 particleJ.particleName(), residueName(particleJ), particleK.particleName(),
203 residueName(particleK), particleL.particleName(), residueName(particleL),
204 particleM.particleName(), residueName(particleM));
208 int Molecule::numParticlesInMolecule() const
210 return particles_.size();
213 void Molecule::addExclusion(const ParticleIdentifier& particle, const ParticleIdentifier& particleToExclude)
215 if (particle == particleToExclude)
220 // duplication for the swapped pair happens in getExclusions()
221 exclusionsByName_.emplace_back(std::make_tuple(particle.particleName(), residueName(particle),
222 particleToExclude.particleName(),
223 residueName(particleToExclude)));
226 const Molecule::InteractionTuple& Molecule::interactionData() const
228 return interactionData_;
231 const ParticleType& Molecule::at(const std::string& particleTypeName) const
233 return particleTypes_.at(particleTypeName);
236 ParticleName Molecule::particleName(int i) const
238 return ParticleName(particles_[i].particleName_);
241 ResidueName Molecule::residueName(int i) const
243 return ResidueName(particles_[i].residueName_);
246 std::vector<std::tuple<int, int>> Molecule::getExclusions() const
248 // tuples of (particleName, residueName, index)
249 std::vector<std::tuple<std::string, std::string, int>> indexKey;
250 indexKey.reserve(numParticlesInMolecule());
252 for (int i = 0; i < numParticlesInMolecule(); ++i)
254 indexKey.emplace_back(particles_[i].particleName_, particles_[i].residueName_, i);
257 std::sort(std::begin(indexKey), std::end(indexKey));
259 std::vector<std::tuple<int, int>> ret = exclusions_;
260 ret.reserve(exclusions_.size() + exclusionsByName_.size());
262 // normal operator<, except ignore third element
263 auto sortKey = [](const auto& tup1, const auto& tup2) {
264 if (std::get<0>(tup1) < std::get<0>(tup2))
270 return std::get<1>(tup1) < std::get<1>(tup2);
274 // convert exclusions given by names to indices and append
275 for (auto& tup : exclusionsByName_)
277 const std::string& particleName1 = std::get<0>(tup);
278 const std::string& residueName1 = std::get<1>(tup);
279 const std::string& particleName2 = std::get<2>(tup);
280 const std::string& residueName2 = std::get<3>(tup);
282 // look up first index (binary search)
283 auto it1 = std::lower_bound(std::begin(indexKey), std::end(indexKey),
284 std::make_tuple(particleName1, residueName2, 0), sortKey);
286 // make sure we have the (particleName,residueName) combo
287 if (it1 == std::end(indexKey) or std::get<0>(*it1) != particleName1 or std::get<1>(*it1) != residueName1)
289 throw std::runtime_error(
290 (std::string("Particle ") += particleName1 + std::string(" in residue ") +=
291 residueName1 + std::string(" not found in list of particles\n")));
294 int firstIndex = std::get<2>(*it1);
296 // look up second index (binary search)
297 auto it2 = std::lower_bound(std::begin(indexKey), std::end(indexKey),
298 std::make_tuple(particleName2, residueName2, 0), sortKey);
300 // make sure we have the (particleName,residueName) combo
301 if (it2 == std::end(indexKey) or std::get<0>(*it2) != particleName2 or std::get<1>(*it2) != residueName2)
303 throw std::runtime_error(
304 (std::string("Particle ") += particleName2 + std::string(" in residue ") +=
305 residueName2 + std::string(" not found in list of particles\n")));
308 int secondIndex = std::get<2>(*it2);
310 ret.emplace_back(firstIndex, secondIndex);
311 ret.emplace_back(secondIndex, firstIndex);
314 std::sort(std::begin(ret), std::end(ret));
316 auto uniqueEnd = std::unique(std::begin(ret), std::end(ret));
317 if (uniqueEnd != std::end(ret))
319 printf("[nblib] Warning: exclusionList for molecule %s contained duplicates",
320 name_.value().c_str());
323 ret.erase(uniqueEnd, std::end(ret));
327 std::unordered_map<std::string, ParticleType> Molecule::particleTypesMap() const
329 return particleTypes_;
332 std::vector<ParticleData> Molecule::particleData() const