Refactor SD update
[gromacs.git] / src / gromacs / fileio / pdbio.cpp
blobd6c7579199759b7517429e5fca7df086e2a1d568
1 /*
2 * This file is part of the GROMACS molecular simulation package.
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, 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.
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.
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.
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.
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.
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.
37 #include "gmxpre.h"
39 #include "pdbio.h"
41 #include <cctype>
42 #include <cmath>
43 #include <cstdlib>
44 #include <cstring>
46 #include <string>
48 #include "gromacs/fileio/gmxfio.h"
49 #include "gromacs/math/units.h"
50 #include "gromacs/math/vec.h"
51 #include "gromacs/pbcutil/pbc.h"
52 #include "gromacs/topology/atomprop.h"
53 #include "gromacs/topology/ifunc.h"
54 #include "gromacs/topology/residuetypes.h"
55 #include "gromacs/topology/symtab.h"
56 #include "gromacs/topology/topology.h"
57 #include "gromacs/utility/coolstuff.h"
58 #include "gromacs/utility/cstringutil.h"
59 #include "gromacs/utility/fatalerror.h"
60 #include "gromacs/utility/futil.h"
61 #include "gromacs/utility/smalloc.h"
62 #include "gromacs/utility/snprintf.h"
64 typedef struct {
65 int ai, aj;
66 } gmx_conection_t;
68 typedef struct gmx_conect_t {
69 int nconect;
70 gmx_bool bSorted;
71 gmx_conection_t *conect;
72 } gmx_conect_t;
74 static const char *pdbtp[epdbNR] = {
75 "ATOM ", "HETATM", "ANISOU", "CRYST1",
76 "COMPND", "MODEL", "ENDMDL", "TER", "HEADER", "TITLE", "REMARK",
77 "CONECT"
81 #define REMARK_SIM_BOX "REMARK THIS IS A SIMULATION BOX"
83 static void xlate_atomname_pdb2gmx(char *name)
85 int i, length;
86 char temp;
88 length = std::strlen(name);
89 if (length > 3 && std::isdigit(name[0]))
91 temp = name[0];
92 for (i = 1; i < length; i++)
94 name[i-1] = name[i];
96 name[length-1] = temp;
100 static void xlate_atomname_gmx2pdb(char *name)
102 int i, length;
103 char temp;
105 length = std::strlen(name);
106 if (length > 3 && std::isdigit(name[length-1]))
108 temp = name[length-1];
109 for (i = length-1; i > 0; --i)
111 name[i] = name[i-1];
113 name[0] = temp;
118 void gmx_write_pdb_box(FILE *out, int ePBC, const matrix box)
120 real alpha, beta, gamma;
122 if (ePBC == -1)
124 ePBC = guess_ePBC(box);
127 if (ePBC == epbcNONE)
129 return;
132 if (norm2(box[YY])*norm2(box[ZZ]) != 0)
134 alpha = RAD2DEG*gmx_angle(box[YY], box[ZZ]);
136 else
138 alpha = 90;
140 if (norm2(box[XX])*norm2(box[ZZ]) != 0)
142 beta = RAD2DEG*gmx_angle(box[XX], box[ZZ]);
144 else
146 beta = 90;
148 if (norm2(box[XX])*norm2(box[YY]) != 0)
150 gamma = RAD2DEG*gmx_angle(box[XX], box[YY]);
152 else
154 gamma = 90;
156 fprintf(out, "REMARK THIS IS A SIMULATION BOX\n");
157 if (ePBC != epbcSCREW)
159 fprintf(out, "CRYST1%9.3f%9.3f%9.3f%7.2f%7.2f%7.2f %-11s%4d\n",
160 10*norm(box[XX]), 10*norm(box[YY]), 10*norm(box[ZZ]),
161 alpha, beta, gamma, "P 1", 1);
163 else
165 /* Double the a-vector length and write the correct space group */
166 fprintf(out, "CRYST1%9.3f%9.3f%9.3f%7.2f%7.2f%7.2f %-11s%4d\n",
167 20*norm(box[XX]), 10*norm(box[YY]), 10*norm(box[ZZ]),
168 alpha, beta, gamma, "P 21 1 1", 1);
173 static void read_cryst1(char *line, int *ePBC, matrix box)
175 #define SG_SIZE 11
176 char sa[12], sb[12], sc[12], sg[SG_SIZE+1], ident;
177 double fa, fb, fc, alpha, beta, gamma, cosa, cosb, cosg, sing;
178 int syma, symb, symc;
179 int ePBC_file;
181 sscanf(line, "%*s%s%s%s%lf%lf%lf", sa, sb, sc, &alpha, &beta, &gamma);
183 ePBC_file = -1;
184 if (strlen(line) >= 55)
186 strncpy(sg, line+55, SG_SIZE);
187 sg[SG_SIZE] = '\0';
188 ident = ' ';
189 syma = 0;
190 symb = 0;
191 symc = 0;
192 sscanf(sg, "%c %d %d %d", &ident, &syma, &symb, &symc);
193 if (ident == 'P' && syma == 1 && symb <= 1 && symc <= 1)
195 fc = strtod(sc, nullptr)*0.1;
196 ePBC_file = (fc > 0 ? epbcXYZ : epbcXY);
198 if (ident == 'P' && syma == 21 && symb == 1 && symc == 1)
200 ePBC_file = epbcSCREW;
203 if (ePBC)
205 *ePBC = ePBC_file;
208 if (box)
210 fa = strtod(sa, nullptr)*0.1;
211 fb = strtod(sb, nullptr)*0.1;
212 fc = strtod(sc, nullptr)*0.1;
213 if (ePBC_file == epbcSCREW)
215 fa *= 0.5;
217 clear_mat(box);
218 box[XX][XX] = fa;
219 if ((alpha != 90.0) || (beta != 90.0) || (gamma != 90.0))
221 if (alpha != 90.0)
223 cosa = std::cos(alpha*DEG2RAD);
225 else
227 cosa = 0;
229 if (beta != 90.0)
231 cosb = std::cos(beta*DEG2RAD);
233 else
235 cosb = 0;
237 if (gamma != 90.0)
239 cosg = std::cos(gamma*DEG2RAD);
240 sing = std::sin(gamma*DEG2RAD);
242 else
244 cosg = 0;
245 sing = 1;
247 box[YY][XX] = fb*cosg;
248 box[YY][YY] = fb*sing;
249 box[ZZ][XX] = fc*cosb;
250 box[ZZ][YY] = fc*(cosa - cosb*cosg)/sing;
251 box[ZZ][ZZ] = std::sqrt(fc*fc
252 - box[ZZ][XX]*box[ZZ][XX] - box[ZZ][YY]*box[ZZ][YY]);
254 else
256 box[YY][YY] = fb;
257 box[ZZ][ZZ] = fc;
262 void write_pdbfile_indexed(FILE *out, const char *title,
263 const t_atoms *atoms, const rvec x[],
264 int ePBC, const matrix box, char chainid,
265 int model_nr, int nindex, const int index[],
266 gmx_conect conect, gmx_bool bTerSepChains)
268 gmx_conect_t *gc = (gmx_conect_t *)conect;
269 char resnm[6], nm[6];
270 int i, ii;
271 int resind, resnr;
272 enum PDB_record type;
273 unsigned char resic, ch;
274 char altloc;
275 real occup, bfac;
276 gmx_bool bOccup;
277 int chainnum, lastchainnum;
278 gmx_residuetype_t*rt;
279 const char *p_restype;
280 const char *p_lastrestype;
282 gmx_residuetype_init(&rt);
284 fprintf(out, "TITLE %s\n", (title && title[0]) ? title : gmx::bromacs().c_str());
285 if (box && ( norm2(box[XX]) || norm2(box[YY]) || norm2(box[ZZ]) ) )
287 gmx_write_pdb_box(out, ePBC, box);
289 if (atoms->havePdbInfo)
291 /* Check whether any occupancies are set, in that case leave it as is,
292 * otherwise set them all to one
294 bOccup = TRUE;
295 for (ii = 0; (ii < nindex) && bOccup; ii++)
297 i = index[ii];
298 bOccup = bOccup && (atoms->pdbinfo[i].occup == 0.0);
301 else
303 bOccup = FALSE;
306 fprintf(out, "MODEL %8d\n", model_nr > 0 ? model_nr : 1);
308 lastchainnum = -1;
309 p_restype = nullptr;
311 for (ii = 0; ii < nindex; ii++)
313 i = index[ii];
314 resind = atoms->atom[i].resind;
315 chainnum = atoms->resinfo[resind].chainnum;
316 p_lastrestype = p_restype;
317 gmx_residuetype_get_type(rt, *atoms->resinfo[resind].name, &p_restype);
319 /* Add a TER record if we changed chain, and if either the previous or this chain is protein/DNA/RNA. */
320 if (bTerSepChains && ii > 0 && chainnum != lastchainnum)
322 /* Only add TER if the previous chain contained protein/DNA/RNA. */
323 if (gmx_residuetype_is_protein(rt, p_lastrestype) || gmx_residuetype_is_dna(rt, p_lastrestype) || gmx_residuetype_is_rna(rt, p_lastrestype))
325 fprintf(out, "TER\n");
327 lastchainnum = chainnum;
330 strncpy(resnm, *atoms->resinfo[resind].name, sizeof(resnm)-1);
331 resnm[sizeof(resnm)-1] = 0;
332 strncpy(nm, *atoms->atomname[i], sizeof(nm)-1);
333 nm[sizeof(nm)-1] = 0;
335 /* rename HG12 to 2HG1, etc. */
336 xlate_atomname_gmx2pdb(nm);
337 resnr = atoms->resinfo[resind].nr;
338 resic = atoms->resinfo[resind].ic;
339 if (chainid != ' ')
341 ch = chainid;
343 else
345 ch = atoms->resinfo[resind].chainid;
347 if (ch == 0)
349 ch = ' ';
352 if (resnr >= 10000)
354 resnr = resnr % 10000;
356 t_pdbinfo pdbinfo;
357 if (atoms->pdbinfo != nullptr)
359 pdbinfo = atoms->pdbinfo[i];
361 else
363 gmx_pdbinfo_init_default(&pdbinfo);
365 type = static_cast<enum PDB_record>(pdbinfo.type);
366 altloc = pdbinfo.altloc;
367 if (!isalnum(altloc))
369 altloc = ' ';
371 occup = bOccup ? 1.0 : pdbinfo.occup;
372 bfac = pdbinfo.bfac;
374 gmx_fprintf_pdb_atomline(out,
375 type,
376 i+1,
378 altloc,
379 resnm,
381 resnr,
382 resic,
383 10*x[i][XX], 10*x[i][YY], 10*x[i][ZZ],
384 occup,
385 bfac,
386 atoms->atom[i].elem);
388 if (atoms->pdbinfo && atoms->pdbinfo[i].bAnisotropic)
390 fprintf(out, "ANISOU%5d %-4.4s%4.4s%c%4d%c %7d%7d%7d%7d%7d%7d\n",
391 (i+1)%100000, nm, resnm, ch, resnr,
392 (resic == '\0') ? ' ' : resic,
393 atoms->pdbinfo[i].uij[0], atoms->pdbinfo[i].uij[1],
394 atoms->pdbinfo[i].uij[2], atoms->pdbinfo[i].uij[3],
395 atoms->pdbinfo[i].uij[4], atoms->pdbinfo[i].uij[5]);
399 fprintf(out, "TER\n");
400 fprintf(out, "ENDMDL\n");
402 if (nullptr != gc)
404 /* Write conect records */
405 for (i = 0; (i < gc->nconect); i++)
407 fprintf(out, "CONECT%5d%5d\n", gc->conect[i].ai+1, gc->conect[i].aj+1);
411 gmx_residuetype_destroy(rt);
414 void write_pdbfile(FILE *out, const char *title, const t_atoms *atoms, const rvec x[],
415 int ePBC, const matrix box, char chainid, int model_nr, gmx_conect conect, gmx_bool bTerSepChains)
417 int i, *index;
419 snew(index, atoms->nr);
420 for (i = 0; i < atoms->nr; i++)
422 index[i] = i;
424 write_pdbfile_indexed(out, title, atoms, x, ePBC, box, chainid, model_nr,
425 atoms->nr, index, conect, bTerSepChains);
426 sfree(index);
429 static int line2type(char *line)
431 int k;
432 char type[8];
434 for (k = 0; (k < 6); k++)
436 type[k] = line[k];
438 type[k] = '\0';
440 for (k = 0; (k < epdbNR); k++)
442 if (std::strncmp(type, pdbtp[k], strlen(pdbtp[k])) == 0)
444 break;
448 return k;
451 static void read_anisou(char line[], int natom, t_atoms *atoms)
453 int i, j, k, atomnr;
454 char nc = '\0';
455 char anr[12], anm[12];
457 /* Skip over type */
458 j = 6;
459 for (k = 0; (k < 5); k++, j++)
461 anr[k] = line[j];
463 anr[k] = nc;
464 j++;
465 for (k = 0; (k < 4); k++, j++)
467 anm[k] = line[j];
469 anm[k] = nc;
470 j++;
472 /* Strip off spaces */
473 trim(anm);
475 /* Search backwards for number and name only */
476 atomnr = std::strtol(anr, nullptr, 10);
477 for (i = natom-1; (i >= 0); i--)
479 if ((std::strcmp(anm, *(atoms->atomname[i])) == 0) &&
480 (atomnr == atoms->pdbinfo[i].atomnr))
482 break;
485 if (i < 0)
487 fprintf(stderr, "Skipping ANISOU record (atom %s %d not found)\n",
488 anm, atomnr);
490 else
492 if (sscanf(line+29, "%d%d%d%d%d%d",
493 &atoms->pdbinfo[i].uij[U11], &atoms->pdbinfo[i].uij[U22],
494 &atoms->pdbinfo[i].uij[U33], &atoms->pdbinfo[i].uij[U12],
495 &atoms->pdbinfo[i].uij[U13], &atoms->pdbinfo[i].uij[U23])
496 == 6)
498 atoms->pdbinfo[i].bAnisotropic = TRUE;
500 else
502 fprintf(stderr, "Invalid ANISOU record for atom %d\n", i);
503 atoms->pdbinfo[i].bAnisotropic = FALSE;
508 void get_pdb_atomnumber(const t_atoms *atoms, gmx_atomprop_t aps)
510 int i, atomnumber, len;
511 size_t k;
512 char anm[6], anm_copy[6], *ptr;
513 char nc = '\0';
514 real eval;
516 if (!atoms->pdbinfo)
518 gmx_incons("Trying to deduce atomnumbers when no pdb information is present");
520 for (i = 0; (i < atoms->nr); i++)
522 std::strcpy(anm, atoms->pdbinfo[i].atomnm);
523 std::strcpy(anm_copy, atoms->pdbinfo[i].atomnm);
524 bool atomNumberSet = false;
525 len = strlen(anm);
526 if ((anm[0] != ' ') && ((len <= 2) || !std::isdigit(anm[2])))
528 anm_copy[2] = nc;
529 if (gmx_atomprop_query(aps, epropElement, "???", anm_copy, &eval))
531 atomnumber = std::round(eval);
532 atomNumberSet = true;
534 else
536 anm_copy[1] = nc;
537 if (gmx_atomprop_query(aps, epropElement, "???", anm_copy, &eval))
539 atomnumber = std::round(eval);
540 atomNumberSet = true;
544 if (!atomNumberSet)
546 k = 0;
547 while ((k < std::strlen(anm)) && (std::isspace(anm[k]) || std::isdigit(anm[k])))
549 k++;
551 anm_copy[0] = anm[k];
552 anm_copy[1] = nc;
553 if (gmx_atomprop_query(aps, epropElement, "???", anm_copy, &eval))
555 atomnumber = std::round(eval);
556 atomNumberSet = true;
559 if (atomNumberSet)
561 atoms->atom[i].atomnumber = atomnumber;
562 ptr = gmx_atomprop_element(aps, atomnumber);
563 if (debug)
565 fprintf(debug, "Atomnumber for atom '%s' is %d\n",
566 anm, atomnumber);
569 else
571 ptr = nullptr;
573 std::strncpy(atoms->atom[i].elem, ptr == nullptr ? "" : ptr, 4);
577 static int read_atom(t_symtab *symtab,
578 char line[], int type, int natom,
579 t_atoms *atoms, rvec x[], int chainnum, gmx_bool bChange)
581 t_atom *atomn;
582 int j, k;
583 char nc = '\0';
584 char anr[12], anm[12], anm_copy[12], altloc, resnm[12], rnr[12], elem[3];
585 char xc[12], yc[12], zc[12], occup[12], bfac[12];
586 unsigned char resic;
587 char chainid;
588 int resnr, atomnumber;
590 if (natom >= atoms->nr)
592 gmx_fatal(FARGS, "\nFound more atoms (%d) in pdb file than expected (%d)",
593 natom+1, atoms->nr);
596 /* Skip over type */
597 j = 6;
598 for (k = 0; (k < 5); k++, j++)
600 anr[k] = line[j];
602 anr[k] = nc;
603 trim(anr);
604 j++;
605 for (k = 0; (k < 4); k++, j++)
607 anm[k] = line[j];
609 anm[k] = nc;
610 std::strcpy(anm_copy, anm);
611 rtrim(anm_copy);
612 atomnumber = 0;
613 trim(anm);
614 altloc = line[j];
615 j++;
616 for (k = 0; (k < 4); k++, j++)
618 resnm[k] = line[j];
620 resnm[k] = nc;
621 trim(resnm);
623 chainid = line[j];
624 j++;
626 for (k = 0; (k < 4); k++, j++)
628 rnr[k] = line[j];
630 rnr[k] = nc;
631 trim(rnr);
632 resnr = std::strtol(rnr, nullptr, 10);
633 resic = line[j];
634 j += 4;
636 /* X,Y,Z Coordinate */
637 for (k = 0; (k < 8); k++, j++)
639 xc[k] = line[j];
641 xc[k] = nc;
642 for (k = 0; (k < 8); k++, j++)
644 yc[k] = line[j];
646 yc[k] = nc;
647 for (k = 0; (k < 8); k++, j++)
649 zc[k] = line[j];
651 zc[k] = nc;
653 /* Weight */
654 for (k = 0; (k < 6); k++, j++)
656 occup[k] = line[j];
658 occup[k] = nc;
660 /* B-Factor */
661 for (k = 0; (k < 7); k++, j++)
663 bfac[k] = line[j];
665 bfac[k] = nc;
667 /* 10 blanks */
668 j += 10;
670 /* Element name */
671 for (k = 0; (k < 2); k++, j++)
673 elem[k] = line[j];
675 elem[k] = nc;
676 trim(elem);
678 if (atoms->atom)
680 atomn = &(atoms->atom[natom]);
681 if ((natom == 0) ||
682 atoms->resinfo[atoms->atom[natom-1].resind].nr != resnr ||
683 atoms->resinfo[atoms->atom[natom-1].resind].ic != resic ||
684 (strcmp(*atoms->resinfo[atoms->atom[natom-1].resind].name, resnm) != 0))
686 if (natom == 0)
688 atomn->resind = 0;
690 else
692 atomn->resind = atoms->atom[natom-1].resind + 1;
694 atoms->nres = atomn->resind + 1;
695 t_atoms_set_resinfo(atoms, natom, symtab, resnm, resnr, resic, chainnum, chainid);
697 else
699 atomn->resind = atoms->atom[natom-1].resind;
701 if (bChange)
703 xlate_atomname_pdb2gmx(anm);
705 atoms->atomname[natom] = put_symtab(symtab, anm);
706 atomn->m = 0.0;
707 atomn->q = 0.0;
708 atomn->atomnumber = atomnumber;
709 strncpy(atomn->elem, elem, 4);
711 x[natom][XX] = strtod(xc, nullptr)*0.1;
712 x[natom][YY] = strtod(yc, nullptr)*0.1;
713 x[natom][ZZ] = strtod(zc, nullptr)*0.1;
714 if (atoms->pdbinfo)
716 atoms->pdbinfo[natom].type = type;
717 atoms->pdbinfo[natom].atomnr = strtol(anr, nullptr, 10);
718 atoms->pdbinfo[natom].altloc = altloc;
719 strcpy(atoms->pdbinfo[natom].atomnm, anm_copy);
720 atoms->pdbinfo[natom].bfac = strtod(bfac, nullptr);
721 atoms->pdbinfo[natom].occup = strtod(occup, nullptr);
723 natom++;
725 return natom;
728 gmx_bool is_hydrogen(const char *nm)
730 char buf[30];
732 std::strcpy(buf, nm);
733 trim(buf);
735 if (buf[0] == 'H')
737 return TRUE;
739 else if ((std::isdigit(buf[0])) && (buf[1] == 'H'))
741 return TRUE;
743 return FALSE;
746 gmx_bool is_dummymass(const char *nm)
748 char buf[30];
750 std::strcpy(buf, nm);
751 trim(buf);
753 if ((buf[0] == 'M') && std::isdigit(buf[strlen(buf)-1]))
755 return TRUE;
758 return FALSE;
761 static void gmx_conect_addline(gmx_conect_t *con, char *line)
763 int n, ai, aj;
764 char format[32], form2[32];
766 sprintf(form2, "%%*s");
767 sprintf(format, "%s%%d", form2);
768 if (sscanf(line, format, &ai) == 1)
772 std::strcat(form2, "%*s");
773 sprintf(format, "%s%%d", form2);
774 n = sscanf(line, format, &aj);
775 if (n == 1)
777 srenew(con->conect, ++con->nconect);
778 con->conect[con->nconect-1].ai = ai-1;
779 con->conect[con->nconect-1].aj = aj-1;
782 while (n == 1);
786 void gmx_conect_dump(FILE *fp, gmx_conect conect)
788 gmx_conect_t *gc = (gmx_conect_t *)conect;
789 int i;
791 for (i = 0; (i < gc->nconect); i++)
793 fprintf(fp, "%6s%5d%5d\n", "CONECT",
794 gc->conect[i].ai+1, gc->conect[i].aj+1);
798 gmx_conect gmx_conect_init()
800 gmx_conect_t *gc;
802 snew(gc, 1);
804 return gc;
807 void gmx_conect_done(gmx_conect conect)
809 gmx_conect_t *gc = conect;
811 sfree(gc->conect);
814 gmx_bool gmx_conect_exist(gmx_conect conect, int ai, int aj)
816 gmx_conect_t *gc = conect;
817 int i;
819 /* if (!gc->bSorted)
820 sort_conect(gc);*/
822 for (i = 0; (i < gc->nconect); i++)
824 if (((gc->conect[i].ai == ai) &&
825 (gc->conect[i].aj == aj)) ||
826 ((gc->conect[i].aj == ai) &&
827 (gc->conect[i].ai == aj)))
829 return TRUE;
832 return FALSE;
835 void gmx_conect_add(gmx_conect conect, int ai, int aj)
837 gmx_conect_t *gc = (gmx_conect_t *)conect;
839 /* if (!gc->bSorted)
840 sort_conect(gc);*/
842 if (!gmx_conect_exist(conect, ai, aj))
844 srenew(gc->conect, ++gc->nconect);
845 gc->conect[gc->nconect-1].ai = ai;
846 gc->conect[gc->nconect-1].aj = aj;
850 int read_pdbfile(FILE *in, char *title, int *model_nr,
851 t_atoms *atoms, t_symtab *symtab, rvec x[], int *ePBC,
852 matrix box, gmx_bool bChange, gmx_conect conect)
854 gmx_conect_t *gc = conect;
855 gmx_bool bCOMPND;
856 gmx_bool bConnWarn = FALSE;
857 char line[STRLEN+1];
858 int line_type;
859 char *c, *d;
860 int natom, chainnum;
861 gmx_bool bStop = FALSE;
863 if (ePBC)
865 /* Only assume pbc when there is a CRYST1 entry */
866 *ePBC = epbcNONE;
868 if (box != nullptr)
870 clear_mat(box);
873 atoms->haveMass = FALSE;
874 atoms->haveCharge = FALSE;
875 atoms->haveType = FALSE;
876 atoms->haveBState = FALSE;
877 atoms->havePdbInfo = (atoms->pdbinfo != nullptr);
879 bCOMPND = FALSE;
880 title[0] = '\0';
881 natom = 0;
882 chainnum = 0;
883 while (!bStop && (fgets2(line, STRLEN, in) != nullptr))
885 line_type = line2type(line);
887 switch (line_type)
889 case epdbATOM:
890 case epdbHETATM:
891 natom = read_atom(symtab, line, line_type, natom, atoms, x, chainnum, bChange);
892 break;
894 case epdbANISOU:
895 if (atoms->havePdbInfo)
897 read_anisou(line, natom, atoms);
899 break;
901 case epdbCRYST1:
902 read_cryst1(line, ePBC, box);
903 break;
905 case epdbTITLE:
906 case epdbHEADER:
907 if (std::strlen(line) > 6)
909 c = line+6;
910 /* skip HEADER or TITLE and spaces */
911 while (c[0] != ' ')
913 c++;
915 while (c[0] == ' ')
917 c++;
919 /* truncate after title */
920 d = std::strstr(c, " ");
921 if (d)
923 d[0] = '\0';
925 if (std::strlen(c) > 0)
927 std::strcpy(title, c);
930 break;
932 case epdbCOMPND:
933 if ((!std::strstr(line, ": ")) || (std::strstr(line+6, "MOLECULE:")))
935 if (!(c = std::strstr(line+6, "MOLECULE:")) )
937 c = line;
939 /* skip 'MOLECULE:' and spaces */
940 while (c[0] != ' ')
942 c++;
944 while (c[0] == ' ')
946 c++;
948 /* truncate after title */
949 d = strstr(c, " ");
950 if (d)
952 while ( (d[-1] == ';') && d > c)
954 d--;
956 d[0] = '\0';
958 if (strlen(c) > 0)
960 if (bCOMPND)
962 std::strcat(title, "; ");
963 std::strcat(title, c);
965 else
967 std::strcpy(title, c);
970 bCOMPND = TRUE;
972 break;
974 case epdbTER:
975 chainnum++;
976 break;
978 case epdbMODEL:
979 if (model_nr)
981 sscanf(line, "%*s%d", model_nr);
983 break;
985 case epdbENDMDL:
986 bStop = TRUE;
987 break;
988 case epdbCONECT:
989 if (gc)
991 gmx_conect_addline(gc, line);
993 else if (!bConnWarn)
995 fprintf(stderr, "WARNING: all CONECT records are ignored\n");
996 bConnWarn = TRUE;
998 break;
1000 default:
1001 break;
1005 return natom;
1008 void get_pdb_coordnum(FILE *in, int *natoms)
1010 char line[STRLEN];
1012 *natoms = 0;
1013 while (fgets2(line, STRLEN, in))
1015 if (std::strncmp(line, "ENDMDL", 6) == 0)
1017 break;
1019 if ((std::strncmp(line, "ATOM ", 6) == 0) || (std::strncmp(line, "HETATM", 6) == 0))
1021 (*natoms)++;
1026 void gmx_pdb_read_conf(const char *infile,
1027 t_symtab *symtab, char **name, t_atoms *atoms,
1028 rvec x[], int *ePBC, matrix box)
1030 FILE *in = gmx_fio_fopen(infile, "r");
1031 char title[STRLEN];
1032 read_pdbfile(in, title, nullptr, atoms, symtab, x, ePBC, box, TRUE, nullptr);
1033 if (name != nullptr)
1035 *name = gmx_strdup(title);
1037 gmx_fio_fclose(in);
1040 gmx_conect gmx_conect_generate(const t_topology *top)
1042 int f, i;
1043 gmx_conect gc;
1045 /* Fill the conect records */
1046 gc = gmx_conect_init();
1048 for (f = 0; (f < F_NRE); f++)
1050 if (IS_CHEMBOND(f))
1052 for (i = 0; (i < top->idef.il[f].nr); i += interaction_function[f].nratoms+1)
1054 gmx_conect_add(gc, top->idef.il[f].iatoms[i+1],
1055 top->idef.il[f].iatoms[i+2]);
1059 return gc;
1063 gmx_fprintf_pdb_atomline(FILE * fp,
1064 enum PDB_record record,
1065 int atom_seq_number,
1066 const char * atom_name,
1067 char alternate_location,
1068 const char * res_name,
1069 char chain_id,
1070 int res_seq_number,
1071 char res_insertion_code,
1072 real x,
1073 real y,
1074 real z,
1075 real occupancy,
1076 real b_factor,
1077 const char * element)
1079 char tmp_atomname[6], tmp_resname[6];
1080 gmx_bool start_name_in_col13;
1081 int n;
1083 if (record != epdbATOM && record != epdbHETATM)
1085 gmx_fatal(FARGS, "Can only print PDB atom lines as ATOM or HETATM records");
1088 /* Format atom name */
1089 if (atom_name != nullptr)
1091 /* If the atom name is an element name with two chars, it should start already in column 13.
1092 * Otherwise it should start in column 14, unless the name length is 4 chars.
1094 if ( (element != nullptr) && (std::strlen(element) >= 2) && (gmx_strncasecmp(atom_name, element, 2) == 0) )
1096 start_name_in_col13 = TRUE;
1098 else
1100 start_name_in_col13 = (std::strlen(atom_name) >= 4);
1102 snprintf(tmp_atomname, sizeof(tmp_atomname), start_name_in_col13 ? "" : " ");
1103 std::strncat(tmp_atomname, atom_name, 4);
1104 tmp_atomname[5] = '\0';
1106 else
1108 tmp_atomname[0] = '\0';
1111 /* Format residue name */
1112 std::strncpy(tmp_resname, (res_name != nullptr) ? res_name : "", 4);
1113 /* Make sure the string is terminated if strlen was > 4 */
1114 tmp_resname[4] = '\0';
1115 /* String is properly terminated, so now we can use strcat. By adding a
1116 * space we can write it right-justified, and if the original name was
1117 * three characters or less there will be a space added on the right side.
1119 std::strcat(tmp_resname, " ");
1121 /* Truncate integers so they fit */
1122 atom_seq_number = atom_seq_number % 100000;
1123 res_seq_number = res_seq_number % 10000;
1125 n = fprintf(fp,
1126 "%-6s%5d %-4.4s%c%4.4s%c%4d%c %8.3f%8.3f%8.3f%6.2f%6.2f %2s\n",
1127 pdbtp[record],
1128 atom_seq_number,
1129 tmp_atomname,
1130 alternate_location,
1131 tmp_resname,
1132 chain_id,
1133 res_seq_number,
1134 res_insertion_code,
1135 x, y, z,
1136 occupancy,
1137 b_factor,
1138 (element != nullptr) ? element : "");
1140 return n;