4 * This source code is part of
8 * GROningen MAchine for Chemical Simulations
11 * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
12 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
13 * Copyright (c) 2001-2004, The GROMACS development team,
14 * check out http://www.gromacs.org for more information.
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation; either version 2
19 * of the License, or (at your option) any later version.
21 * If you want to redistribute modifications, please consider that
22 * scientific software is very special. Version control is crucial -
23 * bugs must be traceable. We will be happy to consider code for
24 * inclusion in the official distribution, but derived work must not
25 * be called official GROMACS. Details are found in the README & COPYING
26 * files - if they are missing, get the official version at www.gromacs.org.
28 * To help us fund GROMACS development, we humbly ask that you cite
29 * the papers on the package - you can find them in the top README file.
31 * For more info, check our website at http://www.gromacs.org
34 * GROwing Monsters And Cloning Shrimps
58 #include "pull_internal.h"
60 void d_pbc_dx(matrix box
,const dvec x1
, const dvec x2
, dvec dx
)
64 /* Not correct for all trilinic boxes !!!
65 Should be as pbc_dx and moved to pbc.c
68 for(m
=DIM
-1; m
>=0; m
--) {
69 while (dx
[m
] < -0.5*box
[m
][m
])
72 while (dx
[m
] >= 0.5*box
[m
][m
])
78 void put_dvec_in_box(matrix box
, dvec v
)
82 for(m
=DIM
-1; m
>=0; m
--) {
86 while (v
[m
] >= box
[m
][m
])
92 /* calculates center of mass of selection index from all coordinates x */
93 void calc_com(t_pullgrp
*pg
, rvec x
[], t_mdatoms
*md
, matrix box
)
100 for(i
=0; i
<pg
->ngx
; i
++) {
106 com
[m
] += wm
*x
[ii
][m
];
109 com
[m
] *= pg
->wscale
/pg
->tmass
;
110 put_dvec_in_box(box
,com
);
111 copy_dvec(com
,pg
->x_unc
);
114 /* calculates com of all atoms in x[], *index has their index numbers
115 to get the masses from atom[] */
116 void calc_com2(t_pullgrp
*pg
, rvec x
[], t_mdatoms
*md
, matrix box
)
123 for(i
=0; i
<pg
->ngx
; i
++) {
129 com
[m
] += wm
*x
[i
][m
];
132 com
[m
] *= pg
->wscale
/pg
->tmass
;
133 put_dvec_in_box(box
,com
);
134 copy_dvec(com
,pg
->x_unc
);
137 void calc_running_com(t_pull
*pull
) {
142 /* for group i, we have nhist[i] points of history. The maximum nr of points
143 is pull->reflag. The array comhist[i][0..nhist[i]-1] has the positions
144 of the center of mass over the last nhist[i] steps. x_unc[i] has the
145 new ones. Remove the oldest one from the list, add the new one, calculate
146 the average, put that in x_unc instead and return. We just move all coms
147 1 down in the list and add the latest one to the top.
151 /* act on dyna groups */
152 for(i
=0;i
<pull
->ngrp
;i
++) {
154 for(j
=0;j
<(pull
->reflag
-1);j
++) {
155 copy_dvec(pull
->dyna
[i
].comhist
[j
+1],pull
->dyna
[i
].comhist
[j
]);
156 dvec_add(ave
,pull
->dyna
[i
].comhist
[j
],ave
);
158 copy_dvec(pull
->dyna
[i
].x_unc
,pull
->dyna
[i
].comhist
[j
]);
159 dvec_add(ave
,pull
->dyna
[i
].x_unc
,ave
);
160 dsvmul(1.0/pull
->reflag
,ave
,ave
);
162 /* now ave has the running com for group i, copy it to x_unc[i] */
163 copy_dvec(ave
,pull
->dyna
[i
].x_unc
);
167 for(n
=0;n
<pull
->reflag
;n
++)
168 fprintf(stderr
,"Comhist %d, grp %d: %8.3f%8.3f%8.3f\n",n
,i
,
169 pull
->dyna
[i
].comhist
[n
][XX
],
170 pull
->dyna
[i
].comhist
[n
][YY
],
171 pull
->dyna
[i
].comhist
[n
][ZZ
]);
175 /* act on ref group */
178 for(j
=0;j
<(pull
->reflag
-1);j
++) {
179 copy_dvec(pull
->ref
.comhist
[j
+1],pull
->ref
.comhist
[j
]);
180 dvec_add(ave
,pull
->ref
.comhist
[j
],ave
);
183 copy_dvec(pull
->ref
.x_unc
,pull
->ref
.comhist
[j
]);
184 dvec_add(ave
,pull
->ref
.x_unc
,ave
);
185 dsvmul(1.0/pull
->reflag
,ave
,ave
);
186 /* now ave has the running com for group i, copy it to x_unc */
187 copy_dvec(ave
,pull
->ref
.x_unc
);
191 for(i
=0;i
<pull
->reflag
;i
++)
192 fprintf(stderr
,"Comhist %d: %8.3f%8.3f%8.3f\n",i
,
193 pull
->ref
.comhist
[i
][XX
],
194 pull
->ref
.comhist
[i
][YY
],
195 pull
->ref
.comhist
[i
][ZZ
]);
200 void correct_t0_pbc(t_pull
*pull
, rvec x
[], t_mdatoms
*md
, matrix box
) {
204 /* loop over all atoms in index for group i. Check if they moved
205 more than half a box with respect to xp. If so add/subtract a box
206 from x0. Copy x to xp.
208 for(i
=0;i
<pull
->ref
.ngx
;i
++) {
209 ii
= pull
->ref
.idx
[i
];
211 /* correct for jumps across the box */
212 pbc_dx(x
[ii
],pull
->ref
.xp
[i
],dx
);
213 for(m
=0; m
<DIM
; m
++) {
214 pull
->ref
.x0
[i
][m
] += dx
[m
];
215 pull
->ref
.xp
[i
][m
] = x
[ii
][m
];
220 /* switch function, x between r and w */
221 real
get_weight(real x
, real r
, real w
) {
223 /* Removed static stuff. Wasn't being used anyway */
224 /* static bool bFirst = TRUE;
225 static real rw, a0, a1, a2, a3; */
231 a0 = (3*r*w*w-w*w*w)/(rw*rw*rw);
232 a1 = -6*r*w/(rw*rw*rw);
233 a2 = 3*(r+w)/(rw*rw*rw);
244 weight
= (w
- x
)/(w
- r
);
249 static double get_cylinder_distance(rvec x
, dvec com
, matrix box
) {
250 /* Triclinic compatible ??? */
251 double dr
, dx
, dy
, boxx
, boxy
;
256 dx
= fabs(x
[XX
] - com
[XX
]);
257 while(dx
> 0.5*boxx
) dx
-= boxx
;
259 dy
= fabs(x
[YY
] - com
[YY
]);
260 while(dy
> 0.5*boxy
) dy
-= boxy
;
262 dr
= sqrt(dx
*dx
+dy
*dy
);
264 fprintf(stderr
,"x:%8.3f%8.3f%8.3f com:%8.3f%8.3f%8.3f dx,dy,dr:%8.3f%8.3f%8.3f\n",x
[0],x
[1],x
[2],com
[0],com
[1],com
[2],dx
,dy
,dr
);
269 void make_refgrps(t_pull
*pull
,matrix box
,t_mdatoms
*md
)
273 double dr
,mass
,wmass
,wwmass
;
277 /* loop over all groups to make a reference group for each*/
278 for(i
=0;i
<pull
->ngrp
;i
++) {
279 pdyna
= &pull
->dyna
[i
];
285 /* loop over all atoms in the main ref group */
286 for(j
=0;j
<pull
->ref
.ngx
;j
++) {
287 ii
= pull
->ref
.idx
[j
];
289 /* get_distance takes pbc into account */
290 dr
= get_cylinder_distance(pull
->ref
.x0
[j
],pull
->grp
[i
].x_unc
,box
);
293 /* add to index, to sum of COM, to weight array */
294 mass
= md
->massT
[ii
];
296 pdyna
->weight
[k
] = get_weight(dr
,pull
->r
,pull
->rc
);
299 pdyna
->x_unc
[m
] += mass
*pdyna
->weight
[k
]*pull
->ref
.x0
[j
][m
];
300 wmass
+= mass
*pdyna
->weight
[k
];
301 wwmass
+= mass
*sqr(pdyna
->weight
[k
]);
306 pdyna
->wscale
= wmass
/wwmass
;
307 pdyna
->tmass
= pdyna
->wscale
*wmass
;
309 /* normalize the new 'x_unc' */
310 dsvmul(1/wmass
,pdyna
->x_unc
,pdyna
->x_unc
);
312 fprintf(stderr
,"Made group %d:%8.3f%8.3f%8.3f m:%8.3f\n",
313 i
,pdyna
->x_unc
[0],pdyna
->x_unc
[1],
314 pdyna
->x_unc
[2],pdyna
->tmass
);