Reimplement constant acceleration groups
[alexxy/gromacs.git] / src / gromacs / tools / dump.cpp
index 546807b7c0c218f9c62800af9439fb931898b169..d6506af7f99dfc769768bcb6350bf89591de0a41 100644 (file)
@@ -3,7 +3,8 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2013, The GROMACS development team.
- * Copyright (c) 2013,2014,2015,2016,2017,2018, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
+ * Copyright (c) 2018,2019,2020,2021, 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.
  * To help us fund GROMACS development, we humbly ask that you cite
  * the research papers on the package. Check out http://www.gromacs.org.
  */
+/*! \internal \file
+ * \brief Implements gmx dump utility.
+ *
+ * \ingroup module_tools
+ */
 #include "gmxpre.h"
 
 #include "dump.h"
 #include <cstdio>
 #include <cstring>
 
-#include "gromacs/commandline/pargs.h"
+#include "gromacs/commandline/cmdlineoptionsmodule.h"
 #include "gromacs/fileio/checkpoint.h"
 #include "gromacs/fileio/enxio.h"
+#include "gromacs/fileio/filetypes.h"
 #include "gromacs/fileio/gmxfio.h"
 #include "gromacs/fileio/mtxio.h"
 #include "gromacs/fileio/tngio.h"
 #include "gromacs/fileio/trrio.h"
 #include "gromacs/fileio/xtcio.h"
 #include "gromacs/gmxpreprocess/gmxcpp.h"
-#include "gromacs/linearalgebra/sparsematrix.h"
 #include "gromacs/math/vecdump.h"
-#include "gromacs/mdrunutility/mdmodules.h"
+#include "gromacs/mdrun/mdmodules.h"
 #include "gromacs/mdtypes/forcerec.h"
 #include "gromacs/mdtypes/inputrec.h"
 #include "gromacs/mdtypes/md_enums.h"
 #include "gromacs/mdtypes/state.h"
+#include "gromacs/options/basicoptions.h"
+#include "gromacs/options/filenameoption.h"
+#include "gromacs/options/ioptionscontainer.h"
 #include "gromacs/topology/mtop_util.h"
 #include "gromacs/topology/topology.h"
 #include "gromacs/trajectory/energyframe.h"
 #include "gromacs/utility/smalloc.h"
 #include "gromacs/utility/txtdump.h"
 
