Add check for pull group PBC to grompp
authorBerk Hess <hess@kth.se>
Wed, 15 Aug 2018 14:45:15 +0000 (16:45 +0200)
committerBerk Hess <hess@kth.se>
Sat, 18 Aug 2018 19:45:13 +0000 (21:45 +0200)
Pull groups that use a reference atom for periodic boundary treatment
should have all their atoms well within half the box size of this
reference. When this is not the case, grompp will now issue a warning.

Refs #2397

Change-Id: Ida7004624a470981d9ce22a1ef921daebad83364

docs/release-notes/2018/2018.3.rst
src/gromacs/gmxpreprocess/grompp.cpp
src/gromacs/gmxpreprocess/readir.h
src/gromacs/gmxpreprocess/readpull.cpp
src/gromacs/pulling/pull.h
src/gromacs/pulling/pullutil.cpp

index 6c4057aee68f8fe501b239e01227b574a16e4bb5..10db91dffb399bf339fe50e3429e01cf20db5597 100644 (file)
@@ -12,6 +12,15 @@ Multi-domain Conjugate Gradient minimimization no longer segfaults.
 
 :issue:`2554`
 
+grompp now checks that pull groups are not close to half the box size
+""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+
+Pull groups that use a reference atom for periodic boundary treatment
+should have all their atoms well within half the box size of this reference.
+When this is not the case, grompp will issue a warning.
+
+:issue:`2397`
+
 Fixes for ``gmx`` tools
 ^^^^^^^^^^^^^^^^^^^^^^^
 
