7e92cf676b9f9015e8375742cab7fbd852f8a3c6
[alexxy/gromacs.git] / src / gromacs / topology / atoms.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) 2013,2014,2015,2016,2017,2018, 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 "atoms.h"
40
41 #include <cstdio>
42 #include <cstring>
43
44 #include <algorithm>
45
46 #include "gromacs/topology/atomprop.h"
47 #include "gromacs/topology/symtab.h"
48 #include "gromacs/utility/compare.h"
49 #include "gromacs/utility/fatalerror.h"
50 #include "gromacs/utility/smalloc.h"
51 #include "gromacs/utility/txtdump.h"
52
53 const char *ptype_str[eptNR+1] = {
54     "Atom", "Nucleus", "Shell", "Bond", "VSite", nullptr
55 };
56
57 void init_atom(t_atoms *at)
58 {
59     at->nr          = 0;
60     at->nres        = 0;
61     at->atom        = nullptr;
62     at->resinfo     = nullptr;
63     at->atomname    = nullptr;
64     at->atomtype    = nullptr;
65     at->atomtypeB   = nullptr;
66     at->pdbinfo     = nullptr;
67     at->haveMass    = FALSE;
68     at->haveCharge  = FALSE;
69     at->haveType    = FALSE;
70     at->haveBState  = FALSE;
71     at->havePdbInfo = FALSE;
72 }
73
74 void init_atomtypes(t_atomtypes *at)
75 {
76     at->nr         = 0;
77     at->atomnumber = nullptr;
78 }
79
80 void done_atom(t_atoms *at)
81 {
82     sfree(at->atom);
83     sfree(at->resinfo);
84     sfree(at->atomname);
85     sfree(at->atomtype);
86     sfree(at->atomtypeB);
87     sfree(at->pdbinfo);
88     init_atom(at);
89 }
90
91 void done_and_delete_atoms(t_atoms *atoms)
92 {
93     done_atom(atoms);
94     delete atoms;
95 }
96
97 void done_atomtypes(t_atomtypes *atype)
98 {
99     atype->nr = 0;
100     sfree(atype->atomnumber);
101 }
102
103 void add_t_atoms(t_atoms *atoms, int natom_extra, int nres_extra)
104 {
105     int i;
106
107     if (natom_extra > 0)
108     {
109         srenew(atoms->atomname, atoms->nr+natom_extra);
110         srenew(atoms->atom, atoms->nr+natom_extra);
111         if (nullptr != atoms->pdbinfo)
112         {
113             srenew(atoms->pdbinfo, atoms->nr+natom_extra);
114         }
115         if (nullptr != atoms->atomtype)
116         {
117             srenew(atoms->atomtype, atoms->nr+natom_extra);
118         }
119         if (nullptr != atoms->atomtypeB)
120         {
121             srenew(atoms->atomtypeB, atoms->nr+natom_extra);
122         }
123         for (i = atoms->nr; (i < atoms->nr+natom_extra); i++)
124         {
125             atoms->atomname[i] = nullptr;
126             memset(&atoms->atom[i], 0, sizeof(atoms->atom[i]));
127             if (nullptr != atoms->pdbinfo)
128             {
129                 std::memset(&atoms->pdbinfo[i], 0, sizeof(atoms->pdbinfo[i]));
130             }
131             if (nullptr != atoms->atomtype)
132             {
133                 atoms->atomtype[i] = nullptr;
134             }
135             if (nullptr != atoms->atomtypeB)
136             {
137                 atoms->atomtypeB[i] = nullptr;
138             }
139         }
140         atoms->nr += natom_extra;
141     }
142     if (nres_extra > 0)
143     {
144         srenew(atoms->resinfo, atoms->nres+nres_extra);
145         for (i = atoms->nres; (i < atoms->nres+nres_extra); i++)
146         {
147             std::memset(&atoms->resinfo[i], 0, sizeof(atoms->resinfo[i]));
148         }
149         atoms->nres += nres_extra;
150     }
151 }
152
153 void init_t_atoms(t_atoms *atoms, int natoms, gmx_bool bPdbinfo)
154 {
155     atoms->nr   = natoms;
156     atoms->nres = 0;
157     snew(atoms->atomname, natoms);
158     atoms->atomtype  = nullptr;
159     atoms->atomtypeB = nullptr;
160     snew(atoms->resinfo, natoms);
161     snew(atoms->atom, natoms);
162     atoms->haveMass    = FALSE;
163     atoms->haveCharge  = FALSE;
164     atoms->haveType    = FALSE;
165     atoms->haveBState  = FALSE;
166     atoms->havePdbInfo = bPdbinfo;
167     if (atoms->havePdbInfo)
168     {
169         snew(atoms->pdbinfo, natoms);
170     }
171     else
172     {
173         atoms->pdbinfo = nullptr;
174     }
175 }
176
177 void gmx_pdbinfo_init_default(t_pdbinfo *pdbinfo)
178 {
179     pdbinfo->type         = epdbATOM;
180     pdbinfo->atomnr       = 0;
181     pdbinfo->altloc       = ' ';
182     pdbinfo->atomnm[0]    = '\0';
183     pdbinfo->occup        = 1.0;
184     pdbinfo->bfac         = 0.0;
185     pdbinfo->bAnisotropic = FALSE;
186     std::fill(pdbinfo->uij, pdbinfo->uij+6, 0.0);
187 }
188
189 t_atoms *copy_t_atoms(const t_atoms *src)
190 {
191     t_atoms *dst;
192     int      i;
193
194     snew(dst, 1);
195     init_t_atoms(dst, src->nr, (nullptr != src->pdbinfo));
196     dst->nr = src->nr;
197     if (nullptr != src->atomname)
198     {
199         snew(dst->atomname, src->nr);
200     }
201     if (nullptr != src->atomtype)
202     {
203         snew(dst->atomtype, src->nr);
204     }
205     if (nullptr != src->atomtypeB)
206     {
207         snew(dst->atomtypeB, src->nr);
208     }
209     for (i = 0; (i < src->nr); i++)
210     {
211         dst->atom[i] = src->atom[i];
212         if (nullptr != src->pdbinfo)
213         {
214             dst->pdbinfo[i] = src->pdbinfo[i];
215         }
216         if (nullptr != src->atomname)
217         {
218             dst->atomname[i]  = src->atomname[i];
219         }
220         if (nullptr != src->atomtype)
221         {
222             dst->atomtype[i] = src->atomtype[i];
223         }
224         if (nullptr != src->atomtypeB)
225         {
226             dst->atomtypeB[i] = src->atomtypeB[i];
227         }
228     }
229     dst->nres = src->nres;
230     for (i = 0; (i < src->nres); i++)
231     {
232         dst->resinfo[i] = src->resinfo[i];
233     }
234     return dst;
235 }
236
237 void t_atoms_set_resinfo(t_atoms *atoms, int atom_ind, t_symtab *symtab,
238                          const char *resname, int resnr, unsigned char ic,
239                          int chainnum, char chainid)
240 {
241     t_resinfo *ri;
242
243     ri           = &atoms->resinfo[atoms->atom[atom_ind].resind];
244     ri->name     = put_symtab(symtab, resname);
245     ri->rtp      = nullptr;
246     ri->nr       = resnr;
247     ri->ic       = ic;
248     ri->chainnum = chainnum;
249     ri->chainid  = chainid;
250 }
251
252 static void pr_atom(FILE *fp, int indent, const char *title, const t_atom *atom, int n)
253 {
254     int i;
255
256     if (available(fp, atom, indent, title))
257     {
258         indent = pr_title_n(fp, indent, title, n);
259         for (i = 0; i < n; i++)
260         {
261             pr_indent(fp, indent);
262             fprintf(fp, "%s[%6d]={type=%3hu, typeB=%3hu, ptype=%8s, m=%12.5e, "
263                     "q=%12.5e, mB=%12.5e, qB=%12.5e, resind=%5d, atomnumber=%3d}\n",
264                     title, i, atom[i].type, atom[i].typeB, ptype_str[atom[i].ptype],
265                     atom[i].m, atom[i].q, atom[i].mB, atom[i].qB,
266                     atom[i].resind, atom[i].atomnumber);
267         }
268     }
269 }
270
271 static void pr_strings2(FILE *fp, int indent, const char *title,
272                         char ***nm, char ***nmB, int n, gmx_bool bShowNumbers)
273 {
274     int i;
275
276     if (available(fp, nm, indent, title))
277     {
278         indent = pr_title_n(fp, indent, title, n);
279         for (i = 0; i < n; i++)
280         {
281             pr_indent(fp, indent);
282             fprintf(fp, "%s[%d]={name=\"%s\",nameB=\"%s\"}\n",
283                     title, bShowNumbers ? i : -1, *(nm[i]), *(nmB[i]));
284         }
285     }
286 }
287
288 static void pr_resinfo(FILE *fp, int indent, const char *title, const t_resinfo *resinfo, int n,
289                        gmx_bool bShowNumbers)
290 {
291     int i;
292
293     if (available(fp, resinfo, indent, title))
294     {
295         indent = pr_title_n(fp, indent, title, n);
296         for (i = 0; i < n; i++)
297         {
298             pr_indent(fp, indent);
299             fprintf(fp, "%s[%d]={name=\"%s\", nr=%d, ic='%c'}\n",
300                     title, bShowNumbers ? i : -1,
301                     *(resinfo[i].name), resinfo[i].nr,
302                     (resinfo[i].ic == '\0') ? ' ' : resinfo[i].ic);
303         }
304     }
305 }
306
307 void pr_atoms(FILE *fp, int indent, const char *title, const t_atoms *atoms,
308               gmx_bool bShownumbers)
309 {
310     if (available(fp, atoms, indent, title))
311     {
312         indent = pr_title(fp, indent, title);
313         pr_atom(fp, indent, "atom", atoms->atom, atoms->nr);
314         pr_strings(fp, indent, "atom", atoms->atomname, atoms->nr, bShownumbers);
315         pr_strings2(fp, indent, "type", atoms->atomtype, atoms->atomtypeB, atoms->nr, bShownumbers);
316         pr_resinfo(fp, indent, "residue", atoms->resinfo, atoms->nres, bShownumbers);
317     }
318 }
319
320
321 void pr_atomtypes(FILE *fp, int indent, const char *title, const t_atomtypes *atomtypes,
322                   gmx_bool bShowNumbers)
323 {
324     int i;
325     if (available(fp, atomtypes, indent, title))
326     {
327         indent = pr_title(fp, indent, title);
328         for (i = 0; i < atomtypes->nr; i++)
329         {
330             pr_indent(fp, indent);
331             fprintf(fp,
332                     "atomtype[%3d]={atomnumber=%4d}\n",
333                     bShowNumbers ? i : -1, atomtypes->atomnumber[i]);
334         }
335     }
336 }
337
338 static void cmp_atom(FILE *fp, int index, const t_atom *a1, const t_atom *a2, real ftol, real abstol)
339 {
340     if (a2)
341     {
342         cmp_us(fp, "atom.type", index, a1->type, a2->type);
343         cmp_us(fp, "atom.ptype", index, a1->ptype, a2->ptype);
344         cmp_int(fp, "atom.resind", index, a1->resind, a2->resind);
345         cmp_int(fp, "atom.atomnumber", index, a1->atomnumber, a2->atomnumber);
346         cmp_real(fp, "atom.m", index, a1->m, a2->m, ftol, abstol);
347         cmp_real(fp, "atom.q", index, a1->q, a2->q, ftol, abstol);
348         cmp_us(fp, "atom.typeB", index, a1->typeB, a2->typeB);
349         cmp_real(fp, "atom.mB", index, a1->mB, a2->mB, ftol, abstol);
350         cmp_real(fp, "atom.qB", index, a1->qB, a2->qB, ftol, abstol);
351     }
352     else
353     {
354         cmp_us(fp, "atom.type", index, a1->type, a1->typeB);
355         cmp_real(fp, "atom.m", index, a1->m, a1->mB, ftol, abstol);
356         cmp_real(fp, "atom.q", index, a1->q, a1->qB, ftol, abstol);
357     }
358 }
359
360 void cmp_atoms(FILE *fp, const t_atoms *a1, const t_atoms *a2, real ftol, real abstol)
361 {
362     int i;
363
364     fprintf(fp, "comparing atoms\n");
365
366     if (a2)
367     {
368         cmp_int(fp, "atoms->nr", -1, a1->nr, a2->nr);
369         for (i = 0; i < std::min(a1->nr, a2->nr); i++)
370         {
371             cmp_atom(fp, i, &(a1->atom[i]), &(a2->atom[i]), ftol, abstol);
372         }
373     }
374     else
375     {
376         for (i = 0; (i < a1->nr); i++)
377         {
378             cmp_atom(fp, i, &(a1->atom[i]), nullptr, ftol, abstol);
379         }
380     }
381 }
382
383 void atomsSetMassesBasedOnNames(t_atoms *atoms, gmx_bool printMissingMasses)
384 {
385     if (atoms->haveMass)
386     {
387         /* We could decide to anyhow assign then or generate a fatal error,
388          * but it's probably most useful to keep the masses we have.
389          */
390         return;
391     }
392
393     int            maxWarn  = (printMissingMasses ? 10 : 0);
394     int            numWarn  = 0;
395
396     gmx_atomprop_t aps      = gmx_atomprop_init();
397
398     gmx_bool       haveMass = TRUE;
399     for (int i = 0; i < atoms->nr; i++)
400     {
401         if (!gmx_atomprop_query(aps, epropMass,
402                                 *atoms->resinfo[atoms->atom[i].resind].name,
403                                 *atoms->atomname[i],
404                                 &atoms->atom[i].m))
405         {
406             haveMass = FALSE;
407
408             if (numWarn < maxWarn)
409             {
410                 fprintf(stderr, "Can not find mass in database for atom %s in residue %d %s\n",
411                         *atoms->atomname[i],
412                         atoms->resinfo[atoms->atom[i].resind].nr,
413                         *atoms->resinfo[atoms->atom[i].resind].name);
414                 numWarn++;
415             }
416             else
417             {
418                 break;
419             }
420         }
421     }
422     atoms->haveMass = haveMass;
423
424     gmx_atomprop_destroy(aps);
425 }