Remove unnecessary config.h includes
[alexxy/gromacs.git] / src / gromacs / mdlib / vcm.c
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5  * Copyright (c) 2001-2004, The GROMACS development team.
6  * Copyright (c) 2013,2014, 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.
10  *
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.
15  *
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.
20  *
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.
25  *
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.
33  *
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.
36  */
37 /* This file is completely threadsafe - keep it that way! */
38 #include "gmxpre.h"
39
40 #include "gromacs/legacyheaders/macros.h"
41 #include "gromacs/legacyheaders/vcm.h"
42 #include "gromacs/math/vec.h"
43 #include "gromacs/utility/smalloc.h"
44 #include "gromacs/legacyheaders/names.h"
45 #include "gromacs/legacyheaders/txtdump.h"
46 #include "gromacs/legacyheaders/network.h"
47 #include "gromacs/pbcutil/pbc.h"
48
49 t_vcm *init_vcm(FILE *fp, gmx_groups_t *groups, t_inputrec *ir)
50 {
51     t_vcm *vcm;
52     int    g;
53
54     snew(vcm, 1);
55
56     vcm->mode = (ir->nstcomm > 0) ? ir->comm_mode : ecmNO;
57     vcm->ndim = ndof_com(ir);
58
59     if (vcm->mode == ecmANGULAR && vcm->ndim < 3)
60     {
61         gmx_fatal(FARGS, "Can not have angular comm removal with pbc=%s",
62                   epbc_names[ir->ePBC]);
63     }
64
65     if (vcm->mode != ecmNO)
66     {
67         vcm->nr = groups->grps[egcVCM].nr;
68         /* Allocate one extra for a possible rest group */
69         if (vcm->mode == ecmANGULAR)
70         {
71             snew(vcm->group_j, vcm->nr+1);
72             snew(vcm->group_x, vcm->nr+1);
73             snew(vcm->group_i, vcm->nr+1);
74             snew(vcm->group_w, vcm->nr+1);
75         }
76         snew(vcm->group_p, vcm->nr+1);
77         snew(vcm->group_v, vcm->nr+1);
78         snew(vcm->group_mass, vcm->nr+1);
79         snew(vcm->group_name, vcm->nr);
80         snew(vcm->group_ndf, vcm->nr);
81         for (g = 0; (g < vcm->nr); g++)
82         {
83             vcm->group_ndf[g] = ir->opts.nrdf[g];
84         }
85
86         /* Copy pointer to group names and print it. */
87         if (fp)
88         {
89             fprintf(fp, "Center of mass motion removal mode is %s\n",
90                     ECOM(vcm->mode));
91             fprintf(fp, "We have the following groups for center of"
92                     " mass motion removal:\n");
93         }
94         for (g = 0; (g < vcm->nr); g++)
95         {
96             vcm->group_name[g] = *groups->grpname[groups->grps[egcVCM].nm_ind[g]];
97             if (fp)
98             {
99                 fprintf(fp, "%3d:  %s\n", g, vcm->group_name[g]);
100             }
101         }
102     }
103
104     return vcm;
105 }
106
107 static void update_tensor(rvec x, real m0, tensor I)
108 {
109     real xy, xz, yz;
110
111     /* Compute inertia tensor contribution due to this atom */
112     xy         = x[XX]*x[YY]*m0;
113     xz         = x[XX]*x[ZZ]*m0;
114     yz         = x[YY]*x[ZZ]*m0;
115     I[XX][XX] += x[XX]*x[XX]*m0;
116     I[YY][YY] += x[YY]*x[YY]*m0;
117     I[ZZ][ZZ] += x[ZZ]*x[ZZ]*m0;
118     I[XX][YY] += xy;
119     I[YY][XX] += xy;
120     I[XX][ZZ] += xz;
121     I[ZZ][XX] += xz;
122     I[YY][ZZ] += yz;
123     I[ZZ][YY] += yz;
124 }
125
126 /* Center of mass code for groups */
127 void calc_vcm_grp(int start, int homenr, t_mdatoms *md,
128                   rvec x[], rvec v[], t_vcm *vcm)
129 {
130     int    i, g, m;
131     real   m0, xx, xy, xz, yy, yz, zz;
132     rvec   j0;
133
134     if (vcm->mode != ecmNO)
135     {
136         /* Also clear a possible rest group */
137         for (g = 0; (g < vcm->nr+1); g++)
138         {
139             /* Reset linear momentum */
140             vcm->group_mass[g] = 0;
141             clear_rvec(vcm->group_p[g]);
142
143             if (vcm->mode == ecmANGULAR)
144             {
145                 /* Reset anular momentum */
146                 clear_rvec(vcm->group_j[g]);
147                 clear_rvec(vcm->group_x[g]);
148                 clear_rvec(vcm->group_w[g]);
149                 clear_mat(vcm->group_i[g]);
150             }
151         }
152
153         g = 0;
154         for (i = start; (i < start+homenr); i++)
155         {
156             m0 = md->massT[i];
157             if (md->cVCM)
158             {
159                 g = md->cVCM[i];
160             }
161
162             /* Calculate linear momentum */
163             vcm->group_mass[g]  += m0;
164             for (m = 0; (m < DIM); m++)
165             {
166                 vcm->group_p[g][m] += m0*v[i][m];
167             }
168
169             if (vcm->mode == ecmANGULAR)
170             {
171                 /* Calculate angular momentum */
172                 cprod(x[i], v[i], j0);
173
174                 for (m = 0; (m < DIM); m++)
175                 {
176                     vcm->group_j[g][m] += m0*j0[m];
177                     vcm->group_x[g][m] += m0*x[i][m];
178                 }
179                 /* Update inertia tensor */
180                 update_tensor(x[i], m0, vcm->group_i[g]);
181             }
182         }
183     }
184 }
185
186 void do_stopcm_grp(int start, int homenr, unsigned short *group_id,
187                    rvec x[], rvec v[], t_vcm *vcm)
188 {
189     int  i, g, m;
190     real tm, tm_1;
191     rvec dv, dx;
192
193     if (vcm->mode != ecmNO)
194     {
195         /* Subtract linear momentum */
196         g = 0;
197         switch (vcm->ndim)
198         {
199             case 1:
200                 for (i = start; (i < start+homenr); i++)
201                 {
202                     if (group_id)
203                     {
204                         g = group_id[i];
205                     }
206                     v[i][XX] -= vcm->group_v[g][XX];
207                 }
208                 break;
209             case 2:
210                 for (i = start; (i < start+homenr); i++)
211                 {
212                     if (group_id)
213                     {
214                         g = group_id[i];
215                     }
216                     v[i][XX] -= vcm->group_v[g][XX];
217                     v[i][YY] -= vcm->group_v[g][YY];
218                 }
219                 break;
220             case 3:
221                 for (i = start; (i < start+homenr); i++)
222                 {
223                     if (group_id)
224                     {
225                         g = group_id[i];
226                     }
227                     rvec_dec(v[i], vcm->group_v[g]);
228                 }
229                 break;
230         }
231         if (vcm->mode == ecmANGULAR)
232         {
233             /* Subtract angular momentum */
234             for (i = start; (i < start+homenr); i++)
235             {
236                 if (group_id)
237                 {
238                     g = group_id[i];
239                 }
240                 /* Compute the correction to the velocity for each atom */
241                 rvec_sub(x[i], vcm->group_x[g], dx);
242                 cprod(vcm->group_w[g], dx, dv);
243                 rvec_dec(v[i], dv);
244             }
245         }
246     }
247 }
248
249 static void get_minv(tensor A, tensor B)
250 {
251     int    m, n;
252     double fac, rfac;
253     tensor tmp;
254
255     tmp[XX][XX] =  A[YY][YY] + A[ZZ][ZZ];
256     tmp[YY][XX] = -A[XX][YY];
257     tmp[ZZ][XX] = -A[XX][ZZ];
258     tmp[XX][YY] = -A[XX][YY];
259     tmp[YY][YY] =  A[XX][XX] + A[ZZ][ZZ];
260     tmp[ZZ][YY] = -A[YY][ZZ];
261     tmp[XX][ZZ] = -A[XX][ZZ];
262     tmp[YY][ZZ] = -A[YY][ZZ];
263     tmp[ZZ][ZZ] =  A[XX][XX] + A[YY][YY];
264
265     /* This is a hack to prevent very large determinants */
266     rfac  = (tmp[XX][XX]+tmp[YY][YY]+tmp[ZZ][ZZ])/3;
267     if (rfac == 0.0)
268     {
269         gmx_fatal(FARGS, "Can not stop center of mass: maybe 2dimensional system");
270     }
271     fac = 1.0/rfac;
272     for (m = 0; (m < DIM); m++)
273     {
274         for (n = 0; (n < DIM); n++)
275         {
276             tmp[m][n] *= fac;
277         }
278     }
279     m_inv(tmp, B);
280     for (m = 0; (m < DIM); m++)
281     {
282         for (n = 0; (n < DIM); n++)
283         {
284             B[m][n] *= fac;
285         }
286     }
287 }
288
289 void check_cm_grp(FILE *fp, t_vcm *vcm, t_inputrec *ir, real Temp_Max)
290 {
291     int    m, g;
292     real   ekcm, ekrot, tm, tm_1, Temp_cm;
293     rvec   jcm;
294     tensor Icm, Tcm;
295
296     /* First analyse the total results */
297     if (vcm->mode != ecmNO)
298     {
299         for (g = 0; (g < vcm->nr); g++)
300         {
301             tm = vcm->group_mass[g];
302             if (tm != 0)
303             {
304                 tm_1 = 1.0/tm;
305                 svmul(tm_1, vcm->group_p[g], vcm->group_v[g]);
306             }
307             /* Else it's zero anyway! */
308         }
309         if (vcm->mode == ecmANGULAR)
310         {
311             for (g = 0; (g < vcm->nr); g++)
312             {
313                 tm = vcm->group_mass[g];
314                 if (tm != 0)
315                 {
316                     tm_1 = 1.0/tm;
317
318                     /* Compute center of mass for this group */
319                     for (m = 0; (m < DIM); m++)
320                     {
321                         vcm->group_x[g][m] *= tm_1;
322                     }
323
324                     /* Subtract the center of mass contribution to the
325                      * angular momentum
326                      */
327                     cprod(vcm->group_x[g], vcm->group_v[g], jcm);
328                     for (m = 0; (m < DIM); m++)
329                     {
330                         vcm->group_j[g][m] -= tm*jcm[m];
331                     }
332
333                     /* Subtract the center of mass contribution from the inertia
334                      * tensor (this is not as trivial as it seems, but due to
335                      * some cancellation we can still do it, even in parallel).
336                      */
337                     clear_mat(Icm);
338                     update_tensor(vcm->group_x[g], tm, Icm);
339                     m_sub(vcm->group_i[g], Icm, vcm->group_i[g]);
340
341                     /* Compute angular velocity, using matrix operation
342                      * Since J = I w
343                      * we have
344                      * w = I^-1 J
345                      */
346                     get_minv(vcm->group_i[g], Icm);
347                     mvmul(Icm, vcm->group_j[g], vcm->group_w[g]);
348                 }
349                 /* Else it's zero anyway! */
350             }
351         }
352     }
353     for (g = 0; (g < vcm->nr); g++)
354     {
355         ekcm    = 0;
356         if (vcm->group_mass[g] != 0 && vcm->group_ndf[g] > 0)
357         {
358             for (m = 0; m < vcm->ndim; m++)
359             {
360                 ekcm += sqr(vcm->group_v[g][m]);
361             }
362             ekcm   *= 0.5*vcm->group_mass[g];
363             Temp_cm = 2*ekcm/vcm->group_ndf[g];
364
365             if ((Temp_cm > Temp_Max) && fp)
366             {
367                 fprintf(fp, "Large VCM(group %s): %12.5f, %12.5f, %12.5f, Temp-cm: %12.5e\n",
368                         vcm->group_name[g], vcm->group_v[g][XX],
369                         vcm->group_v[g][YY], vcm->group_v[g][ZZ], Temp_cm);
370             }
371
372             if (vcm->mode == ecmANGULAR)
373             {
374                 ekrot = 0.5*iprod(vcm->group_j[g], vcm->group_w[g]);
375                 if ((ekrot > 1) && fp && !EI_RANDOM(ir->eI))
376                 {
377                     /* if we have an integrator that may not conserve momenta, skip */
378                     tm    = vcm->group_mass[g];
379                     fprintf(fp, "Group %s with mass %12.5e, Ekrot %12.5e Det(I) = %12.5e\n",
380                             vcm->group_name[g], tm, ekrot, det(vcm->group_i[g]));
381                     fprintf(fp, "  COM: %12.5f  %12.5f  %12.5f\n",
382                             vcm->group_x[g][XX], vcm->group_x[g][YY], vcm->group_x[g][ZZ]);
383                     fprintf(fp, "  P:   %12.5f  %12.5f  %12.5f\n",
384                             vcm->group_p[g][XX], vcm->group_p[g][YY], vcm->group_p[g][ZZ]);
385                     fprintf(fp, "  V:   %12.5f  %12.5f  %12.5f\n",
386                             vcm->group_v[g][XX], vcm->group_v[g][YY], vcm->group_v[g][ZZ]);
387                     fprintf(fp, "  J:   %12.5f  %12.5f  %12.5f\n",
388                             vcm->group_j[g][XX], vcm->group_j[g][YY], vcm->group_j[g][ZZ]);
389                     fprintf(fp, "  w:   %12.5f  %12.5f  %12.5f\n",
390                             vcm->group_w[g][XX], vcm->group_w[g][YY], vcm->group_w[g][ZZ]);
391                     pr_rvecs(fp, 0, "Inertia tensor", vcm->group_i[g], DIM);
392                 }
393             }
394         }
395     }
396 }