Split off the NMR related analyses from gmx energy.
authorDavid van der Spoel <spoel@xray.bmc.uu.se>
Tue, 23 May 2017 11:20:30 +0000 (13:20 +0200)
committerBerk Hess <hess@kth.se>
Mon, 23 Oct 2017 07:38:15 +0000 (09:38 +0200)
A new tool gmx nmr is created by straight copying code from
gmx energy to a new tool. The reason is to reduce complexity.

A few cleanups are introduced to pass the valgrind memory
test.

Added references the gmx nmr in the manual.

Change-Id: I8e4d1dec8806a0518c571d7a01c4f70de5bbbd35

docs/manual/forcefield.tex
src/gromacs/energyanalysis/tests/legacyenergy.cpp
src/gromacs/gmxana/gmx_ana.h
src/gromacs/gmxana/gmx_energy.cpp
src/gromacs/gmxana/gmx_nmr.cpp [new file with mode: 0644]
src/programs/legacymodules.cpp

index cc63d51d0ad9560a3e0abd7076fd132fac7c7c2d..ea969e8a5190853b7e5d8a388a62cb92f3c1563e 100644 (file)
@@ -1409,6 +1409,8 @@ $r_2$ from ~\eqnref{disre}.  In some cases it can be useful to have
 different force constants for some restraints; this is controlled by
 the column {\tt fac}.  The force constant in the parameter file is
 multiplied by the value in the column {\tt fac} for each restraint.
+Information for each restraint is stored in the energy file and can
+be processed and plotted with {\tt gmx nmr}.
 %} % Brace matches ifthenelse test for gmxlite
 
 \newcommand{\SSS}{{\mathbf S}}
@@ -1647,6 +1649,8 @@ should be the inverse of the square of the unit of the observable.
 Some parameters for orientation restraints can be specified in the
 {\tt grompp.mdp} file, for a study of the effect of different
 force constants and averaging times and ensemble averaging see~\cite{Hess2003}.
+Information for each restraint is stored in the energy file and can
+be processed and plotted with {\tt gmx nmr}.
 %} % Brace matches ifthenelse test for gmxlite
 
 %\ifthenelse{\equal{\gmxlite}{1}}{}{
index d64d70662971d1fab69e895aa5b034b365604809..dc2d6217ce4e84d41f3872b974c158d2fed19df9 100644 (file)
@@ -107,7 +107,7 @@ class OriresTest : public CommandLineTestBase
 
             StdioTestHelper stdioHelper(&fileManager());
             stdioHelper.redirectStringToStdin(stringForStdin);
-            ASSERT_EQ(0, gmx_energy(cmdline.argc(), cmdline.argv()));
+            ASSERT_EQ(0, gmx_nmr(cmdline.argc(), cmdline.argv()));
 
             checkOutputFiles();
         }
@@ -115,7 +115,7 @@ class OriresTest : public CommandLineTestBase
 
 TEST_F(OriresTest, ExtractOrires)
 {
-    runTest("Orient.-Rest.\nOri.-R.-RMSD\n0\n-1\n");
+    runTest("-1\n");
 }
 
 class EnergyTest : public CommandLineTestBase
index 787c935e249d1aeb30e71dd8ae201ebdd7d56423..67efbea450ff7e8ec20e85c0b1cf57e9c219d374 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2008, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2017, 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.
@@ -171,6 +171,9 @@ gmx_nmeig(int argc, char *argv[]);
 int
 gmx_nmens(int argc, char *argv[]);
 
+int
+gmx_nmr(int argc, char *argv[]);
+
 int
 gmx_nmtraj(int argc, char *argv[]);
 
index 7c9f28e0e1577a100f5ea5e479e93950f60aecb0..2a65deea16744c811b102a4aea2dacdc5f33cc16 100644 (file)
@@ -70,7 +70,6 @@
 #include "gromacs/utility/smalloc.h"
 #include "gromacs/utility/strconvert.h"
 
-static real       minthird = -1.0/3.0, minsixth = -1.0/6.0;
 static const int  NOTSET   = -23451;
 
 typedef struct {
@@ -112,91 +111,6 @@ static void done_enerdata_t(int nset, enerdata_t *edat)
     sfree(edat->s);
 }
 
-static double mypow(double x, double y)
-{
-    if (x > 0)
-    {
-        return std::pow(x, y);
-    }
-    else
-    {
-        return 0.0;
-    }
-}
-
-static real blk_value(t_enxblock *blk, int sub, int index)
-{
-    range_check(index, 0, blk->sub[sub].nr);
-    if (blk->sub[sub].type == xdr_datatype_float)
-    {
-        return blk->sub[sub].fval[index];
-    }
-    else if (blk->sub[sub].type == xdr_datatype_double)
-    {
-        return blk->sub[sub].dval[index];
-    }
-    else
-    {
-        gmx_incons("Unknown datatype in t_enxblock");
-    }
-    return 0.0;
-}
-
-static int *select_it(int nre, char *nm[], int *nset)
-{
-    gmx_bool *bE;
-    int       n, k, j, i;
-    int      *set;
-    gmx_bool  bVerbose = TRUE;
-
-    if ((getenv("GMX_ENER_VERBOSE")) != nullptr)
-    {
-        bVerbose = FALSE;
-    }
-
-    fprintf(stderr, "Select the terms you want from the following list\n");
-    fprintf(stderr, "End your selection with 0\n");
-
-    if (bVerbose)
-    {
-        for (k = 0; (k < nre); )
-        {
-            for (j = 0; (j < 4) && (k < nre); j++, k++)
-            {
-                fprintf(stderr, " %3d=%14s", k+1, nm[k]);
-            }
-            fprintf(stderr, "\n");
-        }
-    }
-
-    snew(bE, nre);
-    do
-    {
-        if (1 != scanf("%d", &n))
-        {
-            gmx_fatal(FARGS, "Error reading user input");
-        }
-        if ((n > 0) && (n <= nre))
-        {
-            bE[n-1] = TRUE;
-        }
-    }
-    while (n != 0);
-
-    snew(set, nre);
-    for (i = (*nset) = 0; (i < nre); i++)
-    {
-        if (bE[i])
-        {
-            set[(*nset)++] = i;
-        }
-    }
-
-    sfree(bE);
-
-    return set;
-}
-
 static void chomp(char *buf)
 {
     int len = std::strlen(buf);
@@ -401,214 +315,6 @@ static void get_dhdl_parms(const char *topnm, t_inputrec *ir)
     done_mtop(&mtop);
 }
 
