t_pull_coord *coord; /* the pull coordinates */
/* Variables not present in mdp, but used at run time */
- t_pull_group *dyna; /* dynamic groups for use with local constraints */
- rvec *rbuf; /* COM calculation buffer */
- dvec *dbuf; /* COM calculation buffer */
- double *dbuf_cyl; /* cylinder ref. groups COM calculation buffer */
+ t_pull_group *dyna; /* dynamic groups for use with local constraints */
+ gmx_bool bSetPBCatoms; /* Do we need to set x_pbc for the groups? */
- FILE *out_x; /* output file for pull data */
- FILE *out_f; /* output file for pull data */
+ rvec *rbuf; /* COM calculation buffer */
+ dvec *dbuf; /* COM calculation buffer */
+ double *dbuf_cyl; /* cylinder ref. groups COM calculation buffer */
+
+ FILE *out_x; /* output file for pull data */
+ FILE *out_f; /* output file for pull data */
} t_pull;
t_mdatoms *mdatoms,
gmx_enerdata_t *enerd,
real *lambda,
- double t)
+ double t,
+ gmx_wallcycle_t wcycle)
{
t_pbc pbc;
real dvdl;
* The virial contribution is calculated directly,
* which is why we call pull_potential after calc_virial.
*/
+ wallcycle_start(wcycle, ewcPULLPOT);
set_pbc(&pbc, ir->ePBC, box);
dvdl = 0;
enerd->term[F_COM_PULL] +=
gmx_print_sepdvdl(fplog, "Com pull", enerd->term[F_COM_PULL], dvdl);
}
enerd->dvdl_lin[efptRESTRAINT] += dvdl;
+ wallcycle_stop(wcycle, ewcPULLPOT);
}
static void pme_receive_force_ener(FILE *fplog,
if (inputrec->ePull == epullUMBRELLA || inputrec->ePull == epullCONST_F)
{
+ /* Since the COM pulling is always done mass-weighted, no forces are
+ * applied to vsites and this call can be done after vsite spreading.
+ */
pull_potential_wrapper(fplog, bSepDVDL, cr, inputrec, box, x,
- f, vir_force, mdatoms, enerd, lambda, t);
+ f, vir_force, mdatoms, enerd, lambda, t,
+ wcycle);
}
/* Add the forces from enforced rotation potentials (if any) */
if (inputrec->ePull == epullUMBRELLA || inputrec->ePull == epullCONST_F)
{
pull_potential_wrapper(fplog, bSepDVDL, cr, inputrec, box, x,
- f, vir_force, mdatoms, enerd, lambda, t);
+ f, vir_force, mdatoms, enerd, lambda, t,
+ wcycle);
}
/* Add the forces from enforced rotation potentials (if any) */
r_ij[c][m] = a*pull->coord[c].vec[m];
}
}
+
+ if (dnorm2(r_ij[c]) == 0)
+ {
+ gmx_fatal(FARGS, "Distance for pull coordinate %d is zero with constraint pulling, which is not allowed.", c + 1);
+ }
}
bConverged_all = FALSE;
double f_invr;
/* Add the pull contribution to the virial */
+ /* We have already checked above that r_ij[c] != 0 */
f_invr = pcrd->f_scal/dnorm(r_ij[c]);
for (j = 0; j < DIM; j++)
{
case epullgDIST:
ndr = dnorm(pcrd->dr);
- invdr = 1/ndr;
+ if (ndr > 0)
+ {
+ invdr = 1/ndr;
+ }
+ else
+ {
+ /* With an harmonic umbrella, the force is 0 at r=0,
+ * so we can set invdr to any value.
+ * With a constant force, the force at r=0 is not defined,
+ * so we zero it (this is anyhow a very rare event).
+ */
+ invdr = 0;
+ }
if (ePull == epullUMBRELLA)
{
pcrd->f_scal = -k*dev;
make_local_pull_group(ga2la, &pull->group[g],
0, md->homenr);
}
+
+ /* Since the PBC of atoms might have changed, we need to update the PBC */
+ pull->bSetPBCatoms = TRUE;
}
static void init_pull_group_index(FILE *fplog, t_commrec *cr,
snew(pull->dyna, pull->ncoord);
}
+ /* We still need to initialize the PBC reference coordinates */
+ pull->bSetPBCatoms = TRUE;
+
/* Only do I/O when we are doing dynamics and if we are the MASTER */
pull->out_x = NULL;
pull->out_f = NULL;
#include "gmx_ga2la.h"
static void pull_set_pbcatom(t_commrec *cr, t_pull_group *pgrp,
- t_mdatoms *md, rvec *x,
+ rvec *x,
rvec x_pbc)
{
int a, m;
- if (cr && PAR(cr))
+ if (cr != NULL && DOMAINDECOMP(cr))
{
- if (DOMAINDECOMP(cr))
- {
- if (!ga2la_get_home(cr->dd->ga2la, pgrp->pbcatom, &a))
- {
- a = -1;
- }
- }
- else
- {
- a = pgrp->pbcatom;
- }
-
- if (a >= 0 && a < md->homenr)
+ if (ga2la_get_home(cr->dd->ga2la, pgrp->pbcatom, &a))
{
copy_rvec(x[a], x_pbc);
}
}
static void pull_set_pbcatoms(t_commrec *cr, t_pull *pull,
- t_mdatoms *md, rvec *x,
+ rvec *x,
rvec *x_pbc)
{
int g, n, m;
}
else
{
- pull_set_pbcatom(cr, &pull->group[g], md, x, x_pbc[g]);
+ pull_set_pbcatom(cr, &pull->group[g], x, x_pbc[g]);
for (m = 0; m < DIM; m++)
{
if (pull->dim[m] == 0)
snew(pull->dbuf, 3*pull->ngroup);
}
- if (pull->bRefAt)
+ if (pull->bRefAt && pull->bSetPBCatoms)
{
- pull_set_pbcatoms(cr, pull, md, x, pull->rbuf);
+ pull_set_pbcatoms(cr, pull, x, pull->rbuf);
+
+ if (cr != NULL && DOMAINDECOMP(cr))
+ {
+ /* We can keep these PBC reference coordinates fixed for nstlist
+ * steps, since atoms won't jump over PBC.
+ * This avoids a global reduction at the next nstlist-1 steps.
+ * Note that the exact values of the pbc reference coordinates
+ * are irrelevant, as long all atoms in the group are within
+ * half a box distance of the reference coordinate.
+ */
+ pull->bSetPBCatoms = FALSE;
+ }
}
if (pull->cosdim >= 0)
"Comm. coord.", "Born radii", "Force", "Wait + Comm. F", "PME mesh",
"PME redist. X/F", "PME spread/gather", "PME 3D-FFT", "PME 3D-FFT Comm.", "PME solve LJ", "PME solve Elec",
"PME wait for PP", "Wait + Recv. PME F", "Wait GPU nonlocal", "Wait GPU local", "NB X/F buffer ops.",
- "Vsite spread", "Write traj.", "Update", "Constraints", "Comm. energies",
+ "Vsite spread", "COM pull force",
+ "Write traj.", "Update", "Constraints", "Comm. energies",
"Enforced rotation", "Add rot. forces", "Coordinate swapping", "IMD", "Test"
};
ewcMOVEX, ewcGB, ewcFORCE, ewcMOVEF, ewcPMEMESH,
ewcPME_REDISTXF, ewcPME_SPREADGATHER, ewcPME_FFT, ewcPME_FFTCOMM, ewcLJPME, ewcPME_SOLVE,
ewcPMEWAITCOMM, ewcPP_PMEWAITRECVF, ewcWAIT_GPU_NB_NL, ewcWAIT_GPU_NB_L, ewcNB_XF_BUF_OPS,
- ewcVSITESPREAD, ewcTRAJ, ewcUPDATE, ewcCONSTR, ewcMoveE, ewcROT, ewcROTadd, ewcSWAP, ewcIMD,
+ ewcVSITESPREAD, ewcPULLPOT,
+ ewcTRAJ, ewcUPDATE, ewcCONSTR, ewcMoveE, ewcROT, ewcROTadd, ewcSWAP, ewcIMD,
ewcTEST, ewcNR
};