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