index 30cbe16288dbf5f2a5a459d4fe059e73d5011887..1115f4f999677e031905752cfc571dd5e34297f6 100644 (file)
@@ -2332,7 +2332,7 @@ int gmx_grompp(int argc, char *argv[])
 
     if (ir->bPull)
     {
-        pull = set_pull_init(ir, sys, as_rvec_array(state.x.data()), state.box, state.lambda[efptMASS], oenv);
+        pull = set_pull_init(ir, sys, as_rvec_array(state.x.data()), state.box, state.lambda[efptMASS], oenv, wi);
     }
 
     /* Modules that supply external potential for pull coordinates
index 88f04363007803a57b4a15ebf8c1204c466f3b97..3c4fe4149eb90dd9d0d83081aa8825fcc7cede70 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,2016,2017, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016,2017,2018, 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.
@@ -148,7 +148,8 @@ void make_pull_coords(pull_params_t *pull);
 
 pull_t *set_pull_init(t_inputrec *ir, const gmx_mtop_t *mtop,
                       rvec *x, matrix box, real lambda,
-                      const gmx_output_env_t *oenv);
+                      const gmx_output_env_t *oenv,
+                      warninp_t wi);
 /* Prints the initial pull group distances in x.
  * If requested, adds the current distance to the initial reference location.
  * Returns the pull_t pull work struct. This should be passed to finish_pull()
index f732e23395498580a08785ab0be07b156f51b708..bcd252bedbdbf68a7b348dbf7d1cf03b7b2193b1 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,2016,2017, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016,2017,2018, 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.
@@ -504,7 +504,8 @@ void make_pull_coords(pull_params_t *pull)
 
 pull_t *set_pull_init(t_inputrec *ir, const gmx_mtop_t *mtop,
                       rvec *x, matrix box, real lambda,
-                      const gmx_output_env_t *oenv)
+                      const gmx_output_env_t *oenv,
+                      warninp_t wi)
 {
     pull_params_t *pull;
     pull_t        *pull_work;
@@ -528,6 +529,19 @@ pull_t *set_pull_init(t_inputrec *ir, const gmx_mtop_t *mtop,
 
     pull_calc_coms(nullptr, pull_work, md, &pbc, t_start, x, nullptr);
 
+    int groupThatFailsPbc = pullCheckPbcWithinGroups(*pull_work, x, pbc);
+    if (groupThatFailsPbc >= 0)
+    {
+        char buf[STRLEN];
+        sprintf(buf,
+                "Pull group %d has atoms at a distance larger than %g times half the box size from the PBC atom (%d). If atoms are or will more beyond half the box size from the PBC atom, the COM will be ill defined.",
+                groupThatFailsPbc,
+                c_pullGroupPbcMargin,
+                pull->group[groupThatFailsPbc].pbcatom);
+        set_warning_line(wi, nullptr, -1);
+        warning(wi, buf);
+    }
+
     fprintf(stderr, "Pull group  natoms  pbc atom  distance at start  reference at t=0\n");
     for (c = 0; c < pull->ncoord; c++)
     {
index 900d92e58055ae4acdc45b6f7851ed25643383ad..ac423e866fef68569fe1a4903946963fe0370db2 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,2016,2017, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016,2017,2018, 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.
@@ -281,6 +281,28 @@ void pull_calc_coms(t_commrec        *cr,
                     rvec              x[],
                     rvec             *xp);
 
+/*! \brief Margin for checking PBC distances compared to half the box size in pullCheckPbcWithinGroups() */
+static constexpr real c_pullGroupPbcMargin = 0.9;
+
+/*! \brief Checks whether all groups that use a reference atom are within PBC restrictions
+ *
+ * Groups that use a reference atom for determining PBC should have all their
+ * atoms within half the box size from the PBC atom. The box size is used
+ * per dimension for rectangular boxes, but can be a combination of
+ * dimensions for triclinic boxes, depending on which dimensions are
+ * involved in the pull coordinates a group is involved in.
+ *
+ * Should be called without MPI parallelization and after pull_calc_coms()
+ * has been called at least once.
+ *
+ * \param[in] pull  The pull data structure
+ * \param[in] x     The coordinates
+ * \param[in] pbc   Information struct about periodicity
+ * \returns -1 when all groups obey PBC or the first group index that fails PBC
+ */
+int pullCheckPbcWithinGroups(const pull_t &pull,
+                             const rvec   *x,
+                             const t_pbc  &pbc);
 
 /*! \brief Returns if we have pull coordinates with potential pulling.
  *
index 0c62ff647fede330a2c2457742972a1557395f49..e86336deec1de801733f1135bb2aa53b16aaca9d 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,2016,2017, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016,2017,2018, 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.
@@ -819,3 +819,134 @@ void pull_calc_coms(t_commrec *cr,
         make_cyl_refgrps(cr, pull, md, pbc, t, x);
     }
 }
+
+using BoolVec = gmx::BasicVector<bool>;
+
+/* Returns whether the pull group obeys the PBC restrictions */
+static bool pullGroupObeysPbcRestrictions(const pull_group_work_t &group,
+                                          const BoolVec           &dimUsed,
+                                          const rvec              *x,
+                                          const t_pbc             &pbc,
+                                          const rvec              &x_pbc)
+{
+    /* Determine which dimensions are relevant for PBC */
+    BoolVec dimUsesPbc       = { false, false, false };
+    bool    pbcIsRectangular = true;
+    for (int d = 0; d < pbc.ndim_ePBC; d++)
+    {
+        if (dimUsed[d])
+        {
+            dimUsesPbc[d] = true;
+            /* All non-zero dimensions of vector v are involved in PBC */
+            for (int d2 = d + 1; d2 < pbc.ndim_ePBC; d2++)
+            {
+                assert(d2 < DIM);
+                if (pbc.box[d2][d] != 0)
+                {
+                    dimUsesPbc[d2]   = true;
+                    pbcIsRectangular = false;
+                }
+            }
+        }
+    }
+
+    rvec marginPerDim;
+    real marginDistance2 = 0;
+    if (pbcIsRectangular)
+    {
+        /* Use margins for dimensions independently */
+        for (int d = 0; d < pbc.ndim_ePBC; d++)
+        {
+            marginPerDim[d] = c_pullGroupPbcMargin*pbc.hbox_diag[d];
+        }
+    }
+    else
+    {
+        /* Check the total distance along the relevant dimensions */
+        for (int d = 0; d < pbc.ndim_ePBC; d++)
+        {
+            if (dimUsesPbc[d])
+            {
+                marginDistance2 += c_pullGroupPbcMargin*gmx::square(0.5)*norm2(pbc.box[d]);
+            }
+        }
+    }
+
+    for (int i = 0; i < group.nat_loc; i++)
+    {
+        rvec dx;
+        pbc_dx(&pbc, x[group.ind_loc[i]], x_pbc, dx);
+
+        bool atomIsTooFar = false;
+        if (pbcIsRectangular)
+        {
+            for (int d = 0; d < pbc.ndim_ePBC; d++)
+            {
+                if (dimUsesPbc[d] && (dx[d] < -marginPerDim[d] ||
+                                      dx[d] >  marginPerDim[d]))
+                {
+                    atomIsTooFar = true;
+                }
+            }
+        }
+        else
+        {
+            real pbcDistance2 = 0;
+            for (int d = 0; d < pbc.ndim_ePBC; d++)
+            {
+                if (dimUsesPbc[d])
+                {
+                    pbcDistance2 += gmx::square(dx[d]);
+                }
+            }
+            atomIsTooFar = (pbcDistance2 > marginDistance2);
+        }
+        if (atomIsTooFar)
+        {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+int pullCheckPbcWithinGroups(const pull_t &pull,
+                             const rvec   *x,
+                             const t_pbc  &pbc)
+{
+    if (pbc.ePBC == epbcNONE)
+    {
+        return -1;
+    }
+
+    /* Determine what dimensions are used for each group by pull coordinates */
+    std::vector<BoolVec> dimUsed(pull.ngroup, { false, false, false });
+    for (int c = 0; c < pull.ncoord; c++)
+    {
+        const t_pull_coord &coordParams = pull.coord[c].params;
+        for (int groupIndex = 0; groupIndex < coordParams.ngroup; groupIndex++)
+        {
+            for (int d = 0; d < DIM; d++)
+            {
+                if (coordParams.dim[d] &&
+                    !(coordParams.eGeom == epullgCYL && groupIndex == 0))
+                {
+                    dimUsed[coordParams.group[groupIndex]][d] = true;
+                }
+            }
+        }
+    }
+
+    /* Check PBC for every group that uses a PBC reference atom treatment */
+    for (int g = 0; g < pull.ngroup; g++)
+    {
+        const pull_group_work_t &group = pull.group[g];
+        if (group.epgrppbc == epgrppbcREFAT &&
+            !pullGroupObeysPbcRestrictions(group, dimUsed[g], x, pbc, pull.comm.rbuf[g]))
+        {
+            return g;
+        }
+    }
+
+    return -1;
+}