added os-specific defines from cmake required by memtestG80
[gromacs/qmmm-gamess-us.git] / src / mdlib / vcm.c
blobdacdf70790d7219b80947f07976a241cc3e96d18
1 /*
2 *
3 * This source code is part of
4 *
5 * G R O M A C S
6 *
7 * GROningen MAchine for Chemical Simulations
8 *
9 * VERSION 3.2.0
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
32 * And Hey:
33 * GROwing Monsters And Cloning Shrimps
35 /* This file is completely threadsafe - keep it that way! */
36 #ifdef HAVE_CONFIG_H
37 #include <config.h>
38 #endif
40 #include "macros.h"
41 #include "vcm.h"
42 #include "vec.h"
43 #include "smalloc.h"
44 #include "names.h"
45 #include "txtdump.h"
46 #include "network.h"
47 #include "pbc.h"
49 t_vcm *init_vcm(FILE *fp,gmx_groups_t *groups,t_inputrec *ir)
51 t_vcm *vcm;
52 int g;
54 snew(vcm,1);
56 vcm->mode = (ir->nstcomm > 0) ? ir->comm_mode : ecmNO;
57 vcm->ndim = ndof_com(ir);
59 if (vcm->mode == ecmANGULAR && vcm->ndim < 3)
60 gmx_fatal(FARGS,"Can not have angular comm removal with pbc=%s",
61 epbc_names[ir->ePBC]);
63 if (vcm->mode != ecmNO) {
64 vcm->nr = groups->grps[egcVCM].nr;
65 /* Allocate one extra for a possible rest group */
66 if (vcm->mode == ecmANGULAR) {
67 snew(vcm->group_j,vcm->nr+1);
68 snew(vcm->group_x,vcm->nr+1);
69 snew(vcm->group_i,vcm->nr+1);
70 snew(vcm->group_w,vcm->nr+1);
72 snew(vcm->group_p,vcm->nr+1);
73 snew(vcm->group_v,vcm->nr+1);
74 snew(vcm->group_mass,vcm->nr+1);
75 snew(vcm->group_name,vcm->nr);
76 snew(vcm->group_ndf,vcm->nr);
77 for(g=0; (g<vcm->nr); g++)
78 vcm->group_ndf[g] = ir->opts.nrdf[g];
80 /* Copy pointer to group names and print it. */
81 if (fp) {
82 fprintf(fp,"Center of mass motion removal mode is %s\n",
83 ECOM(vcm->mode));
84 fprintf(fp,"We have the following groups for center of"
85 " mass motion removal:\n");
87 for(g=0; (g<vcm->nr); g++) {
88 vcm->group_name[g] = *groups->grpname[groups->grps[egcVCM].nm_ind[g]];
89 if (fp)
90 fprintf(fp,"%3d: %s\n",g,vcm->group_name[g]);
94 return vcm;
97 static void update_tensor(rvec x,real m0,tensor I)
99 real xy,xz,yz;
101 /* Compute inertia tensor contribution due to this atom */
102 xy = x[XX]*x[YY]*m0;
103 xz = x[XX]*x[ZZ]*m0;
104 yz = x[YY]*x[ZZ]*m0;
105 I[XX][XX] += x[XX]*x[XX]*m0;
106 I[YY][YY] += x[YY]*x[YY]*m0;
107 I[ZZ][ZZ] += x[ZZ]*x[ZZ]*m0;
108 I[XX][YY] += xy;
109 I[YY][XX] += xy;
110 I[XX][ZZ] += xz;
111 I[ZZ][XX] += xz;
112 I[YY][ZZ] += yz;
113 I[ZZ][YY] += yz;
116 /* Center of mass code for groups */
117 void calc_vcm_grp(FILE *fp,int start,int homenr,t_mdatoms *md,
118 rvec x[],rvec v[],t_vcm *vcm)
120 int i,g,m;
121 real m0,xx,xy,xz,yy,yz,zz;
122 rvec j0;
124 if (vcm->mode != ecmNO) {
125 /* Also clear a possible rest group */
126 for(g=0; (g<vcm->nr+1); g++) {
127 /* Reset linear momentum */
128 vcm->group_mass[g] = 0;
129 clear_rvec(vcm->group_p[g]);
131 if (vcm->mode == ecmANGULAR) {
132 /* Reset anular momentum */
133 clear_rvec(vcm->group_j[g]);
134 clear_rvec(vcm->group_x[g]);
135 clear_rvec(vcm->group_w[g]);
136 clear_mat(vcm->group_i[g]);
140 g = 0;
141 for(i=start; (i<start+homenr); i++) {
142 m0 = md->massT[i];
143 if (md->cVCM)
144 g = md->cVCM[i];
146 /* Calculate linear momentum */
147 vcm->group_mass[g] += m0;
148 for(m=0; (m<DIM);m++)
149 vcm->group_p[g][m] += m0*v[i][m];
151 if (vcm->mode == ecmANGULAR) {
152 /* Calculate angular momentum */
153 cprod(x[i],v[i],j0);
155 for(m=0; (m<DIM); m++) {
156 vcm->group_j[g][m] += m0*j0[m];
157 vcm->group_x[g][m] += m0*x[i][m];
159 /* Update inertia tensor */
160 update_tensor(x[i],m0,vcm->group_i[g]);
166 void do_stopcm_grp(FILE *fp,int start,int homenr,unsigned short *group_id,
167 rvec x[],rvec v[],t_vcm *vcm)
169 int i,g,m;
170 real tm,tm_1;
171 rvec dv,dx;
173 if (vcm->mode != ecmNO) {
174 /* Subtract linear momentum */
175 g = 0;
176 switch (vcm->ndim) {
177 case 1:
178 for(i=start; (i<start+homenr); i++) {
179 if (group_id)
180 g = group_id[i];
181 v[i][XX] -= vcm->group_v[g][XX];
183 break;
184 case 2:
185 for(i=start; (i<start+homenr); i++) {
186 if (group_id)
187 g = group_id[i];
188 v[i][XX] -= vcm->group_v[g][XX];
189 v[i][YY] -= vcm->group_v[g][YY];
191 break;
192 case 3:
193 for(i=start; (i<start+homenr); i++) {
194 if (group_id)
195 g = group_id[i];
196 rvec_dec(v[i],vcm->group_v[g]);
198 break;
200 if (vcm->mode == ecmANGULAR) {
201 /* Subtract angular momentum */
202 for(i=start; (i<start+homenr); i++) {
203 if (group_id)
204 g = group_id[i];
205 /* Compute the correction to the velocity for each atom */
206 rvec_sub(x[i],vcm->group_x[g],dx);
207 cprod(vcm->group_w[g],dx,dv);
208 rvec_dec(v[i],dv);
214 static void get_minv(tensor A,tensor B)
216 int m,n;
217 double fac,rfac;
218 tensor tmp;
220 tmp[XX][XX] = A[YY][YY] + A[ZZ][ZZ];
221 tmp[YY][XX] = -A[XX][YY];
222 tmp[ZZ][XX] = -A[XX][ZZ];
223 tmp[XX][YY] = -A[XX][YY];
224 tmp[YY][YY] = A[XX][XX] + A[ZZ][ZZ];
225 tmp[ZZ][YY] = -A[YY][ZZ];
226 tmp[XX][ZZ] = -A[XX][ZZ];
227 tmp[YY][ZZ] = -A[YY][ZZ];
228 tmp[ZZ][ZZ] = A[XX][XX] + A[YY][YY];
230 /* This is a hack to prevent very large determinants */
231 rfac = (tmp[XX][XX]+tmp[YY][YY]+tmp[ZZ][ZZ])/3;
232 if (rfac == 0.0)
233 gmx_fatal(FARGS,"Can not stop center of mass: maybe 2dimensional system");
234 fac = 1.0/rfac;
235 for(m=0; (m<DIM); m++)
236 for(n=0; (n<DIM); n++)
237 tmp[m][n] *= fac;
238 m_inv(tmp,B);
239 for(m=0; (m<DIM); m++)
240 for(n=0; (n<DIM); n++)
241 B[m][n] *= fac;
244 void check_cm_grp(FILE *fp,t_vcm *vcm,t_inputrec *ir,real Temp_Max)
246 int m,g;
247 real ekcm,ekrot,tm,tm_1,Temp_cm;
248 rvec jcm;
249 tensor Icm,Tcm;
251 /* First analyse the total results */
252 if (vcm->mode != ecmNO) {
253 for(g=0; (g<vcm->nr); g++) {
254 tm = vcm->group_mass[g];
255 if (tm != 0) {
256 tm_1 = 1.0/tm;
257 svmul(tm_1,vcm->group_p[g],vcm->group_v[g]);
259 /* Else it's zero anyway! */
261 if (vcm->mode == ecmANGULAR) {
262 for(g=0; (g<vcm->nr); g++) {
263 tm = vcm->group_mass[g];
264 if (tm != 0) {
265 tm_1 = 1.0/tm;
267 /* Compute center of mass for this group */
268 for(m=0; (m<DIM); m++)
269 vcm->group_x[g][m] *= tm_1;
271 /* Subtract the center of mass contribution to the
272 * angular momentum
274 cprod(vcm->group_x[g],vcm->group_v[g],jcm);
275 for(m=0; (m<DIM); m++)
276 vcm->group_j[g][m] -= tm*jcm[m];
278 /* Subtract the center of mass contribution from the inertia
279 * tensor (this is not as trivial as it seems, but due to
280 * some cancellation we can still do it, even in parallel).
282 clear_mat(Icm);
283 update_tensor(vcm->group_x[g],tm,Icm);
284 m_sub(vcm->group_i[g],Icm,vcm->group_i[g]);
286 /* Compute angular velocity, using matrix operation
287 * Since J = I w
288 * we have
289 * w = I^-1 J
291 get_minv(vcm->group_i[g],Icm);
292 mvmul(Icm,vcm->group_j[g],vcm->group_w[g]);
294 /* Else it's zero anyway! */
298 for(g=0; (g<vcm->nr); g++) {
299 ekcm = 0;
300 if (vcm->group_mass[g] != 0 && vcm->group_ndf[g] > 0) {
301 for(m=0; m<vcm->ndim; m++)
302 ekcm += sqr(vcm->group_v[g][m]);
303 ekcm *= 0.5*vcm->group_mass[g];
304 Temp_cm = 2*ekcm/vcm->group_ndf[g];
306 if ((Temp_cm > Temp_Max) && fp)
307 fprintf(fp,"Large VCM(group %s): %12.5f, %12.5f, %12.5f, Temp-cm: %12.5e\n",
308 vcm->group_name[g],vcm->group_v[g][XX],
309 vcm->group_v[g][YY],vcm->group_v[g][ZZ],Temp_cm);
311 if (vcm->mode == ecmANGULAR) {
312 ekrot = 0.5*iprod(vcm->group_j[g],vcm->group_w[g]);
313 if ((ekrot > 1) && fp && !EI_RANDOM(ir->eI)) {
314 /* if we have an integrator that may not conserve momenta, skip */
315 tm = vcm->group_mass[g];
316 fprintf(fp,"Group %s with mass %12.5e, Ekrot %12.5e Det(I) = %12.5e\n",
317 vcm->group_name[g],tm,ekrot,det(vcm->group_i[g]));
318 fprintf(fp," COM: %12.5f %12.5f %12.5f\n",
319 vcm->group_x[g][XX],vcm->group_x[g][YY],vcm->group_x[g][ZZ]);
320 fprintf(fp," P: %12.5f %12.5f %12.5f\n",
321 vcm->group_p[g][XX],vcm->group_p[g][YY],vcm->group_p[g][ZZ]);
322 fprintf(fp," V: %12.5f %12.5f %12.5f\n",
323 vcm->group_v[g][XX],vcm->group_v[g][YY],vcm->group_v[g][ZZ]);
324 fprintf(fp," J: %12.5f %12.5f %12.5f\n",
325 vcm->group_j[g][XX],vcm->group_j[g][YY],vcm->group_j[g][ZZ]);
326 fprintf(fp," w: %12.5f %12.5f %12.5f\n",
327 vcm->group_w[g][XX],vcm->group_w[g][YY],vcm->group_w[g][ZZ]);
328 pr_rvecs(fp,0,"Inertia tensor",vcm->group_i[g],DIM);