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, 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.
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/mdrun.h"
62 #include "gromacs/mdtypes/commrec.h"
63 #include "gromacs/mdtypes/inputrec.h"
64 #include "gromacs/mdtypes/md_enums.h"
65 #include "gromacs/mdtypes/mdatom.h"
66 #include "gromacs/pbcutil/pbc.h"
67 #include "gromacs/pulling/pull_internal.h"
68 #include "gromacs/topology/mtop_util.h"
69 #include "gromacs/topology/topology.h"
70 #include "gromacs/utility/exceptions.h"
71 #include "gromacs/utility/fatalerror.h"
72 #include "gromacs/utility/futil.h"
73 #include "gromacs/utility/gmxassert.h"
74 #include "gromacs/utility/pleasecite.h"
75 #include "gromacs/utility/real.h"
76 #include "gromacs/utility/smalloc.h"
78 static bool pull_coordinate_is_angletype(const t_pull_coord
*pcrd
)
80 return (pcrd
->eGeom
== epullgANGLE
||
81 pcrd
->eGeom
== epullgDIHEDRAL
||
82 pcrd
->eGeom
== epullgANGLEAXIS
);
85 const char *pull_coordinate_units(const t_pull_coord
*pcrd
)
87 return pull_coordinate_is_angletype(pcrd
) ? "deg" : "nm";
90 double pull_conversion_factor_userinput2internal(const t_pull_coord
*pcrd
)
92 if (pull_coordinate_is_angletype(pcrd
))
102 double pull_conversion_factor_internal2userinput(const t_pull_coord
*pcrd
)
104 if (pull_coordinate_is_angletype(pcrd
))
114 static std::string
append_before_extension(std::string pathname
,
115 std::string to_append
)
117 /* Appends to_append before last '.' in pathname */
118 size_t extPos
= pathname
.find_last_of('.');
119 if (extPos
== std::string::npos
)
121 return pathname
+ to_append
;
125 return pathname
.substr(0, extPos
) + to_append
+
126 pathname
.substr(extPos
, std::string::npos
);
130 static void pull_print_group_x(FILE *out
, ivec dim
,
131 const pull_group_work_t
*pgrp
)
135 for (m
= 0; m
< DIM
; m
++)
139 fprintf(out
, "\t%g", pgrp
->x
[m
]);
144 static void pull_print_coord_dr_components(FILE *out
, const ivec dim
, const dvec dr
)
146 for (int m
= 0; m
< DIM
; m
++)
150 fprintf(out
, "\t%g", dr
[m
]);
155 static void pull_print_coord_dr(FILE *out
, const pull_coord_work_t
*pcrd
,
156 gmx_bool bPrintRefValue
,
157 gmx_bool bPrintComponents
)
159 double unit_factor
= pull_conversion_factor_internal2userinput(&pcrd
->params
);
161 fprintf(out
, "\t%g", pcrd
->value
*unit_factor
);
165 fprintf(out
, "\t%g", pcrd
->value_ref
*unit_factor
);
168 if (bPrintComponents
)
170 pull_print_coord_dr_components(out
, pcrd
->params
.dim
, pcrd
->dr01
);
171 if (pcrd
->params
.ngroup
>= 4)
173 pull_print_coord_dr_components(out
, pcrd
->params
.dim
, pcrd
->dr23
);
175 if (pcrd
->params
.ngroup
>= 6)
177 pull_print_coord_dr_components(out
, pcrd
->params
.dim
, pcrd
->dr45
);
182 static void pull_print_x(FILE *out
, struct pull_t
*pull
, double t
)
186 fprintf(out
, "%.4f", t
);
188 for (c
= 0; c
< pull
->ncoord
; c
++)
190 pull_coord_work_t
*pcrd
;
192 pcrd
= &pull
->coord
[c
];
194 pull_print_coord_dr(out
, pcrd
,
195 pull
->params
.bPrintRefValue
,
196 pull
->params
.bPrintComp
);
198 if (pull
->params
.bPrintCOM
)
200 if (pcrd
->params
.eGeom
== epullgCYL
)
202 pull_print_group_x(out
, pcrd
->params
.dim
, &pull
->dyna
[c
]);
206 pull_print_group_x(out
, pcrd
->params
.dim
,
207 &pull
->group
[pcrd
->params
.group
[0]]);
209 for (int g
= 1; g
< pcrd
->params
.ngroup
; g
++)
211 pull_print_group_x(out
, pcrd
->params
.dim
, &pull
->group
[pcrd
->params
.group
[g
]]);
218 static void pull_print_f(FILE *out
, struct pull_t
*pull
, double t
)
222 fprintf(out
, "%.4f", t
);
224 for (c
= 0; c
< pull
->ncoord
; c
++)
226 fprintf(out
, "\t%g", pull
->coord
[c
].f_scal
);
231 void pull_print_output(struct pull_t
*pull
, gmx_int64_t step
, double time
)
233 if ((pull
->params
.nstxout
!= 0) && (step
% pull
->params
.nstxout
== 0))
235 pull_print_x(pull
->out_x
, pull
, time
);
238 if ((pull
->params
.nstfout
!= 0) && (step
% pull
->params
.nstfout
== 0))
240 pull_print_f(pull
->out_f
, pull
, time
);
244 static void set_legend_for_coord_components(const pull_coord_work_t
*pcrd
, int coord_index
, char **setname
, int *nsets_ptr
)
246 /* Loop over the distance vectors and print their components. Each vector is made up of two consecutive groups. */
247 for (int g
= 0; g
< pcrd
->params
.ngroup
; g
+= 2)
249 /* Loop over the components */
250 for (int m
= 0; m
< DIM
; m
++)
252 if (pcrd
->params
.dim
[m
])
256 if (g
== 0 && pcrd
->params
.ngroup
<= 2)
258 /* For the simplest case we print a simplified legend without group indices, just the cooordinate index
259 and which dimensional component it is. */
260 sprintf(legend
, "%d d%c", coord_index
+ 1, 'X' + m
);
264 /* Otherwise, print also the group indices (relative to the coordinate, not the global ones). */
265 sprintf(legend
, "%d g %d-%d d%c", coord_index
+ 1, g
+ 1, g
+ 2, 'X' + m
);
268 setname
[*nsets_ptr
] = gmx_strdup(legend
);
275 static FILE *open_pull_out(const char *fn
, struct pull_t
*pull
,
276 const gmx_output_env_t
*oenv
,
277 gmx_bool bCoord
, unsigned long Flags
)
281 char **setname
, buf
[50];
283 if (Flags
& MD_APPENDFILES
)
285 fp
= gmx_fio_fopen(fn
, "a+");
289 fp
= gmx_fio_fopen(fn
, "w+");
292 sprintf(buf
, "Position (nm%s)", pull
->bAngle
? ", deg" : "");
293 xvgr_header(fp
, "Pull COM", "Time (ps)", buf
,
298 sprintf(buf
, "Force (kJ/mol/nm%s)", pull
->bAngle
? ", kJ/mol/rad" : "");
299 xvgr_header(fp
, "Pull force", "Time (ps)", buf
,
303 /* With default mdp options only the actual coordinate value is printed (1),
304 * but optionally the reference value (+ 1),
305 * the group COMs for all the groups (+ ngroups_max*DIM)
306 * and the components of the distance vectors can be printed (+ (ngroups_max/2)*DIM).
308 snew(setname
, pull
->ncoord
*(1 + 1 + c_pullCoordNgroupMax
*DIM
+ c_pullCoordNgroupMax
/2*DIM
));
311 for (c
= 0; c
< pull
->ncoord
; c
++)
315 /* The order of this legend should match the order of printing
316 * the data in print_pull_x above.
319 /* The pull coord distance */
320 sprintf(buf
, "%d", c
+1);
321 setname
[nsets
] = gmx_strdup(buf
);
323 if (pull
->params
.bPrintRefValue
)
325 sprintf(buf
, "%d ref", c
+1);
326 setname
[nsets
] = gmx_strdup(buf
);
329 if (pull
->params
.bPrintComp
)
331 set_legend_for_coord_components(&pull
->coord
[c
], c
, setname
, &nsets
);
334 if (pull
->params
.bPrintCOM
)
336 for (int g
= 0; g
< pull
->coord
[c
].params
.ngroup
; g
++)
338 /* Legend for reference group position */
339 for (m
= 0; m
< DIM
; m
++)
341 if (pull
->coord
[c
].params
.dim
[m
])
343 sprintf(buf
, "%d g %d %c", c
+1, g
+ 1, 'X'+m
);
344 setname
[nsets
] = gmx_strdup(buf
);
353 /* For the pull force we always only use one scalar */
354 sprintf(buf
, "%d", c
+1);
355 setname
[nsets
] = gmx_strdup(buf
);
361 xvgr_legend(fp
, nsets
, (const char**)setname
, oenv
);
363 for (c
= 0; c
< nsets
; c
++)
373 /* Apply forces in a mass weighted fashion */
374 static void apply_forces_grp(const pull_group_work_t
*pgrp
,
376 const dvec f_pull
, int sign
, rvec
*f
)
379 double wmass
, inv_wm
;
381 inv_wm
= pgrp
->mwscale
;
383 if (pgrp
->params
.nat
== 1 && pgrp
->nat_loc
== 1)
385 /* Only one atom and our rank has this atom: we can skip
386 * the mass weighting, which means that this code also works
387 * for mass=0, e.g. with a virtual site.
389 for (m
= 0; m
< DIM
; m
++)
391 f
[pgrp
->ind_loc
[0]][m
] += sign
*f_pull
[m
];
396 for (i
= 0; i
< pgrp
->nat_loc
; i
++)
398 ii
= pgrp
->ind_loc
[i
];
399 wmass
= md
->massT
[ii
];
400 if (pgrp
->weight_loc
)
402 wmass
*= pgrp
->weight_loc
[i
];
405 for (m
= 0; m
< DIM
; m
++)
407 f
[ii
][m
] += sign
* wmass
* f_pull
[m
] * inv_wm
;
413 /* Apply forces in a mass weighted fashion to a cylinder group */
414 static void apply_forces_cyl_grp(const pull_group_work_t
*pgrp
,
417 const dvec f_pull
, double f_scal
,
421 double mass
, weight
, inv_wm
, dv_com
;
423 inv_wm
= pgrp
->mwscale
;
425 for (i
= 0; i
< pgrp
->nat_loc
; i
++)
427 ii
= pgrp
->ind_loc
[i
];
428 mass
= md
->massT
[ii
];
429 weight
= pgrp
->weight_loc
[i
];
430 /* The stored axial distance from the cylinder center (dv) needs
431 * to be corrected for an offset (dv_corr), which was unknown when
434 dv_com
= pgrp
->dv
[i
] + dv_corr
;
436 /* Here we not only add the pull force working along vec (f_pull),
437 * but also a radial component, due to the dependence of the weights
438 * on the radial distance.
440 for (m
= 0; m
< DIM
; m
++)
442 f
[ii
][m
] += sign
*inv_wm
*(mass
*weight
*f_pull
[m
] +
443 pgrp
->mdw
[i
][m
]*dv_com
*f_scal
);
448 /* Apply torque forces in a mass weighted fashion to the groups that define
449 * the pull vector direction for pull coordinate pcrd.
451 static void apply_forces_vec_torque(const struct pull_t
*pull
,
452 const pull_coord_work_t
*pcrd
,
460 /* The component inpr along the pull vector is accounted for in the usual
461 * way. Here we account for the component perpendicular to vec.
464 for (m
= 0; m
< DIM
; m
++)
466 inpr
+= pcrd
->dr01
[m
]*pcrd
->vec
[m
];
468 /* The torque force works along the component of the distance vector
469 * of between the two "usual" pull groups that is perpendicular to
470 * the pull vector. The magnitude of this force is the "usual" scale force
471 * multiplied with the ratio of the distance between the two "usual" pull
472 * groups and the distance between the two groups that define the vector.
474 for (m
= 0; m
< DIM
; m
++)
476 f_perp
[m
] = (pcrd
->dr01
[m
] - inpr
*pcrd
->vec
[m
])/pcrd
->vec_len
*pcrd
->f_scal
;
479 /* Apply the force to the groups defining the vector using opposite signs */
480 apply_forces_grp(&pull
->group
[pcrd
->params
.group
[2]], md
, f_perp
, -1, f
);
481 apply_forces_grp(&pull
->group
[pcrd
->params
.group
[3]], md
, f_perp
, 1, f
);
484 /* Apply forces in a mass weighted fashion */
485 static void apply_forces_coord(struct pull_t
* pull
, int coord
,
486 const t_mdatoms
* md
,
489 const pull_coord_work_t
*pcrd
;
491 pcrd
= &pull
->coord
[coord
];
493 if (pcrd
->params
.eGeom
== epullgCYL
)
498 apply_forces_cyl_grp(&pull
->dyna
[coord
], pcrd
->cyl_dev
, md
,
499 pcrd
->f01
, pcrd
->f_scal
, -1, f
);
501 /* Sum the force along the vector and the radial force */
502 for (m
= 0; m
< DIM
; m
++)
504 f_tot
[m
] = pcrd
->f01
[m
] + pcrd
->f_scal
*pcrd
->ffrad
[m
];
506 apply_forces_grp(&pull
->group
[pcrd
->params
.group
[1]], md
, f_tot
, 1, f
);
510 if (pcrd
->params
.eGeom
== epullgDIRRELATIVE
)
512 /* We need to apply the torque forces to the pull groups
513 * that define the pull vector.
515 apply_forces_vec_torque(pull
, pcrd
, md
, f
);
518 if (pull
->group
[pcrd
->params
.group
[0]].params
.nat
> 0)
520 apply_forces_grp(&pull
->group
[pcrd
->params
.group
[0]], md
, pcrd
->f01
, -1, f
);
522 apply_forces_grp(&pull
->group
[pcrd
->params
.group
[1]], md
, pcrd
->f01
, 1, f
);
524 if (pcrd
->params
.ngroup
>= 4)
526 apply_forces_grp(&pull
->group
[pcrd
->params
.group
[2]], md
, pcrd
->f23
, -1, f
);
527 apply_forces_grp(&pull
->group
[pcrd
->params
.group
[3]], md
, pcrd
->f23
, 1, f
);
529 if (pcrd
->params
.ngroup
>= 6)
531 apply_forces_grp(&pull
->group
[pcrd
->params
.group
[4]], md
, pcrd
->f45
, -1, f
);
532 apply_forces_grp(&pull
->group
[pcrd
->params
.group
[5]], md
, pcrd
->f45
, 1, f
);
537 static double max_pull_distance2(const pull_coord_work_t
*pcrd
,
543 max_d2
= GMX_DOUBLE_MAX
;
545 for (m
= 0; m
< pbc
->ndim_ePBC
; m
++)
547 if (pcrd
->params
.dim
[m
] != 0)
549 max_d2
= std::min(max_d2
, static_cast<double>(norm2(pbc
->box
[m
])));
556 /* This function returns the distance based on coordinates xg and xref.
557 * Note that the pull coordinate struct pcrd is not modified.
559 static void low_get_pull_coord_dr(const struct pull_t
*pull
,
560 const pull_coord_work_t
*pcrd
,
562 dvec xg
, dvec xref
, double max_dist2
,
565 const pull_group_work_t
*pgrp0
;
567 dvec xrefr
, dref
= {0, 0, 0};
570 pgrp0
= &pull
->group
[pcrd
->params
.group
[0]];
572 /* Only the first group can be an absolute reference, in that case nat=0 */
573 if (pgrp0
->params
.nat
== 0)
575 for (m
= 0; m
< DIM
; m
++)
577 xref
[m
] = pcrd
->params
.origin
[m
];
581 copy_dvec(xref
, xrefr
);
583 if (pcrd
->params
.eGeom
== epullgDIRPBC
)
585 for (m
= 0; m
< DIM
; m
++)
587 dref
[m
] = pcrd
->value_ref
*pcrd
->vec
[m
];
589 /* Add the reference position, so we use the correct periodic image */
590 dvec_inc(xrefr
, dref
);
593 pbc_dx_d(pbc
, xg
, xrefr
, dr
);
595 for (m
= 0; m
< DIM
; m
++)
597 dr
[m
] *= pcrd
->params
.dim
[m
];
600 if (max_dist2
>= 0 && dr2
> 0.98*0.98*max_dist2
)
602 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",
603 pcrd
->params
.group
[0], pcrd
->params
.group
[1],
604 sqrt(dr2
), sqrt(0.98*0.98*max_dist2
));
607 if (pcrd
->params
.eGeom
== epullgDIRPBC
)
613 /* This function returns the distance based on the contents of the pull struct.
614 * pull->coord[coord_ind].dr, and potentially vector, are updated.
616 static void get_pull_coord_dr(struct pull_t
*pull
,
621 pull_coord_work_t
*pcrd
;
622 pull_group_work_t
*pgrp0
, *pgrp1
;
624 pcrd
= &pull
->coord
[coord_ind
];
626 if (pcrd
->params
.eGeom
== epullgDIRPBC
)
632 md2
= max_pull_distance2(pcrd
, pbc
);
635 if (pcrd
->params
.eGeom
== epullgDIRRELATIVE
)
637 /* We need to determine the pull vector */
638 const pull_group_work_t
*pgrp2
, *pgrp3
;
642 pgrp2
= &pull
->group
[pcrd
->params
.group
[2]];
643 pgrp3
= &pull
->group
[pcrd
->params
.group
[3]];
645 pbc_dx_d(pbc
, pgrp3
->x
, pgrp2
->x
, vec
);
647 for (m
= 0; m
< DIM
; m
++)
649 vec
[m
] *= pcrd
->params
.dim
[m
];
651 pcrd
->vec_len
= dnorm(vec
);
652 for (m
= 0; m
< DIM
; m
++)
654 pcrd
->vec
[m
] = vec
[m
]/pcrd
->vec_len
;
658 fprintf(debug
, "pull coord %d vector: %6.3f %6.3f %6.3f normalized: %6.3f %6.3f %6.3f\n",
660 vec
[XX
], vec
[YY
], vec
[ZZ
],
661 pcrd
->vec
[XX
], pcrd
->vec
[YY
], pcrd
->vec
[ZZ
]);
665 pgrp0
= &pull
->group
[pcrd
->params
.group
[0]];
666 pgrp1
= &pull
->group
[pcrd
->params
.group
[1]];
668 low_get_pull_coord_dr(pull
, pcrd
, pbc
,
670 pcrd
->params
.eGeom
== epullgCYL
? pull
->dyna
[coord_ind
].x
: pgrp0
->x
,
674 if (pcrd
->params
.ngroup
>= 4)
676 pull_group_work_t
*pgrp2
, *pgrp3
;
677 pgrp2
= &pull
->group
[pcrd
->params
.group
[2]];
678 pgrp3
= &pull
->group
[pcrd
->params
.group
[3]];
680 low_get_pull_coord_dr(pull
, pcrd
, pbc
,
686 if (pcrd
->params
.ngroup
>= 6)
688 pull_group_work_t
*pgrp4
, *pgrp5
;
689 pgrp4
= &pull
->group
[pcrd
->params
.group
[4]];
690 pgrp5
= &pull
->group
[pcrd
->params
.group
[5]];
692 low_get_pull_coord_dr(pull
, pcrd
, pbc
,
700 /* Modify x so that it is periodic in [-pi, pi)
701 * It is assumed that x is in [-3pi, 3pi) so that x
702 * needs to be shifted by at most one period.
704 static void make_periodic_2pi(double *x
)
716 /* This function should always be used to modify pcrd->value_ref */
717 static void low_set_pull_coord_reference_value(pull_coord_work_t
*pcrd
,
721 if (pcrd
->params
.eGeom
== epullgDIST
)
725 gmx_fatal(FARGS
, "Pull reference distance for coordinate %d (%f) needs to be non-negative", coord_ind
+ 1, value_ref
);
728 else if (pcrd
->params
.eGeom
== epullgANGLE
|| pcrd
->params
.eGeom
== epullgANGLEAXIS
)
730 if (value_ref
< 0 || value_ref
> M_PI
)
732 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
));
735 else if (pcrd
->params
.eGeom
== epullgDIHEDRAL
)
737 /* Allow pulling to be periodic for dihedral angles by remapping the reference value to the interval [-pi, pi). */
738 make_periodic_2pi(&value_ref
);
741 pcrd
->value_ref
= value_ref
;
744 static void update_pull_coord_reference_value(pull_coord_work_t
*pcrd
, int coord_ind
, double t
)
746 /* With zero rate the reference value is set initially and doesn't change */
747 if (pcrd
->params
.rate
!= 0)
749 double value_ref
= (pcrd
->params
.init
+ pcrd
->params
.rate
*t
)*pull_conversion_factor_userinput2internal(&pcrd
->params
);
750 low_set_pull_coord_reference_value(pcrd
, coord_ind
, value_ref
);
754 /* Returns the dihedral angle. Updates the plane normal vectors m, n. */
755 static double get_dihedral_angle_coord(pull_coord_work_t
*pcrd
)
758 dvec dr32
; /* store instead of dr23? */
760 dsvmul(-1, pcrd
->dr23
, dr32
);
761 dcprod(pcrd
->dr01
, dr32
, pcrd
->planevec_m
); /* Normal of first plane */
762 dcprod(dr32
, pcrd
->dr45
, pcrd
->planevec_n
); /* Normal of second plane */
763 phi
= gmx_angle_between_dvecs(pcrd
->planevec_m
, pcrd
->planevec_n
);
765 /* Note 1: the sign below is opposite of that in the bondeds or Bekker 1994
766 * because there r_ij = ri - rj, while here dr01 = r_1 - r_0
767 * Note 2: the angle between the plane normal vectors equals pi only when
768 * both planes coincide. Thus, when phi = pi dr01 will lie in both planes and
769 * we get a positive sign below. Thus, the range of the dihedral angle is (-180, 180].
771 sign
= (diprod(pcrd
->dr01
, pcrd
->planevec_n
) < 0.0) ? 1.0 : -1.0;
775 /* Calculates pull->coord[coord_ind].value.
776 * This function also updates pull->coord[coord_ind].dr.
778 static void get_pull_coord_distance(struct pull_t
*pull
,
782 pull_coord_work_t
*pcrd
;
785 pcrd
= &pull
->coord
[coord_ind
];
787 get_pull_coord_dr(pull
, coord_ind
, pbc
);
789 switch (pcrd
->params
.eGeom
)
792 /* Pull along the vector between the com's */
793 pcrd
->value
= dnorm(pcrd
->dr01
);
797 case epullgDIRRELATIVE
:
801 for (m
= 0; m
< DIM
; m
++)
803 pcrd
->value
+= pcrd
->vec
[m
]*pcrd
->dr01
[m
];
807 pcrd
->value
= gmx_angle_between_dvecs(pcrd
->dr01
, pcrd
->dr23
);
810 pcrd
->value
= get_dihedral_angle_coord(pcrd
);
812 case epullgANGLEAXIS
:
813 pcrd
->value
= gmx_angle_between_dvecs(pcrd
->dr01
, pcrd
->vec
);
816 gmx_incons("Unsupported pull type in get_pull_coord_distance");
820 /* Returns the deviation from the reference value.
821 * Updates pull->coord[coord_ind].dr, .value and .value_ref.
823 static double get_pull_coord_deviation(struct pull_t
*pull
,
828 pull_coord_work_t
*pcrd
;
831 pcrd
= &pull
->coord
[coord_ind
];
833 get_pull_coord_distance(pull
, coord_ind
, pbc
);
835 update_pull_coord_reference_value(pcrd
, coord_ind
, t
);
837 /* Determine the deviation */
838 dev
= pcrd
->value
- pcrd
->value_ref
;
840 /* Check that values are allowed */
841 if (pcrd
->params
.eGeom
== epullgDIST
&& pcrd
->value
== 0)
843 /* With no vector we can not determine the direction for the force,
844 * so we set the force to zero.
848 else if (pcrd
->params
.eGeom
== epullgDIHEDRAL
)
850 /* The reference value is in [-pi, pi). The coordinate value is in (-pi, pi].
851 Thus, the unwrapped deviation is here in (-2pi, 2pi].
852 After making it periodic, the deviation will be in [-pi, pi). */
853 make_periodic_2pi(&dev
);
859 void get_pull_coord_value(struct pull_t
*pull
,
864 get_pull_coord_distance(pull
, coord_ind
, pbc
);
866 *value
= pull
->coord
[coord_ind
].value
;
869 static void clear_pull_forces_coord(pull_coord_work_t
*pcrd
)
871 clear_dvec(pcrd
->f01
);
872 clear_dvec(pcrd
->f23
);
873 clear_dvec(pcrd
->f45
);
877 void clear_pull_forces(struct pull_t
*pull
)
881 /* Zeroing the forces is only required for constraint pulling.
882 * It can happen that multiple constraint steps need to be applied
883 * and therefore the constraint forces need to be accumulated.
885 for (i
= 0; i
< pull
->ncoord
; i
++)
887 clear_pull_forces_coord(&pull
->coord
[i
]);
891 /* Apply constraint using SHAKE */
892 static void do_constraint(struct pull_t
*pull
, t_pbc
*pbc
,
894 gmx_bool bMaster
, tensor vir
,
898 dvec
*r_ij
; /* x[i] com of i in prev. step. Obeys constr. -> r_ij[i] */
899 dvec unc_ij
; /* xp[i] com of i this step, before constr. -> unc_ij */
900 dvec
*rnew
; /* current 'new' positions of the groups */
901 double *dr_tot
; /* the total update of the coords */
904 double lambda
, rm
, invdt
= 0;
905 gmx_bool bConverged_all
, bConverged
= FALSE
;
906 int niter
= 0, g
, c
, ii
, j
, m
, max_iter
= 100;
910 snew(r_ij
, pull
->ncoord
);
911 snew(dr_tot
, pull
->ncoord
);
913 snew(rnew
, pull
->ngroup
);
915 /* copy the current unconstrained positions for use in iterations. We
916 iterate until rinew[i] and rjnew[j] obey the constraints. Then
917 rinew - pull.x_unc[i] is the correction dr to group i */
918 for (g
= 0; g
< pull
->ngroup
; g
++)
920 copy_dvec(pull
->group
[g
].xp
, rnew
[g
]);
923 /* Determine the constraint directions from the old positions */
924 for (c
= 0; c
< pull
->ncoord
; c
++)
926 pull_coord_work_t
*pcrd
;
928 pcrd
= &pull
->coord
[c
];
930 if (pcrd
->params
.eType
!= epullCONSTRAINT
)
935 /* Note that get_pull_coord_distance also sets pcrd->dr and pcrd->value.
936 * We don't modify dr and value anymore, so these values are also used
939 get_pull_coord_distance(pull
, c
, pbc
);
943 fprintf(debug
, "Pull coord %d dr %f %f %f\n",
944 c
, pcrd
->dr01
[XX
], pcrd
->dr01
[YY
], pcrd
->dr01
[ZZ
]);
947 if (pcrd
->params
.eGeom
== epullgDIR
||
948 pcrd
->params
.eGeom
== epullgDIRPBC
)
950 /* Select the component along vec */
952 for (m
= 0; m
< DIM
; m
++)
954 a
+= pcrd
->vec
[m
]*pcrd
->dr01
[m
];
956 for (m
= 0; m
< DIM
; m
++)
958 r_ij
[c
][m
] = a
*pcrd
->vec
[m
];
963 copy_dvec(pcrd
->dr01
, r_ij
[c
]);
966 if (dnorm2(r_ij
[c
]) == 0)
968 gmx_fatal(FARGS
, "Distance for pull coordinate %d is zero with constraint pulling, which is not allowed.", c
+ 1);
972 bConverged_all
= FALSE
;
973 while (!bConverged_all
&& niter
< max_iter
)
975 bConverged_all
= TRUE
;
977 /* loop over all constraints */
978 for (c
= 0; c
< pull
->ncoord
; c
++)
980 pull_coord_work_t
*pcrd
;
981 pull_group_work_t
*pgrp0
, *pgrp1
;
984 pcrd
= &pull
->coord
[c
];
986 if (pcrd
->params
.eType
!= epullCONSTRAINT
)
991 update_pull_coord_reference_value(pcrd
, c
, t
);
993 pgrp0
= &pull
->group
[pcrd
->params
.group
[0]];
994 pgrp1
= &pull
->group
[pcrd
->params
.group
[1]];
996 /* Get the current difference vector */
997 low_get_pull_coord_dr(pull
, pcrd
, pbc
,
998 rnew
[pcrd
->params
.group
[1]],
999 rnew
[pcrd
->params
.group
[0]],
1004 fprintf(debug
, "Pull coord %d, iteration %d\n", c
, niter
);
1007 rm
= 1.0/(pgrp0
->invtm
+ pgrp1
->invtm
);
1009 switch (pcrd
->params
.eGeom
)
1012 if (pcrd
->value_ref
<= 0)
1014 gmx_fatal(FARGS
, "The pull constraint reference distance for group %d is <= 0 (%f)", c
, pcrd
->value_ref
);
1018 double q
, c_a
, c_b
, c_c
;
1020 c_a
= diprod(r_ij
[c
], r_ij
[c
]);
1021 c_b
= diprod(unc_ij
, r_ij
[c
])*2;
1022 c_c
= diprod(unc_ij
, unc_ij
) - gmx::square(pcrd
->value_ref
);
1026 q
= -0.5*(c_b
- std::sqrt(c_b
*c_b
- 4*c_a
*c_c
));
1031 q
= -0.5*(c_b
+ std::sqrt(c_b
*c_b
- 4*c_a
*c_c
));
1038 "Pull ax^2+bx+c=0: a=%e b=%e c=%e lambda=%e\n",
1039 c_a
, c_b
, c_c
, lambda
);
1043 /* The position corrections dr due to the constraints */
1044 dsvmul(-lambda
*rm
*pgrp1
->invtm
, r_ij
[c
], dr1
);
1045 dsvmul( lambda
*rm
*pgrp0
->invtm
, r_ij
[c
], dr0
);
1046 dr_tot
[c
] += -lambda
*dnorm(r_ij
[c
]);
1051 /* A 1-dimensional constraint along a vector */
1053 for (m
= 0; m
< DIM
; m
++)
1055 vec
[m
] = pcrd
->vec
[m
];
1056 a
+= unc_ij
[m
]*vec
[m
];
1058 /* Select only the component along the vector */
1059 dsvmul(a
, vec
, unc_ij
);
1060 lambda
= a
- pcrd
->value_ref
;
1063 fprintf(debug
, "Pull inpr %e lambda: %e\n", a
, lambda
);
1066 /* The position corrections dr due to the constraints */
1067 dsvmul(-lambda
*rm
*pgrp1
->invtm
, vec
, dr1
);
1068 dsvmul( lambda
*rm
*pgrp0
->invtm
, vec
, dr0
);
1069 dr_tot
[c
] += -lambda
;
1072 gmx_incons("Invalid enumeration value for eGeom");
1073 /* Keep static analyzer happy */
1083 g0
= pcrd
->params
.group
[0];
1084 g1
= pcrd
->params
.group
[1];
1085 low_get_pull_coord_dr(pull
, pcrd
, pbc
, rnew
[g1
], rnew
[g0
], -1, tmp
);
1086 low_get_pull_coord_dr(pull
, pcrd
, pbc
, dr1
, dr0
, -1, tmp3
);
1088 "Pull cur %8.5f %8.5f %8.5f j:%8.5f %8.5f %8.5f d: %8.5f\n",
1089 rnew
[g0
][0], rnew
[g0
][1], rnew
[g0
][2],
1090 rnew
[g1
][0], rnew
[g1
][1], rnew
[g1
][2], dnorm(tmp
));
1092 "Pull ref %8s %8s %8s %8s %8s %8s d: %8.5f\n",
1093 "", "", "", "", "", "", pcrd
->value_ref
);
1095 "Pull cor %8.5f %8.5f %8.5f j:%8.5f %8.5f %8.5f d: %8.5f\n",
1096 dr0
[0], dr0
[1], dr0
[2],
1097 dr1
[0], dr1
[1], dr1
[2],
1101 /* Update the COMs with dr */
1102 dvec_inc(rnew
[pcrd
->params
.group
[1]], dr1
);
1103 dvec_inc(rnew
[pcrd
->params
.group
[0]], dr0
);
1106 /* Check if all constraints are fullfilled now */
1107 for (c
= 0; c
< pull
->ncoord
; c
++)
1109 pull_coord_work_t
*pcrd
;
1111 pcrd
= &pull
->coord
[c
];
1113 if (pcrd
->params
.eType
!= epullCONSTRAINT
)
1118 low_get_pull_coord_dr(pull
, pcrd
, pbc
,
1119 rnew
[pcrd
->params
.group
[1]],
1120 rnew
[pcrd
->params
.group
[0]],
1123 switch (pcrd
->params
.eGeom
)
1127 fabs(dnorm(unc_ij
) - pcrd
->value_ref
) < pull
->params
.constr_tol
;
1132 for (m
= 0; m
< DIM
; m
++)
1134 vec
[m
] = pcrd
->vec
[m
];
1136 inpr
= diprod(unc_ij
, vec
);
1137 dsvmul(inpr
, vec
, unc_ij
);
1139 fabs(diprod(unc_ij
, vec
) - pcrd
->value_ref
) < pull
->params
.constr_tol
;
1147 fprintf(debug
, "NOT CONVERGED YET: Group %d:"
1148 "d_ref = %f, current d = %f\n",
1149 g
, pcrd
->value_ref
, dnorm(unc_ij
));
1152 bConverged_all
= FALSE
;
1157 /* if after all constraints are dealt with and bConverged is still TRUE
1158 we're finished, if not we do another iteration */
1160 if (niter
> max_iter
)
1162 gmx_fatal(FARGS
, "Too many iterations for constraint run: %d", niter
);
1165 /* DONE ITERATING, NOW UPDATE COORDINATES AND CALC. CONSTRAINT FORCES */
1172 /* update atoms in the groups */
1173 for (g
= 0; g
< pull
->ngroup
; g
++)
1175 const pull_group_work_t
*pgrp
;
1178 pgrp
= &pull
->group
[g
];
1180 /* get the final constraint displacement dr for group g */
1181 dvec_sub(rnew
[g
], pgrp
->xp
, dr
);
1183 if (dnorm2(dr
) == 0)
1185 /* No displacement, no update necessary */
1189 /* update the atom positions */
1191 for (j
= 0; j
< pgrp
->nat_loc
; j
++)
1193 ii
= pgrp
->ind_loc
[j
];
1194 if (pgrp
->weight_loc
)
1196 dsvmul(pgrp
->wscale
*pgrp
->weight_loc
[j
], dr
, tmp
);
1198 for (m
= 0; m
< DIM
; m
++)
1204 for (m
= 0; m
< DIM
; m
++)
1206 v
[ii
][m
] += invdt
*tmp
[m
];
1212 /* calculate the constraint forces, used for output and virial only */
1213 for (c
= 0; c
< pull
->ncoord
; c
++)
1215 pull_coord_work_t
*pcrd
;
1217 pcrd
= &pull
->coord
[c
];
1219 if (pcrd
->params
.eType
!= epullCONSTRAINT
)
1224 pcrd
->f_scal
= dr_tot
[c
]/((pull
->group
[pcrd
->params
.group
[0]].invtm
+ pull
->group
[pcrd
->params
.group
[1]].invtm
)*dt
*dt
);
1226 if (vir
!= NULL
&& pcrd
->params
.eGeom
!= epullgDIRPBC
&& bMaster
)
1230 /* Add the pull contribution to the virial */
1231 /* We have already checked above that r_ij[c] != 0 */
1232 f_invr
= pcrd
->f_scal
/dnorm(r_ij
[c
]);
1234 for (j
= 0; j
< DIM
; j
++)
1236 for (m
= 0; m
< DIM
; m
++)
1238 vir
[j
][m
] -= 0.5*f_invr
*r_ij
[c
][j
]*r_ij
[c
][m
];
1244 /* finished! I hope. Give back some memory */
1250 static void add_virial_coord_dr(tensor vir
, const dvec dr
, const dvec f
)
1252 for (int j
= 0; j
< DIM
; j
++)
1254 for (int m
= 0; m
< DIM
; m
++)
1256 vir
[j
][m
] -= 0.5*f
[j
]*dr
[m
];
1261 /* Adds the pull contribution to the virial */
1262 static void add_virial_coord(tensor vir
, const pull_coord_work_t
*pcrd
)
1264 if (vir
!= NULL
&& pcrd
->params
.eGeom
!= epullgDIRPBC
)
1266 /* Add the pull contribution for each distance vector to the virial. */
1267 add_virial_coord_dr(vir
, pcrd
->dr01
, pcrd
->f01
);
1268 if (pcrd
->params
.ngroup
>= 4)
1270 add_virial_coord_dr(vir
, pcrd
->dr23
, pcrd
->f23
);
1272 if (pcrd
->params
.ngroup
>= 6)
1274 add_virial_coord_dr(vir
, pcrd
->dr45
, pcrd
->f45
);
1279 static void calc_pull_coord_force(pull_coord_work_t
*pcrd
,
1280 double dev
, real lambda
,
1281 real
*V
, tensor vir
, real
*dVdl
)
1286 k
= (1.0 - lambda
)*pcrd
->params
.k
+ lambda
*pcrd
->params
.kB
;
1287 dkdl
= pcrd
->params
.kB
- pcrd
->params
.k
;
1289 switch (pcrd
->params
.eType
)
1292 case epullFLATBOTTOM
:
1293 case epullFLATBOTTOMHIGH
:
1294 /* The only difference between an umbrella and a flat-bottom
1295 * potential is that a flat-bottom is zero above or below
1296 the reference value.
1298 if ((pcrd
->params
.eType
== epullFLATBOTTOM
&& dev
< 0) ||
1299 (pcrd
->params
.eType
== epullFLATBOTTOMHIGH
&& dev
> 0))
1304 pcrd
->f_scal
= -k
*dev
;
1305 *V
+= 0.5* k
*gmx::square(dev
);
1306 *dVdl
+= 0.5*dkdl
*gmx::square(dev
);
1310 *V
+= k
*pcrd
->value
;
1311 *dVdl
+= dkdl
*pcrd
->value
;
1314 gmx_incons("Unsupported pull type in do_pull_pot");
1317 if (pcrd
->params
.eGeom
== epullgDIST
)
1319 double invdr01
= pcrd
->value
> 0 ? 1./pcrd
->value
: 0.;
1320 for (m
= 0; m
< DIM
; m
++)
1322 pcrd
->f01
[m
] = pcrd
->f_scal
*pcrd
->dr01
[m
]*invdr01
;
1325 else if (pcrd
->params
.eGeom
== epullgANGLE
)
1328 double cos_theta
, cos_theta2
;
1330 cos_theta
= cos(pcrd
->value
);
1331 cos_theta2
= gmx::square(cos_theta
);
1333 /* The force at theta = 0, pi is undefined so we should not apply any force.
1334 * cos(theta) = 1 for theta = 0, pi so this is what we check for below.
1335 * Note that dr01 = 0 or dr23 = 0 evaluates to theta = 0 so we do not
1336 * have to check for this before dividing by their norm below.
1340 /* The forces f01 and f23 can be decomposed into one vector parallel to dr01
1341 * and another vector parallel to dr23:
1342 * f01 = -dV/dtheta*(a*dr23/|dr23| - b*dr01*|dr01|)/|dr01|,
1343 * f23 = -dV/dtheta*(a*dr01/|dr01| - b*dr23*|dr23|)/|dr23|,
1345 double a
= -gmx::invsqrt(1 - cos_theta2
); /* comes from d/dx acos(x) */
1346 double b
= a
*cos_theta
;
1347 double invdr01
= 1./dnorm(pcrd
->dr01
);
1348 double invdr23
= 1./dnorm(pcrd
->dr23
);
1349 dvec normalized_dr01
, normalized_dr23
;
1350 dsvmul(invdr01
, pcrd
->dr01
, normalized_dr01
);
1351 dsvmul(invdr23
, pcrd
->dr23
, normalized_dr23
);
1353 for (m
= 0; m
< DIM
; m
++)
1355 /* Here, f_scal is -dV/dtheta */
1356 pcrd
->f01
[m
] = pcrd
->f_scal
*invdr01
*(a
*normalized_dr23
[m
] - b
*normalized_dr01
[m
]);
1357 pcrd
->f23
[m
] = pcrd
->f_scal
*invdr23
*(a
*normalized_dr01
[m
] - b
*normalized_dr23
[m
]);
1362 /* No forces to apply for ill-defined cases*/
1363 clear_pull_forces_coord(pcrd
);
1366 else if (pcrd
->params
.eGeom
== epullgANGLEAXIS
)
1368 double cos_theta
, cos_theta2
;
1370 /* The angle-axis force is exactly the same as the angle force (above) except that in
1371 this case the second vector (dr23) is replaced by the pull vector. */
1372 cos_theta
= cos(pcrd
->value
);
1373 cos_theta2
= gmx::square(cos_theta
);
1379 dvec normalized_dr01
;
1381 invdr01
= 1./dnorm(pcrd
->dr01
);
1382 dsvmul(invdr01
, pcrd
->dr01
, normalized_dr01
);
1383 a
= -gmx::invsqrt(1 - cos_theta2
); /* comes from d/dx acos(x) */
1386 for (m
= 0; m
< DIM
; m
++)
1388 pcrd
->f01
[m
] = pcrd
->f_scal
*invdr01
*(a
*pcrd
->vec
[m
] - b
*normalized_dr01
[m
]);
1393 clear_pull_forces_coord(pcrd
);
1396 else if (pcrd
->params
.eGeom
== epullgDIHEDRAL
)
1398 double m2
, n2
, tol
, sqrdist_32
;
1400 /* Note: there is a small difference here compared to the
1401 dihedral force calculations in the bondeds (ref: Bekker 1994).
1402 There rij = ri - rj, while here dr01 = r1 - r0.
1403 However, all distance vectors occur in form of cross or inner products
1404 so that two signs cancel and we end up with the same expressions.
1405 Also, we treat the more general case of 6 groups (0..5) instead of 4 (i, j, k, l).
1407 m2
= diprod(pcrd
->planevec_m
, pcrd
->planevec_m
);
1408 n2
= diprod(pcrd
->planevec_n
, pcrd
->planevec_n
);
1409 dsvmul(-1, pcrd
->dr23
, dr32
);
1410 sqrdist_32
= diprod(dr32
, dr32
);
1411 tol
= sqrdist_32
*GMX_REAL_EPS
; /* Avoid tiny angles */
1412 if ((m2
> tol
) && (n2
> tol
))
1414 double a_01
, a_23_01
, a_23_45
, a_45
;
1415 double inv_dist_32
, inv_sqrdist_32
, dist_32
;
1417 inv_dist_32
= gmx::invsqrt(sqrdist_32
);
1418 inv_sqrdist_32
= inv_dist_32
*inv_dist_32
;
1419 dist_32
= sqrdist_32
*inv_dist_32
;
1421 /* Forces on groups 0, 1 */
1422 a_01
= pcrd
->f_scal
*dist_32
/m2
; /* f_scal is -dV/dphi */
1423 dsvmul(-a_01
, pcrd
->planevec_m
, pcrd
->f01
); /* added sign to get force on group 1, not 0 */
1425 /* Forces on groups 4, 5 */
1426 a_45
= -pcrd
->f_scal
*dist_32
/n2
;
1427 dsvmul(a_45
, pcrd
->planevec_n
, pcrd
->f45
); /* force on group 5 */
1429 /* Force on groups 2, 3 (defining the axis) */
1430 a_23_01
= -diprod(pcrd
->dr01
, dr32
)*inv_sqrdist_32
;
1431 a_23_45
= -diprod(pcrd
->dr45
, dr32
)*inv_sqrdist_32
;
1432 dsvmul(-a_23_01
, pcrd
->f01
, u
); /* added sign to get force from group 0, not 1 */
1433 dsvmul(a_23_45
, pcrd
->f45
, v
);
1434 dvec_sub(u
, v
, pcrd
->f23
); /* force on group 3 */
1438 /* No force to apply for ill-defined cases */
1439 clear_pull_forces_coord(pcrd
);
1444 for (m
= 0; m
< DIM
; m
++)
1446 pcrd
->f01
[m
] = pcrd
->f_scal
*pcrd
->vec
[m
];
1450 add_virial_coord(vir
, pcrd
);
1453 void set_pull_coord_reference_value(struct pull_t
*pull
,
1454 int coord_ind
, real value_ref
,
1455 const struct t_pbc
*pbc
,
1456 const t_mdatoms
*md
,
1458 gmx_bool bUpdateForce
, rvec
*f
, tensor vir
)
1460 pull_coord_work_t
*pcrd
;
1462 pcrd
= &pull
->coord
[coord_ind
];
1464 if (pcrd
->params
.rate
!= 0)
1466 gmx_incons("Can not update the reference value for pull coordinates with rate!=0");
1469 /* Update the reference value */
1470 low_set_pull_coord_reference_value(pcrd
, coord_ind
, value_ref
);
1474 real V
= 0, dVdl
= 0;
1476 dvec f01_old
, f23_old
, f45_old
;
1480 if (pcrd
->params
.eType
== epullCONSTRAINT
)
1482 gmx_incons("Can not update the pull force for constraint coordinates");
1485 /* The time parameter is not used here, so we pass 0.0 */
1486 dev
= get_pull_coord_deviation(pull
, coord_ind
, pbc
, 0.0);
1488 f_scal_old
= pcrd
->f_scal
;
1489 copy_dvec(pcrd
->f01
, f01_old
);
1491 /* Note: f23, f45 will only actually be used for certain geometries */
1492 copy_dvec(pcrd
->f23
, f23_old
);
1493 copy_dvec(pcrd
->f45
, f45_old
);
1495 /* Calculate the new forces, ingnore V, vir and dVdl */
1496 calc_pull_coord_force(pcrd
, dev
, lambda
, &V
, NULL
, &dVdl
);
1498 /* Here we determine the force correction:
1499 * substract the half step contribution we added already,
1500 * add the half step contribution for the new force.
1501 * Note that the printing of f_scal is done in pull_potential, which
1502 * might be called before this function is called, so the output might
1503 * contain values without the correction below.
1505 pcrd
->f_scal
= 0.5*(-f_scal_old
+ pcrd
->f_scal
);
1506 for (m
= 0; m
< DIM
; m
++)
1508 pcrd
->f01
[m
] = 0.5*(-f01_old
[m
] + pcrd
->f01
[m
]);
1509 pcrd
->f23
[m
] = 0.5*(-f23_old
[m
] + pcrd
->f23
[m
]);
1510 pcrd
->f45
[m
] = 0.5*(-f45_old
[m
] + pcrd
->f45
[m
]);
1513 add_virial_coord(vir
, pcrd
);
1515 apply_forces_coord(pull
, coord_ind
, md
, f
);
1519 /* Calculate the pull potential and scalar force for a pull coordinate */
1520 static void do_pull_pot_coord(struct pull_t
*pull
, int coord_ind
, t_pbc
*pbc
,
1521 double t
, real lambda
,
1522 real
*V
, tensor vir
, real
*dVdl
)
1524 pull_coord_work_t
*pcrd
;
1527 pcrd
= &pull
->coord
[coord_ind
];
1529 assert(pcrd
->params
.eType
!= epullCONSTRAINT
);
1531 dev
= get_pull_coord_deviation(pull
, coord_ind
, pbc
, t
);
1533 calc_pull_coord_force(pcrd
, dev
, lambda
, V
, vir
, dVdl
);
1536 real
pull_potential(struct pull_t
*pull
, t_mdatoms
*md
, t_pbc
*pbc
,
1537 t_commrec
*cr
, double t
, real lambda
,
1538 rvec
*x
, rvec
*f
, tensor vir
, real
*dvdlambda
)
1542 assert(pull
!= NULL
);
1544 if (pull
->comm
.bParticipate
)
1548 pull_calc_coms(cr
, pull
, md
, pbc
, t
, x
, NULL
);
1550 for (int c
= 0; c
< pull
->ncoord
; c
++)
1552 if (pull
->coord
[c
].params
.eType
== epullCONSTRAINT
)
1557 do_pull_pot_coord(pull
, c
, pbc
, t
, lambda
,
1558 &V
, MASTER(cr
) ? vir
: NULL
, &dVdl
);
1560 /* Distribute the force over the atoms in the pulled groups */
1561 apply_forces_coord(pull
, c
, md
, f
);
1570 return (MASTER(cr
) ? V
: 0.0);
1573 void pull_constraint(struct pull_t
*pull
, t_mdatoms
*md
, t_pbc
*pbc
,
1574 t_commrec
*cr
, double dt
, double t
,
1575 rvec
*x
, rvec
*xp
, rvec
*v
, tensor vir
)
1577 assert(pull
!= NULL
);
1579 if (pull
->comm
.bParticipate
)
1581 pull_calc_coms(cr
, pull
, md
, pbc
, t
, x
, xp
);
1583 do_constraint(pull
, pbc
, xp
, v
, MASTER(cr
), vir
, dt
, t
);
1587 static void make_local_pull_group(gmx_ga2la_t
*ga2la
,
1588 pull_group_work_t
*pg
, int start
, int end
)
1593 for (i
= 0; i
< pg
->params
.nat
; i
++)
1595 ii
= pg
->params
.ind
[i
];
1598 if (!ga2la_get_home(ga2la
, ii
, &ii
))
1603 if (ii
>= start
&& ii
< end
)
1605 /* This is a home atom, add it to the local pull group */
1606 if (pg
->nat_loc
>= pg
->nalloc_loc
)
1608 pg
->nalloc_loc
= over_alloc_dd(pg
->nat_loc
+1);
1609 srenew(pg
->ind_loc
, pg
->nalloc_loc
);
1610 if (pg
->epgrppbc
== epgrppbcCOS
|| pg
->params
.weight
!= NULL
)
1612 srenew(pg
->weight_loc
, pg
->nalloc_loc
);
1615 pg
->ind_loc
[pg
->nat_loc
] = ii
;
1616 if (pg
->params
.weight
!= NULL
)
1618 pg
->weight_loc
[pg
->nat_loc
] = pg
->params
.weight
[i
];
1625 void dd_make_local_pull_groups(t_commrec
*cr
, struct pull_t
*pull
, t_mdatoms
*md
)
1630 gmx_bool bMustParticipate
;
1646 /* We always make the master node participate, such that it can do i/o
1647 * and to simplify MC type extensions people might have.
1649 bMustParticipate
= (comm
->bParticipateAll
|| dd
== NULL
|| DDMASTER(dd
));
1651 for (g
= 0; g
< pull
->ngroup
; g
++)
1655 make_local_pull_group(ga2la
, &pull
->group
[g
],
1658 /* We should participate if we have pull or pbc atoms */
1659 if (!bMustParticipate
&&
1660 (pull
->group
[g
].nat_loc
> 0 ||
1661 (pull
->group
[g
].params
.pbcatom
>= 0 &&
1662 ga2la_get_home(dd
->ga2la
, pull
->group
[g
].params
.pbcatom
, &a
))))
1664 bMustParticipate
= TRUE
;
1668 if (!comm
->bParticipateAll
)
1670 /* Keep currently not required ranks in the communicator
1671 * if they needed to participate up to 20 decompositions ago.
1672 * This avoids frequent rebuilds due to atoms jumping back and forth.
1674 const gmx_int64_t history_count
= 20;
1675 gmx_bool bWillParticipate
;
1678 /* Increase the decomposition counter for the current call */
1679 comm
->setup_count
++;
1681 if (bMustParticipate
)
1683 comm
->must_count
= comm
->setup_count
;
1688 (comm
->bParticipate
&&
1689 comm
->must_count
>= comm
->setup_count
- history_count
);
1691 if (debug
&& dd
!= NULL
)
1693 fprintf(debug
, "Our DD rank (%3d) pull #atoms>0 or master: %d, will be part %d\n",
1694 dd
->rank
, bMustParticipate
, bWillParticipate
);
1697 if (bWillParticipate
)
1699 /* Count the number of ranks that we want to have participating */
1701 /* Count the number of ranks that need to be added */
1702 count
[1] = comm
->bParticipate
? 0 : 1;
1710 /* The cost of this global operation will be less that the cost
1711 * of the extra MPI_Comm_split calls that we can avoid.
1713 gmx_sumi(2, count
, cr
);
1715 /* If we are missing ranks or if we have 20% more ranks than needed
1716 * we make a new sub-communicator.
1718 if (count
[1] > 0 || 6*count
[0] < 5*comm
->nparticipate
)
1722 fprintf(debug
, "Creating new pull subcommunicator of size %d\n",
1727 if (comm
->mpi_comm_com
!= MPI_COMM_NULL
)
1729 MPI_Comm_free(&comm
->mpi_comm_com
);
1732 /* This might be an extremely expensive operation, so we try
1733 * to avoid this splitting as much as possible.
1736 MPI_Comm_split(dd
->mpi_comm_all
, bWillParticipate
? 0 : 1, dd
->rank
,
1737 &comm
->mpi_comm_com
);
1740 comm
->bParticipate
= bWillParticipate
;
1741 comm
->nparticipate
= count
[0];
1745 /* Since the PBC of atoms might have changed, we need to update the PBC */
1746 pull
->bSetPBCatoms
= TRUE
;
1749 static void init_pull_group_index(FILE *fplog
, t_commrec
*cr
,
1750 int g
, pull_group_work_t
*pg
,
1751 gmx_bool bConstraint
, ivec pulldim_con
,
1752 const gmx_mtop_t
*mtop
,
1753 const t_inputrec
*ir
, real lambda
)
1755 int i
, ii
, d
, nfrozen
, ndim
;
1757 double tmass
, wmass
, wwmass
;
1758 const gmx_groups_t
*groups
;
1759 gmx_mtop_atomlookup_t alook
;
1762 if (EI_ENERGY_MINIMIZATION(ir
->eI
) || ir
->eI
== eiBD
)
1764 /* There are no masses in the integrator.
1765 * But we still want to have the correct mass-weighted COMs.
1766 * So we store the real masses in the weights.
1767 * We do not set nweight, so these weights do not end up in the tpx file.
1769 if (pg
->params
.nweight
== 0)
1771 snew(pg
->params
.weight
, pg
->params
.nat
);
1780 pg
->weight_loc
= NULL
;
1784 pg
->nat_loc
= pg
->params
.nat
;
1785 pg
->ind_loc
= pg
->params
.ind
;
1786 if (pg
->epgrppbc
== epgrppbcCOS
)
1788 snew(pg
->weight_loc
, pg
->params
.nat
);
1792 pg
->weight_loc
= pg
->params
.weight
;
1796 groups
= &mtop
->groups
;
1798 alook
= gmx_mtop_atomlookup_init(mtop
);
1804 for (i
= 0; i
< pg
->params
.nat
; i
++)
1806 ii
= pg
->params
.ind
[i
];
1807 gmx_mtop_atomnr_to_atom(alook
, ii
, &atom
);
1808 if (bConstraint
&& ir
->opts
.nFreeze
)
1810 for (d
= 0; d
< DIM
; d
++)
1812 if (pulldim_con
[d
] == 1 &&
1813 ir
->opts
.nFreeze
[ggrpnr(groups
, egcFREEZE
, ii
)][d
])
1819 if (ir
->efep
== efepNO
)
1825 m
= (1 - lambda
)*atom
->m
+ lambda
*atom
->mB
;
1827 if (pg
->params
.nweight
> 0)
1829 w
= pg
->params
.weight
[i
];
1835 if (EI_ENERGY_MINIMIZATION(ir
->eI
))
1837 /* Move the mass to the weight */
1840 pg
->params
.weight
[i
] = w
;
1842 else if (ir
->eI
== eiBD
)
1846 mbd
= ir
->bd_fric
*ir
->delta_t
;
1850 if (groups
->grpnr
[egcTC
] == NULL
)
1852 mbd
= ir
->delta_t
/ir
->opts
.tau_t
[0];
1856 mbd
= ir
->delta_t
/ir
->opts
.tau_t
[groups
->grpnr
[egcTC
][ii
]];
1861 pg
->params
.weight
[i
] = w
;
1868 gmx_mtop_atomlookup_destroy(alook
);
1872 /* We can have single atom groups with zero mass with potential pulling
1873 * without cosine weighting.
1875 if (pg
->params
.nat
== 1 && !bConstraint
&& pg
->epgrppbc
!= epgrppbcCOS
)
1877 /* With one atom the mass doesn't matter */
1882 gmx_fatal(FARGS
, "The total%s mass of pull group %d is zero",
1883 pg
->params
.weight
? " weighted" : "", g
);
1889 "Pull group %d: %5d atoms, mass %9.3f",
1890 g
, pg
->params
.nat
, tmass
);
1891 if (pg
->params
.weight
||
1892 EI_ENERGY_MINIMIZATION(ir
->eI
) || ir
->eI
== eiBD
)
1894 fprintf(fplog
, ", weighted mass %9.3f", wmass
*wmass
/wwmass
);
1896 if (pg
->epgrppbc
== epgrppbcCOS
)
1898 fprintf(fplog
, ", cosine weighting will be used");
1900 fprintf(fplog
, "\n");
1905 /* A value != 0 signals not frozen, it is updated later */
1911 for (d
= 0; d
< DIM
; d
++)
1913 ndim
+= pulldim_con
[d
]*pg
->params
.nat
;
1915 if (fplog
&& nfrozen
> 0 && nfrozen
< ndim
)
1918 "\nWARNING: In pull group %d some, but not all of the degrees of freedom\n"
1919 " that are subject to pulling are frozen.\n"
1920 " For constraint pulling the whole group will be frozen.\n\n",
1929 init_pull(FILE *fplog
, const pull_params_t
*pull_params
, const t_inputrec
*ir
,
1930 int nfile
, const t_filenm fnm
[],
1931 gmx_mtop_t
*mtop
, t_commrec
*cr
,
1932 const gmx_output_env_t
*oenv
, real lambda
,
1933 gmx_bool bOutFile
, unsigned long Flags
)
1935 struct pull_t
*pull
;
1941 /* Copy the pull parameters */
1942 pull
->params
= *pull_params
;
1943 /* Avoid pointer copies */
1944 pull
->params
.group
= NULL
;
1945 pull
->params
.coord
= NULL
;
1947 pull
->ncoord
= pull_params
->ncoord
;
1948 pull
->ngroup
= pull_params
->ngroup
;
1949 snew(pull
->coord
, pull
->ncoord
);
1950 snew(pull
->group
, pull
->ngroup
);
1952 pull
->bPotential
= FALSE
;
1953 pull
->bConstraint
= FALSE
;
1954 pull
->bCylinder
= FALSE
;
1955 pull
->bAngle
= FALSE
;
1957 for (g
= 0; g
< pull
->ngroup
; g
++)
1959 pull_group_work_t
*pgrp
;
1962 pgrp
= &pull
->group
[g
];
1964 /* Copy the pull group parameters */
1965 pgrp
->params
= pull_params
->group
[g
];
1967 /* Avoid pointer copies by allocating and copying arrays */
1968 snew(pgrp
->params
.ind
, pgrp
->params
.nat
);
1969 for (i
= 0; i
< pgrp
->params
.nat
; i
++)
1971 pgrp
->params
.ind
[i
] = pull_params
->group
[g
].ind
[i
];
1973 if (pgrp
->params
.nweight
> 0)
1975 snew(pgrp
->params
.weight
, pgrp
->params
.nweight
);
1976 for (i
= 0; i
< pgrp
->params
.nweight
; i
++)
1978 pgrp
->params
.weight
[i
] = pull_params
->group
[g
].weight
[i
];
1983 for (c
= 0; c
< pull
->ncoord
; c
++)
1985 pull_coord_work_t
*pcrd
;
1986 int calc_com_start
, calc_com_end
, g
;
1988 pcrd
= &pull
->coord
[c
];
1990 /* Copy all pull coordinate parameters */
1991 pcrd
->params
= pull_params
->coord
[c
];
1993 switch (pcrd
->params
.eGeom
)
1996 case epullgDIRRELATIVE
: /* Direction vector is determined at each step */
1998 case epullgDIHEDRAL
:
2003 case epullgANGLEAXIS
:
2004 copy_rvec_to_dvec(pull_params
->coord
[c
].vec
, pcrd
->vec
);
2007 /* We allow reading of newer tpx files with new pull geometries,
2008 * but with the same tpx format, with old code. A new geometry
2009 * only adds a new enum value, which will be out of range for
2010 * old code. The first place we need to generate an error is
2011 * here, since the pull code can't handle this.
2012 * The enum can be used before arriving here only for printing
2013 * the string corresponding to the geometry, which will result
2014 * in printing "UNDEFINED".
2016 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.",
2017 c
+ 1, pcrd
->params
.eGeom
, epullgNR
- 1);
2020 if (pcrd
->params
.eType
== epullCONSTRAINT
)
2022 /* Check restrictions of the constraint pull code */
2023 if (pcrd
->params
.eGeom
== epullgCYL
||
2024 pcrd
->params
.eGeom
== epullgDIRRELATIVE
||
2025 pcrd
->params
.eGeom
== epullgANGLE
||
2026 pcrd
->params
.eGeom
== epullgDIHEDRAL
||
2027 pcrd
->params
.eGeom
== epullgANGLEAXIS
)
2029 gmx_fatal(FARGS
, "Pulling of type %s can not be combined with geometry %s. Consider using pull type %s.",
2030 epull_names
[pcrd
->params
.eType
],
2031 epullg_names
[pcrd
->params
.eGeom
],
2032 epull_names
[epullUMBRELLA
]);
2035 pull
->bConstraint
= TRUE
;
2039 pull
->bPotential
= TRUE
;
2042 if (pcrd
->params
.eGeom
== epullgCYL
)
2044 pull
->bCylinder
= TRUE
;
2046 else if (pcrd
->params
.eGeom
== epullgANGLE
|| pcrd
->params
.eGeom
== epullgDIHEDRAL
|| pcrd
->params
.eGeom
== epullgANGLEAXIS
)
2048 pull
->bAngle
= TRUE
;
2051 /* We only need to calculate the plain COM of a group
2052 * when it is not only used as a cylinder group.
2054 calc_com_start
= (pcrd
->params
.eGeom
== epullgCYL
? 1 : 0);
2055 calc_com_end
= pcrd
->params
.ngroup
;
2057 for (g
= calc_com_start
; g
<= calc_com_end
; g
++)
2059 pull
->group
[pcrd
->params
.group
[g
]].bCalcCOM
= TRUE
;
2062 /* With non-zero rate the reference value is set at every step */
2063 if (pcrd
->params
.rate
== 0)
2065 /* Initialize the constant reference value */
2066 low_set_pull_coord_reference_value(pcrd
, c
, pcrd
->params
.init
*pull_conversion_factor_userinput2internal(&pcrd
->params
));
2070 pull
->ePBC
= ir
->ePBC
;
2073 case epbcNONE
: pull
->npbcdim
= 0; break;
2074 case epbcXY
: pull
->npbcdim
= 2; break;
2075 default: pull
->npbcdim
= 3; break;
2080 gmx_bool bAbs
, bCos
;
2083 for (c
= 0; c
< pull
->ncoord
; c
++)
2085 if (pull
->group
[pull
->coord
[c
].params
.group
[0]].params
.nat
== 0 ||
2086 pull
->group
[pull
->coord
[c
].params
.group
[1]].params
.nat
== 0)
2092 fprintf(fplog
, "\n");
2093 if (pull
->bPotential
)
2095 fprintf(fplog
, "Will apply potential COM pulling\n");
2097 if (pull
->bConstraint
)
2099 fprintf(fplog
, "Will apply constraint COM pulling\n");
2101 fprintf(fplog
, "with %d pull coordinate%s and %d group%s\n",
2102 pull
->ncoord
, pull
->ncoord
== 1 ? "" : "s",
2103 pull
->ngroup
, pull
->ngroup
== 1 ? "" : "s");
2106 fprintf(fplog
, "with an absolute reference\n");
2109 for (g
= 0; g
< pull
->ngroup
; g
++)
2111 if (pull
->group
[g
].params
.nat
> 1 &&
2112 pull
->group
[g
].params
.pbcatom
< 0)
2114 /* We are using cosine weighting */
2115 fprintf(fplog
, "Cosine weighting is used for group %d\n", g
);
2121 please_cite(fplog
, "Engin2010");
2125 pull
->bRefAt
= FALSE
;
2127 for (g
= 0; g
< pull
->ngroup
; g
++)
2129 pull_group_work_t
*pgrp
;
2131 pgrp
= &pull
->group
[g
];
2132 pgrp
->epgrppbc
= epgrppbcNONE
;
2133 if (pgrp
->params
.nat
> 0)
2135 /* There is an issue when a group is used in multiple coordinates
2136 * and constraints are applied in different dimensions with atoms
2137 * frozen in some, but not all dimensions.
2138 * Since there is only one mass array per group, we can't have
2139 * frozen/non-frozen atoms for different coords at the same time.
2140 * But since this is a very exotic case, we don't check for this.
2141 * A warning is printed in init_pull_group_index.
2144 gmx_bool bConstraint
;
2145 ivec pulldim
, pulldim_con
;
2147 /* Loop over all pull coordinates to see along which dimensions
2148 * this group is pulled and if it is involved in constraints.
2150 bConstraint
= FALSE
;
2151 clear_ivec(pulldim
);
2152 clear_ivec(pulldim_con
);
2153 for (c
= 0; c
< pull
->ncoord
; c
++)
2155 pull_coord_work_t
*pcrd
;
2157 gmx_bool bGroupUsed
;
2159 pcrd
= &pull
->coord
[c
];
2162 for (gi
= 0; gi
< pcrd
->params
.ngroup
; gi
++)
2164 if (pcrd
->params
.group
[gi
] == g
)
2172 for (m
= 0; m
< DIM
; m
++)
2174 if (pcrd
->params
.dim
[m
] == 1)
2178 if (pcrd
->params
.eType
== epullCONSTRAINT
)
2188 /* Determine if we need to take PBC into account for calculating
2189 * the COM's of the pull groups.
2191 GMX_RELEASE_ASSERT(pull
->npbcdim
<= DIM
, "npbcdim must be <= the number of dimensions");
2192 for (m
= 0; m
< pull
->npbcdim
; m
++)
2194 GMX_RELEASE_ASSERT(m
<= DIM
, "npbcdim must be <= the number of dimensions");
2195 if (pulldim
[m
] == 1 && pgrp
->params
.nat
> 1)
2197 if (pgrp
->params
.pbcatom
>= 0)
2199 pgrp
->epgrppbc
= epgrppbcREFAT
;
2200 pull
->bRefAt
= TRUE
;
2204 if (pgrp
->params
.weight
!= NULL
)
2206 gmx_fatal(FARGS
, "Pull groups can not have relative weights and cosine weighting at same time");
2208 pgrp
->epgrppbc
= epgrppbcCOS
;
2209 if (pull
->cosdim
>= 0 && pull
->cosdim
!= m
)
2211 gmx_fatal(FARGS
, "Can only use cosine weighting with pulling in one dimension (use mdp option pull-coord?-dim)");
2217 /* Set the indices */
2218 init_pull_group_index(fplog
, cr
, g
, pgrp
,
2219 bConstraint
, pulldim_con
,
2224 /* Absolute reference, set the inverse mass to zero.
2225 * This is only relevant (and used) with constraint pulling.
2232 /* If we use cylinder coordinates, do some initialising for them */
2233 if (pull
->bCylinder
)
2235 snew(pull
->dyna
, pull
->ncoord
);
2237 for (c
= 0; c
< pull
->ncoord
; c
++)
2239 const pull_coord_work_t
*pcrd
;
2241 pcrd
= &pull
->coord
[c
];
2243 if (pcrd
->params
.eGeom
== epullgCYL
)
2245 if (pull
->group
[pcrd
->params
.group
[0]].params
.nat
== 0)
2247 gmx_fatal(FARGS
, "A cylinder pull group is not supported when using absolute reference!\n");
2256 /* Use a sub-communicator when we have more than 32 ranks */
2257 comm
->bParticipateAll
= (cr
== NULL
|| !DOMAINDECOMP(cr
) ||
2258 cr
->dd
->nnodes
<= 32 ||
2259 getenv("GMX_PULL_PARTICIPATE_ALL") != NULL
);
2260 /* This sub-commicator is not used with comm->bParticipateAll,
2261 * so we can always initialize it to NULL.
2263 comm
->mpi_comm_com
= MPI_COMM_NULL
;
2264 comm
->nparticipate
= 0;
2266 /* No MPI: 1 rank: all ranks pull */
2267 comm
->bParticipateAll
= TRUE
;
2269 comm
->bParticipate
= comm
->bParticipateAll
;
2270 comm
->setup_count
= 0;
2271 comm
->must_count
= 0;
2273 if (!comm
->bParticipateAll
&& fplog
!= NULL
)
2275 fprintf(fplog
, "Will use a sub-communicator for pull communication\n");
2280 comm
->dbuf_cyl
= NULL
;
2282 /* We still need to initialize the PBC reference coordinates */
2283 pull
->bSetPBCatoms
= TRUE
;
2285 /* Only do I/O when we are doing dynamics and if we are the MASTER */
2290 /* Check for px and pf filename collision, if we are writing
2292 std::string px_filename
, pf_filename
;
2293 std::string px_appended
, pf_appended
;
2296 px_filename
= std::string(opt2fn("-px", nfile
, fnm
));
2297 pf_filename
= std::string(opt2fn("-pf", nfile
, fnm
));
2299 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
;
2302 if ((pull
->params
.nstxout
!= 0) &&
2303 (pull
->params
.nstfout
!= 0) &&
2304 (px_filename
== pf_filename
))
2306 if (!opt2bSet("-px", nfile
, fnm
) && !opt2bSet("-pf", nfile
, fnm
))
2308 /* We are writing both pull files but neither set directly. */
2311 px_appended
= append_before_extension(px_filename
, "_pullx");
2312 pf_appended
= append_before_extension(pf_filename
, "_pullf");
2314 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
;
2315 pull
->out_x
= open_pull_out(px_appended
.c_str(), pull
, oenv
,
2317 pull
->out_f
= open_pull_out(pf_appended
.c_str(), pull
, oenv
,
2323 /* If one of -px and -pf is set but the filenames are identical: */
2324 gmx_fatal(FARGS
, "Identical pull_x and pull_f output filenames %s",
2325 px_filename
.c_str());
2328 if (pull
->params
.nstxout
!= 0)
2330 pull
->out_x
= open_pull_out(opt2fn("-px", nfile
, fnm
), pull
, oenv
,
2333 if (pull
->params
.nstfout
!= 0)
2335 pull
->out_f
= open_pull_out(opt2fn("-pf", nfile
, fnm
), pull
, oenv
,
2343 static void destroy_pull_group(pull_group_work_t
*pgrp
)
2345 if (pgrp
->ind_loc
!= pgrp
->params
.ind
)
2347 sfree(pgrp
->ind_loc
);
2349 if (pgrp
->weight_loc
!= pgrp
->params
.weight
)
2351 sfree(pgrp
->weight_loc
);
2356 sfree(pgrp
->params
.ind
);
2357 sfree(pgrp
->params
.weight
);
2360 static void destroy_pull(struct pull_t
*pull
)
2364 for (i
= 0; i
< pull
->ngroup
; i
++)
2366 destroy_pull_group(&pull
->group
[i
]);
2368 for (i
= 0; i
< pull
->ncoord
; i
++)
2370 if (pull
->coord
[i
].params
.eGeom
== epullgCYL
)
2372 destroy_pull_group(&(pull
->dyna
[i
]));
2380 if (pull
->comm
.mpi_comm_com
!= MPI_COMM_NULL
)
2382 MPI_Comm_free(&pull
->comm
.mpi_comm_com
);
2385 sfree(pull
->comm
.rbuf
);
2386 sfree(pull
->comm
.dbuf
);
2387 sfree(pull
->comm
.dbuf_cyl
);
2392 void finish_pull(struct pull_t
*pull
)
2396 gmx_fio_fclose(pull
->out_x
);
2400 gmx_fio_fclose(pull
->out_f
);
2406 gmx_bool
pull_have_potential(const struct pull_t
*pull
)
2408 return pull
->bPotential
;
2411 gmx_bool
pull_have_constraint(const struct pull_t
*pull
)
2413 return pull
->bConstraint
;