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 * Copyright (c) 2013,2014,2015,2016, 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.
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.
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.
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.
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.
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.
37 /* This file is completely threadsafe - keep it that way! */
42 #include "gromacs/gmxlib/network.h"
43 #include "gromacs/math/functions.h"
44 #include "gromacs/math/invertmatrix.h"
45 #include "gromacs/math/vec.h"
46 #include "gromacs/math/vecdump.h"
47 #include "gromacs/mdlib/gmx_omp_nthreads.h"
48 #include "gromacs/mdtypes/inputrec.h"
49 #include "gromacs/mdtypes/md_enums.h"
50 #include "gromacs/pbcutil/pbc.h"
51 #include "gromacs/topology/topology.h"
52 #include "gromacs/utility/fatalerror.h"
53 #include "gromacs/utility/gmxomp.h"
54 #include "gromacs/utility/smalloc.h"
56 t_vcm
*init_vcm(FILE *fp
, gmx_groups_t
*groups
, t_inputrec
*ir
)
63 vcm
->mode
= (ir
->nstcomm
> 0) ? ir
->comm_mode
: ecmNO
;
64 vcm
->ndim
= ndof_com(ir
);
66 if (vcm
->mode
== ecmANGULAR
&& vcm
->ndim
< 3)
68 gmx_fatal(FARGS
, "Can not have angular comm removal with pbc=%s",
69 epbc_names
[ir
->ePBC
]);
72 if (vcm
->mode
!= ecmNO
)
74 vcm
->nr
= groups
->grps
[egcVCM
].nr
;
75 /* Allocate one extra for a possible rest group */
76 vcm
->size
= vcm
->nr
+ 1;
77 /* We need vcm->nr+1 elements per thread, but to avoid cache
78 * invalidation we add 2 elements to get a 152 byte separation.
80 vcm
->stride
= vcm
->nr
+ 3;
81 if (vcm
->mode
== ecmANGULAR
)
83 snew(vcm
->group_j
, vcm
->size
);
84 snew(vcm
->group_x
, vcm
->size
);
85 snew(vcm
->group_i
, vcm
->size
);
86 snew(vcm
->group_w
, vcm
->size
);
88 snew(vcm
->group_p
, vcm
->size
);
89 snew(vcm
->group_v
, vcm
->size
);
90 snew(vcm
->group_mass
, vcm
->size
);
91 snew(vcm
->group_name
, vcm
->size
);
92 snew(vcm
->group_ndf
, vcm
->size
);
93 for (g
= 0; (g
< vcm
->nr
); g
++)
95 vcm
->group_ndf
[g
] = ir
->opts
.nrdf
[g
];
98 /* Copy pointer to group names and print it. */
101 fprintf(fp
, "Center of mass motion removal mode is %s\n",
103 fprintf(fp
, "We have the following groups for center of"
104 " mass motion removal:\n");
106 for (g
= 0; (g
< vcm
->nr
); g
++)
108 vcm
->group_name
[g
] = *groups
->grpname
[groups
->grps
[egcVCM
].nm_ind
[g
]];
111 fprintf(fp
, "%3d: %s\n", g
, vcm
->group_name
[g
]);
115 snew(vcm
->thread_vcm
, gmx_omp_nthreads_get(emntDefault
) * vcm
->stride
);
121 static void update_tensor(rvec x
, real m0
, tensor I
)
125 /* Compute inertia tensor contribution due to this atom */
129 I
[XX
][XX
] += x
[XX
]*x
[XX
]*m0
;
130 I
[YY
][YY
] += x
[YY
]*x
[YY
]*m0
;
131 I
[ZZ
][ZZ
] += x
[ZZ
]*x
[ZZ
]*m0
;
140 /* Center of mass code for groups */
141 void calc_vcm_grp(int start
, int homenr
, t_mdatoms
*md
,
142 rvec x
[], rvec v
[], t_vcm
*vcm
)
144 int nthreads
= gmx_omp_nthreads_get(emntDefault
);
145 if (vcm
->mode
!= ecmNO
)
147 #pragma omp parallel num_threads(nthreads)
149 int t
= gmx_omp_get_thread_num();
150 for (int g
= 0; g
< vcm
->size
; g
++)
152 /* Reset linear momentum */
153 t_vcm_thread
*vcm_t
= &vcm
->thread_vcm
[t
*vcm
->stride
+ g
];
155 clear_rvec(vcm_t
->p
);
156 if (vcm
->mode
== ecmANGULAR
)
158 /* Reset angular momentum */
159 clear_rvec(vcm_t
->j
);
160 clear_rvec(vcm_t
->x
);
165 #pragma omp for schedule(static)
166 for (int i
= start
; i
< start
+homenr
; i
++)
169 real m0
= md
->massT
[i
];
174 t_vcm_thread
*vcm_t
= &vcm
->thread_vcm
[t
*vcm
->stride
+ g
];
175 /* Calculate linear momentum */
178 for (m
= 0; (m
< DIM
); m
++)
180 vcm_t
->p
[m
] += m0
*v
[i
][m
];
183 if (vcm
->mode
== ecmANGULAR
)
185 /* Calculate angular momentum */
187 cprod(x
[i
], v
[i
], j0
);
189 for (m
= 0; (m
< DIM
); m
++)
191 vcm_t
->j
[m
] += m0
*j0
[m
];
192 vcm_t
->x
[m
] += m0
*x
[i
][m
];
194 /* Update inertia tensor */
195 update_tensor(x
[i
], m0
, vcm_t
->i
);
199 for (int g
= 0; g
< vcm
->size
; g
++)
201 /* Reset linear momentum */
202 vcm
->group_mass
[g
] = 0;
203 clear_rvec(vcm
->group_p
[g
]);
204 if (vcm
->mode
== ecmANGULAR
)
206 /* Reset angular momentum */
207 clear_rvec(vcm
->group_j
[g
]);
208 clear_rvec(vcm
->group_x
[g
]);
209 clear_rvec(vcm
->group_w
[g
]);
210 clear_mat(vcm
->group_i
[g
]);
213 for (int t
= 0; t
< nthreads
; t
++)
215 t_vcm_thread
*vcm_t
= &vcm
->thread_vcm
[t
*vcm
->stride
+ g
];
216 vcm
->group_mass
[g
] += vcm_t
->mass
;
217 rvec_inc(vcm
->group_p
[g
], vcm_t
->p
);
218 if (vcm
->mode
== ecmANGULAR
)
220 rvec_inc(vcm
->group_j
[g
], vcm_t
->j
);
221 rvec_inc(vcm
->group_x
[g
], vcm_t
->x
);
222 m_add(vcm_t
->i
, vcm
->group_i
[g
], vcm
->group_i
[g
]);
230 void do_stopcm_grp(int start
, int homenr
, unsigned short *group_id
,
231 rvec x
[], rvec v
[], t_vcm
*vcm
)
233 if (vcm
->mode
!= ecmNO
)
235 // cppcheck-suppress unreadVariable
236 int gmx_unused nth
= gmx_omp_nthreads_get(emntDefault
);
237 #pragma omp parallel num_threads(nth)
241 /* Subtract linear momentum */
245 #pragma omp for schedule(static)
246 for (i
= start
; i
< start
+homenr
; i
++)
252 v
[i
][XX
] -= vcm
->group_v
[g
][XX
];
256 #pragma omp for schedule(static)
257 for (i
= start
; i
< start
+homenr
; i
++)
263 v
[i
][XX
] -= vcm
->group_v
[g
][XX
];
264 v
[i
][YY
] -= vcm
->group_v
[g
][YY
];
268 #pragma omp for schedule(static)
269 for (i
= start
; i
< start
+homenr
; i
++)
275 rvec_dec(v
[i
], vcm
->group_v
[g
]);
279 if (vcm
->mode
== ecmANGULAR
)
281 /* Subtract angular momentum */
282 #pragma omp for schedule(static)
283 for (i
= start
; i
< start
+homenr
; i
++)
289 /* Compute the correction to the velocity for each atom */
290 rvec_sub(x
[i
], vcm
->group_x
[g
], dx
);
291 cprod(vcm
->group_w
[g
], dx
, dv
);
299 static void get_minv(tensor A
, tensor B
)
305 tmp
[XX
][XX
] = A
[YY
][YY
] + A
[ZZ
][ZZ
];
306 tmp
[YY
][XX
] = -A
[XX
][YY
];
307 tmp
[ZZ
][XX
] = -A
[XX
][ZZ
];
308 tmp
[XX
][YY
] = -A
[XX
][YY
];
309 tmp
[YY
][YY
] = A
[XX
][XX
] + A
[ZZ
][ZZ
];
310 tmp
[ZZ
][YY
] = -A
[YY
][ZZ
];
311 tmp
[XX
][ZZ
] = -A
[XX
][ZZ
];
312 tmp
[YY
][ZZ
] = -A
[YY
][ZZ
];
313 tmp
[ZZ
][ZZ
] = A
[XX
][XX
] + A
[YY
][YY
];
315 /* This is a hack to prevent very large determinants */
316 rfac
= (tmp
[XX
][XX
]+tmp
[YY
][YY
]+tmp
[ZZ
][ZZ
])/3;
319 gmx_fatal(FARGS
, "Can not stop center of mass: maybe 2dimensional system");
322 for (m
= 0; (m
< DIM
); m
++)
324 for (n
= 0; (n
< DIM
); n
++)
329 gmx::invertMatrix(tmp
, B
);
330 for (m
= 0; (m
< DIM
); m
++)
332 for (n
= 0; (n
< DIM
); n
++)
339 void check_cm_grp(FILE *fp
, t_vcm
*vcm
, t_inputrec
*ir
, real Temp_Max
)
342 real ekcm
, ekrot
, tm
, tm_1
, Temp_cm
;
346 /* First analyse the total results */
347 if (vcm
->mode
!= ecmNO
)
349 for (g
= 0; (g
< vcm
->nr
); g
++)
351 tm
= vcm
->group_mass
[g
];
355 svmul(tm_1
, vcm
->group_p
[g
], vcm
->group_v
[g
]);
357 /* Else it's zero anyway! */
359 if (vcm
->mode
== ecmANGULAR
)
361 for (g
= 0; (g
< vcm
->nr
); g
++)
363 tm
= vcm
->group_mass
[g
];
368 /* Compute center of mass for this group */
369 for (m
= 0; (m
< DIM
); m
++)
371 vcm
->group_x
[g
][m
] *= tm_1
;
374 /* Subtract the center of mass contribution to the
377 cprod(vcm
->group_x
[g
], vcm
->group_v
[g
], jcm
);
378 for (m
= 0; (m
< DIM
); m
++)
380 vcm
->group_j
[g
][m
] -= tm
*jcm
[m
];
383 /* Subtract the center of mass contribution from the inertia
384 * tensor (this is not as trivial as it seems, but due to
385 * some cancellation we can still do it, even in parallel).
388 update_tensor(vcm
->group_x
[g
], tm
, Icm
);
389 m_sub(vcm
->group_i
[g
], Icm
, vcm
->group_i
[g
]);
391 /* Compute angular velocity, using matrix operation
396 get_minv(vcm
->group_i
[g
], Icm
);
397 mvmul(Icm
, vcm
->group_j
[g
], vcm
->group_w
[g
]);
399 /* Else it's zero anyway! */
403 for (g
= 0; (g
< vcm
->nr
); g
++)
406 if (vcm
->group_mass
[g
] != 0 && vcm
->group_ndf
[g
] > 0)
408 for (m
= 0; m
< vcm
->ndim
; m
++)
410 ekcm
+= gmx::square(vcm
->group_v
[g
][m
]);
412 ekcm
*= 0.5*vcm
->group_mass
[g
];
413 Temp_cm
= 2*ekcm
/vcm
->group_ndf
[g
];
415 if ((Temp_cm
> Temp_Max
) && fp
)
417 fprintf(fp
, "Large VCM(group %s): %12.5f, %12.5f, %12.5f, Temp-cm: %12.5e\n",
418 vcm
->group_name
[g
], vcm
->group_v
[g
][XX
],
419 vcm
->group_v
[g
][YY
], vcm
->group_v
[g
][ZZ
], Temp_cm
);
422 if (vcm
->mode
== ecmANGULAR
)
424 ekrot
= 0.5*iprod(vcm
->group_j
[g
], vcm
->group_w
[g
]);
425 if ((ekrot
> 1) && fp
&& !EI_RANDOM(ir
->eI
))
427 /* if we have an integrator that may not conserve momenta, skip */
428 tm
= vcm
->group_mass
[g
];
429 fprintf(fp
, "Group %s with mass %12.5e, Ekrot %12.5e Det(I) = %12.5e\n",
430 vcm
->group_name
[g
], tm
, ekrot
, det(vcm
->group_i
[g
]));
431 fprintf(fp
, " COM: %12.5f %12.5f %12.5f\n",
432 vcm
->group_x
[g
][XX
], vcm
->group_x
[g
][YY
], vcm
->group_x
[g
][ZZ
]);
433 fprintf(fp
, " P: %12.5f %12.5f %12.5f\n",
434 vcm
->group_p
[g
][XX
], vcm
->group_p
[g
][YY
], vcm
->group_p
[g
][ZZ
]);
435 fprintf(fp
, " V: %12.5f %12.5f %12.5f\n",
436 vcm
->group_v
[g
][XX
], vcm
->group_v
[g
][YY
], vcm
->group_v
[g
][ZZ
]);
437 fprintf(fp
, " J: %12.5f %12.5f %12.5f\n",
438 vcm
->group_j
[g
][XX
], vcm
->group_j
[g
][YY
], vcm
->group_j
[g
][ZZ
]);
439 fprintf(fp
, " w: %12.5f %12.5f %12.5f\n",
440 vcm
->group_w
[g
][XX
], vcm
->group_w
[g
][YY
], vcm
->group_w
[g
][ZZ
]);
441 pr_rvecs(fp
, 0, "Inertia tensor", vcm
->group_i
[g
], DIM
);