Made distance restraints work with threads and DD
authorBerk Hess <hess@kth.se>
Wed, 10 Aug 2016 10:23:03 +0000 (12:23 +0200)
committerDavid van der Spoel <davidvanderspoel@gmail.com>
Fri, 16 Sep 2016 08:04:42 +0000 (10:04 +0200)
The NMR distance restraints use several buffers for summing distances
that were indexed based on the index of the thread+domain local ilist
force atoms. This gives incorrect results with OpenMP and/or domain
decomposition. Using the type index for the restraint and a domain-
local, but not thread-local index for the pair resolves these issues.
The are now only two limitations left:
* Time-averaged restraint don't work with DD.
* Multiple copies of molecules in the same system without ensemble
  averaging does not work with DD.

Fixes #1117.
Fixes #1989.
Fixes #2029.

Change-Id: Ic51230aa19a4640caca29a7d7ff471e30a3d9f09

src/gromacs/gmxana/gmx_disre.cpp
src/gromacs/listed-forces/disre.cpp
src/gromacs/listed-forces/disre.h
src/gromacs/listed-forces/listed-forces.cpp
src/gromacs/listed-forces/listed-forces.h
src/gromacs/mdlib/force.cpp
src/gromacs/mdtypes/fcdata.h

index 7ab49c13837ea4b74613b9a2bcfff45c5a7bb61d..94dc678cda99126a2d2c54e5054c361899d2be17 100644 (file)
@@ -204,7 +204,7 @@ static void check_viol(FILE *log,
         while (((i+n) < disres->nr) &&
                (forceparams[forceatoms[i+n]].disres.label == label));
 
-        calc_disres_R_6(n, &forceatoms[i], forceparams,
+        calc_disres_R_6(NULL, n, &forceatoms[i],
                         (const rvec*)x, pbc, fcd, NULL);
 
         if (fcd->disres.Rt_6[0] <= 0)
index b591b1969a89e3a87686818ab52b2d9e252d4d47..46ba97584201b7820d74e9390993473b48f2b6f4 100644 (file)
@@ -63,6 +63,7 @@
 #include "gromacs/topology/topology.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/futil.h"
+#include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/pleasecite.h"
 #include "gromacs/utility/smalloc.h"
 
@@ -76,6 +77,7 @@ void init_disres(FILE *fplog, const gmx_mtop_t *mtop,
     gmx_mtop_ilistloop_t iloop;
     t_ilist             *il;
     char                *ptr;
+    int                  type_min, type_max;
 
     dd = &(fcd->disres);
 
@@ -91,12 +93,6 @@ void init_disres(FILE *fplog, const gmx_mtop_t *mtop,
         fprintf(fplog, "Initializing the distance restraints\n");
     }
 
-
-    if (ir->eDisre == edrEnsemble)
-    {
-        gmx_fatal(FARGS, "Sorry, distance restraints with ensemble averaging over multiple molecules in one system are not functional in this version of GROMACS");
-    }
-
     dd->dr_weighting = ir->eDisreWeighting;
     dd->dr_fc        = ir->dr_fc;
     if (EI_DYNAMICS(ir->eI))
@@ -114,6 +110,16 @@ void init_disres(FILE *fplog, const gmx_mtop_t *mtop,
     }
     else
     {
+        /* We store the r^-6 time averages in an array that is indexed
+         * with the local disres iatom index, so this doesn't work with DD.
+         * Note that DD is not initialized yet here, so we check for PAR(cr),
+         * but there are probably also issues with e.g. NM MPI parallelization.
+         */
+        if (cr && PAR(cr))
+        {
+            gmx_fatal(FARGS, "Time-averaged distance restraints are not supported with MPI parallelization. You can use OpenMP parallelization on a single node.");
+        }
+
         dd->dr_bMixed = ir->bDisreMixed;
         dd->ETerm     = std::exp(-(ir->delta_t/ir->dr_tau));
     }
@@ -121,55 +127,54 @@ void init_disres(FILE *fplog, const gmx_mtop_t *mtop,
 
     dd->nres  = 0;
     dd->npair = 0;
+    type_min  = INT_MAX;
+    type_max  = 0;
     iloop     = gmx_mtop_ilistloop_init(mtop);
     while (gmx_mtop_ilistloop_next(iloop, &il, &nmol))
     {
+        if (nmol > 1 && ir->eDisre != edrEnsemble)
+        {
+            gmx_fatal(FARGS, "NMR distance restraints with multiple copies of the same molecule are currently only supported with ensemble averaging. If you just want to restrain distances between atom pairs using a flat-bottomed potential, use a restraint potential (bonds type 10) instead.");
+        }
+
         np = 0;
         for (fa = 0; fa < il[F_DISRES].nr; fa += 3)
         {
+            int type;
+
+            type  = il[F_DISRES].iatoms[fa];
+
             np++;
-            npair = mtop->ffparams.iparams[il[F_DISRES].iatoms[fa]].disres.npair;
+            npair = mtop->ffparams.iparams[type].disres.npair;
             if (np == npair)
             {
-                dd->nres  += (ir->eDisre == edrEnsemble ? 1 : nmol)*npair;
+                dd->nres  += (ir->eDisre == edrEnsemble ? 1 : nmol);
                 dd->npair += nmol*npair;
                 np         = 0;
+
+                type_min   = std::min(type_min, type);
+                type_max   = std::max(type_max, type);
             }
         }
     }
 
-    if (cr && PAR(cr))
+    if (cr && PAR(cr) && ir->nstdisreout > 0)
     {
-        /* Temporary check, will be removed when disre is implemented with DD */
-        const char *notestr = "NOTE: atoms involved in distance restraints should be within the same domain. If this is not the case mdrun generates a fatal error. If you encounter this, use a single MPI rank (Verlet+OpenMP+GPUs work fine).";
+        /* With DD we currently only have local pair information available */
+        gmx_fatal(FARGS, "With MPI parallelization distance-restraint pair output is not supported. Use nstdisreout=0 or use OpenMP parallelization on a single node.");
+    }
 
-        if (MASTER(cr))
-        {
-            fprintf(stderr, "\n%s\n\n", notestr);
-        }
-        if (fplog)
-        {
-            fprintf(fplog, "%s\n", notestr);
-        }
+    /* For communicating and/or reducing (sums of) r^-6 for pairs over threads
+     * we use multiple arrays in t_disresdata. We need to have unique indices
+     * for each restraint that work over threads and MPI ranks. To this end
+     * we use the type index. These should all be in one block and there should
+     * be dd->nres types, but we check for this here.
+     * This setup currently does not allow for multiple copies of the same
+     * molecule without ensemble averaging, this is check for above.
+     */
+    GMX_RELEASE_ASSERT(type_max - type_min + 1 == dd->nres, "All distance restraint parameter entries in the topology should be consecutive");
 
-        if (dd->dr_tau != 0 || ir->eDisre == edrEnsemble ||
-            dd->nres != dd->npair)
-        {
-            gmx_fatal(FARGS, "Time or ensemble averaged or multiple pair distance restraints do not work (yet) with domain decomposition, use a single MPI rank%s", cr->ms ? " per simulation" : "");
-        }
-        if (ir->nstdisreout != 0)
-        {
-            if (fplog)
-            {
-                fprintf(fplog, "\nWARNING: Can not write distance restraint data to energy file with domain decomposition\n\n");
-            }
-            if (MASTER(cr))
-            {
-                fprintf(stderr, "\nWARNING: Can not write distance restraint data to energy file with domain decomposition\n");
-            }
-            ir->nstdisreout = 0;
-        }
-    }
+    dd->type_min = type_min;
 
     snew(dd->rt, dd->npair);
 
@@ -234,14 +239,21 @@ void init_disres(FILE *fplog, const gmx_mtop_t *mtop,
             }
             fprintf(fplog, "\n");
         }
-        snew(dd->Rtl_6, dd->nres);
 #endif
     }
     else
     {
         dd->nsystems = 1;
+    }
+
+    if (dd->nsystems == 1)
+    {
         dd->Rtl_6    = dd->Rt_6;
     }
+    else
+    {
+        snew(dd->Rtl_6, dd->nres);
+    }
 
     if (dd->npair > 0)
     {
@@ -266,18 +278,15 @@ void init_disres(FILE *fplog, const gmx_mtop_t *mtop,
     }
 }
 
-void calc_disres_R_6(int nfa, const t_iatom forceatoms[], const t_iparams ip[],
+void calc_disres_R_6(const t_commrec *cr,
+                     int nfa, const t_iatom forceatoms[],
                      const rvec x[], const t_pbc *pbc,
                      t_fcdata *fcd, history_t *hist)
 {
-    int             ai, aj;
-    int             fa, res, pair;
-    int             type, npair, np;
     rvec            dx;
     real           *rt, *rm3tav, *Rtl_6, *Rt_6, *Rtav_6;
-    real            rt_1, rt_3, rt2;
     t_disresdata   *dd;
-    real            ETerm, ETerm1, cf1 = 0, cf2 = 0, invn = 0;
+    real            ETerm, ETerm1, cf1 = 0, cf2 = 0;
     gmx_bool        bTav;
 
     dd           = &(fcd->disres);
@@ -300,74 +309,91 @@ void calc_disres_R_6(int nfa, const t_iatom forceatoms[], const t_iparams ip[],
         cf2 = 1.0/(1.0 - dd->exp_min_t_tau);
     }
 
-    if (dd->nsystems > 1)
+    for (int res = 0; res < dd->nres; res++)
     {
-        invn = 1.0/dd->nsystems;
+        Rtav_6[res] = 0.0;
+        Rt_6[res]   = 0.0;
     }
 
     /* 'loop' over all atom pairs (pair_nr=fa/3) involved in restraints, *
      * the total number of atoms pairs is nfa/3                          */
-    res = 0;
-    fa  = 0;
-    while (fa < nfa)
+    for (int fa = 0; fa < nfa; fa += 3)
     {
-        type  = forceatoms[fa];
-        npair = ip[type].disres.npair;
+        int type = forceatoms[fa];
+        int res  = type - dd->type_min;
+        int pair = fa/3;
+        int ai   = forceatoms[fa+1];
+        int aj   = forceatoms[fa+2];
 
-        Rtav_6[res] = 0.0;
-        Rt_6[res]   = 0.0;
+        if (pbc)
+        {
+            pbc_dx_aiuc(pbc, x[ai], x[aj], dx);
+        }
+        else
+        {
+            rvec_sub(x[ai], x[aj], dx);
+        }
+        real rt2  = iprod(dx, dx);
+        real rt_1 = gmx::invsqrt(rt2);
+        real rt_3 = rt_1*rt_1*rt_1;
 
-        /* Loop over the atom pairs of 'this' restraint */
-        np = 0;
-        while (fa < nfa && np < npair)
+        rt[pair]  = rt2*rt_1;
+        if (bTav)
         {
-            pair = fa/3;
-            ai   = forceatoms[fa+1];
-            aj   = forceatoms[fa+2];
+            /* Here we update rm3tav in t_fcdata using the data
+             * in history_t.
+             * Thus the results stay correct when this routine
+             * is called multiple times.
+             */
+            rm3tav[pair] = cf2*((ETerm - cf1)*hist->disre_rm3tav[pair] +
+                                ETerm1*rt_3);
+        }
+        else
+        {
+            rm3tav[pair] = rt_3;
+        }
 
-            if (pbc)
-            {
-                pbc_dx_aiuc(pbc, x[ai], x[aj], dx);
-            }
-            else
-            {
-                rvec_sub(x[ai], x[aj], dx);
-            }
-            rt2  = iprod(dx, dx);
-            rt_1 = gmx::invsqrt(rt2);
-            rt_3 = rt_1*rt_1*rt_1;
+        /* Currently divide_bondeds_over_threads() ensures that pairs within
+         * the same restraint get assigned to the same thread, so we could
+         * run this loop thread-parallel.
+         */
+        Rt_6[res]       += rt_3*rt_3;
+        Rtav_6[res]     += rm3tav[pair]*rm3tav[pair];
+    }
 
-            rt[pair]         = std::sqrt(rt2);
-            if (bTav)
-            {
-                /* Here we update rm3tav in t_fcdata using the data
-                 * in history_t.
-                 * Thus the results stay correct when this routine
-                 * is called multiple times.
-                 */
-                rm3tav[pair] = cf2*((ETerm - cf1)*hist->disre_rm3tav[pair] +
-                                    ETerm1*rt_3);
-            }
-            else
-            {
-                rm3tav[pair] = rt_3;
-            }
+    /* NOTE: Rt_6 and Rtav_6 are stored consecutively in memory */
+    if (cr && DOMAINDECOMP(cr))
+    {
+        gmx_sum(2*dd->nres, dd->Rt_6, cr);
+    }
 
-            Rt_6[res]       += rt_3*rt_3;
-            Rtav_6[res]     += rm3tav[pair]*rm3tav[pair];
+    if (fcd->disres.nsystems > 1)
+    {
+        real invn = 1.0/dd->nsystems;
 
-            fa += 3;
-            np++;
-        }
-        if (dd->nsystems > 1)
+        for (int res = 0; res < dd->nres; res++)
         {
             Rtl_6[res]   = Rt_6[res];
             Rt_6[res]   *= invn;
             Rtav_6[res] *= invn;
         }
 
-        res++;
+        GMX_ASSERT(cr != NULL && cr->ms != NULL, "We need multisim with nsystems>1");
+        gmx_sum_sim(2*dd->nres, dd->Rt_6, cr->ms);
+
+        if (DOMAINDECOMP(cr))
+        {
+            gmx_bcast(2*dd->nres, dd->Rt_6, cr);
+        }
     }
+
+    /* Store the base forceatoms pointer, so we can re-calculate the pair
+     * index in ta_disres() for indexing pair data in t_disresdata when
+     * using thread parallelization.
+     */
+    dd->forceatomsStart = forceatoms;
+
+    dd->sumviol         = 0;
 }
 
 real ta_disres(int nfa, const t_iatom forceatoms[], const t_iparams ip[],
@@ -379,9 +405,6 @@ real ta_disres(int nfa, const t_iatom forceatoms[], const t_iparams ip[],
 {
     const real      seven_three = 7.0/3.0;
 
-    int             ai, aj;
-    int             fa, res, npair, p, pair, ki = CENTRAL, m;
-    int             type;
     rvec            dx;
     real            weight_rt_1;
     real            smooth_fc, Rt, Rtav, rt2, *Rtl_6, *Rt_6, *Rtav_6;
@@ -417,17 +440,17 @@ real ta_disres(int nfa, const t_iatom forceatoms[], const t_iparams ip[],
 
     /* 'loop' over all atom pairs (pair_nr=fa/3) involved in restraints, *
      * the total number of atoms pairs is nfa/3                          */
-    res  = 0;
-    fa   = 0;
-    while (fa < nfa)
+    int faOffset = static_cast<int>(forceatoms - dd->forceatomsStart);
+    for (int fa = 0; fa < nfa; fa += 3)
     {
-        type  = forceatoms[fa];
-        /* Take action depending on restraint, calculate scalar force */
-        npair = ip[type].disres.npair;
-        up1   = ip[type].disres.up1;
-        up2   = ip[type].disres.up2;
-        low   = ip[type].disres.low;
-        k0    = smooth_fc*ip[type].disres.kfac;
+        int type  = forceatoms[fa];
+        int npair = ip[type].disres.npair;
+        up1       = ip[type].disres.up1;
+        up2       = ip[type].disres.up2;
+        low       = ip[type].disres.low;
+        k0        = smooth_fc*ip[type].disres.kfac;
+
+        int res   = type - dd->type_min;
 
         /* save some flops when there is only one pair */
         if (ip[type].disres.type != 2)
@@ -439,7 +462,7 @@ real ta_disres(int nfa, const t_iatom forceatoms[], const t_iparams ip[],
         }
         else
         {
-            /* When rtype=2 use instantaneous not ensemble avereged distance */
+            /* When rtype=2 use instantaneous not ensemble averaged distance */
             bConservative = (npair > 1);
             bMixed        = FALSE;
             Rt            = gmx::invsixthroot(Rtl_6[res]);
@@ -463,18 +486,17 @@ real ta_disres(int nfa, const t_iatom forceatoms[], const t_iparams ip[],
 
         if (bViolation)
         {
+            /* Add 1/npair energy and violation for each of the npair pairs */
+            real pairFac = 1/static_cast<real>(npair);
+
             /* NOTE:
              * there is no real potential when time averaging is applied
              */
-            vtot += 0.5*k0*gmx::square(tav_viol);
-            if (1/vtot == 0)
-            {
-                printf("vtot is inf: %f\n", vtot);
-            }
+            vtot += 0.5*k0*gmx::square(tav_viol)*pairFac;
             if (!bMixed)
             {
                 f_scal   = -k0*tav_viol;
-                violtot += fabs(tav_viol);
+                violtot += fabs(tav_viol)*pairFac;
             }
             else
             {
@@ -508,7 +530,7 @@ real ta_disres(int nfa, const t_iatom forceatoms[], const t_iparams ip[],
                 {
                     mixed_viol = std::sqrt(tav_viol*instant_viol);
                     f_scal     = -k0*mixed_viol;
-                    violtot   += mixed_viol;
+                    violtot   += mixed_viol*pairFac;
                 }
             }
         }
@@ -539,67 +561,57 @@ real ta_disres(int nfa, const t_iatom forceatoms[], const t_iparams ip[],
 
             /* Exert the force ... */
 
-            /* Loop over the atom pairs of 'this' restraint */
-            for (p = 0; p < npair; p++)
+            int pair = (faOffset + fa)/3;
+            int ai   = forceatoms[fa+1];
+            int aj   = forceatoms[fa+2];
+            int ki   = CENTRAL;
+            if (pbc)
             {
-                pair = fa/3;
-                ai   = forceatoms[fa+1];
-                aj   = forceatoms[fa+2];
+                ki = pbc_dx_aiuc(pbc, x[ai], x[aj], dx);
+            }
+            else
+            {
+                rvec_sub(x[ai], x[aj], dx);
+            }
+            rt2 = iprod(dx, dx);
+
+            weight_rt_1 = gmx::invsqrt(rt2);
 
-                if (pbc)
+            if (bConservative)
+            {
+                if (!dr_bMixed)
                 {
-                    ki = pbc_dx_aiuc(pbc, x[ai], x[aj], dx);
+                    weight_rt_1 *= std::pow(dd->rm3tav[pair], seven_three);
                 }
                 else
                 {
-                    rvec_sub(x[ai], x[aj], dx);
-                }
-                rt2 = iprod(dx, dx);
-
-                weight_rt_1 = gmx::invsqrt(rt2);
-
-                if (bConservative)
-                {
-                    if (!dr_bMixed)
-                    {
-                        weight_rt_1 *= std::pow(dd->rm3tav[pair], seven_three);
-                    }
-                    else
-                    {
-                        weight_rt_1 *= tav_viol_Rtav7*std::pow(dd->rm3tav[pair], seven_three)+
-                            instant_viol_Rtav7/(dd->rt[pair]*gmx::power6(dd->rt[pair]));
-                    }
+                    weight_rt_1 *= tav_viol_Rtav7*std::pow(dd->rm3tav[pair], seven_three)+
+                        instant_viol_Rtav7/(dd->rt[pair]*gmx::power6(dd->rt[pair]));
                 }
+            }
 
-                fk_scal  = f_scal*weight_rt_1;
+            fk_scal  = f_scal*weight_rt_1;
 
-                if (g)
-                {
-                    ivec_sub(SHIFT_IVEC(g, ai), SHIFT_IVEC(g, aj), dt);
-                    ki = IVEC2IS(dt);
-                }
+            if (g)
+            {
+                ivec_sub(SHIFT_IVEC(g, ai), SHIFT_IVEC(g, aj), dt);
+                ki = IVEC2IS(dt);
+            }
 
-                for (m = 0; m < DIM; m++)
-                {
-                    fij            = fk_scal*dx[m];
+            for (int m = 0; m < DIM; m++)
+            {
+                fij            = fk_scal*dx[m];
 
-                    f[ai][m]           += fij;
-                    f[aj][m]           -= fij;
-                    fshift[ki][m]      += fij;
-                    fshift[CENTRAL][m] -= fij;
-                }
-                fa += 3;
+                f[ai][m]           += fij;
+                f[aj][m]           -= fij;
+                fshift[ki][m]      += fij;
+                fshift[CENTRAL][m] -= fij;
             }
         }
-        else
-        {
-            /* No violation so force and potential contributions */
-            fa += 3*npair;
-        }
-        res++;
     }
 
-    dd->sumviol = violtot;
+#pragma omp atomic
+    dd->sumviol += violtot;
 
     /* Return energy */
     return vtot;
index d328409a6f1c61cb496bc7e108b0bef0004f0690..183847d3709d1df0fc41a12f4b49d13f8bfbfa79 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016, 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.
@@ -74,7 +74,8 @@ void init_disres(FILE *fplog, const gmx_mtop_t *mtop,
  * Calculates r and r^-3 (inst. and time averaged) for all pairs
  * and the ensemble averaged r^-6 (inst. and time averaged) for all restraints
  */
-void calc_disres_R_6(int nfa, const t_iatom *fa, const t_iparams ip[],
+void calc_disres_R_6(const t_commrec *cr,
+                     int nfa, const t_iatom *fa,
                      const rvec *x, const t_pbc *pbc,
                      t_fcdata *fcd, history_t *hist);
 
index 89848f52559d581e41c7ce0bfb2487a3a9e6ebe2..bf3dbf8a4db1d325b361883c3768847531060fea 100644 (file)
@@ -45,8 +45,6 @@
 
 #include "listed-forces.h"
 
-#include "config.h"
-
 #include <assert.h>
 
 #include <algorithm>
@@ -61,6 +59,7 @@
 #include "gromacs/math/vec.h"
 #include "gromacs/mdlib/force.h"
 #include "gromacs/mdlib/force_flags.h"
+#include "gromacs/mdtypes/commrec.h"
 #include "gromacs/mdtypes/fcdata.h"
 #include "gromacs/mdtypes/forcerec.h"
 #include "gromacs/mdtypes/inputrec.h"
@@ -391,7 +390,7 @@ ftype_is_bonded_potential(int ftype)
         (ftype < F_GB12 || ftype > F_GB14);
 }
 
-void calc_listed(const struct gmx_multisim_t *ms,
+void calc_listed(const t_commrec             *cr,
                  struct gmx_wallcycle        *wcycle,
                  const t_idef *idef,
                  const rvec x[], history_t *hist,
@@ -442,8 +441,8 @@ void calc_listed(const struct gmx_multisim_t *ms,
 
     if ((idef->il[F_POSRES].nr > 0) ||
         (idef->il[F_FBPOSRES].nr > 0) ||
-        (idef->il[F_ORIRES].nr > 0) ||
-        (idef->il[F_DISRES].nr > 0))
+        fcd->orires.nr > 0 ||
+        fcd->disres.nres > 0)
     {
         /* TODO Use of restraints triggers further function calls
            inside the loop over calc_one_bond(), but those are too
@@ -463,26 +462,21 @@ void calc_listed(const struct gmx_multisim_t *ms,
         }
 
         /* Do pre force calculation stuff which might require communication */
-        if (idef->il[F_ORIRES].nr > 0)
+        if (fcd->orires.nr > 0)
         {
             enerd->term[F_ORIRESDEV] =
-                calc_orires_dev(ms, idef->il[F_ORIRES].nr,
+                calc_orires_dev(cr->ms, idef->il[F_ORIRES].nr,
                                 idef->il[F_ORIRES].iatoms,
                                 idef->iparams, md, x,
                                 pbc_null, fcd, hist);
         }
-        if (idef->il[F_DISRES].nr)
+        if (fcd->disres.nres > 0)
         {
-            calc_disres_R_6(idef->il[F_DISRES].nr,
+            calc_disres_R_6(cr,
+                            idef->il[F_DISRES].nr,
                             idef->il[F_DISRES].iatoms,
-                            idef->iparams, x, pbc_null,
+                            x, pbc_null,
                             fcd, hist);
-#if GMX_MPI
-            if (fcd->disres.nsystems > 1)
-            {
-                gmx_sum_sim(2*fcd->disres.nres, fcd->disres.Rt_6, ms);
-            }
-#endif
         }
 
         wallcycle_sub_stop(wcycle, ewcsRESTRAINTS);
@@ -635,7 +629,7 @@ void
 do_force_listed(struct gmx_wallcycle        *wcycle,
                 matrix                       box,
                 const t_lambda              *fepvals,
-                const struct gmx_multisim_t *ms,
+                const t_commrec             *cr,
                 const t_idef                *idef,
                 const rvec                   x[],
                 history_t                   *hist,
@@ -664,7 +658,7 @@ do_force_listed(struct gmx_wallcycle        *wcycle,
         /* Not enough flops to bother counting */
         set_pbc(&pbc_full, fr->ePBC, box);
     }
-    calc_listed(ms, wcycle, idef, x, hist, f, fr, pbc, &pbc_full,
+    calc_listed(cr, wcycle, idef, x, hist, f, fr, pbc, &pbc_full,
                 graph, enerd, nrnb, lambda, md, fcd,
                 global_atom_index, flags);
 
index c2f3ec65dbb919a873d66815681b4b5ecb4ce476..acb95107dce6431d07efab3dd9862ec1fd015d2d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2016, 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.
@@ -71,8 +71,8 @@
 
 struct gmx_enerdata_t;
 struct gmx_grppairener_t;
-struct gmx_multisim_t;
 struct history_t;
+struct t_commrec;
 struct t_fcdata;
 struct t_forcerec;
 struct t_idef;
@@ -99,7 +99,7 @@ ftype_is_bonded_potential(int ftype);
  *
  * Note that pbc_full is used only for position restraints, and is
  * not initialized if there are none. */
-void calc_listed(const struct gmx_multisim_t *ms,
+void calc_listed(const t_commrec *cr,
                  struct gmx_wallcycle *wcycle,
                  const t_idef *idef,
                  const rvec x[], history_t *hist,
@@ -130,7 +130,7 @@ void
 do_force_listed(struct gmx_wallcycle           *wcycle,
                 matrix                          box,
                 const t_lambda                 *fepvals,
-                const struct gmx_multisim_t    *ms,
+                const t_commrec                *cr,
                 const t_idef                   *idef,
                 const rvec                      x[],
                 history_t                      *hist,
index 90c4b02f5772714ec0be982d49ea8a27a1b365b1..fa592e1993b0a7736fe2c524975858c6f2c0bf29 100644 (file)
@@ -359,7 +359,7 @@ void do_force_lowlevel(t_forcerec *fr,      t_inputrec *ir,
                    TRUE, box);
     }
 
-    do_force_listed(wcycle, box, ir->fepvals, cr->ms,
+    do_force_listed(wcycle, box, ir->fepvals, cr,
                     idef, (const rvec *) x, hist, f, fr,
                     &pbc, graph, enerd, nrnb, lambda, md, fcd,
                     DOMAINDECOMP(cr) ? cr->dd->gatindex : NULL,
index 0b66406d9de9b628cb04578bfd245345e0074a42..ecb800a818bbccee9948d370c82fcd4ef1b4e079 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2012,2014,2015, by the GROMACS development team, led by
+ * Copyright (c) 2012,2014,2015,2016, 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.
@@ -38,6 +38,7 @@
 #define GMX_MDTYPES_FCDATA_H
 
 #include "gromacs/math/vectypes.h"
+#include "gromacs/topology/idef.h"
 #include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/real.h"
 
@@ -61,13 +62,17 @@ typedef struct t_disresdata {
     real  exp_min_t_tau;   /* Factor for slowly switching on the force         */
     int   nres;            /* The number of distance restraints                */
     int   npair;           /* The number of distance restraint pairs           */
+    int   type_min;        /* The minimum iparam type index for restraints     */
     real  sumviol;         /* The sum of violations                            */
-    real *rt;              /* The calculated instantaneous distance (npr)      */
-    real *rm3tav;          /* The calculated time averaged distance (npr)      */
-    real *Rtl_6;           /* The calculated instantaneous r^-6 (nr)           */
-    real *Rt_6;            /* The calculated inst. ens. averaged r^-6 (nr)     */
-    real *Rtav_6;          /* The calculated time and ens. averaged r^-6 (nr)  */
+    real *rt;              /* The instantaneous distance (npair)               */
+    real *rm3tav;          /* The time averaged distance (npair)               */
+    real *Rtl_6;           /* The instantaneous r^-6 (nres)                    */
+    real *Rt_6;            /* The instantaneous ensemble averaged r^-6 (nres)  */
+    real *Rtav_6;          /* The time and ensemble averaged r^-6 (nres)       */
     int   nsystems;        /* The number of systems for ensemble averaging     */
+
+    /* TODO: Implement a proper solution for parallel disre indexing */
+    const t_iatom *forceatomsStart; /* Pointer to the start of the disre forceatoms */
 } t_disresdata;