-static void list_tpx(const char *fn,
-                     gmx_bool    bShowNumbers,
-                     gmx_bool    bShowParameters,
-                     const char *mdpfn,
-                     gmx_bool    bSysTop,
-                     gmx_bool    bOriginalInputrec)
+namespace gmx
 {
-    FILE         *gp;
-    int           indent, i, j, **gcount, atot;
-    t_state       state;
-    t_tpxheader   tpx;
-    gmx_mtop_t    mtop;
-    gmx_groups_t *groups;
-    t_topology    top;
-
-    read_tpxheader(fn, &tpx, TRUE);
-    t_inputrec     ir;
-    read_tpx_state(fn,
-                   tpx.bIr ? &ir : nullptr,
-                   &state,
-                   tpx.bTop ? &mtop : nullptr);
+
+namespace
+{
+
+//! Dump a TPR file
+void list_tpr(const char* fn,
+              gmx_bool    bShowNumbers,
+              gmx_bool    bShowParameters,
+              const char* mdpfn,
+              gmx_bool    bSysTop,
+              gmx_bool    bOriginalInputrec)
+{
+    FILE*      gp;
+    int        indent, atot;
+    t_state    state;
+    gmx_mtop_t mtop;
+    t_topology top;
+
+    TpxFileHeader tpx = readTpxHeader(fn, true);
+    t_inputrec    ir;
+
+    read_tpx_state(fn, tpx.bIr ? &ir : nullptr, &state, tpx.bTop ? &mtop : nullptr);
     if (tpx.bIr && !bOriginalInputrec)
     {
-        gmx::MDModules().adjustInputrecBasedOnModules(&ir);
+        MDModules().adjustInputrecBasedOnModules(&ir);
     }
 
     if (mdpfn && tpx.bIr)
@@ -140,49 +152,48 @@ static void list_tpx(const char *fn,
             pr_doubles(stdout, indent, "nosehoover_xi", state.nosehoover_xi.data(), state.ngtc);
             /*pr_doubles(stdout,indent,"nosehoover_vxi",state.nosehoover_vxi,state.ngtc);*/
             /*pr_doubles(stdout,indent,"therm_integral",state.therm_integral,state.ngtc);*/
-            pr_rvecs(stdout, indent, "x", tpx.bX ? as_rvec_array(state.x.data()) : nullptr, state.natoms);
-            pr_rvecs(stdout, indent, "v", tpx.bV ? as_rvec_array(state.v.data()) : nullptr, state.natoms);
+            pr_rvecs(stdout, indent, "x", tpx.bX ? state.x.rvec_array() : nullptr, state.natoms);
+            pr_rvecs(stdout, indent, "v", tpx.bV ? state.v.rvec_array() : nullptr, state.natoms);
         }
 
-        groups = &mtop.groups;
+        const SimulationGroups& groups = mtop.groups;
 
-        snew(gcount, egcNR);
-        for (i = 0; (i < egcNR); i++)
+        gmx::EnumerationArray<SimulationAtomGroupType, std::vector<int>> gcount;
+        for (auto group : keysOf(gcount))
         {
-            snew(gcount[i], groups->grps[i].nr);
+            gcount[group].resize(groups.groups[group].size());
         }
 
-        for (i = 0; (i < mtop.natoms); i++)
+        for (int i = 0; (i < mtop.natoms); i++)
         {
-            for (j = 0; (j < egcNR); j++)
+            for (auto group : keysOf(gcount))
             {
-                gcount[j][ggrpnr(groups, j, i)]++;
+                gcount[group][getGroupType(groups, group, i)]++;
             }
         }
         printf("Group statistics\n");
-        for (i = 0; (i < egcNR); i++)
+        for (auto group : keysOf(gcount))
         {
             atot = 0;
-            printf("%-12s: ", gtypes[i]);
-            for (j = 0; (j < groups->grps[i].nr); j++)
+            printf("%-12s: ", shortName(group));
+            for (const auto& entry : gcount[group])
             {
-                printf("  %5d", gcount[i][j]);
-                atot += gcount[i][j];
+                printf("  %5d", entry);
+                atot += entry;
             }
             printf("  (total %d atoms)\n", atot);
-            sfree(gcount[i]);
         }
-        sfree(gcount);
     }
 }
 
-static void list_top(const char *fn)
+//! Dump a topology file
+void list_top(const char* fn)
 {
-    int       status, done;
-#define BUFLEN 256
-    char      buf[BUFLEN];
+    int status, done;
+    // Legacy string length macro
+    char      buf[STRLEN];
     gmx_cpp_t handle;
-    char     *cppopts[] = { nullptr };
+    char*     cppopts[] = { nullptr };
 
     status = cpp_open_file(fn, &handle, cppopts);
     if (status != 0)
@@ -191,8 +202,8 @@ static void list_top(const char *fn)
     }
     do
     {
-        status = cpp_read_line(&handle, BUFLEN, buf);
-        done   = (status == eCPP_EOF);
+        status = cpp_read_line(&handle, STRLEN, buf);
+        done   = static_cast<int>(status == eCPP_EOF);
         if (!done)
         {
             if (status != eCPP_OK)
@@ -204,8 +215,7 @@ static void list_top(const char *fn)
                 printf("%s\n", buf);
             }
         }
-    }
-    while (!done);
+    } while (done == 0);
     status = cpp_close_file(&handle);
     if (status != eCPP_OK)
     {
@@ -213,17 +223,18 @@ static void list_top(const char *fn)
     }
 }
 
