3 * This source code is part of
7 * GROningen MAchine for Chemical Simulations
10 * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
11 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
12 * Copyright (c) 2001-2004, The GROMACS development team,
13 * check out http://www.gromacs.org for more information.
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * If you want to redistribute modifications, please consider that
21 * scientific software is very special. Version control is crucial -
22 * bugs must be traceable. We will be happy to consider code for
23 * inclusion in the official distribution, but derived work must not
24 * be called official GROMACS. Details are found in the README & COPYING
25 * files - if they are missing, get the official version at www.gromacs.org.
27 * To help us fund GROMACS development, we humbly ask that you cite
28 * the papers on the package - you can find them in the top README file.
30 * For more info, check our website at http://www.gromacs.org
33 * GROwing Monsters And Cloning Shrimps
49 #include "gmx_fatal.h"
57 #include "gmx_ga2la.h"
59 static void pull_set_pbcatom(t_commrec *cr, t_pullgrp *pg,
60 t_mdatoms *md, rvec *x,
66 if (DOMAINDECOMP(cr)) {
67 if (!ga2la_get_home(cr->dd->ga2la,pg->pbcatom,&a)) {
74 if (a >= md->start && a < md->start+md->homenr) {
75 copy_rvec(x[a],x_pbc);
80 copy_rvec(x[pg->pbcatom],x_pbc);
84 static void pull_set_pbcatoms(t_commrec *cr, t_pull *pull,
85 t_mdatoms *md, rvec *x,
91 for(g=0; g<1+pull->ngrp; g++) {
92 if ((g==0 && PULL_CYL(pull)) || pull->grp[g].pbcatom == -1) {
95 pull_set_pbcatom(cr,&pull->grp[g],md,x,x_pbc[g]);
96 for(m=0; m<DIM; m++) {
97 if (pull->dim[m] == 0) {
105 if (cr && PAR(cr) && n > 0) {
106 /* Sum over the nodes to get x_pbc from the home node of pbcatom */
107 gmx_sum((1+pull->ngrp)*DIM,x_pbc[0],cr);
111 /* switch function, x between r and w */
112 static real get_weight(real x, real r1, real r0)
121 weight = (r0 - x)/(r0 - r1);
126 static void make_cyl_refgrps(t_commrec *cr,t_pull *pull,t_mdatoms *md,
127 t_pbc *pbc,double t,rvec *x,rvec *xp)
129 int g,i,ii,m,start,end;
131 double r0_2,sum_a,sum_ap,dr2,mass,weight,wmass,wwmass,inp;
132 t_pullgrp *pref,*pgrp,*pdyna;
133 gmx_ga2la_t ga2la=NULL;
135 if (pull->dbuf_cyl == NULL) {
136 snew(pull->dbuf_cyl,pull->ngrp*4);
139 if (cr && DOMAINDECOMP(cr))
140 ga2la = cr->dd->ga2la;
143 end = md->homenr + start;
145 r0_2 = dsqr(pull->cyl_r0);
147 /* loop over all groups to make a reference group for each*/
148 pref = &pull->grp[0];
149 for(g=1; g<1+pull->ngrp; g++) {
150 pgrp = &pull->grp[g];
151 pdyna = &pull->dyna[g];
152 copy_rvec(pgrp->vec,dir);
159 for(m=0; m<DIM; m++) {
160 g_x[m] = pgrp->x[m] - pgrp->vec[m]*(pgrp->init[0] + pgrp->rate*t);
163 /* loop over all atoms in the main ref group */
164 for(i=0; i<pref->nat; i++) {
165 ii = pull->grp[0].ind[i];
167 if (!ga2la_get_home(ga2la,pref->ind[i],&ii)) {
171 if (ii >= start && ii < end) {
172 pbc_dx_aiuc(pbc,x[ii],g_x,dx);
175 for(m=0; m<DIM; m++) {
176 dr2 += dsqr(dx[m] - inp*dir[m]);
180 /* add to index, to sum of COM, to weight array */
181 if (pdyna->nat_loc >= pdyna->nalloc_loc) {
182 pdyna->nalloc_loc = over_alloc_large(pdyna->nat_loc+1);
183 srenew(pdyna->ind_loc,pdyna->nalloc_loc);
184 srenew(pdyna->weight_loc,pdyna->nalloc_loc);
186 pdyna->ind_loc[pdyna->nat_loc] = ii;
187 mass = md->massT[ii];
188 weight = get_weight(sqrt(dr2),pull->cyl_r1,pull->cyl_r0);
189 pdyna->weight_loc[pdyna->nat_loc] = weight;
190 sum_a += mass*weight*inp;
192 pbc_dx_aiuc(pbc,xp[ii],g_x,dx);
194 sum_ap += mass*weight*inp;
196 wmass += mass*weight;
197 wwmass += mass*sqr(weight);
202 pull->dbuf_cyl[(g-1)*4+0] = wmass;
203 pull->dbuf_cyl[(g-1)*4+1] = wwmass;
204 pull->dbuf_cyl[(g-1)*4+2] = sum_a;
205 pull->dbuf_cyl[(g-1)*4+3] = sum_ap;
209 /* Sum the contributions over the nodes */
210 gmx_sumd(pull->ngrp*4,pull->dbuf_cyl,cr);
213 for(g=1; g<1+pull->ngrp; g++) {
214 pgrp = &pull->grp[g];
215 pdyna = &pull->dyna[g];
217 wmass = pull->dbuf_cyl[(g-1)*4+0];
218 wwmass = pull->dbuf_cyl[(g-1)*4+1];
219 pdyna->wscale = wmass/wwmass;
220 pdyna->invtm = 1.0/(pdyna->wscale*wmass);
222 for(m=0; m<DIM; m++) {
223 g_x[m] = pgrp->x[m] - pgrp->vec[m]*(pgrp->init[0] + pgrp->rate*t);
224 pdyna->x[m] = g_x[m] + pgrp->vec[m]*pull->dbuf_cyl[(g-1)*4+2]/wmass;
226 pdyna->xp[m] = g_x[m] + pgrp->vec[m]*pull->dbuf_cyl[(g-1)*4+3]/wmass;
231 fprintf(debug,"Pull cylinder group %d:%8.3f%8.3f%8.3f m:%8.3f\n",
232 g,pdyna->x[0],pdyna->x[1],
233 pdyna->x[2],1.0/pdyna->invtm);
238 static double atan2_0_2pi(double y,double x)
249 /* calculates center of mass of selection index from all coordinates x */
250 void pull_calc_coms(t_commrec *cr,
251 t_pull *pull, t_mdatoms *md, t_pbc *pbc,double t,
255 real mass,w,wm,twopi_box=0;
256 double wmass,wwmass,invwmass;
258 double cm,sm,cmp,smp,ccm,csm,ssm,csw,snw;
259 rvec *xx[2],x_pbc={0,0,0},dx;
262 if (pull->rbuf == NULL) {
263 snew(pull->rbuf,1+pull->ngrp);
265 if (pull->dbuf == NULL) {
266 snew(pull->dbuf,3*(1+pull->ngrp));
270 pull_set_pbcatoms(cr,pull,md,x,pull->rbuf);
273 if (pull->cosdim >= 0) {
274 for(m=pull->cosdim+1; m<pull->npbcdim; m++) {
275 if (pbc->box[m][pull->cosdim] != 0) {
276 gmx_fatal(FARGS,"Can not do cosine weighting for trilinic dimensions");
279 twopi_box = 2.0*M_PI/pbc->box[pull->cosdim][pull->cosdim];
282 for (g=0; g<1+pull->ngrp; g++) {
283 pgrp = &pull->grp[g];
295 if (!(g==0 && PULL_CYL(pull))) {
296 if (pgrp->epgrppbc == epgrppbcREFAT) {
297 /* Set the pbc atom */
298 copy_rvec(pull->rbuf[g],x_pbc);
301 for(i=0; i<pgrp->nat_loc; i++) {
302 ii = pgrp->ind_loc[i];
303 mass = md->massT[ii];
304 if (pgrp->epgrppbc != epgrppbcCOS) {
305 if (pgrp->weight_loc) {
306 w = pgrp->weight_loc[i];
311 if (pgrp->epgrppbc == epgrppbcNONE) {
312 /* Plain COM: sum the coordinates */
314 com[m] += wm*x[ii][m];
317 comp[m] += wm*xp[ii][m];
320 /* Sum the difference with the reference atom */
321 pbc_dx(pbc,x[ii],x_pbc,dx);
322 for(m=0; m<DIM; m++) {
326 /* For xp add the difference between xp and x to dx,
327 * such that we use the same periodic image,
328 * also when xp has a large displacement.
330 for(m=0; m<DIM; m++) {
331 comp[m] += wm*(dx[m] + xp[ii][m] - x[ii][m]);
336 /* Determine cos and sin sums */
337 csw = cos(x[ii][pull->cosdim]*twopi_box);
338 snw = sin(x[ii][pull->cosdim]*twopi_box);
346 csw = cos(xp[ii][pull->cosdim]*twopi_box);
347 snw = sin(xp[ii][pull->cosdim]*twopi_box);
355 /* Copy local sums to a buffer for global summing */
356 switch (pgrp->epgrppbc) {
359 copy_dvec(com,pull->dbuf[g*3]);
360 copy_dvec(comp,pull->dbuf[g*3+1]);
361 pull->dbuf[g*3+2][0] = wmass;
362 pull->dbuf[g*3+2][1] = wwmass;
363 pull->dbuf[g*3+2][2] = 0;
366 pull->dbuf[g*3 ][0] = cm;
367 pull->dbuf[g*3 ][1] = sm;
368 pull->dbuf[g*3 ][2] = 0;
369 pull->dbuf[g*3+1][0] = ccm;
370 pull->dbuf[g*3+1][1] = csm;
371 pull->dbuf[g*3+1][2] = ssm;
372 pull->dbuf[g*3+2][0] = cmp;
373 pull->dbuf[g*3+2][1] = smp;
374 pull->dbuf[g*3+2][2] = 0;
380 /* Sum the contributions over the nodes */
381 gmx_sumd((1+pull->ngrp)*3*DIM,pull->dbuf[0],cr);
384 for (g=0; g<1+pull->ngrp; g++) {
385 pgrp = &pull->grp[g];
386 if (pgrp->nat > 0 && !(g==0 && PULL_CYL(pull))) {
387 if (pgrp->epgrppbc != epgrppbcCOS) {
388 /* Determine the inverse mass */
389 wmass = pull->dbuf[g*3+2][0];
390 wwmass = pull->dbuf[g*3+2][1];
392 /* invtm==0 signals a frozen group, so then we should keep it zero */
393 if (pgrp->invtm > 0) {
394 pgrp->wscale = wmass/wwmass;
395 pgrp->invtm = 1.0/(pgrp->wscale*wmass);
397 /* Divide by the total mass */
398 for(m=0; m<DIM; m++) {
399 pgrp->x[m] = pull->dbuf[g*3 ][m]*invwmass;
401 pgrp->xp[m] = pull->dbuf[g*3+1][m]*invwmass;
403 if (pgrp->epgrppbc == epgrppbcREFAT) {
404 pgrp->x[m] += pull->rbuf[g][m];
406 pgrp->xp[m] += pull->rbuf[g][m];
411 /* Determine the optimal location of the cosine weight */
412 csw = pull->dbuf[g*3][0];
413 snw = pull->dbuf[g*3][1];
414 pgrp->x[pull->cosdim] = atan2_0_2pi(snw,csw)/twopi_box;
415 /* Set the weights for the local atoms */
416 wmass = sqrt(csw*csw + snw*snw);
417 wwmass = (pull->dbuf[g*3+1][0]*csw*csw +
418 pull->dbuf[g*3+1][1]*csw*snw +
419 pull->dbuf[g*3+1][2]*snw*snw)/(wmass*wmass);
420 pgrp->wscale = wmass/wwmass;
421 pgrp->invtm = 1.0/(pgrp->wscale*wmass);
422 /* Set the weights for the local atoms */
425 for(i=0; i<pgrp->nat_loc; i++) {
426 ii = pgrp->ind_loc[i];
427 pgrp->weight_loc[i] = csw*cos(twopi_box*x[ii][pull->cosdim]) +
428 snw*sin(twopi_box*x[ii][pull->cosdim]);
431 csw = pull->dbuf[g*3+2][0];
432 snw = pull->dbuf[g*3+2][1];
433 pgrp->xp[pull->cosdim] = atan2_0_2pi(snw,csw)/twopi_box;
437 fprintf(debug,"Pull group %d wmass %f wwmass %f invtm %f\n",
438 g,wmass,wwmass,pgrp->invtm);
443 if (PULL_CYL(pull)) {
444 /* Calculate the COMs for the cyclinder reference groups */
445 make_cyl_refgrps(cr,pull,md,pbc,t,x,xp);