4d7f7711889d7a0bea54c45df11d0f5cee0cd302
[alexxy/gromacs.git] / src / gromacs / topology / atomsbuilder.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2014,2015,2016, 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  * Implements classes from atomsbuilder.h.
38  *
39  * \author Teemu Murtola <teemu.murtola@gmail.com>
40  */
41 #include "gmxpre.h"
42
43 #include "atomsbuilder.h"
44
45 #include <algorithm>
46
47 #include "gromacs/math/vec.h"
48 #include "gromacs/topology/atoms.h"
49 #include "gromacs/topology/symtab.h"
50 #include "gromacs/utility/gmxassert.h"
51 #include "gromacs/utility/smalloc.h"
52
53 namespace gmx
54 {
55
56 /********************************************************************
57  * AtomsBuilder
58  */
59
60 AtomsBuilder::AtomsBuilder(t_atoms *atoms, t_symtab *symtab)
61     : atoms_(atoms), symtab_(symtab),
62       nrAlloc_(atoms->nr), nresAlloc_(atoms->nres),
63       currentResidueIndex_(atoms->nres), nextResidueNumber_(-1)
64 {
65     if (atoms->nres > 0)
66     {
67         nextResidueNumber_ = atoms->resinfo[atoms->nres - 1].nr + 1;
68     }
69 }
70
71 AtomsBuilder::~AtomsBuilder()
72 {
73 }
74
75 char **AtomsBuilder::symtabString(char **source)
76 {
77     if (symtab_ != NULL)
78     {
79         return put_symtab(symtab_, *source);
80     }
81     return source;
82 }
83
84 void AtomsBuilder::reserve(int atomCount, int residueCount)
85 {
86     srenew(atoms_->atom,     atomCount);
87     srenew(atoms_->atomname, atomCount);
88     srenew(atoms_->resinfo,  residueCount);
89     if (atoms_->pdbinfo != nullptr)
90     {
91         srenew(atoms_->pdbinfo, atomCount);
92     }
93     nrAlloc_   = atomCount;
94     nresAlloc_ = residueCount;
95 }
96
97 void AtomsBuilder::clearAtoms()
98 {
99     atoms_->nr           = 0;
100     atoms_->nres         = 0;
101     currentResidueIndex_ = 0;
102     nextResidueNumber_   = -1;
103 }
104
105 int AtomsBuilder::currentAtomCount() const
106 {
107     return atoms_->nr;
108 }
109
110 void AtomsBuilder::setNextResidueNumber(int number)
111 {
112     nextResidueNumber_ = number;
113 }
114
115 void AtomsBuilder::addAtom(const t_atoms &atoms, int i)
116 {
117     const int index = atoms_->nr;
118     atoms_->atom[index]        = atoms.atom[i];
119     atoms_->atomname[index]    = symtabString(atoms.atomname[i]);
120     atoms_->atom[index].resind = currentResidueIndex_;
121     if (atoms_->pdbinfo != nullptr)
122     {
123         if (atoms.pdbinfo != nullptr)
124         {
125             atoms_->pdbinfo[index]  = atoms.pdbinfo[i];
126         }
127         else
128         {
129             gmx_pdbinfo_init_default(&atoms_->pdbinfo[index]);
130         }
131     }
132     ++atoms_->nr;
133 }
134
135 void AtomsBuilder::startResidue(const t_resinfo &resinfo)
136 {
137     if (nextResidueNumber_ == -1)
138     {
139         nextResidueNumber_ = resinfo.nr;
140     }
141     const int index = atoms_->nres;
142     atoms_->resinfo[index]      = resinfo;
143     atoms_->resinfo[index].nr   = nextResidueNumber_;
144     atoms_->resinfo[index].name = symtabString(resinfo.name);
145     ++nextResidueNumber_;
146     currentResidueIndex_      = index;
147     ++atoms_->nres;
148 }
149
150 void AtomsBuilder::finishResidue(const t_resinfo &resinfo)
151 {
152     if (nextResidueNumber_ == -1)
153     {
154         nextResidueNumber_ = resinfo.nr;
155     }
156     const int index = currentResidueIndex_;
157     atoms_->resinfo[index]      = resinfo;
158     atoms_->resinfo[index].nr   = nextResidueNumber_;
159     atoms_->resinfo[index].name = symtabString(resinfo.name);
160     ++nextResidueNumber_;
161     currentResidueIndex_      = index + 1;
162     if (index >= atoms_->nres)
163     {
164         ++atoms_->nres;
165     }
166 }
167
168 void AtomsBuilder::discardCurrentResidue()
169 {
170     int index = atoms_->nr - 1;
171     while (index > 0 && atoms_->atom[index - 1].resind == currentResidueIndex_)
172     {
173         --index;
174     }
175     atoms_->nr   = index;
176     atoms_->nres = currentResidueIndex_;
177 }
178
179 void AtomsBuilder::mergeAtoms(const t_atoms &atoms)
180 {
181     if (atoms_->nr + atoms.nr > nrAlloc_
182         || atoms_->nres + atoms.nres > nresAlloc_)
183     {
184         reserve(atoms_->nr + atoms.nr, atoms_->nres + atoms.nres);
185     }
186     int prevResInd = -1;
187     for (int i = 0; i < atoms.nr; ++i)
188     {
189         const int resind = atoms.atom[i].resind;
190         if (resind != prevResInd)
191         {
192             startResidue(atoms.resinfo[resind]);
193             prevResInd = resind;
194         }
195         addAtom(atoms, i);
196     }
197 }
198
199 /********************************************************************
200  * AtomsRemover
201  */
202
203 AtomsRemover::AtomsRemover(const t_atoms &atoms)
204     : removed_(atoms.nr, 0)
205 {
206 }
207
208 AtomsRemover::~AtomsRemover()
209 {
210 }
211
212 void AtomsRemover::refreshAtomCount(const t_atoms &atoms)
213 {
214     removed_.resize(atoms.nr, 0);
215 }
216
217 void AtomsRemover::markAll()
218 {
219     std::fill(removed_.begin(), removed_.end(), 1);
220 }
221
222 void AtomsRemover::markResidue(const t_atoms &atoms, int atomIndex, bool bStatus)
223 {
224     const int resind = atoms.atom[atomIndex].resind;
225     while (atomIndex > 0 && resind == atoms.atom[atomIndex - 1].resind)
226     {
227         --atomIndex;
228     }
229     while (atomIndex < atoms.nr && resind == atoms.atom[atomIndex].resind)
230     {
231         removed_[atomIndex] = (bStatus ? 1 : 0);
232         ++atomIndex;
233     }
234 }
235
236 void AtomsRemover::removeMarkedElements(std::vector<RVec> *container) const
237 {
238     GMX_RELEASE_ASSERT(container->size() == removed_.size(),
239                        "Mismatching contained passed for removing values");
240     int j = 0;
241     for (size_t i = 0; i < removed_.size(); ++i)
242     {
243         if (!removed_[i])
244         {
245             (*container)[j] = (*container)[i];
246             ++j;
247         }
248     }
249     container->resize(j);
250 }
251
252 void AtomsRemover::removeMarkedElements(std::vector<real> *container) const
253 {
254     GMX_RELEASE_ASSERT(container->size() == removed_.size(),
255                        "Mismatching contained passed for removing values");
256     int j = 0;
257     for (size_t i = 0; i < removed_.size(); ++i)
258     {
259         if (!removed_[i])
260         {
261             (*container)[j] = (*container)[i];
262             ++j;
263         }
264     }
265     container->resize(j);
266 }
267
268 void AtomsRemover::removeMarkedAtoms(t_atoms *atoms) const
269 {
270     const int    originalAtomCount = atoms->nr;
271     AtomsBuilder builder(atoms, NULL);
272     if (atoms->nr > 0)
273     {
274         builder.setNextResidueNumber(atoms->resinfo[0].nr);
275     }
276     builder.clearAtoms();
277     int          prevResInd = -1;
278     for (int i = 0; i < originalAtomCount; ++i)
279     {
280         if (!removed_[i])
281         {
282             const int resind = atoms->atom[i].resind;
283             if (resind != prevResInd)
284             {
285                 builder.startResidue(atoms->resinfo[resind]);
286                 prevResInd = resind;
287             }
288             builder.addAtom(*atoms, i);
289         }
290     }
291 }
292
293 } // namespace gmx