-static void list_trr(const char *fn)
+//! Dump a TRR file
+void list_trr(const char* fn)
 {
-    t_fileio         *fpread;
-    int               nframe, indent;
-    char              buf[256];
-    rvec             *x, *v, *f;
-    matrix            box;
-    gmx_trr_header_t  trrheader;
-    gmx_bool          bOK;
+    t_fileio*        fpread;
+    int              nframe, indent;
+    char             buf[256];
+    rvec *           x, *v, *f;
+    matrix           box;
+    gmx_trr_header_t trrheader;
+    gmx_bool         bOK;
 
-    fpread  = gmx_trr_open(fn, "r");
+    fpread = gmx_trr_open(fn, "r");
 
     nframe = 0;
     while (gmx_trr_read_frame_header(fpread, &trrheader, &bOK))
@@ -231,18 +242,23 @@ static void list_trr(const char *fn)
         snew(x, trrheader.natoms);
         snew(v, trrheader.natoms);
         snew(f, trrheader.natoms);
-        if (gmx_trr_read_frame_data(fpread, &trrheader,
+        if (gmx_trr_read_frame_data(fpread,
+                                    &trrheader,
                                     trrheader.box_size ? box : nullptr,
-                                    trrheader.x_size   ? x : nullptr,
-                                    trrheader.v_size   ? v : nullptr,
-                                    trrheader.f_size   ? f : nullptr))
+                                    trrheader.x_size ? x : nullptr,
+                                    trrheader.v_size ? v : nullptr,
+                                    trrheader.f_size ? f : nullptr))
         {
             sprintf(buf, "%s frame %d", fn, nframe);
             indent = 0;
             indent = pr_title(stdout, indent, buf);
             pr_indent(stdout, indent);
-            fprintf(stdout, "natoms=%10d  step=%10" PRId64 "  time=%12.7e  lambda=%10g\n",
-                    trrheader.natoms, trrheader.step, trrheader.t, trrheader.lambda);
+            fprintf(stdout,
+                    "natoms=%10d  step=%10" PRId64 "  time=%12.7e  lambda=%10g\n",
+                    trrheader.natoms,
+                    trrheader.step,
+                    trrheader.t,
+                    trrheader.lambda);
             if (trrheader.box_size)
             {
                 pr_rvecs(stdout, indent, "box", box, DIM);
@@ -262,8 +278,7 @@ static void list_trr(const char *fn)
         }
         else
         {
-            fprintf(stderr, "\nWARNING: Incomplete frame: nr %d, t=%g\n",
-                    nframe, trrheader.t);
+            fprintf(stderr, "\nWARNING: Incomplete frame: nr %d, t=%g\n", nframe, trrheader.t);
         }
 
         sfree(x);
@@ -273,23 +288,23 @@ static void list_trr(const char *fn)
     }
     if (!bOK)
     {
-        fprintf(stderr, "\nWARNING: Incomplete frame header: nr %d, t=%g\n",
-                nframe, trrheader.t);
+        fprintf(stderr, "\nWARNING: Incomplete frame header: nr %d, t=%g\n", nframe, trrheader.t);
     }
     gmx_trr_close(fpread);
 }
 
-static void list_xtc(const char *fn)
+//! Dump an xtc file
+void list_xtc(const char* fn)
 {
-    t_fileio   *xd;
-    int         indent;
-    char        buf[256];
-    rvec       *x;
-    matrix      box;
-    int         nframe, natoms;
-    int64_t     step;
-    real        prec, time;
-    gmx_bool    bOK;
+    t_fileioxd;
+    int       indent;
+    char      buf[256];
+    rvec*     x;
+    matrix    box;
+    int       nframe, natoms;
+    int64_t   step;
+    real      prec, time;
+    gmx_bool  bOK;
 
     xd = open_xtc(fn, "r");
     read_first_xtc(xd, &natoms, &step, &time, box, &x, &prec, &bOK);
@@ -301,13 +316,11 @@ static void list_xtc(const char *fn)
         indent = 0;
         indent = pr_title(stdout, indent, buf);
         pr_indent(stdout, indent);
-        fprintf(stdout, "natoms=%10d  step=%10" PRId64 "  time=%12.7e  prec=%10g\n",
-                natoms, step, time, prec);
+        fprintf(stdout, "natoms=%10d  step=%10" PRId64 "  time=%12.7e  prec=%10g\n", natoms, step, time, prec);
         pr_rvecs(stdout, indent, "box", box, DIM);
         pr_rvecs(stdout, indent, "x", x, natoms);
         nframe++;
-    }
-    while (read_next_xtc(xd, natoms, &step, &time, box, x, &prec, &bOK));
+    } while (read_next_xtc(xd, natoms, &step, &time, box, x, &prec, &bOK) != 0);
     if (!bOK)
     {
         fprintf(stderr, "\nWARNING: Incomplete frame at time %g\n", time);
@@ -316,20 +329,22 @@ static void list_xtc(const char *fn)
     close_xtc(xd);
 }
 
+#if GMX_USE_TNG
+
 /*! \brief Callback used by list_tng_for_gmx_dump. */
