d5b65c5c35b460d33846ab10accbe64acb13482a
[alexxy/gromacs.git] / src / gromacs / gmxpreprocess / gpp_atomtype.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5  * Copyright (c) 2001-2004, The GROMACS development team.
6  * Copyright (c) 2011,2014,2015,2017,2018,2019, by the GROMACS development team, led by
7  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8  * and including many others, as listed in the AUTHORS file in the
9  * top-level source directory and at http://www.gromacs.org.
10  *
11  * GROMACS is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public License
13  * as published by the Free Software Foundation; either version 2.1
14  * of the License, or (at your option) any later version.
15  *
16  * GROMACS is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with GROMACS; if not, see
23  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
25  *
26  * If you want to redistribute modifications to GROMACS, please
27  * consider that scientific software is very special. Version
28  * control is crucial - bugs must be traceable. We will be happy to
29  * consider code for inclusion in the official distribution, but
30  * derived work must not be called official GROMACS. Details are found
31  * in the README & COPYING files - if they are missing, get the
32  * official version at http://www.gromacs.org.
33  *
34  * To help us fund GROMACS development, we humbly ask that you cite
35  * the research papers on the package. Check out http://www.gromacs.org.
36  */
37 #include "gmxpre.h"
38
39 #include "gpp_atomtype.h"
40
41 #include <climits>
42 #include <cmath>
43 #include <cstring>
44
45 #include <algorithm>
46
47 #include "gromacs/gmxpreprocess/grompp_impl.h"
48 #include "gromacs/gmxpreprocess/notset.h"
49 #include "gromacs/gmxpreprocess/topdirs.h"
50 #include "gromacs/gmxpreprocess/toputil.h"
51 #include "gromacs/math/vecdump.h"
52 #include "gromacs/topology/ifunc.h"
53 #include "gromacs/topology/symtab.h"
54 #include "gromacs/topology/topology.h"
55 #include "gromacs/utility/fatalerror.h"
56 #include "gromacs/utility/smalloc.h"
57
58 struct AtomTypeData
59 {
60     //! Explicit constructor.
61     AtomTypeData(const t_atom& a, char** name, const InteractionOfType& nb, const int bondAtomType, const int atomNumber) :
62         atom_(a),
63         name_(name),
64         nb_(nb),
65         bondAtomType_(bondAtomType),
66         atomNumber_(atomNumber)
67     {
68     }
69     //! Actual atom data.
70     t_atom atom_;
71     //! Atom name.
72     char** name_;
73     //! Nonbonded data.
74     InteractionOfType nb_;
75     //! Bonded atomtype for the type.
76     int bondAtomType_;
77     //! Atom number for the atom type.
78     int atomNumber_;
79 };
80
81 class PreprocessingAtomTypes::Impl
82 {
83 public:
84     //! The number for currently loaded entries.
85     size_t size() const { return types.size(); }
86     //! The actual atom type data.
87     std::vector<AtomTypeData> types;
88 };
89
90 bool PreprocessingAtomTypes::isSet(int nt) const
91 {
92     return ((nt >= 0) && (nt < gmx::ssize(*this)));
93 }
94
95 int PreprocessingAtomTypes::atomTypeFromName(const std::string& str) const
96 {
97     /* Atom types are always case sensitive */
98     auto found = std::find_if(impl_->types.begin(), impl_->types.end(),
99                               [&str](const auto& type) { return str == *type.name_; });
100     if (found == impl_->types.end())
101     {
102         return NOTSET;
103     }
104     else
105     {
106         return std::distance(impl_->types.begin(), found);
107     }
108 }
109
110 size_t PreprocessingAtomTypes::size() const
111 {
112     return impl_->size();
113 }
114
115 const char* PreprocessingAtomTypes::atomNameFromAtomType(int nt) const
116 {
117     return isSet(nt) ? *(impl_->types[nt].name_) : nullptr;
118 }
119
120 real PreprocessingAtomTypes::atomMassFromAtomType(int nt) const
121 {
122     return isSet(nt) ? impl_->types[nt].atom_.m : NOTSET;
123 }
124
125 real PreprocessingAtomTypes::atomChargeFromAtomType(int nt) const
126 {
127     return isSet(nt) ? impl_->types[nt].atom_.q : NOTSET;
128 }
129
130 int PreprocessingAtomTypes::atomParticleTypeFromAtomType(int nt) const
131 {
132     return isSet(nt) ? impl_->types[nt].atom_.ptype : NOTSET;
133 }
134
135 int PreprocessingAtomTypes::bondAtomTypeFromAtomType(int nt) const
136 {
137     return isSet(nt) ? impl_->types[nt].bondAtomType_ : NOTSET;
138 }
139
140 int PreprocessingAtomTypes::atomNumberFromAtomType(int nt) const
141 {
142     return isSet(nt) ? impl_->types[nt].atomNumber_ : NOTSET;
143 }
144
145 real PreprocessingAtomTypes::atomNonBondedParamFromAtomType(int nt, int param) const
146 {
147     if (!isSet(nt))
148     {
149         return NOTSET;
150     }
151     gmx::ArrayRef<const real> forceParam = impl_->types[nt].nb_.forceParam();
152     if ((param < 0) || (param >= MAXFORCEPARAM))
153     {
154         return NOTSET;
155     }
156     return forceParam[param];
157 }
158
159 PreprocessingAtomTypes::PreprocessingAtomTypes() : impl_(new Impl) {}
160
161 PreprocessingAtomTypes::PreprocessingAtomTypes(PreprocessingAtomTypes&& old) noexcept :
162     impl_(std::move(old.impl_))
163 {
164 }
165
166 PreprocessingAtomTypes& PreprocessingAtomTypes::operator=(PreprocessingAtomTypes&& old) noexcept
167 {
168     impl_ = std::move(old.impl_);
169     return *this;
170 }
171
172 PreprocessingAtomTypes::~PreprocessingAtomTypes() {}
173
174 int PreprocessingAtomTypes::addType(t_symtab*                tab,
175                                     const t_atom&            a,
176                                     const std::string&       name,
177                                     const InteractionOfType& nb,
178                                     int                      bondAtomType,
179                                     int                      atomNumber)
180 {
181     int position = atomTypeFromName(name);
182     if (position == NOTSET)
183     {
184         impl_->types.emplace_back(a, put_symtab(tab, name.c_str()), nb, bondAtomType, atomNumber);
185         return atomTypeFromName(name);
186     }
187     else
188     {
189         return position;
190     }
191 }
192
193 int PreprocessingAtomTypes::setType(int                      nt,
194                                     t_symtab*                tab,
195                                     const t_atom&            a,
196                                     const std::string&       name,
197                                     const InteractionOfType& nb,
198                                     int                      bondAtomType,
199                                     int                      atomNumber)
200 {
201     if (!isSet(nt))
202     {
203         return NOTSET;
204     }
205
206     impl_->types[nt].atom_         = a;
207     impl_->types[nt].name_         = put_symtab(tab, name.c_str());
208     impl_->types[nt].nb_           = nb;
209     impl_->types[nt].bondAtomType_ = bondAtomType;
210     impl_->types[nt].atomNumber_   = atomNumber;
211
212     return nt;
213 }
214
215 void PreprocessingAtomTypes::printTypes(FILE* out)
216 {
217     fprintf(out, "[ %s ]\n", dir2str(Directive::d_atomtypes));
218     fprintf(out, "; %6s  %8s  %8s  %8s  %12s  %12s\n", "type", "mass", "charge", "particle", "c6",
219             "c12");
220     for (auto& entry : impl_->types)
221     {
222         fprintf(out, "%8s  %8.3f  %8.3f  %8s  %12e  %12e\n", *(entry.name_), entry.atom_.m,
223                 entry.atom_.q, "A", entry.nb_.c0(), entry.nb_.c1());
224     }
225
226     fprintf(out, "\n");
227 }
228
229 static int search_atomtypes(const PreprocessingAtomTypes*          ga,
230                             int*                                   n,
231                             gmx::ArrayRef<int>                     typelist,
232                             int                                    thistype,
233                             gmx::ArrayRef<const InteractionOfType> interactionTypes,
234                             int                                    ftype)
235 {
236     int nn    = *n;
237     int nrfp  = NRFP(ftype);
238     int ntype = ga->size();
239
240     int i;
241     for (i = 0; (i < nn); i++)
242     {
243         if (typelist[i] == thistype)
244         {
245             /* This type number has already been added */
246             break;
247         }
248
249         /* Otherwise, check if the parameters are identical to any previously added type */
250
251         bool bFound = true;
252         for (int j = 0; j < ntype && bFound; j++)
253         {
254             /* Check nonbonded parameters */
255             gmx::ArrayRef<const real> forceParam1 =
256                     interactionTypes[ntype * typelist[i] + j].forceParam();
257             gmx::ArrayRef<const real> forceParam2 = interactionTypes[ntype * thistype + j].forceParam();
258             for (int k = 0; (k < nrfp) && bFound; k++)
259             {
260                 bFound = forceParam1[k] == forceParam2[k];
261             }
262
263             /* Check atomnumber */
264             int tli = typelist[i];
265             bFound = bFound && (ga->atomNumberFromAtomType(tli) == ga->atomNumberFromAtomType(thistype));
266         }
267         if (bFound)
268         {
269             break;
270         }
271     }
272
273     if (i == nn)
274     {
275         if (nn == ntype)
276         {
277             gmx_fatal(FARGS, "Atomtype horror n = %d, %s, %d", nn, __FILE__, __LINE__);
278         }
279         typelist[nn] = thistype;
280         nn++;
281     }
282     *n = nn;
283
284     return i;
285 }
286
287 void PreprocessingAtomTypes::renumberTypes(gmx::ArrayRef<InteractionsOfType> plist,
288                                            gmx_mtop_t*                       mtop,
289                                            int*                              wall_atomtype,
290                                            bool                              bVerbose)
291 {
292     int nat, ftype, ntype;
293
294     ntype = size();
295     std::vector<int> typelist(ntype);
296
297     if (bVerbose)
298     {
299         fprintf(stderr, "renumbering atomtypes...\n");
300     }
301
302     /* Since the bonded interactions have been assigned now,
303      * we want to reduce the number of atom types by merging
304      * ones with identical nonbonded interactions, in addition
305      * to removing unused ones.
306      *
307      * With QM/MM we also check that the atom numbers match
308      */
309
310     /* Get nonbonded interaction type */
311     if (plist[F_LJ].size() > 0)
312     {
313         ftype = F_LJ;
314     }
315     else
316     {
317         ftype = F_BHAM;
318     }
319
320     /* Renumber atomtypes by first making a list of which ones are actually used.
321      * We provide the list of nonbonded parameters so search_atomtypes
322      * can determine if two types should be merged.
323      */
324     nat = 0;
325     for (const gmx_moltype_t& moltype : mtop->moltype)
326     {
327         const t_atoms* atoms = &moltype.atoms;
328         for (int i = 0; (i < atoms->nr); i++)
329         {
330             atoms->atom[i].type  = search_atomtypes(this, &nat, typelist, atoms->atom[i].type,
331                                                    plist[ftype].interactionTypes, ftype);
332             atoms->atom[i].typeB = search_atomtypes(this, &nat, typelist, atoms->atom[i].typeB,
333                                                     plist[ftype].interactionTypes, ftype);
334         }
335     }
336
337     for (int i = 0; i < 2; i++)
338     {
339         if (wall_atomtype[i] >= 0)
340         {
341             wall_atomtype[i] = search_atomtypes(this, &nat, typelist, wall_atomtype[i],
342                                                 plist[ftype].interactionTypes, ftype);
343         }
344     }
345
346     std::vector<AtomTypeData> new_types;
347     /* We now have a list of unique atomtypes in typelist */
348
349     /* Renumber nlist */
350     std::vector<InteractionOfType> nbsnew;
351
352     for (int i = 0; (i < nat); i++)
353     {
354         int mi = typelist[i];
355         for (int j = 0; (j < nat); j++)
356         {
357             int                      mj              = typelist[j];
358             const InteractionOfType& interactionType = plist[ftype].interactionTypes[ntype * mi + mj];
359             nbsnew.emplace_back(interactionType.atoms(), interactionType.forceParam(),
360                                 interactionType.interactionTypeName());
361         }
362         new_types.push_back(impl_->types[mi]);
363     }
364
365     mtop->ffparams.atnr = nat;
366
367     impl_->types                  = new_types;
368     plist[ftype].interactionTypes = nbsnew;
369 }
370
371 void PreprocessingAtomTypes::copyTot_atomtypes(t_atomtypes* atomtypes) const
372 {
373     /* Copy the atomtype data to the topology atomtype list */
374     int ntype     = size();
375     atomtypes->nr = ntype;
376     snew(atomtypes->atomnumber, ntype);
377
378     for (int i = 0; i < ntype; i++)
379     {
380         atomtypes->atomnumber[i] = impl_->types[i].atomNumber_;
381     }
382 }