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,2021, 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.
40 #include "gromacs/fileio/pdbio.h"
50 #include "gromacs/fileio/gmxfio.h"
51 #include "gromacs/math/units.h"
52 #include "gromacs/math/utilities.h"
53 #include "gromacs/math/vec.h"
54 #include "gromacs/pbcutil/pbc.h"
55 #include "gromacs/topology/atomprop.h"
56 #include "gromacs/topology/ifunc.h"
57 #include "gromacs/topology/symtab.h"
58 #include "gromacs/topology/topology.h"
59 #include "gromacs/utility/coolstuff.h"
60 #include "gromacs/utility/cstringutil.h"
61 #include "gromacs/utility/enumerationhelpers.h"
62 #include "gromacs/utility/fatalerror.h"
63 #include "gromacs/utility/futil.h"
64 #include "gromacs/utility/smalloc.h"
65 #include "gromacs/utility/snprintf.h"
66 #include "gromacs/utility/stringtoenumvalueconverter.h"
73 typedef struct gmx_conect_t
77 gmx_conection_t* conect;
80 const char* enumValueToString(PdbRecordType enumValue)
82 static constexpr gmx::EnumerationArray<PdbRecordType, const char*> pdbRecordTypeName = {
83 "ATOM ", "HETATM", "ANISOU", "CRYST1", "COMPND", "MODEL",
84 "ENDMDL", "TER", "HEADER", "TITLE", "REMARK", "CONECT"
86 return pdbRecordTypeName[enumValue];
89 void gmx_write_pdb_box(FILE* out, PbcType pbcType, const matrix box)
91 real alpha, beta, gamma;
93 if (pbcType == PbcType::Unset)
95 pbcType = guessPbcType(box);
98 if (pbcType == PbcType::No)
103 if (norm2(box[YY]) * norm2(box[ZZ]) != 0)
105 alpha = gmx::c_rad2Deg * gmx_angle(box[YY], box[ZZ]);
111 if (norm2(box[XX]) * norm2(box[ZZ]) != 0)
113 beta = gmx::c_rad2Deg * gmx_angle(box[XX], box[ZZ]);
119 if (norm2(box[XX]) * norm2(box[YY]) != 0)
121 gamma = gmx::c_rad2Deg * gmx_angle(box[XX], box[YY]);
127 fprintf(out, "REMARK THIS IS A SIMULATION BOX\n");
128 if (pbcType != PbcType::Screw)
131 "CRYST1%9.3f%9.3f%9.3f%7.2f%7.2f%7.2f %-11s%4d\n",
143 /* Double the a-vector length and write the correct space group */
145 "CRYST1%9.3f%9.3f%9.3f%7.2f%7.2f%7.2f %-11s%4d\n",
157 static void read_cryst1(char* line, PbcType* pbcType, matrix box)
160 char sa[12], sb[12], sc[12], sg[SG_SIZE + 1], ident;
161 double fa, fb, fc, alpha, beta, gamma, cosa, cosb, cosg, sing;
162 int syma, symb, symc;
165 sscanf(line, "%*s%s%s%s%lf%lf%lf", sa, sb, sc, &alpha, &beta, &gamma);
167 pbcTypeFile = PbcType::Unset;
168 if (strlen(line) >= 55)
170 strncpy(sg, line + 55, SG_SIZE);
176 sscanf(sg, "%c %d %d %d", &ident, &syma, &symb, &symc);
177 if (ident == 'P' && syma == 1 && symb <= 1 && symc <= 1)
179 fc = strtod(sc, nullptr) * 0.1;
180 pbcTypeFile = (fc > 0 ? PbcType::Xyz : PbcType::XY);
182 if (ident == 'P' && syma == 21 && symb == 1 && symc == 1)
184 pbcTypeFile = PbcType::Screw;
189 *pbcType = pbcTypeFile;
194 fa = strtod(sa, nullptr) * 0.1;
195 fb = strtod(sb, nullptr) * 0.1;
196 fc = strtod(sc, nullptr) * 0.1;
197 if (pbcTypeFile == PbcType::Screw)
203 if ((alpha != 90.0) || (beta != 90.0) || (gamma != 90.0))
207 cosa = std::cos(alpha * gmx::c_deg2Rad);
215 cosb = std::cos(beta * gmx::c_deg2Rad);
223 cosg = std::cos(gamma * gmx::c_deg2Rad);
224 sing = std::sin(gamma * gmx::c_deg2Rad);
231 box[YY][XX] = fb * cosg;
232 box[YY][YY] = fb * sing;
233 box[ZZ][XX] = fc * cosb;
234 box[ZZ][YY] = fc * (cosa - cosb * cosg) / sing;
235 box[ZZ][ZZ] = std::sqrt(fc * fc - box[ZZ][XX] * box[ZZ][XX] - box[ZZ][YY] * box[ZZ][YY]);
245 static int gmx_fprintf_pqr_atomline(FILE* fp,
246 PdbRecordType record,
248 const char* atom_name,
249 const char* res_name,
258 GMX_RELEASE_ASSERT(record == PdbRecordType::Atom || record == PdbRecordType::Hetatm,
259 "Can only print PQR atom lines as ATOM or HETATM records");
261 /* Check atom name */
262 GMX_RELEASE_ASSERT(atom_name != nullptr, "Need atom information to print pqr");
264 /* Check residue name */
265 GMX_RELEASE_ASSERT(res_name != nullptr, "Need residue information to print pqr");
267 /* Truncate integers so they fit */
268 atom_seq_number = atom_seq_number % 100000;
269 res_seq_number = res_seq_number % 10000;
272 "%-6s%5d %-4.4s%4.4s%c%4d %8.3f %8.3f %8.3f %6.2f %6.2f\n",
273 enumValueToString(record),
288 void write_pdbfile_indexed(FILE* out,
290 const t_atoms* atoms,
300 bool standardCompliantMode)
302 gmx_conect_t* gc = static_cast<gmx_conect_t*>(conect);
308 if (standardCompliantMode)
310 fprintf(out, "HEADER GROMACS SIMULATION BOX 01-JAN-00 0000\n");
312 "TITLE Gromacs simulation box\n"
313 "COMPND MOL_ID: 1; \n"
314 "COMPND 2 MOLECULE: GROMACS SIMULATION BOX; \n"
315 "COMPND 3 CHAIN: A; \n"
316 "SOURCE MOL_ID: 1;\n"
317 "SOURCE 2 SYNTHETIC\n"
319 "EXPDTA PURE PRODUCT OF COMPUTER SIMULATION\n"
321 "REVDAT 1 01-JAN-00 0000 0\n");
325 fprintf(out, "TITLE %s\n", (title && title[0]) ? title : gmx::bromacs().c_str());
329 if (box && ((norm2(box[XX]) != 0.0F) || (norm2(box[YY]) != 0.0F) || (norm2(box[ZZ]) != 0.0F)))
331 gmx_write_pdb_box(out, pbcType, box);
333 if (atoms->havePdbInfo)
335 /* Check whether any occupancies are set, in that case leave it as is,
336 * otherwise set them all to one
339 for (int ii = 0; (ii < nindex) && bOccup; ii++)
342 bOccup = bOccup && (atoms->pdbinfo[i].occup == 0.0);
350 fprintf(out, "MODEL %8d\n", model_nr > 0 ? model_nr : 1);
352 // Collect last printed values for TER record
353 int lastAtomNumber = 0;
354 std::string lastResName;
357 for (int ii = 0; ii < nindex; ii++)
360 int resind = atoms->atom[i].resind;
361 std::string resnm = *atoms->resinfo[resind].name;
362 std::string nm = *atoms->atomname[i];
364 int resnr = atoms->resinfo[resind].nr;
365 unsigned char resic = atoms->resinfo[resind].ic;
373 ch = atoms->resinfo[resind].chainid;
382 resnr = resnr % 10000;
385 if (atoms->pdbinfo != nullptr)
387 pdbinfo = atoms->pdbinfo[i];
391 gmx_pdbinfo_init_default(&pdbinfo);
394 altloc = pdbinfo.altloc;
395 if (!isalnum(altloc))
399 occup = bOccup ? 1.0 : pdbinfo.occup;
403 gmx_fprintf_pdb_atomline(out,
417 atoms->atom[i].elem);
419 lastAtomNumber = i + 1;
423 if (atoms->pdbinfo && atoms->pdbinfo[i].bAnisotropic)
426 "ANISOU%5d %-4.4s%4.4s%c%4d%c %7d%7d%7d%7d%7d%7d\n",
432 (resic == '\0') ? ' ' : resic,
433 atoms->pdbinfo[i].uij[0],
434 atoms->pdbinfo[i].uij[1],
435 atoms->pdbinfo[i].uij[2],
436 atoms->pdbinfo[i].uij[3],
437 atoms->pdbinfo[i].uij[4],
438 atoms->pdbinfo[i].uij[5]);
443 gmx_fprintf_pqr_atomline(out,
458 if (standardCompliantMode)
460 fprintf(out, "TER %5d %4.4s%c%4d\n", lastAtomNumber, lastResName.c_str(), chainid, lastResNr);
464 fprintf(out, "TER\n");
467 fprintf(out, "ENDMDL\n");
471 /* Write conect records */
472 for (int i = 0; (i < gc->nconect); i++)
474 fprintf(out, "CONECT%5d%5d\n", gc->conect[i].ai + 1, gc->conect[i].aj + 1);
479 void write_pdbfile(FILE* out,
481 const t_atoms* atoms,
491 snew(index, atoms->nr);
492 for (i = 0; i < atoms->nr; i++)
496 write_pdbfile_indexed(
497 out, title, atoms, x, pbcType, box, chainid, model_nr, atoms->nr, index, conect, false);
501 static void read_anisou(char line[], int natom, t_atoms* atoms)
505 char anr[12], anm[12];
509 for (k = 0; (k < 5); k++, j++)
515 for (k = 0; (k < 4); k++, j++)
522 /* Strip off spaces */
525 /* Search backwards for number and name only */
526 atomnr = std::strtol(anr, nullptr, 10);
527 for (i = natom - 1; (i >= 0); i--)
529 if ((std::strcmp(anm, *(atoms->atomname[i])) == 0) && (atomnr == atoms->pdbinfo[i].atomnr))
536 fprintf(stderr, "Skipping ANISOU record (atom %s %d not found)\n", anm, atomnr);
540 if (sscanf(line + 29,
542 &atoms->pdbinfo[i].uij[U11],
543 &atoms->pdbinfo[i].uij[U22],
544 &atoms->pdbinfo[i].uij[U33],
545 &atoms->pdbinfo[i].uij[U12],
546 &atoms->pdbinfo[i].uij[U13],
547 &atoms->pdbinfo[i].uij[U23])
550 atoms->pdbinfo[i].bAnisotropic = TRUE;
554 fprintf(stderr, "Invalid ANISOU record for atom %d\n", i);
555 atoms->pdbinfo[i].bAnisotropic = FALSE;
560 void get_pdb_atomnumber(const t_atoms* atoms, AtomProperties* aps)
562 int i, atomnumber, len;
564 char anm[6], anm_copy[6];
570 gmx_incons("Trying to deduce atomnumbers when no pdb information is present");
572 for (i = 0; (i < atoms->nr); i++)
574 std::strcpy(anm, atoms->pdbinfo[i].atomnm);
575 std::strcpy(anm_copy, atoms->pdbinfo[i].atomnm);
576 bool atomNumberSet = false;
578 if ((anm[0] != ' ') && ((len <= 2) || !std::isdigit(anm[2])))
581 if (aps->setAtomProperty(epropElement, "???", anm_copy, &eval))
583 atomnumber = gmx::roundToInt(eval);
584 atomNumberSet = true;
589 if (aps->setAtomProperty(epropElement, "???", anm_copy, &eval))
591 atomnumber = gmx::roundToInt(eval);
592 atomNumberSet = true;
599 while ((k < std::strlen(anm)) && (std::isspace(anm[k]) || std::isdigit(anm[k])))
603 anm_copy[0] = anm[k];
605 if (aps->setAtomProperty(epropElement, "???", anm_copy, &eval))
607 atomnumber = gmx::roundToInt(eval);
608 atomNumberSet = true;
611 static constexpr size_t sc_maxElementNameLength = 3;
612 static_assert(sizeof(atoms->atom[i].elem) >= sc_maxElementNameLength + 1);
616 atoms->atom[i].atomnumber = atomnumber;
617 element = aps->elementFromAtomNumber(atomnumber);
620 fprintf(debug, "Atomnumber for atom '%s' is %d\n", anm, atomnumber);
623 element.resize(sc_maxElementNameLength);
624 std::strcpy(atoms->atom[i].elem, element.c_str());
629 read_atom(t_symtab* symtab, const char line[], PdbRecordType type, int natom, t_atoms* atoms, rvec x[], int chainnum)
634 char anr[12], anm[12], anm_copy[12], altloc, resnm[12], rnr[12], elem[3];
635 char xc[12], yc[12], zc[12], occup[12], bfac[12];
638 int resnr, atomnumber;
640 if (natom >= atoms->nr)
642 gmx_fatal(FARGS, "\nFound more atoms (%d) in pdb file than expected (%d)", natom + 1, atoms->nr);
647 for (k = 0; (k < 5); k++, j++)
654 for (k = 0; (k < 4); k++, j++)
659 std::strcpy(anm_copy, anm);
665 for (k = 0; (k < 4); k++, j++)
675 for (k = 0; (k < 4); k++, j++)
681 resnr = std::strtol(rnr, nullptr, 10);
685 /* X,Y,Z Coordinate */
686 for (k = 0; (k < 8); k++, j++)
691 for (k = 0; (k < 8); k++, j++)
696 for (k = 0; (k < 8); k++, j++)
703 for (k = 0; (k < 6); k++, j++)
710 for (k = 0; (k < 7); k++, j++)
720 for (k = 0; (k < 2); k++, j++)
729 atomn = &(atoms->atom[natom]);
730 if ((natom == 0) || atoms->resinfo[atoms->atom[natom - 1].resind].nr != resnr
731 || atoms->resinfo[atoms->atom[natom - 1].resind].ic != resic
732 || (strcmp(*atoms->resinfo[atoms->atom[natom - 1].resind].name, resnm) != 0))
740 atomn->resind = atoms->atom[natom - 1].resind + 1;
742 atoms->nres = atomn->resind + 1;
743 t_atoms_set_resinfo(atoms, natom, symtab, resnm, resnr, resic, chainnum, chainid);
747 atomn->resind = atoms->atom[natom - 1].resind;
749 atoms->atomname[natom] = put_symtab(symtab, anm);
752 atomn->atomnumber = atomnumber;
753 strncpy(atomn->elem, elem, 4);
755 x[natom][XX] = strtod(xc, nullptr) * 0.1;
756 x[natom][YY] = strtod(yc, nullptr) * 0.1;
757 x[natom][ZZ] = strtod(zc, nullptr) * 0.1;
760 atoms->pdbinfo[natom].type = type;
761 atoms->pdbinfo[natom].atomnr = strtol(anr, nullptr, 10);
762 atoms->pdbinfo[natom].altloc = altloc;
763 strcpy(atoms->pdbinfo[natom].atomnm, anm_copy);
764 atoms->pdbinfo[natom].bfac = strtod(bfac, nullptr);
765 atoms->pdbinfo[natom].occup = strtod(occup, nullptr);
772 gmx_bool is_hydrogen(const char* nm)
776 std::strcpy(buf, nm);
779 return ((buf[0] == 'H') || ((std::isdigit(buf[0]) != 0) && (buf[1] == 'H')));
782 gmx_bool is_dummymass(const char* nm)
786 std::strcpy(buf, nm);
789 return (buf[0] == 'M') && (std::isdigit(buf[strlen(buf) - 1]) != 0);
792 static void gmx_conect_addline(gmx_conect_t* con, char* line)
796 std::string form2 = "%*s";
797 std::string format = form2 + "%d";
798 if (sscanf(line, format.c_str(), &ai) == 1)
803 format = form2 + "%d";
804 n = sscanf(line, format.c_str(), &aj);
807 gmx_conect_add(con, ai - 1, aj - 1); /* to prevent duplicated records */
813 void gmx_conect_dump(FILE* fp, gmx_conect conect)
815 gmx_conect_t* gc = static_cast<gmx_conect_t*>(conect);
818 for (i = 0; (i < gc->nconect); i++)
820 fprintf(fp, "%6s%5d%5d\n", "CONECT", gc->conect[i].ai + 1, gc->conect[i].aj + 1);
824 gmx_conect gmx_conect_init()
833 void gmx_conect_done(gmx_conect conect)
835 gmx_conect_t* gc = conect;
840 gmx_bool gmx_conect_exist(gmx_conect conect, int ai, int aj)
842 gmx_conect_t* gc = conect;
848 for (i = 0; (i < gc->nconect); i++)
850 if (((gc->conect[i].ai == ai) && (gc->conect[i].aj == aj))
851 || ((gc->conect[i].aj == ai) && (gc->conect[i].ai == aj)))
859 void gmx_conect_add(gmx_conect conect, int ai, int aj)
861 gmx_conect_t* gc = static_cast<gmx_conect_t*>(conect);
866 if (!gmx_conect_exist(conect, ai, aj))
868 srenew(gc->conect, ++gc->nconect);
869 gc->conect[gc->nconect - 1].ai = ai;
870 gc->conect[gc->nconect - 1].aj = aj;
874 int read_pdbfile(FILE* in,
884 gmx_conect_t* gc = conect;
886 gmx_bool bConnWarn = FALSE;
887 char line[STRLEN + 1];
890 gmx_bool bStop = FALSE;
894 /* Only assume pbc when there is a CRYST1 entry */
895 *pbcType = PbcType::No;
902 atoms->haveMass = FALSE;
903 atoms->haveCharge = FALSE;
904 atoms->haveType = FALSE;
905 atoms->haveBState = FALSE;
906 atoms->havePdbInfo = (atoms->pdbinfo != nullptr);
912 static const gmx::StringToEnumValueConverter<PdbRecordType, enumValueToString, gmx::StringCompareType::Exact, gmx::StripStrings::Yes>
913 sc_pdbRecordTypeIdentifier;
914 while (!bStop && (fgets2(line, STRLEN, in) != nullptr))
916 // Convert line to a null-terminated string, then take a substring of at most 6 chars
917 std::string lineAsString(line);
918 std::optional<PdbRecordType> line_type =
919 sc_pdbRecordTypeIdentifier.valueFrom(lineAsString.substr(0, 6));
922 // Skip this line because it does not start with a
923 // recognized leading string describing a PDB record type.
927 switch (line_type.value())
929 case PdbRecordType::Atom:
930 case PdbRecordType::Hetatm:
931 natom = read_atom(symtab, line, line_type.value(), natom, atoms, x, chainnum);
934 case PdbRecordType::Anisou:
935 if (atoms->havePdbInfo)
937 read_anisou(line, natom, atoms);
941 case PdbRecordType::Cryst1: read_cryst1(line, pbcType, box); break;
943 case PdbRecordType::Title:
944 case PdbRecordType::Header:
945 if (std::strlen(line) > 6)
948 /* skip HEADER or TITLE and spaces */
957 /* truncate after title */
958 d = std::strstr(c, " ");
963 if (std::strlen(c) > 0)
965 std::strcpy(title, c);
970 case PdbRecordType::Compound:
971 if ((!std::strstr(line, ": ")) || (std::strstr(line + 6, "MOLECULE:")))
973 if (!(c = std::strstr(line + 6, "MOLECULE:")))
977 /* skip 'MOLECULE:' and spaces */
986 /* truncate after title */
990 while ((d[-1] == ';') && d > c)
1000 std::strcat(title, "; ");
1001 std::strcat(title, c);
1005 std::strcpy(title, c);
1012 case PdbRecordType::Ter: chainnum++; break;
1014 case PdbRecordType::Model:
1017 sscanf(line, "%*s%d", model_nr);
1021 case PdbRecordType::EndModel: bStop = TRUE; break;
1022 case PdbRecordType::Conect:
1025 gmx_conect_addline(gc, line);
1027 else if (!bConnWarn)
1029 fprintf(stderr, "WARNING: all CONECT records are ignored\n");
1041 void get_pdb_coordnum(FILE* in, int* natoms)
1046 while (fgets2(line, STRLEN, in))
1048 if (std::strncmp(line, "ENDMDL", 6) == 0)
1052 if ((std::strncmp(line, "ATOM ", 6) == 0) || (std::strncmp(line, "HETATM", 6) == 0))
1059 void gmx_pdb_read_conf(const char* infile, t_symtab* symtab, char** name, t_atoms* atoms, rvec x[], PbcType* pbcType, matrix box)
1061 FILE* in = gmx_fio_fopen(infile, "r");
1063 read_pdbfile(in, title, nullptr, atoms, symtab, x, pbcType, box, nullptr);
1064 if (name != nullptr)
1066 *name = gmx_strdup(title);
1071 gmx_conect gmx_conect_generate(const t_topology* top)
1076 /* Fill the conect records */
1077 gc = gmx_conect_init();
1079 for (f = 0; (f < F_NRE); f++)
1083 for (i = 0; (i < top->idef.il[f].nr); i += interaction_function[f].nratoms + 1)
1085 gmx_conect_add(gc, top->idef.il[f].iatoms[i + 1], top->idef.il[f].iatoms[i + 2]);
1092 int gmx_fprintf_pdb_atomline(FILE* fp,
1093 PdbRecordType record,
1094 int atom_seq_number,
1095 const char* atom_name,
1096 char alternate_location,
1097 const char* res_name,
1100 char res_insertion_code,
1106 const char* element)
1108 char tmp_atomname[6], tmp_resname[6];
1109 gmx_bool start_name_in_col13;
1112 if (record != PdbRecordType::Atom && record != PdbRecordType::Hetatm)
1114 gmx_fatal(FARGS, "Can only print PDB atom lines as ATOM or HETATM records");
1117 /* Format atom name */
1118 if (atom_name != nullptr)
1120 /* If the atom name is an element name with two chars, it should start already in column 13.
1121 * Otherwise it should start in column 14, unless the name length is 4 chars.
1123 if ((element != nullptr) && (std::strlen(element) >= 2)
1124 && (gmx_strncasecmp(atom_name, element, 2) == 0))
1126 start_name_in_col13 = TRUE;
1130 start_name_in_col13 = (std::strlen(atom_name) >= 4);
1132 snprintf(tmp_atomname, sizeof(tmp_atomname), start_name_in_col13 ? "" : " ");
1133 std::strncat(tmp_atomname, atom_name, 4);
1134 tmp_atomname[5] = '\0';
1138 tmp_atomname[0] = '\0';
1141 /* Format residue name */
1142 std::strncpy(tmp_resname, (res_name != nullptr) ? res_name : "", 4);
1143 /* Make sure the string is terminated if strlen was > 4 */
1144 tmp_resname[4] = '\0';
1145 /* String is properly terminated, so now we can use strcat. By adding a
1146 * space we can write it right-justified, and if the original name was
1147 * three characters or less there will be a space added on the right side.
1149 std::strcat(tmp_resname, " ");
1151 /* Truncate integers so they fit */
1152 atom_seq_number = atom_seq_number % 100000;
1153 res_seq_number = res_seq_number % 10000;
1156 "%-6s%5d %-4.4s%c%4.4s%c%4d%c %8.3f%8.3f%8.3f%6.2f%6.2f %2s\n",
1157 enumValueToString(record),
1170 (element != nullptr) ? element : "");