Tidy: modernize-use-nullptr
[gromacs.git] / src / gromacs / pulling / pull.cpp
blobd430f8a609ab02040c1c8a182c333b5738fc083f
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,2015,2016,2017, 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 "gmxpre.h"
39 #include "pull.h"
41 #include "config.h"
43 #include <assert.h>
44 #include <math.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
49 #include <algorithm>
51 #include "gromacs/commandline/filenm.h"
52 #include "gromacs/domdec/domdec_struct.h"
53 #include "gromacs/domdec/ga2la.h"
54 #include "gromacs/fileio/gmxfio.h"
55 #include "gromacs/fileio/xvgr.h"
56 #include "gromacs/gmxlib/network.h"
57 #include "gromacs/math/functions.h"
58 #include "gromacs/math/units.h"
59 #include "gromacs/math/vec.h"
60 #include "gromacs/math/vectypes.h"
61 #include "gromacs/mdlib/gmx_omp_nthreads.h"
62 #include "gromacs/mdlib/mdrun.h"
63 #include "gromacs/mdtypes/commrec.h"
64 #include "gromacs/mdtypes/inputrec.h"
65 #include "gromacs/mdtypes/md_enums.h"
66 #include "gromacs/mdtypes/mdatom.h"
67 #include "gromacs/pbcutil/pbc.h"
68 #include "gromacs/pulling/pull_internal.h"
69 #include "gromacs/topology/mtop_lookup.h"
70 #include "gromacs/topology/topology.h"
71 #include "gromacs/utility/cstringutil.h"
72 #include "gromacs/utility/exceptions.h"
73 #include "gromacs/utility/fatalerror.h"
74 #include "gromacs/utility/futil.h"
75 #include "gromacs/utility/gmxassert.h"
76 #include "gromacs/utility/pleasecite.h"
77 #include "gromacs/utility/real.h"
78 #include "gromacs/utility/smalloc.h"
80 static bool pull_coordinate_is_angletype(const t_pull_coord *pcrd)
82 return (pcrd->eGeom == epullgANGLE ||
83 pcrd->eGeom == epullgDIHEDRAL ||
84 pcrd->eGeom == epullgANGLEAXIS);
87 static bool pull_coordinate_is_directional(const t_pull_coord *pcrd)
89 return (pcrd->eGeom == epullgDIR ||
90 pcrd->eGeom == epullgDIRPBC ||
91 pcrd->eGeom == epullgDIRRELATIVE ||
92 pcrd->eGeom == epullgCYL);
95 const char *pull_coordinate_units(const t_pull_coord *pcrd)
97 return pull_coordinate_is_angletype(pcrd) ? "deg" : "nm";
100 double pull_conversion_factor_userinput2internal(const t_pull_coord *pcrd)
102 if (pull_coordinate_is_angletype(pcrd))
104 return DEG2RAD;
106 else
108 return 1.0;
112 double pull_conversion_factor_internal2userinput(const t_pull_coord *pcrd)
114 if (pull_coordinate_is_angletype(pcrd))
116 return RAD2DEG;
118 else
120 return 1.0;
124 static std::string append_before_extension(std::string pathname,
125 std::string to_append)
127 /* Appends to_append before last '.' in pathname */
128 size_t extPos = pathname.find_last_of('.');
129 if (extPos == std::string::npos)
131 return pathname + to_append;
133 else
135 return pathname.substr(0, extPos) + to_append +
136 pathname.substr(extPos, std::string::npos);
140 static void pull_print_group_x(FILE *out, ivec dim,
141 const pull_group_work_t *pgrp)
143 int m;
145 for (m = 0; m < DIM; m++)
147 if (dim[m])
149 fprintf(out, "\t%g", pgrp->x[m]);
154 static void pull_print_coord_dr_components(FILE *out, const ivec dim, const dvec dr)
156 for (int m = 0; m < DIM; m++)
158 if (dim[m])
160 fprintf(out, "\t%g", dr[m]);
165 static void pull_print_coord_dr(FILE *out, const pull_coord_work_t *pcrd,
166 gmx_bool bPrintRefValue,
167 gmx_bool bPrintComponents)
169 double unit_factor = pull_conversion_factor_internal2userinput(&pcrd->params);
171 fprintf(out, "\t%g", pcrd->value*unit_factor);
173 if (bPrintRefValue)
175 fprintf(out, "\t%g", pcrd->value_ref*unit_factor);
178 if (bPrintComponents)
180 pull_print_coord_dr_components(out, pcrd->params.dim, pcrd->dr01);
181 if (pcrd->params.ngroup >= 4)
183 pull_print_coord_dr_components(out, pcrd->params.dim, pcrd->dr23);
185 if (pcrd->params.ngroup >= 6)
187 pull_print_coord_dr_components(out, pcrd->params.dim, pcrd->dr45);
192 static void pull_print_x(FILE *out, struct pull_t *pull, double t)
194 int c;
196 fprintf(out, "%.4f", t);
198 for (c = 0; c < pull->ncoord; c++)
200 pull_coord_work_t *pcrd;
202 pcrd = &pull->coord[c];
204 pull_print_coord_dr(out, pcrd,
205 pull->params.bPrintRefValue && pcrd->params.eType != epullEXTERNAL,
206 pull->params.bPrintComp);
208 if (pull->params.bPrintCOM)
210 if (pcrd->params.eGeom == epullgCYL)
212 pull_print_group_x(out, pcrd->params.dim, &pull->dyna[c]);
214 else
216 pull_print_group_x(out, pcrd->params.dim,
217 &pull->group[pcrd->params.group[0]]);
219 for (int g = 1; g < pcrd->params.ngroup; g++)
221 pull_print_group_x(out, pcrd->params.dim, &pull->group[pcrd->params.group[g]]);
225 fprintf(out, "\n");
228 static void pull_print_f(FILE *out, struct pull_t *pull, double t)
230 int c;
232 fprintf(out, "%.4f", t);
234 for (c = 0; c < pull->ncoord; c++)
236 fprintf(out, "\t%g", pull->coord[c].f_scal);
238 fprintf(out, "\n");
241 void pull_print_output(struct pull_t *pull, gmx_int64_t step, double time)
243 GMX_ASSERT(pull->numExternalPotentialsStillToBeAppliedThisStep == 0, "pull_print_output called before all external pull potentials have been applied");
245 if ((pull->params.nstxout != 0) && (step % pull->params.nstxout == 0))
247 pull_print_x(pull->out_x, pull, time);
250 if ((pull->params.nstfout != 0) && (step % pull->params.nstfout == 0))
252 pull_print_f(pull->out_f, pull, time);
256 static void set_legend_for_coord_components(const pull_coord_work_t *pcrd, int coord_index, char **setname, int *nsets_ptr)
258 /* Loop over the distance vectors and print their components. Each vector is made up of two consecutive groups. */
259 for (int g = 0; g < pcrd->params.ngroup; g += 2)
261 /* Loop over the components */
262 for (int m = 0; m < DIM; m++)
264 if (pcrd->params.dim[m])
266 char legend[STRLEN];
268 if (g == 0 && pcrd->params.ngroup <= 2)
270 /* For the simplest case we print a simplified legend without group indices, just the cooordinate index
271 and which dimensional component it is. */
272 sprintf(legend, "%d d%c", coord_index + 1, 'X' + m);
274 else
276 /* Otherwise, print also the group indices (relative to the coordinate, not the global ones). */
277 sprintf(legend, "%d g %d-%d d%c", coord_index + 1, g + 1, g + 2, 'X' + m);
280 setname[*nsets_ptr] = gmx_strdup(legend);
281 (*nsets_ptr)++;
287 static FILE *open_pull_out(const char *fn, struct pull_t *pull,
288 const gmx_output_env_t *oenv,
289 gmx_bool bCoord, unsigned long Flags)
291 FILE *fp;
292 int nsets, c, m;
293 char **setname, buf[50];
295 if (Flags & MD_APPENDFILES)
297 fp = gmx_fio_fopen(fn, "a+");
299 else
301 fp = gmx_fio_fopen(fn, "w+");
302 if (bCoord)
304 sprintf(buf, "Position (nm%s)", pull->bAngle ? ", deg" : "");
305 xvgr_header(fp, "Pull COM", "Time (ps)", buf,
306 exvggtXNY, oenv);
308 else
310 sprintf(buf, "Force (kJ/mol/nm%s)", pull->bAngle ? ", kJ/mol/rad" : "");
311 xvgr_header(fp, "Pull force", "Time (ps)", buf,
312 exvggtXNY, oenv);
315 /* With default mdp options only the actual coordinate value is printed (1),
316 * but optionally the reference value (+ 1),
317 * the group COMs for all the groups (+ ngroups_max*DIM)
318 * and the components of the distance vectors can be printed (+ (ngroups_max/2)*DIM).
320 snew(setname, pull->ncoord*(1 + 1 + c_pullCoordNgroupMax*DIM + c_pullCoordNgroupMax/2*DIM));
322 nsets = 0;
323 for (c = 0; c < pull->ncoord; c++)
325 if (bCoord)
327 /* The order of this legend should match the order of printing
328 * the data in print_pull_x above.
331 /* The pull coord distance */
332 sprintf(buf, "%d", c+1);
333 setname[nsets] = gmx_strdup(buf);
334 nsets++;
335 if (pull->params.bPrintRefValue &&
336 pull->coord[c].params.eType != epullEXTERNAL)
338 sprintf(buf, "%d ref", c+1);
339 setname[nsets] = gmx_strdup(buf);
340 nsets++;
342 if (pull->params.bPrintComp)
344 set_legend_for_coord_components(&pull->coord[c], c, setname, &nsets);
347 if (pull->params.bPrintCOM)
349 for (int g = 0; g < pull->coord[c].params.ngroup; g++)
351 /* Legend for reference group position */
352 for (m = 0; m < DIM; m++)
354 if (pull->coord[c].params.dim[m])
356 sprintf(buf, "%d g %d %c", c+1, g + 1, 'X'+m);
357 setname[nsets] = gmx_strdup(buf);
358 nsets++;
364 else
366 /* For the pull force we always only use one scalar */
367 sprintf(buf, "%d", c+1);
368 setname[nsets] = gmx_strdup(buf);
369 nsets++;
372 if (nsets > 1)
374 xvgr_legend(fp, nsets, (const char**)setname, oenv);
376 for (c = 0; c < nsets; c++)
378 sfree(setname[c]);
380 sfree(setname);
383 return fp;
386 /* Apply forces in a mass weighted fashion for part of the pull group */
387 static void apply_forces_grp_part(const pull_group_work_t *pgrp,
388 int ind_start, int ind_end,
389 const t_mdatoms *md,
390 const dvec f_pull, int sign, rvec *f)
392 double inv_wm = pgrp->mwscale;
394 for (int i = ind_start; i < ind_end; i++)
396 int ii = pgrp->ind_loc[i];
397 double wmass = md->massT[ii];
398 if (pgrp->weight_loc)
400 wmass *= pgrp->weight_loc[i];
403 for (int d = 0; d < DIM; d++)
405 f[ii][d] += sign * wmass * f_pull[d] * inv_wm;
410 /* Apply forces in a mass weighted fashion */
411 static void apply_forces_grp(const pull_group_work_t *pgrp,
412 const t_mdatoms *md,
413 const dvec f_pull, int sign, rvec *f,
414 int nthreads)
416 if (pgrp->params.nat == 1 && pgrp->nat_loc == 1)
418 /* Only one atom and our rank has this atom: we can skip
419 * the mass weighting, which means that this code also works
420 * for mass=0, e.g. with a virtual site.
422 for (int d = 0; d < DIM; d++)
424 f[pgrp->ind_loc[0]][d] += sign*f_pull[d];
427 else
429 if (pgrp->nat_loc <= c_pullMaxNumLocalAtomsSingleThreaded)
431 apply_forces_grp_part(pgrp, 0, pgrp->nat_loc, md, f_pull, sign, f);
433 else
435 #pragma omp parallel for num_threads(nthreads) schedule(static)
436 for (int th = 0; th < nthreads; th++)
438 int ind_start = (pgrp->nat_loc*(th + 0))/nthreads;
439 int ind_end = (pgrp->nat_loc*(th + 1))/nthreads;
440 apply_forces_grp_part(pgrp, ind_start, ind_end,
441 md, f_pull, sign, f);
447 /* Apply forces in a mass weighted fashion to a cylinder group */
448 static void apply_forces_cyl_grp(const pull_group_work_t *pgrp,
449 const double dv_corr,
450 const t_mdatoms *md,
451 const dvec f_pull, double f_scal,
452 int sign, rvec *f,
453 int gmx_unused nthreads)
455 double inv_wm = pgrp->mwscale;
457 /* The cylinder group is always a slab in the system, thus large.
458 * Therefore we always thread-parallelize this group.
460 #pragma omp parallel for num_threads(nthreads) schedule(static)
461 for (int i = 0; i < pgrp->nat_loc; i++)
463 int ii = pgrp->ind_loc[i];
464 double mass = md->massT[ii];
465 double weight = pgrp->weight_loc[i];
466 /* The stored axial distance from the cylinder center (dv) needs
467 * to be corrected for an offset (dv_corr), which was unknown when
468 * we calculated dv.
470 double dv_com = pgrp->dv[i] + dv_corr;
472 /* Here we not only add the pull force working along vec (f_pull),
473 * but also a radial component, due to the dependence of the weights
474 * on the radial distance.
476 for (int m = 0; m < DIM; m++)
478 f[ii][m] += sign*inv_wm*(mass*weight*f_pull[m] +
479 pgrp->mdw[i][m]*dv_com*f_scal);
484 /* Apply torque forces in a mass weighted fashion to the groups that define
485 * the pull vector direction for pull coordinate pcrd.
487 static void apply_forces_vec_torque(const struct pull_t *pull,
488 const pull_coord_work_t *pcrd,
489 const t_mdatoms *md,
490 rvec *f)
492 double inpr;
493 int m;
494 dvec f_perp;
496 /* The component inpr along the pull vector is accounted for in the usual
497 * way. Here we account for the component perpendicular to vec.
499 inpr = 0;
500 for (m = 0; m < DIM; m++)
502 inpr += pcrd->dr01[m]*pcrd->vec[m];
504 /* The torque force works along the component of the distance vector
505 * of between the two "usual" pull groups that is perpendicular to
506 * the pull vector. The magnitude of this force is the "usual" scale force
507 * multiplied with the ratio of the distance between the two "usual" pull
508 * groups and the distance between the two groups that define the vector.
510 for (m = 0; m < DIM; m++)
512 f_perp[m] = (pcrd->dr01[m] - inpr*pcrd->vec[m])/pcrd->vec_len*pcrd->f_scal;
515 /* Apply the force to the groups defining the vector using opposite signs */
516 apply_forces_grp(&pull->group[pcrd->params.group[2]], md,
517 f_perp, -1, f, pull->nthreads);
518 apply_forces_grp(&pull->group[pcrd->params.group[3]], md,
519 f_perp, 1, f, pull->nthreads);
522 /* Apply forces in a mass weighted fashion */
523 static void apply_forces_coord(struct pull_t * pull, int coord,
524 const t_mdatoms * md,
525 rvec *f)
527 /* Here it would be more efficient to use one large thread-parallel
528 * region instead of potential parallel regions within apply_forces_grp.
529 * But there could be overlap between pull groups and this would lead
530 * to data races.
533 const pull_coord_work_t *pcrd = &pull->coord[coord];
535 if (pcrd->params.eGeom == epullgCYL)
537 apply_forces_cyl_grp(&pull->dyna[coord], pcrd->cyl_dev, md,
538 pcrd->f01, pcrd->f_scal, -1, f,
539 pull->nthreads);
541 /* Sum the force along the vector and the radial force */
542 dvec f_tot;
543 for (int m = 0; m < DIM; m++)
545 f_tot[m] = pcrd->f01[m] + pcrd->f_scal*pcrd->ffrad[m];
547 apply_forces_grp(&pull->group[pcrd->params.group[1]], md,
548 f_tot, 1, f, pull->nthreads);
550 else
552 if (pcrd->params.eGeom == epullgDIRRELATIVE)
554 /* We need to apply the torque forces to the pull groups
555 * that define the pull vector.
557 apply_forces_vec_torque(pull, pcrd, md, f);
560 if (pull->group[pcrd->params.group[0]].params.nat > 0)
562 apply_forces_grp(&pull->group[pcrd->params.group[0]], md,
563 pcrd->f01, -1, f, pull->nthreads);
565 apply_forces_grp(&pull->group[pcrd->params.group[1]], md,
566 pcrd->f01, 1, f, pull->nthreads);
568 if (pcrd->params.ngroup >= 4)
570 apply_forces_grp(&pull->group[pcrd->params.group[2]], md,
571 pcrd->f23, -1, f, pull->nthreads);
572 apply_forces_grp(&pull->group[pcrd->params.group[3]], md,
573 pcrd->f23, 1, f, pull->nthreads);
575 if (pcrd->params.ngroup >= 6)
577 apply_forces_grp(&pull->group[pcrd->params.group[4]], md,
578 pcrd->f45, -1, f, pull->nthreads);
579 apply_forces_grp(&pull->group[pcrd->params.group[5]], md,
580 pcrd->f45, 1, f, pull->nthreads);
585 real max_pull_distance2(const pull_coord_work_t *pcrd,
586 const t_pbc *pbc)
588 /* Note that this maximum distance calculation is more complex than
589 * most other cases in GROMACS, since here we have to take care of
590 * distance calculations that don't involve all three dimensions.
591 * For example, we can use distances that are larger than the
592 * box X and Y dimensions for a box that is elongated along Z.
595 real max_d2 = GMX_REAL_MAX;
597 if (pull_coordinate_is_directional(&pcrd->params))
599 /* Directional pulling along along direction pcrd->vec.
600 * Calculating the exact maximum distance is complex and bug-prone.
601 * So we take a safe approach by not allowing distances that
602 * are larger than half the distance between unit cell faces
603 * along dimensions involved in pcrd->vec.
605 for (int m = 0; m < DIM; m++)
607 if (m < pbc->ndim_ePBC && pcrd->vec[m] != 0)
609 real imageDistance2 = gmx::square(pbc->box[m][m]);
610 for (int d = m + 1; d < DIM; d++)
612 imageDistance2 -= gmx::square(pbc->box[d][m]);
614 max_d2 = std::min(max_d2, imageDistance2);
618 else
620 /* Distance pulling along dimensions with pcrd->params.dim[d]==1.
621 * We use half the minimum box vector length of the dimensions involved.
622 * This is correct for all cases, except for corner cases with
623 * triclinic boxes where e.g. dim[XX]=1 and dim[YY]=0 with
624 * box[YY][XX]!=0 and box[YY][YY] < box[XX][XX]. But since even
625 * in such corner cases the user could get correct results,
626 * depending on the details of the setup, we avoid further
627 * code complications.
629 for (int m = 0; m < DIM; m++)
631 if (m < pbc->ndim_ePBC && pcrd->params.dim[m] != 0)
633 real imageDistance2 = gmx::square(pbc->box[m][m]);
634 for (int d = 0; d < m; d++)
636 if (pcrd->params.dim[d] != 0)
638 imageDistance2 += gmx::square(pbc->box[m][d]);
641 max_d2 = std::min(max_d2, imageDistance2);
646 return 0.25*max_d2;
649 /* This function returns the distance based on coordinates xg and xref.
650 * Note that the pull coordinate struct pcrd is not modified.
652 static void low_get_pull_coord_dr(const struct pull_t *pull,
653 const pull_coord_work_t *pcrd,
654 const t_pbc *pbc,
655 dvec xg, dvec xref, double max_dist2,
656 dvec dr)
658 const pull_group_work_t *pgrp0 = &pull->group[pcrd->params.group[0]];
660 /* Only the first group can be an absolute reference, in that case nat=0 */
661 if (pgrp0->params.nat == 0)
663 for (int m = 0; m < DIM; m++)
665 xref[m] = pcrd->params.origin[m];
669 dvec xrefr;
670 copy_dvec(xref, xrefr);
672 dvec dref = {0, 0, 0};
673 if (pcrd->params.eGeom == epullgDIRPBC)
675 for (int m = 0; m < DIM; m++)
677 dref[m] = pcrd->value_ref*pcrd->vec[m];
679 /* Add the reference position, so we use the correct periodic image */
680 dvec_inc(xrefr, dref);
683 pbc_dx_d(pbc, xg, xrefr, dr);
685 bool directional = pull_coordinate_is_directional(&pcrd->params);
686 double dr2 = 0;
687 for (int m = 0; m < DIM; m++)
689 dr[m] *= pcrd->params.dim[m];
690 if (pcrd->params.dim[m] && !(directional && pcrd->vec[m] == 0))
692 dr2 += dr[m]*dr[m];
695 /* Check if we are close to switching to another periodic image */
696 if (max_dist2 > 0 && dr2 > 0.98*0.98*max_dist2)
698 /* Note that technically there is no issue with switching periodic
699 * image, as pbc_dx_d returns the distance to the closest periodic
700 * image. However in all cases where periodic image switches occur,
701 * the pull results will be useless in practice.
703 gmx_fatal(FARGS, "Distance between pull groups %d and %d (%f nm) is larger than 0.49 times the box size (%f).\n%s",
704 pcrd->params.group[0], pcrd->params.group[1],
705 sqrt(dr2), sqrt(0.98*0.98*max_dist2),
706 pcrd->params.eGeom == epullgDIR ? "You might want to consider using \"pull-geometry = direction-periodic\" instead.\n" : "");
709 if (pcrd->params.eGeom == epullgDIRPBC)
711 dvec_inc(dr, dref);
715 /* This function returns the distance based on the contents of the pull struct.
716 * pull->coord[coord_ind].dr, and potentially vector, are updated.
718 static void get_pull_coord_dr(struct pull_t *pull,
719 int coord_ind,
720 const t_pbc *pbc)
722 double md2;
723 pull_coord_work_t *pcrd;
724 pull_group_work_t *pgrp0, *pgrp1;
726 pcrd = &pull->coord[coord_ind];
728 if (pcrd->params.eGeom == epullgDIRPBC)
730 md2 = -1;
732 else
734 md2 = static_cast<double>(max_pull_distance2(pcrd, pbc));
737 if (pcrd->params.eGeom == epullgDIRRELATIVE)
739 /* We need to determine the pull vector */
740 const pull_group_work_t *pgrp2, *pgrp3;
741 dvec vec;
742 int m;
744 pgrp2 = &pull->group[pcrd->params.group[2]];
745 pgrp3 = &pull->group[pcrd->params.group[3]];
747 pbc_dx_d(pbc, pgrp3->x, pgrp2->x, vec);
749 for (m = 0; m < DIM; m++)
751 vec[m] *= pcrd->params.dim[m];
753 pcrd->vec_len = dnorm(vec);
754 for (m = 0; m < DIM; m++)
756 pcrd->vec[m] = vec[m]/pcrd->vec_len;
758 if (debug)
760 fprintf(debug, "pull coord %d vector: %6.3f %6.3f %6.3f normalized: %6.3f %6.3f %6.3f\n",
761 coord_ind,
762 vec[XX], vec[YY], vec[ZZ],
763 pcrd->vec[XX], pcrd->vec[YY], pcrd->vec[ZZ]);
767 pgrp0 = &pull->group[pcrd->params.group[0]];
768 pgrp1 = &pull->group[pcrd->params.group[1]];
770 low_get_pull_coord_dr(pull, pcrd, pbc,
771 pgrp1->x,
772 pcrd->params.eGeom == epullgCYL ? pull->dyna[coord_ind].x : pgrp0->x,
773 md2,
774 pcrd->dr01);
776 if (pcrd->params.ngroup >= 4)
778 pull_group_work_t *pgrp2, *pgrp3;
779 pgrp2 = &pull->group[pcrd->params.group[2]];
780 pgrp3 = &pull->group[pcrd->params.group[3]];
782 low_get_pull_coord_dr(pull, pcrd, pbc,
783 pgrp3->x,
784 pgrp2->x,
785 md2,
786 pcrd->dr23);
788 if (pcrd->params.ngroup >= 6)
790 pull_group_work_t *pgrp4, *pgrp5;
791 pgrp4 = &pull->group[pcrd->params.group[4]];
792 pgrp5 = &pull->group[pcrd->params.group[5]];
794 low_get_pull_coord_dr(pull, pcrd, pbc,
795 pgrp5->x,
796 pgrp4->x,
797 md2,
798 pcrd->dr45);
802 /* Modify x so that it is periodic in [-pi, pi)
803 * It is assumed that x is in [-3pi, 3pi) so that x
804 * needs to be shifted by at most one period.
806 static void make_periodic_2pi(double *x)
808 if (*x >= M_PI)
810 *x -= M_2PI;
812 else if (*x < -M_PI)
814 *x += M_2PI;
818 /* This function should always be used to modify pcrd->value_ref */
819 static void low_set_pull_coord_reference_value(pull_coord_work_t *pcrd,
820 int coord_ind,
821 double value_ref)
823 GMX_ASSERT(pcrd->params.eType != epullEXTERNAL, "The pull coord reference value should not be used with type external-potential");
825 if (pcrd->params.eGeom == epullgDIST)
827 if (value_ref < 0)
829 gmx_fatal(FARGS, "Pull reference distance for coordinate %d (%f) needs to be non-negative", coord_ind + 1, value_ref);
832 else if (pcrd->params.eGeom == epullgANGLE || pcrd->params.eGeom == epullgANGLEAXIS)
834 if (value_ref < 0 || value_ref > M_PI)
836 gmx_fatal(FARGS, "Pull reference angle for coordinate %d (%f) needs to be in the allowed interval [0,180] deg", coord_ind + 1, value_ref*pull_conversion_factor_internal2userinput(&pcrd->params));
839 else if (pcrd->params.eGeom == epullgDIHEDRAL)
841 /* Allow pulling to be periodic for dihedral angles by remapping the reference value to the interval [-pi, pi). */
842 make_periodic_2pi(&value_ref);
845 pcrd->value_ref = value_ref;
848 static void update_pull_coord_reference_value(pull_coord_work_t *pcrd, int coord_ind, double t)
850 /* With zero rate the reference value is set initially and doesn't change */
851 if (pcrd->params.rate != 0)
853 double value_ref = (pcrd->params.init + pcrd->params.rate*t)*pull_conversion_factor_userinput2internal(&pcrd->params);
854 low_set_pull_coord_reference_value(pcrd, coord_ind, value_ref);
858 /* Returns the dihedral angle. Updates the plane normal vectors m, n. */
859 static double get_dihedral_angle_coord(pull_coord_work_t *pcrd)
861 double phi, sign;
862 dvec dr32; /* store instead of dr23? */
864 dsvmul(-1, pcrd->dr23, dr32);
865 dcprod(pcrd->dr01, dr32, pcrd->planevec_m); /* Normal of first plane */
866 dcprod(dr32, pcrd->dr45, pcrd->planevec_n); /* Normal of second plane */
867 phi = gmx_angle_between_dvecs(pcrd->planevec_m, pcrd->planevec_n);
869 /* Note 1: the sign below is opposite of that in the bondeds or Bekker 1994
870 * because there r_ij = ri - rj, while here dr01 = r_1 - r_0
871 * Note 2: the angle between the plane normal vectors equals pi only when
872 * both planes coincide. Thus, when phi = pi dr01 will lie in both planes and
873 * we get a positive sign below. Thus, the range of the dihedral angle is (-180, 180].
875 sign = (diprod(pcrd->dr01, pcrd->planevec_n) < 0.0) ? 1.0 : -1.0;
876 return sign*phi;
879 /* Calculates pull->coord[coord_ind].value.
880 * This function also updates pull->coord[coord_ind].dr.
882 static void get_pull_coord_distance(struct pull_t *pull,
883 int coord_ind,
884 const t_pbc *pbc)
886 pull_coord_work_t *pcrd;
887 int m;
889 pcrd = &pull->coord[coord_ind];
891 get_pull_coord_dr(pull, coord_ind, pbc);
893 switch (pcrd->params.eGeom)
895 case epullgDIST:
896 /* Pull along the vector between the com's */
897 pcrd->value = dnorm(pcrd->dr01);
898 break;
899 case epullgDIR:
900 case epullgDIRPBC:
901 case epullgDIRRELATIVE:
902 case epullgCYL:
903 /* Pull along vec */
904 pcrd->value = 0;
905 for (m = 0; m < DIM; m++)
907 pcrd->value += pcrd->vec[m]*pcrd->dr01[m];
909 break;
910 case epullgANGLE:
911 pcrd->value = gmx_angle_between_dvecs(pcrd->dr01, pcrd->dr23);
912 break;
913 case epullgDIHEDRAL:
914 pcrd->value = get_dihedral_angle_coord(pcrd);
915 break;
916 case epullgANGLEAXIS:
917 pcrd->value = gmx_angle_between_dvecs(pcrd->dr01, pcrd->vec);
918 break;
919 default:
920 gmx_incons("Unsupported pull type in get_pull_coord_distance");
924 /* Returns the deviation from the reference value.
925 * Updates pull->coord[coord_ind].dr, .value and .value_ref.
927 static double get_pull_coord_deviation(struct pull_t *pull,
928 int coord_ind,
929 const t_pbc *pbc,
930 double t)
932 pull_coord_work_t *pcrd;
933 double dev = 0;
935 pcrd = &pull->coord[coord_ind];
937 get_pull_coord_distance(pull, coord_ind, pbc);
939 update_pull_coord_reference_value(pcrd, coord_ind, t);
941 /* Determine the deviation */
942 dev = pcrd->value - pcrd->value_ref;
944 /* Check that values are allowed */
945 if (pcrd->params.eGeom == epullgDIST && pcrd->value == 0)
947 /* With no vector we can not determine the direction for the force,
948 * so we set the force to zero.
950 dev = 0;
952 else if (pcrd->params.eGeom == epullgDIHEDRAL)
954 /* The reference value is in [-pi, pi). The coordinate value is in (-pi, pi].
955 Thus, the unwrapped deviation is here in (-2pi, 2pi].
956 After making it periodic, the deviation will be in [-pi, pi). */
957 make_periodic_2pi(&dev);
960 return dev;
963 void get_pull_coord_value(struct pull_t *pull,
964 int coord_ind,
965 const t_pbc *pbc,
966 double *value)
968 get_pull_coord_distance(pull, coord_ind, pbc);
970 *value = pull->coord[coord_ind].value;
973 static void clear_pull_forces_coord(pull_coord_work_t *pcrd)
975 clear_dvec(pcrd->f01);
976 clear_dvec(pcrd->f23);
977 clear_dvec(pcrd->f45);
978 pcrd->f_scal = 0;
981 void clear_pull_forces(struct pull_t *pull)
983 int i;
985 /* Zeroing the forces is only required for constraint pulling.
986 * It can happen that multiple constraint steps need to be applied
987 * and therefore the constraint forces need to be accumulated.
989 for (i = 0; i < pull->ncoord; i++)
991 clear_pull_forces_coord(&pull->coord[i]);
995 /* Apply constraint using SHAKE */
996 static void do_constraint(struct pull_t *pull, t_pbc *pbc,
997 rvec *x, rvec *v,
998 gmx_bool bMaster, tensor vir,
999 double dt, double t)
1002 dvec *r_ij; /* x[i] com of i in prev. step. Obeys constr. -> r_ij[i] */
1003 dvec unc_ij; /* xp[i] com of i this step, before constr. -> unc_ij */
1004 dvec *rnew; /* current 'new' positions of the groups */
1005 double *dr_tot; /* the total update of the coords */
1006 dvec vec;
1007 double inpr;
1008 double lambda, rm, invdt = 0;
1009 gmx_bool bConverged_all, bConverged = FALSE;
1010 int niter = 0, g, c, ii, j, m, max_iter = 100;
1011 double a;
1012 dvec tmp, tmp3;
1014 snew(r_ij, pull->ncoord);
1015 snew(dr_tot, pull->ncoord);
1017 snew(rnew, pull->ngroup);
1019 /* copy the current unconstrained positions for use in iterations. We
1020 iterate until rinew[i] and rjnew[j] obey the constraints. Then
1021 rinew - pull.x_unc[i] is the correction dr to group i */
1022 for (g = 0; g < pull->ngroup; g++)
1024 copy_dvec(pull->group[g].xp, rnew[g]);
1027 /* Determine the constraint directions from the old positions */
1028 for (c = 0; c < pull->ncoord; c++)
1030 pull_coord_work_t *pcrd;
1032 pcrd = &pull->coord[c];
1034 if (pcrd->params.eType != epullCONSTRAINT)
1036 continue;
1039 /* Note that get_pull_coord_distance also sets pcrd->dr and pcrd->value.
1040 * We don't modify dr and value anymore, so these values are also used
1041 * for printing.
1043 get_pull_coord_distance(pull, c, pbc);
1045 if (debug)
1047 fprintf(debug, "Pull coord %d dr %f %f %f\n",
1048 c, pcrd->dr01[XX], pcrd->dr01[YY], pcrd->dr01[ZZ]);
1051 if (pcrd->params.eGeom == epullgDIR ||
1052 pcrd->params.eGeom == epullgDIRPBC)
1054 /* Select the component along vec */
1055 a = 0;
1056 for (m = 0; m < DIM; m++)
1058 a += pcrd->vec[m]*pcrd->dr01[m];
1060 for (m = 0; m < DIM; m++)
1062 r_ij[c][m] = a*pcrd->vec[m];
1065 else
1067 copy_dvec(pcrd->dr01, r_ij[c]);
1070 if (dnorm2(r_ij[c]) == 0)
1072 gmx_fatal(FARGS, "Distance for pull coordinate %d is zero with constraint pulling, which is not allowed.", c + 1);
1076 bConverged_all = FALSE;
1077 while (!bConverged_all && niter < max_iter)
1079 bConverged_all = TRUE;
1081 /* loop over all constraints */
1082 for (c = 0; c < pull->ncoord; c++)
1084 pull_coord_work_t *pcrd;
1085 pull_group_work_t *pgrp0, *pgrp1;
1086 dvec dr0, dr1;
1088 pcrd = &pull->coord[c];
1090 if (pcrd->params.eType != epullCONSTRAINT)
1092 continue;
1095 update_pull_coord_reference_value(pcrd, c, t);
1097 pgrp0 = &pull->group[pcrd->params.group[0]];
1098 pgrp1 = &pull->group[pcrd->params.group[1]];
1100 /* Get the current difference vector */
1101 low_get_pull_coord_dr(pull, pcrd, pbc,
1102 rnew[pcrd->params.group[1]],
1103 rnew[pcrd->params.group[0]],
1104 -1, unc_ij);
1106 if (debug)
1108 fprintf(debug, "Pull coord %d, iteration %d\n", c, niter);
1111 rm = 1.0/(pgrp0->invtm + pgrp1->invtm);
1113 switch (pcrd->params.eGeom)
1115 case epullgDIST:
1116 if (pcrd->value_ref <= 0)
1118 gmx_fatal(FARGS, "The pull constraint reference distance for group %d is <= 0 (%f)", c, pcrd->value_ref);
1122 double q, c_a, c_b, c_c;
1124 c_a = diprod(r_ij[c], r_ij[c]);
1125 c_b = diprod(unc_ij, r_ij[c])*2;
1126 c_c = diprod(unc_ij, unc_ij) - gmx::square(pcrd->value_ref);
1128 if (c_b < 0)
1130 q = -0.5*(c_b - std::sqrt(c_b*c_b - 4*c_a*c_c));
1131 lambda = -q/c_a;
1133 else
1135 q = -0.5*(c_b + std::sqrt(c_b*c_b - 4*c_a*c_c));
1136 lambda = -c_c/q;
1139 if (debug)
1141 fprintf(debug,
1142 "Pull ax^2+bx+c=0: a=%e b=%e c=%e lambda=%e\n",
1143 c_a, c_b, c_c, lambda);
1147 /* The position corrections dr due to the constraints */
1148 dsvmul(-lambda*rm*pgrp1->invtm, r_ij[c], dr1);
1149 dsvmul( lambda*rm*pgrp0->invtm, r_ij[c], dr0);
1150 dr_tot[c] += -lambda*dnorm(r_ij[c]);
1151 break;
1152 case epullgDIR:
1153 case epullgDIRPBC:
1154 case epullgCYL:
1155 /* A 1-dimensional constraint along a vector */
1156 a = 0;
1157 for (m = 0; m < DIM; m++)
1159 vec[m] = pcrd->vec[m];
1160 a += unc_ij[m]*vec[m];
1162 /* Select only the component along the vector */
1163 dsvmul(a, vec, unc_ij);
1164 lambda = a - pcrd->value_ref;
1165 if (debug)
1167 fprintf(debug, "Pull inpr %e lambda: %e\n", a, lambda);
1170 /* The position corrections dr due to the constraints */
1171 dsvmul(-lambda*rm*pgrp1->invtm, vec, dr1);
1172 dsvmul( lambda*rm*pgrp0->invtm, vec, dr0);
1173 dr_tot[c] += -lambda;
1174 break;
1175 default:
1176 gmx_incons("Invalid enumeration value for eGeom");
1177 /* Keep static analyzer happy */
1178 clear_dvec(dr0);
1179 clear_dvec(dr1);
1182 /* DEBUG */
1183 if (debug)
1185 int g0, g1;
1187 g0 = pcrd->params.group[0];
1188 g1 = pcrd->params.group[1];
1189 low_get_pull_coord_dr(pull, pcrd, pbc, rnew[g1], rnew[g0], -1, tmp);
1190 low_get_pull_coord_dr(pull, pcrd, pbc, dr1, dr0, -1, tmp3);
1191 fprintf(debug,
1192 "Pull cur %8.5f %8.5f %8.5f j:%8.5f %8.5f %8.5f d: %8.5f\n",
1193 rnew[g0][0], rnew[g0][1], rnew[g0][2],
1194 rnew[g1][0], rnew[g1][1], rnew[g1][2], dnorm(tmp));
1195 fprintf(debug,
1196 "Pull ref %8s %8s %8s %8s %8s %8s d: %8.5f\n",
1197 "", "", "", "", "", "", pcrd->value_ref);
1198 fprintf(debug,
1199 "Pull cor %8.5f %8.5f %8.5f j:%8.5f %8.5f %8.5f d: %8.5f\n",
1200 dr0[0], dr0[1], dr0[2],
1201 dr1[0], dr1[1], dr1[2],
1202 dnorm(tmp3));
1203 } /* END DEBUG */
1205 /* Update the COMs with dr */
1206 dvec_inc(rnew[pcrd->params.group[1]], dr1);
1207 dvec_inc(rnew[pcrd->params.group[0]], dr0);
1210 /* Check if all constraints are fullfilled now */
1211 for (c = 0; c < pull->ncoord; c++)
1213 pull_coord_work_t *pcrd;
1215 pcrd = &pull->coord[c];
1217 if (pcrd->params.eType != epullCONSTRAINT)
1219 continue;
1222 low_get_pull_coord_dr(pull, pcrd, pbc,
1223 rnew[pcrd->params.group[1]],
1224 rnew[pcrd->params.group[0]],
1225 -1, unc_ij);
1227 switch (pcrd->params.eGeom)
1229 case epullgDIST:
1230 bConverged =
1231 fabs(dnorm(unc_ij) - pcrd->value_ref) < pull->params.constr_tol;
1232 break;
1233 case epullgDIR:
1234 case epullgDIRPBC:
1235 case epullgCYL:
1236 for (m = 0; m < DIM; m++)
1238 vec[m] = pcrd->vec[m];
1240 inpr = diprod(unc_ij, vec);
1241 dsvmul(inpr, vec, unc_ij);
1242 bConverged =
1243 fabs(diprod(unc_ij, vec) - pcrd->value_ref) < pull->params.constr_tol;
1244 break;
1247 if (!bConverged)
1249 if (debug)
1251 fprintf(debug, "NOT CONVERGED YET: Group %d:"
1252 "d_ref = %f, current d = %f\n",
1253 g, pcrd->value_ref, dnorm(unc_ij));
1256 bConverged_all = FALSE;
1260 niter++;
1261 /* if after all constraints are dealt with and bConverged is still TRUE
1262 we're finished, if not we do another iteration */
1264 if (niter > max_iter)
1266 gmx_fatal(FARGS, "Too many iterations for constraint run: %d", niter);
1269 /* DONE ITERATING, NOW UPDATE COORDINATES AND CALC. CONSTRAINT FORCES */
1271 if (v)
1273 invdt = 1/dt;
1276 /* update atoms in the groups */
1277 for (g = 0; g < pull->ngroup; g++)
1279 const pull_group_work_t *pgrp;
1280 dvec dr;
1282 pgrp = &pull->group[g];
1284 /* get the final constraint displacement dr for group g */
1285 dvec_sub(rnew[g], pgrp->xp, dr);
1287 if (dnorm2(dr) == 0)
1289 /* No displacement, no update necessary */
1290 continue;
1293 /* update the atom positions */
1294 copy_dvec(dr, tmp);
1295 for (j = 0; j < pgrp->nat_loc; j++)
1297 ii = pgrp->ind_loc[j];
1298 if (pgrp->weight_loc)
1300 dsvmul(pgrp->wscale*pgrp->weight_loc[j], dr, tmp);
1302 for (m = 0; m < DIM; m++)
1304 x[ii][m] += tmp[m];
1306 if (v)
1308 for (m = 0; m < DIM; m++)
1310 v[ii][m] += invdt*tmp[m];
1316 /* calculate the constraint forces, used for output and virial only */
1317 for (c = 0; c < pull->ncoord; c++)
1319 pull_coord_work_t *pcrd;
1321 pcrd = &pull->coord[c];
1323 if (pcrd->params.eType != epullCONSTRAINT)
1325 continue;
1328 pcrd->f_scal = dr_tot[c]/((pull->group[pcrd->params.group[0]].invtm + pull->group[pcrd->params.group[1]].invtm)*dt*dt);
1330 if (vir != nullptr && pcrd->params.eGeom != epullgDIRPBC && bMaster)
1332 double f_invr;
1334 /* Add the pull contribution to the virial */
1335 /* We have already checked above that r_ij[c] != 0 */
1336 f_invr = pcrd->f_scal/dnorm(r_ij[c]);
1338 for (j = 0; j < DIM; j++)
1340 for (m = 0; m < DIM; m++)
1342 vir[j][m] -= 0.5*f_invr*r_ij[c][j]*r_ij[c][m];
1348 /* finished! I hope. Give back some memory */
1349 sfree(r_ij);
1350 sfree(dr_tot);
1351 sfree(rnew);
1354 static void add_virial_coord_dr(tensor vir, const dvec dr, const dvec f)
1356 for (int j = 0; j < DIM; j++)
1358 for (int m = 0; m < DIM; m++)
1360 vir[j][m] -= 0.5*f[j]*dr[m];
1365 /* Adds the pull contribution to the virial */
1366 static void add_virial_coord(tensor vir, const pull_coord_work_t *pcrd)
1368 if (vir != nullptr && pcrd->params.eGeom != epullgDIRPBC)
1370 /* Add the pull contribution for each distance vector to the virial. */
1371 add_virial_coord_dr(vir, pcrd->dr01, pcrd->f01);
1372 if (pcrd->params.ngroup >= 4)
1374 add_virial_coord_dr(vir, pcrd->dr23, pcrd->f23);
1376 if (pcrd->params.ngroup >= 6)
1378 add_virial_coord_dr(vir, pcrd->dr45, pcrd->f45);
1383 static void calc_pull_coord_scalar_force_and_potential(pull_coord_work_t *pcrd,
1384 double dev, real lambda,
1385 real *V, real *dVdl)
1387 real k, dkdl;
1389 k = (1.0 - lambda)*pcrd->params.k + lambda*pcrd->params.kB;
1390 dkdl = pcrd->params.kB - pcrd->params.k;
1392 switch (pcrd->params.eType)
1394 case epullUMBRELLA:
1395 case epullFLATBOTTOM:
1396 case epullFLATBOTTOMHIGH:
1397 /* The only difference between an umbrella and a flat-bottom
1398 * potential is that a flat-bottom is zero above or below
1399 the reference value.
1401 if ((pcrd->params.eType == epullFLATBOTTOM && dev < 0) ||
1402 (pcrd->params.eType == epullFLATBOTTOMHIGH && dev > 0))
1404 dev = 0;
1407 pcrd->f_scal = -k*dev;
1408 *V += 0.5* k*gmx::square(dev);
1409 *dVdl += 0.5*dkdl*gmx::square(dev);
1410 break;
1411 case epullCONST_F:
1412 pcrd->f_scal = -k;
1413 *V += k*pcrd->value;
1414 *dVdl += dkdl*pcrd->value;
1415 break;
1416 case epullEXTERNAL:
1417 gmx_incons("the scalar pull force should not be calculated internally for pull type external");
1418 break;
1419 default:
1420 gmx_incons("Unsupported pull type in do_pull_pot");
1424 static void calc_pull_coord_vector_force(pull_coord_work_t *pcrd)
1426 /* The geometry of the coordinate determines how the scalar force relates to the force on each group */
1428 if (pcrd->params.eGeom == epullgDIST)
1430 double invdr01 = pcrd->value > 0 ? 1./pcrd->value : 0.;
1431 for (int m = 0; m < DIM; m++)
1433 pcrd->f01[m] = pcrd->f_scal*pcrd->dr01[m]*invdr01;
1436 else if (pcrd->params.eGeom == epullgANGLE)
1439 double cos_theta, cos_theta2;
1441 cos_theta = cos(pcrd->value);
1442 cos_theta2 = gmx::square(cos_theta);
1444 /* The force at theta = 0, pi is undefined so we should not apply any force.
1445 * cos(theta) = 1 for theta = 0, pi so this is what we check for below.
1446 * Note that dr01 = 0 or dr23 = 0 evaluates to theta = 0 so we do not
1447 * have to check for this before dividing by their norm below.
1449 if (cos_theta2 < 1)
1451 /* The forces f01 and f23 can be decomposed into one vector parallel to dr01
1452 * and another vector parallel to dr23:
1453 * f01 = -dV/dtheta*(a*dr23/|dr23| - b*dr01*|dr01|)/|dr01|,
1454 * f23 = -dV/dtheta*(a*dr01/|dr01| - b*dr23*|dr23|)/|dr23|,
1456 double a = -gmx::invsqrt(1 - cos_theta2); /* comes from d/dx acos(x) */
1457 double b = a*cos_theta;
1458 double invdr01 = 1./dnorm(pcrd->dr01);
1459 double invdr23 = 1./dnorm(pcrd->dr23);
1460 dvec normalized_dr01, normalized_dr23;
1461 dsvmul(invdr01, pcrd->dr01, normalized_dr01);
1462 dsvmul(invdr23, pcrd->dr23, normalized_dr23);
1464 for (int m = 0; m < DIM; m++)
1466 /* Here, f_scal is -dV/dtheta */
1467 pcrd->f01[m] = pcrd->f_scal*invdr01*(a*normalized_dr23[m] - b*normalized_dr01[m]);
1468 pcrd->f23[m] = pcrd->f_scal*invdr23*(a*normalized_dr01[m] - b*normalized_dr23[m]);
1471 else
1473 /* No forces to apply for ill-defined cases*/
1474 clear_pull_forces_coord(pcrd);
1477 else if (pcrd->params.eGeom == epullgANGLEAXIS)
1479 double cos_theta, cos_theta2;
1481 /* The angle-axis force is exactly the same as the angle force (above) except that in
1482 this case the second vector (dr23) is replaced by the pull vector. */
1483 cos_theta = cos(pcrd->value);
1484 cos_theta2 = gmx::square(cos_theta);
1486 if (cos_theta2 < 1)
1488 double a, b;
1489 double invdr01;
1490 dvec normalized_dr01;
1492 invdr01 = 1./dnorm(pcrd->dr01);
1493 dsvmul(invdr01, pcrd->dr01, normalized_dr01);
1494 a = -gmx::invsqrt(1 - cos_theta2); /* comes from d/dx acos(x) */
1495 b = a*cos_theta;
1497 for (int m = 0; m < DIM; m++)
1499 pcrd->f01[m] = pcrd->f_scal*invdr01*(a*pcrd->vec[m] - b*normalized_dr01[m]);
1502 else
1504 clear_pull_forces_coord(pcrd);
1507 else if (pcrd->params.eGeom == epullgDIHEDRAL)
1509 double m2, n2, tol, sqrdist_32;
1510 dvec dr32;
1511 /* Note: there is a small difference here compared to the
1512 dihedral force calculations in the bondeds (ref: Bekker 1994).
1513 There rij = ri - rj, while here dr01 = r1 - r0.
1514 However, all distance vectors occur in form of cross or inner products
1515 so that two signs cancel and we end up with the same expressions.
1516 Also, we treat the more general case of 6 groups (0..5) instead of 4 (i, j, k, l).
1518 m2 = diprod(pcrd->planevec_m, pcrd->planevec_m);
1519 n2 = diprod(pcrd->planevec_n, pcrd->planevec_n);
1520 dsvmul(-1, pcrd->dr23, dr32);
1521 sqrdist_32 = diprod(dr32, dr32);
1522 tol = sqrdist_32*GMX_REAL_EPS; /* Avoid tiny angles */
1523 if ((m2 > tol) && (n2 > tol))
1525 double a_01, a_23_01, a_23_45, a_45;
1526 double inv_dist_32, inv_sqrdist_32, dist_32;
1527 dvec u, v;
1528 inv_dist_32 = gmx::invsqrt(sqrdist_32);
1529 inv_sqrdist_32 = inv_dist_32*inv_dist_32;
1530 dist_32 = sqrdist_32*inv_dist_32;
1532 /* Forces on groups 0, 1 */
1533 a_01 = pcrd->f_scal*dist_32/m2; /* f_scal is -dV/dphi */
1534 dsvmul(-a_01, pcrd->planevec_m, pcrd->f01); /* added sign to get force on group 1, not 0 */
1536 /* Forces on groups 4, 5 */
1537 a_45 = -pcrd->f_scal*dist_32/n2;
1538 dsvmul(a_45, pcrd->planevec_n, pcrd->f45); /* force on group 5 */
1540 /* Force on groups 2, 3 (defining the axis) */
1541 a_23_01 = -diprod(pcrd->dr01, dr32)*inv_sqrdist_32;
1542 a_23_45 = -diprod(pcrd->dr45, dr32)*inv_sqrdist_32;
1543 dsvmul(-a_23_01, pcrd->f01, u); /* added sign to get force from group 0, not 1 */
1544 dsvmul(a_23_45, pcrd->f45, v);
1545 dvec_sub(u, v, pcrd->f23); /* force on group 3 */
1547 else
1549 /* No force to apply for ill-defined cases */
1550 clear_pull_forces_coord(pcrd);
1553 else
1555 for (int m = 0; m < DIM; m++)
1557 pcrd->f01[m] = pcrd->f_scal*pcrd->vec[m];
1563 void register_external_pull_potential(struct pull_t *pull,
1564 int coord_index,
1565 const char *provider)
1567 GMX_RELEASE_ASSERT(pull != nullptr, "register_external_pull_potential called before init_pull");
1568 GMX_RELEASE_ASSERT(provider != nullptr, "register_external_pull_potential called with NULL as provider name");
1570 if (coord_index < 0 || coord_index > pull->ncoord - 1)
1572 gmx_fatal(FARGS, "Module '%s' attempted to register an external potential for pull coordinate %d which is out of the pull coordinate range %d - %d\n",
1573 provider, coord_index + 1, 1, pull->ncoord);
1576 pull_coord_work_t *pcrd = &pull->coord[coord_index];
1578 if (pcrd->params.eType != epullEXTERNAL)
1580 gmx_fatal(FARGS, "Module '%s' attempted to register an external potential for pull coordinate %d which of type '%s', whereas external potentials are only supported with type '%s'",
1581 provider, coord_index + 1, epull_names[pcrd->params.eType], epull_names[epullEXTERNAL]);
1584 GMX_RELEASE_ASSERT(pcrd->params.externalPotentialProvider != nullptr, "The external potential provider string for a pull coordinate is NULL");
1586 if (gmx_strcasecmp(provider, pcrd->params.externalPotentialProvider) != 0)
1588 gmx_fatal(FARGS, "Module '%s' attempted to register an external potential for pull coordinate %d which expects the external potential to be provided by a module named '%s'",
1589 provider, coord_index + 1, pcrd->params.externalPotentialProvider);
1592 if (pcrd->bExternalPotentialProviderHasBeenRegistered)
1594 gmx_fatal(FARGS, "Module '%s' attempted to register an external potential for pull coordinate %d multiple times",
1595 provider, coord_index + 1);
1598 pcrd->bExternalPotentialProviderHasBeenRegistered = true;
1599 pull->numUnregisteredExternalPotentials--;
1601 GMX_RELEASE_ASSERT(pull->numUnregisteredExternalPotentials >= 0, "Negative unregisterd potentials, the pull code in inconsistent");
1605 static void check_external_potential_registration(const struct pull_t *pull)
1607 if (pull->numUnregisteredExternalPotentials > 0)
1609 int c;
1610 for (c = 0; c < pull->ncoord; c++)
1612 if (pull->coord[c].params.eType == epullEXTERNAL &&
1613 !pull->coord[c].bExternalPotentialProviderHasBeenRegistered)
1615 break;
1619 GMX_RELEASE_ASSERT(c < pull->ncoord, "Internal inconsistency in the pull potential provider counting");
1621 gmx_fatal(FARGS, "No external provider for external pull potentials have been provided for %d pull coordinates. The first coordinate without provider is number %d, which expects a module named '%s' to provide the external potential.",
1622 pull->numUnregisteredExternalPotentials,
1623 c + 1, pull->coord[c].params.externalPotentialProvider);
1628 /* Pull takes care of adding the forces of the external potential.
1629 * The external potential module has to make sure that the corresponding
1630 * potential energy is added either to the pull term or to a term
1631 * specific to the external module.
1633 void apply_external_pull_coord_force(struct pull_t *pull,
1634 int coord_index,
1635 double coord_force,
1636 const t_mdatoms *mdatoms,
1637 rvec *force, tensor virial)
1639 pull_coord_work_t *pcrd;
1641 GMX_ASSERT(coord_index >= 0 && coord_index < pull->ncoord, "apply_external_pull_coord_force called with coord_index out of range");
1643 if (pull->comm.bParticipate)
1645 pcrd = &pull->coord[coord_index];
1647 GMX_RELEASE_ASSERT(pcrd->params.eType == epullEXTERNAL, "The pull force can only be set externally on pull coordinates of external type");
1649 GMX_ASSERT(pcrd->bExternalPotentialProviderHasBeenRegistered, "apply_external_pull_coord_force called for an unregistered pull coordinate");
1651 /* Set the force */
1652 pcrd->f_scal = coord_force;
1654 /* Calculate the forces on the pull groups */
1655 calc_pull_coord_vector_force(pcrd);
1657 /* Add the forces for this coordinate to the total virial and force */
1658 add_virial_coord(virial, pcrd);
1660 apply_forces_coord(pull, coord_index, mdatoms, force);
1663 pull->numExternalPotentialsStillToBeAppliedThisStep--;
1666 /* Calculate the pull potential and scalar force for a pull coordinate */
1667 static void do_pull_pot_coord(struct pull_t *pull, int coord_ind, t_pbc *pbc,
1668 double t, real lambda,
1669 real *V, tensor vir, real *dVdl)
1671 pull_coord_work_t *pcrd;
1672 double dev;
1674 pcrd = &pull->coord[coord_ind];
1676 assert(pcrd->params.eType != epullCONSTRAINT);
1678 dev = get_pull_coord_deviation(pull, coord_ind, pbc, t);
1680 calc_pull_coord_scalar_force_and_potential(pcrd, dev, lambda, V, dVdl);
1682 calc_pull_coord_vector_force(pcrd);
1684 add_virial_coord(vir, pcrd);
1687 real pull_potential(struct pull_t *pull, t_mdatoms *md, t_pbc *pbc,
1688 t_commrec *cr, double t, real lambda,
1689 rvec *x, rvec *f, tensor vir, real *dvdlambda)
1691 real V = 0;
1693 assert(pull != NULL);
1695 /* Ideally we should check external potential registration only during
1696 * the initialization phase, but that requires another function call
1697 * that should be done exactly in the right order. So we check here.
1699 check_external_potential_registration(pull);
1701 if (pull->comm.bParticipate)
1703 real dVdl = 0;
1705 pull_calc_coms(cr, pull, md, pbc, t, x, nullptr);
1707 for (int c = 0; c < pull->ncoord; c++)
1709 /* For external potential the force is assumed to be given by an external module by a call to
1710 apply_pull_coord_external_force */
1711 if (pull->coord[c].params.eType == epullCONSTRAINT || pull->coord[c].params.eType == epullEXTERNAL)
1713 continue;
1716 do_pull_pot_coord(pull, c, pbc, t, lambda,
1717 &V, MASTER(cr) ? vir : nullptr, &dVdl);
1719 /* Distribute the force over the atoms in the pulled groups */
1720 apply_forces_coord(pull, c, md, f);
1723 if (MASTER(cr))
1725 *dvdlambda += dVdl;
1729 GMX_ASSERT(pull->numExternalPotentialsStillToBeAppliedThisStep == 0, "Too few or too many external pull potentials have been applied the previous step");
1730 /* All external pull potentials still need to be applied */
1731 pull->numExternalPotentialsStillToBeAppliedThisStep =
1732 pull->numCoordinatesWithExternalPotential;
1734 return (MASTER(cr) ? V : 0.0);
1737 void pull_constraint(struct pull_t *pull, t_mdatoms *md, t_pbc *pbc,
1738 t_commrec *cr, double dt, double t,
1739 rvec *x, rvec *xp, rvec *v, tensor vir)
1741 assert(pull != NULL);
1743 if (pull->comm.bParticipate)
1745 pull_calc_coms(cr, pull, md, pbc, t, x, xp);
1747 do_constraint(pull, pbc, xp, v, MASTER(cr), vir, dt, t);
1751 static void make_local_pull_group(gmx_ga2la_t *ga2la,
1752 pull_group_work_t *pg, int start, int end)
1754 int i, ii;
1756 pg->nat_loc = 0;
1757 for (i = 0; i < pg->params.nat; i++)
1759 ii = pg->params.ind[i];
1760 if (ga2la)
1762 if (!ga2la_get_home(ga2la, ii, &ii))
1764 ii = -1;
1767 if (ii >= start && ii < end)
1769 /* This is a home atom, add it to the local pull group */
1770 if (pg->nat_loc >= pg->nalloc_loc)
1772 pg->nalloc_loc = over_alloc_dd(pg->nat_loc+1);
1773 srenew(pg->ind_loc, pg->nalloc_loc);
1774 if (pg->epgrppbc == epgrppbcCOS || pg->params.weight != nullptr)
1776 srenew(pg->weight_loc, pg->nalloc_loc);
1779 pg->ind_loc[pg->nat_loc] = ii;
1780 if (pg->params.weight != nullptr)
1782 pg->weight_loc[pg->nat_loc] = pg->params.weight[i];
1784 pg->nat_loc++;
1789 void dd_make_local_pull_groups(t_commrec *cr, struct pull_t *pull, t_mdatoms *md)
1791 gmx_domdec_t *dd;
1792 pull_comm_t *comm;
1793 gmx_ga2la_t *ga2la;
1794 gmx_bool bMustParticipate;
1795 int g;
1797 dd = cr->dd;
1799 comm = &pull->comm;
1801 if (dd)
1803 ga2la = dd->ga2la;
1805 else
1807 ga2la = nullptr;
1810 /* We always make the master node participate, such that it can do i/o
1811 * and to simplify MC type extensions people might have.
1813 bMustParticipate = (comm->bParticipateAll || dd == nullptr || DDMASTER(dd));
1815 for (g = 0; g < pull->ngroup; g++)
1817 int a;
1819 make_local_pull_group(ga2la, &pull->group[g],
1820 0, md->homenr);
1822 /* We should participate if we have pull or pbc atoms */
1823 if (!bMustParticipate &&
1824 (pull->group[g].nat_loc > 0 ||
1825 (pull->group[g].params.pbcatom >= 0 &&
1826 ga2la_get_home(dd->ga2la, pull->group[g].params.pbcatom, &a))))
1828 bMustParticipate = TRUE;
1832 if (!comm->bParticipateAll)
1834 /* Keep currently not required ranks in the communicator
1835 * if they needed to participate up to 20 decompositions ago.
1836 * This avoids frequent rebuilds due to atoms jumping back and forth.
1838 const gmx_int64_t history_count = 20;
1839 gmx_bool bWillParticipate;
1840 int count[2];
1842 /* Increase the decomposition counter for the current call */
1843 comm->setup_count++;
1845 if (bMustParticipate)
1847 comm->must_count = comm->setup_count;
1850 bWillParticipate =
1851 bMustParticipate ||
1852 (comm->bParticipate &&
1853 comm->must_count >= comm->setup_count - history_count);
1855 if (debug && dd != nullptr)
1857 fprintf(debug, "Our DD rank (%3d) pull #atoms>0 or master: %d, will be part %d\n",
1858 dd->rank, bMustParticipate, bWillParticipate);
1861 if (bWillParticipate)
1863 /* Count the number of ranks that we want to have participating */
1864 count[0] = 1;
1865 /* Count the number of ranks that need to be added */
1866 count[1] = comm->bParticipate ? 0 : 1;
1868 else
1870 count[0] = 0;
1871 count[1] = 0;
1874 /* The cost of this global operation will be less that the cost
1875 * of the extra MPI_Comm_split calls that we can avoid.
1877 gmx_sumi(2, count, cr);
1879 /* If we are missing ranks or if we have 20% more ranks than needed
1880 * we make a new sub-communicator.
1882 if (count[1] > 0 || 6*count[0] < 5*comm->nparticipate)
1884 if (debug)
1886 fprintf(debug, "Creating new pull subcommunicator of size %d\n",
1887 count[0]);
1890 #if GMX_MPI
1891 if (comm->mpi_comm_com != MPI_COMM_NULL)
1893 MPI_Comm_free(&comm->mpi_comm_com);
1896 /* This might be an extremely expensive operation, so we try
1897 * to avoid this splitting as much as possible.
1899 assert(dd != NULL);
1900 MPI_Comm_split(dd->mpi_comm_all, bWillParticipate ? 0 : 1, dd->rank,
1901 &comm->mpi_comm_com);
1902 #endif
1904 comm->bParticipate = bWillParticipate;
1905 comm->nparticipate = count[0];
1909 /* Since the PBC of atoms might have changed, we need to update the PBC */
1910 pull->bSetPBCatoms = TRUE;
1913 static void init_pull_group_index(FILE *fplog, t_commrec *cr,
1914 int g, pull_group_work_t *pg,
1915 gmx_bool bConstraint, ivec pulldim_con,
1916 const gmx_mtop_t *mtop,
1917 const t_inputrec *ir, real lambda)
1919 if (EI_ENERGY_MINIMIZATION(ir->eI) || ir->eI == eiBD)
1921 /* There are no masses in the integrator.
1922 * But we still want to have the correct mass-weighted COMs.
1923 * So we store the real masses in the weights.
1924 * We do not set nweight, so these weights do not end up in the tpx file.
1926 if (pg->params.nweight == 0)
1928 snew(pg->params.weight, pg->params.nat);
1932 if (cr && PAR(cr))
1934 pg->nat_loc = 0;
1935 pg->nalloc_loc = 0;
1936 pg->ind_loc = nullptr;
1937 pg->weight_loc = nullptr;
1939 else
1941 pg->nat_loc = pg->params.nat;
1942 pg->ind_loc = pg->params.ind;
1943 if (pg->epgrppbc == epgrppbcCOS)
1945 snew(pg->weight_loc, pg->params.nat);
1947 else
1949 pg->weight_loc = pg->params.weight;
1953 const gmx_groups_t *groups = &mtop->groups;
1955 /* Count frozen dimensions and (weighted) mass */
1956 int nfrozen = 0;
1957 double tmass = 0;
1958 double wmass = 0;
1959 double wwmass = 0;
1960 int molb = 0;
1961 for (int i = 0; i < pg->params.nat; i++)
1963 int ii = pg->params.ind[i];
1964 if (bConstraint && ir->opts.nFreeze)
1966 for (int d = 0; d < DIM; d++)
1968 if (pulldim_con[d] == 1 &&
1969 ir->opts.nFreeze[ggrpnr(groups, egcFREEZE, ii)][d])
1971 nfrozen++;
1975 const t_atom &atom = mtopGetAtomParameters(mtop, ii, &molb);
1976 real m;
1977 if (ir->efep == efepNO)
1979 m = atom.m;
1981 else
1983 m = (1 - lambda)*atom.m + lambda*atom.mB;
1985 real w;
1986 if (pg->params.nweight > 0)
1988 w = pg->params.weight[i];
1990 else
1992 w = 1;
1994 if (EI_ENERGY_MINIMIZATION(ir->eI))
1996 /* Move the mass to the weight */
1997 w *= m;
1998 m = 1;
1999 pg->params.weight[i] = w;
2001 else if (ir->eI == eiBD)
2003 real mbd;
2004 if (ir->bd_fric)
2006 mbd = ir->bd_fric*ir->delta_t;
2008 else
2010 if (groups->grpnr[egcTC] == nullptr)
2012 mbd = ir->delta_t/ir->opts.tau_t[0];
2014 else
2016 mbd = ir->delta_t/ir->opts.tau_t[groups->grpnr[egcTC][ii]];
2019 w *= m/mbd;
2020 m = mbd;
2021 pg->params.weight[i] = w;
2023 tmass += m;
2024 wmass += m*w;
2025 wwmass += m*w*w;
2028 if (wmass == 0)
2030 /* We can have single atom groups with zero mass with potential pulling
2031 * without cosine weighting.
2033 if (pg->params.nat == 1 && !bConstraint && pg->epgrppbc != epgrppbcCOS)
2035 /* With one atom the mass doesn't matter */
2036 wwmass = 1;
2038 else
2040 gmx_fatal(FARGS, "The total%s mass of pull group %d is zero",
2041 pg->params.weight ? " weighted" : "", g);
2044 if (fplog)
2046 fprintf(fplog,
2047 "Pull group %d: %5d atoms, mass %9.3f",
2048 g, pg->params.nat, tmass);
2049 if (pg->params.weight ||
2050 EI_ENERGY_MINIMIZATION(ir->eI) || ir->eI == eiBD)
2052 fprintf(fplog, ", weighted mass %9.3f", wmass*wmass/wwmass);
2054 if (pg->epgrppbc == epgrppbcCOS)
2056 fprintf(fplog, ", cosine weighting will be used");
2058 fprintf(fplog, "\n");
2061 if (nfrozen == 0)
2063 /* A value != 0 signals not frozen, it is updated later */
2064 pg->invtm = -1.0;
2066 else
2068 int ndim = 0;
2069 for (int d = 0; d < DIM; d++)
2071 ndim += pulldim_con[d]*pg->params.nat;
2073 if (fplog && nfrozen > 0 && nfrozen < ndim)
2075 fprintf(fplog,
2076 "\nWARNING: In pull group %d some, but not all of the degrees of freedom\n"
2077 " that are subject to pulling are frozen.\n"
2078 " For constraint pulling the whole group will be frozen.\n\n",
2081 pg->invtm = 0.0;
2082 pg->wscale = 1.0;
2086 struct pull_t *
2087 init_pull(FILE *fplog, const pull_params_t *pull_params, const t_inputrec *ir,
2088 int nfile, const t_filenm fnm[],
2089 const gmx_mtop_t *mtop, t_commrec *cr,
2090 const gmx_output_env_t *oenv, real lambda,
2091 gmx_bool bOutFile, unsigned long Flags)
2093 struct pull_t *pull;
2094 pull_comm_t *comm;
2095 int g, c, m;
2097 snew(pull, 1);
2099 /* Copy the pull parameters */
2100 pull->params = *pull_params;
2101 /* Avoid pointer copies */
2102 pull->params.group = nullptr;
2103 pull->params.coord = nullptr;
2105 pull->ncoord = pull_params->ncoord;
2106 pull->ngroup = pull_params->ngroup;
2107 snew(pull->coord, pull->ncoord);
2108 snew(pull->group, pull->ngroup);
2110 pull->bPotential = FALSE;
2111 pull->bConstraint = FALSE;
2112 pull->bCylinder = FALSE;
2113 pull->bAngle = FALSE;
2115 for (g = 0; g < pull->ngroup; g++)
2117 pull_group_work_t *pgrp;
2118 int i;
2120 pgrp = &pull->group[g];
2122 /* Copy the pull group parameters */
2123 pgrp->params = pull_params->group[g];
2125 /* Avoid pointer copies by allocating and copying arrays */
2126 snew(pgrp->params.ind, pgrp->params.nat);
2127 for (i = 0; i < pgrp->params.nat; i++)
2129 pgrp->params.ind[i] = pull_params->group[g].ind[i];
2131 if (pgrp->params.nweight > 0)
2133 snew(pgrp->params.weight, pgrp->params.nweight);
2134 for (i = 0; i < pgrp->params.nweight; i++)
2136 pgrp->params.weight[i] = pull_params->group[g].weight[i];
2141 pull->numCoordinatesWithExternalPotential = 0;
2143 for (c = 0; c < pull->ncoord; c++)
2145 pull_coord_work_t *pcrd;
2146 int calc_com_start, calc_com_end, g;
2148 pcrd = &pull->coord[c];
2150 /* Copy all pull coordinate parameters */
2151 pcrd->params = pull_params->coord[c];
2153 switch (pcrd->params.eGeom)
2155 case epullgDIST:
2156 case epullgDIRRELATIVE: /* Direction vector is determined at each step */
2157 case epullgANGLE:
2158 case epullgDIHEDRAL:
2159 break;
2160 case epullgDIR:
2161 case epullgDIRPBC:
2162 case epullgCYL:
2163 case epullgANGLEAXIS:
2164 copy_rvec_to_dvec(pull_params->coord[c].vec, pcrd->vec);
2165 break;
2166 default:
2167 /* We allow reading of newer tpx files with new pull geometries,
2168 * but with the same tpx format, with old code. A new geometry
2169 * only adds a new enum value, which will be out of range for
2170 * old code. The first place we need to generate an error is
2171 * here, since the pull code can't handle this.
2172 * The enum can be used before arriving here only for printing
2173 * the string corresponding to the geometry, which will result
2174 * in printing "UNDEFINED".
2176 gmx_fatal(FARGS, "Pull geometry not supported for pull coordinate %d. The geometry enum %d in the input is larger than that supported by the code (up to %d). You are probably reading a tpr file generated with a newer version of Gromacs with an binary from an older version of Gromacs.",
2177 c + 1, pcrd->params.eGeom, epullgNR - 1);
2180 if (pcrd->params.eType == epullCONSTRAINT)
2182 /* Check restrictions of the constraint pull code */
2183 if (pcrd->params.eGeom == epullgCYL ||
2184 pcrd->params.eGeom == epullgDIRRELATIVE ||
2185 pcrd->params.eGeom == epullgANGLE ||
2186 pcrd->params.eGeom == epullgDIHEDRAL ||
2187 pcrd->params.eGeom == epullgANGLEAXIS)
2189 gmx_fatal(FARGS, "Pulling of type %s can not be combined with geometry %s. Consider using pull type %s.",
2190 epull_names[pcrd->params.eType],
2191 epullg_names[pcrd->params.eGeom],
2192 epull_names[epullUMBRELLA]);
2195 pull->bConstraint = TRUE;
2197 else
2199 pull->bPotential = TRUE;
2202 if (pcrd->params.eGeom == epullgCYL)
2204 pull->bCylinder = TRUE;
2206 else if (pcrd->params.eGeom == epullgANGLE || pcrd->params.eGeom == epullgDIHEDRAL || pcrd->params.eGeom == epullgANGLEAXIS)
2208 pull->bAngle = TRUE;
2211 /* We only need to calculate the plain COM of a group
2212 * when it is not only used as a cylinder group.
2214 calc_com_start = (pcrd->params.eGeom == epullgCYL ? 1 : 0);
2215 calc_com_end = pcrd->params.ngroup;
2217 for (g = calc_com_start; g <= calc_com_end; g++)
2219 pull->group[pcrd->params.group[g]].bCalcCOM = TRUE;
2222 /* With non-zero rate the reference value is set at every step */
2223 if (pcrd->params.rate == 0)
2225 /* Initialize the constant reference value */
2226 if (pcrd->params.eType != epullEXTERNAL)
2228 low_set_pull_coord_reference_value(pcrd, c, pcrd->params.init*pull_conversion_factor_userinput2internal(&pcrd->params));
2230 else
2232 /* With an external pull potential, the reference value loses
2233 * it's meaning and should not be used. Setting it to zero
2234 * makes any terms dependent on it disappear.
2235 * The only issue this causes is that with cylinder pulling
2236 * no atoms of the cylinder group within the cylinder radius
2237 * should be more than half a box length away from the COM of
2238 * the pull group along the axial direction.
2240 pcrd->value_ref = 0.0;
2244 if (pcrd->params.eType == epullEXTERNAL)
2246 GMX_RELEASE_ASSERT(pcrd->params.rate == 0, "With an external potential, a pull coordinate should have rate = 0");
2248 /* This external potential needs to be registered later */
2249 pull->numCoordinatesWithExternalPotential++;
2251 pcrd->bExternalPotentialProviderHasBeenRegistered = false;
2254 pull->numUnregisteredExternalPotentials =
2255 pull->numCoordinatesWithExternalPotential;
2256 pull->numExternalPotentialsStillToBeAppliedThisStep = 0;
2258 pull->ePBC = ir->ePBC;
2259 switch (pull->ePBC)
2261 case epbcNONE: pull->npbcdim = 0; break;
2262 case epbcXY: pull->npbcdim = 2; break;
2263 default: pull->npbcdim = 3; break;
2266 if (fplog)
2268 gmx_bool bAbs, bCos;
2270 bAbs = FALSE;
2271 for (c = 0; c < pull->ncoord; c++)
2273 if (pull->group[pull->coord[c].params.group[0]].params.nat == 0 ||
2274 pull->group[pull->coord[c].params.group[1]].params.nat == 0)
2276 bAbs = TRUE;
2280 fprintf(fplog, "\n");
2281 if (pull->bPotential)
2283 fprintf(fplog, "Will apply potential COM pulling\n");
2285 if (pull->bConstraint)
2287 fprintf(fplog, "Will apply constraint COM pulling\n");
2289 fprintf(fplog, "with %d pull coordinate%s and %d group%s\n",
2290 pull->ncoord, pull->ncoord == 1 ? "" : "s",
2291 pull->ngroup, pull->ngroup == 1 ? "" : "s");
2292 if (bAbs)
2294 fprintf(fplog, "with an absolute reference\n");
2296 bCos = FALSE;
2297 for (g = 0; g < pull->ngroup; g++)
2299 if (pull->group[g].params.nat > 1 &&
2300 pull->group[g].params.pbcatom < 0)
2302 /* We are using cosine weighting */
2303 fprintf(fplog, "Cosine weighting is used for group %d\n", g);
2304 bCos = TRUE;
2307 if (bCos)
2309 please_cite(fplog, "Engin2010");
2313 pull->bRefAt = FALSE;
2314 pull->cosdim = -1;
2315 for (g = 0; g < pull->ngroup; g++)
2317 pull_group_work_t *pgrp;
2319 pgrp = &pull->group[g];
2320 pgrp->epgrppbc = epgrppbcNONE;
2321 if (pgrp->params.nat > 0)
2323 /* There is an issue when a group is used in multiple coordinates
2324 * and constraints are applied in different dimensions with atoms
2325 * frozen in some, but not all dimensions.
2326 * Since there is only one mass array per group, we can't have
2327 * frozen/non-frozen atoms for different coords at the same time.
2328 * But since this is a very exotic case, we don't check for this.
2329 * A warning is printed in init_pull_group_index.
2332 gmx_bool bConstraint;
2333 ivec pulldim, pulldim_con;
2335 /* Loop over all pull coordinates to see along which dimensions
2336 * this group is pulled and if it is involved in constraints.
2338 bConstraint = FALSE;
2339 clear_ivec(pulldim);
2340 clear_ivec(pulldim_con);
2341 for (c = 0; c < pull->ncoord; c++)
2343 pull_coord_work_t *pcrd;
2344 int gi;
2345 gmx_bool bGroupUsed;
2347 pcrd = &pull->coord[c];
2349 bGroupUsed = FALSE;
2350 for (gi = 0; gi < pcrd->params.ngroup; gi++)
2352 if (pcrd->params.group[gi] == g)
2354 bGroupUsed = TRUE;
2358 if (bGroupUsed)
2360 for (m = 0; m < DIM; m++)
2362 if (pcrd->params.dim[m] == 1)
2364 pulldim[m] = 1;
2366 if (pcrd->params.eType == epullCONSTRAINT)
2368 bConstraint = TRUE;
2369 pulldim_con[m] = 1;
2376 /* Determine if we need to take PBC into account for calculating
2377 * the COM's of the pull groups.
2379 GMX_RELEASE_ASSERT(pull->npbcdim <= DIM, "npbcdim must be <= the number of dimensions");
2380 for (m = 0; m < pull->npbcdim; m++)
2382 GMX_RELEASE_ASSERT(m <= DIM, "npbcdim must be <= the number of dimensions");
2383 if (pulldim[m] == 1 && pgrp->params.nat > 1)
2385 if (pgrp->params.pbcatom >= 0)
2387 pgrp->epgrppbc = epgrppbcREFAT;
2388 pull->bRefAt = TRUE;
2390 else
2392 if (pgrp->params.weight != nullptr)
2394 gmx_fatal(FARGS, "Pull groups can not have relative weights and cosine weighting at same time");
2396 pgrp->epgrppbc = epgrppbcCOS;
2397 if (pull->cosdim >= 0 && pull->cosdim != m)
2399 gmx_fatal(FARGS, "Can only use cosine weighting with pulling in one dimension (use mdp option pull-coord?-dim)");
2401 pull->cosdim = m;
2405 /* Set the indices */
2406 init_pull_group_index(fplog, cr, g, pgrp,
2407 bConstraint, pulldim_con,
2408 mtop, ir, lambda);
2410 else
2412 /* Absolute reference, set the inverse mass to zero.
2413 * This is only relevant (and used) with constraint pulling.
2415 pgrp->invtm = 0;
2416 pgrp->wscale = 1;
2420 /* If we use cylinder coordinates, do some initialising for them */
2421 if (pull->bCylinder)
2423 snew(pull->dyna, pull->ncoord);
2425 for (c = 0; c < pull->ncoord; c++)
2427 const pull_coord_work_t *pcrd;
2429 pcrd = &pull->coord[c];
2431 if (pcrd->params.eGeom == epullgCYL)
2433 if (pull->group[pcrd->params.group[0]].params.nat == 0)
2435 gmx_fatal(FARGS, "A cylinder pull group is not supported when using absolute reference!\n");
2441 /* The gmx_omp_nthreads module might not be initialized here, so max(1,) */
2442 pull->nthreads = std::max(1, gmx_omp_nthreads_get(emntDefault));
2443 snew(pull->sum_com, pull->nthreads);
2445 comm = &pull->comm;
2447 #if GMX_MPI
2448 /* Use a sub-communicator when we have more than 32 ranks */
2449 comm->bParticipateAll = (cr == nullptr || !DOMAINDECOMP(cr) ||
2450 cr->dd->nnodes <= 32 ||
2451 getenv("GMX_PULL_PARTICIPATE_ALL") != nullptr);
2452 /* This sub-commicator is not used with comm->bParticipateAll,
2453 * so we can always initialize it to NULL.
2455 comm->mpi_comm_com = MPI_COMM_NULL;
2456 comm->nparticipate = 0;
2457 #else
2458 /* No MPI: 1 rank: all ranks pull */
2459 comm->bParticipateAll = TRUE;
2460 #endif
2461 comm->bParticipate = comm->bParticipateAll;
2462 comm->setup_count = 0;
2463 comm->must_count = 0;
2465 if (!comm->bParticipateAll && fplog != nullptr)
2467 fprintf(fplog, "Will use a sub-communicator for pull communication\n");
2470 comm->rbuf = nullptr;
2471 comm->dbuf = nullptr;
2472 comm->dbuf_cyl = nullptr;
2474 /* We still need to initialize the PBC reference coordinates */
2475 pull->bSetPBCatoms = TRUE;
2477 /* Only do I/O when we are doing dynamics and if we are the MASTER */
2478 pull->out_x = nullptr;
2479 pull->out_f = nullptr;
2480 if (bOutFile)
2482 /* Check for px and pf filename collision, if we are writing
2483 both files */
2484 std::string px_filename, pf_filename;
2485 std::string px_appended, pf_appended;
2488 px_filename = std::string(opt2fn("-px", nfile, fnm));
2489 pf_filename = std::string(opt2fn("-pf", nfile, fnm));
2491 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
2494 if ((pull->params.nstxout != 0) &&
2495 (pull->params.nstfout != 0) &&
2496 (px_filename == pf_filename))
2498 if (!opt2bSet("-px", nfile, fnm) && !opt2bSet("-pf", nfile, fnm))
2500 /* We are writing both pull files but neither set directly. */
2503 px_appended = append_before_extension(px_filename, "_pullx");
2504 pf_appended = append_before_extension(pf_filename, "_pullf");
2506 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
2507 pull->out_x = open_pull_out(px_appended.c_str(), pull, oenv,
2508 TRUE, Flags);
2509 pull->out_f = open_pull_out(pf_appended.c_str(), pull, oenv,
2510 FALSE, Flags);
2511 return pull;
2513 else
2515 /* If one of -px and -pf is set but the filenames are identical: */
2516 gmx_fatal(FARGS, "Identical pull_x and pull_f output filenames %s",
2517 px_filename.c_str());
2520 if (pull->params.nstxout != 0)
2522 pull->out_x = open_pull_out(opt2fn("-px", nfile, fnm), pull, oenv,
2523 TRUE, Flags);
2525 if (pull->params.nstfout != 0)
2527 pull->out_f = open_pull_out(opt2fn("-pf", nfile, fnm), pull, oenv,
2528 FALSE, Flags);
2532 return pull;
2535 static void destroy_pull_group(pull_group_work_t *pgrp)
2537 if (pgrp->ind_loc != pgrp->params.ind)
2539 sfree(pgrp->ind_loc);
2541 if (pgrp->weight_loc != pgrp->params.weight)
2543 sfree(pgrp->weight_loc);
2545 sfree(pgrp->mdw);
2546 sfree(pgrp->dv);
2548 sfree(pgrp->params.ind);
2549 sfree(pgrp->params.weight);
2552 static void destroy_pull(struct pull_t *pull)
2554 int i;
2556 for (i = 0; i < pull->ngroup; i++)
2558 destroy_pull_group(&pull->group[i]);
2560 for (i = 0; i < pull->ncoord; i++)
2562 if (pull->coord[i].params.eGeom == epullgCYL)
2564 destroy_pull_group(&(pull->dyna[i]));
2567 sfree(pull->group);
2568 sfree(pull->dyna);
2569 sfree(pull->coord);
2571 #if GMX_MPI
2572 if (pull->comm.mpi_comm_com != MPI_COMM_NULL)
2574 MPI_Comm_free(&pull->comm.mpi_comm_com);
2576 #endif
2577 sfree(pull->comm.rbuf);
2578 sfree(pull->comm.dbuf);
2579 sfree(pull->comm.dbuf_cyl);
2581 sfree(pull);
2584 void finish_pull(struct pull_t *pull)
2586 check_external_potential_registration(pull);
2588 if (pull->out_x)
2590 gmx_fio_fclose(pull->out_x);
2592 if (pull->out_f)
2594 gmx_fio_fclose(pull->out_f);
2597 destroy_pull(pull);
2600 gmx_bool pull_have_potential(const struct pull_t *pull)
2602 return pull->bPotential;
2605 gmx_bool pull_have_constraint(const struct pull_t *pull)
2607 return pull->bConstraint;