Remove all unnecessary HAVE_CONFIG_H
[gromacs.git] / src / gromacs / pulling / pull.c
blob677c48fa5d5864991ee7f0eb284c968c76667f36
1 /*
2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5 * Copyright (c) 2001-2004, The GROMACS development team.
6 * Copyright (c) 2013,2014, by the GROMACS development team, led by
7 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8 * and including many others, as listed in the AUTHORS file in the
9 * top-level source directory and at http://www.gromacs.org.
11 * GROMACS is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public License
13 * as published by the Free Software Foundation; either version 2.1
14 * of the License, or (at your option) any later version.
16 * GROMACS is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with GROMACS; if not, see
23 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 * If you want to redistribute modifications to GROMACS, please
27 * consider that scientific software is very special. Version
28 * control is crucial - bugs must be traceable. We will be happy to
29 * consider code for inclusion in the official distribution, but
30 * derived work must not be called official GROMACS. Details are found
31 * in the README & COPYING files - if they are missing, get the
32 * official version at http://www.gromacs.org.
34 * To help us fund GROMACS development, we humbly ask that you cite
35 * the research papers on the package. Check out http://www.gromacs.org.
37 #include "config.h"
39 #include <math.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
44 #include "gromacs/utility/futil.h"
45 #include "typedefs.h"
46 #include "types/commrec.h"
47 #include "network.h"
48 #include "pull.h"
49 #include "names.h"
50 #include "gromacs/pbcutil/pbc.h"
51 #include "gromacs/topology/mtop_util.h"
52 #include "mdrun.h"
53 #include "gmx_ga2la.h"
54 #include "copyrite.h"
55 #include "macros.h"
57 #include "gromacs/fileio/filenm.h"
58 #include "gromacs/fileio/gmxfio.h"
59 #include "gromacs/fileio/xvgr.h"
60 #include "gromacs/math/vec.h"
61 #include "gromacs/utility/smalloc.h"
63 static void pull_print_group_x(FILE *out, ivec dim, const t_pull_group *pgrp)
65 int m;
67 for (m = 0; m < DIM; m++)
69 if (dim[m])
71 fprintf(out, "\t%g", pgrp->x[m]);
76 static void pull_print_coord_dr(FILE *out, ivec dim, const t_pull_coord *pcrd)
78 int m;
80 for (m = 0; m < DIM; m++)
82 if (dim[m])
84 fprintf(out, "\t%g", pcrd->dr[m]);
89 static void pull_print_x(FILE *out, t_pull *pull, double t)
91 int c;
92 const t_pull_coord *pcrd;
94 fprintf(out, "%.4f", t);
96 for (c = 0; c < pull->ncoord; c++)
98 pcrd = &pull->coord[c];
100 if (pull->bPrintRef)
102 if (PULL_CYL(pull))
104 pull_print_group_x(out, pull->dim, &pull->dyna[c]);
106 else
108 pull_print_group_x(out, pull->dim, &pull->group[pcrd->group[0]]);
111 pull_print_coord_dr(out, pull->dim, pcrd);
113 fprintf(out, "\n");
116 static void pull_print_f(FILE *out, t_pull *pull, double t)
118 int c, d;
120 fprintf(out, "%.4f", t);
122 for (c = 0; c < pull->ncoord; c++)
124 fprintf(out, "\t%g", pull->coord[c].f_scal);
126 fprintf(out, "\n");
129 void pull_print_output(t_pull *pull, gmx_int64_t step, double time)
131 if ((pull->nstxout != 0) && (step % pull->nstxout == 0))
133 pull_print_x(pull->out_x, pull, time);
136 if ((pull->nstfout != 0) && (step % pull->nstfout == 0))
138 pull_print_f(pull->out_f, pull, time);
142 static FILE *open_pull_out(const char *fn, t_pull *pull, const output_env_t oenv,
143 gmx_bool bCoord, unsigned long Flags)
145 FILE *fp;
146 int nsets, c, m;
147 char **setname, buf[10];
149 if (Flags & MD_APPENDFILES)
151 fp = gmx_fio_fopen(fn, "a+");
153 else
155 fp = gmx_fio_fopen(fn, "w+");
156 if (bCoord)
158 xvgr_header(fp, "Pull COM", "Time (ps)", "Position (nm)",
159 exvggtXNY, oenv);
161 else
163 xvgr_header(fp, "Pull force", "Time (ps)", "Force (kJ/mol/nm)",
164 exvggtXNY, oenv);
167 snew(setname, 2*pull->ncoord*DIM);
168 nsets = 0;
169 for (c = 0; c < pull->ncoord; c++)
171 if (bCoord)
173 if (pull->bPrintRef)
175 for (m = 0; m < DIM; m++)
177 if (pull->dim[m])
179 sprintf(buf, "%d %s%c", c+1, "c", 'X'+m);
180 setname[nsets] = strdup(buf);
181 nsets++;
185 for (m = 0; m < DIM; m++)
187 if (pull->dim[m])
189 sprintf(buf, "%d %s%c", c+1, "d", 'X'+m);
190 setname[nsets] = strdup(buf);
191 nsets++;
195 else
197 sprintf(buf, "%d", c+1);
198 setname[nsets] = strdup(buf);
199 nsets++;
202 if (nsets > 1)
204 xvgr_legend(fp, nsets, (const char**)setname, oenv);
206 for (c = 0; c < nsets; c++)
208 sfree(setname[c]);
210 sfree(setname);
213 return fp;
216 /* Apply forces in a mass weighted fashion */
217 static void apply_forces_grp(const t_pull_group *pgrp, const t_mdatoms *md,
218 const dvec f_pull, int sign, rvec *f)
220 int i, ii, m;
221 double wmass, inv_wm;
223 inv_wm = pgrp->wscale*pgrp->invtm;
225 for (i = 0; i < pgrp->nat_loc; i++)
227 ii = pgrp->ind_loc[i];
228 wmass = md->massT[ii];
229 if (pgrp->weight_loc)
231 wmass *= pgrp->weight_loc[i];
234 for (m = 0; m < DIM; m++)
236 f[ii][m] += sign * wmass * f_pull[m] * inv_wm;
241 /* Apply forces in a mass weighted fashion */
242 static void apply_forces(t_pull * pull, t_mdatoms * md, rvec *f)
244 int c;
245 const t_pull_coord *pcrd;
247 for (c = 0; c < pull->ncoord; c++)
249 pcrd = &pull->coord[c];
251 if (PULL_CYL(pull))
253 apply_forces_grp(&pull->dyna[c], md, pcrd->f, -1, f);
255 else
257 if (pull->group[pcrd->group[0]].nat > 0)
259 apply_forces_grp(&pull->group[pcrd->group[0]], md, pcrd->f, -1, f);
262 apply_forces_grp(&pull->group[pcrd->group[1]], md, pcrd->f, 1, f);
266 static double max_pull_distance2(const t_pull *pull, const t_pbc *pbc)
268 double max_d2;
269 int m;
271 max_d2 = GMX_DOUBLE_MAX;
273 if (pull->eGeom != epullgDIRPBC)
275 for (m = 0; m < pbc->ndim_ePBC; m++)
277 if (pull->dim[m] != 0)
279 max_d2 = min(max_d2, norm2(pbc->box[m]));
284 return 0.25*max_d2;
287 static void low_get_pull_coord_dr(const t_pull *pull,
288 const t_pull_coord *pcrd,
289 const t_pbc *pbc, double t,
290 dvec xg, dvec xref, double max_dist2,
291 dvec dr)
293 const t_pull_group *pgrp0, *pgrp1;
294 int m;
295 dvec xrefr, dref = {0, 0, 0};
296 double dr2;
298 pgrp0 = &pull->group[pcrd->group[0]];
299 pgrp1 = &pull->group[pcrd->group[1]];
301 /* Only the first group can be an absolute reference, in that case nat=0 */
302 if (pgrp0->nat == 0)
304 for (m = 0; m < DIM; m++)
306 xref[m] = pcrd->origin[m];
310 copy_dvec(xref, xrefr);
312 if (pull->eGeom == epullgDIRPBC)
314 for (m = 0; m < DIM; m++)
316 dref[m] = (pcrd->init + pcrd->rate*t)*pcrd->vec[m];
318 /* Add the reference position, so we use the correct periodic image */
319 dvec_inc(xrefr, dref);
322 pbc_dx_d(pbc, xg, xrefr, dr);
323 dr2 = 0;
324 for (m = 0; m < DIM; m++)
326 dr[m] *= pull->dim[m];
327 dr2 += dr[m]*dr[m];
329 if (max_dist2 >= 0 && dr2 > 0.98*0.98*max_dist2)
331 gmx_fatal(FARGS, "Distance between pull groups %d and %d (%f nm) is larger than 0.49 times the box size (%f).\nYou might want to consider using \"pull-geometry = direction-periodic\" instead.\n",
332 pcrd->group[0], pcrd->group[1], sqrt(dr2), sqrt(max_dist2));
335 if (pull->eGeom == epullgDIRPBC)
337 dvec_inc(dr, dref);
341 static void get_pull_coord_dr(const t_pull *pull,
342 int coord_ind,
343 const t_pbc *pbc, double t,
344 dvec dr)
346 double md2;
347 const t_pull_coord *pcrd;
349 if (pull->eGeom == epullgDIRPBC)
351 md2 = -1;
353 else
355 md2 = max_pull_distance2(pull, pbc);
358 pcrd = &pull->coord[coord_ind];
360 low_get_pull_coord_dr(pull, pcrd, pbc, t,
361 pull->group[pcrd->group[1]].x,
362 PULL_CYL(pull) ? pull->dyna[coord_ind].x : pull->group[pcrd->group[0]].x,
363 md2,
364 dr);
367 void get_pull_coord_distance(const t_pull *pull,
368 int coord_ind,
369 const t_pbc *pbc, double t,
370 dvec dr, double *dev)
372 static gmx_bool bWarned = FALSE; /* TODO: this should be fixed for thread-safety,
373 but is fairly benign */
374 const t_pull_coord *pcrd;
375 int m;
376 double ref, drs, inpr;
378 pcrd = &pull->coord[coord_ind];
380 get_pull_coord_dr(pull, coord_ind, pbc, t, dr);
382 ref = pcrd->init + pcrd->rate*t;
384 switch (pull->eGeom)
386 case epullgDIST:
387 /* Pull along the vector between the com's */
388 if (ref < 0 && !bWarned)
390 fprintf(stderr, "\nPull reference distance for coordinate %d is negative (%f)\n", coord_ind+1, ref);
391 bWarned = TRUE;
393 drs = dnorm(dr);
394 if (drs == 0)
396 /* With no vector we can not determine the direction for the force,
397 * so we set the force to zero.
399 *dev = 0;
401 else
403 /* Determine the deviation */
404 *dev = drs - ref;
406 break;
407 case epullgDIR:
408 case epullgDIRPBC:
409 case epullgCYL:
410 /* Pull along vec */
411 inpr = 0;
412 for (m = 0; m < DIM; m++)
414 inpr += pcrd->vec[m]*dr[m];
416 *dev = inpr - ref;
417 break;
421 void clear_pull_forces(t_pull *pull)
423 int i;
425 /* Zeroing the forces is only required for constraint pulling.
426 * It can happen that multiple constraint steps need to be applied
427 * and therefore the constraint forces need to be accumulated.
429 for (i = 0; i < pull->ncoord; i++)
431 clear_dvec(pull->coord[i].f);
432 pull->coord[i].f_scal = 0;
436 /* Apply constraint using SHAKE */
437 static void do_constraint(t_pull *pull, t_pbc *pbc,
438 rvec *x, rvec *v,
439 gmx_bool bMaster, tensor vir,
440 double dt, double t)
443 dvec *r_ij; /* x[i] com of i in prev. step. Obeys constr. -> r_ij[i] */
444 dvec unc_ij; /* xp[i] com of i this step, before constr. -> unc_ij */
445 dvec *rnew; /* current 'new' positions of the groups */
446 double *dr_tot; /* the total update of the coords */
447 double ref;
448 dvec vec;
449 double d0, inpr;
450 double lambda, rm, mass, invdt = 0;
451 gmx_bool bConverged_all, bConverged = FALSE;
452 int niter = 0, g, c, ii, j, m, max_iter = 100;
453 double a;
454 dvec f; /* the pull force */
455 dvec tmp, tmp3;
456 t_pull_group *pdyna, *pgrp0, *pgrp1;
457 t_pull_coord *pcrd;
459 snew(r_ij, pull->ncoord);
460 snew(dr_tot, pull->ncoord);
462 snew(rnew, pull->ngroup);
464 /* copy the current unconstrained positions for use in iterations. We
465 iterate until rinew[i] and rjnew[j] obey the constraints. Then
466 rinew - pull.x_unc[i] is the correction dr to group i */
467 for (g = 0; g < pull->ngroup; g++)
469 copy_dvec(pull->group[g].xp, rnew[g]);
471 if (PULL_CYL(pull))
473 /* There is only one pull coordinate and reference group */
474 copy_dvec(pull->dyna[0].xp, rnew[pull->coord[0].group[0]]);
477 /* Determine the constraint directions from the old positions */
478 for (c = 0; c < pull->ncoord; c++)
480 get_pull_coord_dr(pull, c, pbc, t, r_ij[c]);
481 /* Store the difference vector at time t for printing */
482 copy_dvec(r_ij[c], pull->coord[c].dr);
483 if (debug)
485 fprintf(debug, "Pull coord %d dr %f %f %f\n",
486 c, r_ij[c][XX], r_ij[c][YY], r_ij[c][ZZ]);
489 if (pull->eGeom == epullgDIR || pull->eGeom == epullgDIRPBC)
491 /* Select the component along vec */
492 a = 0;
493 for (m = 0; m < DIM; m++)
495 a += pull->coord[c].vec[m]*r_ij[c][m];
497 for (m = 0; m < DIM; m++)
499 r_ij[c][m] = a*pull->coord[c].vec[m];
504 bConverged_all = FALSE;
505 while (!bConverged_all && niter < max_iter)
507 bConverged_all = TRUE;
509 /* loop over all constraints */
510 for (c = 0; c < pull->ncoord; c++)
512 dvec dr0, dr1;
514 pcrd = &pull->coord[c];
515 pgrp0 = &pull->group[pcrd->group[0]];
516 pgrp1 = &pull->group[pcrd->group[1]];
518 /* Get the current difference vector */
519 low_get_pull_coord_dr(pull, pcrd, pbc, t,
520 rnew[pcrd->group[1]],
521 rnew[pcrd->group[0]],
522 -1, unc_ij);
524 ref = pcrd->init + pcrd->rate*t;
526 if (debug)
528 fprintf(debug, "Pull coord %d, iteration %d\n", c, niter);
531 rm = 1.0/(pgrp0->invtm + pgrp1->invtm);
533 switch (pull->eGeom)
535 case epullgDIST:
536 if (ref <= 0)
538 gmx_fatal(FARGS, "The pull constraint reference distance for group %d is <= 0 (%f)", c, ref);
542 double q, c_a, c_b, c_c;
544 c_a = diprod(r_ij[c], r_ij[c]);
545 c_b = diprod(unc_ij, r_ij[c])*2;
546 c_c = diprod(unc_ij, unc_ij) - dsqr(ref);
548 if (c_b < 0)
550 q = -0.5*(c_b - sqrt(c_b*c_b - 4*c_a*c_c));
551 lambda = -q/c_a;
553 else
555 q = -0.5*(c_b + sqrt(c_b*c_b - 4*c_a*c_c));
556 lambda = -c_c/q;
559 if (debug)
561 fprintf(debug,
562 "Pull ax^2+bx+c=0: a=%e b=%e c=%e lambda=%e\n",
563 c_a, c_b, c_c, lambda);
567 /* The position corrections dr due to the constraints */
568 dsvmul(-lambda*rm*pgrp1->invtm, r_ij[c], dr1);
569 dsvmul( lambda*rm*pgrp0->invtm, r_ij[c], dr0);
570 dr_tot[c] += -lambda*dnorm(r_ij[c]);
571 break;
572 case epullgDIR:
573 case epullgDIRPBC:
574 case epullgCYL:
575 /* A 1-dimensional constraint along a vector */
576 a = 0;
577 for (m = 0; m < DIM; m++)
579 vec[m] = pcrd->vec[m];
580 a += unc_ij[m]*vec[m];
582 /* Select only the component along the vector */
583 dsvmul(a, vec, unc_ij);
584 lambda = a - ref;
585 if (debug)
587 fprintf(debug, "Pull inpr %e lambda: %e\n", a, lambda);
590 /* The position corrections dr due to the constraints */
591 dsvmul(-lambda*rm*pgrp1->invtm, vec, dr1);
592 dsvmul( lambda*rm*pgrp0->invtm, vec, dr0);
593 dr_tot[c] += -lambda;
594 break;
597 /* DEBUG */
598 if (debug)
600 int g0, g1;
602 g0 = pcrd->group[0];
603 g1 = pcrd->group[1];
604 low_get_pull_coord_dr(pull, pcrd, pbc, t, rnew[g1], rnew[g0], -1, tmp);
605 low_get_pull_coord_dr(pull, pcrd, pbc, t, dr1, dr0, -1, tmp3);
606 fprintf(debug,
607 "Pull cur %8.5f %8.5f %8.5f j:%8.5f %8.5f %8.5f d: %8.5f\n",
608 rnew[g0][0], rnew[g0][1], rnew[g0][2],
609 rnew[g1][0], rnew[g1][1], rnew[g1][2], dnorm(tmp));
610 fprintf(debug,
611 "Pull ref %8s %8s %8s %8s %8s %8s d: %8.5f\n",
612 "", "", "", "", "", "", ref);
613 fprintf(debug,
614 "Pull cor %8.5f %8.5f %8.5f j:%8.5f %8.5f %8.5f d: %8.5f\n",
615 dr0[0], dr0[1], dr0[2],
616 dr1[0], dr1[1], dr1[2],
617 dnorm(tmp3));
618 } /* END DEBUG */
620 /* Update the COMs with dr */
621 dvec_inc(rnew[pcrd->group[1]], dr1);
622 dvec_inc(rnew[pcrd->group[0]], dr0);
625 /* Check if all constraints are fullfilled now */
626 for (c = 0; c < pull->ncoord; c++)
628 pcrd = &pull->coord[c];
629 ref = pcrd->init + pcrd->rate*t;
631 low_get_pull_coord_dr(pull, pcrd, pbc, t,
632 rnew[pcrd->group[1]],
633 rnew[pcrd->group[0]],
634 -1, unc_ij);
636 switch (pull->eGeom)
638 case epullgDIST:
639 bConverged = fabs(dnorm(unc_ij) - ref) < pull->constr_tol;
640 break;
641 case epullgDIR:
642 case epullgDIRPBC:
643 case epullgCYL:
644 for (m = 0; m < DIM; m++)
646 vec[m] = pcrd->vec[m];
648 inpr = diprod(unc_ij, vec);
649 dsvmul(inpr, vec, unc_ij);
650 bConverged =
651 fabs(diprod(unc_ij, vec) - ref) < pull->constr_tol;
652 break;
655 if (!bConverged)
657 if (debug)
659 fprintf(debug, "NOT CONVERGED YET: Group %d:"
660 "d_ref = %f, current d = %f\n",
661 g, ref, dnorm(unc_ij));
664 bConverged_all = FALSE;
668 niter++;
669 /* if after all constraints are dealt with and bConverged is still TRUE
670 we're finished, if not we do another iteration */
672 if (niter > max_iter)
674 gmx_fatal(FARGS, "Too many iterations for constraint run: %d", niter);
677 /* DONE ITERATING, NOW UPDATE COORDINATES AND CALC. CONSTRAINT FORCES */
679 if (v)
681 invdt = 1/dt;
684 /* update atoms in the groups */
685 for (g = 0; g < pull->ngroup; g++)
687 const t_pull_group *pgrp;
688 dvec dr;
690 if (PULL_CYL(pull) && g == pull->coord[0].group[0])
692 pgrp = &pull->dyna[0];
694 else
696 pgrp = &pull->group[g];
699 /* get the final constraint displacement dr for group g */
700 dvec_sub(rnew[g], pgrp->xp, dr);
701 /* select components of dr */
702 for (m = 0; m < DIM; m++)
704 dr[m] *= pull->dim[m];
707 /* update the atom positions */
708 copy_dvec(dr, tmp);
709 for (j = 0; j < pgrp->nat_loc; j++)
711 ii = pgrp->ind_loc[j];
712 if (pgrp->weight_loc)
714 dsvmul(pgrp->wscale*pgrp->weight_loc[j], dr, tmp);
716 for (m = 0; m < DIM; m++)
718 x[ii][m] += tmp[m];
720 if (v)
722 for (m = 0; m < DIM; m++)
724 v[ii][m] += invdt*tmp[m];
730 /* calculate the constraint forces, used for output and virial only */
731 for (c = 0; c < pull->ncoord; c++)
733 pcrd = &pull->coord[c];
734 pcrd->f_scal = dr_tot[c]/((pull->group[pcrd->group[0]].invtm + pull->group[pcrd->group[1]].invtm)*dt*dt);
736 if (vir && bMaster)
738 double f_invr;
740 /* Add the pull contribution to the virial */
741 f_invr = pcrd->f_scal/dnorm(r_ij[c]);
743 for (j = 0; j < DIM; j++)
745 for (m = 0; m < DIM; m++)
747 vir[j][m] -= 0.5*f_invr*r_ij[c][j]*r_ij[c][m];
753 /* finished! I hope. Give back some memory */
754 sfree(r_ij);
755 sfree(dr_tot);
756 sfree(rnew);
759 /* Pulling with a harmonic umbrella potential or constant force */
760 static void do_pull_pot(int ePull,
761 t_pull *pull, t_pbc *pbc, double t, real lambda,
762 real *V, tensor vir, real *dVdl)
764 int c, j, m;
765 double dev, ndr, invdr;
766 real k, dkdl;
767 t_pull_coord *pcrd;
769 /* loop over the pull coordinates */
770 *V = 0;
771 *dVdl = 0;
772 for (c = 0; c < pull->ncoord; c++)
774 pcrd = &pull->coord[c];
776 get_pull_coord_distance(pull, c, pbc, t, pcrd->dr, &dev);
778 k = (1.0 - lambda)*pcrd->k + lambda*pcrd->kB;
779 dkdl = pcrd->kB - pcrd->k;
781 switch (pull->eGeom)
783 case epullgDIST:
784 ndr = dnorm(pcrd->dr);
785 invdr = 1/ndr;
786 if (ePull == epullUMBRELLA)
788 pcrd->f_scal = -k*dev;
789 *V += 0.5* k*dsqr(dev);
790 *dVdl += 0.5*dkdl*dsqr(dev);
792 else
794 pcrd->f_scal = -k;
795 *V += k*ndr;
796 *dVdl += dkdl*ndr;
798 for (m = 0; m < DIM; m++)
800 pcrd->f[m] = pcrd->f_scal*pcrd->dr[m]*invdr;
802 break;
803 case epullgDIR:
804 case epullgDIRPBC:
805 case epullgCYL:
806 if (ePull == epullUMBRELLA)
808 pcrd->f_scal = -k*dev;
809 *V += 0.5* k*dsqr(dev);
810 *dVdl += 0.5*dkdl*dsqr(dev);
812 else
814 ndr = 0;
815 for (m = 0; m < DIM; m++)
817 ndr += pcrd->vec[m]*pcrd->dr[m];
819 pcrd->f_scal = -k;
820 *V += k*ndr;
821 *dVdl += dkdl*ndr;
823 for (m = 0; m < DIM; m++)
825 pcrd->f[m] = pcrd->f_scal*pcrd->vec[m];
827 break;
830 if (vir)
832 /* Add the pull contribution to the virial */
833 for (j = 0; j < DIM; j++)
835 for (m = 0; m < DIM; m++)
837 vir[j][m] -= 0.5*pcrd->f[j]*pcrd->dr[m];
844 real pull_potential(int ePull, t_pull *pull, t_mdatoms *md, t_pbc *pbc,
845 t_commrec *cr, double t, real lambda,
846 rvec *x, rvec *f, tensor vir, real *dvdlambda)
848 real V, dVdl;
850 pull_calc_coms(cr, pull, md, pbc, t, x, NULL);
852 do_pull_pot(ePull, pull, pbc, t, lambda,
853 &V, pull->bVirial && MASTER(cr) ? vir : NULL, &dVdl);
855 /* Distribute forces over pulled groups */
856 apply_forces(pull, md, f);
858 if (MASTER(cr))
860 *dvdlambda += dVdl;
863 return (MASTER(cr) ? V : 0.0);
866 void pull_constraint(t_pull *pull, t_mdatoms *md, t_pbc *pbc,
867 t_commrec *cr, double dt, double t,
868 rvec *x, rvec *xp, rvec *v, tensor vir)
870 pull_calc_coms(cr, pull, md, pbc, t, x, xp);
872 do_constraint(pull, pbc, xp, v, pull->bVirial && MASTER(cr), vir, dt, t);
875 static void make_local_pull_group(gmx_ga2la_t ga2la,
876 t_pull_group *pg, int start, int end)
878 int i, ii;
880 pg->nat_loc = 0;
881 for (i = 0; i < pg->nat; i++)
883 ii = pg->ind[i];
884 if (ga2la)
886 if (!ga2la_get_home(ga2la, ii, &ii))
888 ii = -1;
891 if (ii >= start && ii < end)
893 /* This is a home atom, add it to the local pull group */
894 if (pg->nat_loc >= pg->nalloc_loc)
896 pg->nalloc_loc = over_alloc_dd(pg->nat_loc+1);
897 srenew(pg->ind_loc, pg->nalloc_loc);
898 if (pg->epgrppbc == epgrppbcCOS || pg->weight)
900 srenew(pg->weight_loc, pg->nalloc_loc);
903 pg->ind_loc[pg->nat_loc] = ii;
904 if (pg->weight)
906 pg->weight_loc[pg->nat_loc] = pg->weight[i];
908 pg->nat_loc++;
913 void dd_make_local_pull_groups(gmx_domdec_t *dd, t_pull *pull, t_mdatoms *md)
915 gmx_ga2la_t ga2la;
916 int g;
918 if (dd)
920 ga2la = dd->ga2la;
922 else
924 ga2la = NULL;
927 for (g = 0; g < pull->ngroup; g++)
929 make_local_pull_group(ga2la, &pull->group[g],
930 0, md->homenr);
934 static void init_pull_group_index(FILE *fplog, t_commrec *cr,
935 int g, t_pull_group *pg, ivec pulldims,
936 gmx_mtop_t *mtop, t_inputrec *ir, real lambda)
938 int i, ii, d, nfrozen, ndim;
939 real m, w, mbd;
940 double tmass, wmass, wwmass;
941 gmx_groups_t *groups;
942 gmx_mtop_atomlookup_t alook;
943 t_atom *atom;
945 if (EI_ENERGY_MINIMIZATION(ir->eI) || ir->eI == eiBD)
947 /* There are no masses in the integrator.
948 * But we still want to have the correct mass-weighted COMs.
949 * So we store the real masses in the weights.
950 * We do not set nweight, so these weights do not end up in the tpx file.
952 if (pg->nweight == 0)
954 snew(pg->weight, pg->nat);
958 if (cr && PAR(cr))
960 pg->nat_loc = 0;
961 pg->nalloc_loc = 0;
962 pg->ind_loc = NULL;
963 pg->weight_loc = NULL;
965 else
967 pg->nat_loc = pg->nat;
968 pg->ind_loc = pg->ind;
969 if (pg->epgrppbc == epgrppbcCOS)
971 snew(pg->weight_loc, pg->nat);
973 else
975 pg->weight_loc = pg->weight;
979 groups = &mtop->groups;
981 alook = gmx_mtop_atomlookup_init(mtop);
983 nfrozen = 0;
984 tmass = 0;
985 wmass = 0;
986 wwmass = 0;
987 for (i = 0; i < pg->nat; i++)
989 ii = pg->ind[i];
990 gmx_mtop_atomnr_to_atom(alook, ii, &atom);
991 if (ir->opts.nFreeze)
993 for (d = 0; d < DIM; d++)
995 if (pulldims[d] && ir->opts.nFreeze[ggrpnr(groups, egcFREEZE, ii)][d])
997 nfrozen++;
1001 if (ir->efep == efepNO)
1003 m = atom->m;
1005 else
1007 m = (1 - lambda)*atom->m + lambda*atom->mB;
1009 if (pg->nweight > 0)
1011 w = pg->weight[i];
1013 else
1015 w = 1;
1017 if (EI_ENERGY_MINIMIZATION(ir->eI))
1019 /* Move the mass to the weight */
1020 w *= m;
1021 m = 1;
1022 pg->weight[i] = w;
1024 else if (ir->eI == eiBD)
1026 if (ir->bd_fric)
1028 mbd = ir->bd_fric*ir->delta_t;
1030 else
1032 if (groups->grpnr[egcTC] == NULL)
1034 mbd = ir->delta_t/ir->opts.tau_t[0];
1036 else
1038 mbd = ir->delta_t/ir->opts.tau_t[groups->grpnr[egcTC][ii]];
1041 w *= m/mbd;
1042 m = mbd;
1043 pg->weight[i] = w;
1045 tmass += m;
1046 wmass += m*w;
1047 wwmass += m*w*w;
1050 gmx_mtop_atomlookup_destroy(alook);
1052 if (wmass == 0)
1054 gmx_fatal(FARGS, "The total%s mass of pull group %d is zero",
1055 pg->weight ? " weighted" : "", g);
1057 if (fplog)
1059 fprintf(fplog,
1060 "Pull group %d: %5d atoms, mass %9.3f", g, pg->nat, tmass);
1061 if (pg->weight || EI_ENERGY_MINIMIZATION(ir->eI) || ir->eI == eiBD)
1063 fprintf(fplog, ", weighted mass %9.3f", wmass*wmass/wwmass);
1065 if (pg->epgrppbc == epgrppbcCOS)
1067 fprintf(fplog, ", cosine weighting will be used");
1069 fprintf(fplog, "\n");
1072 if (nfrozen == 0)
1074 /* A value > 0 signals not frozen, it is updated later */
1075 pg->invtm = 1.0;
1077 else
1079 ndim = 0;
1080 for (d = 0; d < DIM; d++)
1082 ndim += pulldims[d]*pg->nat;
1084 if (fplog && nfrozen > 0 && nfrozen < ndim)
1086 fprintf(fplog,
1087 "\nWARNING: In pull group %d some, but not all of the degrees of freedom\n"
1088 " that are subject to pulling are frozen.\n"
1089 " For pulling the whole group will be frozen.\n\n",
1092 pg->invtm = 0.0;
1093 pg->wscale = 1.0;
1097 void init_pull(FILE *fplog, t_inputrec *ir, int nfile, const t_filenm fnm[],
1098 gmx_mtop_t *mtop, t_commrec *cr, const output_env_t oenv, real lambda,
1099 gmx_bool bOutFile, unsigned long Flags)
1101 t_pull *pull;
1102 t_pull_group *pgrp;
1103 int c, g, start = 0, end = 0, m;
1105 pull = ir->pull;
1107 pull->ePBC = ir->ePBC;
1108 switch (pull->ePBC)
1110 case epbcNONE: pull->npbcdim = 0; break;
1111 case epbcXY: pull->npbcdim = 2; break;
1112 default: pull->npbcdim = 3; break;
1115 if (fplog)
1117 gmx_bool bAbs, bCos;
1119 bAbs = FALSE;
1120 for (c = 0; c < pull->ncoord; c++)
1122 if (pull->group[pull->coord[c].group[0]].nat == 0 ||
1123 pull->group[pull->coord[c].group[1]].nat == 0)
1125 bAbs = TRUE;
1129 fprintf(fplog, "\nWill apply %s COM pulling in geometry '%s'\n",
1130 EPULLTYPE(ir->ePull), EPULLGEOM(pull->eGeom));
1131 fprintf(fplog, "with %d pull coordinate%s and %d group%s\n",
1132 pull->ncoord, pull->ncoord == 1 ? "" : "s",
1133 pull->ngroup, pull->ngroup == 1 ? "" : "s");
1134 if (bAbs)
1136 fprintf(fplog, "with an absolute reference\n");
1138 bCos = FALSE;
1139 for (g = 0; g < pull->ngroup; g++)
1141 if (pull->group[g].nat > 1 &&
1142 pull->group[g].pbcatom < 0)
1144 /* We are using cosine weighting */
1145 fprintf(fplog, "Cosine weighting is used for group %d\n", g);
1146 bCos = TRUE;
1149 if (bCos)
1151 please_cite(fplog, "Engin2010");
1155 /* We always add the virial contribution,
1156 * except for geometry = direction_periodic where this is impossible.
1158 pull->bVirial = (pull->eGeom != epullgDIRPBC);
1159 if (getenv("GMX_NO_PULLVIR") != NULL)
1161 if (fplog)
1163 fprintf(fplog, "Found env. var., will not add the virial contribution of the COM pull forces\n");
1165 pull->bVirial = FALSE;
1168 pull->rbuf = NULL;
1169 pull->dbuf = NULL;
1170 pull->dbuf_cyl = NULL;
1171 pull->bRefAt = FALSE;
1172 pull->cosdim = -1;
1173 for (g = 0; g < pull->ngroup; g++)
1175 pgrp = &pull->group[g];
1176 pgrp->epgrppbc = epgrppbcNONE;
1177 if (pgrp->nat > 0)
1179 /* Determine if we need to take PBC into account for calculating
1180 * the COM's of the pull groups.
1182 for (m = 0; m < pull->npbcdim; m++)
1184 if (pull->dim[m] && pgrp->nat > 1)
1186 if (pgrp->pbcatom >= 0)
1188 pgrp->epgrppbc = epgrppbcREFAT;
1189 pull->bRefAt = TRUE;
1191 else
1193 if (pgrp->weight)
1195 gmx_fatal(FARGS, "Pull groups can not have relative weights and cosine weighting at same time");
1197 pgrp->epgrppbc = epgrppbcCOS;
1198 if (pull->cosdim >= 0 && pull->cosdim != m)
1200 gmx_fatal(FARGS, "Can only use cosine weighting with pulling in one dimension (use mdp option pull_dim)");
1202 pull->cosdim = m;
1206 /* Set the indices */
1207 init_pull_group_index(fplog, cr, g, pgrp, pull->dim, mtop, ir, lambda);
1208 if (PULL_CYL(pull) && pgrp->invtm == 0)
1210 gmx_fatal(FARGS, "Can not have frozen atoms in a cylinder pull group");
1213 else
1215 /* Absolute reference, set the inverse mass to zero */
1216 pgrp->invtm = 0;
1217 pgrp->wscale = 1;
1221 /* if we use dynamic reference groups, do some initialising for them */
1222 if (PULL_CYL(pull))
1224 if (ir->ePull == epullCONSTRAINT && pull->ncoord > 1)
1226 /* We can't easily update the single reference group with multiple
1227 * constraints. This would require recalculating COMs.
1229 gmx_fatal(FARGS, "Constraint COM pulling supports only one coordinate with geometry=cylinder, you can use umbrella pulling with multiple coordinates");
1232 for (c = 0; c < pull->ncoord; c++)
1234 if (pull->group[pull->coord[c].group[0]].nat == 0)
1236 gmx_fatal(FARGS, "Dynamic reference groups are not supported when using absolute reference!\n");
1240 snew(pull->dyna, pull->ncoord);
1243 /* Only do I/O when we are doing dynamics and if we are the MASTER */
1244 pull->out_x = NULL;
1245 pull->out_f = NULL;
1246 if (bOutFile)
1248 if (pull->nstxout > 0)
1250 pull->out_x = open_pull_out(opt2fn("-px", nfile, fnm), pull, oenv, TRUE, Flags);
1252 if (pull->nstfout > 0)
1254 pull->out_f = open_pull_out(opt2fn("-pf", nfile, fnm), pull, oenv,
1255 FALSE, Flags);
1260 void finish_pull(t_pull *pull)
1262 if (pull->out_x)
1264 gmx_fio_fclose(pull->out_x);
1266 if (pull->out_f)
1268 gmx_fio_fclose(pull->out_f);