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.
46 #include "gromacs/commandline/pargs.h"
48 #include "gromacs/utility/fatalerror.h"
50 #include "gromacs/math/vec.h"
51 #include "gromacs/pbcutil/pbc.h"
52 #include "gromacs/math/units.h"
54 #include "gromacs/utility/smalloc.h"
56 #include "mtop_util.h"
57 #include "gromacs/utility/futil.h"
58 #include "gromacs/fileio/gmxfio.h"
59 #include "gromacs/fileio/trnio.h"
60 #include "gromacs/fileio/xtcio.h"
61 #include "gromacs/fileio/confio.h"
62 #include "gromacs/fileio/enxio.h"
63 #include "gromacs/fileio/tpxio.h"
64 #include "gromacs/fileio/trxio.h"
65 #include "gromacs/topology/block.h"
89 static void tpx2system(FILE *fp, gmx_mtop_t *mtop)
91 int i, nmol, nvsite = 0;
92 gmx_mtop_atomloop_block_t aloop;
95 fprintf(fp, "\\subsection{Simulation system}\n");
96 aloop = gmx_mtop_atomloop_block_init(mtop);
97 while (gmx_mtop_atomloop_block_next(aloop, &atom, &nmol))
99 if (atom->ptype == eptVSite)
104 fprintf(fp, "A system of %d molecules (%d atoms) was simulated.\n",
105 mtop->mols.nr, mtop->natoms-nvsite);
108 fprintf(fp, "Virtual sites were used in some of the molecules.\n");
113 static void tpx2params(FILE *fp, t_inputrec *ir)
115 fprintf(fp, "\\subsection{Simulation settings}\n");
116 fprintf(fp, "A total of %g ns were simulated with a time step of %g fs.\n",
117 ir->nsteps*ir->delta_t*0.001, 1000*ir->delta_t);
118 fprintf(fp, "Neighbor searching was performed every %d steps.\n", ir->nstlist);
119 fprintf(fp, "The %s algorithm was used for electrostatic interactions.\n",
120 EELTYPE(ir->coulombtype));
121 fprintf(fp, "with a cut-off of %g nm.\n", ir->rcoulomb);
122 if (ir->coulombtype == eelPME)
124 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);
126 if (ir->rvdw > ir->rlist)
128 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);
132 fprintf(fp, "A single cut-off of %g was used for Van der Waals interactions.\n", ir->rlist);
136 fprintf(fp, "Temperature coupling was done with the %s algorithm.\n",
137 etcoupl_names[ir->etc]);
141 fprintf(fp, "Pressure coupling was done with the %s algorithm.\n",
142 epcoupl_names[ir->epc]);
147 static void tpx2methods(const char *tpx, const char *tex)
155 read_tpx_state(tpx, &ir, &state, NULL, &mtop);
156 fp = gmx_fio_fopen(tex, "w");
157 fprintf(fp, "\\section{Methods}\n");
158 tpx2system(fp, &mtop);
163 static void chk_coords(int frame, int natoms, rvec *x, matrix box, real fac, real tol)
169 for (i = 0; (i < natoms); i++)
171 for (j = 0; (j < DIM); j++)
173 if ((vol > 0) && (fabs(x[i][j]) > fac*box[j][j]))
175 printf("Warning at frame %d: coordinates for atom %d are large (%g)\n",
179 if ((fabs(x[i][XX]) < tol) &&
180 (fabs(x[i][YY]) < tol) &&
181 (fabs(x[i][ZZ]) < tol))
188 printf("Warning at frame %d: there are %d particles with all coordinates zero\n",
193 static void chk_vels(int frame, int natoms, rvec *v)
197 for (i = 0; (i < natoms); i++)
199 for (j = 0; (j < DIM); j++)
201 if (fabs(v[i][j]) > 500)
203 printf("Warning at frame %d. Velocities for atom %d are large (%g)\n",
210 static void chk_forces(int frame, int natoms, rvec *f)
214 for (i = 0; (i < natoms); i++)
216 for (j = 0; (j < DIM); j++)
218 if (fabs(f[i][j]) > 10000)
220 printf("Warning at frame %d. Forces for atom %d are large (%g)\n",
227 static void chk_bonds(t_idef *idef, int ePBC, rvec *x, matrix box, real tol)
229 int ftype, i, k, ai, aj, type;
230 real b0, blen, deviation, devtot;
235 set_pbc(&pbc, ePBC, box);
236 for (ftype = 0; (ftype < F_NRE); ftype++)
238 if ((interaction_function[ftype].flags & IF_CHEMBOND) == IF_CHEMBOND)
240 for (k = 0; (k < idef->il[ftype].nr); )
242 type = idef->il[ftype].iatoms[k++];
243 ai = idef->il[ftype].iatoms[k++];
244 aj = idef->il[ftype].iatoms[k++];
249 b0 = idef->iparams[type].harmonic.rA;
252 b0 = sqrt(idef->iparams[type].harmonic.rA);
255 b0 = idef->iparams[type].morse.b0A;
258 b0 = idef->iparams[type].cubic.b0;
261 b0 = idef->iparams[type].constr.dA;
268 pbc_dx(&pbc, x[ai], x[aj], dx);
270 deviation = sqr(blen-b0);
271 if (sqrt(deviation/sqr(b0) > tol))
273 fprintf(stderr, "Distance between atoms %d and %d is %.3f, should be %.3f\n", ai+1, aj+1, blen, b0);
281 void chk_trj(const output_env_t oenv, const char *fn, const char *tpr, real tol)
285 t_fr_time first, last;
286 int j = -1, new_natoms, natoms;
287 real rdum, tt, old_t1, old_t2, prec;
288 gmx_bool bShowTimestep = TRUE, bOK, newline = FALSE;
291 gmx_localtop_t *top = NULL;
297 read_tpx_state(tpr, &ir, &state, NULL, &mtop);
298 top = gmx_mtop_generate_local_top(&mtop, &ir);
303 printf("Checking file %s\n", fn);
333 read_first_frame(oenv, &status, fn, &fr, TRX_READ_X | TRX_READ_V | TRX_READ_F);
339 fprintf(stderr, "\n# Atoms %d\n", fr.natoms);
342 fprintf(stderr, "Precision %g (nm)\n", 1/fr.prec);
346 if ((natoms > 0) && (new_natoms != natoms))
348 fprintf(stderr, "\nNumber of atoms at t=%g don't match (%d, %d)\n",
349 old_t1, natoms, new_natoms);
354 if (fabs((fr.time-old_t1)-(old_t1-old_t2)) >
355 0.1*(fabs(fr.time-old_t1)+fabs(old_t1-old_t2)) )
357 bShowTimestep = FALSE;
358 fprintf(stderr, "%sTimesteps at t=%g don't match (%g, %g)\n",
359 newline ? "\n" : "", old_t1, old_t1-old_t2, fr.time-old_t1);
365 chk_bonds(&top->idef, ir.ePBC, fr.x, fr.box, tol);
369 chk_coords(j, natoms, fr.x, fr.box, 1e5, tol);
373 chk_vels(j, natoms, fr.v);
377 chk_forces(j, natoms, fr.f);
383 new_natoms = fr.natoms;
384 #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++; \
386 INC(fr, count, first, last, bStep);
387 INC(fr, count, first, last, bTime);
388 INC(fr, count, first, last, bLambda);
389 INC(fr, count, first, last, bX);
390 INC(fr, count, first, last, bV);
391 INC(fr, count, first, last, bF);
392 INC(fr, count, first, last, bBox);
395 while (read_next_frame(oenv, status, &fr));
397 fprintf(stderr, "\n");
401 fprintf(stderr, "\nItem #frames");
404 fprintf(stderr, " Timestep (ps)");
406 fprintf(stderr, "\n");
407 #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")
408 PRINTITEM ( "Step", bStep );
409 PRINTITEM ( "Time", bTime );
410 PRINTITEM ( "Lambda", bLambda );
411 PRINTITEM ( "Coords", bX );
412 PRINTITEM ( "Velocities", bV );
413 PRINTITEM ( "Forces", bF );
414 PRINTITEM ( "Box", bBox );
417 void chk_tps(const char *fn, real vdw_fac, real bon_lo, real bon_hi)
428 gmx_bool bV, bX, bB, bFirst, bOut;
429 real r2, ekin, temp1, temp2, dist2, vdwfac2, bonlo2, bonhi2;
433 fprintf(stderr, "Checking coordinate file %s\n", fn);
434 read_tps_conf(fn, title, &top, &ePBC, &x, &v, box, TRUE);
437 fprintf(stderr, "%d atoms in file\n", atoms->nr);
439 /* check coordinates and box */
442 for (i = 0; (i < natom) && !(bV && bX); i++)
444 for (j = 0; (j < DIM) && !(bV && bX); j++)
446 bV = bV || (v[i][j] != 0);
447 bX = bX || (x[i][j] != 0);
451 for (i = 0; (i < DIM) && !bB; i++)
453 for (j = 0; (j < DIM) && !bB; j++)
455 bB = bB || (box[i][j] != 0);
459 fprintf(stderr, "coordinates %s\n", bX ? "found" : "absent");
460 fprintf(stderr, "box %s\n", bB ? "found" : "absent");
461 fprintf(stderr, "velocities %s\n", bV ? "found" : "absent");
462 fprintf(stderr, "\n");
464 /* check velocities */
468 for (i = 0; (i < natom); i++)
470 for (j = 0; (j < DIM); j++)
472 ekin += 0.5*atoms->atom[i].m*v[i][j]*v[i][j];
475 temp1 = (2.0*ekin)/(natom*DIM*BOLTZ);
476 temp2 = (2.0*ekin)/(natom*(DIM-1)*BOLTZ);
477 fprintf(stderr, "Kinetic energy: %g (kJ/mol)\n", ekin);
478 fprintf(stderr, "Assuming the number of degrees of freedom to be "
479 "Natoms * %d or Natoms * %d,\n"
480 "the velocities correspond to a temperature of the system\n"
481 "of %g K or %g K respectively.\n\n", DIM, DIM-1, temp1, temp2);
484 /* check coordinates */
487 vdwfac2 = sqr(vdw_fac);
488 bonlo2 = sqr(bon_lo);
489 bonhi2 = sqr(bon_hi);
492 "Checking for atoms closer than %g and not between %g and %g,\n"
493 "relative to sum of Van der Waals distance:\n",
494 vdw_fac, bon_lo, bon_hi);
495 snew(atom_vdw, natom);
496 aps = gmx_atomprop_init();
497 for (i = 0; (i < natom); i++)
499 gmx_atomprop_query(aps, epropVDW,
500 *(atoms->resinfo[atoms->atom[i].resind].name),
501 *(atoms->atomname[i]), &(atom_vdw[i]));
504 fprintf(debug, "%5d %4s %4s %7g\n", i+1,
505 *(atoms->resinfo[atoms->atom[i].resind].name),
506 *(atoms->atomname[i]),
510 gmx_atomprop_destroy(aps);
513 set_pbc(&pbc, ePBC, box);
517 for (i = 0; (i < natom); i++)
521 fprintf(stderr, "\r%5d", i+1);
523 for (j = i+1; (j < natom); j++)
527 pbc_dx(&pbc, x[i], x[j], dx);
531 rvec_sub(x[i], x[j], dx);
534 dist2 = sqr(atom_vdw[i]+atom_vdw[j]);
535 if ( (r2 <= dist2*bonlo2) ||
536 ( (r2 >= dist2*bonhi2) && (r2 <= dist2*vdwfac2) ) )
540 fprintf(stderr, "\r%5s %4s %8s %5s %5s %4s %8s %5s %6s\n",
541 "atom#", "name", "residue", "r_vdw",
542 "atom#", "name", "residue", "r_vdw", "distance");
546 "\r%5d %4s %4s%4d %-5.3g %5d %4s %4s%4d %-5.3g %-6.4g\n",
547 i+1, *(atoms->atomname[i]),
548 *(atoms->resinfo[atoms->atom[i].resind].name),
549 atoms->resinfo[atoms->atom[i].resind].nr,
551 j+1, *(atoms->atomname[j]),
552 *(atoms->resinfo[atoms->atom[j].resind].name),
553 atoms->resinfo[atoms->atom[j].resind].nr,
561 fprintf(stderr, "\rno close atoms found\n");
563 fprintf(stderr, "\r \n");
570 for (i = 0; (i < natom) && (k < 10); i++)
573 for (j = 0; (j < DIM) && !bOut; j++)
575 bOut = bOut || (x[i][j] < 0) || (x[i][j] > box[j][j]);
582 fprintf(stderr, "Atoms outside box ( ");
583 for (j = 0; (j < DIM); j++)
585 fprintf(stderr, "%g ", box[j][j]);
587 fprintf(stderr, "):\n"
588 "(These may occur often and are normally not a problem)\n"
589 "%5s %4s %8s %5s %s\n",
590 "atom#", "name", "residue", "r_vdw", "coordinate");
594 "%5d %4s %4s%4d %-5.3g",
595 i, *(atoms->atomname[i]),
596 *(atoms->resinfo[atoms->atom[i].resind].name),
597 atoms->resinfo[atoms->atom[i].resind].nr, atom_vdw[i]);
598 for (j = 0; (j < DIM); j++)
600 fprintf(stderr, " %6.3g", x[i][j]);
602 fprintf(stderr, "\n");
607 fprintf(stderr, "(maybe more)\n");
611 fprintf(stderr, "no atoms found outside box\n");
613 fprintf(stderr, "\n");
618 void chk_ndx(const char *fn)
624 grps = init_index(fn, &grpname);
627 pr_blocka(debug, 0, fn, grps, FALSE);
631 printf("Contents of index file %s\n", fn);
632 printf("--------------------------------------------------\n");
633 printf("Nr. Group #Entries First Last\n");
634 for (i = 0; (i < grps->nr); i++)
636 printf("%4d %-20s%8d%8d%8d\n", i, grpname[i],
637 grps->index[i+1]-grps->index[i],
638 grps->a[grps->index[i]]+1,
639 grps->a[grps->index[i+1]-1]+1);
642 for (i = 0; (i < grps->nr); i++)
650 void chk_enx(const char *fn)
654 gmx_enxnm_t *enm = NULL;
657 real t0, old_t1, old_t2;
660 fprintf(stderr, "Checking energy file %s\n\n", fn);
662 in = open_enx(fn, "r");
663 do_enxnms(in, &nre, &enm);
664 fprintf(stderr, "%d groups in energy file", nre);
672 while (do_enx(in, fr))
676 if (fabs((fr->t-old_t1)-(old_t1-old_t2)) >
677 0.1*(fabs(fr->t-old_t1)+fabs(old_t1-old_t2)) )
680 fprintf(stderr, "\nTimesteps at t=%g don't match (%g, %g)\n",
681 old_t1, old_t1-old_t2, fr->t-old_t1);
692 fprintf(stderr, "\rframe: %6s (index %6d), t: %10.3f\n",
693 gmx_step_str(fr->step, buf), fnr, fr->t);
697 fprintf(stderr, "\n\nFound %d frames", fnr);
698 if (bShowTStep && fnr > 1)
700 fprintf(stderr, " with a timestep of %g ps", (old_t1-t0)/(fnr-1));
702 fprintf(stderr, ".\n");
705 free_enxnms(nre, enm);
709 int gmx_check(int argc, char *argv[])
711 const char *desc[] = {
712 "[THISMODULE] reads a trajectory ([TT].trj[tt], [TT].trr[tt] or ",
713 "[TT].xtc[tt]), an energy file ([TT].ene[tt] or [TT].edr[tt])",
714 "or an index file ([TT].ndx[tt])",
715 "and prints out useful information about them.[PAR]",
716 "Option [TT]-c[tt] checks for presence of coordinates,",
717 "velocities and box in the file, for close contacts (smaller than",
718 "[TT]-vdwfac[tt] and not bonded, i.e. not between [TT]-bonlo[tt]",
719 "and [TT]-bonhi[tt], all relative to the sum of both Van der Waals",
720 "radii) and atoms outside the box (these may occur often and are",
721 "no problem). If velocities are present, an estimated temperature",
722 "will be calculated from them.[PAR]",
723 "If an index file, is given its contents will be summarized.[PAR]",
724 "If both a trajectory and a [TT].tpr[tt] file are given (with [TT]-s1[tt])",
725 "the program will check whether the bond lengths defined in the tpr",
726 "file are indeed correct in the trajectory. If not you may have",
727 "non-matching files due to e.g. deshuffling or due to problems with",
728 "virtual sites. With these flags, [TT]gmx check[tt] provides a quick check for such problems.[PAR]",
729 "The program can compare two run input ([TT].tpr[tt], [TT].tpb[tt] or",
730 "[TT].tpa[tt]) files",
731 "when both [TT]-s1[tt] and [TT]-s2[tt] are supplied.",
732 "Similarly a pair of trajectory files can be compared (using the [TT]-f2[tt]",
733 "option), or a pair of energy files (using the [TT]-e2[tt] option).[PAR]",
734 "For free energy simulations the A and B state topology from one",
735 "run input file can be compared with options [TT]-s1[tt] and [TT]-ab[tt].[PAR]",
736 "In case the [TT]-m[tt] flag is given a LaTeX file will be written",
737 "consisting of a rough outline for a methods section for a paper."
740 { efTRX, "-f", NULL, ffOPTRD },
741 { efTRX, "-f2", NULL, ffOPTRD },
742 { efTPX, "-s1", "top1", ffOPTRD },
743 { efTPX, "-s2", "top2", ffOPTRD },
744 { efTPS, "-c", NULL, ffOPTRD },
745 { efEDR, "-e", NULL, ffOPTRD },
746 { efEDR, "-e2", "ener2", ffOPTRD },
747 { efNDX, "-n", NULL, ffOPTRD },
748 { efTEX, "-m", NULL, ffOPTWR }
750 #define NFILE asize(fnm)
751 const char *fn1 = NULL, *fn2 = NULL, *tex = NULL;
754 static real vdw_fac = 0.8;
755 static real bon_lo = 0.4;
756 static real bon_hi = 0.7;
757 static gmx_bool bRMSD = FALSE;
758 static real ftol = 0.001;
759 static real abstol = 0.001;
760 static gmx_bool bCompAB = FALSE;
761 static char *lastener = NULL;
762 static t_pargs pa[] = {
763 { "-vdwfac", FALSE, etREAL, {&vdw_fac},
764 "Fraction of sum of VdW radii used as warning cutoff" },
765 { "-bonlo", FALSE, etREAL, {&bon_lo},
766 "Min. fract. of sum of VdW radii for bonded atoms" },
767 { "-bonhi", FALSE, etREAL, {&bon_hi},
768 "Max. fract. of sum of VdW radii for bonded atoms" },
769 { "-rmsd", FALSE, etBOOL, {&bRMSD},
770 "Print RMSD for x, v and f" },
771 { "-tol", FALSE, etREAL, {&ftol},
772 "Relative tolerance for comparing real values defined as [MATH]2*(a-b)/([MAG]a[mag]+[MAG]b[mag])[math]" },
773 { "-abstol", FALSE, etREAL, {&abstol},
774 "Absolute tolerance, useful when sums are close to zero." },
775 { "-ab", FALSE, etBOOL, {&bCompAB},
776 "Compare the A and B topology from one file" },
777 { "-lastener", FALSE, etSTR, {&lastener},
778 "Last energy term to compare (if not given all are tested). It makes sense to go up until the Pressure." }
781 if (!parse_common_args(&argc, argv, 0, NFILE, fnm, asize(pa), pa,
782 asize(desc), desc, 0, NULL, &oenv))
787 fn1 = opt2fn_null("-f", NFILE, fnm);
788 fn2 = opt2fn_null("-f2", NFILE, fnm);
789 tex = opt2fn_null("-m", NFILE, fnm);
792 comp_trx(oenv, fn1, fn2, bRMSD, ftol, abstol);
796 chk_trj(oenv, fn1, opt2fn_null("-s1", NFILE, fnm), ftol);
800 fprintf(stderr, "Please give me TWO trajectory (.xtc/.trr/.trj) files!\n");
803 fn1 = opt2fn_null("-s1", NFILE, fnm);
804 fn2 = opt2fn_null("-s2", NFILE, fnm);
805 if ((fn1 && fn2) || bCompAB)
811 gmx_fatal(FARGS, "With -ab you need to set the -s1 option");
815 comp_tpx(fn1, fn2, bRMSD, ftol, abstol);
819 tpx2methods(fn1, tex);
821 else if ((fn1 && !opt2fn_null("-f", NFILE, fnm)) || (!fn1 && fn2))
823 fprintf(stderr, "Please give me TWO run input (.tpr/.tpa/.tpb) files\n"
824 "or specify the -m flag to generate a methods.tex file\n");
827 fn1 = opt2fn_null("-e", NFILE, fnm);
828 fn2 = opt2fn_null("-e2", NFILE, fnm);
831 comp_enx(fn1, fn2, ftol, abstol, lastener);
835 chk_enx(ftp2fn(efEDR, NFILE, fnm));
839 fprintf(stderr, "Please give me TWO energy (.edr/.ene) files!\n");
842 if (ftp2bSet(efTPS, NFILE, fnm))
844 chk_tps(ftp2fn(efTPS, NFILE, fnm), vdw_fac, bon_lo, bon_hi);
847 if (ftp2bSet(efNDX, NFILE, fnm))
849 chk_ndx(ftp2fn(efNDX, NFILE, fnm));