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.
7 * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
8 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
9 * and including many others, as listed in the AUTHORS file in the
10 * top-level source directory and at http://www.gromacs.org.
12 * GROMACS is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public License
14 * as published by the Free Software Foundation; either version 2.1
15 * of the License, or (at your option) any later version.
17 * GROMACS is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with GROMACS; if not, see
24 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
25 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 * If you want to redistribute modifications to GROMACS, please
28 * consider that scientific software is very special. Version
29 * control is crucial - bugs must be traceable. We will be happy to
30 * consider code for inclusion in the official distribution, but
31 * derived work must not be called official GROMACS. Details are found
32 * in the README & COPYING files - if they are missing, get the
33 * official version at http://www.gromacs.org.
35 * To help us fund GROMACS development, we humbly ask that you cite
36 * the research papers on the package. Check out http://www.gromacs.org.
49 #include "gromacs/fileio/gmxfio.h"
50 #include "gromacs/math/units.h"
51 #include "gromacs/math/vec.h"
52 #include "gromacs/pbcutil/pbc.h"
53 #include "gromacs/topology/atomprop.h"
54 #include "gromacs/topology/ifunc.h"
55 #include "gromacs/topology/residuetypes.h"
56 #include "gromacs/topology/symtab.h"
57 #include "gromacs/topology/topology.h"
58 #include "gromacs/utility/coolstuff.h"
59 #include "gromacs/utility/cstringutil.h"
60 #include "gromacs/utility/fatalerror.h"
61 #include "gromacs/utility/futil.h"
62 #include "gromacs/utility/smalloc.h"
63 #include "gromacs/utility/snprintf.h"
70 typedef struct gmx_conect_t
74 gmx_conection_t
* conect
;
77 static const char* pdbtp
[epdbNR
] = { "ATOM ", "HETATM", "ANISOU", "CRYST1", "COMPND", "MODEL",
78 "ENDMDL", "TER", "HEADER", "TITLE", "REMARK", "CONECT" };
80 #define REMARK_SIM_BOX "REMARK THIS IS A SIMULATION BOX"
82 static void xlate_atomname_pdb2gmx(char* name
)
87 length
= std::strlen(name
);
88 if (length
> 3 && std::isdigit(name
[0]))
91 for (i
= 1; i
< length
; i
++)
93 name
[i
- 1] = name
[i
];
95 name
[length
- 1] = temp
;
99 // Deliberately taking a copy of name to return it later
100 static std::string
xlate_atomname_gmx2pdb(std::string name
)
102 size_t length
= name
.size();
103 if (length
> 3 && std::isdigit(name
[length
- 1]))
105 char temp
= name
[length
- 1];
106 for (size_t i
= length
- 1; i
> 0; --i
)
108 name
[i
] = name
[i
- 1];
116 void gmx_write_pdb_box(FILE* out
, PbcType pbcType
, const matrix box
)
118 real alpha
, beta
, gamma
;
120 if (pbcType
== PbcType::Unset
)
122 pbcType
= guessPbcType(box
);
125 if (pbcType
== PbcType::No
)
130 if (norm2(box
[YY
]) * norm2(box
[ZZ
]) != 0)
132 alpha
= RAD2DEG
* gmx_angle(box
[YY
], box
[ZZ
]);
138 if (norm2(box
[XX
]) * norm2(box
[ZZ
]) != 0)
140 beta
= RAD2DEG
* gmx_angle(box
[XX
], box
[ZZ
]);
146 if (norm2(box
[XX
]) * norm2(box
[YY
]) != 0)
148 gamma
= RAD2DEG
* gmx_angle(box
[XX
], box
[YY
]);
154 fprintf(out
, "REMARK THIS IS A SIMULATION BOX\n");
155 if (pbcType
!= PbcType::Screw
)
157 fprintf(out
, "CRYST1%9.3f%9.3f%9.3f%7.2f%7.2f%7.2f %-11s%4d\n", 10 * norm(box
[XX
]),
158 10 * norm(box
[YY
]), 10 * norm(box
[ZZ
]), alpha
, beta
, gamma
, "P 1", 1);
162 /* Double the a-vector length and write the correct space group */
163 fprintf(out
, "CRYST1%9.3f%9.3f%9.3f%7.2f%7.2f%7.2f %-11s%4d\n", 20 * norm(box
[XX
]),
164 10 * norm(box
[YY
]), 10 * norm(box
[ZZ
]), alpha
, beta
, gamma
, "P 21 1 1", 1);
168 static void read_cryst1(char* line
, PbcType
* pbcType
, matrix box
)
171 char sa
[12], sb
[12], sc
[12], sg
[SG_SIZE
+ 1], ident
;
172 double fa
, fb
, fc
, alpha
, beta
, gamma
, cosa
, cosb
, cosg
, sing
;
173 int syma
, symb
, symc
;
176 sscanf(line
, "%*s%s%s%s%lf%lf%lf", sa
, sb
, sc
, &alpha
, &beta
, &gamma
);
178 pbcTypeFile
= PbcType::Unset
;
179 if (strlen(line
) >= 55)
181 strncpy(sg
, line
+ 55, SG_SIZE
);
187 sscanf(sg
, "%c %d %d %d", &ident
, &syma
, &symb
, &symc
);
188 if (ident
== 'P' && syma
== 1 && symb
<= 1 && symc
<= 1)
190 fc
= strtod(sc
, nullptr) * 0.1;
191 pbcTypeFile
= (fc
> 0 ? PbcType::Xyz
: PbcType::XY
);
193 if (ident
== 'P' && syma
== 21 && symb
== 1 && symc
== 1)
195 pbcTypeFile
= PbcType::Screw
;
200 *pbcType
= pbcTypeFile
;
205 fa
= strtod(sa
, nullptr) * 0.1;
206 fb
= strtod(sb
, nullptr) * 0.1;
207 fc
= strtod(sc
, nullptr) * 0.1;
208 if (pbcTypeFile
== PbcType::Screw
)
214 if ((alpha
!= 90.0) || (beta
!= 90.0) || (gamma
!= 90.0))
218 cosa
= std::cos(alpha
* DEG2RAD
);
226 cosb
= std::cos(beta
* DEG2RAD
);
234 cosg
= std::cos(gamma
* DEG2RAD
);
235 sing
= std::sin(gamma
* DEG2RAD
);
242 box
[YY
][XX
] = fb
* cosg
;
243 box
[YY
][YY
] = fb
* sing
;
244 box
[ZZ
][XX
] = fc
* cosb
;
245 box
[ZZ
][YY
] = fc
* (cosa
- cosb
* cosg
) / sing
;
246 box
[ZZ
][ZZ
] = std::sqrt(fc
* fc
- box
[ZZ
][XX
] * box
[ZZ
][XX
] - box
[ZZ
][YY
] * box
[ZZ
][YY
]);
256 static int gmx_fprintf_pqr_atomline(FILE* fp
,
257 enum PDB_record record
,
259 const char* atom_name
,
260 const char* res_name
,
269 GMX_RELEASE_ASSERT(record
== epdbATOM
|| record
== epdbHETATM
,
270 "Can only print PQR atom lines as ATOM or HETATM records");
272 /* Check atom name */
273 GMX_RELEASE_ASSERT(atom_name
!= nullptr, "Need atom information to print pqr");
275 /* Check residue name */
276 GMX_RELEASE_ASSERT(res_name
!= nullptr, "Need residue information to print pqr");
278 /* Truncate integers so they fit */
279 atom_seq_number
= atom_seq_number
% 100000;
280 res_seq_number
= res_seq_number
% 10000;
282 int n
= fprintf(fp
, "%-6s%5d %-4.4s%4.4s%c%4d %8.3f %8.3f %8.3f %6.2f %6.2f\n", pdbtp
[record
],
283 atom_seq_number
, atom_name
, res_name
, chain_id
, res_seq_number
, x
, y
, z
,
284 occupancy
, b_factor
);
289 void write_pdbfile_indexed(FILE* out
,
291 const t_atoms
* atoms
,
302 gmx_conect_t
* gc
= static_cast<gmx_conect_t
*>(conect
);
303 enum PDB_record type
;
309 fprintf(out
, "TITLE %s\n", (title
&& title
[0]) ? title
: gmx::bromacs().c_str());
310 if (box
&& ((norm2(box
[XX
]) != 0.0F
) || (norm2(box
[YY
]) != 0.0F
) || (norm2(box
[ZZ
]) != 0.0F
)))
312 gmx_write_pdb_box(out
, pbcType
, box
);
314 if (atoms
->havePdbInfo
)
316 /* Check whether any occupancies are set, in that case leave it as is,
317 * otherwise set them all to one
320 for (int ii
= 0; (ii
< nindex
) && bOccup
; ii
++)
323 bOccup
= bOccup
&& (atoms
->pdbinfo
[i
].occup
== 0.0);
331 fprintf(out
, "MODEL %8d\n", model_nr
> 0 ? model_nr
: 1);
334 for (int ii
= 0; ii
< nindex
; ii
++)
337 int resind
= atoms
->atom
[i
].resind
;
338 std::string resnm
= *atoms
->resinfo
[resind
].name
;
339 std::string nm
= *atoms
->atomname
[i
];
341 /* rename HG12 to 2HG1, etc. */
342 nm
= xlate_atomname_gmx2pdb(nm
);
343 int resnr
= atoms
->resinfo
[resind
].nr
;
344 unsigned char resic
= atoms
->resinfo
[resind
].ic
;
352 ch
= atoms
->resinfo
[resind
].chainid
;
361 resnr
= resnr
% 10000;
364 if (atoms
->pdbinfo
!= nullptr)
366 pdbinfo
= atoms
->pdbinfo
[i
];
370 gmx_pdbinfo_init_default(&pdbinfo
);
372 type
= static_cast<enum PDB_record
>(pdbinfo
.type
);
373 altloc
= pdbinfo
.altloc
;
374 if (!isalnum(altloc
))
378 occup
= bOccup
? 1.0 : pdbinfo
.occup
;
382 gmx_fprintf_pdb_atomline(out
, type
, i
+ 1, nm
.c_str(), altloc
, resnm
.c_str(), ch
, resnr
,
383 resic
, 10 * x
[i
][XX
], 10 * x
[i
][YY
], 10 * x
[i
][ZZ
], occup
,
384 bfac
, atoms
->atom
[i
].elem
);
386 if (atoms
->pdbinfo
&& atoms
->pdbinfo
[i
].bAnisotropic
)
388 fprintf(out
, "ANISOU%5d %-4.4s%4.4s%c%4d%c %7d%7d%7d%7d%7d%7d\n", (i
+ 1) % 100000,
389 nm
.c_str(), resnm
.c_str(), ch
, resnr
, (resic
== '\0') ? ' ' : resic
,
390 atoms
->pdbinfo
[i
].uij
[0], atoms
->pdbinfo
[i
].uij
[1], atoms
->pdbinfo
[i
].uij
[2],
391 atoms
->pdbinfo
[i
].uij
[3], atoms
->pdbinfo
[i
].uij
[4], atoms
->pdbinfo
[i
].uij
[5]);
396 gmx_fprintf_pqr_atomline(out
, type
, i
+ 1, nm
.c_str(), resnm
.c_str(), ch
, resnr
,
397 10 * x
[i
][XX
], 10 * x
[i
][YY
], 10 * x
[i
][ZZ
], occup
, bfac
);
401 fprintf(out
, "TER\n");
402 fprintf(out
, "ENDMDL\n");
406 /* Write conect records */
407 for (int i
= 0; (i
< gc
->nconect
); i
++)
409 fprintf(out
, "CONECT%5d%5d\n", gc
->conect
[i
].ai
+ 1, gc
->conect
[i
].aj
+ 1);
414 void write_pdbfile(FILE* out
,
416 const t_atoms
* atoms
,
426 snew(index
, atoms
->nr
);
427 for (i
= 0; i
< atoms
->nr
; i
++)
431 write_pdbfile_indexed(out
, title
, atoms
, x
, pbcType
, box
, chainid
, model_nr
, atoms
->nr
, index
,
436 static int line2type(const char* line
)
441 for (k
= 0; (k
< 6); k
++)
447 for (k
= 0; (k
< epdbNR
); k
++)
449 if (std::strncmp(type
, pdbtp
[k
], strlen(pdbtp
[k
])) == 0)
458 static void read_anisou(char line
[], int natom
, t_atoms
* atoms
)
462 char anr
[12], anm
[12];
466 for (k
= 0; (k
< 5); k
++, j
++)
472 for (k
= 0; (k
< 4); k
++, j
++)
479 /* Strip off spaces */
482 /* Search backwards for number and name only */
483 atomnr
= std::strtol(anr
, nullptr, 10);
484 for (i
= natom
- 1; (i
>= 0); i
--)
486 if ((std::strcmp(anm
, *(atoms
->atomname
[i
])) == 0) && (atomnr
== atoms
->pdbinfo
[i
].atomnr
))
493 fprintf(stderr
, "Skipping ANISOU record (atom %s %d not found)\n", anm
, atomnr
);
497 if (sscanf(line
+ 29, "%d%d%d%d%d%d", &atoms
->pdbinfo
[i
].uij
[U11
], &atoms
->pdbinfo
[i
].uij
[U22
],
498 &atoms
->pdbinfo
[i
].uij
[U33
], &atoms
->pdbinfo
[i
].uij
[U12
],
499 &atoms
->pdbinfo
[i
].uij
[U13
], &atoms
->pdbinfo
[i
].uij
[U23
])
502 atoms
->pdbinfo
[i
].bAnisotropic
= TRUE
;
506 fprintf(stderr
, "Invalid ANISOU record for atom %d\n", i
);
507 atoms
->pdbinfo
[i
].bAnisotropic
= FALSE
;
512 void get_pdb_atomnumber(const t_atoms
* atoms
, AtomProperties
* aps
)
514 int i
, atomnumber
, len
;
516 char anm
[6], anm_copy
[6];
522 gmx_incons("Trying to deduce atomnumbers when no pdb information is present");
524 for (i
= 0; (i
< atoms
->nr
); i
++)
526 std::strcpy(anm
, atoms
->pdbinfo
[i
].atomnm
);
527 std::strcpy(anm_copy
, atoms
->pdbinfo
[i
].atomnm
);
528 bool atomNumberSet
= false;
530 if ((anm
[0] != ' ') && ((len
<= 2) || !std::isdigit(anm
[2])))
533 if (aps
->setAtomProperty(epropElement
, "???", anm_copy
, &eval
))
535 atomnumber
= gmx::roundToInt(eval
);
536 atomNumberSet
= true;
541 if (aps
->setAtomProperty(epropElement
, "???", anm_copy
, &eval
))
543 atomnumber
= gmx::roundToInt(eval
);
544 atomNumberSet
= true;
551 while ((k
< std::strlen(anm
)) && (std::isspace(anm
[k
]) || std::isdigit(anm
[k
])))
555 anm_copy
[0] = anm
[k
];
557 if (aps
->setAtomProperty(epropElement
, "???", anm_copy
, &eval
))
559 atomnumber
= gmx::roundToInt(eval
);
560 atomNumberSet
= true;
566 atoms
->atom
[i
].atomnumber
= atomnumber
;
567 buf
= aps
->elementFromAtomNumber(atomnumber
);
570 fprintf(debug
, "Atomnumber for atom '%s' is %d\n", anm
, atomnumber
);
574 std::strncpy(atoms
->atom
[i
].elem
, buf
.c_str(), 4);
579 read_atom(t_symtab
* symtab
, const char line
[], int type
, int natom
, t_atoms
* atoms
, rvec x
[], int chainnum
, gmx_bool bChange
)
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];
588 int resnr
, atomnumber
;
590 if (natom
>= atoms
->nr
)
592 gmx_fatal(FARGS
, "\nFound more atoms (%d) in pdb file than expected (%d)", natom
+ 1, atoms
->nr
);
597 for (k
= 0; (k
< 5); k
++, j
++)
604 for (k
= 0; (k
< 4); k
++, j
++)
609 std::strcpy(anm_copy
, anm
);
615 for (k
= 0; (k
< 4); k
++, j
++)
625 for (k
= 0; (k
< 4); k
++, j
++)
631 resnr
= std::strtol(rnr
, nullptr, 10);
635 /* X,Y,Z Coordinate */
636 for (k
= 0; (k
< 8); k
++, j
++)
641 for (k
= 0; (k
< 8); k
++, j
++)
646 for (k
= 0; (k
< 8); k
++, j
++)
653 for (k
= 0; (k
< 6); k
++, j
++)
660 for (k
= 0; (k
< 7); k
++, j
++)
670 for (k
= 0; (k
< 2); k
++, j
++)
679 atomn
= &(atoms
->atom
[natom
]);
680 if ((natom
== 0) || atoms
->resinfo
[atoms
->atom
[natom
- 1].resind
].nr
!= resnr
681 || atoms
->resinfo
[atoms
->atom
[natom
- 1].resind
].ic
!= resic
682 || (strcmp(*atoms
->resinfo
[atoms
->atom
[natom
- 1].resind
].name
, resnm
) != 0))
690 atomn
->resind
= atoms
->atom
[natom
- 1].resind
+ 1;
692 atoms
->nres
= atomn
->resind
+ 1;
693 t_atoms_set_resinfo(atoms
, natom
, symtab
, resnm
, resnr
, resic
, chainnum
, chainid
);
697 atomn
->resind
= atoms
->atom
[natom
- 1].resind
;
701 xlate_atomname_pdb2gmx(anm
);
703 atoms
->atomname
[natom
] = put_symtab(symtab
, anm
);
706 atomn
->atomnumber
= atomnumber
;
707 strncpy(atomn
->elem
, elem
, 4);
709 x
[natom
][XX
] = strtod(xc
, nullptr) * 0.1;
710 x
[natom
][YY
] = strtod(yc
, nullptr) * 0.1;
711 x
[natom
][ZZ
] = strtod(zc
, nullptr) * 0.1;
714 atoms
->pdbinfo
[natom
].type
= type
;
715 atoms
->pdbinfo
[natom
].atomnr
= strtol(anr
, nullptr, 10);
716 atoms
->pdbinfo
[natom
].altloc
= altloc
;
717 strcpy(atoms
->pdbinfo
[natom
].atomnm
, anm_copy
);
718 atoms
->pdbinfo
[natom
].bfac
= strtod(bfac
, nullptr);
719 atoms
->pdbinfo
[natom
].occup
= strtod(occup
, nullptr);
726 gmx_bool
is_hydrogen(const char* nm
)
730 std::strcpy(buf
, nm
);
733 return ((buf
[0] == 'H') || ((std::isdigit(buf
[0]) != 0) && (buf
[1] == 'H')));
736 gmx_bool
is_dummymass(const char* nm
)
740 std::strcpy(buf
, nm
);
743 return (buf
[0] == 'M') && (std::isdigit(buf
[strlen(buf
) - 1]) != 0);
746 static void gmx_conect_addline(gmx_conect_t
* con
, char* line
)
750 std::string form2
= "%*s";
751 std::string format
= form2
+ "%d";
752 if (sscanf(line
, format
.c_str(), &ai
) == 1)
757 format
= form2
+ "%d";
758 n
= sscanf(line
, format
.c_str(), &aj
);
761 gmx_conect_add(con
, ai
- 1, aj
- 1); /* to prevent duplicated records */
767 void gmx_conect_dump(FILE* fp
, gmx_conect conect
)
769 gmx_conect_t
* gc
= static_cast<gmx_conect_t
*>(conect
);
772 for (i
= 0; (i
< gc
->nconect
); i
++)
774 fprintf(fp
, "%6s%5d%5d\n", "CONECT", gc
->conect
[i
].ai
+ 1, gc
->conect
[i
].aj
+ 1);
778 gmx_conect
gmx_conect_init()
787 void gmx_conect_done(gmx_conect conect
)
789 gmx_conect_t
* gc
= conect
;
794 gmx_bool
gmx_conect_exist(gmx_conect conect
, int ai
, int aj
)
796 gmx_conect_t
* gc
= conect
;
802 for (i
= 0; (i
< gc
->nconect
); i
++)
804 if (((gc
->conect
[i
].ai
== ai
) && (gc
->conect
[i
].aj
== aj
))
805 || ((gc
->conect
[i
].aj
== ai
) && (gc
->conect
[i
].ai
== aj
)))
813 void gmx_conect_add(gmx_conect conect
, int ai
, int aj
)
815 gmx_conect_t
* gc
= static_cast<gmx_conect_t
*>(conect
);
820 if (!gmx_conect_exist(conect
, ai
, aj
))
822 srenew(gc
->conect
, ++gc
->nconect
);
823 gc
->conect
[gc
->nconect
- 1].ai
= ai
;
824 gc
->conect
[gc
->nconect
- 1].aj
= aj
;
828 int read_pdbfile(FILE* in
,
839 gmx_conect_t
* gc
= conect
;
841 gmx_bool bConnWarn
= FALSE
;
842 char line
[STRLEN
+ 1];
846 gmx_bool bStop
= FALSE
;
850 /* Only assume pbc when there is a CRYST1 entry */
851 *pbcType
= PbcType::No
;
858 atoms
->haveMass
= FALSE
;
859 atoms
->haveCharge
= FALSE
;
860 atoms
->haveType
= FALSE
;
861 atoms
->haveBState
= FALSE
;
862 atoms
->havePdbInfo
= (atoms
->pdbinfo
!= nullptr);
868 while (!bStop
&& (fgets2(line
, STRLEN
, in
) != nullptr))
870 line_type
= line2type(line
);
876 natom
= read_atom(symtab
, line
, line_type
, natom
, atoms
, x
, chainnum
, bChange
);
880 if (atoms
->havePdbInfo
)
882 read_anisou(line
, natom
, atoms
);
886 case epdbCRYST1
: read_cryst1(line
, pbcType
, box
); break;
890 if (std::strlen(line
) > 6)
893 /* skip HEADER or TITLE and spaces */
902 /* truncate after title */
903 d
= std::strstr(c
, " ");
908 if (std::strlen(c
) > 0)
910 std::strcpy(title
, c
);
916 if ((!std::strstr(line
, ": ")) || (std::strstr(line
+ 6, "MOLECULE:")))
918 if (!(c
= std::strstr(line
+ 6, "MOLECULE:")))
922 /* skip 'MOLECULE:' and spaces */
931 /* truncate after title */
935 while ((d
[-1] == ';') && d
> c
)
945 std::strcat(title
, "; ");
946 std::strcat(title
, c
);
950 std::strcpy(title
, c
);
957 case epdbTER
: chainnum
++; break;
962 sscanf(line
, "%*s%d", model_nr
);
966 case epdbENDMDL
: bStop
= TRUE
; break;
970 gmx_conect_addline(gc
, line
);
974 fprintf(stderr
, "WARNING: all CONECT records are ignored\n");
986 void get_pdb_coordnum(FILE* in
, int* natoms
)
991 while (fgets2(line
, STRLEN
, in
))
993 if (std::strncmp(line
, "ENDMDL", 6) == 0)
997 if ((std::strncmp(line
, "ATOM ", 6) == 0) || (std::strncmp(line
, "HETATM", 6) == 0))
1004 void gmx_pdb_read_conf(const char* infile
, t_symtab
* symtab
, char** name
, t_atoms
* atoms
, rvec x
[], PbcType
* pbcType
, matrix box
)
1006 FILE* in
= gmx_fio_fopen(infile
, "r");
1008 read_pdbfile(in
, title
, nullptr, atoms
, symtab
, x
, pbcType
, box
, TRUE
, nullptr);
1009 if (name
!= nullptr)
1011 *name
= gmx_strdup(title
);
1016 gmx_conect
gmx_conect_generate(const t_topology
* top
)
1021 /* Fill the conect records */
1022 gc
= gmx_conect_init();
1024 for (f
= 0; (f
< F_NRE
); f
++)
1028 for (i
= 0; (i
< top
->idef
.il
[f
].nr
); i
+= interaction_function
[f
].nratoms
+ 1)
1030 gmx_conect_add(gc
, top
->idef
.il
[f
].iatoms
[i
+ 1], top
->idef
.il
[f
].iatoms
[i
+ 2]);
1037 int gmx_fprintf_pdb_atomline(FILE* fp
,
1038 enum PDB_record record
,
1039 int atom_seq_number
,
1040 const char* atom_name
,
1041 char alternate_location
,
1042 const char* res_name
,
1045 char res_insertion_code
,
1051 const char* element
)
1053 char tmp_atomname
[6], tmp_resname
[6];
1054 gmx_bool start_name_in_col13
;
1057 if (record
!= epdbATOM
&& record
!= epdbHETATM
)
1059 gmx_fatal(FARGS
, "Can only print PDB atom lines as ATOM or HETATM records");
1062 /* Format atom name */
1063 if (atom_name
!= nullptr)
1065 /* If the atom name is an element name with two chars, it should start already in column 13.
1066 * Otherwise it should start in column 14, unless the name length is 4 chars.
1068 if ((element
!= nullptr) && (std::strlen(element
) >= 2)
1069 && (gmx_strncasecmp(atom_name
, element
, 2) == 0))
1071 start_name_in_col13
= TRUE
;
1075 start_name_in_col13
= (std::strlen(atom_name
) >= 4);
1077 snprintf(tmp_atomname
, sizeof(tmp_atomname
), start_name_in_col13
? "" : " ");
1078 std::strncat(tmp_atomname
, atom_name
, 4);
1079 tmp_atomname
[5] = '\0';
1083 tmp_atomname
[0] = '\0';
1086 /* Format residue name */
1087 std::strncpy(tmp_resname
, (res_name
!= nullptr) ? res_name
: "", 4);
1088 /* Make sure the string is terminated if strlen was > 4 */
1089 tmp_resname
[4] = '\0';
1090 /* String is properly terminated, so now we can use strcat. By adding a
1091 * space we can write it right-justified, and if the original name was
1092 * three characters or less there will be a space added on the right side.
1094 std::strcat(tmp_resname
, " ");
1096 /* Truncate integers so they fit */
1097 atom_seq_number
= atom_seq_number
% 100000;
1098 res_seq_number
= res_seq_number
% 10000;
1100 n
= fprintf(fp
, "%-6s%5d %-4.4s%c%4.4s%c%4d%c %8.3f%8.3f%8.3f%6.2f%6.2f %2s\n",
1101 pdbtp
[record
], atom_seq_number
, tmp_atomname
, alternate_location
, tmp_resname
,
1102 chain_id
, res_seq_number
, res_insertion_code
, x
, y
, z
, occupancy
, b_factor
,
1103 (element
!= nullptr) ? element
: "");