2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2009-2018, The GROMACS development team.
5 * Copyright (c) 2019, by the GROMACS development team, led by
6 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
7 * and including many others, as listed in the AUTHORS file in the
8 * top-level source directory and at http://www.gromacs.org.
10 * GROMACS is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public License
12 * as published by the Free Software Foundation; either version 2.1
13 * of the License, or (at your option) any later version.
15 * GROMACS is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with GROMACS; if not, see
22 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
23 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 * If you want to redistribute modifications to GROMACS, please
26 * consider that scientific software is very special. Version
27 * control is crucial - bugs must be traceable. We will be happy to
28 * consider code for inclusion in the official distribution, but
29 * derived work must not be called official GROMACS. Details are found
30 * in the README & COPYING files - if they are missing, get the
31 * official version at http://www.gromacs.org.
33 * To help us fund GROMACS development, we humbly ask that you cite
34 * the research papers on the package. Check out http://www.gromacs.org.
38 * Implements functions in centerofmass.h.
40 * \author Teemu Murtola <teemu.murtola@gmail.com>
41 * \ingroup module_selection
45 #include "centerofmass.h"
49 #include "gromacs/math/vec.h"
50 #include "gromacs/pbcutil/pbc.h"
51 #include "gromacs/topology/block.h"
52 #include "gromacs/topology/mtop_lookup.h"
53 #include "gromacs/topology/topology.h"
54 #include "gromacs/utility/gmxassert.h"
56 void gmx_calc_cog(const gmx_mtop_t
* /* top */, rvec x
[], int nrefat
, const int index
[], rvec xout
)
61 for (m
= 0; m
< nrefat
; ++m
)
64 rvec_inc(xout
, x
[ai
]);
66 svmul(1.0 / nrefat
, xout
, xout
);
70 * \param[in] top Topology structure with masses.
71 * \param[in] x Position vectors of all atoms.
72 * \param[in] nrefat Number of atoms in the index.
73 * \param[in] index Indices of atoms.
74 * \param[out] xout COM position for the indexed atoms.
76 * Works exactly as gmx_calc_cog() with the exception that a center of
77 * mass are calculated, and hence a topology with masses is required.
79 void gmx_calc_com(const gmx_mtop_t
* top
, rvec x
[], int nrefat
, const int index
[], rvec xout
)
81 GMX_RELEASE_ASSERT(gmx_mtop_has_masses(top
),
82 "No masses available while mass weighting was requested");
86 for (int m
= 0; m
< nrefat
; ++m
)
88 const int ai
= index
[m
];
89 const real mass
= mtopGetAtomMass(top
, ai
, &molb
);
90 for (int j
= 0; j
< DIM
; ++j
)
92 xout
[j
] += mass
* x
[ai
][j
];
96 svmul(1.0 / mtot
, xout
, xout
);
100 * \param[in] top Topology structure with masses.
101 * \param[in] f Forces on all atoms.
102 * \param[in] nrefat Number of atoms in the index.
103 * \param[in] index Indices of atoms.
104 * \param[out] fout Force on the COG position for the indexed atoms.
106 void gmx_calc_cog_f(const gmx_mtop_t
* top
, rvec f
[], int nrefat
, const int index
[], rvec fout
)
108 GMX_RELEASE_ASSERT(gmx_mtop_has_masses(top
),
109 "No masses available while mass weighting was requested");
113 for (int m
= 0; m
< nrefat
; ++m
)
115 const int ai
= index
[m
];
116 const real mass
= mtopGetAtomMass(top
, ai
, &molb
);
117 for (int j
= 0; j
< DIM
; ++j
)
119 fout
[j
] += f
[ai
][j
] / mass
;
123 svmul(mtot
/ nrefat
, fout
, fout
);
126 void gmx_calc_com_f(const gmx_mtop_t
* /* top */, rvec f
[], int nrefat
, const int index
[], rvec fout
)
129 for (int m
= 0; m
< nrefat
; ++m
)
131 const int ai
= index
[m
];
132 rvec_inc(fout
, f
[ai
]);
137 * \param[in] top Topology structure with masses
138 * (can be NULL if \p bMASS==false).
139 * \param[in] x Position vectors of all atoms.
140 * \param[in] nrefat Number of atoms in the index.
141 * \param[in] index Indices of atoms.
142 * \param[in] bMass If true, mass weighting is used.
143 * \param[out] xout COM/COG position for the indexed atoms.
145 * Calls either gmx_calc_com() or gmx_calc_cog() depending on the value of
147 * Other parameters are passed unmodified to these functions.
149 void gmx_calc_comg(const gmx_mtop_t
* top
, rvec x
[], int nrefat
, const int index
[], bool bMass
, rvec xout
)
153 gmx_calc_com(top
, x
, nrefat
, index
, xout
);
157 gmx_calc_cog(top
, x
, nrefat
, index
, xout
);
162 * \param[in] top Topology structure with masses
163 * (can be NULL if \p bMASS==true).
164 * \param[in] f Forces on all atoms.
165 * \param[in] nrefat Number of atoms in the index.
166 * \param[in] index Indices of atoms.
167 * \param[in] bMass If true, force on COM is calculated.
168 * \param[out] fout Force on the COM/COG position for the indexed atoms.
170 * Calls either gmx_calc_cog_f() or gmx_calc_com_f() depending on the value of
172 * Other parameters are passed unmodified to these functions.
174 void gmx_calc_comg_f(const gmx_mtop_t
* top
, rvec f
[], int nrefat
, const int index
[], bool bMass
, rvec fout
)
178 gmx_calc_com_f(top
, f
, nrefat
, index
, fout
);
182 gmx_calc_cog_f(top
, f
, nrefat
, index
, fout
);
188 * \param[in] top Topology structure (unused, can be NULL).
189 * \param[in] x Position vectors of all atoms.
190 * \param[in] pbc Periodic boundary conditions structure.
191 * \param[in] nrefat Number of atoms in the index.
192 * \param[in] index Indices of atoms.
193 * \param[out] xout COG position for the indexed atoms.
195 * Works exactly as gmx_calc_com_pbc(), but calculates the center of geometry.
197 void gmx_calc_cog_pbc(const gmx_mtop_t
* top
, rvec x
[], const t_pbc
* pbc
, int nrefat
, const int index
[], rvec xout
)
199 const real tol
= 1e-4;
204 /* First simple calculation */
205 gmx_calc_cog(top
, x
, nrefat
, index
, xout
);
206 /* Now check if any atom is more than half the box from the COM */
213 for (m
= 0; m
< nrefat
; ++m
)
216 pbc_dx(pbc
, x
[ai
], xout
, dx
);
217 rvec_add(xout
, dx
, xtest
);
218 for (j
= 0; j
< DIM
; ++j
)
220 if (std::fabs(xtest
[j
] - x
[ai
][j
]) > tol
)
222 /* Here we have used the wrong image for contributing to the COM */
223 xout
[j
] += (xtest
[j
] - x
[ai
][j
]) / nrefat
;
235 * \param[in] top Topology structure with masses.
236 * \param[in] x Position vectors of all atoms.
237 * \param[in] pbc Periodic boundary conditions structure.
238 * \param[in] nrefat Number of atoms in the index.
239 * \param[in] index Indices of atoms.
240 * \param[out] xout COM position for the indexed atoms.
242 * Works as gmx_calc_com(), but takes into account periodic boundary
243 * conditions: If any atom is more than half the box from the COM,
244 * it is wrapped around and a new COM is calculated. This is repeated
245 * until no atoms violate the condition.
247 * Modified from src/tools/gmx_sorient.c in Gromacs distribution.
249 void gmx_calc_com_pbc(const gmx_mtop_t
* top
, rvec x
[], const t_pbc
* pbc
, int nrefat
, const int index
[], rvec xout
)
251 GMX_RELEASE_ASSERT(gmx_mtop_has_masses(top
),
252 "No masses available while mass weighting was requested");
253 /* First simple calculation */
257 for (int m
= 0; m
< nrefat
; ++m
)
259 const int ai
= index
[m
];
260 const real mass
= mtopGetAtomMass(top
, ai
, &molb
);
261 for (int j
= 0; j
< DIM
; ++j
)
263 xout
[j
] += mass
* x
[ai
][j
];
267 svmul(1.0 / mtot
, xout
, xout
);
268 /* Now check if any atom is more than half the box from the COM */
271 const real tol
= 1e-4;
277 for (int m
= 0; m
< nrefat
; ++m
)
280 const int ai
= index
[m
];
281 const real mass
= mtopGetAtomMass(top
, ai
, &molb
) / mtot
;
282 pbc_dx(pbc
, x
[ai
], xout
, dx
);
283 rvec_add(xout
, dx
, xtest
);
284 for (int j
= 0; j
< DIM
; ++j
)
286 if (std::fabs(xtest
[j
] - x
[ai
][j
]) > tol
)
288 /* Here we have used the wrong image for contributing to the COM */
289 xout
[j
] += mass
* (xtest
[j
] - x
[ai
][j
]);
300 * \param[in] top Topology structure with masses
301 * (can be NULL if \p bMASS==false).
302 * \param[in] x Position vectors of all atoms.
303 * \param[in] pbc Periodic boundary conditions structure.
304 * \param[in] nrefat Number of atoms in the index.
305 * \param[in] index Indices of atoms.
306 * \param[in] bMass If true, mass weighting is used.
307 * \param[out] xout COM/COG position for the indexed atoms.
309 * Calls either gmx_calc_com() or gmx_calc_cog() depending on the value of
311 * Other parameters are passed unmodified to these functions.
313 void gmx_calc_comg_pbc(const gmx_mtop_t
* top
, rvec x
[], const t_pbc
* pbc
, int nrefat
, const int index
[], bool bMass
, rvec xout
)
317 gmx_calc_com_pbc(top
, x
, pbc
, nrefat
, index
, xout
);
321 gmx_calc_cog_pbc(top
, x
, pbc
, nrefat
, index
, xout
);
326 void gmx_calc_cog_block(const gmx_mtop_t
* /* top */, rvec x
[], const t_block
* block
, const int index
[], rvec xout
[])
331 for (b
= 0; b
< block
->nr
; ++b
)
334 for (i
= block
->index
[b
]; i
< block
->index
[b
+ 1]; ++i
)
339 svmul(1.0 / (block
->index
[b
+ 1] - block
->index
[b
]), xb
, xout
[b
]);
344 * \param[in] top Topology structure with masses.
345 * \param[in] x Position vectors of all atoms.
346 * \param[in] block t_block structure that divides \p index into blocks.
347 * \param[in] index Indices of atoms.
348 * \param[out] xout \p block->nr COM positions.
350 * Works exactly as gmx_calc_cog_block() with the exception that centers of
351 * mass are calculated, and hence a topology with masses is required.
353 void gmx_calc_com_block(const gmx_mtop_t
* top
, rvec x
[], const t_block
* block
, const int index
[], rvec xout
[])
355 GMX_RELEASE_ASSERT(gmx_mtop_has_masses(top
),
356 "No masses available while mass weighting was requested");
358 for (int b
= 0; b
< block
->nr
; ++b
)
363 for (int i
= block
->index
[b
]; i
< block
->index
[b
+ 1]; ++i
)
365 const int ai
= index
[i
];
366 const real mass
= mtopGetAtomMass(top
, ai
, &molb
);
367 for (int d
= 0; d
< DIM
; ++d
)
369 xb
[d
] += mass
* x
[ai
][d
];
373 svmul(1.0 / mtot
, xb
, xout
[b
]);
378 * \param[in] top Topology structure with masses.
379 * \param[in] f Forces on all atoms.
380 * \param[in] block t_block structure that divides \p index into blocks.
381 * \param[in] index Indices of atoms.
382 * \param[out] fout \p block->nr Forces on COG positions.
384 void gmx_calc_cog_f_block(const gmx_mtop_t
* top
, rvec f
[], const t_block
* block
, const int index
[], rvec fout
[])
386 GMX_RELEASE_ASSERT(gmx_mtop_has_masses(top
),
387 "No masses available while mass weighting was requested");
389 for (int b
= 0; b
< block
->nr
; ++b
)
394 for (int i
= block
->index
[b
]; i
< block
->index
[b
+ 1]; ++i
)
396 const int ai
= index
[i
];
397 const real mass
= mtopGetAtomMass(top
, ai
, &molb
);
398 for (int d
= 0; d
< DIM
; ++d
)
400 fb
[d
] += f
[ai
][d
] / mass
;
404 svmul(mtot
/ (block
->index
[b
+ 1] - block
->index
[b
]), fb
, fout
[b
]);
408 void gmx_calc_com_f_block(const gmx_mtop_t
* /* top */,
410 const t_block
* block
,
414 for (int b
= 0; b
< block
->nr
; ++b
)
418 for (int i
= block
->index
[b
]; i
< block
->index
[b
+ 1]; ++i
)
420 const int ai
= index
[i
];
423 copy_rvec(fb
, fout
[b
]);
428 * \param[in] top Topology structure with masses
429 * (can be NULL if \p bMASS==false).
430 * \param[in] x Position vectors of all atoms.
431 * \param[in] block t_block structure that divides \p index into blocks.
432 * \param[in] index Indices of atoms.
433 * \param[in] bMass If true, mass weighting is used.
434 * \param[out] xout \p block->nr COM/COG positions.
436 * Calls either gmx_calc_com_block() or gmx_calc_cog_block() depending on the
438 * Other parameters are passed unmodified to these functions.
440 void gmx_calc_comg_block(const gmx_mtop_t
* top
,
442 const t_block
* block
,
449 gmx_calc_com_block(top
, x
, block
, index
, xout
);
453 gmx_calc_cog_block(top
, x
, block
, index
, xout
);
458 * \param[in] top Topology structure with masses
459 * (can be NULL if \p bMASS==false).
460 * \param[in] f Forces on all atoms.
461 * \param[in] block t_block structure that divides \p index into blocks.
462 * \param[in] index Indices of atoms.
463 * \param[in] bMass If true, force on COM is calculated.
464 * \param[out] fout \p block->nr forces on the COM/COG positions.
466 * Calls either gmx_calc_com_f_block() or gmx_calc_cog_f_block() depending on
467 * the value of \p bMass.
468 * Other parameters are passed unmodified to these functions.
470 void gmx_calc_comg_f_block(const gmx_mtop_t
* top
,
472 const t_block
* block
,
479 gmx_calc_com_f_block(top
, f
, block
, index
, fout
);
483 gmx_calc_cog_f_block(top
, f
, block
, index
, fout
);
488 * \param[in] top Topology structure with masses
489 * (can be NULL if \p bMASS==false).
490 * \param[in] x Position vectors of all atoms.
491 * \param[in] block Blocks for calculation.
492 * \param[in] bMass If true, mass weighting is used.
493 * \param[out] xout \p block->nr COM/COG positions.
495 * Calls gmx_calc_comg_block(), converting the \p t_blocka structure into
496 * a \p t_block and an index. Other parameters are passed unmodified.
499 * This function assumes that a pointer to \c t_blocka can be safely typecast
500 * into \c t_block such that the index fields can still be referenced.
501 * With the present Gromacs defitions of these types, this is the case,
502 * but if the layout of these structures is changed, this may lead to strange
505 void gmx_calc_comg_blocka(const gmx_mtop_t
* top
, rvec x
[], const t_blocka
* block
, bool bMass
, rvec xout
[])
507 /* TODO: It would probably be better to do this without the type cast */
508 gmx_calc_comg_block(top
, x
, reinterpret_cast<const t_block
*>(block
), block
->a
, bMass
, xout
);
512 * \param[in] top Topology structure with masses
513 * (can be NULL if \p bMASS==true).
514 * \param[in] f Forces on all atoms.
515 * \param[in] block Blocks for calculation.
516 * \param[in] bMass If true, force on COM is calculated.
517 * \param[out] fout \p block->nr forces on the COM/COG positions.
519 * Calls gmx_calc_comg_f_block(), converting the \p t_blocka structure into
520 * a \p t_block and an index. Other parameters are passed unmodified.
523 * This function assumes that a pointer to \c t_blocka can be safely typecast
524 * into \c t_block such that the index fields can still be referenced.
525 * With the present Gromacs defitions of these types, this is the case,
526 * but if the layout of these structures is changed, this may lead to strange
529 void gmx_calc_comg_f_blocka(const gmx_mtop_t
* top
, rvec f
[], const t_blocka
* block
, bool bMass
, rvec fout
[])
531 /* TODO: It would probably be better to do this without the type cast */
532 gmx_calc_comg_f_block(top
, f
, reinterpret_cast<const t_block
*>(block
), block
->a
, bMass
, fout
);