-static void list_tng_inner(const char *fn,
-                           gmx_bool    bFirstFrame,
-                           real       *values,
-                           int64_t     step,
-                           double      frame_time,
-                           int64_t     n_values_per_frame,
-                           int64_t     n_atoms,
-                           real        prec,
-                           int64_t     nframe,
-                           char       *block_name)
+void list_tng_inner(const char* fn,
+                    gmx_bool    bFirstFrame,
+                    real*       values,
+                    int64_t     step,
+                    double      frame_time,
+                    int64_t     n_values_per_frame,
+                    int64_t     n_atoms,
+                    real        prec,
+                    int64_t     nframe,
+                    char*       block_name)
 {
-    char                 buf[256];
-    int                  indent = 0;
+    char buf[256];
+    int  indent = 0;
 
     if (bFirstFrame)
     {
@@ -337,8 +352,7 @@ static void list_tng_inner(const char *fn,
         indent = 0;
         indent = pr_title(stdout, indent, buf);
         pr_indent(stdout, indent);
-        fprintf(stdout, "natoms=%10" PRId64 "  step=%10" PRId64 "  time=%12.7e",
-                n_atoms, step, frame_time);
+        fprintf(stdout, "natoms=%10" PRId64 "  step=%10" PRId64 "  time=%12.7e", n_atoms, step, frame_time);
         if (prec > 0)
         {
             fprintf(stdout, "  prec=%10g", prec);
@@ -348,37 +362,42 @@ static void list_tng_inner(const char *fn,
     pr_reals_of_dim(stdout, indent, block_name, values, n_atoms, n_values_per_frame);
 }
 
-static void list_tng(const char gmx_unused *fn)
+#endif
+
+//! Dump a TNG file
+void list_tng(const char* fn)
 {
-#ifdef GMX_USE_TNG
+#if GMX_USE_TNG
     gmx_tng_trajectory_t tng;
     int64_t              nframe = 0;
     int64_t              i, *block_ids = nullptr, step, ndatablocks;
     gmx_bool             bOK;
-    real                *values = nullptr;
+    real*                values = nullptr;
 
     gmx_tng_open(fn, 'r', &tng);
     gmx_print_tng_molecule_system(tng, stdout);
 
-    bOK    = gmx_get_tng_data_block_types_of_next_frame(tng, -1,
-                                                        0,
-                                                        nullptr,
-                                                        &step, &ndatablocks,
-                                                        &block_ids);
+    bOK = gmx_get_tng_data_block_types_of_next_frame(tng, -1, 0, nullptr, &step, &ndatablocks, &block_ids);
     do
     {
         for (i = 0; i < ndatablocks; i++)
         {
-            double               frame_time;
-            real                 prec;
-            int64_t              n_values_per_frame, n_atoms;
-            char                 block_name[STRLEN];
-
-            gmx_get_tng_data_next_frame_of_block_type(tng, block_ids[i], &values,
-                                                      &step, &frame_time,
-                                                      &n_values_per_frame, &n_atoms,
+            double  frame_time;
+            real    prec;
+            int64_t n_values_per_frame, n_atoms;
+            char    block_name[STRLEN];
+
+            gmx_get_tng_data_next_frame_of_block_type(tng,
+                                                      block_ids[i],
+                                                      &values,
+                                                      &step,
+                                                      &frame_time,
+                                                      &n_values_per_frame,
+                                                      &n_atoms,
                                                       &prec,
-                                                      block_name, STRLEN, &bOK);
+                                                      block_name,
+                                                      STRLEN,
+                                                      &bOK);
             if (!bOK)
             {
                 /* Can't write any output because we don't know what
@@ -387,18 +406,13 @@ static void list_tng(const char gmx_unused *fn)
             }
             else
             {
-                list_tng_inner(fn, (0 == i), values, step, frame_time,
-                               n_values_per_frame, n_atoms, prec, nframe, block_name);
+                list_tng_inner(
+                        fn, (0 == i), values, step, frame_time, n_values_per_frame, n_atoms, prec, nframe, block_name);
             }
         }
         nframe++;
-    }
-    while (gmx_get_tng_data_block_types_of_next_frame(tng, step,
-                                                      0,
-                                                      nullptr,
-                                                      &step,
-                                                      &ndatablocks,
-                                                      &block_ids));
+    } while (gmx_get_tng_data_block_types_of_next_frame(
+            tng, step, 0, nullptr, &step, &ndatablocks, &block_ids));
 
     if (block_ids)
     {
@@ -406,36 +420,33 @@ static void list_tng(const char gmx_unused *fn)
     }
     sfree(values);
     gmx_tng_close(&tng);
+#else
+    GMX_UNUSED_VALUE(fn);
 #endif
 }
 
-static void list_trx(const char *fn)
+//! Dump a trajectory file
+void list_trx(const char* fn)
 {
     switch (fn2ftp(fn))
     {
-        case efXTC:
-            list_xtc(fn);
-            break;
-        case efTRR:
-            list_trr(fn);
-            break;
-        case efTNG:
-            list_tng(fn);
-            break;
+        case efXTC: list_xtc(fn); break;
+        case efTRR: list_trr(fn); break;
+        case efTNG: list_tng(fn); break;
         default:
-            fprintf(stderr, "File %s is of an unsupported type. Try using the command\n 'less %s'\n",
-                    fn, fn);
+            fprintf(stderr, "File %s is of an unsupported type. Try using the command\n 'less %s'\n", fn, fn);
     }
 }
 
-static void list_ene(const char *fn)
+//! Dump an energy file
+void list_ene(const char* fn)
 {
-    ener_file_t    in;
-    gmx_bool       bCont;
-    gmx_enxnm_t   *enm = nullptr;
-    t_enxframe    *fr;
-    int            i, j, nre, b;
-    char           buf[22];
+    ener_file_t  in;
+    gmx_bool     bCont;
+    gmx_enxnm_tenm = nullptr;
+    t_enxframe*  fr;
+    int          i, j, nre, b;
+    char         buf[22];
 
     printf("gmx dump: %s\n", fn);
     in = open_enx(fn, "r");
@@ -455,22 +466,24 @@ static void list_ene(const char *fn)
 
         if (bCont)
         {
-            printf("\n%24s  %12.5e  %12s  %12s\n", "time:",
-                   fr->t, "step:", gmx_step_str(fr->step, buf));
-            printf("%24s  %12s  %12s  %12s\n",
-                   "", "", "nsteps:", gmx_step_str(fr->nsteps, buf));
-            printf("%24s  %12.5e  %12s  %12s\n",
-                   "delta_t:", fr->dt, "sum steps:", gmx_step_str(fr->nsum, buf));
+            printf("\n%24s  %12.5e  %12s  %12s\n", "time:", fr->t, "step:", gmx_step_str(fr->step, buf));
+            printf("%24s  %12s  %12s  %12s\n", "", "", "nsteps:", gmx_step_str(fr->nsteps, buf));
+            printf("%24s  %12.5e  %12s  %12s\n", "delta_t:", fr->dt, "sum steps:", gmx_step_str(fr->nsum, buf));
             if (fr->nre == nre)
             {
                 printf("%24s  %12s  %12s  %12s\n",
-                       "Component", "Energy", "Av. Energy", "Sum Energy");
+                       "Component",
+                       "Energy",
+                       "Av. Energy",
+                       "Sum Energy");
                 if (fr->nsum > 0)
                 {
                     for (i = 0; (i < nre); i++)
                     {
                         printf("%24s  %12.5e  %12.5e  %12.5e\n",
-                               enm[i].name, fr->ener[i].e, fr->ener[i].eav,
+                               enm[i].name,
+                               fr->ener[i].e,
+                               fr->ener[i].eav,
                                fr->ener[i].esum);
                     }
                 }
@@ -478,18 +491,16 @@ static void list_ene(const char *fn)
                 {
                     for (i = 0; (i < nre); i++)
                     {
-                        printf("%24s  %12.5e\n",
-                               enm[i].name, fr->ener[i].e);
+                        printf("%24s  %12.5e\n", enm[i].name, fr->ener[i].e);
                     }
                 }
             }
             for (b = 0; b < fr->nblock; b++)
             {
-                const char *typestr = "";
+                const chartypestr = "";
 
-                t_enxblock *eb = &(fr->block[b]);
-                printf("Block data %2d (%3d subblocks, id=%d)\n",
-                       b, eb->nsub, eb->id);
+                t_enxblock* eb = &(fr->block[b]);
+                printf("Block data %2d (%3d subblocks, id=%d)\n", b, eb->nsub, eb->id);
 
                 if (eb->id < enxNR)
                 {
@@ -498,57 +509,56 @@ static void list_ene(const char *fn)
                 printf("  id='%s'\n", typestr);
                 for (i = 0; i < eb->nsub; i++)
                 {
-                    t_enxsubblock *sb = &(eb->sub[i]);
+                    t_enxsubblocksb = &(eb->sub[i]);
                     printf("  Sub block %3d (%5d elems, type=%s) values:\n",
-                           i, sb->nr, xdr_datatype_names[sb->type]);
+                           i,
+                           sb->nr,
+                           enumValueToString(sb->type));
 
                     switch (sb->type)
                     {
-                        case xdr_datatype_float:
+                        case XdrDataType::Float:
                             for (j = 0; j < sb->nr; j++)
                             {
                                 printf("%14d   %8.4f\n", j, sb->fval[j]);
                             }
                             break;
-                        case xdr_datatype_double:
+                        case XdrDataType::Double:
                             for (j = 0; j < sb->nr; j++)
                             {
                                 printf("%14d   %10.6f\n", j, sb->dval[j]);
                             }
                             break;
-                        case xdr_datatype_int:
+                        case XdrDataType::Int:
                             for (j = 0; j < sb->nr; j++)
                             {
                                 printf("%14d %10d\n", j, sb->ival[j]);
                             }
                             break;
-                        case xdr_datatype_int64:
+                        case XdrDataType::Int64:
                             for (j = 0; j < sb->nr; j++)
                             {
-                                printf("%14d %s\n",
-                                       j, gmx_step_str(sb->lval[j], buf));
+                                printf("%14d %s\n", j, gmx_step_str(sb->lval[j], buf));
                             }
                             break;
-                        case xdr_datatype_char:
+                        case XdrDataType::Char:
                             for (j = 0; j < sb->nr; j++)
                             {
                                 printf("%14d %1c\n", j, sb->cval[j]);
                             }
                             break;
-                        case xdr_datatype_string:
+                        case XdrDataType::String:
                             for (j = 0; j < sb->nr; j++)
                             {
                                 printf("%14d %80s\n", j, sb->sval[j]);
                             }
                             break;
-                        default:
-                            gmx_incons("Unknown subblock type");
+                        default: gmx_incons("Unknown subblock type");
                     }
                 }
             }
         }
-    }
-    while (bCont);
+    } while (bCont);
 
     close_enx(in);
 
@@ -557,18 +567,19 @@ static void list_ene(const char *fn)
     sfree(enm);
 }
 
-static void list_mtx(const char *fn)
+//! Dump a (Hessian) matrix file
+void list_mtx(const char* fn)
 {
-    int                  nrow, ncol, i, j, k;
-    real                *full   = nullptr, value;
-    gmx_sparsematrix_t * sparse = nullptr;
+    int                 nrow, ncol, i, j, k;
+    real *              full   = nullptr, value;
+    gmx_sparsematrix_t* sparse = nullptr;
 
     gmx_mtxio_read(fn, &nrow, &ncol, &full, &sparse);
 
     if (full == nullptr)
     {
-        snew(full, nrow*ncol);
-        for (i = 0; i < nrow*ncol; i++)
+        snew(full, nrow * ncol);
+        for (i = 0; i < nrow * ncol; i++)
         {
             full[i] = 0;
         }
@@ -577,10 +588,10 @@ static void list_mtx(const char *fn)
         {
             for (j = 0; j < sparse->ndata[i]; j++)
             {
-                k              = sparse->data[i][j].col;
-                value          = sparse->data[i][j].value;
-                full[i*ncol+k] = value;
-                full[k*ncol+i] = value;
+                k                  = sparse->data[i][j].col;
+                value              = sparse->data[i][j].value;
+                full[i * ncol + k] = value;
+                full[k * ncol + i] = value;
             }
         }
         gmx_sparsematrix_destroy(sparse);
@@ -591,7 +602,7 @@ static void list_mtx(const char *fn)
     {
         for (j = 0; j < ncol; j++)
         {
-            printf(" %g", full[i*ncol+j]);
+            printf(" %g", full[i * ncol + j]);
         }
         printf("\n");
     }
@@ -599,78 +610,145 @@ static void list_mtx(const char *fn)
     sfree(full);
 }
 
-int gmx_dump(int argc, char *argv[])
+class Dump : public ICommandLineOptionsModule
 {
-    const char *desc[] = {
-        "[THISMODULE] reads a run input file ([REF].tpr[ref]),",
-        "a trajectory ([REF].trr[ref]/[REF].xtc[ref]/[TT]/tng[tt]), an energy",
-        "file ([REF].edr[ref]) or a checkpoint file ([REF].cpt[ref])",
-        "and prints that to standard output in a readable format.",
-        "This program is essential for checking your run input file in case of",
-        "problems.[PAR]",
-        "The program can also preprocess a topology to help finding problems.",
-        "Note that currently setting [TT]GMXLIB[tt] is the only way to customize",
-        "directories used for searching include files.",
-    };
-    const char *bugs[] = {
-        "Position restraint output from -sys -s is broken"
-    };
-    t_filenm    fnm[] = {
-        { efTPR, "-s", nullptr, ffOPTRD },
-        { efTRX, "-f", nullptr, ffOPTRD },
-        { efEDR, "-e", nullptr, ffOPTRD },
-        { efCPT, nullptr, nullptr, ffOPTRD },
-        { efTOP, "-p", nullptr, ffOPTRD },
-        { efMTX, "-mtx", "hessian", ffOPTRD },
-        { efMDP, "-om", nullptr, ffOPTWR }
-    };
-#define NFILE asize(fnm)
-
-    gmx_output_env_t *oenv;
-    /* Command line options */
-    gmx_bool          bShowNumbers      = TRUE;
-    gmx_bool          bShowParams       = FALSE;
-    gmx_bool          bSysTop           = FALSE;
-    gmx_bool          bOriginalInputrec = FALSE;
-    t_pargs           pa[]              = {
-        { "-nr", FALSE, etBOOL, {&bShowNumbers}, "Show index numbers in output (leaving them out makes comparison easier, but creates a useless topology)" },
-        { "-param", FALSE, etBOOL, {&bShowParams}, "Show parameters for each bonded interaction (for comparing dumps, it is useful to combine this with -nonr)" },
-        { "-sys", FALSE, etBOOL, {&bSysTop}, "List the atoms and bonded interactions for the whole system instead of for each molecule type" },
-        { "-orgir", FALSE, etBOOL, {&bOriginalInputrec}, "Show input parameters from tpr as they were written by the version that produced the file, instead of how the current version reads them" }
+public:
+    Dump() {}
+
+    // From ICommandLineOptionsModule
+    void init(CommandLineModuleSettings* /*settings*/) override {}
+
+    void initOptions(IOptionsContainer* options, ICommandLineOptionsModuleSettings* settings) override;
+
+    void optionsFinished() override;
+
+    int run() override;
+
+private:
+    //! Commandline options
+    //! \{
+    bool bShowNumbers_      = true;
+    bool bShowParams_       = false;
+    bool bSysTop_           = false;
+    bool bOriginalInputrec_ = false;
+    //! \}
+    //! Commandline file options
+    //! \{
+    std::string inputTprFilename_;
+    std::string inputTrajectoryFilename_;
+    std::string inputEnergyFilename_;
+    std::string inputCheckpointFilename_;
+    std::string inputTopologyFilename_;
+    std::string inputMatrixFilename_;
+    std::string outputMdpFilename_;
+    //! \}
+};
+
+void Dump::initOptions(IOptionsContainer* options, ICommandLineOptionsModuleSettings* settings)
+{
+    const char* desc[] = { "[THISMODULE] reads a run input file ([REF].tpr[ref]),",
+                           "a trajectory ([REF].trr[ref]/[REF].xtc[ref]/[TT]tng[tt]), an energy",
+                           "file ([REF].edr[ref]), a checkpoint file ([REF].cpt[ref])",
+                           "or topology file ([REF].top[ref])",
+                           "and prints that to standard output in a readable format.",
+                           "This program is essential for checking your run input file in case of",
+                           "problems." };
+    settings->setHelpText(desc);
+
+    const char* bugs[] = {
+        "The [REF].mdp[ref] file produced by [TT]-om[tt] can not be read by grompp."
     };
+    settings->setBugText(bugs);
+    // TODO If this ancient note acknowledging a bug is still true,
+    // fix it or block that run path:
+    //   Position restraint output from -sys -s is broken
+
+    options->addOption(FileNameOption("s")
+                               .filetype(OptionFileType::RunInput)
+                               .inputFile()
+                               .store(&inputTprFilename_)
+                               .description("Run input file to dump"));
+    options->addOption(FileNameOption("f")
+                               .filetype(OptionFileType::Trajectory)
+                               .inputFile()
+                               .store(&inputTrajectoryFilename_)
+                               .description("Trajectory file to dump"));
+    options->addOption(FileNameOption("e")
+                               .filetype(OptionFileType::Energy)
+                               .inputFile()
+                               .store(&inputEnergyFilename_)
+                               .description("Energy file to dump"));
+    options->addOption(
+            FileNameOption("cp").legacyType(efCPT).inputFile().store(&inputCheckpointFilename_).description("Checkpoint file to dump"));
+    options->addOption(
+            FileNameOption("p").legacyType(efTOP).inputFile().store(&inputTopologyFilename_).description("Topology file to dump"));
+    options->addOption(
+            FileNameOption("mtx").legacyType(efMTX).inputFile().store(&inputMatrixFilename_).description("Hessian matrix to dump"));
+    options->addOption(FileNameOption("om")
+                               .legacyType(efMDP)
+                               .outputFile()
+                               .store(&outputMdpFilename_)
+                               .description("grompp input file from run input file"));
+
+    options->addOption(
+            BooleanOption("nr").store(&bShowNumbers_).defaultValue(true).description("Show index numbers in output (leaving them out makes comparison easier, but creates a useless topology)"));
+    options->addOption(
+            BooleanOption("param").store(&bShowParams_).defaultValue(false).description("Show parameters for each bonded interaction (for comparing dumps, it is useful to combine this with -nonr)"));
+    options->addOption(
+            BooleanOption("sys").store(&bShowParams_).defaultValue(false).description("List the atoms and bonded interactions for the whole system instead of for each molecule type"));
+    options->addOption(
+            BooleanOption("orgir").store(&bShowParams_).defaultValue(false).description("Show input parameters from tpr as they were written by the version that produced the file, instead of how the current version reads them"));
+}
 
-    if (!parse_common_args(&argc, argv, 0, NFILE, fnm, asize(pa), pa,
-                           asize(desc), desc, asize(bugs), bugs, &oenv))
-    {
-        return 0;
-    }
-
+void Dump::optionsFinished()
+{
+    // TODO Currently gmx dump ignores user input that seeks to dump
+    // multiple files. Here, we could enforce that the user only asks
+    // to dump one file.
+}
 
-    if (ftp2bSet(efTPR, NFILE, fnm))
+int Dump::run()
+{
+    if (!inputTprFilename_.empty())
     {
-        list_tpx(ftp2fn(efTPR, NFILE, fnm), bShowNumbers, bShowParams,
-                 ftp2fn_null(efMDP, NFILE, fnm), bSysTop, bOriginalInputrec);
+        list_tpr(inputTprFilename_.c_str(),
+                 bShowNumbers_,
+                 bShowParams_,
+                 outputMdpFilename_.empty() ? nullptr : outputMdpFilename_.c_str(),
+                 bSysTop_,
+                 bOriginalInputrec_);
     }
-    else if (ftp2bSet(efTRX, NFILE, fnm))
+    else if (!inputTrajectoryFilename_.empty())
     {
-        list_trx(ftp2fn(efTRX, NFILE, fnm));
+        list_trx(inputTrajectoryFilename_.c_str());
     }
-    else if (ftp2bSet(efEDR, NFILE, fnm))
+    else if (!inputEnergyFilename_.empty())
     {
-        list_ene(ftp2fn(efEDR, NFILE, fnm));
+        list_ene(inputEnergyFilename_.c_str());
     }
-    else if (ftp2bSet(efCPT, NFILE, fnm))
+    else if (!inputCheckpointFilename_.empty())
     {
-        list_checkpoint(ftp2fn(efCPT, NFILE, fnm), stdout);
+        list_checkpoint(inputCheckpointFilename_.c_str(), stdout);
     }
-    else if (ftp2bSet(efTOP, NFILE, fnm))
+    else if (!inputTopologyFilename_.empty())
     {
-        list_top(ftp2fn(efTOP, NFILE, fnm));
+        list_top(inputTopologyFilename_.c_str());
     }
-    else if (ftp2bSet(efMTX, NFILE, fnm))
+    else if (!inputMatrixFilename_.empty())
     {
-        list_mtx(ftp2fn(efMTX, NFILE, fnm));
+        list_mtx(inputMatrixFilename_.c_str());
     }
 
     return 0;
 }
+
+} // namespace
+
+const char                       DumpInfo::name[]             = "dump";
+const char                       DumpInfo::shortDescription[] = "Make binary files human readable";
+ICommandLineOptionsModulePointer DumpInfo::create()
+{
+    return std::make_unique<Dump>();
+}
+
+} // namespace gmx