Add nblib backend: Part 1 of 2
[gromacs.git] / api / nblib / molecules.cpp
blobb8f70ee797e1fdb11b901efca36fa04aa453e112
1 /*
2 * This file is part of the GROMACS molecular simulation package.
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.
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.
35 /*! \internal \file
36 * \brief
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>
45 #include <algorithm>
46 #include <tuple>
48 #include "nblib/exception.h"
49 #include "nblib/molecules.h"
50 #include "nblib/particletype.h"
51 #include "nblib/util/internal.h"
53 namespace nblib
57 Molecule::Molecule(MoleculeName moleculeName) : name_(std::move(moleculeName)) {}
59 MoleculeName Molecule::name() const
61 return name_;
64 Molecule& Molecule::addParticle(const ParticleName& particleName,
65 const ResidueName& residueName,
66 const Charge& charge,
67 ParticleType const& particleType)
69 auto found = particleTypes_.find(particleType.name());
70 if (found == particleTypes_.end())
72 particleTypes_.insert(std::make_pair(particleType.name(), particleType));
74 else
76 if (!(found->second == particleType))
78 throw InputException(
79 "Differing ParticleTypes with identical names encountered in the same "
80 "molecule.");
84 particles_.emplace_back(ParticleData{ particleName, residueName, particleType.name(), charge });
86 // Add self exclusion. We just added the particle, so we know its index and that the exclusion doesn't exist yet
87 std::size_t id = particles_.size() - 1;
88 exclusions_.emplace_back(id, id);
90 return *this;
93 Molecule& Molecule::addParticle(const ParticleName& particleName,
94 const ResidueName& residueName,
95 ParticleType const& particleType)
97 addParticle(particleName, residueName, Charge(0), particleType);
99 return *this;
102 Molecule& Molecule::addParticle(const ParticleName& particleName,
103 const Charge& charge,
104 ParticleType const& particleType)
106 addParticle(particleName, ResidueName(name_), charge, particleType);
108 return *this;
111 Molecule& Molecule::addParticle(const ParticleName& particleName, const ParticleType& particleType)
113 addParticle(particleName, ResidueName(name_), Charge(0), particleType);
115 return *this;
118 int Molecule::numParticlesInMolecule() const
120 return particles_.size();
123 void Molecule::addExclusion(const int particleIndex, const int particleIndexToExclude)
125 // We do not need to add exclusion in case the particle indexes are the same
126 // because self exclusion are added by addParticle
127 if (particleIndex != particleIndexToExclude)
129 exclusions_.emplace_back(particleIndex, particleIndexToExclude);
130 exclusions_.emplace_back(particleIndexToExclude, particleIndex);
134 void Molecule::addExclusion(std::tuple<std::string, std::string> particle,
135 std::tuple<std::string, std::string> particleToExclude)
137 // duplication for the swapped pair happens in getExclusions()
138 exclusionsByName_.emplace_back(std::make_tuple(std::get<0>(particle), std::get<1>(particle),
139 std::get<0>(particleToExclude),
140 std::get<1>(particleToExclude)));
143 void Molecule::addExclusion(const std::string& particleName, const std::string& particleNameToExclude)
145 addExclusion(std::make_tuple(particleName, name_), std::make_tuple(particleNameToExclude, name_));
148 const ParticleType& Molecule::at(const std::string& particleTypeName) const
150 return particleTypes_.at(particleTypeName);
153 ParticleName Molecule::particleName(int i) const
155 return ParticleName(particles_[i].particleName_);
158 ResidueName Molecule::residueName(int i) const
160 return ResidueName(particles_[i].residueName_);
163 std::vector<std::tuple<int, int>> Molecule::getExclusions() const
165 // tuples of (particleName, residueName, index)
166 std::vector<std::tuple<std::string, std::string, int>> indexKey;
167 indexKey.reserve(numParticlesInMolecule());
169 for (int i = 0; i < numParticlesInMolecule(); ++i)
171 indexKey.emplace_back(particles_[i].particleName_, particles_[i].residueName_, i);
174 std::sort(std::begin(indexKey), std::end(indexKey));
176 std::vector<std::tuple<int, int>> ret = exclusions_;
177 ret.reserve(exclusions_.size() + exclusionsByName_.size());
179 // normal operator<, except ignore third element
180 auto sortKey = [](const auto& tup1, const auto& tup2) {
181 if (std::get<0>(tup1) < std::get<0>(tup2))
183 return true;
185 else
187 return std::get<1>(tup1) < std::get<1>(tup2);
191 // convert exclusions given by names to indices and append
192 for (auto& tup : exclusionsByName_)
194 const std::string& particleName1 = std::get<0>(tup);
195 const std::string& residueName1 = std::get<1>(tup);
196 const std::string& particleName2 = std::get<2>(tup);
197 const std::string& residueName2 = std::get<3>(tup);
199 // look up first index (binary search)
200 auto it1 = std::lower_bound(std::begin(indexKey), std::end(indexKey),
201 std::make_tuple(particleName1, residueName2, 0), sortKey);
203 // make sure we have the (particleName,residueName) combo
204 if (it1 == std::end(indexKey) or std::get<0>(*it1) != particleName1 or std::get<1>(*it1) != residueName1)
206 throw std::runtime_error(
207 (std::string("Particle ") += particleName1 + std::string(" in residue ") +=
208 residueName1 + std::string(" not found in list of particles\n")));
211 int firstIndex = std::get<2>(*it1);
213 // look up second index (binary search)
214 auto it2 = std::lower_bound(std::begin(indexKey), std::end(indexKey),
215 std::make_tuple(particleName2, residueName2, 0), sortKey);
217 // make sure we have the (particleName,residueName) combo
218 if (it2 == std::end(indexKey) or std::get<0>(*it2) != particleName2 or std::get<1>(*it2) != residueName2)
220 throw std::runtime_error(
221 (std::string("Particle ") += particleName2 + std::string(" in residue ") +=
222 residueName2 + std::string(" not found in list of particles\n")));
225 int secondIndex = std::get<2>(*it2);
227 ret.emplace_back(firstIndex, secondIndex);
228 ret.emplace_back(secondIndex, firstIndex);
231 std::sort(std::begin(ret), std::end(ret));
233 auto uniqueEnd = std::unique(std::begin(ret), std::end(ret));
234 if (uniqueEnd != std::end(ret))
236 printf("[nblib] Warning: exclusionList for molecule %s contained duplicates",
237 name_.value().c_str());
240 ret.erase(uniqueEnd, std::end(ret));
241 return ret;
244 std::unordered_map<std::string, ParticleType> Molecule::particleTypesMap() const
246 return particleTypes_;
249 std::vector<ParticleData> Molecule::particleData() const
251 return particles_;
254 } // namespace nblib