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 * check out http://www.gromacs.org for more information.
7 * Copyright (c) 2012,2013, by the GROMACS development team, led by
8 * David van der Spoel, Berk Hess, Erik Lindahl, and including many
9 * others, as listed in the AUTHORS file in the top-level source
10 * directory and at http://www.gromacs.org.
12 * GROMACS is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public License
14 * as published by the Free Software Foundation; either version 2.1
15 * of the License, or (at your option) any later version.
17 * GROMACS is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with GROMACS; if not, see
24 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
25 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 * If you want to redistribute modifications to GROMACS, please
28 * consider that scientific software is very special. Version
29 * control is crucial - bugs must be traceable. We will be happy to
30 * consider code for inclusion in the official distribution, but
31 * derived work must not be called official GROMACS. Details are found
32 * in the README & COPYING files - if they are missing, get the
33 * official version at http://www.gromacs.org.
35 * To help us fund GROMACS development, we humbly ask that you cite
36 * the research papers on the package. Check out http://www.gromacs.org.
38 /* This file is completely threadsafe - keep it that way! */
52 t_vcm *init_vcm(FILE *fp,gmx_groups_t *groups,t_inputrec *ir)
59 vcm->mode = (ir->nstcomm > 0) ? ir->comm_mode : ecmNO;
60 vcm->ndim = ndof_com(ir);
62 if (vcm->mode == ecmANGULAR && vcm->ndim < 3)
63 gmx_fatal(FARGS,"Can not have angular comm removal with pbc=%s",
64 epbc_names[ir->ePBC]);
66 if (vcm->mode != ecmNO) {
67 vcm->nr = groups->grps[egcVCM].nr;
68 /* Allocate one extra for a possible rest group */
69 if (vcm->mode == ecmANGULAR) {
70 snew(vcm->group_j,vcm->nr+1);
71 snew(vcm->group_x,vcm->nr+1);
72 snew(vcm->group_i,vcm->nr+1);
73 snew(vcm->group_w,vcm->nr+1);
75 snew(vcm->group_p,vcm->nr+1);
76 snew(vcm->group_v,vcm->nr+1);
77 snew(vcm->group_mass,vcm->nr+1);
78 snew(vcm->group_name,vcm->nr);
79 snew(vcm->group_ndf,vcm->nr);
80 for(g=0; (g<vcm->nr); g++)
81 vcm->group_ndf[g] = ir->opts.nrdf[g];
83 /* Copy pointer to group names and print it. */
85 fprintf(fp,"Center of mass motion removal mode is %s\n",
87 fprintf(fp,"We have the following groups for center of"
88 " mass motion removal:\n");
90 for(g=0; (g<vcm->nr); g++) {
91 vcm->group_name[g] = *groups->grpname[groups->grps[egcVCM].nm_ind[g]];
93 fprintf(fp,"%3d: %s\n",g,vcm->group_name[g]);
100 static void update_tensor(rvec x,real m0,tensor I)
104 /* Compute inertia tensor contribution due to this atom */
108 I[XX][XX] += x[XX]*x[XX]*m0;
109 I[YY][YY] += x[YY]*x[YY]*m0;
110 I[ZZ][ZZ] += x[ZZ]*x[ZZ]*m0;
119 /* Center of mass code for groups */
120 void calc_vcm_grp(FILE *fp,int start,int homenr,t_mdatoms *md,
121 rvec x[],rvec v[],t_vcm *vcm)
124 real m0,xx,xy,xz,yy,yz,zz;
127 if (vcm->mode != ecmNO) {
128 /* Also clear a possible rest group */
129 for(g=0; (g<vcm->nr+1); g++) {
130 /* Reset linear momentum */
131 vcm->group_mass[g] = 0;
132 clear_rvec(vcm->group_p[g]);
134 if (vcm->mode == ecmANGULAR) {
135 /* Reset anular momentum */
136 clear_rvec(vcm->group_j[g]);
137 clear_rvec(vcm->group_x[g]);
138 clear_rvec(vcm->group_w[g]);
139 clear_mat(vcm->group_i[g]);
144 for(i=start; (i<start+homenr); i++) {
149 /* Calculate linear momentum */
150 vcm->group_mass[g] += m0;
151 for(m=0; (m<DIM);m++)
152 vcm->group_p[g][m] += m0*v[i][m];
154 if (vcm->mode == ecmANGULAR) {
155 /* Calculate angular momentum */
158 for(m=0; (m<DIM); m++) {
159 vcm->group_j[g][m] += m0*j0[m];
160 vcm->group_x[g][m] += m0*x[i][m];
162 /* Update inertia tensor */
163 update_tensor(x[i],m0,vcm->group_i[g]);
169 void do_stopcm_grp(FILE *fp,int start,int homenr,unsigned short *group_id,
170 rvec x[],rvec v[],t_vcm *vcm)
176 if (vcm->mode != ecmNO) {
177 /* Subtract linear momentum */
181 for(i=start; (i<start+homenr); i++) {
184 v[i][XX] -= vcm->group_v[g][XX];
188 for(i=start; (i<start+homenr); i++) {
191 v[i][XX] -= vcm->group_v[g][XX];
192 v[i][YY] -= vcm->group_v[g][YY];
196 for(i=start; (i<start+homenr); i++) {
199 rvec_dec(v[i],vcm->group_v[g]);
203 if (vcm->mode == ecmANGULAR) {
204 /* Subtract angular momentum */
205 for(i=start; (i<start+homenr); i++) {
208 /* Compute the correction to the velocity for each atom */
209 rvec_sub(x[i],vcm->group_x[g],dx);
210 cprod(vcm->group_w[g],dx,dv);
217 static void get_minv(tensor A,tensor B)
223 tmp[XX][XX] = A[YY][YY] + A[ZZ][ZZ];
224 tmp[YY][XX] = -A[XX][YY];
225 tmp[ZZ][XX] = -A[XX][ZZ];
226 tmp[XX][YY] = -A[XX][YY];
227 tmp[YY][YY] = A[XX][XX] + A[ZZ][ZZ];
228 tmp[ZZ][YY] = -A[YY][ZZ];
229 tmp[XX][ZZ] = -A[XX][ZZ];
230 tmp[YY][ZZ] = -A[YY][ZZ];
231 tmp[ZZ][ZZ] = A[XX][XX] + A[YY][YY];
233 /* This is a hack to prevent very large determinants */
234 rfac = (tmp[XX][XX]+tmp[YY][YY]+tmp[ZZ][ZZ])/3;
236 gmx_fatal(FARGS,"Can not stop center of mass: maybe 2dimensional system");
238 for(m=0; (m<DIM); m++)
239 for(n=0; (n<DIM); n++)
242 for(m=0; (m<DIM); m++)
243 for(n=0; (n<DIM); n++)
247 void check_cm_grp(FILE *fp,t_vcm *vcm,t_inputrec *ir,real Temp_Max)
250 real ekcm,ekrot,tm,tm_1,Temp_cm;
254 /* First analyse the total results */
255 if (vcm->mode != ecmNO) {
256 for(g=0; (g<vcm->nr); g++) {
257 tm = vcm->group_mass[g];
260 svmul(tm_1,vcm->group_p[g],vcm->group_v[g]);
262 /* Else it's zero anyway! */
264 if (vcm->mode == ecmANGULAR) {
265 for(g=0; (g<vcm->nr); g++) {
266 tm = vcm->group_mass[g];
270 /* Compute center of mass for this group */
271 for(m=0; (m<DIM); m++)
272 vcm->group_x[g][m] *= tm_1;
274 /* Subtract the center of mass contribution to the
277 cprod(vcm->group_x[g],vcm->group_v[g],jcm);
278 for(m=0; (m<DIM); m++)
279 vcm->group_j[g][m] -= tm*jcm[m];
281 /* Subtract the center of mass contribution from the inertia
282 * tensor (this is not as trivial as it seems, but due to
283 * some cancellation we can still do it, even in parallel).
286 update_tensor(vcm->group_x[g],tm,Icm);
287 m_sub(vcm->group_i[g],Icm,vcm->group_i[g]);
289 /* Compute angular velocity, using matrix operation
294 get_minv(vcm->group_i[g],Icm);
295 mvmul(Icm,vcm->group_j[g],vcm->group_w[g]);
297 /* Else it's zero anyway! */
301 for(g=0; (g<vcm->nr); g++) {
303 if (vcm->group_mass[g] != 0 && vcm->group_ndf[g] > 0) {
304 for(m=0; m<vcm->ndim; m++)
305 ekcm += sqr(vcm->group_v[g][m]);
306 ekcm *= 0.5*vcm->group_mass[g];
307 Temp_cm = 2*ekcm/vcm->group_ndf[g];
309 if ((Temp_cm > Temp_Max) && fp)
310 fprintf(fp,"Large VCM(group %s): %12.5f, %12.5f, %12.5f, Temp-cm: %12.5e\n",
311 vcm->group_name[g],vcm->group_v[g][XX],
312 vcm->group_v[g][YY],vcm->group_v[g][ZZ],Temp_cm);
314 if (vcm->mode == ecmANGULAR) {
315 ekrot = 0.5*iprod(vcm->group_j[g],vcm->group_w[g]);
316 if ((ekrot > 1) && fp && !EI_RANDOM(ir->eI)) {
317 /* if we have an integrator that may not conserve momenta, skip */
318 tm = vcm->group_mass[g];
319 fprintf(fp,"Group %s with mass %12.5e, Ekrot %12.5e Det(I) = %12.5e\n",
320 vcm->group_name[g],tm,ekrot,det(vcm->group_i[g]));
321 fprintf(fp," COM: %12.5f %12.5f %12.5f\n",
322 vcm->group_x[g][XX],vcm->group_x[g][YY],vcm->group_x[g][ZZ]);
323 fprintf(fp," P: %12.5f %12.5f %12.5f\n",
324 vcm->group_p[g][XX],vcm->group_p[g][YY],vcm->group_p[g][ZZ]);
325 fprintf(fp," V: %12.5f %12.5f %12.5f\n",
326 vcm->group_v[g][XX],vcm->group_v[g][YY],vcm->group_v[g][ZZ]);
327 fprintf(fp," J: %12.5f %12.5f %12.5f\n",
328 vcm->group_j[g][XX],vcm->group_j[g][YY],vcm->group_j[g][ZZ]);
329 fprintf(fp," w: %12.5f %12.5f %12.5f\n",
330 vcm->group_w[g][XX],vcm->group_w[g][YY],vcm->group_w[g][ZZ]);
331 pr_rvecs(fp,0,"Inertia tensor",vcm->group_i[g],DIM);