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/trxio.h"
48 #include "gromacs/fileio/checkpoint.h"
49 #include "gromacs/fileio/confio.h"
50 #include "gromacs/fileio/filetypes.h"
51 #include "gromacs/fileio/g96io.h"
52 #include "gromacs/fileio/gmxfio.h"
53 #include "gromacs/fileio/gmxfio_xdr.h"
54 #include "gromacs/fileio/groio.h"
55 #include "gromacs/fileio/oenv.h"
56 #include "gromacs/fileio/pdbio.h"
57 #include "gromacs/fileio/timecontrol.h"
58 #include "gromacs/fileio/tngio.h"
59 #include "gromacs/fileio/tpxio.h"
60 #include "gromacs/fileio/trrio.h"
61 #include "gromacs/fileio/xdrf.h"
62 #include "gromacs/fileio/xtcio.h"
63 #include "gromacs/math/vec.h"
64 #include "gromacs/mdtypes/md_enums.h"
65 #include "gromacs/topology/atoms.h"
66 #include "gromacs/topology/symtab.h"
67 #include "gromacs/topology/topology.h"
68 #include "gromacs/trajectory/trajectoryframe.h"
69 #include "gromacs/utility/fatalerror.h"
70 #include "gromacs/utility/futil.h"
71 #include "gromacs/utility/gmxassert.h"
72 #include "gromacs/utility/smalloc.h"
75 # include "gromacs/fileio/vmdio.h"
78 /* defines for frame counter output */
85 int flags; /* flags for read_first/next_frame */
87 real t0; /* time of the first frame, needed *
88 * for skipping frames with -dt */
89 real tf; /* internal frame time */
92 gmx_tng_trajectory_t tng;
96 char* persistent_line; /* Persistent line for reading g96 trajectories */
98 gmx_vmdplugin_t* vmdplugin;
102 /* utility functions */
104 gmx_bool bRmod_fd(double a, double b, double c, gmx_bool bDouble)
109 tol = 2 * (bDouble ? GMX_DOUBLE_EPS : GMX_FLOAT_EPS);
111 iq = static_cast<int>((a - b + tol * a) / c);
113 return fabs(a - b - c * iq) <= tol * fabs(a);
117 int check_times2(real t, real t0, gmx_bool bDouble)
122 /* since t is float, we can not use double precision for bRmod */
127 if ((!bTimeSet(TimeControl::Begin) || (t >= rTimeValue(TimeControl::Begin)))
128 && (!bTimeSet(TimeControl::End) || (t <= rTimeValue(TimeControl::End))))
130 if (bTimeSet(TimeControl::Delta) && !bRmod_fd(t, t0, rTimeValue(TimeControl::Delta), bDouble))
139 else if (bTimeSet(TimeControl::End) && (t >= rTimeValue(TimeControl::End)))
146 "t=%g, t0=%g, b=%g, e=%g, dt=%g: r=%d\n",
149 rTimeValue(TimeControl::Begin),
150 rTimeValue(TimeControl::End),
151 rTimeValue(TimeControl::Delta),
157 int check_times(real t)
159 return check_times2(t, t, FALSE);
162 static void initcount(t_trxstatus* status)
164 status->currentFrame = -1;
167 static void status_init(t_trxstatus* status)
170 status->xframe = nullptr;
171 status->fio = nullptr;
172 status->currentFrame = -1;
175 status->persistent_line = nullptr;
176 status->tng = nullptr;
180 int nframes_read(t_trxstatus* status)
182 return status->currentFrame;
185 static void printcount_(t_trxstatus* status, const gmx_output_env_t* oenv, const char* l, real t)
187 if ((status->currentFrame < 2 * SKIP1 || status->currentFrame % SKIP1 == 0)
188 && (status->currentFrame < 2 * SKIP2 || status->currentFrame % SKIP2 == 0)
189 && (status->currentFrame < 2 * SKIP3 || status->currentFrame % SKIP3 == 0)
190 && output_env_get_trajectory_io_verbosity(oenv) != 0)
192 fprintf(stderr, "\r%-14s %6d time %8.3f ", l, status->currentFrame, output_env_conv_time(oenv, t));
197 static void printcount(t_trxstatus* status, const gmx_output_env_t* oenv, real t, gmx_bool bSkip)
199 status->currentFrame++;
200 printcount_(status, oenv, bSkip ? "Skipping frame" : "Reading frame", t);
203 static void printlast(t_trxstatus* status, const gmx_output_env_t* oenv, real t)
205 printcount_(status, oenv, "Last frame", t);
206 fprintf(stderr, "\n");
210 static void printincomp(t_trxstatus* status, t_trxframe* fr)
212 if (fr->not_ok & HEADER_NOT_OK)
214 fprintf(stderr, "WARNING: Incomplete header: nr %d time %g\n", status->currentFrame + 1, fr->time);
218 fprintf(stderr, "WARNING: Incomplete frame: nr %d time %g\n", status->currentFrame + 1, fr->time);
223 int prec2ndec(real prec)
227 gmx_fatal(FARGS, "DEATH HORROR prec (%g) <= 0 in prec2ndec", prec);
230 return gmx::roundToInt(log(prec) / log(10.0));
233 real ndec2prec(int ndec)
235 return pow(10.0, ndec);
238 t_fileio* trx_get_fileio(t_trxstatus* status)
243 float trx_get_time_of_final_frame(t_trxstatus* status)
245 t_fileio* stfio = trx_get_fileio(status);
246 int filetype = gmx_fio_getftp(stfio);
250 if (filetype == efXTC)
252 lasttime = xdr_xtc_get_last_frame_time(
253 gmx_fio_getfp(stfio), gmx_fio_getxdr(stfio), status->natoms, &bOK);
256 gmx_fatal(FARGS, "Error reading last frame. Maybe seek not supported.");
259 else if (filetype == efTNG)
261 gmx_tng_trajectory_t tng = status->tng;
264 gmx_fatal(FARGS, "Error opening TNG file.");
266 lasttime = gmx_tng_get_time_of_final_frame(tng);
270 gmx_incons("Only supported for TNG and XTC");
275 void clear_trxframe(t_trxframe* fr, gmx_bool bFirst)
281 fr->bFepState = FALSE;
303 fr->pbcType = PbcType::Unset;
307 void setTrxFramePbcType(t_trxframe* fr, PbcType pbcType)
309 fr->bPBC = (pbcType == PbcType::Unset);
310 fr->pbcType = pbcType;
313 int write_trxframe_indexed(t_trxstatus* status, const t_trxframe* fr, int nind, const int* ind, gmx_conect gc)
316 rvec *xout = nullptr, *vout = nullptr, *fout = nullptr;
333 else if (status->fio)
335 ftp = gmx_fio_getftp(status->fio);
339 gmx_incons("No input file available");
349 gmx_fatal(FARGS, "Need coordinates to write a %s trajectory", ftp2ext(ftp));
361 for (i = 0; i < nind; i++)
363 copy_rvec(fr->v[ind[i]], vout[i]);
369 for (i = 0; i < nind; i++)
371 copy_rvec(fr->f[ind[i]], fout[i]);
377 for (i = 0; i < nind; i++)
379 copy_rvec(fr->x[ind[i]], xout[i]);
387 for (i = 0; i < nind; i++)
389 copy_rvec(fr->x[ind[i]], xout[i]);
398 case efTNG: gmx_write_tng_from_trxframe(status->tng, fr, nind); break;
399 case efXTC: write_xtc(status->fio, nind, fr->step, fr->time, fr->box, xout, prec); break;
402 status->fio, nframes_read(status), fr->time, fr->step, fr->box, nind, xout, vout, fout);
410 gmx_fatal(FARGS, "Can not write a %s file without atom names", ftp2ext(ftp));
412 sprintf(title, "frame t= %.3f", fr->time);
415 write_hconf_indexed_p(gmx_fio_getfp(status->fio),
421 fr->bV ? fr->v : nullptr,
426 write_pdbfile_indexed(gmx_fio_getfp(status->fio),
441 sprintf(title, "frame t= %.3f", fr->time);
442 write_g96_conf(gmx_fio_getfp(status->fio), title, fr, nind, ind);
444 default: gmx_fatal(FARGS, "Sorry, write_trxframe_indexed can not write %s", ftp2ext(ftp));
461 case efXTC: sfree(xout); break;
468 t_trxstatus* trjtools_gmx_prepare_tng_writing(const char* filename,
473 const gmx_mtop_t* mtop,
474 gmx::ArrayRef<const int> index,
475 const char* index_group_name)
477 if (filemode != 'w' && filemode != 'a')
479 gmx_incons("Sorry, can only prepare for TNG output.");
487 gmx_prepare_tng_writing(
488 filename, filemode, &in->tng, &out->tng, natoms, mtop, index, index_group_name);
490 else if ((infile) && (efTNG == fn2ftp(infile)))
492 gmx_tng_trajectory_t tng_in;
493 gmx_tng_open(infile, 'r', &tng_in);
495 gmx_prepare_tng_writing(
496 filename, filemode, &tng_in, &out->tng, natoms, mtop, index, index_group_name);
500 // we start from a file that is not a tng file or have been unable to load the
501 // input file, so we need to populate the fields independently of it
502 gmx_prepare_tng_writing(
503 filename, filemode, nullptr, &out->tng, natoms, mtop, index, index_group_name);
508 void write_tng_frame(t_trxstatus* status, t_trxframe* frame)
510 gmx_write_tng_from_trxframe(status->tng, frame, -1);
513 int write_trxframe(t_trxstatus* status, t_trxframe* fr, gmx_conect gc)
530 gmx_tng_set_compression_precision(status->tng, prec);
531 write_tng_frame(status, fr);
536 switch (gmx_fio_getftp(status->fio))
543 "Need coordinates to write a %s trajectory",
544 ftp2ext(gmx_fio_getftp(status->fio)));
549 switch (gmx_fio_getftp(status->fio))
552 write_xtc(status->fio, fr->natoms, fr->step, fr->time, fr->box, fr->x, prec);
555 gmx_trr_write_frame(status->fio,
561 fr->bX ? fr->x : nullptr,
562 fr->bV ? fr->v : nullptr,
563 fr->bF ? fr->f : nullptr);
572 "Can not write a %s file without atom names",
573 ftp2ext(gmx_fio_getftp(status->fio)));
575 sprintf(title, "frame t= %.3f", fr->time);
576 if (gmx_fio_getftp(status->fio) == efGRO)
579 gmx_fio_getfp(status->fio), title, fr->atoms, fr->x, fr->bV ? fr->v : nullptr, fr->box);
583 write_pdbfile(gmx_fio_getfp(status->fio),
587 fr->bPBC ? fr->pbcType : PbcType::Unset,
594 case efG96: write_g96_conf(gmx_fio_getfp(status->fio), title, fr, -1, nullptr); break;
596 gmx_fatal(FARGS, "Sorry, write_trxframe can not write %s", ftp2ext(gmx_fio_getftp(status->fio)));
602 int write_trx(t_trxstatus* status,
605 const t_atoms* atoms,
615 clear_trxframe(&fr, TRUE);
620 fr.bAtoms = atoms != nullptr;
621 fr.atoms = const_cast<t_atoms*>(atoms);
624 fr.bV = v != nullptr;
627 copy_mat(box, fr.box);
629 return write_trxframe_indexed(status, &fr, nind, ind, gc);
632 void close_trx(t_trxstatus* status)
634 if (status == nullptr)
638 gmx_tng_close(&status->tng);
641 gmx_fio_close(status->fio);
643 sfree(status->persistent_line);
645 sfree(status->vmdplugin);
647 /* The memory in status->xframe is lost here,
648 * but the read_first_x/read_next_x functions are deprecated anyhow.
649 * read_first_frame/read_next_frame and close_trx should be used.
654 void done_trx_xframe(t_trxstatus* status)
656 done_frame(status->xframe);
657 sfree(status->xframe);
660 t_trxstatus* open_trx(const char* outfile, const char* filemode)
663 if (filemode[0] != 'w' && filemode[0] != 'a' && filemode[1] != '+')
665 gmx_fatal(FARGS, "Sorry, write_trx can only write");
671 stat->fio = gmx_fio_open(outfile, filemode);
675 static gmx_bool gmx_next_frame(t_trxstatus* status, t_trxframe* fr)
682 if (gmx_trr_read_frame_header(status->fio, &sh, &bOK))
684 fr->bDouble = sh.bDouble;
685 fr->natoms = sh.natoms;
691 fr->bFepState = TRUE;
692 fr->lambda = sh.lambda;
693 fr->bBox = sh.box_size > 0;
694 if (status->flags & (TRX_READ_X | TRX_NEED_X))
696 if (fr->x == nullptr)
698 snew(fr->x, sh.natoms);
700 fr->bX = sh.x_size > 0;
702 if (status->flags & (TRX_READ_V | TRX_NEED_V))
704 if (fr->v == nullptr)
706 snew(fr->v, sh.natoms);
708 fr->bV = sh.v_size > 0;
710 if (status->flags & (TRX_READ_F | TRX_NEED_F))
712 if (fr->f == nullptr)
714 snew(fr->f, sh.natoms);
716 fr->bF = sh.f_size > 0;
718 if (gmx_trr_read_frame_data(status->fio, &sh, fr->box, fr->x, fr->v, fr->f))
724 fr->not_ok = DATA_NOT_OK;
729 fr->not_ok = HEADER_NOT_OK;
735 static gmx_bool pdb_next_x(t_trxstatus* status, FILE* fp, t_trxframe* fr)
740 // Initiate model_nr to -1 rather than NOTSET.
741 // It is not worthwhile introducing extra variables in the
742 // read_pdbfile call to verify that a model_nr was read.
744 int model_nr = -1, na;
745 char title[STRLEN], *time, *step;
748 atoms.nr = fr->natoms;
749 atoms.atom = nullptr;
750 atoms.pdbinfo = nullptr;
751 /* the other pointers in atoms should not be accessed if these are NULL */
754 na = read_pdbfile(fp, title, &model_nr, &atoms, symtab, fr->x, &pbcType, boxpdb, nullptr);
757 setTrxFramePbcType(fr, pbcType);
758 if (nframes_read(status) == 0)
760 fprintf(stderr, " '%s', %d atoms\n", title, fr->natoms);
765 fr->bBox = (boxpdb[XX][XX] != 0.0);
768 copy_mat(boxpdb, fr->box);
772 step = std::strstr(title, " step= ");
773 fr->bStep = ((step != nullptr) && sscanf(step + 7, "%" SCNd64, &fr->step) == 1);
776 time = std::strstr(title, " t= ");
777 fr->bTime = ((time != nullptr) && sscanf(time + 4, "%lf", &dbl) == 1);
786 if (na != fr->natoms)
789 "Number of atoms in pdb frame %d is %d instead of %d",
790 nframes_read(status),
798 static int pdb_first_x(t_trxstatus* status, FILE* fp, t_trxframe* fr)
802 fprintf(stderr, "Reading frames from pdb file");
804 get_pdb_coordnum(fp, &fr->natoms);
807 gmx_fatal(FARGS, "\nNo coordinates in pdb file\n");
810 snew(fr->x, fr->natoms);
811 pdb_next_x(status, fp, fr);
816 bool read_next_frame(const gmx_output_env_t* oenv, t_trxstatus* status, t_trxframe* fr)
820 gmx_bool bOK, bMissingData = FALSE, bSkip = FALSE;
828 clear_trxframe(fr, FALSE);
832 /* Special treatment for TNG files */
837 ftp = gmx_fio_getftp(status->fio);
841 case efTRR: bRet = gmx_next_frame(status, fr); break;
843 /* Checkpoint files can not contain mulitple frames */
847 t_symtab* symtab = nullptr;
848 read_g96_conf(gmx_fio_getfp(status->fio), nullptr, nullptr, fr, symtab, status->persistent_line);
849 bRet = (fr->natoms > 0);
853 if (bTimeSet(TimeControl::Begin) && (status->tf < rTimeValue(TimeControl::Begin)))
855 if (xtc_seek_time(status->fio, rTimeValue(TimeControl::Begin), fr->natoms, TRUE))
858 "Specified frame (time %f) doesn't exist or file "
859 "corrupt/inconsistent.",
860 rTimeValue(TimeControl::Begin));
864 bRet = (read_next_xtc(
865 status->fio, fr->natoms, &fr->step, &fr->time, fr->box, fr->x, &fr->prec, &bOK)
867 fr->bPrec = (bRet && fr->prec > 0);
874 /* Actually the header could also be not ok,
875 but from bOK from read_next_xtc this can't be distinguished */
876 fr->not_ok = DATA_NOT_OK;
879 case efTNG: bRet = gmx_read_next_tng_frame(status->tng, fr, nullptr, 0); break;
880 case efPDB: bRet = pdb_next_x(status, gmx_fio_getfp(status->fio), fr); break;
881 case efGRO: bRet = gro_next_x_or_v(gmx_fio_getfp(status->fio), fr); break;
884 bRet = read_next_vmd_frame(status->vmdplugin, fr);
887 "DEATH HORROR in read_next_frame ftp=%s,status=%s",
888 ftp2ext(gmx_fio_getftp(status->fio)),
889 gmx_fio_getname(status->fio));
892 status->tf = fr->time;
896 bMissingData = ((((status->flags & TRX_NEED_X) != 0) && !fr->bX)
897 || (((status->flags & TRX_NEED_V) != 0) && !fr->bV)
898 || (((status->flags & TRX_NEED_F) != 0) && !fr->bF));
902 ct = check_times2(fr->time, status->t0, fr->bDouble);
903 if (ct == 0 || ((status->flags & TRX_DONT_SKIP) && ct < 0))
905 printcount(status, oenv, fr->time, FALSE);
913 printcount(status, oenv, fr->time, TRUE);
919 } while (bRet && (bMissingData || bSkip));
923 printlast(status, oenv, pt);
926 printincomp(status, fr);
933 bool read_first_frame(const gmx_output_env_t* oenv, t_trxstatus** status, const char* fn, t_trxframe* fr, int flags)
935 t_fileio* fio = nullptr;
936 gmx_bool bFirst, bOK;
937 int ftp = fn2ftp(fn);
939 clear_trxframe(fr, TRUE);
945 status_init(*status);
947 (*status)->flags = flags;
951 /* Special treatment for TNG files */
952 gmx_tng_open(fn, 'r', &(*status)->tng);
956 fio = (*status)->fio = gmx_fio_open(fn, "r");
962 read_checkpoint_trxframe(fio, fr);
967 /* Can not rewind a compressed file, so open it twice */
968 if (!(*status)->persistent_line)
970 /* allocate the persistent line */
971 snew((*status)->persistent_line, STRLEN + 1);
973 t_symtab* symtab = nullptr;
974 read_g96_conf(gmx_fio_getfp(fio), fn, nullptr, fr, symtab, (*status)->persistent_line);
976 clear_trxframe(fr, FALSE);
977 if (flags & (TRX_READ_X | TRX_NEED_X))
979 snew(fr->x, fr->natoms);
981 if (flags & (TRX_READ_V | TRX_NEED_V))
983 snew(fr->v, fr->natoms);
985 (*status)->fio = gmx_fio_open(fn, "r");
989 if (read_first_xtc(fio, &fr->natoms, &fr->step, &fr->time, fr->box, &fr->x, &fr->prec, &bOK) == 0)
991 GMX_RELEASE_ASSERT(!bOK,
992 "Inconsistent results - OK status from read_first_xtc, but 0 "
994 fr->not_ok = DATA_NOT_OK;
999 printincomp(*status, fr);
1003 fr->bPrec = (fr->prec > 0);
1008 printcount(*status, oenv, fr->time, FALSE);
1014 if (!gmx_read_next_tng_frame((*status)->tng, fr, nullptr, 0))
1016 fr->not_ok = DATA_NOT_OK;
1018 printincomp(*status, fr);
1022 printcount(*status, oenv, fr->time, FALSE);
1027 pdb_first_x(*status, gmx_fio_getfp(fio), fr);
1030 printcount(*status, oenv, fr->time, FALSE);
1035 if (gro_first_x_or_v(gmx_fio_getfp(fio), fr))
1037 printcount(*status, oenv, fr->time, FALSE);
1044 "The file format of %s is not a known trajectory format to GROMACS.\n"
1045 "Please make sure that the file is a trajectory!\n"
1046 "GROMACS will now assume it to be a trajectory and will try to open it using "
1047 "the VMD plug-ins.\n"
1048 "This will only work in case the VMD plugins are found and it is a trajectory "
1049 "format supported by VMD.\n",
1051 gmx_fio_fp_close(fio); /*only close the file without removing FIO entry*/
1052 if (!read_first_vmd_frame(fn, &(*status)->vmdplugin, fr))
1054 gmx_fatal(FARGS, "Not supported in read_first_frame: %s", fn);
1058 "Not supported in read_first_frame: %s. Please make sure that the file is a "
1060 "GROMACS is not compiled with plug-in support. Thus it cannot read "
1061 "non-GROMACS trajectory formats using the VMD plug-ins.\n"
1062 "Please compile with plug-in support if you want to read non-GROMACS "
1063 "trajectory formats.\n",
1067 (*status)->tf = fr->time;
1069 /* Return FALSE if we read a frame that's past the set ending time. */
1070 if (!bFirst && (!(flags & TRX_DONT_SKIP) && check_times(fr->time) > 0))
1072 (*status)->t0 = fr->time;
1076 if (bFirst || (!(flags & TRX_DONT_SKIP) && check_times(fr->time) < 0))
1078 /* Read a frame when no frame was read or the first was skipped */
1079 if (!read_next_frame(oenv, *status, fr))
1084 (*status)->t0 = fr->time;
1086 /* We need the number of atoms for random-access XTC searching, even when
1087 * we don't have access to the actual frame data.
1089 (*status)->natoms = fr->natoms;
1091 return (fr->natoms > 0);
1094 /***** C O O R D I N A T E S T U F F *****/
1096 int read_first_x(const gmx_output_env_t* oenv, t_trxstatus** status, const char* fn, real* t, rvec** x, matrix box)
1100 read_first_frame(oenv, status, fn, &fr, TRX_NEED_X);
1102 snew((*status)->xframe, 1);
1103 (*(*status)->xframe) = fr;
1104 *t = (*status)->xframe->time;
1105 *x = (*status)->xframe->x;
1106 copy_mat((*status)->xframe->box, box);
1108 return (*status)->xframe->natoms;
1111 gmx_bool read_next_x(const gmx_output_env_t* oenv, t_trxstatus* status, real* t, rvec x[], matrix box)
1115 status->xframe->x = x;
1116 /*xframe[status].x = x;*/
1117 bRet = read_next_frame(oenv, status, status->xframe);
1118 *t = status->xframe->time;
1119 copy_mat(status->xframe->box, box);
1124 void rewind_trj(t_trxstatus* status)
1128 gmx_fio_rewind(status->fio);
1131 /***** T O P O L O G Y S T U F F ******/
1133 t_topology* read_top(const char* fn, PbcType* pbcType)
1136 PbcType pbcTypeFile;
1140 pbcTypeFile = read_tpx_top(fn, nullptr, nullptr, &natoms, nullptr, nullptr, top);
1143 *pbcType = pbcTypeFile;