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