Allow gmx tune_pme to skip the check for command-line health
[alexxy/gromacs.git] / src / gromacs / gmxana / gmx_tune_pme.c
index b3683936abdcbe48dab1e654854ea299308e7774..a4378039327b2f23e842dc8ec5bb3c1ce79ae3cc 100644 (file)
@@ -1,56 +1,54 @@
 /*
+ * This file is part of the GROMACS molecular simulation package.
  *
- *                This source code is part of
+ * Copyright (c) 2009,2010,2011,2012,2013,2014, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
  *
- *                 G   R   O   M   A   C   S
- *
- *          GROningen MAchine for Chemical Simulations
- *
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2008, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
  * of the License, or (at your option) any later version.
  *
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
  *
- * To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
  *
- * For more info, check our website at http://www.gromacs.org
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
  *
- * And Hey:
- * Gallium Rubidium Oxygen Manganese Argon Carbon Silicon
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
  */
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif
 
-
 #include <time.h>
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
 #endif
 
-
-
-#include "statutil.h"
+#include "gromacs/commandline/pargs.h"
 #include "typedefs.h"
-#include "smalloc.h"
+#include "types/commrec.h"
+#include "gromacs/utility/smalloc.h"
 #include "vec.h"
 #include "copyrite.h"
-#include "statutil.h"
-#include "tpxio.h"
-#include "string2.h"
+#include "gromacs/fileio/tpxio.h"
+#include "gromacs/utility/cstringutil.h"
 #include "readinp.h"
 #include "calcgrid.h"
 #include "checkpoint.h"
 #include "gmx_ana.h"
 #include "names.h"
 #include "perf_est.h"
-#include "sim_util.h"
+#include "inputrec.h"
+#include "gromacs/timing/walltime_accounting.h"
+#include "gromacs/math/utilities.h"
 
+#include "gmx_fatal.h"
 
 /* Enum for situations that can occur during log file parsing, the
  * corresponding string entries can be found in do_the_tests() in
@@ -97,8 +98,8 @@ typedef struct
 typedef struct
 {
     int             nr_inputfiles;  /* The number of tpr and mdp input files */
-    gmx_large_int_t orig_sim_steps; /* Number of steps to be done in the real simulation */
-    gmx_large_int_t orig_init_step; /* Init step for the real simulation */
+    gmx_int64_t     orig_sim_steps; /* Number of steps to be done in the real simulation */
+    gmx_int64_t     orig_init_step; /* Init step for the real simulation */
     real           *rcoulomb;       /* The coulomb radii [0...nr_inputfiles] */
     real           *rvdw;           /* The vdW radii */
     real           *rlist;          /* Neighbourlist cutoff radius */
@@ -165,6 +166,16 @@ static gmx_bool is_equal(real a, real b)
 }
 
 