-static void get_orires_parms(const char *topnm, t_inputrec *ir,
-                             int *nor, int *nex, int **label, real **obs)
-{
-    gmx_mtop_t      mtop;
-    t_topology      top;
-    t_iparams      *ip;
-    int             natoms, i;
-    t_iatom        *iatom;
-    int             nb;
-    matrix          box;
-
-    read_tpx(topnm, ir, box, &natoms, nullptr, nullptr, &mtop);
-    top = gmx_mtop_t_to_t_topology(&mtop, FALSE);
-
-    ip       = top.idef.iparams;
-    iatom    = top.idef.il[F_ORIRES].iatoms;
-
-    /* Count how many distance restraint there are... */
-    nb = top.idef.il[F_ORIRES].nr;
-    if (nb == 0)
-    {
-        gmx_fatal(FARGS, "No orientation restraints in topology!\n");
-    }
-
-    *nor = nb/3;
-    *nex = 0;
-    snew(*label, *nor);
-    snew(*obs, *nor);
-    for (i = 0; i < nb; i += 3)
-    {
-        (*label)[i/3] = ip[iatom[i]].orires.label;
-        (*obs)[i/3]   = ip[iatom[i]].orires.obs;
-        if (ip[iatom[i]].orires.ex >= *nex)
-        {
-            *nex = ip[iatom[i]].orires.ex+1;
-        }
-    }
-    fprintf(stderr, "Found %d orientation restraints with %d experiments",
-            *nor, *nex);
-    done_top_mtop(&top, &mtop);
-}
-
-static int get_bounds(const char *topnm,
-                      real **bounds, int **index, int **dr_pair, int *npairs,
-                      gmx_mtop_t *mtop, gmx_localtop_t **ltop, t_inputrec *ir)
-{
-    gmx_localtop_t *top;
-    t_functype     *functype;
-    t_iparams      *ip;
-    int             natoms, i, j, k, type, ftype, natom;
-    t_ilist        *disres;
-    t_iatom        *iatom;
-    real           *b;
-    int            *ind, *pair;
-    int             nb, label1;
-    matrix          box;
-
-    read_tpx(topnm, ir, box, &natoms, nullptr, nullptr, mtop);
-    snew(*ltop, 1);
-    top   = gmx_mtop_generate_local_top(mtop, ir->efep != efepNO);
-    *ltop = top;
-
-    functype = top->idef.functype;
-    ip       = top->idef.iparams;
-
-    /* Count how many distance restraint there are... */
-    nb = top->idef.il[F_DISRES].nr;
-    if (nb == 0)
-    {
-        gmx_fatal(FARGS, "No distance restraints in topology!\n");
-    }
-
-    /* Allocate memory */
-    snew(b, nb);
-    snew(ind, nb);
-    snew(pair, nb+1);
-
-    /* Fill the bound array */
-    nb = 0;
-    for (i = 0; (i < top->idef.ntypes); i++)
-    {
-        ftype = functype[i];
-        if (ftype == F_DISRES)
-        {
-
-            label1  = ip[i].disres.label;
-            b[nb]   = ip[i].disres.up1;
-            ind[nb] = label1;
-            nb++;
-        }
-    }
-    *bounds = b;
-
-    /* Fill the index array */
-    label1  = -1;
-    disres  = &(top->idef.il[F_DISRES]);
-    iatom   = disres->iatoms;
-    for (i = j = k = 0; (i < disres->nr); )
-    {
-        type  = iatom[i];
-        ftype = top->idef.functype[type];
-        natom = interaction_function[ftype].nratoms+1;
-        if (label1 != top->idef.iparams[type].disres.label)
-        {
-            pair[j] = k;
-            label1  = top->idef.iparams[type].disres.label;
-            j++;
-        }
-        k++;
-        i += natom;
-    }
-    pair[j]  = k;
-    *npairs  = k;
-    if (j != nb)
-    {
-        gmx_incons("get_bounds for distance restraints");
-    }
-
-    *index   = ind;
-    *dr_pair = pair;
-
-    return nb;
-}
-
-static void calc_violations(real rt[], real rav3[], int nb, int index[],
-                            real bounds[], real *viol, double *st, double *sa)
-{
-    const   real sixth = 1.0/6.0;
-    int          i, j;
-    double       rsum, rav, sumaver, sumt;
-
-    sumaver = 0;
-    sumt    = 0;
-    for (i = 0; (i < nb); i++)
-    {
-        rsum = 0.0;
-        rav  = 0.0;
-        for (j = index[i]; (j < index[i+1]); j++)
-        {
-            if (viol)
-            {
-                viol[j] += mypow(rt[j], -3.0);
-            }
-            rav     += gmx::square(rav3[j]);
-            rsum    += mypow(rt[j], -6);
-        }
-        rsum    = std::max(0.0, mypow(rsum, -sixth)-bounds[i]);
-        rav     = std::max(0.0, mypow(rav, -sixth)-bounds[i]);
-
-        sumt    += rsum;
-        sumaver += rav;
-    }
-    *st = sumt;
-    *sa = sumaver;
-}
-
-static void analyse_disre(const char *voutfn,    int nframes,
-                          real violaver[], real bounds[], int index[],
-                          int pair[],      int nbounds,
-                          const gmx_output_env_t *oenv)
-{
-    FILE   *vout;
-    double  sum, sumt, sumaver;
-    int     i, j;
-
-    /* Subtract bounds from distances, to calculate violations */
-    calc_violations(violaver, violaver,
-                    nbounds, pair, bounds, nullptr, &sumt, &sumaver);
-
-#ifdef DEBUG
-    fprintf(stdout, "\nSum of violations averaged over simulation: %g nm\n",
-            sumaver);
-    fprintf(stdout, "Largest violation averaged over simulation: %g nm\n\n",
-            sumt);
-#endif
-    vout = xvgropen(voutfn, "r\\S-3\\N average violations", "DR Index", "nm",
-                    oenv);
-    sum  = 0.0;
-    sumt = 0.0;
-    for (i = 0; (i < nbounds); i++)
-    {
-        /* Do ensemble averaging */
-        sumaver = 0;
-        for (j = pair[i]; (j < pair[i+1]); j++)
-        {
-            sumaver += gmx::square(violaver[j]/nframes);
-        }
-        sumaver = std::max(0.0, mypow(sumaver, minsixth)-bounds[i]);
-
-        sumt   += sumaver;
-        sum     = std::max(sum, sumaver);
-        fprintf(vout, "%10d  %10.5e\n", index[i], sumaver);
-    }
-#ifdef DEBUG
-    for (j = 0; (j < dr.ndr); j++)
-    {
-        fprintf(vout, "%10d  %10.5e\n", j, mypow(violaver[j]/nframes, minthird));
-    }
-#endif
-    xvgrclose(vout);
-
-    fprintf(stdout, "\nSum of violations averaged over simulation: %g nm\n",
-            sumt);
-    fprintf(stdout, "Largest violation averaged over simulation: %g nm\n\n", sum);
-
-    do_view(oenv, voutfn, "-graphtype bar");
-}
-
 static void einstein_visco(const char *fn, const char *fni, int nsets,
                            int nint, real **eneint,
                            real V, real T, double dt,
@@ -1875,8 +1581,8 @@ static void do_dhdl(t_enxframe *fr, const t_inputrec *ir, FILE **fp_dhdl,
 int gmx_energy(int argc, char *argv[])
 {
     const char        *desc[] = {
-        "[THISMODULE] extracts energy components or distance restraint",
-        "data from an energy file. The user is prompted to interactively",
+        "[THISMODULE] extracts energy components",
+        "from an energy file. The user is prompted to interactively",
         "select the desired energy terms.[PAR]",
 
         "Average, RMSD, and drift are calculated with full precision from the",
@@ -1914,29 +1620,6 @@ int gmx_energy(int argc, char *argv[])
         "You always need to set the number of molecules [TT]-nmol[tt].",
         "The C[SUB]p[sub]/C[SUB]v[sub] computations do [BB]not[bb] include any corrections",
         "for quantum effects. Use the [gmx-dos] program if you need that (and you do).[PAR]"
-        "When the [TT]-viol[tt] option is set, the time averaged",
-        "violations are plotted and the running time-averaged and",
-        "instantaneous sum of violations are recalculated. Additionally",
-        "running time-averaged and instantaneous distances between",
-        "selected pairs can be plotted with the [TT]-pairs[tt] option.[PAR]",
-
-        "Options [TT]-ora[tt], [TT]-ort[tt], [TT]-oda[tt], [TT]-odr[tt] and",
-        "[TT]-odt[tt] are used for analyzing orientation restraint data.",
-        "The first two options plot the orientation, the last three the",
-        "deviations of the orientations from the experimental values.",
-        "The options that end on an 'a' plot the average over time",
-        "as a function of restraint. The options that end on a 't'",
-        "prompt the user for restraint label numbers and plot the data",
-        "as a function of time. Option [TT]-odr[tt] plots the RMS",
-        "deviation as a function of restraint.",
-        "When the run used time or ensemble averaged orientation restraints,",
-        "option [TT]-orinst[tt] can be used to analyse the instantaneous,",
-        "not ensemble-averaged orientations and deviations instead of",
-        "the time and ensemble averages.[PAR]",
-
-        "Option [TT]-oten[tt] plots the eigenvalues of the molecular order",
-        "tensor for each orientation restraint experiment. With option",
-        "[TT]-ovec[tt] also the eigenvectors are plotted.[PAR]",
 
         "Option [TT]-odh[tt] extracts and plots the free energy data",
         "(Hamiltoian differences and/or the Hamiltonian derivative dhdl)",
@@ -2008,50 +1691,34 @@ int gmx_energy(int argc, char *argv[])
         { "-ovec", FALSE, etBOOL, {&bOvec},
           "Also plot the eigenvectors with [TT]-oten[tt]" }
     };
-    const char       * drleg[] = {
-        "Running average",
-        "Instantaneous"
-    };
     static const char *setnm[] = {
         "Pres-XX", "Pres-XY", "Pres-XZ", "Pres-YX", "Pres-YY",
         "Pres-YZ", "Pres-ZX", "Pres-ZY", "Pres-ZZ", "Temperature",
         "Volume",  "Pressure"
     };
 
-    FILE              *out     = nullptr, *fp_pairs = nullptr, *fort = nullptr, *fodt = nullptr, *foten = nullptr;
+    FILE              *out     = nullptr;
     FILE              *fp_dhdl = nullptr;
     ener_file_t        fp;
     int                timecheck = 0;
-    gmx_mtop_t         mtop;
-    gmx_localtop_t    *top = nullptr;
     enerdata_t         edat;
     gmx_enxnm_t       *enm = nullptr;
     t_enxframe        *frame, *fr = nullptr;
     int                cur = 0;
 #define NEXT (1-cur)
-    int                nre, teller, teller_disre, nfr;
+    int                nre, teller, nfr;
     gmx_int64_t        start_step;
-    int                nor = 0, nex = 0, norfr = 0, enx_i = 0;
     real               start_t;
-    real              *bounds  = nullptr, *violaver = nullptr, *oobs = nullptr, *orient = nullptr, *odrms = nullptr;
-    int               *index   = nullptr, *pair = nullptr, norsel = 0, *orsel = nullptr, *or_label = nullptr;
-    int                nbounds = 0, npairs;
-    gmx_bool           bDisRe, bDRAll, bORA, bORT, bODA, bODR, bODT, bORIRE, bOTEN, bDHDL;
+    gmx_bool           bDHDL;
     gmx_bool           bFoundStart, bCont, bVisco;
-    double             sum, sumaver, sumt, dbl;
+    double             sum, dbl;
     double            *time = nullptr;
     real               Vaver;
-    int               *set     = nullptr, i, j, k, nset, sss;
+    int               *set     = nullptr, i, j, nset, sss;
     gmx_bool          *bIsEner = nullptr;
-    char             **pairleg, **odtleg, **otenleg;
-    char             **leg = nullptr;
-    const char        *anm_j, *anm_k, *resnm_j, *resnm_k;
-    int                resnr_j, resnr_k;
-    const char        *orinst_sub = "@ subtitle \"instantaneous\"\n";
+    char             **leg     = nullptr;
     char               buf[256];
     gmx_output_env_t  *oenv;
-    t_enxblock        *blk_disre = nullptr;
-    int                ndisre    = 0;
     int                dh_blocks = 0, dh_hists = 0, dh_samples = 0, dh_lambdas = 0;
 
     t_filenm           fnm[] = {
@@ -2061,12 +1728,6 @@ int gmx_energy(int argc, char *argv[])
         { efXVG, "-o",    "energy",  ffWRITE },
         { efXVG, "-viol", "violaver", ffOPTWR },
         { efXVG, "-pairs", "pairs",   ffOPTWR },
-        { efXVG, "-ora",  "orienta", ffOPTWR },
-        { efXVG, "-ort",  "orientt", ffOPTWR },
-        { efXVG, "-oda",  "orideva", ffOPTWR },
-        { efXVG, "-odr",  "oridevr", ffOPTWR },
-        { efXVG, "-odt",  "oridevt", ffOPTWR },
-        { efXVG, "-oten", "oriten",  ffOPTWR },
         { efXVG, "-corr", "enecorr", ffOPTWR },
         { efXVG, "-vis",  "visco",   ffOPTWR },
         { efXVG, "-evisco",  "evisco",  ffOPTWR },
@@ -2088,15 +1749,6 @@ int gmx_energy(int argc, char *argv[])
         return 0;
     }
 
-    bDRAll = opt2bSet("-pairs", NFILE, fnm);
-    bDisRe = opt2bSet("-viol", NFILE, fnm) || bDRAll;
-    bORA   = opt2bSet("-ora", NFILE, fnm);
-    bORT   = opt2bSet("-ort", NFILE, fnm);
-    bODA   = opt2bSet("-oda", NFILE, fnm);
-    bODR   = opt2bSet("-odr", NFILE, fnm);
-    bODT   = opt2bSet("-odt", NFILE, fnm);
-    bORIRE = bORA || bORT || bODA || bODR || bODT;
-    bOTEN  = opt2bSet("-oten", NFILE, fnm);
     bDHDL  = opt2bSet("-odh", NFILE, fnm);
 
     nset = 0;
@@ -2112,7 +1764,7 @@ int gmx_energy(int argc, char *argv[])
     t_inputrec  irInstance;
     t_inputrec *ir = &irInstance;
 
-    if ((!bDisRe) && (!bDHDL))
+    if (!bDHDL)
     {
         if (bVisco)
         {
@@ -2203,162 +1855,6 @@ int gmx_energy(int argc, char *argv[])
             gmx_fatal(FARGS, "Printing averages can only be done when a single set is selected");
         }
 
-        time = nullptr;
-
-        if (bORIRE || bOTEN)
-        {
-            get_orires_parms(ftp2fn(efTPR, NFILE, fnm), ir,
-                             &nor, &nex, &or_label, &oobs);
-        }
-
-        if (bORIRE)
-        {
-            if (bOrinst)
-            {
-                enx_i = enxORI;
-            }
-            else
-            {
-                enx_i = enxOR;
-            }
-
-            if (bORA || bODA)
-            {
-                snew(orient, nor);
-            }
-            if (bODR)
-            {
-                snew(odrms, nor);
-            }
-            if (bORT || bODT)
-            {
-                fprintf(stderr, "Select the orientation restraint labels you want (-1 is all)\n");
-                fprintf(stderr, "End your selection with 0\n");
-                j     = -1;
-                orsel = nullptr;
-                do
-                {
-                    j++;
-                    srenew(orsel, j+1);
-                    if (1 != scanf("%d", &(orsel[j])))
-                    {
-                        gmx_fatal(FARGS, "Error reading user input");
-                    }
-                }
-                while (orsel[j] > 0);
-                if (orsel[0] == -1)
-                {
-                    fprintf(stderr, "Selecting all %d orientation restraints\n", nor);
-                    norsel = nor;
-                    srenew(orsel, nor);
-                    for (i = 0; i < nor; i++)
-                    {
-                        orsel[i] = i;
-                    }
-                }
-                else
-                {
-                    /* Build the selection */
-                    norsel = 0;
-                    for (i = 0; i < j; i++)
-                    {
-                        for (k = 0; k < nor; k++)
-                        {
-                            if (or_label[k] == orsel[i])
-                            {
-                                orsel[norsel] = k;
-                                norsel++;
-                                break;
-                            }
-                        }
-                        if (k == nor)
-                        {
-                            fprintf(stderr, "Orientation restraint label %d not found\n",
-                                    orsel[i]);
-                        }
-                    }
-                }
-                snew(odtleg, norsel);
-                for (i = 0; i < norsel; i++)
-                {
-                    snew(odtleg[i], 256);
-                    sprintf(odtleg[i], "%d", or_label[orsel[i]]);
-                }
-                if (bORT)
-                {
-                    fort = xvgropen(opt2fn("-ort", NFILE, fnm), "Calculated orientations",
-                                    "Time (ps)", "", oenv);
-                    if (bOrinst && output_env_get_print_xvgr_codes(oenv))
-                    {
-                        fprintf(fort, "%s", orinst_sub);
-                    }
-                    xvgr_legend(fort, norsel, (const char**)odtleg, oenv);
-                }
-                if (bODT)
-                {
-                    fodt = xvgropen(opt2fn("-odt", NFILE, fnm),
-                                    "Orientation restraint deviation",
-                                    "Time (ps)", "", oenv);
-                    if (bOrinst && output_env_get_print_xvgr_codes(oenv))
-                    {
-                        fprintf(fodt, "%s", orinst_sub);
-                    }
-                    xvgr_legend(fodt, norsel, (const char**)odtleg, oenv);
-                }
-                for (i = 0; i < norsel; i++)
-                {
-                    sfree(odtleg[i]);
-                }
-                sfree(odtleg);
-            }
-        }
-        if (bOTEN)
-        {
-            foten = xvgropen(opt2fn("-oten", NFILE, fnm),
-                             "Order tensor", "Time (ps)", "", oenv);
-            snew(otenleg, bOvec ? nex*12 : nex*3);
-            for (i = 0; i < nex; i++)
-            {
-                for (j = 0; j < 3; j++)
-                {
-                    sprintf(buf, "eig%d", j+1);
-                    otenleg[(bOvec ? 12 : 3)*i+j] = gmx_strdup(buf);
-                }
-                if (bOvec)
-                {
-                    for (j = 0; j < 9; j++)
-                    {
-                        sprintf(buf, "vec%d%s", j/3+1, j%3 == 0 ? "x" : (j%3 == 1 ? "y" : "z"));
-                        otenleg[12*i+3+j] = gmx_strdup(buf);
-                    }
-                }
-            }
-            xvgr_legend(foten, bOvec ? nex*12 : nex*3, (const char**)otenleg, oenv);
-            for (j = 0; j < 3; j++)
-            {
-                sfree(otenleg[j]);
-            }
-            sfree(otenleg);
-        }
-    }
-    else if (bDisRe)
-    {
-        nbounds = get_bounds(ftp2fn(efTPR, NFILE, fnm), &bounds, &index, &pair, &npairs,
-                             &mtop, &top, ir);
-        snew(violaver, npairs);
-        out = xvgropen(opt2fn("-o", NFILE, fnm), "Sum of Violations",
-                       "Time (ps)", "nm", oenv);
-        xvgr_legend(out, 2, drleg, oenv);
-        if (bDRAll)
-        {
-            fp_pairs = xvgropen(opt2fn("-pairs", NFILE, fnm), "Pair Distances",
-                                "Time (ps)", "Distance (nm)", oenv);
-            if (output_env_get_print_xvgr_codes(oenv))
-            {
-                fprintf(fp_pairs, "@ subtitle \"averaged (tau=%g) and instantaneous\"\n",
-                        ir->dr_tau);
-            }
-        }
     }
     else if (bDHDL)
     {
@@ -2377,7 +1873,6 @@ int gmx_energy(int argc, char *argv[])
 
     /* Initiate counters */
     teller       = 0;
-    teller_disre = 0;
     bFoundStart  = FALSE;
     start_step   = 0;
     start_t      = 0;
@@ -2493,59 +1988,10 @@ int gmx_energy(int argc, char *argv[])
                     edat.s[i].ener[nfr] = fr->ener[set[i]].e;
                 }
             }
-            /*
-             * Define distance restraint legends. Can only be done after
-             * the first frame has been read... (Then we know how many there are)
-             */
-            blk_disre = find_block_id_enxframe(fr, enxDISRE, nullptr);
-            if (bDisRe && bDRAll && !leg && blk_disre)
-            {
-                t_iatom   *fa;
-                t_iparams *ip;
-
-                fa = top->idef.il[F_DISRES].iatoms;
-                ip = top->idef.iparams;
-                if (blk_disre->nsub != 2 ||
-                    (blk_disre->sub[0].nr != blk_disre->sub[1].nr) )
-                {
-                    gmx_incons("Number of disre sub-blocks not equal to 2");
-                }
-
-                ndisre = blk_disre->sub[0].nr;
-                if (ndisre != top->idef.il[F_DISRES].nr/3)
-                {
-                    gmx_fatal(FARGS, "Number of disre pairs in the energy file (%d) does not match the number in the run input file (%d)\n",
-                              ndisre, top->idef.il[F_DISRES].nr/3);
-                }
-                snew(pairleg, ndisre);
-                int molb = 0;
-                for (i = 0; i < ndisre; i++)
-                {
-                    snew(pairleg[i], 30);
-                    j = fa[3*i+1];
-                    k = fa[3*i+2];
-                    mtopGetAtomAndResidueName(&mtop, j, &molb, &anm_j, &resnr_j, &resnm_j, nullptr);
-                    mtopGetAtomAndResidueName(&mtop, k, &molb, &anm_k, &resnr_k, &resnm_k, nullptr);
-                    sprintf(pairleg[i], "%d %s %d %s (%d)",
-                            resnr_j, anm_j, resnr_k, anm_k,
-                            ip[fa[3*i]].disres.label);
-                }
-                set = select_it(ndisre, pairleg, &nset);
-                snew(leg, 2*nset);
-                for (i = 0; (i < nset); i++)
-                {
-                    snew(leg[2*i], 32);
-                    sprintf(leg[2*i],  "a %s", pairleg[set[i]]);
-                    snew(leg[2*i+1], 32);
-                    sprintf(leg[2*i+1], "i %s", pairleg[set[i]]);
-                }
-                xvgr_legend(fp_pairs, 2*nset, (const char**)leg, oenv);
-            }
-
             /*
              * Store energies for analysis afterwards...
              */
-            if (!bDisRe && !bDHDL && (fr->nre > 0))
+            if (!bDHDL && (fr->nre > 0))
             {
                 if (edat.nframes % 1000 == 0)
                 {
@@ -2559,48 +2005,7 @@ int gmx_energy(int argc, char *argv[])
              */
             if (!skip || teller % skip == 0)
             {
-                if (bDisRe)
-                {
-                    /*******************************************
-                     * D I S T A N C E   R E S T R A I N T S
-                     *******************************************/
-                    if (ndisre > 0)
-                    {
-                        GMX_RELEASE_ASSERT(blk_disre != nullptr, "Trying to dereference NULL blk_disre pointer");
- #if !GMX_DOUBLE
-                        float  *disre_rt     =     blk_disre->sub[0].fval;
-                        float  *disre_rm3tav = blk_disre->sub[1].fval;
- #else
-                        double *disre_rt     =     blk_disre->sub[0].dval;
-                        double *disre_rm3tav = blk_disre->sub[1].dval;
- #endif
-
-                        print_time(out, fr->t);
-                        if (violaver == nullptr)
-                        {
-                            snew(violaver, ndisre);
-                        }
-
-                        /* Subtract bounds from distances, to calculate violations */
-                        calc_violations(disre_rt, disre_rm3tav,
-                                        nbounds, pair, bounds, violaver, &sumt, &sumaver);
-
-                        fprintf(out, "  %8.4f  %8.4f\n", sumaver, sumt);
-                        if (bDRAll)
-                        {
-                            print_time(fp_pairs, fr->t);
-                            for (i = 0; (i < nset); i++)
-                            {
-                                sss = set[i];
-                                fprintf(fp_pairs, "  %8.4f", mypow(disre_rm3tav[sss], minthird));
-                                fprintf(fp_pairs, "  %8.4f", disre_rt[sss]);
-                            }
-                            fprintf(fp_pairs, "\n");
-                        }
-                        teller_disre++;
-                    }
-                }
-                else if (bDHDL)
+                if (bDHDL)
                 {
                     do_dhdl(fr, ir, &fp_dhdl, opt2fn("-odh", NFILE, fnm), bDp, &dh_blocks, &dh_hists, &dh_samples, &dh_lambdas, oenv);
                 }
@@ -2655,76 +2060,6 @@ int gmx_energy(int argc, char *argv[])
                             fprintf(out, "\n");
                         }
                     }
-                    t_enxblock *blk = find_block_id_enxframe(fr, enx_i, nullptr);
-                    if (bORIRE && blk)
-                    {
-                        if (blk->nsub != 1)
-                        {
-                            gmx_fatal(FARGS, "Orientational restraints read in incorrectly.");
-                        }
-
-                        if (blk->sub[0].nr != nor)
-                        {
-                            gmx_fatal(FARGS, "Number of orientation restraints in energy file (%d) does not match with the topology (%d)", blk->sub[0].nr);
-                        }
-                        if (bORA || bODA)
-                        {
-                            for (i = 0; i < nor; i++)
-                            {
-                                orient[i] += blk_value(blk, 0, i);
-                            }
-                        }
-                        if (bODR)
-                        {
-                            for (i = 0; i < nor; i++)
-                            {
-                                real v = blk_value(blk, 0, i);
-                                odrms[i] += gmx::square(v - oobs[i]);
-                            }
-                        }
-                        if (bORT)
-                        {
-                            fprintf(fort, "  %10f", fr->t);
-                            for (i = 0; i < norsel; i++)
-                            {
-                                fprintf(fort, " %g", blk_value(blk, 0, orsel[i]));
-                            }
-                            fprintf(fort, "\n");
-                        }
-                        if (bODT)
-                        {
-                            fprintf(fodt, "  %10f", fr->t);
-                            for (i = 0; i < norsel; i++)
-                            {
-                                fprintf(fodt, " %g", blk_value(blk, 0, orsel[i])-oobs[orsel[i]]);
-                            }
-                            fprintf(fodt, "\n");
-                        }
-                        norfr++;
-                    }
-                    blk = find_block_id_enxframe(fr, enxORT, nullptr);
-                    if (bOTEN && blk)
-                    {
-                        if (blk->nsub != 1)
-                        {
-                            gmx_fatal(FARGS, "Orientational restraints read in incorrectly");
-                        }
-
-                        if (blk->sub[0].nr != nex*12)
-                        {
-                            gmx_fatal(FARGS, "Number of orientation experiments in energy file (%g) does not match with the topology (%d)",
-                                      blk->sub[0].nr/12, nex);
-                        }
-                        fprintf(foten, "  %10f", fr->t);
-                        for (i = 0; i < nex; i++)
-                        {
-                            for (j = 0; j < (bOvec ? 12 : 3); j++)
-                            {
-                                fprintf(foten, " %g", blk_value(blk, 0, i*12+j));
-                            }
-                        }
-                        fprintf(foten, "\n");
-                    }
                 }
             }
             teller++;
@@ -2739,81 +2074,7 @@ int gmx_energy(int argc, char *argv[])
         xvgrclose(out);
     }
 
