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.
45 #include "gromacs/legacyheaders/macros.h"
46 #include "gromacs/legacyheaders/txtdump.h"
47 #include "gromacs/math/vec.h"
48 #include "gromacs/math/units.h"
49 #include "gromacs/topology/index.h"
50 #include "gromacs/legacyheaders/names.h"
51 #include "gromacs/utility/futil.h"
52 #include "gromacs/fileio/gmxfio.h"
53 #include "gromacs/fileio/trnio.h"
54 #include "gromacs/fileio/xtcio.h"
55 #include "gromacs/fileio/confio.h"
56 #include "gromacs/fileio/enxio.h"
57 #include "gromacs/fileio/tpxio.h"
58 #include "gromacs/fileio/trxio.h"
60 #include "gromacs/commandline/pargs.h"
61 #include "gromacs/pbcutil/pbc.h"
62 #include "gromacs/topology/atomprop.h"
63 #include "gromacs/topology/block.h"
64 #include "gromacs/topology/mtop_util.h"
65 #include "gromacs/utility/fatalerror.h"
66 #include "gromacs/utility/smalloc.h"
90 static void tpx2system(FILE *fp, gmx_mtop_t *mtop)
92 int i, nmol, nvsite = 0;
93 gmx_mtop_atomloop_block_t aloop;
96 fprintf(fp, "\\subsection{Simulation system}\n");
97 aloop = gmx_mtop_atomloop_block_init(mtop);
98 while (gmx_mtop_atomloop_block_next(aloop, &atom, &nmol))
100 if (atom->ptype == eptVSite)
105 fprintf(fp, "A system of %d molecules (%d atoms) was simulated.\n",
106 mtop->mols.nr, mtop->natoms-nvsite);
109 fprintf(fp, "Virtual sites were used in some of the molecules.\n");
114 static void tpx2params(FILE *fp, t_inputrec *ir)
116 fprintf(fp, "\\subsection{Simulation settings}\n");
117 fprintf(fp, "A total of %g ns were simulated with a time step of %g fs.\n",
118 ir->nsteps*ir->delta_t*0.001, 1000*ir->delta_t);
119 fprintf(fp, "Neighbor searching was performed every %d steps.\n", ir->nstlist);
120 fprintf(fp, "The %s algorithm was used for electrostatic interactions.\n",
121 EELTYPE(ir->coulombtype));
122 fprintf(fp, "with a cut-off of %g nm.\n", ir->rcoulomb);
123 if (ir->coulombtype == eelPME)
125 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);
127 if (ir->rvdw > ir->rlist)
129 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);
133 fprintf(fp, "A single cut-off of %g was used for Van der Waals interactions.\n", ir->rlist);
137 fprintf(fp, "Temperature coupling was done with the %s algorithm.\n",
138 etcoupl_names[ir->etc]);
142 fprintf(fp, "Pressure coupling was done with the %s algorithm.\n",
143 epcoupl_names[ir->epc]);
148 static void tpx2methods(const char *tpx, const char *tex)
156 read_tpx_state(tpx, &ir, &state, NULL, &mtop);
157 fp = gmx_fio_fopen(tex, "w");
158 fprintf(fp, "\\section{Methods}\n");
159 tpx2system(fp, &mtop);
164 static void chk_coords(int frame, int natoms, rvec *x, matrix box, real fac, real tol)
170 for (i = 0; (i < natoms); i++)
172 for (j = 0; (j < DIM); j++)
174 if ((vol > 0) && (fabs(x[i][j]) > fac*box[j][j]))
176 printf("Warning at frame %d: coordinates for atom %d are large (%g)\n",
180 if ((fabs(x[i][XX]) < tol) &&
181 (fabs(x[i][YY]) < tol) &&
182 (fabs(x[i][ZZ]) < tol))
189 printf("Warning at frame %d: there are %d particles with all coordinates zero\n",
194 static void chk_vels(int frame, int natoms, rvec *v)
198 for (i = 0; (i < natoms); i++)
200 for (j = 0; (j < DIM); j++)
202 if (fabs(v[i][j]) > 500)
204 printf("Warning at frame %d. Velocities for atom %d are large (%g)\n",
211 static void chk_forces(int frame, int natoms, rvec *f)
215 for (i = 0; (i < natoms); i++)
217 for (j = 0; (j < DIM); j++)
219 if (fabs(f[i][j]) > 10000)
221 printf("Warning at frame %d. Forces for atom %d are large (%g)\n",
228 static void chk_bonds(t_idef *idef, int ePBC, rvec *x, matrix box, real tol)
230 int ftype, i, k, ai, aj, type;
231 real b0, blen, deviation, devtot;
236 set_pbc(&pbc, ePBC, box);
237 for (ftype = 0; (ftype < F_NRE); ftype++)
239 if ((interaction_function[ftype].flags & IF_CHEMBOND) == IF_CHEMBOND)
241 for (k = 0; (k < idef->il[ftype].nr); )
243 type = idef->il[ftype].iatoms[k++];
244 ai = idef->il[ftype].iatoms[k++];
245 aj = idef->il[ftype].iatoms[k++];
250 b0 = idef->iparams[type].harmonic.rA;
253 b0 = sqrt(idef->iparams[type].harmonic.rA);
256 b0 = idef->iparams[type].morse.b0A;
259 b0 = idef->iparams[type].cubic.b0;
262 b0 = idef->iparams[type].constr.dA;
269 pbc_dx(&pbc, x[ai], x[aj], dx);
271 deviation = sqr(blen-b0);
272 if (sqrt(deviation/sqr(b0) > tol))
274 fprintf(stderr, "Distance between atoms %d and %d is %.3f, should be %.3f\n", ai+1, aj+1, blen, b0);
282 void chk_trj(const output_env_t oenv, const char *fn, const char *tpr, real tol)
286 t_fr_time first, last;
287 int j = -1, new_natoms, natoms;
288 real rdum, tt, old_t1, old_t2, prec;
289 gmx_bool bShowTimestep = TRUE, bOK, newline = FALSE;
292 gmx_localtop_t *top = NULL;
298 read_tpx_state(tpr, &ir, &state, NULL, &mtop);
299 top = gmx_mtop_generate_local_top(&mtop, &ir);
304 printf("Checking file %s\n", fn);
334 read_first_frame(oenv, &status, fn, &fr, TRX_READ_X | TRX_READ_V | TRX_READ_F);
340 fprintf(stderr, "\n# Atoms %d\n", fr.natoms);
343 fprintf(stderr, "Precision %g (nm)\n", 1/fr.prec);
347 if ((natoms > 0) && (new_natoms != natoms))
349 fprintf(stderr, "\nNumber of atoms at t=%g don't match (%d, %d)\n",
350 old_t1, natoms, new_natoms);
355 if (fabs((fr.time-old_t1)-(old_t1-old_t2)) >
356 0.1*(fabs(fr.time-old_t1)+fabs(old_t1-old_t2)) )
358 bShowTimestep = FALSE;
359 fprintf(stderr, "%sTimesteps at t=%g don't match (%g, %g)\n",
360 newline ? "\n" : "", old_t1, old_t1-old_t2, fr.time-old_t1);
366 chk_bonds(&top->idef, ir.ePBC, fr.x, fr.box, tol);
370 chk_coords(j, natoms, fr.x, fr.box, 1e5, tol);
374 chk_vels(j, natoms, fr.v);
378 chk_forces(j, natoms, fr.f);
384 new_natoms = fr.natoms;
385 #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++; \
387 INC(fr, count, first, last, bStep);
388 INC(fr, count, first, last, bTime);
389 INC(fr, count, first, last, bLambda);
390 INC(fr, count, first, last, bX);
391 INC(fr, count, first, last, bV);
392 INC(fr, count, first, last, bF);
393 INC(fr, count, first, last, bBox);
396 while (read_next_frame(oenv, status, &fr));
398 fprintf(stderr, "\n");
402 fprintf(stderr, "\nItem #frames");
405 fprintf(stderr, " Timestep (ps)");
407 fprintf(stderr, "\n");
408 #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")
409 PRINTITEM ( "Step", bStep );
410 PRINTITEM ( "Time", bTime );
411 PRINTITEM ( "Lambda", bLambda );
412 PRINTITEM ( "Coords", bX );
413 PRINTITEM ( "Velocities", bV );
414 PRINTITEM ( "Forces", bF );
415 PRINTITEM ( "Box", bBox );
418 void chk_tps(const char *fn, real vdw_fac, real bon_lo, real bon_hi)
429 gmx_bool bV, bX, bB, bFirst, bOut;
430 real r2, ekin, temp1, temp2, dist2, vdwfac2, bonlo2, bonhi2;
434 fprintf(stderr, "Checking coordinate file %s\n", fn);
435 read_tps_conf(fn, title, &top, &ePBC, &x, &v, box, TRUE);
438 fprintf(stderr, "%d atoms in file\n", atoms->nr);
440 /* check coordinates and box */
443 for (i = 0; (i < natom) && !(bV && bX); i++)
445 for (j = 0; (j < DIM) && !(bV && bX); j++)
447 bV = bV || (v[i][j] != 0);
448 bX = bX || (x[i][j] != 0);
452 for (i = 0; (i < DIM) && !bB; i++)
454 for (j = 0; (j < DIM) && !bB; j++)
456 bB = bB || (box[i][j] != 0);
460 fprintf(stderr, "coordinates %s\n", bX ? "found" : "absent");
461 fprintf(stderr, "box %s\n", bB ? "found" : "absent");
462 fprintf(stderr, "velocities %s\n", bV ? "found" : "absent");
463 fprintf(stderr, "\n");
465 /* check velocities */
469 for (i = 0; (i < natom); i++)
471 for (j = 0; (j < DIM); j++)
473 ekin += 0.5*atoms->atom[i].m*v[i][j]*v[i][j];
476 temp1 = (2.0*ekin)/(natom*DIM*BOLTZ);
477 temp2 = (2.0*ekin)/(natom*(DIM-1)*BOLTZ);
478 fprintf(stderr, "Kinetic energy: %g (kJ/mol)\n", ekin);
479 fprintf(stderr, "Assuming the number of degrees of freedom to be "
480 "Natoms * %d or Natoms * %d,\n"
481 "the velocities correspond to a temperature of the system\n"
482 "of %g K or %g K respectively.\n\n", DIM, DIM-1, temp1, temp2);
485 /* check coordinates */
488 vdwfac2 = sqr(vdw_fac);
489 bonlo2 = sqr(bon_lo);
490 bonhi2 = sqr(bon_hi);
493 "Checking for atoms closer than %g and not between %g and %g,\n"
494 "relative to sum of Van der Waals distance:\n",
495 vdw_fac, bon_lo, bon_hi);
496 snew(atom_vdw, natom);
497 aps = gmx_atomprop_init();
498 for (i = 0; (i < natom); i++)
500 gmx_atomprop_query(aps, epropVDW,
501 *(atoms->resinfo[atoms->atom[i].resind].name),
502 *(atoms->atomname[i]), &(atom_vdw[i]));
505 fprintf(debug, "%5d %4s %4s %7g\n", i+1,
506 *(atoms->resinfo[atoms->atom[i].resind].name),
507 *(atoms->atomname[i]),
511 gmx_atomprop_destroy(aps);
514 set_pbc(&pbc, ePBC, box);
518 for (i = 0; (i < natom); i++)
522 fprintf(stderr, "\r%5d", i+1);
524 for (j = i+1; (j < natom); j++)
528 pbc_dx(&pbc, x[i], x[j], dx);
532 rvec_sub(x[i], x[j], dx);
535 dist2 = sqr(atom_vdw[i]+atom_vdw[j]);
536 if ( (r2 <= dist2*bonlo2) ||
537 ( (r2 >= dist2*bonhi2) && (r2 <= dist2*vdwfac2) ) )
541 fprintf(stderr, "\r%5s %4s %8s %5s %5s %4s %8s %5s %6s\n",
542 "atom#", "name", "residue", "r_vdw",
543 "atom#", "name", "residue", "r_vdw", "distance");
547 "\r%5d %4s %4s%4d %-5.3g %5d %4s %4s%4d %-5.3g %-6.4g\n",
548 i+1, *(atoms->atomname[i]),
549 *(atoms->resinfo[atoms->atom[i].resind].name),
550 atoms->resinfo[atoms->atom[i].resind].nr,
552 j+1, *(atoms->atomname[j]),
553 *(atoms->resinfo[atoms->atom[j].resind].name),
554 atoms->resinfo[atoms->atom[j].resind].nr,
562 fprintf(stderr, "\rno close atoms found\n");
564 fprintf(stderr, "\r \n");
571 for (i = 0; (i < natom) && (k < 10); i++)
574 for (j = 0; (j < DIM) && !bOut; j++)
576 bOut = bOut || (x[i][j] < 0) || (x[i][j] > box[j][j]);
583 fprintf(stderr, "Atoms outside box ( ");
584 for (j = 0; (j < DIM); j++)
586 fprintf(stderr, "%g ", box[j][j]);
588 fprintf(stderr, "):\n"
589 "(These may occur often and are normally not a problem)\n"
590 "%5s %4s %8s %5s %s\n",
591 "atom#", "name", "residue", "r_vdw", "coordinate");
595 "%5d %4s %4s%4d %-5.3g",
596 i, *(atoms->atomname[i]),
597 *(atoms->resinfo[atoms->atom[i].resind].name),
598 atoms->resinfo[atoms->atom[i].resind].nr, atom_vdw[i]);
599 for (j = 0; (j < DIM); j++)
601 fprintf(stderr, " %6.3g", x[i][j]);
603 fprintf(stderr, "\n");
608 fprintf(stderr, "(maybe more)\n");
612 fprintf(stderr, "no atoms found outside box\n");
614 fprintf(stderr, "\n");
619 void chk_ndx(const char *fn)
625 grps = init_index(fn, &grpname);
628 pr_blocka(debug, 0, fn, grps, FALSE);
632 printf("Contents of index file %s\n", fn);
633 printf("--------------------------------------------------\n");
634 printf("Nr. Group #Entries First Last\n");
635 for (i = 0; (i < grps->nr); i++)
637 printf("%4d %-20s%8d%8d%8d\n", i, grpname[i],
638 grps->index[i+1]-grps->index[i],
639 grps->a[grps->index[i]]+1,
640 grps->a[grps->index[i+1]-1]+1);
643 for (i = 0; (i < grps->nr); i++)
651 void chk_enx(const char *fn)
655 gmx_enxnm_t *enm = NULL;
658 real t0, old_t1, old_t2;
661 fprintf(stderr, "Checking energy file %s\n\n", fn);
663 in = open_enx(fn, "r");
664 do_enxnms(in, &nre, &enm);
665 fprintf(stderr, "%d groups in energy file", nre);
673 while (do_enx(in, fr))
677 if (fabs((fr->t-old_t1)-(old_t1-old_t2)) >
678 0.1*(fabs(fr->t-old_t1)+fabs(old_t1-old_t2)) )
681 fprintf(stderr, "\nTimesteps at t=%g don't match (%g, %g)\n",
682 old_t1, old_t1-old_t2, fr->t-old_t1);
693 fprintf(stderr, "\rframe: %6s (index %6d), t: %10.3f\n",
694 gmx_step_str(fr->step, buf), fnr, fr->t);
698 fprintf(stderr, "\n\nFound %d frames", fnr);
699 if (bShowTStep && fnr > 1)
701 fprintf(stderr, " with a timestep of %g ps", (old_t1-t0)/(fnr-1));
703 fprintf(stderr, ".\n");
706 free_enxnms(nre, enm);
710 int gmx_check(int argc, char *argv[])
712 const char *desc[] = {
713 "[THISMODULE] reads a trajectory ([TT].trj[tt], [TT].trr[tt] or ",
714 "[TT].xtc[tt]), an energy file ([TT].ene[tt] or [TT].edr[tt])",
715 "or an index file ([TT].ndx[tt])",
716 "and prints out useful information about them.[PAR]",
717 "Option [TT]-c[tt] checks for presence of coordinates,",
718 "velocities and box in the file, for close contacts (smaller than",
719 "[TT]-vdwfac[tt] and not bonded, i.e. not between [TT]-bonlo[tt]",
720 "and [TT]-bonhi[tt], all relative to the sum of both Van der Waals",
721 "radii) and atoms outside the box (these may occur often and are",
722 "no problem). If velocities are present, an estimated temperature",
723 "will be calculated from them.[PAR]",
724 "If an index file, is given its contents will be summarized.[PAR]",
725 "If both a trajectory and a [TT].tpr[tt] file are given (with [TT]-s1[tt])",
726 "the program will check whether the bond lengths defined in the tpr",
727 "file are indeed correct in the trajectory. If not you may have",
728 "non-matching files due to e.g. deshuffling or due to problems with",
729 "virtual sites. With these flags, [TT]gmx check[tt] provides a quick check for such problems.[PAR]",
730 "The program can compare two run input ([TT].tpr[tt], [TT].tpb[tt] or",
731 "[TT].tpa[tt]) files",
732 "when both [TT]-s1[tt] and [TT]-s2[tt] are supplied.",
733 "Similarly a pair of trajectory files can be compared (using the [TT]-f2[tt]",
734 "option), or a pair of energy files (using the [TT]-e2[tt] option).[PAR]",
735 "For free energy simulations the A and B state topology from one",
736 "run input file can be compared with options [TT]-s1[tt] and [TT]-ab[tt].[PAR]",
737 "In case the [TT]-m[tt] flag is given a LaTeX file will be written",
738 "consisting of a rough outline for a methods section for a paper."
741 { efTRX, "-f", NULL, ffOPTRD },
742 { efTRX, "-f2", NULL, ffOPTRD },
743 { efTPX, "-s1", "top1", ffOPTRD },
744 { efTPX, "-s2", "top2", ffOPTRD },
745 { efTPS, "-c", NULL, ffOPTRD },
746 { efEDR, "-e", NULL, ffOPTRD },
747 { efEDR, "-e2", "ener2", ffOPTRD },
748 { efNDX, "-n", NULL, ffOPTRD },
749 { efTEX, "-m", NULL, ffOPTWR }
751 #define NFILE asize(fnm)
752 const char *fn1 = NULL, *fn2 = NULL, *tex = NULL;
755 static real vdw_fac = 0.8;
756 static real bon_lo = 0.4;
757 static real bon_hi = 0.7;
758 static gmx_bool bRMSD = FALSE;
759 static real ftol = 0.001;
760 static real abstol = 0.001;
761 static gmx_bool bCompAB = FALSE;
762 static char *lastener = NULL;
763 static t_pargs pa[] = {
764 { "-vdwfac", FALSE, etREAL, {&vdw_fac},
765 "Fraction of sum of VdW radii used as warning cutoff" },
766 { "-bonlo", FALSE, etREAL, {&bon_lo},
767 "Min. fract. of sum of VdW radii for bonded atoms" },
768 { "-bonhi", FALSE, etREAL, {&bon_hi},
769 "Max. fract. of sum of VdW radii for bonded atoms" },
770 { "-rmsd", FALSE, etBOOL, {&bRMSD},
771 "Print RMSD for x, v and f" },
772 { "-tol", FALSE, etREAL, {&ftol},
773 "Relative tolerance for comparing real values defined as [MATH]2*(a-b)/([MAG]a[mag]+[MAG]b[mag])[math]" },
774 { "-abstol", FALSE, etREAL, {&abstol},
775 "Absolute tolerance, useful when sums are close to zero." },
776 { "-ab", FALSE, etBOOL, {&bCompAB},
777 "Compare the A and B topology from one file" },
778 { "-lastener", FALSE, etSTR, {&lastener},
779 "Last energy term to compare (if not given all are tested). It makes sense to go up until the Pressure." }
782 if (!parse_common_args(&argc, argv, 0, NFILE, fnm, asize(pa), pa,
783 asize(desc), desc, 0, NULL, &oenv))
788 fn1 = opt2fn_null("-f", NFILE, fnm);
789 fn2 = opt2fn_null("-f2", NFILE, fnm);
790 tex = opt2fn_null("-m", NFILE, fnm);
793 comp_trx(oenv, fn1, fn2, bRMSD, ftol, abstol);
797 chk_trj(oenv, fn1, opt2fn_null("-s1", NFILE, fnm), ftol);
801 fprintf(stderr, "Please give me TWO trajectory (.xtc/.trr/.trj) files!\n");
804 fn1 = opt2fn_null("-s1", NFILE, fnm);
805 fn2 = opt2fn_null("-s2", NFILE, fnm);
806 if ((fn1 && fn2) || bCompAB)
812 gmx_fatal(FARGS, "With -ab you need to set the -s1 option");
816 comp_tpx(fn1, fn2, bRMSD, ftol, abstol);
820 tpx2methods(fn1, tex);
822 else if ((fn1 && !opt2fn_null("-f", NFILE, fnm)) || (!fn1 && fn2))
824 fprintf(stderr, "Please give me TWO run input (.tpr/.tpa/.tpb) files\n"
825 "or specify the -m flag to generate a methods.tex file\n");
828 fn1 = opt2fn_null("-e", NFILE, fnm);
829 fn2 = opt2fn_null("-e2", NFILE, fnm);
832 comp_enx(fn1, fn2, ftol, abstol, lastener);
836 chk_enx(ftp2fn(efEDR, NFILE, fnm));
840 fprintf(stderr, "Please give me TWO energy (.edr/.ene) files!\n");
843 if (ftp2bSet(efTPS, NFILE, fnm))
845 chk_tps(ftp2fn(efTPS, NFILE, fnm), vdw_fac, bon_lo, bon_hi);
848 if (ftp2bSet(efNDX, NFILE, fnm))
850 chk_ndx(ftp2fn(efNDX, NFILE, fnm));