+static void remove_if_exists(const char *fn)
+{
+    if (gmx_fexist(fn))
+    {
+        fprintf(stdout, "Deleting %s\n", fn);
+        remove(fn);
+    }
+}
+
+
 static void finalize(const char *fn_out)
 {
     char  buf[STRLEN];
@@ -188,7 +199,7 @@ enum {
 };
 
 static int parse_logfile(const char *logfile, const char *errfile,
-                         t_perf *perfdata, int test_nr, int presteps, gmx_large_int_t cpt_steps,
+                         t_perf *perfdata, int test_nr, int presteps, gmx_int64_t cpt_steps,
                          int nnodes)
 {
     FILE           *fp;
@@ -199,11 +210,10 @@ static int parse_logfile(const char *logfile, const char *errfile,
     const char      matchstring[] = "R E A L   C Y C L E   A N D   T I M E   A C C O U N T I N G";
     const char      errSIG[]      = "signal, stopping at the next";
     int             iFound;
-    int             procs;
     float           dum1, dum2, dum3, dum4;
     int             ndum;
     int             npme;
-    gmx_large_int_t resetsteps     = -1;
+    gmx_int64_t     resetsteps     = -1;
     gmx_bool        bFoundResetStr = FALSE;
     gmx_bool        bResetChecked  = FALSE;
 
@@ -243,7 +253,7 @@ static int parse_logfile(const char *logfile, const char *errfile,
         {
             if (strstr(line, matchstrcr) != NULL)
             {
-                sprintf(dumstring, "step %s", gmx_large_int_pfmt);
+                sprintf(dumstring, "step %s", "%"GMX_SCNd64);
                 sscanf(line, dumstring, &resetsteps);
                 bFoundResetStr = TRUE;
                 if (resetsteps == presteps+cpt_steps)
@@ -252,8 +262,8 @@ static int parse_logfile(const char *logfile, const char *errfile,
                 }
                 else
                 {
-                    sprintf(dumstring, gmx_large_int_pfmt, resetsteps);
-                    sprintf(dumstring2, gmx_large_int_pfmt, presteps+cpt_steps);
+                    sprintf(dumstring, "%"GMX_PRId64, resetsteps);
+                    sprintf(dumstring2, "%"GMX_PRId64, presteps+cpt_steps);
                     fprintf(stderr, "WARNING: Time step counters were reset at step %s,\n"
                             "         though they were supposed to be reset at step %s!\n",
                             dumstring, dumstring2);
@@ -268,7 +278,7 @@ static int parse_logfile(const char *logfile, const char *errfile,
                 /* Look for domain decomp grid and separate PME nodes: */
                 if (str_starts(line, matchstrdd))
                 {
-                    sscanf(line, "Domain decomposition grid %d x %d x %d, separate PME nodes %d",
+                    sscanf(line, "Domain decomposition grid %d x %d x %d, separate PME ranks %d",
                            &(perfdata->nx), &(perfdata->ny), &(perfdata->nz), &npme);
                     if (perfdata->nPMEnodes == -1)
                     {
@@ -276,7 +286,7 @@ static int parse_logfile(const char *logfile, const char *errfile,
                     }
                     else if (perfdata->nPMEnodes != npme)
                     {
-                        gmx_fatal(FARGS, "PME nodes from command line and output file are not identical");
+                        gmx_fatal(FARGS, "PME ranks from command line and output file are not identical");
                     }
                     iFound = eFoundDDStr;
                 }
@@ -286,7 +296,7 @@ static int parse_logfile(const char *logfile, const char *errfile,
                     fclose(fp);
                     return eParselogNoDDGrid;
                 }
-                else if (str_starts(line, "The number of nodes you selected"))
+                else if (str_starts(line, "The number of ranks you selected"))
                 {
                     fclose(fp);
                     return eParselogLargePrimeFactor;
@@ -318,7 +328,7 @@ static int parse_logfile(const char *logfile, const char *errfile,
                 /* Already found matchstring - look for cycle data */
                 if (str_starts(line, "Total  "))
                 {
-                    sscanf(line, "Total %d %lf", &procs, &(perfdata->Gcycles[test_nr]));
+                    sscanf(line, "Total %*f %lf", &(perfdata->Gcycles[test_nr]));
                     iFound = eFoundCycleStr;
                 }
                 break;
@@ -408,7 +418,7 @@ static gmx_bool analyze_data(
     {
         sep_line(fp);
         fprintf(fp, "Summary of successful runs:\n");
-        fprintf(fp, "Line tpr PME nodes  Gcycles Av.     Std.dev.       ns/day        PME/f");
+        fprintf(fp, "Line tpr PME ranks  Gcycles Av.     Std.dev.       ns/day        PME/f");
         if (nnodes > 1)
         {
             fprintf(fp, "    DD grid");
@@ -528,11 +538,11 @@ static gmx_bool analyze_data(
         /* We have optimized the number of PME-only nodes */
         if (winPME == -1)
         {
-            sprintf(strbuf, "%s", "the automatic number of PME nodes");
+            sprintf(strbuf, "%s", "the automatic number of PME ranks");
         }
         else
         {
-            sprintf(strbuf, "%d PME nodes", winPME);
+            sprintf(strbuf, "%d PME ranks", winPME);
         }
     }
     fprintf(fp, "Best performance was achieved with %s", strbuf);
@@ -645,7 +655,7 @@ static void check_mdrun_works(gmx_bool    bThreads,
     /* This string should always be identical to the one in copyrite.c,
      * gmx_print_version_info() in the defined(GMX_MPI) section */
     const char match_mpi[]    = "MPI library:        MPI";
-    const char match_mdrun[]  = "Program: ";
+    const char match_mdrun[]  = "Executable: ";
     gmx_bool   bMdrun         = FALSE;
     gmx_bool   bMPI           = FALSE;
 
@@ -698,7 +708,7 @@ static void check_mdrun_works(gmx_bool    bThreads,
             gmx_fatal(FARGS, "Need a threaded version of mdrun. This one\n"
                       "(%s)\n"
                       "seems to have been compiled with MPI instead.",
-                      *cmd_mdrun);
+                      cmd_mdrun);
         }
     }
     else
@@ -708,7 +718,7 @@ static void check_mdrun_works(gmx_bool    bThreads,
             gmx_fatal(FARGS, "Need an MPI-enabled version of mdrun. This one\n"
                       "(%s)\n"
                       "seems to have been compiled without MPI support.",
-                      *cmd_mdrun);
+                      cmd_mdrun);
         }
     }
 
@@ -773,8 +783,8 @@ static void launch_simulation(
 
 
 static void modify_PMEsettings(
-        gmx_large_int_t simsteps,    /* Set this value as number of time steps */
-        gmx_large_int_t init_step,   /* Set this value as init_step */
+        gmx_int64_t     simsteps,    /* Set this value as number of time steps */
+        gmx_int64_t     init_step,   /* Set this value as init_step */
         const char     *fn_best_tpr, /* tpr file with the best performance */
         const char     *fn_sim_tpr)  /* name of tpr file to be launched */
 {
@@ -791,7 +801,7 @@ static void modify_PMEsettings(
     ir->init_step = init_step;
 
     /* Write the tpr file which will be launched */
-    sprintf(buf, "Writing optimized simulation file %s with nsteps=%s.\n", fn_sim_tpr, gmx_large_int_pfmt);
+    sprintf(buf, "Writing optimized simulation file %s with nsteps=%s.\n", fn_sim_tpr, "%"GMX_PRId64);
     fprintf(stdout, buf, ir->nsteps);
     fflush(stdout);
     write_tpx_state(fn_sim_tpr, ir, &state, &mtop);
@@ -799,6 +809,11 @@ static void modify_PMEsettings(
     sfree(ir);
 }
 
+static gmx_bool can_scale_rvdw(int vdwtype)
+{
+    return (evdwCUT == vdwtype ||
+            evdwPME == vdwtype);
+}
 
 #define EPME_SWITCHED(e) ((e) == eelPMESWITCH || (e) == eelPMEUSERSWITCH)
 
@@ -807,8 +822,8 @@ static void modify_PMEsettings(
 static void make_benchmark_tprs(
         const char     *fn_sim_tpr,      /* READ : User-provided tpr file                 */
         char           *fn_bench_tprs[], /* WRITE: Names of benchmark tpr files           */
-        gmx_large_int_t benchsteps,      /* Number of time steps for benchmark runs       */
-        gmx_large_int_t statesteps,      /* Step counter in checkpoint file               */
+        gmx_int64_t     benchsteps,      /* Number of time steps for benchmark runs       */
+        gmx_int64_t     statesteps,      /* Step counter in checkpoint file               */
         real            rmin,            /* Minimal Coulomb radius                        */
         real            rmax,            /* Maximal Coulomb radius                        */
         real            bScaleRvdw,      /* Scale rvdw along with rcoulomb                */
@@ -831,11 +846,11 @@ static void make_benchmark_tprs(
 
 
     sprintf(buf, "Making benchmark tpr file%s with %s time step%s",
-            *ntprs > 1 ? "s" : "", gmx_large_int_pfmt, benchsteps > 1 ? "s" : "");
+            *ntprs > 1 ? "s" : "", "%"GMX_PRId64, benchsteps > 1 ? "s" : "");
     fprintf(stdout, buf, benchsteps);
     if (statesteps > 0)
     {
-        sprintf(buf, " (adding %s steps from checkpoint file)", gmx_large_int_pfmt);
+        sprintf(buf, " (adding %s steps from checkpoint file)", "%"GMX_PRId64);
         fprintf(stdout, buf, statesteps);
         benchsteps += statesteps;
     }
@@ -930,7 +945,7 @@ static void make_benchmark_tprs(
     fprintf(fp, "   Grid spacing x y z   : %f %f %f\n",
             box_size[XX]/ir->nkx, box_size[YY]/ir->nky, box_size[ZZ]/ir->nkz);
     fprintf(fp, "   Van der Waals type   : %s\n", EVDWTYPE(ir->vdwtype));
-    if (EVDW_SWITCHED(ir->vdwtype))
+    if (ir_vdw_switched(ir))
     {
         fprintf(fp, "   rvdw_switch          : %f nm\n", ir->rvdw_switch);
     }
@@ -948,7 +963,7 @@ static void make_benchmark_tprs(
     fprintf(fp, " No.   scaling  rcoulomb");
     fprintf(fp, "  nkx  nky  nkz");
     fprintf(fp, "   spacing");
-    if (evdwCUT == ir->vdwtype)
+    if (can_scale_rvdw(ir->vdwtype))
     {
         fprintf(fp, "      rvdw");
     }
@@ -993,7 +1008,7 @@ static void make_benchmark_tprs(
             ir->nkx = ir->nky = ir->nkz = 0;
             calc_grid(NULL, state.box, fourierspacing*fac, &ir->nkx, &ir->nky, &ir->nkz);
 
-            /* Adjust other radii since various conditions neet to be fulfilled */
+            /* Adjust other radii since various conditions need to be fulfilled */
             if (eelPME == ir->coulombtype)
             {
                 /* plain PME, rcoulomb must be equal to rlist */
@@ -1005,10 +1020,21 @@ static void make_benchmark_tprs(
                 ir->rlist = ir->rcoulomb + nlist_buffer;
             }
 
-            if (bScaleRvdw && evdwCUT == ir->vdwtype)
+            if (bScaleRvdw && can_scale_rvdw(ir->vdwtype))
             {
-                /* For vdw cutoff, rvdw >= rlist */
-                ir->rvdw = max(info->rvdw[0], ir->rlist);
+                if (ecutsVERLET == ir->cutoff_scheme ||
+                    evdwPME == ir->vdwtype)
+                {
+                    /* With either the Verlet cutoff-scheme or LJ-PME,
+                       the van der Waals radius must always equal the
+                       Coulomb radius */
+                    ir->rvdw = ir->rcoulomb;
+                }
+                else
+                {
+                    /* For vdw cutoff, rvdw >= rlist */
+                    ir->rvdw = max(info->rvdw[0], ir->rlist);
+                }
             }
 
             ir->rlistlong = max_cutoff(ir->rlist, max_cutoff(ir->rvdw, ir->rcoulomb));
@@ -1033,7 +1059,7 @@ static void make_benchmark_tprs(
         sprintf(buf, "_bench%.2d.tpr", j);
         strcat(fn_bench_tprs[j], buf);
         fprintf(stdout, "Writing benchmark tpr %s with nsteps=", fn_bench_tprs[j]);
-        fprintf(stdout, gmx_large_int_pfmt, ir->nsteps);
+        fprintf(stdout, "%"GMX_PRId64, ir->nsteps);
         if (j > 0)
         {
             fprintf(stdout, ", scaling factor %f\n", fac);
@@ -1049,7 +1075,7 @@ static void make_benchmark_tprs(
         fprintf(fp, "%4d%10f%10f", j, fac, ir->rcoulomb);
         fprintf(fp, "%5d%5d%5d", ir->nkx, ir->nky, ir->nkz);
         fprintf(fp, " %9f ", info->fsx[j]);
-        if (evdwCUT == ir->vdwtype)
+        if (can_scale_rvdw(ir->vdwtype))
         {
             fprintf(fp, "%10f", ir->rvdw);
         }
@@ -1149,33 +1175,12 @@ static void cleanup(const t_filenm *fnm, int nfile, int k, int nnodes,
         /* Delete the files which are created for each benchmark run: (options -b*) */
         else if ( (0 == strncmp(opt, "-b", 2)) && (opt2bSet(opt, nfile, fnm) || !is_optional(&fnm[i])) )
         {
-            fn = opt2fn(opt, nfile, fnm);
-            if (gmx_fexist(fn))
-            {
-                fprintf(stdout, "Deleting %s\n", fn);
-                remove(fn);
-            }
+            remove_if_exists(opt2fn(opt, nfile, fnm));
         }
     }
 }
 
 
-/* Returns the largest common factor of n1 and n2 */
-static int largest_common_factor(int n1, int n2)
-{
-    int factor, nmax;
-
-    nmax = min(n1, n2);
-    for (factor = nmax; factor > 0; factor--)
-    {
-        if (0 == (n1 % factor) && 0 == (n2 % factor) )
-        {
-            return(factor);
-        }
-    }
-    return 0; /* one for the compiler */
-}
-
 enum {
     eNpmeAuto, eNpmeAll, eNpmeReduced, eNpmeSubset, eNpmeNr
 };
@@ -1262,7 +1267,7 @@ static void make_npme_list(
                 gmx_fatal(FARGS, "Unknown option for eNPME in make_npme_list");
                 break;
         }
-        if (largest_common_factor(npp, npme) >= min_factor)
+        if (gmx_greatest_common_divisor(npp, npme) >= min_factor)
         {
             (*nPMEnodes)[nlist] = npme;
             nlist++;
@@ -1305,28 +1310,32 @@ static void init_perfdata(t_perf *perfdata[], int ntprs, int datasets, int repea
 
 
 /* Check for errors on mdrun -h */
-static void make_sure_it_runs(char *mdrun_cmd_line, int length, FILE *fp)
+static void make_sure_it_runs(char *mdrun_cmd_line, int length, FILE *fp,
+                              const t_filenm *fnm, int nfile)
 {
-    char *command, *msg;
-    int   ret;
+    const char *fn = NULL;
+    char       *command, *msg;
+    int         ret;
 
 
     snew(command, length +  15);
     snew(msg, length + 500);
 
-    fprintf(stdout, "Making sure the benchmarks can be executed ...\n");
-    /* FIXME: mdrun -h no longer actually does anything useful.
-     * It unconditionally prints the help, ignoring all other options. */
-    sprintf(command, "%s-h -quiet", mdrun_cmd_line);
+    fprintf(stdout, "Making sure the benchmarks can be executed by running just 1 step...\n");
+    sprintf(command, "%s -nsteps 1 -quiet", mdrun_cmd_line);
+    fprintf(stdout, "Executing '%s' ...\n", command);
     ret = gmx_system_call(command);
 
     if (0 != ret)
     {
         /* To prevent confusion, do not again issue a gmx_fatal here since we already
          * get the error message from mdrun itself */
-        sprintf(msg,    "Cannot run the benchmark simulations! Please check the error message of\n"
+        sprintf(msg,
+                "Cannot run the first benchmark simulation! Please check the error message of\n"
                 "mdrun for the source of the problem. Did you provide a command line\n"
-                "argument that neither g_tune_pme nor mdrun understands? Offending command:\n"
+                "argument that neither gmx tune_pme nor mdrun understands? If you're\n"
+                "sure your command line should work, you can bypass this check with \n"
+                "gmx tune_pme -nocheck. The failing command was:\n"
                 "\n%s\n\n", command);
 
         fprintf(stderr, "%s", msg);
@@ -1335,6 +1344,14 @@ static void make_sure_it_runs(char *mdrun_cmd_line, int length, FILE *fp)
 
         exit(ret);
     }
+    fprintf(stdout, "Benchmarks can be executed!\n");
+
+    /* Clean up the benchmark output files we just created */
+    fprintf(stdout, "Cleaning up ...\n");
+    remove_if_exists(opt2fn("-bc", nfile, fnm));
+    remove_if_exists(opt2fn("-be", nfile, fnm));
+    remove_if_exists(opt2fn("-bcpo", nfile, fnm));
+    remove_if_exists(opt2fn("-bg", nfile, fnm));
 
     sfree(command);
     sfree(msg    );
@@ -1349,7 +1366,7 @@ static void do_the_tests(
         int             npme_fixed,     /* If >= -1, test fixed number of PME
                                          * nodes only                             */
         const char     *npmevalues_opt, /* Which -npme values should be tested    */
-        t_perf        **perfdata,       /* Here the performace data is stored     */
+        t_perf        **perfdata,       /* Here the performance data is stored    */
         int            *pmeentries,     /* Entries in the nPMEnodes list          */
         int             repeats,        /* Repeat each test this often            */
         int             nnodes,         /* Total number of nodes = nPP + nPME     */
@@ -1362,7 +1379,8 @@ static void do_the_tests(
         const t_filenm *fnm,            /* List of filenames from command line    */
         int             nfile,          /* Number of files specified on the cmdl. */
         int             presteps,       /* DLB equilibration steps, is checked    */
-        gmx_large_int_t cpt_steps)      /* Time step counter in the checkpoint    */
+        gmx_int64_t     cpt_steps,      /* Time step counter in the checkpoint    */
+        gmx_bool        bCheck)         /* Check whether benchmark mdrun works    */
 {
     int      i, nr, k, ret, count = 0, totaltests;
     int     *nPMEnodes = NULL;
@@ -1385,7 +1403,7 @@ static void do_the_tests(
         "No DD grid found for these settings.",
         "TPX version conflict!",
         "mdrun was not started in parallel!",
-        "Number of PP nodes has a prime factor that is too large.",
+        "Number of PP ranks has a prime factor that is too large.",
         "An error occured."
     };
     char        str_PME_f_load[13];
@@ -1422,13 +1440,13 @@ static void do_the_tests(
         *pmeentries  = 1;
         snew(nPMEnodes, 1);
         nPMEnodes[0] = npme_fixed;
-        fprintf(stderr, "Will use a fixed number of %d PME-only nodes.\n", nPMEnodes[0]);
+        fprintf(stderr, "Will use a fixed number of %d PME-only ranks.\n", nPMEnodes[0]);
     }
 
     if (0 == repeats)
     {
         fprintf(fp, "\nNo benchmarks done since number of repeats (-r) is 0.\n");
-        ffclose(fp);
+        gmx_ffclose(fp);
         finalize(opt2fn("-p", nfile, fnm));
         exit(0);
     }
@@ -1443,7 +1461,7 @@ static void do_the_tests(
     for (k = 0; k < nr_tprs; k++)
     {
         fprintf(fp, "\nIndividual timings for input file %d (%s):\n", k, tpr_names[k]);
-        fprintf(fp, "PME nodes      Gcycles       ns/day        PME/f    Remark\n");
+        fprintf(fp, "PME ranks      Gcycles       ns/day        PME/f    Remark\n");
         /* Loop over various numbers of PME nodes: */
         for (i = 0; i < *pmeentries; i++)
         {
@@ -1462,10 +1480,13 @@ static void do_the_tests(
                         cmd_stub, pd->nPMEnodes, tpr_names[k], cmd_args_bench);
 
                 /* To prevent that all benchmarks fail due to a show-stopper argument
-                 * on the mdrun command line, we make a quick check with mdrun -h first */
-                if (bFirst)
+                 * on the mdrun command line, we make a quick check first.
+                 * This check can be turned off in cases where the automatically chosen
+                 * number of PME-only ranks leads to a number of PP ranks for which no
+                 * decomposition can be found (e.g. for large prime numbers) */
+                if (bFirst && bCheck)
                 {
-                    make_sure_it_runs(pd->mdrun_cmd_line, cmdline_length, fp);
+                    make_sure_it_runs(pd->mdrun_cmd_line, cmdline_length, fp, fnm, nfile);
                 }
                 bFirst = FALSE;
 
@@ -1560,7 +1581,7 @@ static void check_input(
         real            maxPMEfraction,
         real            minPMEfraction,
         int             npme_fixed,
-        gmx_large_int_t bench_nsteps,
+        gmx_int64_t     bench_nsteps,
         const t_filenm *fnm,
         int             nfile,
         int             sim_part,
@@ -1593,7 +1614,7 @@ static void check_input(
     /* Check number of nodes */
     if (nnodes < 1)
     {
-        gmx_fatal(FARGS, "Number of nodes/threads must be a positive integer.");
+        gmx_fatal(FARGS, "Number of ranks/threads must be a positive integer.");
     }
 
     /* Automatically choose -ntpr if not set */
@@ -1704,7 +1725,7 @@ static void check_input(
     if (bench_nsteps > 10000 || bench_nsteps < 100)
     {
         fprintf(stderr, "WARNING: steps=");
-        fprintf(stderr, gmx_large_int_pfmt, bench_nsteps);
+        fprintf(stderr, "%"GMX_PRId64, bench_nsteps);
         fprintf(stderr, ". Are you sure you want to perform so %s steps for each benchmark?\n", (bench_nsteps < 100) ? "few" : "many");
     }
 
@@ -1730,18 +1751,18 @@ static void check_input(
         /* No more than 50% of all nodes can be assigned as PME-only nodes. */
         if (2*npme_fixed > nnodes)
         {
-            gmx_fatal(FARGS, "Cannot have more than %d PME-only nodes for a total of %d nodes (you chose %d).\n",
+            gmx_fatal(FARGS, "Cannot have more than %d PME-only ranks for a total of %d ranks (you chose %d).\n",
                       nnodes/2, nnodes, npme_fixed);
         }
         if ((npme_fixed > 0) && (5*npme_fixed < nnodes))
         {
-            fprintf(stderr, "WARNING: Only %g percent of the nodes are assigned as PME-only nodes.\n",
+            fprintf(stderr, "WARNING: Only %g percent of the ranks are assigned as PME-only ranks.\n",
                     100.0*((real)npme_fixed / (real)nnodes));
         }
         if (opt2parg_bSet("-min", npargs, pa) || opt2parg_bSet("-max", npargs, pa))
         {
             fprintf(stderr, "NOTE: The -min, -max, and -npme options have no effect when a\n"
-                    "      fixed number of PME-only nodes is requested with -fix.\n");
+                    "      fixed number of PME-only ranks is requested with -fix.\n");
         }
     }
 }
@@ -1750,6 +1771,11 @@ static void check_input(
 /* Returns TRUE when "opt" is needed at launch time */
 static gmx_bool is_launch_file(char *opt, gmx_bool bSet)
 {
+    if (0 == strncmp(opt, "-swap", 5))
+    {
+        return bSet;
+    }
+
     /* Apart from the input .tpr and the output log files we need all options that
      * were set on the command line and that do not start with -b */
     if    (0 == strncmp(opt, "-b", 2) || 0 == strncmp(opt, "-s", 2)
@@ -1925,6 +1951,7 @@ static float inspect_tpr(int nfile, t_filenm fnm[], real *rcoulomb)
     gmx_bool     bTpi;      /* Is test particle insertion requested?          */
     gmx_bool     bFree;     /* Is a free energy simulation requested?         */
     gmx_bool     bNM;       /* Is a normal mode analysis requested?           */
+    gmx_bool     bSwap;     /* Is water/ion position swapping requested?      */
     t_inputrec   ir;
     t_state      state;
     gmx_mtop_t   mtop;
@@ -1935,6 +1962,7 @@ static float inspect_tpr(int nfile, t_filenm fnm[], real *rcoulomb)
     bPull = (epullNO != ir.ePull);
     bFree = (efepNO  != ir.efep );
     bNM   = (eiNM    == ir.eI   );
+    bSwap = (eswapNO != ir.eSwapCoords);
     bTpi  = EI_TPI(ir.eI);
 
     /* Set these output files on the tuning command-line */
@@ -1956,6 +1984,10 @@ static float inspect_tpr(int nfile, t_filenm fnm[], real *rcoulomb)
     {
         setopt("-mtx", nfile, fnm);
     }
+    if (bSwap)
+    {
+        setopt("-swap", nfile, fnm);
+    }
 
     *rcoulomb = ir.rcoulomb;
 
@@ -2000,44 +2032,47 @@ static void couple_files_options(int nfile, t_filenm fnm[])
 int gmx_tune_pme(int argc, char *argv[])
 {
     const char     *desc[] = {
-        "For a given number [TT]-np[tt] or [TT]-ntmpi[tt] of processors/threads, this program systematically",
-        "times [TT]mdrun[tt] with various numbers of PME-only nodes and determines",
+        "For a given number [TT]-np[tt] or [TT]-ntmpi[tt] of ranks, [THISMODULE] systematically",
+        "times [gmx-mdrun] with various numbers of PME-only ranks and determines",
         "which setting is fastest. It will also test whether performance can",
         "be enhanced by shifting load from the reciprocal to the real space",
         "part of the Ewald sum. ",
-        "Simply pass your [TT].tpr[tt] file to [TT]g_tune_pme[tt] together with other options",
-        "for [TT]mdrun[tt] as needed.[PAR]",
+        "Simply pass your [TT].tpr[tt] file to [THISMODULE] together with other options",
+        "for [gmx-mdrun] as needed.[PAR]",
         "Which executables are used can be set in the environment variables",
         "MPIRUN and MDRUN. If these are not present, 'mpirun' and 'mdrun'",
         "will be used as defaults. Note that for certain MPI frameworks you",
         "need to provide a machine- or hostfile. This can also be passed",
         "via the MPIRUN variable, e.g.[PAR]",
         "[TT]export MPIRUN=\"/usr/local/mpirun -machinefile hosts\"[tt][PAR]",
-        "Please call [TT]g_tune_pme[tt] with the normal options you would pass to",
-        "[TT]mdrun[tt] and add [TT]-np[tt] for the number of processors to perform the",
+        "Before doing the actual benchmark runs, [THISMODULE] will do a quick",
+        "check whether mdrun works as expected with the provided parallel settings",
+        "if the [TT]-check[tt] option is activated (the default).",
+        "Please call [THISMODULE] with the normal options you would pass to",
+        "[gmx-mdrun] and add [TT]-np[tt] for the number of ranks to perform the",
         "tests on, or [TT]-ntmpi[tt] for the number of threads. You can also add [TT]-r[tt]",
         "to repeat each test several times to get better statistics. [PAR]",
-        "[TT]g_tune_pme[tt] can test various real space / reciprocal space workloads",
+        "[THISMODULE] can test various real space / reciprocal space workloads",
         "for you. With [TT]-ntpr[tt] you control how many extra [TT].tpr[tt] files will be",
         "written with enlarged cutoffs and smaller Fourier grids respectively.",
         "Typically, the first test (number 0) will be with the settings from the input",
         "[TT].tpr[tt] file; the last test (number [TT]ntpr[tt]) will have the Coulomb cutoff",
-        "specified by [TT]-rmax[tt] with a somwhat smaller PME grid at the same time. ",
+        "specified by [TT]-rmax[tt] with a somewhat smaller PME grid at the same time. ",
         "In this last test, the Fourier spacing is multiplied with [TT]rmax[tt]/rcoulomb. ",
         "The remaining [TT].tpr[tt] files will have equally-spaced Coulomb radii (and Fourier "
         "spacings) between these extremes. [BB]Note[bb] that you can set [TT]-ntpr[tt] to 1",
-        "if you just seek the optimal number of PME-only nodes; in that case",
+        "if you just seek the optimal number of PME-only ranks; in that case",
         "your input [TT].tpr[tt] file will remain unchanged.[PAR]",
         "For the benchmark runs, the default of 1000 time steps should suffice for most",
         "MD systems. The dynamic load balancing needs about 100 time steps",
         "to adapt to local load imbalances, therefore the time step counters",
         "are by default reset after 100 steps. For large systems (>1M atoms), as well as ",
-        "for a higher accuarcy of the measurements, you should set [TT]-resetstep[tt] to a higher value.",
+        "for a higher accuracy of the measurements, you should set [TT]-resetstep[tt] to a higher value.",
         "From the 'DD' load imbalance entries in the md.log output file you",
         "can tell after how many steps the load is sufficiently balanced. Example call:[PAR]"
-        "[TT]g_tune_pme -np 64 -s protein.tpr -launch[tt][PAR]",
-        "After calling [TT]mdrun[tt] several times, detailed performance information",
-        "is available in the output file [TT]perf.out.[tt] ",
+        "[TT]gmx tune_pme -np 64 -s protein.tpr -launch[tt][PAR]",
+        "After calling [gmx-mdrun] several times, detailed performance information",
+        "is available in the output file [TT]perf.out[tt].",
         "[BB]Note[bb] that during the benchmarks, a couple of temporary files are written",
         "(options [TT]-b[tt]*), these will be automatically deleted after each test.[PAR]",
         "If you want the simulation to be started automatically with the",
@@ -2058,9 +2093,9 @@ int gmx_tune_pme(int argc, char *argv[])
     real            rmin           = 0.0, rmax = 0.0; /* min and max value for rcoulomb if scaling is requested */
     real            rcoulomb       = -1.0;            /* Coulomb radius as set in .tpr file */
     gmx_bool        bScaleRvdw     = TRUE;
-    gmx_large_int_t bench_nsteps   = BENCHSTEPS;
-    gmx_large_int_t new_sim_nsteps = -1;  /* -1 indicates: not set by the user */
-    gmx_large_int_t cpt_steps      = 0;   /* Step counter in .cpt input file   */
+    gmx_int64_t     bench_nsteps   = BENCHSTEPS;
+    gmx_int64_t     new_sim_nsteps = -1;  /* -1 indicates: not set by the user */
+    gmx_int64_t     cpt_steps      = 0;   /* Step counter in .cpt input file   */
     int             presteps       = 100; /* Do a full cycle reset after presteps steps */
     gmx_bool        bOverwrite     = FALSE, bKeepTPR;
     gmx_bool        bLaunch        = FALSE;
@@ -2093,7 +2128,7 @@ int gmx_tune_pme(int argc, char *argv[])
         /* mdrun: */
         { efTPX, NULL,      NULL,       ffREAD },
         { efTRN, "-o",      NULL,       ffWRITE },
-        { efXTC, "-x",      NULL,       ffOPTWR },
+        { efCOMPRESSED, "-x", NULL,     ffOPTWR },
         { efCPT, "-cpi",    NULL,       ffOPTRD },
         { efCPT, "-cpo",    NULL,       ffOPTWR },
         { efSTO, "-c",      "confout",  ffWRITE },
@@ -2120,6 +2155,7 @@ int gmx_tune_pme(int argc, char *argv[])
         { efLOG, "-rt",     "rottorque", ffOPTWR },
         { efMTX, "-mtx",    "nm",       ffOPTWR },
         { efNDX, "-dn",     "dipole",   ffOPTWR },
+        { efXVG, "-swap",   "swapions", ffOPTWR },
         /* Output files that are deleted after each benchmark run */
         { efTRN, "-bo",     "bench",    ffWRITE },
         { efXTC, "-bx",     "bench",    ffWRITE },
@@ -2141,7 +2177,8 @@ int gmx_tune_pme(int argc, char *argv[])
         { efLOG, "-brs",    "benchrots", ffOPTWR },
         { efLOG, "-brt",    "benchrott", ffOPTWR },
         { efMTX, "-bmtx",   "benchn",   ffOPTWR },
-        { efNDX, "-bdn",    "bench",    ffOPTWR }
+        { efNDX, "-bdn",    "bench",    ffOPTWR },
+        { efXVG, "-bswap",  "benchswp", ffOPTWR }
     };
 
     gmx_bool        bThreads     = FALSE;
@@ -2157,6 +2194,7 @@ int gmx_tune_pme(int argc, char *argv[])
     gmx_bool     bKeepAndNumCPT        = FALSE;
     gmx_bool     bResetCountersHalfWay = FALSE;
     gmx_bool     bBenchmark            = TRUE;
+    gmx_bool     bCheck                = TRUE;
 
     output_env_t oenv = NULL;
 
@@ -2165,22 +2203,22 @@ int gmx_tune_pme(int argc, char *argv[])
         /* g_tune_pme options: */
         /***********************/
         { "-np",       FALSE, etINT,  {&nnodes},
-          "Number of nodes to run the tests on (must be > 2 for separate PME nodes)" },
+          "Number of ranks to run the tests on (must be > 2 for separate PME ranks)" },
         { "-npstring", FALSE, etENUM, {procstring},
-          "Specify the number of processors to [TT]$MPIRUN[tt] using this string"},
+          "Specify the number of ranks to [TT]$MPIRUN[tt] using this string"},
         { "-ntmpi",    FALSE, etINT,  {&nthreads},
           "Number of MPI-threads to run the tests on (turns MPI & mpirun off)"},
         { "-r",        FALSE, etINT,  {&repeats},
           "Repeat each test this often" },
         { "-max",      FALSE, etREAL, {&maxPMEfraction},
-          "Max fraction of PME nodes to test with" },
+          "Max fraction of PME ranks to test with" },
         { "-min",      FALSE, etREAL, {&minPMEfraction},
-          "Min fraction of PME nodes to test with" },
+          "Min fraction of PME ranks to test with" },
         { "-npme",     FALSE, etENUM, {npmevalues_opt},
           "Within -min and -max, benchmark all possible values for [TT]-npme[tt], or just a reasonable subset. "
           "Auto neglects -min and -max and chooses reasonable values around a guess for npme derived from the .tpr"},
         { "-fix",      FALSE, etINT,  {&npme_fixed},
-          "If >= -1, do not vary the number of PME-only nodes, instead use this fixed value and only vary rcoulomb and the PME grid spacing."},
+          "If >= -1, do not vary the number of PME-only ranks, instead use this fixed value and only vary rcoulomb and the PME grid spacing."},
         { "-rmax",     FALSE, etREAL, {&rmax},
           "If >0, maximal rcoulomb for -ntpr>1 (rcoulomb upscaling results in fourier grid downscaling)" },
         { "-rmin",     FALSE, etREAL, {&rmin},
@@ -2190,16 +2228,18 @@ int gmx_tune_pme(int argc, char *argv[])
         { "-ntpr",     FALSE, etINT,  {&ntprs},
           "Number of [TT].tpr[tt] files to benchmark. Create this many files with different rcoulomb scaling factors depending on -rmin and -rmax. "
           "If < 1, automatically choose the number of [TT].tpr[tt] files to test" },
-        { "-steps",    FALSE, etGMX_LARGE_INT, {&bench_nsteps},
+        { "-steps",    FALSE, etINT64, {&bench_nsteps},
           "Take timings for this many steps in the benchmark runs" },
         { "-resetstep", FALSE, etINT,  {&presteps},
           "Let dlb equilibrate this many steps before timings are taken (reset cycle counters after this many steps)" },
-        { "-simsteps", FALSE, etGMX_LARGE_INT, {&new_sim_nsteps},
+        { "-simsteps", FALSE, etINT64, {&new_sim_nsteps},
           "If non-negative, perform this many steps in the real run (overwrites nsteps from [TT].tpr[tt], add [TT].cpt[tt] steps)" },
         { "-launch",   FALSE, etBOOL, {&bLaunch},
           "Launch the real simulation after optimization" },
         { "-bench",    FALSE, etBOOL, {&bBenchmark},
           "Run the benchmarks or just create the input [TT].tpr[tt] files?" },
+        { "-check",    FALSE, etBOOL, {&bCheck},
+          "Before the benchmark runs, check whether mdrun works in parallel" },
         /******************/
         /* mdrun options: */
         /******************/
@@ -2299,7 +2339,7 @@ int gmx_tune_pme(int argc, char *argv[])
     }
 
     /* Open performance output file and write header info */
-    fp = ffopen(opt2fn("-p", NFILE, fnm), "w");
+    fp = gmx_ffopen(opt2fn("-p", NFILE, fnm), "w");
 
     /* Make a quick consistency check of command line parameters */
     check_input(nnodes, repeats, &ntprs, &rmin, rcoulomb, &rmax,
@@ -2339,7 +2379,7 @@ int gmx_tune_pme(int argc, char *argv[])
             {
                 fprintf(stdout, "- %d ", maxPMEnodes);
             }
-            fprintf(stdout, "PME-only nodes.\n  Note that the automatic number of PME-only nodes and no separate PME nodes are always tested.\n");
+            fprintf(stdout, "PME-only ranks.\n  Note that the automatic number of PME-only ranks and no separate PME ranks are always tested.\n");
         }
     }
     else
@@ -2362,15 +2402,15 @@ int gmx_tune_pme(int argc, char *argv[])
     fprintf(fp, "%s for Gromacs %s\n", ShortProgram(), GromacsVersion());
     if (!bThreads)
     {
-        fprintf(fp, "Number of nodes         : %d\n", nnodes);
+        fprintf(fp, "Number of ranks         : %d\n", nnodes);
         fprintf(fp, "The mpirun command is   : %s\n", cmd_mpirun);
         if (strcmp(procstring[0], "none") != 0)
         {
-            fprintf(fp, "Passing # of nodes via  : %s\n", procstring[0]);
+            fprintf(fp, "Passing # of ranks via  : %s\n", procstring[0]);
         }
         else
         {
-            fprintf(fp, "Not setting number of nodes in system call\n");
+            fprintf(fp, "Not setting number of ranks in system call\n");
         }
     }
     else
@@ -2381,13 +2421,13 @@ int gmx_tune_pme(int argc, char *argv[])
     fprintf(fp, "The mdrun  command is   : %s\n", cmd_mdrun);
     fprintf(fp, "mdrun args benchmarks   : %s\n", cmd_args_bench);
     fprintf(fp, "Benchmark steps         : ");
-    fprintf(fp, gmx_large_int_pfmt, bench_nsteps);
+    fprintf(fp, "%"GMX_PRId64, bench_nsteps);
     fprintf(fp, "\n");
     fprintf(fp, "dlb equilibration steps : %d\n", presteps);
     if (sim_part > 1)
     {
         fprintf(fp, "Checkpoint time step    : ");
-        fprintf(fp, gmx_large_int_pfmt, cpt_steps);
+        fprintf(fp, "%"GMX_PRId64, cpt_steps);
         fprintf(fp, "\n");
     }
     fprintf(fp, "mdrun args at launchtime: %s\n", cmd_args_launch);
@@ -2396,10 +2436,10 @@ int gmx_tune_pme(int argc, char *argv[])
     {
         bOverwrite = TRUE;
         fprintf(stderr, "Note: Simulation input file %s will have ", opt2fn("-so", NFILE, fnm));
-        fprintf(stderr, gmx_large_int_pfmt, new_sim_nsteps+cpt_steps);
+        fprintf(stderr, "%"GMX_PRId64, new_sim_nsteps+cpt_steps);
         fprintf(stderr, " steps.\n");
         fprintf(fp, "Simulation steps        : ");
-        fprintf(fp, gmx_large_int_pfmt, new_sim_nsteps);
+        fprintf(fp, "%"GMX_PRId64, new_sim_nsteps);
         fprintf(fp, "\n");
     }
     if (repeats > 1)
@@ -2451,7 +2491,7 @@ int gmx_tune_pme(int argc, char *argv[])
     {
         do_the_tests(fp, tpr_names, maxPMEnodes, minPMEnodes, npme_fixed, npmevalues_opt[0], perfdata, &pmeentries,
                      repeats, nnodes, ntprs, bThreads, cmd_mpirun, cmd_np, cmd_mdrun,
-                     cmd_args_bench, fnm, NFILE, presteps, cpt_steps);
+                     cmd_args_bench, fnm, NFILE, presteps, cpt_steps, bCheck);
 
         fprintf(fp, "\nTuning took%8.1f minutes.\n", (gmx_gettime()-seconds)/60.0);
 
@@ -2482,7 +2522,7 @@ int gmx_tune_pme(int argc, char *argv[])
         launch_simulation(bLaunch, fp, bThreads, cmd_mpirun, cmd_np, cmd_mdrun,
                           cmd_args_launch, simulation_tpr, best_npme);
     }
-    ffclose(fp);
+    gmx_ffclose(fp);
 
     /* ... or simply print the performance results to screen: */
     if (!bLaunch)