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,2015,2016,2017,2018, 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/commandline/pargs.h"
46 #include "gromacs/fileio/confio.h"
47 #include "gromacs/fileio/enxio.h"
48 #include "gromacs/fileio/gmxfio.h"
49 #include "gromacs/fileio/tpxio.h"
50 #include "gromacs/fileio/trxio.h"
51 #include "gromacs/fileio/xtcio.h"
52 #include "gromacs/math/functions.h"
53 #include "gromacs/math/units.h"
54 #include "gromacs/math/vec.h"
55 #include "gromacs/mdrunutility/mdmodules.h"
56 #include "gromacs/mdtypes/inputrec.h"
57 #include "gromacs/mdtypes/md_enums.h"
58 #include "gromacs/mdtypes/state.h"
59 #include "gromacs/pbcutil/pbc.h"
60 #include "gromacs/topology/atomprop.h"
61 #include "gromacs/topology/block.h"
62 #include "gromacs/topology/ifunc.h"
63 #include "gromacs/topology/index.h"
64 #include "gromacs/topology/mtop_util.h"
65 #include "gromacs/topology/topology.h"
66 #include "gromacs/trajectory/energyframe.h"
67 #include "gromacs/trajectory/trajectoryframe.h"
68 #include "gromacs/utility/arraysize.h"
69 #include "gromacs/utility/fatalerror.h"
70 #include "gromacs/utility/futil.h"
71 #include "gromacs/utility/smalloc.h"
93 static void comp_tpx(const char *fn1, const char *fn2,
94 gmx_bool bRMSD, real ftol, real abstol)
105 for (i = 0; i < (fn2 ? 2 : 1); i++)
107 ir[i] = new t_inputrec();
108 read_tpx_state(ff[i], ir[i], &state[i], &(mtop[i]));
109 gmx::MDModules().adjustInputrecBasedOnModules(ir[i]);
113 cmp_inputrec(stdout, ir[0], ir[1], ftol, abstol);
114 /* Convert gmx_mtop_t to t_topology.
115 * We should implement direct mtop comparison,
116 * but it might be useful to keep t_topology comparison as an option.
118 top[0] = gmx_mtop_t_to_t_topology(&mtop[0], false);
119 top[1] = gmx_mtop_t_to_t_topology(&mtop[1], false);
120 cmp_top(stdout, &top[0], &top[1], ftol, abstol);
121 cmp_groups(stdout, &mtop[0].groups, &mtop[1].groups,
122 mtop[0].natoms, mtop[1].natoms);
123 comp_state(&state[0], &state[1], bRMSD, ftol, abstol);
127 if (ir[0]->efep == efepNO)
129 fprintf(stdout, "inputrec->efep = %s\n", efep_names[ir[0]->efep]);
135 comp_pull_AB(stdout, ir[0]->pull, ftol, abstol);
137 /* Convert gmx_mtop_t to t_topology.
138 * We should implement direct mtop comparison,
139 * but it might be useful to keep t_topology comparison as an option.
141 top[0] = gmx_mtop_t_to_t_topology(&mtop[0], true);
142 cmp_top(stdout, &top[0], nullptr, ftol, abstol);
147 static void comp_trx(const gmx_output_env_t *oenv, const char *fn1, const char *fn2,
148 gmx_bool bRMSD, real ftol, real abstol)
153 t_trxstatus *status[2];
158 fprintf(stderr, "Comparing trajectory files %s and %s\n", fn1, fn2);
159 for (i = 0; i < 2; i++)
161 b[i] = read_first_frame(oenv, &status[i], fn[i], &fr[i], TRX_READ_X|TRX_READ_V|TRX_READ_F);
168 comp_frame(stdout, &(fr[0]), &(fr[1]), bRMSD, ftol, abstol);
170 for (i = 0; i < 2; i++)
172 b[i] = read_next_frame(oenv, status[i], &fr[i]);
175 while (b[0] && b[1]);
177 for (i = 0; i < 2; i++)
181 fprintf(stdout, "\nEnd of file on %s but not on %s\n", fn[1-i], fn[i]);
183 close_trx(status[i]);
188 fprintf(stdout, "\nBoth files read correctly\n");
192 static void tpx2system(FILE *fp, const gmx_mtop_t *mtop)
194 int nmol, nvsite = 0;
195 gmx_mtop_atomloop_block_t aloop;
198 fprintf(fp, "\\subsection{Simulation system}\n");
199 aloop = gmx_mtop_atomloop_block_init(mtop);
200 while (gmx_mtop_atomloop_block_next(aloop, &atom, &nmol))
202 if (atom->ptype == eptVSite)
207 fprintf(fp, "A system of %d molecules (%d atoms) was simulated.\n",
208 gmx_mtop_num_molecules(*mtop), mtop->natoms-nvsite);
211 fprintf(fp, "Virtual sites were used in some of the molecules.\n");
216 static void tpx2params(FILE *fp, const t_inputrec *ir)
218 fprintf(fp, "\\subsection{Simulation settings}\n");
219 fprintf(fp, "A total of %g ns were simulated with a time step of %g fs.\n",
220 ir->nsteps*ir->delta_t*0.001, 1000*ir->delta_t);
221 fprintf(fp, "Neighbor searching was performed every %d steps.\n", ir->nstlist);
222 fprintf(fp, "The %s algorithm was used for electrostatic interactions.\n",
223 EELTYPE(ir->coulombtype));
224 fprintf(fp, "with a cut-off of %g nm.\n", ir->rcoulomb);
225 if (ir->coulombtype == eelPME)
227 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);
229 if (ir->rvdw > ir->rlist)
231 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);
235 fprintf(fp, "A single cut-off of %g was used for Van der Waals interactions.\n", ir->rlist);
239 fprintf(fp, "Temperature coupling was done with the %s algorithm.\n",
240 etcoupl_names[ir->etc]);
244 fprintf(fp, "Pressure coupling was done with the %s algorithm.\n",
245 epcoupl_names[ir->epc]);
250 static void tpx2methods(const char *tpx, const char *tex)
257 read_tpx_state(tpx, &ir, &state, &mtop);
258 fp = gmx_fio_fopen(tex, "w");
259 fprintf(fp, "\\section{Methods}\n");
260 tpx2system(fp, &mtop);
265 static void chk_coords(int frame, int natoms, rvec *x, matrix box, real fac, real tol)
271 for (i = 0; (i < natoms); i++)
273 for (j = 0; (j < DIM); j++)
275 if ((vol > 0) && (fabs(x[i][j]) > fac*box[j][j]))
277 printf("Warning at frame %d: coordinates for atom %d are large (%g)\n",
281 if ((fabs(x[i][XX]) < tol) &&
282 (fabs(x[i][YY]) < tol) &&
283 (fabs(x[i][ZZ]) < tol))
290 printf("Warning at frame %d: there are %d particles with all coordinates zero\n",
295 static void chk_vels(int frame, int natoms, rvec *v)
299 for (i = 0; (i < natoms); i++)
301 for (j = 0; (j < DIM); j++)
303 if (fabs(v[i][j]) > 500)
305 printf("Warning at frame %d. Velocities for atom %d are large (%g)\n",
312 static void chk_forces(int frame, int natoms, rvec *f)
316 for (i = 0; (i < natoms); i++)
318 for (j = 0; (j < DIM); j++)
320 if (fabs(f[i][j]) > 10000)
322 printf("Warning at frame %d. Forces for atom %d are large (%g)\n",
329 static void chk_bonds(t_idef *idef, int ePBC, rvec *x, matrix box, real tol)
331 int ftype, k, ai, aj, type;
332 real b0, blen, deviation;
336 set_pbc(&pbc, ePBC, box);
337 for (ftype = 0; (ftype < F_NRE); ftype++)
339 if ((interaction_function[ftype].flags & IF_CHEMBOND) == IF_CHEMBOND)
341 for (k = 0; (k < idef->il[ftype].nr); )
343 type = idef->il[ftype].iatoms[k++];
344 ai = idef->il[ftype].iatoms[k++];
345 aj = idef->il[ftype].iatoms[k++];
350 b0 = idef->iparams[type].harmonic.rA;
353 b0 = std::sqrt(idef->iparams[type].harmonic.rA);
356 b0 = idef->iparams[type].morse.b0A;
359 b0 = idef->iparams[type].cubic.b0;
362 b0 = idef->iparams[type].constr.dA;
369 pbc_dx(&pbc, x[ai], x[aj], dx);
371 deviation = gmx::square(blen-b0);
372 if (std::sqrt(deviation/gmx::square(b0)) > tol)
374 fprintf(stderr, "Distance between atoms %d and %d is %.3f, should be %.3f\n", ai+1, aj+1, blen, b0);
382 static void chk_trj(const gmx_output_env_t *oenv, const char *fn, const char *tpr, real tol)
386 t_fr_time first, last;
387 int j = -1, new_natoms, natoms;
389 gmx_bool bShowTimestep = TRUE, newline = FALSE;
392 gmx_localtop_t *top = nullptr;
398 read_tpx_state(tpr, &ir, &state, &mtop);
399 top = gmx_mtop_generate_local_top(&mtop, ir.efep != efepNO);
404 printf("Checking file %s\n", fn);
434 read_first_frame(oenv, &status, fn, &fr, TRX_READ_X | TRX_READ_V | TRX_READ_F);
440 fprintf(stderr, "\n# Atoms %d\n", fr.natoms);
443 fprintf(stderr, "Precision %g (nm)\n", 1/fr.prec);
447 if ((natoms > 0) && (new_natoms != natoms))
449 fprintf(stderr, "\nNumber of atoms at t=%g don't match (%d, %d)\n",
450 old_t1, natoms, new_natoms);
455 if (std::fabs((fr.time-old_t1)-(old_t1-old_t2)) >
456 0.1*(std::fabs(fr.time-old_t1)+std::fabs(old_t1-old_t2)) )
458 bShowTimestep = FALSE;
459 fprintf(stderr, "%sTimesteps at t=%g don't match (%g, %g)\n",
460 newline ? "\n" : "", old_t1, old_t1-old_t2, fr.time-old_t1);
466 chk_bonds(&top->idef, ir.ePBC, fr.x, fr.box, tol);
470 chk_coords(j, natoms, fr.x, fr.box, 1e5, tol);
474 chk_vels(j, natoms, fr.v);
478 chk_forces(j, natoms, fr.f);
484 new_natoms = fr.natoms;
485 #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++; \
487 INC(fr, count, first, last, bStep);
488 INC(fr, count, first, last, bTime);
489 INC(fr, count, first, last, bLambda);
490 INC(fr, count, first, last, bX);
491 INC(fr, count, first, last, bV);
492 INC(fr, count, first, last, bF);
493 INC(fr, count, first, last, bBox);
496 while (read_next_frame(oenv, status, &fr));
498 fprintf(stderr, "\n");
502 fprintf(stderr, "\nItem #frames");
505 fprintf(stderr, " Timestep (ps)");
507 fprintf(stderr, "\n");
508 #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")
509 PRINTITEM ( "Step", bStep );
510 PRINTITEM ( "Time", bTime );
511 PRINTITEM ( "Lambda", bLambda );
512 PRINTITEM ( "Coords", bX );
513 PRINTITEM ( "Velocities", bV );
514 PRINTITEM ( "Forces", bF );
515 PRINTITEM ( "Box", bBox );
518 static void chk_tps(const char *fn, real vdw_fac, real bon_lo, real bon_hi)
528 gmx_bool bV, bX, bB, bFirst, bOut;
529 real r2, ekin, temp1, temp2, dist2, vdwfac2, bonlo2, bonhi2;
533 fprintf(stderr, "Checking coordinate file %s\n", fn);
534 read_tps_conf(fn, &top, &ePBC, &x, &v, box, TRUE);
537 fprintf(stderr, "%d atoms in file\n", atoms->nr);
539 /* check coordinates and box */
542 for (i = 0; (i < natom) && !(bV && bX); i++)
544 for (j = 0; (j < DIM) && !(bV && bX); j++)
546 bV = bV || (v[i][j] != 0);
547 bX = bX || (x[i][j] != 0);
551 for (i = 0; (i < DIM) && !bB; i++)
553 for (j = 0; (j < DIM) && !bB; j++)
555 bB = bB || (box[i][j] != 0);
559 fprintf(stderr, "coordinates %s\n", bX ? "found" : "absent");
560 fprintf(stderr, "box %s\n", bB ? "found" : "absent");
561 fprintf(stderr, "velocities %s\n", bV ? "found" : "absent");
562 fprintf(stderr, "\n");
564 /* check velocities */
568 for (i = 0; (i < natom); i++)
570 for (j = 0; (j < DIM); j++)
572 ekin += 0.5*atoms->atom[i].m*v[i][j]*v[i][j];
575 temp1 = (2.0*ekin)/(natom*DIM*BOLTZ);
576 temp2 = (2.0*ekin)/(natom*(DIM-1)*BOLTZ);
577 fprintf(stderr, "Kinetic energy: %g (kJ/mol)\n", ekin);
578 fprintf(stderr, "Assuming the number of degrees of freedom to be "
579 "Natoms * %d or Natoms * %d,\n"
580 "the velocities correspond to a temperature of the system\n"
581 "of %g K or %g K respectively.\n\n", DIM, DIM-1, temp1, temp2);
584 /* check coordinates */
587 vdwfac2 = gmx::square(vdw_fac);
588 bonlo2 = gmx::square(bon_lo);
589 bonhi2 = gmx::square(bon_hi);
592 "Checking for atoms closer than %g and not between %g and %g,\n"
593 "relative to sum of Van der Waals distance:\n",
594 vdw_fac, bon_lo, bon_hi);
595 snew(atom_vdw, natom);
596 aps = gmx_atomprop_init();
597 for (i = 0; (i < natom); i++)
599 gmx_atomprop_query(aps, epropVDW,
600 *(atoms->resinfo[atoms->atom[i].resind].name),
601 *(atoms->atomname[i]), &(atom_vdw[i]));
604 fprintf(debug, "%5d %4s %4s %7g\n", i+1,
605 *(atoms->resinfo[atoms->atom[i].resind].name),
606 *(atoms->atomname[i]),
610 gmx_atomprop_destroy(aps);
613 set_pbc(&pbc, ePBC, box);
617 for (i = 0; (i < natom); i++)
621 fprintf(stderr, "\r%5d", i+1);
624 for (j = i+1; (j < natom); j++)
628 pbc_dx(&pbc, x[i], x[j], dx);
632 rvec_sub(x[i], x[j], dx);
635 dist2 = gmx::square(atom_vdw[i]+atom_vdw[j]);
636 if ( (r2 <= dist2*bonlo2) ||
637 ( (r2 >= dist2*bonhi2) && (r2 <= dist2*vdwfac2) ) )
641 fprintf(stderr, "\r%5s %4s %8s %5s %5s %4s %8s %5s %6s\n",
642 "atom#", "name", "residue", "r_vdw",
643 "atom#", "name", "residue", "r_vdw", "distance");
647 "\r%5d %4s %4s%4d %-5.3g %5d %4s %4s%4d %-5.3g %-6.4g\n",
648 i+1, *(atoms->atomname[i]),
649 *(atoms->resinfo[atoms->atom[i].resind].name),
650 atoms->resinfo[atoms->atom[i].resind].nr,
652 j+1, *(atoms->atomname[j]),
653 *(atoms->resinfo[atoms->atom[j].resind].name),
654 atoms->resinfo[atoms->atom[j].resind].nr,
662 fprintf(stderr, "\rno close atoms found\n");
664 fprintf(stderr, "\r \n");
671 for (i = 0; (i < natom) && (k < 10); i++)
674 for (j = 0; (j < DIM) && !bOut; j++)
676 bOut = bOut || (x[i][j] < 0) || (x[i][j] > box[j][j]);
683 fprintf(stderr, "Atoms outside box ( ");
684 for (j = 0; (j < DIM); j++)
686 fprintf(stderr, "%g ", box[j][j]);
688 fprintf(stderr, "):\n"
689 "(These may occur often and are normally not a problem)\n"
690 "%5s %4s %8s %5s %s\n",
691 "atom#", "name", "residue", "r_vdw", "coordinate");
695 "%5d %4s %4s%4d %-5.3g",
696 i, *(atoms->atomname[i]),
697 *(atoms->resinfo[atoms->atom[i].resind].name),
698 atoms->resinfo[atoms->atom[i].resind].nr, atom_vdw[i]);
699 for (j = 0; (j < DIM); j++)
701 fprintf(stderr, " %6.3g", x[i][j]);
703 fprintf(stderr, "\n");
708 fprintf(stderr, "(maybe more)\n");
712 fprintf(stderr, "no atoms found outside box\n");
714 fprintf(stderr, "\n");
719 static void chk_ndx(const char *fn)
725 grps = init_index(fn, &grpname);
728 pr_blocka(debug, 0, fn, grps, FALSE);
732 printf("Contents of index file %s\n", fn);
733 printf("--------------------------------------------------\n");
734 printf("Nr. Group #Entries First Last\n");
735 for (i = 0; (i < grps->nr); i++)
737 printf("%4d %-20s%8d%8d%8d\n", i, grpname[i],
738 grps->index[i+1]-grps->index[i],
739 grps->a[grps->index[i]]+1,
740 grps->a[grps->index[i+1]-1]+1);
743 for (i = 0; (i < grps->nr); i++)
751 static void chk_enx(const char *fn)
755 gmx_enxnm_t *enm = nullptr;
759 real t0, old_t1, old_t2;
762 fprintf(stderr, "Checking energy file %s\n\n", fn);
764 in = open_enx(fn, "r");
765 do_enxnms(in, &nre, &enm);
766 fprintf(stderr, "%d groups in energy file", nre);
775 while (do_enx(in, fr))
779 if (fabs((fr->t-old_t1)-(old_t1-old_t2)) >
780 0.1*(fabs(fr->t-old_t1)+std::fabs(old_t1-old_t2)) )
783 fprintf(stderr, "\nTimesteps at t=%g don't match (%g, %g)\n",
784 old_t1, old_t1-old_t2, fr->t-old_t1);
796 fprintf(stderr, "\rframe: %6s (index %6d), t: %10.3f\n",
797 gmx_step_str(fr->step, buf), fnr, fr->t);
801 fprintf(stderr, "\n\nFound %d frames", fnr);
802 if (bShowTStep && fnr > 1)
804 fprintf(stderr, " with a timestep of %g ps", (old_t1-t0)/(fnr-1));
806 fprintf(stderr, ".\n");
809 free_enxnms(nre, enm);
813 int gmx_check(int argc, char *argv[])
815 const char *desc[] = {
816 "[THISMODULE] reads a trajectory ([REF].tng[ref], [REF].trr[ref] or ",
817 "[REF].xtc[ref]), an energy file ([REF].edr[ref])",
818 "or an index file ([REF].ndx[ref])",
819 "and prints out useful information about them.[PAR]",
820 "Option [TT]-c[tt] checks for presence of coordinates,",
821 "velocities and box in the file, for close contacts (smaller than",
822 "[TT]-vdwfac[tt] and not bonded, i.e. not between [TT]-bonlo[tt]",
823 "and [TT]-bonhi[tt], all relative to the sum of both Van der Waals",
824 "radii) and atoms outside the box (these may occur often and are",
825 "no problem). If velocities are present, an estimated temperature",
826 "will be calculated from them.[PAR]",
827 "If an index file, is given its contents will be summarized.[PAR]",
828 "If both a trajectory and a [REF].tpr[ref] file are given (with [TT]-s1[tt])",
829 "the program will check whether the bond lengths defined in the tpr",
830 "file are indeed correct in the trajectory. If not you may have",
831 "non-matching files due to e.g. deshuffling or due to problems with",
832 "virtual sites. With these flags, [TT]gmx check[tt] provides a quick check for such problems.[PAR]",
833 "The program can compare two run input ([REF].tpr[ref])",
835 "when both [TT]-s1[tt] and [TT]-s2[tt] are supplied. When comparing",
836 "run input files this way, the default relative tolerance is reduced",
837 "to 0.000001 and the absolute tolerance set to zero to find any differences",
838 "not due to minor compiler optimization differences, although you can",
839 "of course still set any other tolerances through the options.",
840 "Similarly a pair of trajectory files can be compared (using the [TT]-f2[tt]",
841 "option), or a pair of energy files (using the [TT]-e2[tt] option).[PAR]",
842 "For free energy simulations the A and B state topology from one",
843 "run input file can be compared with options [TT]-s1[tt] and [TT]-ab[tt].[PAR]",
844 "In case the [TT]-m[tt] flag is given a LaTeX file will be written",
845 "consisting of a rough outline for a methods section for a paper."
848 { efTRX, "-f", nullptr, ffOPTRD },
849 { efTRX, "-f2", nullptr, ffOPTRD },
850 { efTPR, "-s1", "top1", ffOPTRD },
851 { efTPR, "-s2", "top2", ffOPTRD },
852 { efTPS, "-c", nullptr, ffOPTRD },
853 { efEDR, "-e", nullptr, ffOPTRD },
854 { efEDR, "-e2", "ener2", ffOPTRD },
855 { efNDX, "-n", nullptr, ffOPTRD },
856 { efTEX, "-m", nullptr, ffOPTWR }
858 #define NFILE asize(fnm)
859 const char *fn1 = nullptr, *fn2 = nullptr, *tex = nullptr;
861 gmx_output_env_t *oenv;
862 static real vdw_fac = 0.8;
863 static real bon_lo = 0.4;
864 static real bon_hi = 0.7;
865 static gmx_bool bRMSD = FALSE;
866 static real ftol = 0.001;
867 static real abstol = 0.001;
868 static gmx_bool bCompAB = FALSE;
869 static char *lastener = nullptr;
870 static t_pargs pa[] = {
871 { "-vdwfac", FALSE, etREAL, {&vdw_fac},
872 "Fraction of sum of VdW radii used as warning cutoff" },
873 { "-bonlo", FALSE, etREAL, {&bon_lo},
874 "Min. fract. of sum of VdW radii for bonded atoms" },
875 { "-bonhi", FALSE, etREAL, {&bon_hi},
876 "Max. fract. of sum of VdW radii for bonded atoms" },
877 { "-rmsd", FALSE, etBOOL, {&bRMSD},
878 "Print RMSD for x, v and f" },
879 { "-tol", FALSE, etREAL, {&ftol},
880 "Relative tolerance for comparing real values defined as [MATH]2*(a-b)/([MAG]a[mag]+[MAG]b[mag])[math]" },
881 { "-abstol", FALSE, etREAL, {&abstol},
882 "Absolute tolerance, useful when sums are close to zero." },
883 { "-ab", FALSE, etBOOL, {&bCompAB},
884 "Compare the A and B topology from one file" },
885 { "-lastener", FALSE, etSTR, {&lastener},
886 "Last energy term to compare (if not given all are tested). It makes sense to go up until the Pressure." }
889 if (!parse_common_args(&argc, argv, 0, NFILE, fnm, asize(pa), pa,
890 asize(desc), desc, 0, nullptr, &oenv))
895 fn1 = opt2fn_null("-f", NFILE, fnm);
896 fn2 = opt2fn_null("-f2", NFILE, fnm);
897 tex = opt2fn_null("-m", NFILE, fnm);
900 comp_trx(oenv, fn1, fn2, bRMSD, ftol, abstol);
904 chk_trj(oenv, fn1, opt2fn_null("-s1", NFILE, fnm), ftol);
908 fprintf(stderr, "Please give me TWO trajectory (.xtc/.trr/.tng) files!\n");
911 fn1 = opt2fn_null("-s1", NFILE, fnm);
912 fn2 = opt2fn_null("-s2", NFILE, fnm);
913 if ((fn1 && fn2) || bCompAB)
919 gmx_fatal(FARGS, "With -ab you need to set the -s1 option");
924 fprintf(stderr, "Note: When comparing run input files, default tolerances are reduced.\n");
925 if (!opt2parg_bSet("-tol", asize(pa), pa))
929 if (!opt2parg_bSet("-abstol", asize(pa), pa))
933 comp_tpx(fn1, fn2, bRMSD, ftol, abstol);
937 tpx2methods(fn1, tex);
939 else if ((fn1 && !opt2fn_null("-f", NFILE, fnm)) || (!fn1 && fn2))
941 fprintf(stderr, "Please give me TWO run input (.tpr) files\n"
942 "or specify the -m flag to generate a methods.tex file\n");
945 fn1 = opt2fn_null("-e", NFILE, fnm);
946 fn2 = opt2fn_null("-e2", NFILE, fnm);
949 comp_enx(fn1, fn2, ftol, abstol, lastener);
953 chk_enx(ftp2fn(efEDR, NFILE, fnm));
957 fprintf(stderr, "Please give me TWO energy (.edr/.ene) files!\n");
960 if (ftp2bSet(efTPS, NFILE, fnm))
962 chk_tps(ftp2fn(efTPS, NFILE, fnm), vdw_fac, bon_lo, bon_hi);
965 if (ftp2bSet(efNDX, NFILE, fnm))
967 chk_ndx(ftp2fn(efNDX, NFILE, fnm));