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-2013, The GROMACS development team.
6 * Copyright (c) 2013,2014, 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.
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.
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.
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.
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.
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.
43 #include "gromacs/commandline/pargs.h"
44 #include "gromacs/fileio/confio.h"
45 #include "gromacs/fileio/enxio.h"
46 #include "gromacs/fileio/gmxfio.h"
47 #include "gromacs/fileio/tpxio.h"
48 #include "gromacs/fileio/trnio.h"
49 #include "gromacs/fileio/trxio.h"
50 #include "gromacs/fileio/xtcio.h"
51 #include "gromacs/legacyheaders/macros.h"
52 #include "gromacs/legacyheaders/names.h"
53 #include "gromacs/legacyheaders/txtdump.h"
54 #include "gromacs/math/units.h"
55 #include "gromacs/math/vec.h"
56 #include "gromacs/pbcutil/pbc.h"
57 #include "gromacs/tools/compare.h"
58 #include "gromacs/topology/atomprop.h"
59 #include "gromacs/topology/block.h"
60 #include "gromacs/topology/index.h"
61 #include "gromacs/topology/mtop_util.h"
62 #include "gromacs/utility/fatalerror.h"
63 #include "gromacs/utility/futil.h"
64 #include "gromacs/utility/smalloc.h"
86 static void tpx2system(FILE *fp, gmx_mtop_t *mtop)
88 int i, nmol, nvsite = 0;
89 gmx_mtop_atomloop_block_t aloop;
92 fprintf(fp, "\\subsection{Simulation system}\n");
93 aloop = gmx_mtop_atomloop_block_init(mtop);
94 while (gmx_mtop_atomloop_block_next(aloop, &atom, &nmol))
96 if (atom->ptype == eptVSite)
101 fprintf(fp, "A system of %d molecules (%d atoms) was simulated.\n",
102 mtop->mols.nr, mtop->natoms-nvsite);
105 fprintf(fp, "Virtual sites were used in some of the molecules.\n");
110 static void tpx2params(FILE *fp, t_inputrec *ir)
112 fprintf(fp, "\\subsection{Simulation settings}\n");
113 fprintf(fp, "A total of %g ns were simulated with a time step of %g fs.\n",
114 ir->nsteps*ir->delta_t*0.001, 1000*ir->delta_t);
115 fprintf(fp, "Neighbor searching was performed every %d steps.\n", ir->nstlist);
116 fprintf(fp, "The %s algorithm was used for electrostatic interactions.\n",
117 EELTYPE(ir->coulombtype));
118 fprintf(fp, "with a cut-off of %g nm.\n", ir->rcoulomb);
119 if (ir->coulombtype == eelPME)
121 fprintf(fp, "A reciprocal grid of %d x %d x %d cells was used with %dth order B-spline interpolation.\n", ir->nkx, ir->nky, ir->nkz, ir->pme_order);
123 if (ir->rvdw > ir->rlist)
125 fprintf(fp, "A twin-range Van der Waals cut-off (%g/%g nm) was used, where the long range forces were updated during neighborsearching.\n", ir->rlist, ir->rvdw);
129 fprintf(fp, "A single cut-off of %g was used for Van der Waals interactions.\n", ir->rlist);
133 fprintf(fp, "Temperature coupling was done with the %s algorithm.\n",
134 etcoupl_names[ir->etc]);
138 fprintf(fp, "Pressure coupling was done with the %s algorithm.\n",
139 epcoupl_names[ir->epc]);
144 static void tpx2methods(const char *tpx, const char *tex)
152 read_tpx_state(tpx, &ir, &state, NULL, &mtop);
153 fp = gmx_fio_fopen(tex, "w");
154 fprintf(fp, "\\section{Methods}\n");
155 tpx2system(fp, &mtop);
160 static void chk_coords(int frame, int natoms, rvec *x, matrix box, real fac, real tol)
166 for (i = 0; (i < natoms); i++)
168 for (j = 0; (j < DIM); j++)
170 if ((vol > 0) && (fabs(x[i][j]) > fac*box[j][j]))
172 printf("Warning at frame %d: coordinates for atom %d are large (%g)\n",
176 if ((fabs(x[i][XX]) < tol) &&
177 (fabs(x[i][YY]) < tol) &&
178 (fabs(x[i][ZZ]) < tol))
185 printf("Warning at frame %d: there are %d particles with all coordinates zero\n",
190 static void chk_vels(int frame, int natoms, rvec *v)
194 for (i = 0; (i < natoms); i++)
196 for (j = 0; (j < DIM); j++)
198 if (fabs(v[i][j]) > 500)
200 printf("Warning at frame %d. Velocities for atom %d are large (%g)\n",
207 static void chk_forces(int frame, int natoms, rvec *f)
211 for (i = 0; (i < natoms); i++)
213 for (j = 0; (j < DIM); j++)
215 if (fabs(f[i][j]) > 10000)
217 printf("Warning at frame %d. Forces for atom %d are large (%g)\n",
224 static void chk_bonds(t_idef *idef, int ePBC, rvec *x, matrix box, real tol)
226 int ftype, i, k, ai, aj, type;
227 real b0, blen, deviation, devtot;
232 set_pbc(&pbc, ePBC, box);
233 for (ftype = 0; (ftype < F_NRE); ftype++)
235 if ((interaction_function[ftype].flags & IF_CHEMBOND) == IF_CHEMBOND)
237 for (k = 0; (k < idef->il[ftype].nr); )
239 type = idef->il[ftype].iatoms[k++];
240 ai = idef->il[ftype].iatoms[k++];
241 aj = idef->il[ftype].iatoms[k++];
246 b0 = idef->iparams[type].harmonic.rA;
249 b0 = sqrt(idef->iparams[type].harmonic.rA);
252 b0 = idef->iparams[type].morse.b0A;
255 b0 = idef->iparams[type].cubic.b0;
258 b0 = idef->iparams[type].constr.dA;
265 pbc_dx(&pbc, x[ai], x[aj], dx);
267 deviation = sqr(blen-b0);
268 if (sqrt(deviation/sqr(b0) > tol))
270 fprintf(stderr, "Distance between atoms %d and %d is %.3f, should be %.3f\n", ai+1, aj+1, blen, b0);
278 void chk_trj(const output_env_t oenv, const char *fn, const char *tpr, real tol)
282 t_fr_time first, last;
283 int j = -1, new_natoms, natoms;
284 real rdum, tt, old_t1, old_t2, prec;
285 gmx_bool bShowTimestep = TRUE, bOK, newline = FALSE;
288 gmx_localtop_t *top = NULL;
294 read_tpx_state(tpr, &ir, &state, NULL, &mtop);
295 top = gmx_mtop_generate_local_top(&mtop, &ir);
300 printf("Checking file %s\n", fn);
330 read_first_frame(oenv, &status, fn, &fr, TRX_READ_X | TRX_READ_V | TRX_READ_F);
336 fprintf(stderr, "\n# Atoms %d\n", fr.natoms);
339 fprintf(stderr, "Precision %g (nm)\n", 1/fr.prec);
343 if ((natoms > 0) && (new_natoms != natoms))
345 fprintf(stderr, "\nNumber of atoms at t=%g don't match (%d, %d)\n",
346 old_t1, natoms, new_natoms);
351 if (fabs((fr.time-old_t1)-(old_t1-old_t2)) >
352 0.1*(fabs(fr.time-old_t1)+fabs(old_t1-old_t2)) )
354 bShowTimestep = FALSE;
355 fprintf(stderr, "%sTimesteps at t=%g don't match (%g, %g)\n",
356 newline ? "\n" : "", old_t1, old_t1-old_t2, fr.time-old_t1);
362 chk_bonds(&top->idef, ir.ePBC, fr.x, fr.box, tol);
366 chk_coords(j, natoms, fr.x, fr.box, 1e5, tol);
370 chk_vels(j, natoms, fr.v);
374 chk_forces(j, natoms, fr.f);
380 new_natoms = fr.natoms;
381 #define INC(s, n, f, l, item) if (s.item != 0) { if (n.item == 0) { first.item = fr.time; } last.item = fr.time; n.item++; \
383 INC(fr, count, first, last, bStep);
384 INC(fr, count, first, last, bTime);
385 INC(fr, count, first, last, bLambda);
386 INC(fr, count, first, last, bX);
387 INC(fr, count, first, last, bV);
388 INC(fr, count, first, last, bF);
389 INC(fr, count, first, last, bBox);
392 while (read_next_frame(oenv, status, &fr));
394 fprintf(stderr, "\n");
398 fprintf(stderr, "\nItem #frames");
401 fprintf(stderr, " Timestep (ps)");
403 fprintf(stderr, "\n");
404 #define PRINTITEM(label, item) fprintf(stderr, "%-10s %6d", label, count.item); if ((bShowTimestep) && (count.item > 1)) {fprintf(stderr, " %g\n", (last.item-first.item)/(count.item-1)); }else fprintf(stderr, "\n")
405 PRINTITEM ( "Step", bStep );
406 PRINTITEM ( "Time", bTime );
407 PRINTITEM ( "Lambda", bLambda );
408 PRINTITEM ( "Coords", bX );
409 PRINTITEM ( "Velocities", bV );
410 PRINTITEM ( "Forces", bF );
411 PRINTITEM ( "Box", bBox );
414 void chk_tps(const char *fn, real vdw_fac, real bon_lo, real bon_hi)
425 gmx_bool bV, bX, bB, bFirst, bOut;
426 real r2, ekin, temp1, temp2, dist2, vdwfac2, bonlo2, bonhi2;
430 fprintf(stderr, "Checking coordinate file %s\n", fn);
431 read_tps_conf(fn, title, &top, &ePBC, &x, &v, box, TRUE);
434 fprintf(stderr, "%d atoms in file\n", atoms->nr);
436 /* check coordinates and box */
439 for (i = 0; (i < natom) && !(bV && bX); i++)
441 for (j = 0; (j < DIM) && !(bV && bX); j++)
443 bV = bV || (v[i][j] != 0);
444 bX = bX || (x[i][j] != 0);
448 for (i = 0; (i < DIM) && !bB; i++)
450 for (j = 0; (j < DIM) && !bB; j++)
452 bB = bB || (box[i][j] != 0);
456 fprintf(stderr, "coordinates %s\n", bX ? "found" : "absent");
457 fprintf(stderr, "box %s\n", bB ? "found" : "absent");
458 fprintf(stderr, "velocities %s\n", bV ? "found" : "absent");
459 fprintf(stderr, "\n");
461 /* check velocities */
465 for (i = 0; (i < natom); i++)
467 for (j = 0; (j < DIM); j++)
469 ekin += 0.5*atoms->atom[i].m*v[i][j]*v[i][j];
472 temp1 = (2.0*ekin)/(natom*DIM*BOLTZ);
473 temp2 = (2.0*ekin)/(natom*(DIM-1)*BOLTZ);
474 fprintf(stderr, "Kinetic energy: %g (kJ/mol)\n", ekin);
475 fprintf(stderr, "Assuming the number of degrees of freedom to be "
476 "Natoms * %d or Natoms * %d,\n"
477 "the velocities correspond to a temperature of the system\n"
478 "of %g K or %g K respectively.\n\n", DIM, DIM-1, temp1, temp2);
481 /* check coordinates */
484 vdwfac2 = sqr(vdw_fac);
485 bonlo2 = sqr(bon_lo);
486 bonhi2 = sqr(bon_hi);
489 "Checking for atoms closer than %g and not between %g and %g,\n"
490 "relative to sum of Van der Waals distance:\n",
491 vdw_fac, bon_lo, bon_hi);
492 snew(atom_vdw, natom);
493 aps = gmx_atomprop_init();
494 for (i = 0; (i < natom); i++)
496 gmx_atomprop_query(aps, epropVDW,
497 *(atoms->resinfo[atoms->atom[i].resind].name),
498 *(atoms->atomname[i]), &(atom_vdw[i]));
501 fprintf(debug, "%5d %4s %4s %7g\n", i+1,
502 *(atoms->resinfo[atoms->atom[i].resind].name),
503 *(atoms->atomname[i]),
507 gmx_atomprop_destroy(aps);
510 set_pbc(&pbc, ePBC, box);
514 for (i = 0; (i < natom); i++)
518 fprintf(stderr, "\r%5d", i+1);
520 for (j = i+1; (j < natom); j++)
524 pbc_dx(&pbc, x[i], x[j], dx);
528 rvec_sub(x[i], x[j], dx);
531 dist2 = sqr(atom_vdw[i]+atom_vdw[j]);
532 if ( (r2 <= dist2*bonlo2) ||
533 ( (r2 >= dist2*bonhi2) && (r2 <= dist2*vdwfac2) ) )
537 fprintf(stderr, "\r%5s %4s %8s %5s %5s %4s %8s %5s %6s\n",
538 "atom#", "name", "residue", "r_vdw",
539 "atom#", "name", "residue", "r_vdw", "distance");
543 "\r%5d %4s %4s%4d %-5.3g %5d %4s %4s%4d %-5.3g %-6.4g\n",
544 i+1, *(atoms->atomname[i]),
545 *(atoms->resinfo[atoms->atom[i].resind].name),
546 atoms->resinfo[atoms->atom[i].resind].nr,
548 j+1, *(atoms->atomname[j]),
549 *(atoms->resinfo[atoms->atom[j].resind].name),
550 atoms->resinfo[atoms->atom[j].resind].nr,
558 fprintf(stderr, "\rno close atoms found\n");
560 fprintf(stderr, "\r \n");
567 for (i = 0; (i < natom) && (k < 10); i++)
570 for (j = 0; (j < DIM) && !bOut; j++)
572 bOut = bOut || (x[i][j] < 0) || (x[i][j] > box[j][j]);
579 fprintf(stderr, "Atoms outside box ( ");
580 for (j = 0; (j < DIM); j++)
582 fprintf(stderr, "%g ", box[j][j]);
584 fprintf(stderr, "):\n"
585 "(These may occur often and are normally not a problem)\n"
586 "%5s %4s %8s %5s %s\n",
587 "atom#", "name", "residue", "r_vdw", "coordinate");
591 "%5d %4s %4s%4d %-5.3g",
592 i, *(atoms->atomname[i]),
593 *(atoms->resinfo[atoms->atom[i].resind].name),
594 atoms->resinfo[atoms->atom[i].resind].nr, atom_vdw[i]);
595 for (j = 0; (j < DIM); j++)
597 fprintf(stderr, " %6.3g", x[i][j]);
599 fprintf(stderr, "\n");
604 fprintf(stderr, "(maybe more)\n");
608 fprintf(stderr, "no atoms found outside box\n");
610 fprintf(stderr, "\n");
615 void chk_ndx(const char *fn)
621 grps = init_index(fn, &grpname);
624 pr_blocka(debug, 0, fn, grps, FALSE);
628 printf("Contents of index file %s\n", fn);
629 printf("--------------------------------------------------\n");
630 printf("Nr. Group #Entries First Last\n");
631 for (i = 0; (i < grps->nr); i++)
633 printf("%4d %-20s%8d%8d%8d\n", i, grpname[i],
634 grps->index[i+1]-grps->index[i],
635 grps->a[grps->index[i]]+1,
636 grps->a[grps->index[i+1]-1]+1);
639 for (i = 0; (i < grps->nr); i++)
647 void chk_enx(const char *fn)
651 gmx_enxnm_t *enm = NULL;
654 real t0, old_t1, old_t2;
657 fprintf(stderr, "Checking energy file %s\n\n", fn);
659 in = open_enx(fn, "r");
660 do_enxnms(in, &nre, &enm);
661 fprintf(stderr, "%d groups in energy file", nre);
669 while (do_enx(in, fr))
673 if (fabs((fr->t-old_t1)-(old_t1-old_t2)) >
674 0.1*(fabs(fr->t-old_t1)+fabs(old_t1-old_t2)) )
677 fprintf(stderr, "\nTimesteps at t=%g don't match (%g, %g)\n",
678 old_t1, old_t1-old_t2, fr->t-old_t1);
689 fprintf(stderr, "\rframe: %6s (index %6d), t: %10.3f\n",
690 gmx_step_str(fr->step, buf), fnr, fr->t);
694 fprintf(stderr, "\n\nFound %d frames", fnr);
695 if (bShowTStep && fnr > 1)
697 fprintf(stderr, " with a timestep of %g ps", (old_t1-t0)/(fnr-1));
699 fprintf(stderr, ".\n");
702 free_enxnms(nre, enm);
706 int gmx_check(int argc, char *argv[])
708 const char *desc[] = {
709 "[THISMODULE] reads a trajectory ([TT].tng[tt], [TT].trr[tt] or ",
710 "[TT].xtc[tt]), an energy file ([TT].edr[tt])",
711 "or an index file ([TT].ndx[tt])",
712 "and prints out useful information about them.[PAR]",
713 "Option [TT]-c[tt] checks for presence of coordinates,",
714 "velocities and box in the file, for close contacts (smaller than",
715 "[TT]-vdwfac[tt] and not bonded, i.e. not between [TT]-bonlo[tt]",
716 "and [TT]-bonhi[tt], all relative to the sum of both Van der Waals",
717 "radii) and atoms outside the box (these may occur often and are",
718 "no problem). If velocities are present, an estimated temperature",
719 "will be calculated from them.[PAR]",
720 "If an index file, is given its contents will be summarized.[PAR]",
721 "If both a trajectory and a [TT].tpr[tt] file are given (with [TT]-s1[tt])",
722 "the program will check whether the bond lengths defined in the tpr",
723 "file are indeed correct in the trajectory. If not you may have",
724 "non-matching files due to e.g. deshuffling or due to problems with",
725 "virtual sites. With these flags, [TT]gmx check[tt] provides a quick check for such problems.[PAR]",
726 "The program can compare two run input ([TT].tpr[tt])",
728 "when both [TT]-s1[tt] and [TT]-s2[tt] are supplied.",
729 "Similarly a pair of trajectory files can be compared (using the [TT]-f2[tt]",
730 "option), or a pair of energy files (using the [TT]-e2[tt] option).[PAR]",
731 "For free energy simulations the A and B state topology from one",
732 "run input file can be compared with options [TT]-s1[tt] and [TT]-ab[tt].[PAR]",
733 "In case the [TT]-m[tt] flag is given a LaTeX file will be written",
734 "consisting of a rough outline for a methods section for a paper."
737 { efTRX, "-f", NULL, ffOPTRD },
738 { efTRX, "-f2", NULL, ffOPTRD },
739 { efTPR, "-s1", "top1", ffOPTRD },
740 { efTPR, "-s2", "top2", ffOPTRD },
741 { efTPS, "-c", NULL, ffOPTRD },
742 { efEDR, "-e", NULL, ffOPTRD },
743 { efEDR, "-e2", "ener2", ffOPTRD },
744 { efNDX, "-n", NULL, ffOPTRD },
745 { efTEX, "-m", NULL, ffOPTWR }
747 #define NFILE asize(fnm)
748 const char *fn1 = NULL, *fn2 = NULL, *tex = NULL;
751 static real vdw_fac = 0.8;
752 static real bon_lo = 0.4;
753 static real bon_hi = 0.7;
754 static gmx_bool bRMSD = FALSE;
755 static real ftol = 0.001;
756 static real abstol = 0.001;
757 static gmx_bool bCompAB = FALSE;
758 static char *lastener = NULL;
759 static t_pargs pa[] = {
760 { "-vdwfac", FALSE, etREAL, {&vdw_fac},
761 "Fraction of sum of VdW radii used as warning cutoff" },
762 { "-bonlo", FALSE, etREAL, {&bon_lo},
763 "Min. fract. of sum of VdW radii for bonded atoms" },
764 { "-bonhi", FALSE, etREAL, {&bon_hi},
765 "Max. fract. of sum of VdW radii for bonded atoms" },
766 { "-rmsd", FALSE, etBOOL, {&bRMSD},
767 "Print RMSD for x, v and f" },
768 { "-tol", FALSE, etREAL, {&ftol},
769 "Relative tolerance for comparing real values defined as [MATH]2*(a-b)/([MAG]a[mag]+[MAG]b[mag])[math]" },
770 { "-abstol", FALSE, etREAL, {&abstol},
771 "Absolute tolerance, useful when sums are close to zero." },
772 { "-ab", FALSE, etBOOL, {&bCompAB},
773 "Compare the A and B topology from one file" },
774 { "-lastener", FALSE, etSTR, {&lastener},
775 "Last energy term to compare (if not given all are tested). It makes sense to go up until the Pressure." }
778 if (!parse_common_args(&argc, argv, 0, NFILE, fnm, asize(pa), pa,
779 asize(desc), desc, 0, NULL, &oenv))
784 fn1 = opt2fn_null("-f", NFILE, fnm);
785 fn2 = opt2fn_null("-f2", NFILE, fnm);
786 tex = opt2fn_null("-m", NFILE, fnm);
789 comp_trx(oenv, fn1, fn2, bRMSD, ftol, abstol);
793 chk_trj(oenv, fn1, opt2fn_null("-s1", NFILE, fnm), ftol);
797 fprintf(stderr, "Please give me TWO trajectory (.xtc/.trr/.tng) files!\n");
800 fn1 = opt2fn_null("-s1", NFILE, fnm);
801 fn2 = opt2fn_null("-s2", NFILE, fnm);
802 if ((fn1 && fn2) || bCompAB)
808 gmx_fatal(FARGS, "With -ab you need to set the -s1 option");
812 comp_tpx(fn1, fn2, bRMSD, ftol, abstol);
816 tpx2methods(fn1, tex);
818 else if ((fn1 && !opt2fn_null("-f", NFILE, fnm)) || (!fn1 && fn2))
820 fprintf(stderr, "Please give me TWO run input (.tpr) files\n"
821 "or specify the -m flag to generate a methods.tex file\n");
824 fn1 = opt2fn_null("-e", NFILE, fnm);
825 fn2 = opt2fn_null("-e2", NFILE, fnm);
828 comp_enx(fn1, fn2, ftol, abstol, lastener);
832 chk_enx(ftp2fn(efEDR, NFILE, fnm));
836 fprintf(stderr, "Please give me TWO energy (.edr/.ene) files!\n");
839 if (ftp2bSet(efTPS, NFILE, fnm))
841 chk_tps(ftp2fn(efTPS, NFILE, fnm), vdw_fac, bon_lo, bon_hi);
844 if (ftp2bSet(efNDX, NFILE, fnm))
846 chk_ndx(ftp2fn(efNDX, NFILE, fnm));