Move fileio sources to C++
[alexxy/gromacs.git] / src / gromacs / fileio / trxio.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, 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 "trxio.h"
40
41 #include "config.h"
42
43 #include <cassert>
44 #include <cmath>
45
46 #include "gromacs/fileio/confio.h"
47 #include "gromacs/fileio/gmxfio.h"
48 #include "gromacs/fileio/gmxfio-xdr.h"
49 #include "gromacs/fileio/pdbio.h"
50 #include "gromacs/fileio/timecontrol.h"
51 #include "gromacs/fileio/tngio.h"
52 #include "gromacs/fileio/tngio_for_tools.h"
53 #include "gromacs/fileio/tpxio.h"
54 #include "gromacs/fileio/trnio.h"
55 #include "gromacs/fileio/trx.h"
56 #include "gromacs/fileio/xdrf.h"
57 #include "gromacs/fileio/xtcio.h"
58 #include "gromacs/legacyheaders/checkpoint.h"
59 #include "gromacs/legacyheaders/names.h"
60 #include "gromacs/math/vec.h"
61 #include "gromacs/topology/atoms.h"
62 #include "gromacs/utility/fatalerror.h"
63 #include "gromacs/utility/futil.h"
64 #include "gromacs/utility/gmxassert.h"
65 #include "gromacs/utility/smalloc.h"
66
67 #ifdef GMX_USE_PLUGINS
68 #include "gromacs/fileio/vmdio.h"
69 #endif
70
71 /* defines for frame counter output */
72 #define SKIP1   10
73 #define SKIP2  100
74 #define SKIP3 1000
75
76 struct t_trxstatus
77 {
78     int                     __frame;
79     t_trxframe             *xframe;
80     int                     nxframe;
81     t_fileio               *fio;
82     tng_trajectory_t        tng;
83     int                     natoms;
84     double                  DT, BOX[3];
85     gmx_bool                bReadBox;
86     char                   *persistent_line; /* Persistent line for reading g96 trajectories */
87 };
88
89 /* utility functions */
90
91 gmx_bool bRmod_fd(double a, double b, double c, gmx_bool bDouble)
92 {
93     int    iq;
94     double tol;
95
96     tol = 2*(bDouble ? GMX_DOUBLE_EPS : GMX_FLOAT_EPS);
97
98     iq = (int)((a - b + tol*a)/c);
99
100     if (fabs(a - b - c*iq) <= tol*fabs(a))
101     {
102         return TRUE;
103     }
104     else
105     {
106         return FALSE;
107     }
108 }
109
110
111
112 int check_times2(real t, real t0, gmx_bool bDouble)
113 {
114     int  r;
115
116 #ifndef GMX_DOUBLE
117     /* since t is float, we can not use double precision for bRmod */
118     bDouble = FALSE;
119 #endif
120
121     r = -1;
122     if ((!bTimeSet(TBEGIN) || (t >= rTimeValue(TBEGIN)))  &&
123         (!bTimeSet(TEND)   || (t <= rTimeValue(TEND))))
124     {
125         if (bTimeSet(TDELTA) && !bRmod_fd(t, t0, rTimeValue(TDELTA), bDouble))
126         {
127             r = -1;
128         }
129         else
130         {
131             r = 0;
132         }
133     }
134     else if (bTimeSet(TEND) && (t >= rTimeValue(TEND)))
135     {
136         r = 1;
137     }
138     if (debug)
139     {
140         fprintf(debug, "t=%g, t0=%g, b=%g, e=%g, dt=%g: r=%d\n",
141                 t, t0, rTimeValue(TBEGIN), rTimeValue(TEND), rTimeValue(TDELTA), r);
142     }
143     return r;
144 }
145
146 int check_times(real t)
147 {
148     return check_times2(t, t, FALSE);
149 }
150
151 static void initcount(t_trxstatus *status)
152 {
153     status->__frame = -1;
154 }
155
156 static void status_init(t_trxstatus *status)
157 {
158     status->nxframe         = 0;
159     status->xframe          = NULL;
160     status->fio             = NULL;
161     status->__frame         = -1;
162     status->persistent_line = NULL;
163     status->tng             = NULL;
164 }
165
166
167 int nframes_read(t_trxstatus *status)
168 {
169     return status->__frame;
170 }
171
172 static void printcount_(t_trxstatus *status, const output_env_t oenv,
173                         const char *l, real t)
174 {
175     if ((status->__frame < 2*SKIP1 || status->__frame % SKIP1 == 0) &&
176         (status->__frame < 2*SKIP2 || status->__frame % SKIP2 == 0) &&
177         (status->__frame < 2*SKIP3 || status->__frame % SKIP3 == 0))
178     {
179         fprintf(stderr, "\r%-14s %6d time %8.3f   ", l, status->__frame,
180                 output_env_conv_time(oenv, t));
181     }
182 }
183
184 static void printcount(t_trxstatus *status, const output_env_t oenv, real t,
185                        gmx_bool bSkip)
186 {
187     status->__frame++;
188     printcount_(status, oenv, bSkip ? "Skipping frame" : "Reading frame", t);
189 }
190
191 static void printlast(t_trxstatus *status, const output_env_t oenv, real t)
192 {
193     printcount_(status, oenv, "Last frame", t);
194     fprintf(stderr, "\n");
195 }
196
197 static void printincomp(t_trxstatus *status, t_trxframe *fr)
198 {
199     if (fr->not_ok & HEADER_NOT_OK)
200     {
201         fprintf(stderr, "WARNING: Incomplete header: nr %d time %g\n",
202                 status->__frame+1, fr->time);
203     }
204     else if (fr->not_ok)
205     {
206         fprintf(stderr, "WARNING: Incomplete frame: nr %d time %g\n",
207                 status->__frame+1, fr->time);
208     }
209 }
210
211 int prec2ndec(real prec)
212 {
213     if (prec <= 0)
214     {
215         gmx_fatal(FARGS, "DEATH HORROR prec (%g) <= 0 in prec2ndec", prec);
216     }
217
218     return (int)(log(prec)/log(10.0)+0.5);
219 }
220
221 real ndec2prec(int ndec)
222 {
223     return pow(10.0, ndec);
224 }
225
226 t_fileio *trx_get_fileio(t_trxstatus *status)
227 {
228     return status->fio;
229 }
230
231 float trx_get_time_of_final_frame(t_trxstatus *status)
232 {
233     t_fileio *stfio    = trx_get_fileio(status);
234     int       filetype = gmx_fio_getftp(stfio);
235     int       bOK;
236     float     lasttime = -1;
237
238     if (filetype == efXTC)
239     {
240         lasttime =
241             xdr_xtc_get_last_frame_time(gmx_fio_getfp(stfio),
242                                         gmx_fio_getxdr(stfio),
243                                         status->natoms, &bOK);
244         if (!bOK)
245         {
246             gmx_fatal(FARGS, "Error reading last frame. Maybe seek not supported." );
247         }
248     }
249     else if (filetype == efTNG)
250     {
251         tng_trajectory_t tng = status->tng;
252         if (!tng)
253         {
254             gmx_fatal(FARGS, "Error opening TNG file.");
255         }
256         lasttime = gmx_tng_get_time_of_final_frame(tng);
257     }
258     else
259     {
260         gmx_incons("Only supported for TNG and XTC");
261     }
262     return lasttime;
263 }
264
265 void clear_trxframe(t_trxframe *fr, gmx_bool bFirst)
266 {
267     fr->not_ok    = 0;
268     fr->bTitle    = FALSE;
269     fr->bStep     = FALSE;
270     fr->bTime     = FALSE;
271     fr->bLambda   = FALSE;
272     fr->bFepState = FALSE;
273     fr->bAtoms    = FALSE;
274     fr->bPrec     = FALSE;
275     fr->bX        = FALSE;
276     fr->bV        = FALSE;
277     fr->bF        = FALSE;
278     fr->bBox      = FALSE;
279     if (bFirst)
280     {
281         fr->flags     = 0;
282         fr->bDouble   = FALSE;
283         fr->natoms    = -1;
284         fr->t0        = 0;
285         fr->tf        = 0;
286         fr->tpf       = 0;
287         fr->tppf      = 0;
288         fr->title     = NULL;
289         fr->step      = 0;
290         fr->time      = 0;
291         fr->lambda    = 0;
292         fr->fep_state = 0;
293         fr->atoms     = NULL;
294         fr->prec      = 0;
295         fr->x         = NULL;
296         fr->v         = NULL;
297         fr->f         = NULL;
298         clear_mat(fr->box);
299         fr->bPBC   = FALSE;
300         fr->ePBC   = -1;
301     }
302 }
303
304 void set_trxframe_ePBC(t_trxframe *fr, int ePBC)
305 {
306     fr->bPBC = (ePBC == -1);
307     fr->ePBC = ePBC;
308 }
309
310 int write_trxframe_indexed(t_trxstatus *status, t_trxframe *fr, int nind,
311                            const atom_id *ind, gmx_conect gc)
312 {
313     char  title[STRLEN];
314     rvec *xout = NULL, *vout = NULL, *fout = NULL;
315     int   i, ftp = -1;
316     real  prec;
317
318     if (fr->bPrec)
319     {
320         prec = fr->prec;
321     }
322     else
323     {
324         prec = 1000.0;
325     }
326
327     if (status->tng)
328     {
329         ftp = efTNG;
330     }
331     else if (status->fio)
332     {
333         ftp = gmx_fio_getftp(status->fio);
334     }
335     else
336     {
337         gmx_incons("No input file available");
338     }
339
340     switch (ftp)
341     {
342         case efTRR:
343         case efTNG:
344             break;
345         default:
346             if (!fr->bX)
347             {
348                 gmx_fatal(FARGS, "Need coordinates to write a %s trajectory",
349                           ftp2ext(ftp));
350             }
351             break;
352     }
353
354     switch (ftp)
355     {
356         case efTRR:
357         case efTNG:
358             if (fr->bV)
359             {
360                 snew(vout, nind);
361                 for (i = 0; i < nind; i++)
362                 {
363                     copy_rvec(fr->v[ind[i]], vout[i]);
364                 }
365             }
366             if (fr->bF)
367             {
368                 snew(fout, nind);
369                 for (i = 0; i < nind; i++)
370                 {
371                     copy_rvec(fr->f[ind[i]], fout[i]);
372                 }
373             }
374         /* no break */
375         case efXTC:
376             if (fr->bX)
377             {
378                 snew(xout, nind);
379                 for (i = 0; i < nind; i++)
380                 {
381                     copy_rvec(fr->x[ind[i]], xout[i]);
382                 }
383             }
384             break;
385         default:
386             break;
387     }
388
389     switch (ftp)
390     {
391         case efTNG:
392             gmx_write_tng_from_trxframe(status->tng, fr, nind);
393             break;
394         case efXTC:
395             write_xtc(status->fio, nind, fr->step, fr->time, fr->box, xout, prec);
396             break;
397         case efTRR:
398             fwrite_trn(status->fio, nframes_read(status),
399                        fr->time, fr->step, fr->box, nind, xout, vout, fout);
400             break;
401         case efGRO:
402         case efPDB:
403         case efBRK:
404         case efENT:
405             if (!fr->bAtoms)
406             {
407                 gmx_fatal(FARGS, "Can not write a %s file without atom names",
408                           ftp2ext(ftp));
409             }
410             sprintf(title, "frame t= %.3f", fr->time);
411             if (ftp == efGRO)
412             {
413                 write_hconf_indexed_p(gmx_fio_getfp(status->fio), title, fr->atoms, nind, ind,
414                                       prec2ndec(prec),
415                                       fr->x, fr->bV ? fr->v : NULL, fr->box);
416             }
417             else
418             {
419                 write_pdbfile_indexed(gmx_fio_getfp(status->fio), title, fr->atoms,
420                                       fr->x, -1, fr->box, ' ', fr->step, nind, ind, gc, TRUE);
421             }
422             break;
423         case efG96:
424             write_g96_conf(gmx_fio_getfp(status->fio), fr, nind, ind);
425             break;
426         default:
427             gmx_fatal(FARGS, "Sorry, write_trxframe_indexed can not write %s",
428                       ftp2ext(ftp));
429             break;
430     }
431
432     switch (ftp)
433     {
434         case efTRR:
435         case efTNG:
436             if (vout)
437             {
438                 sfree(vout);
439             }
440             if (fout)
441             {
442                 sfree(fout);
443             }
444         /* no break */
445         case efXTC:
446             sfree(xout);
447             break;
448         default:
449             break;
450     }
451
452     return 0;
453 }
454
455 void trjtools_gmx_prepare_tng_writing(const char       *filename,
456                                       char              filemode,
457                                       t_trxstatus      *in,
458                                       t_trxstatus     **out,
459                                       const char       *infile,
460                                       const int         natoms,
461                                       const gmx_mtop_t *mtop,
462                                       const atom_id    *index,
463                                       const char       *index_group_name)
464 {
465     if (filemode != 'w' && filemode != 'a')
466     {
467         gmx_incons("Sorry, can only prepare for TNG output.");
468     }
469
470     if (*out == NULL)
471     {
472         snew((*out), 1);
473     }
474     status_init(*out);
475
476     if (in != NULL)
477     {
478         gmx_prepare_tng_writing(filename,
479                                 filemode,
480                                 &in->tng,
481                                 &(*out)->tng,
482                                 natoms,
483                                 mtop,
484                                 index,
485                                 index_group_name);
486     }
487     else if (efTNG == fn2ftp(infile))
488     {
489         tng_trajectory_t tng_in;
490         gmx_tng_open(infile, 'r', &tng_in);
491
492         gmx_prepare_tng_writing(filename,
493                                 filemode,
494                                 &tng_in,
495                                 &(*out)->tng,
496                                 natoms,
497                                 mtop,
498                                 index,
499                                 index_group_name);
500     }
501 }
502
503 void write_tng_frame(t_trxstatus *status,
504                      t_trxframe  *frame)
505 {
506     gmx_write_tng_from_trxframe(status->tng, frame, -1);
507 }
508
509 int write_trxframe(t_trxstatus *status, t_trxframe *fr, gmx_conect gc)
510 {
511     char title[STRLEN];
512     real prec;
513
514     if (fr->bPrec)
515     {
516         prec = fr->prec;
517     }
518     else
519     {
520         prec = 1000.0;
521     }
522
523     if (status->tng)
524     {
525         gmx_tng_set_compression_precision(status->tng, prec);
526         write_tng_frame(status, fr);
527
528         return 0;
529     }
530
531     switch (gmx_fio_getftp(status->fio))
532     {
533         case efTRR:
534             break;
535         default:
536             if (!fr->bX)
537             {
538                 gmx_fatal(FARGS, "Need coordinates to write a %s trajectory",
539                           ftp2ext(gmx_fio_getftp(status->fio)));
540             }
541             break;
542     }
543
544     switch (gmx_fio_getftp(status->fio))
545     {
546         case efXTC:
547             write_xtc(status->fio, fr->natoms, fr->step, fr->time, fr->box, fr->x, prec);
548             break;
549         case efTRR:
550             fwrite_trn(status->fio, fr->step, fr->time, fr->lambda, fr->box, fr->natoms,
551                        fr->bX ? fr->x : NULL, fr->bV ? fr->v : NULL, fr->bF ? fr->f : NULL);
552             break;
553         case efGRO:
554         case efPDB:
555         case efBRK:
556         case efENT:
557             if (!fr->bAtoms)
558             {
559                 gmx_fatal(FARGS, "Can not write a %s file without atom names",
560                           ftp2ext(gmx_fio_getftp(status->fio)));
561             }
562             sprintf(title, "frame t= %.3f", fr->time);
563             if (gmx_fio_getftp(status->fio) == efGRO)
564             {
565                 write_hconf_p(gmx_fio_getfp(status->fio), title, fr->atoms,
566                               prec2ndec(prec), fr->x, fr->bV ? fr->v : NULL, fr->box);
567             }
568             else
569             {
570                 write_pdbfile(gmx_fio_getfp(status->fio), title,
571                               fr->atoms, fr->x, fr->bPBC ? fr->ePBC : -1, fr->box,
572                               ' ', fr->step, gc, TRUE);
573             }
574             break;
575         case efG96:
576             write_g96_conf(gmx_fio_getfp(status->fio), fr, -1, NULL);
577             break;
578         default:
579             gmx_fatal(FARGS, "Sorry, write_trxframe can not write %s",
580                       ftp2ext(gmx_fio_getftp(status->fio)));
581             break;
582     }
583
584     return 0;
585 }
586
587 int write_trx(t_trxstatus *status, int nind, const atom_id *ind, t_atoms *atoms,
588               int step, real time, matrix box, rvec x[], rvec *v,
589               gmx_conect gc)
590 {
591     t_trxframe fr;
592
593     clear_trxframe(&fr, TRUE);
594     fr.bStep  = TRUE;
595     fr.step   = step;
596     fr.bTime  = TRUE;
597     fr.time   = time;
598     fr.bAtoms = atoms != NULL;
599     fr.atoms  = atoms;
600     fr.bX     = TRUE;
601     fr.x      = x;
602     fr.bV     = v != NULL;
603     fr.v      = v;
604     fr.bBox   = TRUE;
605     copy_mat(box, fr.box);
606
607     return write_trxframe_indexed(status, &fr, nind, ind, gc);
608 }
609
610 void close_trx(t_trxstatus *status)
611 {
612     gmx_tng_close(&status->tng);
613     if (status->fio)
614     {
615         gmx_fio_close(status->fio);
616     }
617     sfree(status);
618 }
619
620 t_trxstatus *open_trx(const char *outfile, const char *filemode)
621 {
622     t_trxstatus *stat;
623     if (filemode[0] != 'w' && filemode[0] != 'a' && filemode[1] != '+')
624     {
625         gmx_fatal(FARGS, "Sorry, write_trx can only write");
626     }
627
628     snew(stat, 1);
629     status_init(stat);
630
631     stat->fio = gmx_fio_open(outfile, filemode);
632     return stat;
633 }
634
635 static gmx_bool gmx_next_frame(t_trxstatus *status, t_trxframe *fr)
636 {
637     t_trnheader sh;
638     gmx_bool    bOK, bRet;
639
640     bRet = FALSE;
641
642     if (fread_trnheader(status->fio, &sh, &bOK))
643     {
644         fr->bDouble   = sh.bDouble;
645         fr->natoms    = sh.natoms;
646         fr->bStep     = TRUE;
647         fr->step      = sh.step;
648         fr->bTime     = TRUE;
649         fr->time      = sh.t;
650         fr->bLambda   = TRUE;
651         fr->bFepState = TRUE;
652         fr->lambda    = sh.lambda;
653         fr->bBox      = sh.box_size > 0;
654         if (fr->flags & (TRX_READ_X | TRX_NEED_X))
655         {
656             if (fr->x == NULL)
657             {
658                 snew(fr->x, sh.natoms);
659             }
660             fr->bX = sh.x_size > 0;
661         }
662         if (fr->flags & (TRX_READ_V | TRX_NEED_V))
663         {
664             if (fr->v == NULL)
665             {
666                 snew(fr->v, sh.natoms);
667             }
668             fr->bV = sh.v_size > 0;
669         }
670         if (fr->flags & (TRX_READ_F | TRX_NEED_F))
671         {
672             if (fr->f == NULL)
673             {
674                 snew(fr->f, sh.natoms);
675             }
676             fr->bF = sh.f_size > 0;
677         }
678         if (fread_htrn(status->fio, &sh, fr->box, fr->x, fr->v, fr->f))
679         {
680             bRet = TRUE;
681         }
682         else
683         {
684             fr->not_ok = DATA_NOT_OK;
685         }
686     }
687     else
688     if (!bOK)
689     {
690         fr->not_ok = HEADER_NOT_OK;
691     }
692
693     return bRet;
694 }
695
696 static gmx_bool pdb_next_x(t_trxstatus *status, FILE *fp, t_trxframe *fr)
697 {
698     t_atoms   atoms;
699     matrix    boxpdb;
700     int       ePBC, model_nr, na;
701     char      title[STRLEN], *time;
702     double    dbl;
703
704     atoms.nr      = fr->natoms;
705     atoms.atom    = NULL;
706     atoms.pdbinfo = NULL;
707     /* the other pointers in atoms should not be accessed if these are NULL */
708     model_nr = NOTSET;
709     na       = read_pdbfile(fp, title, &model_nr, &atoms, fr->x, &ePBC, boxpdb, TRUE, NULL);
710     set_trxframe_ePBC(fr, ePBC);
711     if (nframes_read(status) == 0)
712     {
713         fprintf(stderr, " '%s', %d atoms\n", title, fr->natoms);
714     }
715     fr->bPrec = TRUE;
716     fr->prec  = 10000;
717     fr->bX    = TRUE;
718     fr->bBox  = (boxpdb[XX][XX] != 0.0);
719     if (fr->bBox)
720     {
721         copy_mat(boxpdb, fr->box);
722     }
723
724     if (model_nr != NOTSET)
725     {
726         fr->bStep = TRUE;
727         fr->step  = model_nr;
728     }
729     time = strstr(title, " t= ");
730     if (time)
731     {
732         fr->bTime = TRUE;
733         sscanf(time+4, "%lf", &dbl);
734         fr->time = (real)dbl;
735     }
736     else
737     {
738         fr->bTime = FALSE;
739         /* this is a bit dirty, but it will work: if no time is read from
740            comment line in pdb file, set time to current frame number */
741         if (fr->bStep)
742         {
743             fr->time = (real)fr->step;
744         }
745         else
746         {
747             fr->time = (real)nframes_read(status);
748         }
749     }
750     if (na == 0)
751     {
752         return FALSE;
753     }
754     else
755     {
756         if (na != fr->natoms)
757         {
758             gmx_fatal(FARGS, "Number of atoms in pdb frame %d is %d instead of %d",
759                       nframes_read(status), na, fr->natoms);
760         }
761         return TRUE;
762     }
763 }
764
765 static int pdb_first_x(t_trxstatus *status, FILE *fp, t_trxframe *fr)
766 {
767     initcount(status);
768
769     fprintf(stderr, "Reading frames from pdb file");
770     frewind(fp);
771     get_pdb_coordnum(fp, &fr->natoms);
772     if (fr->natoms == 0)
773     {
774         gmx_fatal(FARGS, "\nNo coordinates in pdb file\n");
775     }
776     frewind(fp);
777     snew(fr->x, fr->natoms);
778     pdb_next_x(status, fp, fr);
779
780     return fr->natoms;
781 }
782
783 gmx_bool read_next_frame(const output_env_t oenv, t_trxstatus *status, t_trxframe *fr)
784 {
785     real     pt;
786     int      ct;
787     gmx_bool bOK, bRet, bMissingData = FALSE, bSkip = FALSE;
788     int      ftp;
789
790     bRet = FALSE;
791     pt   = fr->tf;
792
793     do
794     {
795         clear_trxframe(fr, FALSE);
796         fr->tppf = fr->tpf;
797         fr->tpf  = fr->tf;
798
799         if (status->tng)
800         {
801             /* Special treatment for TNG files */
802             ftp = efTNG;
803         }
804         else
805         {
806             ftp = gmx_fio_getftp(status->fio);
807         }
808         switch (ftp)
809         {
810             case efTRR:
811                 bRet = gmx_next_frame(status, fr);
812                 break;
813             case efCPT:
814                 /* Checkpoint files can not contain mulitple frames */
815                 break;
816             case efG96:
817                 read_g96_conf(gmx_fio_getfp(status->fio), NULL, fr,
818                               status->persistent_line);
819                 bRet = (fr->natoms > 0);
820                 break;
821             case efXTC:
822                 /* B. Hess 2005-4-20
823                  * Sometimes is off by one frame
824                  * and sometimes reports frame not present/file not seekable
825                  */
826                 /* DvdS 2005-05-31: this has been fixed along with the increased
827                  * accuracy of the control over -b and -e options.
828                  */
829                 if (bTimeSet(TBEGIN) && (fr->tf < rTimeValue(TBEGIN)))
830                 {
831                     if (xtc_seek_time(status->fio, rTimeValue(TBEGIN), fr->natoms, TRUE))
832                     {
833                         gmx_fatal(FARGS, "Specified frame (time %f) doesn't exist or file corrupt/inconsistent.",
834                                   rTimeValue(TBEGIN));
835                     }
836                     initcount(status);
837                 }
838                 bRet = read_next_xtc(status->fio, fr->natoms, &fr->step, &fr->time, fr->box,
839                                      fr->x, &fr->prec, &bOK);
840                 fr->bPrec = (bRet && fr->prec > 0);
841                 fr->bStep = bRet;
842                 fr->bTime = bRet;
843                 fr->bX    = bRet;
844                 fr->bBox  = bRet;
845                 if (!bOK)
846                 {
847                     /* Actually the header could also be not ok,
848                        but from bOK from read_next_xtc this can't be distinguished */
849                     fr->not_ok = DATA_NOT_OK;
850                 }
851                 break;
852             case efTNG:
853                 bRet = gmx_read_next_tng_frame(status->tng, fr, NULL, 0);
854                 break;
855             case efPDB:
856                 bRet = pdb_next_x(status, gmx_fio_getfp(status->fio), fr);
857                 break;
858             case efGRO:
859                 bRet = gro_next_x_or_v(gmx_fio_getfp(status->fio), fr);
860                 break;
861             default:
862 #ifdef GMX_USE_PLUGINS
863                 bRet = read_next_vmd_frame(fr);
864 #else
865                 gmx_fatal(FARGS, "DEATH HORROR in read_next_frame ftp=%s,status=%s",
866                           ftp2ext(gmx_fio_getftp(status->fio)),
867                           gmx_fio_getname(status->fio));
868 #endif
869         }
870         fr->tf = fr->time;
871
872         if (bRet)
873         {
874             bMissingData = (((fr->flags & TRX_NEED_X) && !fr->bX) ||
875                             ((fr->flags & TRX_NEED_V) && !fr->bV) ||
876                             ((fr->flags & TRX_NEED_F) && !fr->bF));
877             bSkip = FALSE;
878             if (!bMissingData)
879             {
880                 ct = check_times2(fr->time, fr->t0, fr->bDouble);
881                 if (ct == 0 || ((fr->flags & TRX_DONT_SKIP) && ct < 0))
882                 {
883                     printcount(status, oenv, fr->time, FALSE);
884                 }
885                 else if (ct > 0)
886                 {
887                     bRet = FALSE;
888                 }
889                 else
890                 {
891                     printcount(status, oenv, fr->time, TRUE);
892                     bSkip = TRUE;
893                 }
894             }
895         }
896
897     }
898     while (bRet && (bMissingData || bSkip));
899
900     if (!bRet)
901     {
902         printlast(status, oenv, pt);
903         if (fr->not_ok)
904         {
905             printincomp(status, fr);
906         }
907     }
908
909     return bRet;
910 }
911
912 int read_first_frame(const output_env_t oenv, t_trxstatus **status,
913                      const char *fn, t_trxframe *fr, int flags)
914 {
915     t_fileio      *fio;
916     gmx_bool       bFirst, bOK;
917     int            ftp   = fn2ftp(fn);
918
919     clear_trxframe(fr, TRUE);
920     fr->flags = flags;
921
922     bFirst = TRUE;
923
924     snew((*status), 1);
925
926     status_init( *status );
927     (*status)->nxframe = 1;
928     initcount(*status);
929
930     if (efTNG == ftp)
931     {
932         /* Special treatment for TNG files */
933         gmx_tng_open(fn, 'r', &(*status)->tng);
934     }
935     else
936     {
937         fio = (*status)->fio = gmx_fio_open(fn, "r");
938     }
939     switch (ftp)
940     {
941         case efTRR:
942             break;
943         case efCPT:
944             read_checkpoint_trxframe(fio, fr);
945             bFirst = FALSE;
946             break;
947         case efG96:
948             /* Can not rewind a compressed file, so open it twice */
949             if (!(*status)->persistent_line)
950             {
951                 /* allocate the persistent line */
952                 snew((*status)->persistent_line, STRLEN+1);
953             }
954             read_g96_conf(gmx_fio_getfp(fio), fn, fr, (*status)->persistent_line);
955             gmx_fio_close(fio);
956             clear_trxframe(fr, FALSE);
957             if (flags & (TRX_READ_X | TRX_NEED_X))
958             {
959                 snew(fr->x, fr->natoms);
960             }
961             if (flags & (TRX_READ_V | TRX_NEED_V))
962             {
963                 snew(fr->v, fr->natoms);
964             }
965             (*status)->fio = gmx_fio_open(fn, "r");
966             break;
967         case efXTC:
968             if (read_first_xtc(fio, &fr->natoms, &fr->step, &fr->time, fr->box, &fr->x,
969                                &fr->prec, &bOK) == 0)
970             {
971                 GMX_RELEASE_ASSERT(!bOK, "Inconsistent results - OK status from read_first_xtc, but 0 atom coords read");
972                 fr->not_ok = DATA_NOT_OK;
973             }
974             if (fr->not_ok)
975             {
976                 fr->natoms = 0;
977                 printincomp(*status, fr);
978             }
979             else
980             {
981                 fr->bPrec = (fr->prec > 0);
982                 fr->bStep = TRUE;
983                 fr->bTime = TRUE;
984                 fr->bX    = TRUE;
985                 fr->bBox  = TRUE;
986                 printcount(*status, oenv, fr->time, FALSE);
987             }
988             bFirst = FALSE;
989             break;
990         case efTNG:
991             fr->step = -1;
992             if (!gmx_read_next_tng_frame((*status)->tng, fr, NULL, 0))
993             {
994                 fr->not_ok = DATA_NOT_OK;
995                 fr->natoms = 0;
996                 printincomp(*status, fr);
997             }
998             else
999             {
1000                 printcount(*status, oenv, fr->time, FALSE);
1001             }
1002             bFirst = FALSE;
1003             break;
1004         case efPDB:
1005             pdb_first_x(*status, gmx_fio_getfp(fio), fr);
1006             if (fr->natoms)
1007             {
1008                 printcount(*status, oenv, fr->time, FALSE);
1009             }
1010             bFirst = FALSE;
1011             break;
1012         case efGRO:
1013             if (gro_first_x_or_v(gmx_fio_getfp(fio), fr))
1014             {
1015                 printcount(*status, oenv, fr->time, FALSE);
1016             }
1017             bFirst = FALSE;
1018             break;
1019         default:
1020 #ifdef GMX_USE_PLUGINS
1021             fprintf(stderr, "The file format of %s is not a known trajectory format to GROMACS.\n"
1022                     "Please make sure that the file is a trajectory!\n"
1023                     "GROMACS will now assume it to be a trajectory and will try to open it using the VMD plug-ins.\n"
1024                     "This will only work in case the VMD plugins are found and it is a trajectory format supported by VMD.\n", fn);
1025             gmx_fio_fp_close(fio); /*only close the file without removing FIO entry*/
1026             if (!read_first_vmd_frame(fn, fr))
1027             {
1028                 gmx_fatal(FARGS, "Not supported in read_first_frame: %s", fn);
1029             }
1030 #else
1031             gmx_fatal(FARGS, "Not supported in read_first_frame: %s. Please make sure that the file is a trajectory.\n"
1032                       "GROMACS is not compiled with plug-in support. Thus it cannot read non-GROMACS trajectory formats using the VMD plug-ins.\n"
1033                       "Please compile with plug-in support if you want to read non-GROMACS trajectory formats.\n", fn);
1034 #endif
1035             break;
1036     }
1037     fr->tf = fr->time;
1038
1039     /* Return FALSE if we read a frame that's past the set ending time. */
1040     if (!bFirst && (!(fr->flags & TRX_DONT_SKIP) && check_times(fr->time) > 0))
1041     {
1042         fr->t0 = fr->time;
1043         return FALSE;
1044     }
1045
1046     if (bFirst ||
1047         (!(fr->flags & TRX_DONT_SKIP) && check_times(fr->time) < 0))
1048     {
1049         /* Read a frame when no frame was read or the first was skipped */
1050         if (!read_next_frame(oenv, *status, fr))
1051         {
1052             return FALSE;
1053         }
1054     }
1055     fr->t0 = fr->time;
1056
1057     /* We need the number of atoms for random-access XTC searching, even when
1058      * we don't have access to the actual frame data.
1059      */
1060     (*status)->natoms = fr->natoms;
1061
1062     return (fr->natoms > 0);
1063 }
1064
1065 /***** C O O R D I N A T E   S T U F F *****/
1066
1067 int read_first_x(const output_env_t oenv, t_trxstatus **status, const char *fn,
1068                  real *t, rvec **x, matrix box)
1069 {
1070     t_trxframe fr;
1071
1072     read_first_frame(oenv, status, fn, &fr, TRX_NEED_X);
1073
1074     snew((*status)->xframe, 1);
1075     (*status)->nxframe   = 1;
1076     (*(*status)->xframe) = fr;
1077     *t                   = (*status)->xframe->time;
1078     *x                   = (*status)->xframe->x;
1079     copy_mat((*status)->xframe->box, box);
1080
1081     return (*status)->xframe->natoms;
1082 }
1083
1084 gmx_bool read_next_x(const output_env_t oenv, t_trxstatus *status, real *t,
1085                      rvec x[], matrix box)
1086 {
1087     gmx_bool bRet;
1088
1089     status->xframe->x = x;
1090     /*xframe[status].x = x;*/
1091     bRet = read_next_frame(oenv, status, status->xframe);
1092     *t   = status->xframe->time;
1093     copy_mat(status->xframe->box, box);
1094
1095     return bRet;
1096 }
1097
1098 void close_trj(t_trxstatus *status)
1099 {
1100     gmx_tng_close(&status->tng);
1101     if (status->fio)
1102     {
1103         gmx_fio_close(status->fio);
1104     }
1105
1106     /* The memory in status->xframe is lost here,
1107      * but the read_first_x/read_next_x functions are deprecated anyhow.
1108      * read_first_frame/read_next_frame and close_trx should be used.
1109      */
1110     sfree(status);
1111 }
1112
1113 void rewind_trj(t_trxstatus *status)
1114 {
1115     initcount(status);
1116
1117     gmx_fio_rewind(status->fio);
1118 }
1119
1120 /***** T O P O L O G Y   S T U F F ******/
1121
1122 t_topology *read_top(const char *fn, int *ePBC)
1123 {
1124     int         epbc, natoms;
1125     t_topology *top;
1126
1127     snew(top, 1);
1128     epbc = read_tpx_top(fn, NULL, NULL, &natoms, NULL, NULL, NULL, top);
1129     if (ePBC)
1130     {
1131         *ePBC = epbc;
1132     }
1133
1134     return top;
1135 }