-    if (bDRAll)
-    {
-        xvgrclose(fp_pairs);
-    }
-
-    if (bORT)
-    {
-        xvgrclose(fort);
-    }
-    if (bODT)
-    {
-        xvgrclose(fodt);
-    }
-    if (bORA)
-    {
-        out = xvgropen(opt2fn("-ora", NFILE, fnm),
-                       "Average calculated orientations",
-                       "Restraint label", "", oenv);
-        if (bOrinst && output_env_get_print_xvgr_codes(oenv))
-        {
-            fprintf(out, "%s", orinst_sub);
-        }
-        for (i = 0; i < nor; i++)
-        {
-            fprintf(out, "%5d  %g\n", or_label[i], orient[i]/norfr);
-        }
-        xvgrclose(out);
-    }
-    if (bODA)
-    {
-        out = xvgropen(opt2fn("-oda", NFILE, fnm),
-                       "Average restraint deviation",
-                       "Restraint label", "", oenv);
-        if (bOrinst && output_env_get_print_xvgr_codes(oenv))
-        {
-            fprintf(out, "%s", orinst_sub);
-        }
-        for (i = 0; i < nor; i++)
-        {
-            fprintf(out, "%5d  %g\n", or_label[i], orient[i]/norfr-oobs[i]);
-        }
-        xvgrclose(out);
-    }
-    if (bODR)
-    {
-        out = xvgropen(opt2fn("-odr", NFILE, fnm),
-                       "RMS orientation restraint deviations",
-                       "Restraint label", "", oenv);
-        if (bOrinst && output_env_get_print_xvgr_codes(oenv))
-        {
-            fprintf(out, "%s", orinst_sub);
-        }
-        for (i = 0; i < nor; i++)
-        {
-            fprintf(out, "%5d  %g\n", or_label[i], std::sqrt(odrms[i]/norfr));
-        }
-        xvgrclose(out);
-    }
-    // Clean up orires variables.
-    sfree(or_label);
-    sfree(oobs);
-    sfree(orient);
-    sfree(odrms);
-    sfree(orsel);
-    if (bOTEN)
-    {
-        xvgrclose(foten);
-    }
-
-    if (bDisRe)
-    {
-        analyse_disre(opt2fn("-viol", NFILE, fnm),
-                      teller_disre, violaver, bounds, index, pair, nbounds, oenv);
-    }
-    else if (bDHDL)
+    if (bDHDL)
     {
         if (fp_dhdl)
         {
@@ -2876,12 +2137,6 @@ int gmx_energy(int argc, char *argv[])
 
         do_view(oenv, opt2fn("-o", NFILE, fnm), nxy);
         do_view(oenv, opt2fn_null("-ravg", NFILE, fnm), nxy);
-        do_view(oenv, opt2fn_null("-ora", NFILE, fnm), nxy);
-        do_view(oenv, opt2fn_null("-ort", NFILE, fnm), nxy);
-        do_view(oenv, opt2fn_null("-oda", NFILE, fnm), nxy);
-        do_view(oenv, opt2fn_null("-odr", NFILE, fnm), nxy);
-        do_view(oenv, opt2fn_null("-odt", NFILE, fnm), nxy);
-        do_view(oenv, opt2fn_null("-oten", NFILE, fnm), nxy);
         do_view(oenv, opt2fn_null("-odh", NFILE, fnm), nxy);
     }
     output_env_done(oenv);
diff --git a/src/gromacs/gmxana/gmx_nmr.cpp b/src/gromacs/gmxana/gmx_nmr.cpp
new file mode 100644 (file)
index 0000000..a33c01a
--- /dev/null
@@ -0,0 +1,953 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2004, The GROMACS development team.
+ * Copyright (c) 2013,2014,2015,2016,2017, 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * 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.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+#include "gmxpre.h"
+
+#include <cmath>
+#include <cstdlib>
+#include <cstring>
+
+#include <algorithm>
+
+#include "gromacs/commandline/pargs.h"
+#include "gromacs/commandline/viewit.h"
+#include "gromacs/correlationfunctions/autocorr.h"
+#include "gromacs/fileio/enxio.h"
+#include "gromacs/fileio/gmxfio.h"
+#include "gromacs/fileio/tpxio.h"
+#include "gromacs/fileio/trxio.h"
+#include "gromacs/fileio/xvgr.h"
+#include "gromacs/gmxana/gmx_ana.h"
+#include "gromacs/gmxana/gstat.h"
+#include "gromacs/math/functions.h"
+#include "gromacs/math/units.h"
+#include "gromacs/math/vec.h"
+#include "gromacs/mdlib/mdebin.h"
+#include "gromacs/mdtypes/inputrec.h"
+#include "gromacs/mdtypes/md_enums.h"
+#include "gromacs/topology/ifunc.h"
+#include "gromacs/topology/mtop_lookup.h"
+#include "gromacs/topology/mtop_util.h"
+#include "gromacs/topology/topology.h"
+#include "gromacs/utility/arraysize.h"
+#include "gromacs/utility/cstringutil.h"
+#include "gromacs/utility/fatalerror.h"
+#include "gromacs/utility/gmxassert.h"
+#include "gromacs/utility/pleasecite.h"
+#include "gromacs/utility/smalloc.h"
+#include "gromacs/utility/strconvert.h"
+
+static real       minthird = -1.0/3.0, minsixth = -1.0/6.0;
+
+static double mypow(double x, double y)
+{
+    if (x > 0)
+    {
+        return std::pow(x, y);
+    }
+    else
+    {
+        return 0.0;
+    }
+}
+
+static real blk_value(t_enxblock *blk, int sub, int index)
+{
+    range_check(index, 0, blk->sub[sub].nr);
+    if (blk->sub[sub].type == xdr_datatype_float)
+    {
+        return blk->sub[sub].fval[index];
+    }
+    else if (blk->sub[sub].type == xdr_datatype_double)
+    {
+        return blk->sub[sub].dval[index];
+    }
+    else
+    {
+        gmx_incons("Unknown datatype in t_enxblock");
+    }
+    return 0.0;
+}
+
+static int *select_it(int nre, char *nm[], int *nset)
+{
+    gmx_bool *bE;
+    int       n, k, j, i;
+    int      *set;
+    gmx_bool  bVerbose = TRUE;
+
+    if ((getenv("GMX_ENER_VERBOSE")) != nullptr)
+    {
+        bVerbose = FALSE;
+    }
+
+    fprintf(stderr, "Select the terms you want from the following list\n");
+    fprintf(stderr, "End your selection with 0\n");
+
+    if (bVerbose)
+    {
+        for (k = 0; (k < nre); )
+        {
+            for (j = 0; (j < 4) && (k < nre); j++, k++)
+            {
+                fprintf(stderr, " %3d=%14s", k+1, nm[k]);
+            }
+            fprintf(stderr, "\n");
+        }
+    }
+
+    snew(bE, nre);
+    do
+    {
+        if (1 != scanf("%d", &n))
+        {
+            gmx_fatal(FARGS, "Error reading user input");
+        }
+        if ((n > 0) && (n <= nre))
+        {
+            bE[n-1] = TRUE;
+        }
+    }
+    while (n != 0);
+
+    snew(set, nre);
+    for (i = (*nset) = 0; (i < nre); i++)
+    {
+        if (bE[i])
+        {
+            set[(*nset)++] = i;
+        }
+    }
+
+    sfree(bE);
+
+    return set;
+}
+
+static void get_orires_parms(const char *topnm, t_inputrec *ir,
+                             int *nor, int *nex, int **label, real **obs)
+{
+    gmx_mtop_t      mtop;
+    t_topology      top;
+    t_iparams      *ip;
+    int             natoms, i;
+    t_iatom        *iatom;
+    int             nb;
+    matrix          box;
+
+    read_tpx(topnm, ir, box, &natoms, nullptr, nullptr, &mtop);
+    top = gmx_mtop_t_to_t_topology(&mtop, FALSE);
+
+    ip       = top.idef.iparams;
+    iatom    = top.idef.il[F_ORIRES].iatoms;
+
+    /* Count how many distance restraint there are... */
+    nb = top.idef.il[F_ORIRES].nr;
+    if (nb == 0)
+    {
+        gmx_fatal(FARGS, "No orientation restraints in topology!\n");
+    }
+
+    *nor = nb/3;
+    *nex = 0;
+    snew(*label, *nor);
+    snew(*obs, *nor);
+    for (i = 0; i < nb; i += 3)
+    {
+        (*label)[i/3] = ip[iatom[i]].orires.label;
+        (*obs)[i/3]   = ip[iatom[i]].orires.obs;
+        if (ip[iatom[i]].orires.ex >= *nex)
+        {
+            *nex = ip[iatom[i]].orires.ex+1;
+        }
+    }
+    fprintf(stderr, "Found %d orientation restraints with %d experiments",
+            *nor, *nex);
+    done_top_mtop(&top, &mtop);
+}
+
+static int get_bounds(const char *topnm,
+                      real **bounds, int **index, int **dr_pair, int *npairs,
+                      gmx_mtop_t *mtop, gmx_localtop_t **ltop, t_inputrec *ir)
+{
+    gmx_localtop_t *top;
+    t_functype     *functype;
+    t_iparams      *ip;
+    int             natoms, i, j, k, type, ftype, natom;
+    t_ilist        *disres;
+    t_iatom        *iatom;
+    real           *b;
+    int            *ind, *pair;
+    int             nb, label1;
+    matrix          box;
+
+    read_tpx(topnm, ir, box, &natoms, nullptr, nullptr, mtop);
+    snew(*ltop, 1);
+    top   = gmx_mtop_generate_local_top(mtop, ir->efep != efepNO);
+    *ltop = top;
+
+    functype = top->idef.functype;
+    ip       = top->idef.iparams;
+
+    /* Count how many distance restraint there are... */
+    nb = top->idef.il[F_DISRES].nr;
+    if (nb == 0)
+    {
+        gmx_fatal(FARGS, "No distance restraints in topology!\n");
+    }
+
+    /* Allocate memory */
+    snew(b, nb);
+    snew(ind, nb);
+    snew(pair, nb+1);
+
+    /* Fill the bound array */
+    nb = 0;
+    for (i = 0; (i < top->idef.ntypes); i++)
+    {
+        ftype = functype[i];
+        if (ftype == F_DISRES)
+        {
+
+            label1  = ip[i].disres.label;
+            b[nb]   = ip[i].disres.up1;
+            ind[nb] = label1;
+            nb++;
+        }
+    }
+    *bounds = b;
+
+    /* Fill the index array */
+    label1  = -1;
+    disres  = &(top->idef.il[F_DISRES]);
+    iatom   = disres->iatoms;
+    for (i = j = k = 0; (i < disres->nr); )
+    {
+        type  = iatom[i];
+        ftype = top->idef.functype[type];
+        natom = interaction_function[ftype].nratoms+1;
+        if (label1 != top->idef.iparams[type].disres.label)
+        {
+            pair[j] = k;
+            label1  = top->idef.iparams[type].disres.label;
+            j++;
+        }
+        k++;
+        i += natom;
+    }
+    pair[j]  = k;
+    *npairs  = k;
+    if (j != nb)
+    {
+        gmx_incons("get_bounds for distance restraints");
+    }
+
+    *index   = ind;
+    *dr_pair = pair;
+
+    return nb;
+}
+
+static void calc_violations(real rt[], real rav3[], int nb, int index[],
+                            real bounds[], real *viol, double *st, double *sa)
+{
+    const   real sixth = 1.0/6.0;
+    int          i, j;
+    double       rsum, rav, sumaver, sumt;
+
+    sumaver = 0;
+    sumt    = 0;
+    for (i = 0; (i < nb); i++)
+    {
+        rsum = 0.0;
+        rav  = 0.0;
+        for (j = index[i]; (j < index[i+1]); j++)
+        {
+            if (viol)
+            {
+                viol[j] += mypow(rt[j], -3.0);
+            }
+            rav     += gmx::square(rav3[j]);
+            rsum    += mypow(rt[j], -6);
+        }
+        rsum    = std::max(0.0, mypow(rsum, -sixth)-bounds[i]);
+        rav     = std::max(0.0, mypow(rav, -sixth)-bounds[i]);
+
+        sumt    += rsum;
+        sumaver += rav;
+    }
+    *st = sumt;
+    *sa = sumaver;
+}
+
+static void analyse_disre(const char *voutfn,    int nframes,
+                          real violaver[], real bounds[], int index[],
+                          int pair[],      int nbounds,
+                          const gmx_output_env_t *oenv)
+{
+    FILE   *vout;
+    double  sum, sumt, sumaver;
+    int     i, j;
+
+    /* Subtract bounds from distances, to calculate violations */
+    calc_violations(violaver, violaver,
+                    nbounds, pair, bounds, nullptr, &sumt, &sumaver);
+
+#ifdef DEBUG
+    fprintf(stdout, "\nSum of violations averaged over simulation: %g nm\n",
+            sumaver);
+    fprintf(stdout, "Largest violation averaged over simulation: %g nm\n\n",
+            sumt);
+#endif
+    vout = xvgropen(voutfn, "r\\S-3\\N average violations", "DR Index", "nm",
+                    oenv);
+    sum  = 0.0;
+    sumt = 0.0;
+    for (i = 0; (i < nbounds); i++)
+    {
+        /* Do ensemble averaging */
+        sumaver = 0;
+        for (j = pair[i]; (j < pair[i+1]); j++)
+        {
+            sumaver += gmx::square(violaver[j]/nframes);
+        }
+        sumaver = std::max(0.0, mypow(sumaver, minsixth)-bounds[i]);
+
+        sumt   += sumaver;
+        sum     = std::max(sum, sumaver);
+        fprintf(vout, "%10d  %10.5e\n", index[i], sumaver);
+    }
+#ifdef DEBUG
+    for (j = 0; (j < dr.ndr); j++)
+    {
+        fprintf(vout, "%10d  %10.5e\n", j, mypow(violaver[j]/nframes, minthird));
+    }
+#endif
+    xvgrclose(vout);
+
+    fprintf(stdout, "\nSum of violations averaged over simulation: %g nm\n",
+            sumt);
+    fprintf(stdout, "Largest violation averaged over simulation: %g nm\n\n", sum);
+
+    do_view(oenv, voutfn, "-graphtype bar");
+}
+
+static void print_time(FILE *fp, double t)
+{
+    fprintf(fp, "%12.6f", t);
+}
+
+int gmx_nmr(int argc, char *argv[])
+{
+    const char        *desc[] = {
+        "[THISMODULE] extracts distance or orientation restraint",
+        "data from an energy file. The user is prompted to interactively",
+        "select the desired terms.[PAR]",
+
+        "When the [TT]-viol[tt] option is set, the time averaged",
+        "violations are plotted and the running time-averaged and",
+        "instantaneous sum of violations are recalculated. Additionally",
+        "running time-averaged and instantaneous distances between",
+        "selected pairs can be plotted with the [TT]-pairs[tt] option.[PAR]",
+
+        "Options [TT]-ora[tt], [TT]-ort[tt], [TT]-oda[tt], [TT]-odr[tt] and",
+        "[TT]-odt[tt] are used for analyzing orientation restraint data.",
+        "The first two options plot the orientation, the last three the",
+        "deviations of the orientations from the experimental values.",
+        "The options that end on an 'a' plot the average over time",
+        "as a function of restraint. The options that end on a 't'",
+        "prompt the user for restraint label numbers and plot the data",
+        "as a function of time. Option [TT]-odr[tt] plots the RMS",
+        "deviation as a function of restraint.",
+        "When the run used time or ensemble averaged orientation restraints,",
+        "option [TT]-orinst[tt] can be used to analyse the instantaneous,",
+        "not ensemble-averaged orientations and deviations instead of",
+        "the time and ensemble averages.[PAR]",
+
+        "Option [TT]-oten[tt] plots the eigenvalues of the molecular order",
+        "tensor for each orientation restraint experiment. With option",
+        "[TT]-ovec[tt] also the eigenvectors are plotted.[PAR]",
+
+
+    };
+    static gmx_bool    bPrAll  = FALSE;
+    static gmx_bool    bDp     = FALSE, bOrinst = FALSE, bOvec = FALSE;
+    static int         skip    = 0;
+    t_pargs            pa[]    = {
+        { "-dp",   FALSE, etBOOL, {&bDp},
+          "Print energies in high precision" },
+        { "-skip", FALSE, etINT,  {&skip},
+          "Skip number of frames between data points" },
+        { "-aver", FALSE, etBOOL, {&bPrAll},
+          "Also print the exact average and rmsd stored in the energy frames (only when 1 term is requested)" },
+        { "-orinst", FALSE, etBOOL, {&bOrinst},
+          "Analyse instantaneous orientation data" },
+        { "-ovec", FALSE, etBOOL, {&bOvec},
+          "Also plot the eigenvectors with [TT]-oten[tt]" }
+    };
+    const char       * drleg[] = {
+        "Running average",
+        "Instantaneous"
+    };
+
+    FILE              /* *out     = NULL,*/ *out_disre = NULL, *fp_pairs = NULL, *fort = NULL, *fodt = NULL, *foten = NULL;
+    ener_file_t        fp;
+    int                timecheck = 0;
+    gmx_mtop_t         mtop;
+    gmx_localtop_t    *top = nullptr;
+    gmx_enxnm_t       *enm = nullptr;
+    t_enxframe         fr;
+    int                nre, teller, teller_disre;
+    int                nor     = 0, nex = 0, norfr = 0, enx_i = 0;
+    real              *bounds  = NULL, *violaver = NULL, *oobs = NULL, *orient = NULL, *odrms = NULL;
+    int               *index   = NULL, *pair = NULL, norsel = 0, *orsel = NULL, *or_label = NULL;
+    int                nbounds = 0, npairs;
+    gmx_bool           bDisRe, bDRAll, bORA, bORT, bODA, bODR, bODT, bORIRE, bOTEN;
+    gmx_bool           bCont;
+    double             sumaver, sumt;
+    int               *set     = NULL, i, j, k, nset, sss;
+    char             **pairleg, **odtleg, **otenleg;
+    char             **leg = nullptr;
+    const char        *anm_j, *anm_k, *resnm_j, *resnm_k;
+    int                resnr_j, resnr_k;
+    const char        *orinst_sub = "@ subtitle \"instantaneous\"\n";
+    char               buf[256];
+    gmx_output_env_t  *oenv;
+    t_enxblock        *blk_disre = nullptr;
+    int                ndisre    = 0;
+
+    t_filenm           fnm[] = {
+        { efEDR, "-f",    nullptr,      ffREAD  },
+        { efEDR, "-f2",   nullptr,      ffOPTRD },
+        { efTPR, "-s",    nullptr,      ffOPTRD },
+        // { efXVG, "-o",    "energy",  ffWRITE },
+        { efXVG, "-viol", "violaver", ffOPTWR },
+        { efXVG, "-pairs", "pairs",   ffOPTWR },
+        { efXVG, "-ora",  "orienta", ffOPTWR },
+        { efXVG, "-ort",  "orientt", ffOPTWR },
+        { efXVG, "-oda",  "orideva", ffOPTWR },
+        { efXVG, "-odr",  "oridevr", ffOPTWR },
+        { efXVG, "-odt",  "oridevt", ffOPTWR },
+        { efXVG, "-oten", "oriten",  ffOPTWR }
+    };
+#define NFILE asize(fnm)
+    int                npargs;
+
+    npargs = asize(pa);
+    if (!parse_common_args(&argc, argv,
+                           PCA_CAN_VIEW | PCA_CAN_BEGIN | PCA_CAN_END,
+                           NFILE, fnm, npargs, pa, asize(desc), desc, 0, nullptr, &oenv))
+    {
+        return 0;
+    }
+
+    bDRAll = opt2bSet("-pairs", NFILE, fnm);
+    bDisRe = opt2bSet("-viol", NFILE, fnm) || bDRAll;
+    bORA   = opt2bSet("-ora", NFILE, fnm);
+    bORT   = opt2bSet("-ort", NFILE, fnm);
+    bODA   = opt2bSet("-oda", NFILE, fnm);
+    bODR   = opt2bSet("-odr", NFILE, fnm);
+    bODT   = opt2bSet("-odt", NFILE, fnm);
+    bORIRE = bORA || bORT || bODA || bODR || bODT;
+    bOTEN  = opt2bSet("-oten", NFILE, fnm);
+    if (!(bDRAll || bDisRe || bORA || bORT || bODA || bODR || bODT || bORIRE || bOTEN))
+    {
+        printf("No output selected. Run with -h to see options. Terminating program.\n");
+        return 0;
+    }
+    nset = 0;
+
+    fp = open_enx(ftp2fn(efEDR, NFILE, fnm), "r");
+    do_enxnms(fp, &nre, &enm);
+    free_enxnms(nre, enm);
+
+    t_inputrec  irInstance;
+    t_inputrec *ir = &irInstance;
+    init_enxframe(&fr);
+
+    if (!bDisRe)
+    {
+        if (bORIRE || bOTEN)
+        {
+            get_orires_parms(ftp2fn(efTPR, NFILE, fnm), ir,
+                             &nor, &nex, &or_label, &oobs);
+        }
+
+        if (bORIRE)
+        {
+            if (bOrinst)
+            {
+                enx_i = enxORI;
+            }
+            else
+            {
+                enx_i = enxOR;
+            }
+
+            if (bORA || bODA)
+            {
+                snew(orient, nor);
+            }
+            if (bODR)
+            {
+                snew(odrms, nor);
+            }
+            if (bORT || bODT)
+            {
+                fprintf(stderr, "Select the orientation restraint labels you want (-1 is all)\n");
+                fprintf(stderr, "End your selection with 0\n");
+                j     = -1;
+                orsel = nullptr;
+                do
+                {
+                    j++;
+                    srenew(orsel, j+1);
+                    if (1 != scanf("%d", &(orsel[j])))
+                    {
+                        gmx_fatal(FARGS, "Error reading user input");
+                    }
+                }
+                while (orsel[j] > 0);
+                if (orsel[0] == -1)
+                {
+                    fprintf(stderr, "Selecting all %d orientation restraints\n", nor);
+                    norsel = nor;
+                    srenew(orsel, nor);
+                    for (i = 0; i < nor; i++)
+                    {
+                        orsel[i] = i;
+                    }
+                }
+                else
+                {
+                    /* Build the selection */
+                    norsel = 0;
+                    for (i = 0; i < j; i++)
+                    {
+                        for (k = 0; k < nor; k++)
+                        {
+                            if (or_label[k] == orsel[i])
+                            {
+                                orsel[norsel] = k;
+                                norsel++;
+                                break;
+                            }
+                        }
+                        if (k == nor)
+                        {
+                            fprintf(stderr, "Orientation restraint label %d not found\n",
+                                    orsel[i]);
+                        }
+                    }
+                }
+                snew(odtleg, norsel);
+                for (i = 0; i < norsel; i++)
+                {
+                    snew(odtleg[i], 256);
+                    sprintf(odtleg[i], "%d", or_label[orsel[i]]);
+                }
+                if (bORT)
+                {
+                    fort = xvgropen(opt2fn("-ort", NFILE, fnm), "Calculated orientations",
+                                    "Time (ps)", "", oenv);
+                    if (bOrinst && output_env_get_print_xvgr_codes(oenv))
+                    {
+                        fprintf(fort, "%s", orinst_sub);
+                    }
+                    xvgr_legend(fort, norsel, (const char**)odtleg, oenv);
+                }
+                if (bODT)
+                {
+                    fodt = xvgropen(opt2fn("-odt", NFILE, fnm),
+                                    "Orientation restraint deviation",
+                                    "Time (ps)", "", oenv);
+                    if (bOrinst && output_env_get_print_xvgr_codes(oenv))
+                    {
+                        fprintf(fodt, "%s", orinst_sub);
+                    }
+                    xvgr_legend(fodt, norsel, (const char**)odtleg, oenv);
+                }
+                for (i = 0; i < norsel; i++)
+                {
+                    sfree(odtleg[i]);
+                }
+                sfree(odtleg);
+            }
+        }
+        if (bOTEN)
+        {
+            foten = xvgropen(opt2fn("-oten", NFILE, fnm),
+                             "Order tensor", "Time (ps)", "", oenv);
+            snew(otenleg, bOvec ? nex*12 : nex*3);
+            for (i = 0; i < nex; i++)
+            {
+                for (j = 0; j < 3; j++)
+                {
+                    sprintf(buf, "eig%d", j+1);
+                    otenleg[(bOvec ? 12 : 3)*i+j] = gmx_strdup(buf);
+                }
+                if (bOvec)
+                {
+                    for (j = 0; j < 9; j++)
+                    {
+                        sprintf(buf, "vec%d%s", j/3+1, j%3 == 0 ? "x" : (j%3 == 1 ? "y" : "z"));
+                        otenleg[12*i+3+j] = gmx_strdup(buf);
+                    }
+                }
+            }
+            xvgr_legend(foten, bOvec ? nex*12 : nex*3, (const char**)otenleg, oenv);
+            for (j = 0; j < 3; j++)
+            {
+                sfree(otenleg[j]);
+            }
+            sfree(otenleg);
+        }
+    }
+    else
+    {
+        nbounds = get_bounds(ftp2fn(efTPR, NFILE, fnm), &bounds, &index, &pair, &npairs,
+                             &mtop, &top, ir);
+        snew(violaver, npairs);
+        out_disre = xvgropen(opt2fn("-o", NFILE, fnm), "Sum of Violations",
+                             "Time (ps)", "nm", oenv);
+        xvgr_legend(out_disre, 2, drleg, oenv);
+        if (bDRAll)
+        {
+            fp_pairs = xvgropen(opt2fn("-pairs", NFILE, fnm), "Pair Distances",
+                                "Time (ps)", "Distance (nm)", oenv);
+            if (output_env_get_print_xvgr_codes(oenv))
+            {
+                fprintf(fp_pairs, "@ subtitle \"averaged (tau=%g) and instantaneous\"\n",
+                        ir->dr_tau);
+            }
+        }
+    }
+
+    /* Initiate counters */
+    teller       = 0;
+    teller_disre = 0;
+    do
+    {
+        /* This loop searches for the first frame (when -b option is given),
+         * or when this has been found it reads just one energy frame
+         */
+        do
+        {
+            bCont = do_enx(fp, &fr);
+            if (bCont)
+            {
+                timecheck = check_times(fr.t);
+            }
+        }
+        while (bCont && (timecheck < 0));
+
+        if ((timecheck == 0) && bCont)
+        {
+            /*
+             * Define distance restraint legends. Can only be done after
+             * the first frame has been read... (Then we know how many there are)
+             */
+            blk_disre = find_block_id_enxframe(&fr, enxDISRE, nullptr);
+            if (bDisRe && bDRAll && !leg && blk_disre)
+            {
+                t_iatom   *fa;
+                t_iparams *ip;
+
+                fa = top->idef.il[F_DISRES].iatoms;
+                ip = top->idef.iparams;
+                if (blk_disre->nsub != 2 ||
+                    (blk_disre->sub[0].nr != blk_disre->sub[1].nr) )
+                {
+                    gmx_incons("Number of disre sub-blocks not equal to 2");
+                }
+
+                ndisre = blk_disre->sub[0].nr;
+                if (ndisre != top->idef.il[F_DISRES].nr/3)
+                {
+                    gmx_fatal(FARGS, "Number of disre pairs in the energy file (%d) does not match the number in the run input file (%d)\n",
+                              ndisre, top->idef.il[F_DISRES].nr/3);
+                }
+                snew(pairleg, ndisre);
+                int molb = 0;
+                for (i = 0; i < ndisre; i++)
+                {
+                    snew(pairleg[i], 30);
+                    j = fa[3*i+1];
+                    k = fa[3*i+2];
+                    mtopGetAtomAndResidueName(&mtop, j, &molb, &anm_j, &resnr_j, &resnm_j, nullptr);
+                    mtopGetAtomAndResidueName(&mtop, k, &molb, &anm_k, &resnr_k, &resnm_k, nullptr);
+                    sprintf(pairleg[i], "%d %s %d %s (%d)",
+                            resnr_j, anm_j, resnr_k, anm_k,
+                            ip[fa[3*i]].disres.label);
+                }
+                set = select_it(ndisre, pairleg, &nset);
+                snew(leg, 2*nset);
+                for (i = 0; (i < nset); i++)
+                {
+                    snew(leg[2*i], 32);
+                    sprintf(leg[2*i],  "a %s", pairleg[set[i]]);
+                    snew(leg[2*i+1], 32);
+                    sprintf(leg[2*i+1], "i %s", pairleg[set[i]]);
+                }
+                xvgr_legend(fp_pairs, 2*nset, (const char**)leg, oenv);
+            }
+
+            /*
+             * Printing time, only when we do not want to skip frames
+             */
+            if (!skip || teller % skip == 0)
+            {
+                if (bDisRe)
+                {
+                    /*******************************************
+                     * D I S T A N C E   R E S T R A I N T S
+                     *******************************************/
+                    if (ndisre > 0)
+                    {
+                        GMX_RELEASE_ASSERT(blk_disre != nullptr, "Trying to dereference NULL blk_disre pointer");
+ #if !GMX_DOUBLE
+                        float  *disre_rt     = blk_disre->sub[0].fval;
+                        float  *disre_rm3tav = blk_disre->sub[1].fval;
+ #else
+                        double *disre_rt     = blk_disre->sub[0].dval;
+                        double *disre_rm3tav = blk_disre->sub[1].dval;
+ #endif
+
+                        print_time(out_disre, fr.t);
+                        if (violaver == nullptr)
+                        {
+                            snew(violaver, ndisre);
+                        }
+
+                        /* Subtract bounds from distances, to calculate violations */
+                        calc_violations(disre_rt, disre_rm3tav,
+                                        nbounds, pair, bounds, violaver, &sumt, &sumaver);
+
+                        fprintf(out_disre, "  %8.4f  %8.4f\n", sumaver, sumt);
+                        if (bDRAll)
+                        {
+                            print_time(fp_pairs, fr.t);
+                            for (i = 0; (i < nset); i++)
+                            {
+                                sss = set[i];
+                                fprintf(fp_pairs, "  %8.4f", mypow(disre_rm3tav[sss], minthird));
+                                fprintf(fp_pairs, "  %8.4f", disre_rt[sss]);
+                            }
+                            fprintf(fp_pairs, "\n");
+                        }
+                        teller_disre++;
+                    }
+                }
+
+                /*******************************************
+                 * O R I R E S
+                 *******************************************/
+                else
+                {
+                    t_enxblock *blk = find_block_id_enxframe(&fr, enx_i, nullptr);
+                    if (bORIRE && blk)
+                    {
+                        if (blk->nsub != 1)
+                        {
+                            gmx_fatal(FARGS, "Orientational restraints read in incorrectly.");
+                        }
+
+                        if (blk->sub[0].nr != nor)
+                        {
+                            gmx_fatal(FARGS, "Number of orientation restraints in energy file (%d) does not match with the topology (%d)", blk->sub[0].nr);
+                        }
+                        if (bORA || bODA)
+                        {
+                            for (i = 0; i < nor; i++)
+                            {
+                                orient[i] += blk_value(blk, 0, i);
+                            }
+                        }
+                        if (bODR)
+                        {
+                            for (i = 0; i < nor; i++)
+                            {
+                                real v = blk_value(blk, 0, i);
+                                odrms[i] += gmx::square(v - oobs[i]);
+                            }
+                        }
+                        if (bORT)
+                        {
+                            fprintf(fort, "  %10f", fr.t);
+                            for (i = 0; i < norsel; i++)
+                            {
+                                fprintf(fort, " %g", blk_value(blk, 0, orsel[i]));
+                            }
+                            fprintf(fort, "\n");
+                        }
+                        if (bODT)
+                        {
+                            fprintf(fodt, "  %10f", fr.t);
+                            for (i = 0; i < norsel; i++)
+                            {
+                                fprintf(fodt, " %g", blk_value(blk, 0, orsel[i])-oobs[orsel[i]]);
+                            }
+                            fprintf(fodt, "\n");
+                        }
+                        norfr++;
+                    }
+                    blk = find_block_id_enxframe(&fr, enxORT, nullptr);
+                    if (bOTEN && blk)
+                    {
+                        if (blk->nsub != 1)
+                        {
+                            gmx_fatal(FARGS, "Orientational restraints read in incorrectly");
+                        }
+
+                        if (blk->sub[0].nr != nex*12)
+                        {
+                            gmx_fatal(FARGS, "Number of orientation experiments in energy file (%g) does not match with the topology (%d)",
+                                      blk->sub[0].nr/12, nex);
+                        }
+                        fprintf(foten, "  %10f", fr.t);
+                        for (i = 0; i < nex; i++)
+                        {
+                            for (j = 0; j < (bOvec ? 12 : 3); j++)
+                            {
+                                fprintf(foten, " %g", blk_value(blk, 0, i*12+j));
+                            }
+                        }
+                        fprintf(foten, "\n");
+                    }
+                }
+            }
+            teller++;
+        }
+    }
+    while (bCont && (timecheck == 0));
+    free_enxframe(&fr);
+
+    fprintf(stderr, "\n");
+    done_ener_file(fp);
+    if (out_disre)
+    {
+        xvgrclose(out_disre);
+    }
+
+    if (bDRAll)
+    {
+        xvgrclose(fp_pairs);
+    }
+
+    if (bORT)
+    {
+        xvgrclose(fort);
+    }
+    if (bODT)
+    {
+        xvgrclose(fodt);
+    }
+    if (bORA)
+    {
+        FILE *out = xvgropen(opt2fn("-ora", NFILE, fnm),
+                             "Average calculated orientations",
+                             "Restraint label", "", oenv);
+        if (bOrinst && output_env_get_print_xvgr_codes(oenv))
+        {
+            fprintf(out, "%s", orinst_sub);
+        }
+        for (i = 0; i < nor; i++)
+        {
+            fprintf(out, "%5d  %g\n", or_label[i], orient[i]/norfr);
+        }
+        xvgrclose(out);
+    }
+    if (bODA)
+    {
+        FILE *out = xvgropen(opt2fn("-oda", NFILE, fnm),
+                             "Average restraint deviation",
+                             "Restraint label", "", oenv);
+        if (bOrinst && output_env_get_print_xvgr_codes(oenv))
+        {
+            fprintf(out, "%s", orinst_sub);
+        }
+        for (i = 0; i < nor; i++)
+        {
+            fprintf(out, "%5d  %g\n", or_label[i], orient[i]/norfr-oobs[i]);
+        }
+        xvgrclose(out);
+    }
+    if (bODR)
+    {
+        FILE *out = xvgropen(opt2fn("-odr", NFILE, fnm),
+                             "RMS orientation restraint deviations",
+                             "Restraint label", "", oenv);
+        if (bOrinst && output_env_get_print_xvgr_codes(oenv))
+        {
+            fprintf(out, "%s", orinst_sub);
+        }
+        for (i = 0; i < nor; i++)
+        {
+            fprintf(out, "%5d  %g\n", or_label[i], std::sqrt(odrms[i]/norfr));
+        }
+        xvgrclose(out);
+    }
+    // Clean up orires variables.
+    sfree(or_label);
+    sfree(oobs);
+    sfree(orient);
+    sfree(odrms);
+    sfree(orsel);
+    if (bOTEN)
+    {
+        xvgrclose(foten);
+    }
+
+    if (bDisRe)
+    {
+        analyse_disre(opt2fn("-viol", NFILE, fnm),
+                      teller_disre, violaver, bounds, index, pair, nbounds, oenv);
+    }
+    {
+        const char *nxy = "-nxy";
+
+        do_view(oenv, opt2fn_null("-ora", NFILE, fnm), nxy);
+        do_view(oenv, opt2fn_null("-ort", NFILE, fnm), nxy);
+        do_view(oenv, opt2fn_null("-oda", NFILE, fnm), nxy);
+        do_view(oenv, opt2fn_null("-odr", NFILE, fnm), nxy);
+        do_view(oenv, opt2fn_null("-odt", NFILE, fnm), nxy);
+        do_view(oenv, opt2fn_null("-oten", NFILE, fnm), nxy);
+    }
+    output_env_done(oenv);
+    done_filenms(NFILE, fnm);
+
+    return 0;
+}
index c39c2c4ae99548ad3e7373078e103d69d754d1d3..0a159de02b4cb90e2b0afc60b1748c9c69956000 100644 (file)
@@ -301,6 +301,8 @@ void registerLegacyModules(gmx::CommandLineModuleManager *manager)
                    "Diagonalize the Hessian for normal mode analysis");
     registerModule(manager, &gmx_nmens, "nmens",
                    "Generate an ensemble of structures from the normal modes");
+    registerModule(manager, &gmx_nmr, "nmr",
+                   "Analyze nuclear magnetic resonance properties from an energy file");
     registerModule(manager, &gmx_nmtraj, "nmtraj",
                    "Generate a virtual oscillating trajectory from an eigenvector");
     registerModule(manager, &gmx_order, "order",