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-2004, The GROMACS development team,
6 * check out http://www.gromacs.org for more information.
7 * Copyright (c) 2012, by the GROMACS development team, led by
8 * David van der Spoel, Berk Hess, Erik Lindahl, and including many
9 * others, as listed in the AUTHORS file in the top-level source
10 * directory and at http://www.gromacs.org.
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.
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.
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.
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.
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.
53 #include "gmx_fatal.h"
68 #include "mtop_util.h"
90 static void tpx2system(FILE *fp,gmx_mtop_t *mtop)
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)) {
99 if (atom->ptype == eptVSite)
102 fprintf(fp,"A system of %d molecules (%d atoms) was simulated.\n",
103 mtop->mols.nr,mtop->natoms-nvsite);
105 fprintf(fp,"Virtual sites were used in some of the molecules.\n");
109 static void tpx2params(FILE *fp,t_inputrec *ir)
111 fprintf(fp,"\\subsection{Simulation settings}\n");
112 fprintf(fp,"A total of %g ns were simulated with a time step of %g fs.\n",
113 ir->nsteps*ir->delta_t*0.001,1000*ir->delta_t);
114 fprintf(fp,"Neighbor searching was performed every %d steps.\n",ir->nstlist);
115 fprintf(fp,"The %s algorithm was used for electrostatic interactions.\n",
116 EELTYPE(ir->coulombtype));
117 fprintf(fp,"with a cut-off of %g nm.\n",ir->rcoulomb);
118 if (ir->coulombtype == eelPME)
119 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);
120 if (ir->rvdw > ir->rlist)
121 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);
123 fprintf(fp,"A single cut-off of %g was used for Van der Waals interactions.\n",ir->rlist);
125 fprintf(fp,"Temperature coupling was done with the %s algorithm.\n",
126 etcoupl_names[ir->etc]);
129 fprintf(fp,"Pressure coupling was done with the %s algorithm.\n",
130 epcoupl_names[ir->epc]);
135 static void tpx2methods(const char *tpx,const char *tex)
143 read_tpx_state(tpx,&ir,&state,NULL,&mtop);
144 fp=gmx_fio_fopen(tex,"w");
145 fprintf(fp,"\\section{Methods}\n");
146 tpx2system(fp,&mtop);
151 static void chk_coords(int frame,int natoms,rvec *x,matrix box,real fac,real tol)
157 for(i=0; (i<natoms); i++) {
158 for(j=0; (j<DIM); j++) {
159 if ((vol > 0) && (fabs(x[i][j]) > fac*box[j][j]))
160 printf("Warning at frame %d: coordinates for atom %d are large (%g)\n",
163 if ((fabs(x[i][XX]) < tol) &&
164 (fabs(x[i][YY]) < tol) &&
165 (fabs(x[i][ZZ]) < tol))
171 printf("Warning at frame %d: there are %d particles with all coordinates zero\n",
175 static void chk_vels(int frame,int natoms,rvec *v)
179 for(i=0; (i<natoms); i++) {
180 for(j=0; (j<DIM); j++) {
181 if (fabs(v[i][j]) > 500)
182 printf("Warning at frame %d. Velocities for atom %d are large (%g)\n",
188 static void chk_forces(int frame,int natoms,rvec *f)
192 for(i=0; (i<natoms); i++) {
193 for(j=0; (j<DIM); j++) {
194 if (fabs(f[i][j]) > 10000)
195 printf("Warning at frame %d. Forces for atom %d are large (%g)\n",
201 static void chk_bonds(t_idef *idef,int ePBC,rvec *x,matrix box,real tol)
203 int ftype,i,k,ai,aj,type;
204 real b0,blen,deviation,devtot;
209 set_pbc(&pbc,ePBC,box);
210 for(ftype=0; (ftype<F_NRE); ftype++)
211 if ((interaction_function[ftype].flags & IF_CHEMBOND) == IF_CHEMBOND) {
212 for(k=0; (k<idef->il[ftype].nr); ) {
213 type = idef->il[ftype].iatoms[k++];
214 ai = idef->il[ftype].iatoms[k++];
215 aj = idef->il[ftype].iatoms[k++];
219 b0 = idef->iparams[type].harmonic.rA;
222 b0 = sqrt(idef->iparams[type].harmonic.rA);
225 b0 = idef->iparams[type].morse.b0A;
228 b0 = idef->iparams[type].cubic.b0;
231 b0 = idef->iparams[type].constr.dA;
237 pbc_dx(&pbc,x[ai],x[aj],dx);
239 deviation = sqr(blen-b0);
240 if (sqrt(deviation/sqr(b0) > tol)) {
241 fprintf(stderr,"Distance between atoms %d and %d is %.3f, should be %.3f\n",ai+1,aj+1,blen,b0);
248 void chk_trj(const output_env_t oenv,const char *fn,const char *tpr,real tol)
252 t_fr_time first,last;
253 int j=-1,new_natoms,natoms;
255 real rdum,tt,old_t1,old_t2,prec;
256 gmx_bool bShowTimestep=TRUE,bOK,newline=FALSE;
259 gmx_localtop_t *top=NULL;
264 read_tpx_state(tpr,&ir,&state,NULL,&mtop);
265 top = gmx_mtop_generate_local_top(&mtop,&ir);
270 printf("Checking file %s\n",fn);
301 read_first_frame(oenv,&status,fn,&fr,TRX_READ_X | TRX_READ_V | TRX_READ_F);
305 fprintf(stderr,"\n# Atoms %d\n",fr.natoms);
307 fprintf(stderr,"Precision %g (nm)\n",1/fr.prec);
310 if ((natoms > 0) && (new_natoms != natoms)) {
311 fprintf(stderr,"\nNumber of atoms at t=%g don't match (%d, %d)\n",
312 old_t1,natoms,new_natoms);
316 if ( fabs((fr.time-old_t1)-(old_t1-old_t2)) >
317 0.1*(fabs(fr.time-old_t1)+fabs(old_t1-old_t2)) ) {
319 fprintf(stderr,"%sTimesteps at t=%g don't match (%g, %g)\n",
320 newline?"\n":"",old_t1,old_t1-old_t2,fr.time-old_t1);
325 chk_bonds(&top->idef,ir.ePBC,fr.x,fr.box,tol);
328 chk_coords(j,natoms,fr.x,fr.box,1e5,tol);
330 chk_vels(j,natoms,fr.v);
332 chk_forces(j,natoms,fr.f);
336 /*if (fpos && ((j<10 || j%10==0)))
337 fprintf(stderr," byte: %10lu",(unsigned long)fpos);*/
339 new_natoms=fr.natoms;
340 #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++; }
341 INC(fr,count,first,last,bStep);
342 INC(fr,count,first,last,bTime);
343 INC(fr,count,first,last,bLambda);
344 INC(fr,count,first,last,bX);
345 INC(fr,count,first,last,bV);
346 INC(fr,count,first,last,bF);
347 INC(fr,count,first,last,bBox);
349 fpos = gmx_fio_ftell(trx_get_fileio(status));
350 } while (read_next_frame(oenv,status,&fr));
352 fprintf(stderr,"\n");
356 fprintf(stderr,"\nItem #frames");
358 fprintf(stderr," Timestep (ps)");
359 fprintf(stderr,"\n");
360 #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")
361 PRINTITEM ( "Step", bStep );
362 PRINTITEM ( "Time", bTime );
363 PRINTITEM ( "Lambda", bLambda );
364 PRINTITEM ( "Coords", bX );
365 PRINTITEM ( "Velocities", bV );
366 PRINTITEM ( "Forces", bF );
367 PRINTITEM ( "Box", bBox );
370 void chk_tps(const char *fn, real vdw_fac, real bon_lo, real bon_hi)
381 gmx_bool bV,bX,bB,bFirst,bOut;
382 real r2,ekin,temp1,temp2,dist2,vdwfac2,bonlo2,bonhi2;
386 fprintf(stderr,"Checking coordinate file %s\n",fn);
387 read_tps_conf(fn,title,&top,&ePBC,&x,&v,box,TRUE);
390 fprintf(stderr,"%d atoms in file\n",atoms->nr);
392 /* check coordinates and box */
395 for (i=0; (i<natom) && !(bV && bX); i++)
396 for (j=0; (j<DIM) && !(bV && bX); j++) {
397 bV=bV || (v[i][j]!=0);
398 bX=bX || (x[i][j]!=0);
401 for (i=0; (i<DIM) && !bB; i++)
402 for (j=0; (j<DIM) && !bB; j++)
403 bB=bB || (box[i][j]!=0);
405 fprintf(stderr,"coordinates %s\n",bX?"found":"absent");
406 fprintf(stderr,"box %s\n",bB?"found":"absent");
407 fprintf(stderr,"velocities %s\n",bV?"found":"absent");
408 fprintf(stderr,"\n");
410 /* check velocities */
413 for (i=0; (i<natom); i++)
414 for (j=0; (j<DIM); j++)
415 ekin+=0.5*atoms->atom[i].m*v[i][j]*v[i][j];
416 temp1=(2.0*ekin)/(natom*DIM*BOLTZ);
417 temp2=(2.0*ekin)/(natom*(DIM-1)*BOLTZ);
418 fprintf(stderr,"Kinetic energy: %g (kJ/mol)\n",ekin);
419 fprintf(stderr,"Assuming the number of degrees of freedom to be "
420 "Natoms * %d or Natoms * %d,\n"
421 "the velocities correspond to a temperature of the system\n"
422 "of %g K or %g K respectively.\n\n",DIM,DIM-1,temp1,temp2);
425 /* check coordinates */
427 vdwfac2=sqr(vdw_fac);
432 "Checking for atoms closer than %g and not between %g and %g,\n"
433 "relative to sum of Van der Waals distance:\n",
434 vdw_fac,bon_lo,bon_hi);
435 snew(atom_vdw,natom);
436 aps = gmx_atomprop_init();
437 for (i=0; (i<natom); i++) {
438 gmx_atomprop_query(aps,epropVDW,
439 *(atoms->resinfo[atoms->atom[i].resind].name),
440 *(atoms->atomname[i]),&(atom_vdw[i]));
441 if (debug) fprintf(debug,"%5d %4s %4s %7g\n",i+1,
442 *(atoms->resinfo[atoms->atom[i].resind].name),
443 *(atoms->atomname[i]),
446 gmx_atomprop_destroy(aps);
448 set_pbc(&pbc,ePBC,box);
451 for (i=0; (i<natom); i++) {
453 fprintf(stderr,"\r%5d",i+1);
454 for (j=i+1; (j<natom); j++) {
456 pbc_dx(&pbc,x[i],x[j],dx);
458 rvec_sub(x[i],x[j],dx);
460 dist2=sqr(atom_vdw[i]+atom_vdw[j]);
461 if ( (r2<=dist2*bonlo2) ||
462 ( (r2>=dist2*bonhi2) && (r2<=dist2*vdwfac2) ) ) {
464 fprintf(stderr,"\r%5s %4s %8s %5s %5s %4s %8s %5s %6s\n",
465 "atom#","name","residue","r_vdw",
466 "atom#","name","residue","r_vdw","distance");
470 "\r%5d %4s %4s%4d %-5.3g %5d %4s %4s%4d %-5.3g %-6.4g\n",
471 i+1,*(atoms->atomname[i]),
472 *(atoms->resinfo[atoms->atom[i].resind].name),
473 atoms->resinfo[atoms->atom[i].resind].nr,
475 j+1,*(atoms->atomname[j]),
476 *(atoms->resinfo[atoms->atom[j].resind].name),
477 atoms->resinfo[atoms->atom[j].resind].nr,
484 fprintf(stderr,"\rno close atoms found\n");
485 fprintf(stderr,"\r \n");
491 for (i=0; (i<natom) && (k<10); i++) {
493 for(j=0; (j<DIM) && !bOut; j++)
494 bOut = bOut || (x[i][j]<0) || (x[i][j]>box[j][j]);
498 fprintf(stderr,"Atoms outside box ( ");
499 for (j=0; (j<DIM); j++)
500 fprintf(stderr,"%g ",box[j][j]);
501 fprintf(stderr,"):\n"
502 "(These may occur often and are normally not a problem)\n"
503 "%5s %4s %8s %5s %s\n",
504 "atom#","name","residue","r_vdw","coordinate");
508 "%5d %4s %4s%4d %-5.3g",
509 i,*(atoms->atomname[i]),
510 *(atoms->resinfo[atoms->atom[i].resind].name),
511 atoms->resinfo[atoms->atom[i].resind].nr,atom_vdw[i]);
512 for (j=0; (j<DIM); j++)
513 fprintf(stderr," %6.3g",x[i][j]);
514 fprintf(stderr,"\n");
518 fprintf(stderr,"(maybe more)\n");
520 fprintf(stderr,"no atoms found outside box\n");
521 fprintf(stderr,"\n");
526 void chk_ndx(const char *fn)
532 grps = init_index(fn,&grpname);
534 pr_blocka(debug,0,fn,grps,FALSE);
536 printf("Contents of index file %s\n",fn);
537 printf("--------------------------------------------------\n");
538 printf("Nr. Group #Entries First Last\n");
539 for(i=0; (i<grps->nr); i++) {
540 printf("%4d %-20s%8d%8d%8d\n",i,grpname[i],
541 grps->index[i+1]-grps->index[i],
542 grps->a[grps->index[i]]+1,
543 grps->a[grps->index[i+1]-1]+1);
546 for(i=0; (i<grps->nr); i++)
552 void chk_enx(const char *fn)
556 gmx_enxnm_t *enm=NULL;
559 real t0,old_t1,old_t2;
562 fprintf(stderr,"Checking energy file %s\n\n",fn);
564 in = open_enx(fn,"r");
565 do_enxnms(in,&nre,&enm);
566 fprintf(stderr,"%d groups in energy file",nre);
574 while (do_enx(in,fr)) {
576 if ( fabs((fr->t-old_t1)-(old_t1-old_t2)) >
577 0.1*(fabs(fr->t-old_t1)+fabs(old_t1-old_t2)) ) {
579 fprintf(stderr,"\nTimesteps at t=%g don't match (%g, %g)\n",
580 old_t1,old_t1-old_t2,fr->t-old_t1);
585 if (t0 == NOTSET) t0=fr->t;
587 fprintf(stderr,"\rframe: %6s (index %6d), t: %10.3f\n",
588 gmx_step_str(fr->step,buf),fnr,fr->t);
591 fprintf(stderr,"\n\nFound %d frames",fnr);
592 if (bShowTStep && fnr>1)
593 fprintf(stderr," with a timestep of %g ps",(old_t1-t0)/(fnr-1));
594 fprintf(stderr,".\n");
597 free_enxnms(nre,enm);
601 int cmain(int argc,char *argv[])
603 const char *desc[] = {
604 "[TT]gmxcheck[tt] reads a trajectory ([TT].trj[tt], [TT].trr[tt] or ",
605 "[TT].xtc[tt]), an energy file ([TT].ene[tt] or [TT].edr[tt])",
606 "or an index file ([TT].ndx[tt])",
607 "and prints out useful information about them.[PAR]",
608 "Option [TT]-c[tt] checks for presence of coordinates,",
609 "velocities and box in the file, for close contacts (smaller than",
610 "[TT]-vdwfac[tt] and not bonded, i.e. not between [TT]-bonlo[tt]",
611 "and [TT]-bonhi[tt], all relative to the sum of both Van der Waals",
612 "radii) and atoms outside the box (these may occur often and are",
613 "no problem). If velocities are present, an estimated temperature",
614 "will be calculated from them.[PAR]",
615 "If an index file, is given its contents will be summarized.[PAR]",
616 "If both a trajectory and a [TT].tpr[tt] file are given (with [TT]-s1[tt])",
617 "the program will check whether the bond lengths defined in the tpr",
618 "file are indeed correct in the trajectory. If not you may have",
619 "non-matching files due to e.g. deshuffling or due to problems with",
620 "virtual sites. With these flags, [TT]gmxcheck[tt] provides a quick check for such problems.[PAR]",
621 "The program can compare two run input ([TT].tpr[tt], [TT].tpb[tt] or",
622 "[TT].tpa[tt]) files",
623 "when both [TT]-s1[tt] and [TT]-s2[tt] are supplied.",
624 "Similarly a pair of trajectory files can be compared (using the [TT]-f2[tt]",
625 "option), or a pair of energy files (using the [TT]-e2[tt] option).[PAR]",
626 "For free energy simulations the A and B state topology from one",
627 "run input file can be compared with options [TT]-s1[tt] and [TT]-ab[tt].[PAR]",
628 "In case the [TT]-m[tt] flag is given a LaTeX file will be written",
629 "consisting of a rough outline for a methods section for a paper."
632 { efTRX, "-f", NULL, ffOPTRD },
633 { efTRX, "-f2", NULL, ffOPTRD },
634 { efTPX, "-s1", "top1", ffOPTRD },
635 { efTPX, "-s2", "top2", ffOPTRD },
636 { efTPS, "-c", NULL, ffOPTRD },
637 { efEDR, "-e", NULL, ffOPTRD },
638 { efEDR, "-e2", "ener2", ffOPTRD },
639 { efNDX, "-n", NULL, ffOPTRD },
640 { efTEX, "-m", NULL, ffOPTWR }
642 #define NFILE asize(fnm)
643 const char *fn1=NULL,*fn2=NULL,*tex=NULL;
646 static real vdw_fac=0.8;
647 static real bon_lo=0.4;
648 static real bon_hi=0.7;
649 static gmx_bool bRMSD=FALSE;
650 static real ftol=0.001;
651 static real abstol=0.001;
652 static gmx_bool bCompAB=FALSE;
653 static char *lastener=NULL;
654 static t_pargs pa[] = {
655 { "-vdwfac", FALSE, etREAL, {&vdw_fac},
656 "Fraction of sum of VdW radii used as warning cutoff" },
657 { "-bonlo", FALSE, etREAL, {&bon_lo},
658 "Min. fract. of sum of VdW radii for bonded atoms" },
659 { "-bonhi", FALSE, etREAL, {&bon_hi},
660 "Max. fract. of sum of VdW radii for bonded atoms" },
661 { "-rmsd", FALSE, etBOOL, {&bRMSD},
662 "Print RMSD for x, v and f" },
663 { "-tol", FALSE, etREAL, {&ftol},
664 "Relative tolerance for comparing real values defined as [MATH]2*(a-b)/([MAG]a[mag]+[MAG]b[mag])[math]" },
665 { "-abstol", FALSE, etREAL, {&abstol},
666 "Absolute tolerance, useful when sums are close to zero." },
667 { "-ab", FALSE, etBOOL, {&bCompAB},
668 "Compare the A and B topology from one file" },
669 { "-lastener",FALSE, etSTR, {&lastener},
670 "Last energy term to compare (if not given all are tested). It makes sense to go up until the Pressure." }
673 CopyRight(stderr,argv[0]);
674 parse_common_args(&argc,argv,0,NFILE,fnm,asize(pa),pa,
675 asize(desc),desc,0,NULL,&oenv);
677 fn1 = opt2fn_null("-f",NFILE,fnm);
678 fn2 = opt2fn_null("-f2",NFILE,fnm);
679 tex = opt2fn_null("-m",NFILE,fnm);
681 comp_trx(oenv,fn1,fn2,bRMSD,ftol,abstol);
683 chk_trj(oenv,fn1,opt2fn_null("-s1",NFILE,fnm),ftol);
685 fprintf(stderr,"Please give me TWO trajectory (.xtc/.trr/.trj) files!\n");
687 fn1 = opt2fn_null("-s1",NFILE,fnm);
688 fn2 = opt2fn_null("-s2",NFILE,fnm);
689 if ((fn1 && fn2) || bCompAB) {
692 gmx_fatal(FARGS,"With -ab you need to set the -s1 option");
695 comp_tpx(fn1,fn2,bRMSD,ftol,abstol);
696 } else if (fn1 && tex)
697 tpx2methods(fn1,tex);
698 else if ((fn1 && !opt2fn_null("-f",NFILE,fnm)) || (!fn1 && fn2)) {
699 fprintf(stderr,"Please give me TWO run input (.tpr/.tpa/.tpb) files\n"
700 "or specify the -m flag to generate a methods.tex file\n");
703 fn1 = opt2fn_null("-e",NFILE,fnm);
704 fn2 = opt2fn_null("-e2",NFILE,fnm);
706 comp_enx(fn1,fn2,ftol,abstol,lastener);
708 chk_enx(ftp2fn(efEDR,NFILE,fnm));
710 fprintf(stderr,"Please give me TWO energy (.edr/.ene) files!\n");
712 if (ftp2bSet(efTPS,NFILE,fnm))
713 chk_tps(ftp2fn(efTPS,NFILE,fnm), vdw_fac, bon_lo, bon_hi);
715 if (ftp2bSet(efNDX,NFILE,fnm))
716 chk_ndx(ftp2fn(efNDX,NFILE,fnm));