Simplify CMAP loop
[gromacs.git] / src / gromacs / listed-forces / bonded.cpp
blobc9d7b45e02b9c97edd2c2b0183f0d07f7da4903f
1 /*
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,2017, 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 /*! \internal \file
39 * \brief This file defines low-level functions necessary for
40 * computing energies and forces for listed interactions.
42 * \author Mark Abraham <mark.j.abraham@gmail.com>
44 * \ingroup module_listed-forces
46 #include "gmxpre.h"
48 #include "bonded.h"
50 #include "config.h"
52 #include <cassert>
53 #include <cmath>
55 #include <algorithm>
57 #include "gromacs/listed-forces/pairs.h"
58 #include "gromacs/math/functions.h"
59 #include "gromacs/math/units.h"
60 #include "gromacs/math/utilities.h"
61 #include "gromacs/math/vec.h"
62 #include "gromacs/pbcutil/ishift.h"
63 #include "gromacs/pbcutil/mshift.h"
64 #include "gromacs/pbcutil/pbc.h"
65 #include "gromacs/pbcutil/pbc-simd.h"
66 #include "gromacs/simd/simd.h"
67 #include "gromacs/simd/simd_math.h"
68 #include "gromacs/simd/vector_operations.h"
69 #include "gromacs/utility/basedefinitions.h"
70 #include "gromacs/utility/fatalerror.h"
71 #include "gromacs/utility/real.h"
72 #include "gromacs/utility/smalloc.h"
74 #include "listed-internal.h"
75 #include "restcbt.h"
77 using namespace gmx; // TODO: Remove when this file is moved into gmx namespace
79 /*! \brief Mysterious CMAP coefficient matrix */
80 const int cmap_coeff_matrix[] = {
81 1, 0, -3, 2, 0, 0, 0, 0, -3, 0, 9, -6, 2, 0, -6, 4,
82 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, -9, 6, -2, 0, 6, -4,
83 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, -6, 0, 0, -6, 4,
84 0, 0, 3, -2, 0, 0, 0, 0, 0, 0, -9, 6, 0, 0, 6, -4,
85 0, 0, 0, 0, 1, 0, -3, 2, -2, 0, 6, -4, 1, 0, -3, 2,
86 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 3, -2, 1, 0, -3, 2,
87 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 2, 0, 0, 3, -2,
88 0, 0, 0, 0, 0, 0, 3, -2, 0, 0, -6, 4, 0, 0, 3, -2,
89 0, 1, -2, 1, 0, 0, 0, 0, 0, -3, 6, -3, 0, 2, -4, 2,
90 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, -6, 3, 0, -2, 4, -2,
91 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 3, 0, 0, 2, -2,
92 0, 0, -1, 1, 0, 0, 0, 0, 0, 0, 3, -3, 0, 0, -2, 2,
93 0, 0, 0, 0, 0, 1, -2, 1, 0, -2, 4, -2, 0, 1, -2, 1,
94 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 2, -1, 0, 1, -2, 1,
95 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, -1, 0, 0, -1, 1,
96 0, 0, 0, 0, 0, 0, -1, 1, 0, 0, 2, -2, 0, 0, -1, 1
100 /*! \brief Compute dx = xi - xj, modulo PBC if non-NULL
102 * \todo This kind of code appears in many places. Consolidate it */
103 static int pbc_rvec_sub(const t_pbc *pbc, const rvec xi, const rvec xj, rvec dx)
105 if (pbc)
107 return pbc_dx_aiuc(pbc, xi, xj, dx);
109 else
111 rvec_sub(xi, xj, dx);
112 return CENTRAL;
116 /*! \brief Morse potential bond
118 * By Frank Everdij. Three parameters needed:
120 * b0 = equilibrium distance in nm
121 * be = beta in nm^-1 (actually, it's nu_e*Sqrt(2*pi*pi*mu/D_e))
122 * cb = well depth in kJ/mol
124 * Note: the potential is referenced to be +cb at infinite separation
125 * and zero at the equilibrium distance!
127 real morse_bonds(int nbonds,
128 const t_iatom forceatoms[], const t_iparams forceparams[],
129 const rvec x[], rvec4 f[], rvec fshift[],
130 const t_pbc *pbc, const t_graph *g,
131 real lambda, real *dvdlambda,
132 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
133 int gmx_unused *global_atom_index)
135 const real one = 1.0;
136 const real two = 2.0;
137 real dr, dr2, temp, omtemp, cbomtemp, fbond, vbond, fij, vtot;
138 real b0, be, cb, b0A, beA, cbA, b0B, beB, cbB, L1;
139 rvec dx;
140 int i, m, ki, type, ai, aj;
141 ivec dt;
143 vtot = 0.0;
144 for (i = 0; (i < nbonds); )
146 type = forceatoms[i++];
147 ai = forceatoms[i++];
148 aj = forceatoms[i++];
150 b0A = forceparams[type].morse.b0A;
151 beA = forceparams[type].morse.betaA;
152 cbA = forceparams[type].morse.cbA;
154 b0B = forceparams[type].morse.b0B;
155 beB = forceparams[type].morse.betaB;
156 cbB = forceparams[type].morse.cbB;
158 L1 = one-lambda; /* 1 */
159 b0 = L1*b0A + lambda*b0B; /* 3 */
160 be = L1*beA + lambda*beB; /* 3 */
161 cb = L1*cbA + lambda*cbB; /* 3 */
163 ki = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /* 3 */
164 dr2 = iprod(dx, dx); /* 5 */
165 dr = dr2*gmx::invsqrt(dr2); /* 10 */
166 temp = std::exp(-be*(dr-b0)); /* 12 */
168 if (temp == one)
170 /* bonds are constrainted. This may _not_ include bond constraints if they are lambda dependent */
171 *dvdlambda += cbB-cbA;
172 continue;
175 omtemp = one-temp; /* 1 */
176 cbomtemp = cb*omtemp; /* 1 */
177 vbond = cbomtemp*omtemp; /* 1 */
178 fbond = -two*be*temp*cbomtemp*gmx::invsqrt(dr2); /* 9 */
179 vtot += vbond; /* 1 */
181 *dvdlambda += (cbB - cbA) * omtemp * omtemp - (2-2*omtemp)*omtemp * cb * ((b0B-b0A)*be - (beB-beA)*(dr-b0)); /* 15 */
183 if (g)
185 ivec_sub(SHIFT_IVEC(g, ai), SHIFT_IVEC(g, aj), dt);
186 ki = IVEC2IS(dt);
189 for (m = 0; (m < DIM); m++) /* 15 */
191 fij = fbond*dx[m];
192 f[ai][m] += fij;
193 f[aj][m] -= fij;
194 fshift[ki][m] += fij;
195 fshift[CENTRAL][m] -= fij;
197 } /* 83 TOTAL */
198 return vtot;
201 //! \cond
202 real cubic_bonds(int nbonds,
203 const t_iatom forceatoms[], const t_iparams forceparams[],
204 const rvec x[], rvec4 f[], rvec fshift[],
205 const t_pbc *pbc, const t_graph *g,
206 real gmx_unused lambda, real gmx_unused *dvdlambda,
207 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
208 int gmx_unused *global_atom_index)
210 const real three = 3.0;
211 const real two = 2.0;
212 real kb, b0, kcub;
213 real dr, dr2, dist, kdist, kdist2, fbond, vbond, fij, vtot;
214 rvec dx;
215 int i, m, ki, type, ai, aj;
216 ivec dt;
218 vtot = 0.0;
219 for (i = 0; (i < nbonds); )
221 type = forceatoms[i++];
222 ai = forceatoms[i++];
223 aj = forceatoms[i++];
225 b0 = forceparams[type].cubic.b0;
226 kb = forceparams[type].cubic.kb;
227 kcub = forceparams[type].cubic.kcub;
229 ki = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /* 3 */
230 dr2 = iprod(dx, dx); /* 5 */
232 if (dr2 == 0.0)
234 continue;
237 dr = dr2*gmx::invsqrt(dr2); /* 10 */
238 dist = dr-b0;
239 kdist = kb*dist;
240 kdist2 = kdist*dist;
242 vbond = kdist2 + kcub*kdist2*dist;
243 fbond = -(two*kdist + three*kdist2*kcub)/dr;
245 vtot += vbond; /* 21 */
247 if (g)
249 ivec_sub(SHIFT_IVEC(g, ai), SHIFT_IVEC(g, aj), dt);
250 ki = IVEC2IS(dt);
252 for (m = 0; (m < DIM); m++) /* 15 */
254 fij = fbond*dx[m];
255 f[ai][m] += fij;
256 f[aj][m] -= fij;
257 fshift[ki][m] += fij;
258 fshift[CENTRAL][m] -= fij;
260 } /* 54 TOTAL */
261 return vtot;
264 real FENE_bonds(int nbonds,
265 const t_iatom forceatoms[], const t_iparams forceparams[],
266 const rvec x[], rvec4 f[], rvec fshift[],
267 const t_pbc *pbc, const t_graph *g,
268 real gmx_unused lambda, real gmx_unused *dvdlambda,
269 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
270 int *global_atom_index)
272 const real half = 0.5;
273 const real one = 1.0;
274 real bm, kb;
275 real dr2, bm2, omdr2obm2, fbond, vbond, fij, vtot;
276 rvec dx;
277 int i, m, ki, type, ai, aj;
278 ivec dt;
280 vtot = 0.0;
281 for (i = 0; (i < nbonds); )
283 type = forceatoms[i++];
284 ai = forceatoms[i++];
285 aj = forceatoms[i++];
287 bm = forceparams[type].fene.bm;
288 kb = forceparams[type].fene.kb;
290 ki = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /* 3 */
291 dr2 = iprod(dx, dx); /* 5 */
293 if (dr2 == 0.0)
295 continue;
298 bm2 = bm*bm;
300 if (dr2 >= bm2)
302 gmx_fatal(FARGS,
303 "r^2 (%f) >= bm^2 (%f) in FENE bond between atoms %d and %d",
304 dr2, bm2,
305 glatnr(global_atom_index, ai),
306 glatnr(global_atom_index, aj));
309 omdr2obm2 = one - dr2/bm2;
311 vbond = -half*kb*bm2*std::log(omdr2obm2);
312 fbond = -kb/omdr2obm2;
314 vtot += vbond; /* 35 */
316 if (g)
318 ivec_sub(SHIFT_IVEC(g, ai), SHIFT_IVEC(g, aj), dt);
319 ki = IVEC2IS(dt);
321 for (m = 0; (m < DIM); m++) /* 15 */
323 fij = fbond*dx[m];
324 f[ai][m] += fij;
325 f[aj][m] -= fij;
326 fshift[ki][m] += fij;
327 fshift[CENTRAL][m] -= fij;
329 } /* 58 TOTAL */
330 return vtot;
333 static real harmonic(real kA, real kB, real xA, real xB, real x, real lambda,
334 real *V, real *F)
336 const real half = 0.5;
337 real L1, kk, x0, dx, dx2;
338 real v, f, dvdlambda;
340 L1 = 1.0-lambda;
341 kk = L1*kA+lambda*kB;
342 x0 = L1*xA+lambda*xB;
344 dx = x-x0;
345 dx2 = dx*dx;
347 f = -kk*dx;
348 v = half*kk*dx2;
349 dvdlambda = half*(kB-kA)*dx2 + (xA-xB)*kk*dx;
351 *F = f;
352 *V = v;
354 return dvdlambda;
356 /* That was 19 flops */
360 real bonds(int nbonds,
361 const t_iatom forceatoms[], const t_iparams forceparams[],
362 const rvec x[], rvec4 f[], rvec fshift[],
363 const t_pbc *pbc, const t_graph *g,
364 real lambda, real *dvdlambda,
365 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
366 int gmx_unused *global_atom_index)
368 int i, m, ki, ai, aj, type;
369 real dr, dr2, fbond, vbond, fij, vtot;
370 rvec dx;
371 ivec dt;
373 vtot = 0.0;
374 for (i = 0; (i < nbonds); )
376 type = forceatoms[i++];
377 ai = forceatoms[i++];
378 aj = forceatoms[i++];
380 ki = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /* 3 */
381 dr2 = iprod(dx, dx); /* 5 */
382 dr = dr2*gmx::invsqrt(dr2); /* 10 */
384 *dvdlambda += harmonic(forceparams[type].harmonic.krA,
385 forceparams[type].harmonic.krB,
386 forceparams[type].harmonic.rA,
387 forceparams[type].harmonic.rB,
388 dr, lambda, &vbond, &fbond); /* 19 */
390 if (dr2 == 0.0)
392 continue;
396 vtot += vbond; /* 1*/
397 fbond *= gmx::invsqrt(dr2); /* 6 */
398 #ifdef DEBUG
399 if (debug)
401 fprintf(debug, "BONDS: dr = %10g vbond = %10g fbond = %10g\n",
402 dr, vbond, fbond);
404 #endif
405 if (g)
407 ivec_sub(SHIFT_IVEC(g, ai), SHIFT_IVEC(g, aj), dt);
408 ki = IVEC2IS(dt);
410 for (m = 0; (m < DIM); m++) /* 15 */
412 fij = fbond*dx[m];
413 f[ai][m] += fij;
414 f[aj][m] -= fij;
415 fshift[ki][m] += fij;
416 fshift[CENTRAL][m] -= fij;
418 } /* 59 TOTAL */
419 return vtot;
422 real restraint_bonds(int nbonds,
423 const t_iatom forceatoms[], const t_iparams forceparams[],
424 const rvec x[], rvec4 f[], rvec fshift[],
425 const t_pbc *pbc, const t_graph *g,
426 real lambda, real *dvdlambda,
427 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
428 int gmx_unused *global_atom_index)
430 int i, m, ki, ai, aj, type;
431 real dr, dr2, fbond, vbond, fij, vtot;
432 real L1;
433 real low, dlow, up1, dup1, up2, dup2, k, dk;
434 real drh, drh2;
435 rvec dx;
436 ivec dt;
438 L1 = 1.0 - lambda;
440 vtot = 0.0;
441 for (i = 0; (i < nbonds); )
443 type = forceatoms[i++];
444 ai = forceatoms[i++];
445 aj = forceatoms[i++];
447 ki = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /* 3 */
448 dr2 = iprod(dx, dx); /* 5 */
449 dr = dr2*gmx::invsqrt(dr2); /* 10 */
451 low = L1*forceparams[type].restraint.lowA + lambda*forceparams[type].restraint.lowB;
452 dlow = -forceparams[type].restraint.lowA + forceparams[type].restraint.lowB;
453 up1 = L1*forceparams[type].restraint.up1A + lambda*forceparams[type].restraint.up1B;
454 dup1 = -forceparams[type].restraint.up1A + forceparams[type].restraint.up1B;
455 up2 = L1*forceparams[type].restraint.up2A + lambda*forceparams[type].restraint.up2B;
456 dup2 = -forceparams[type].restraint.up2A + forceparams[type].restraint.up2B;
457 k = L1*forceparams[type].restraint.kA + lambda*forceparams[type].restraint.kB;
458 dk = -forceparams[type].restraint.kA + forceparams[type].restraint.kB;
459 /* 24 */
461 if (dr < low)
463 drh = dr - low;
464 drh2 = drh*drh;
465 vbond = 0.5*k*drh2;
466 fbond = -k*drh;
467 *dvdlambda += 0.5*dk*drh2 - k*dlow*drh;
468 } /* 11 */
469 else if (dr <= up1)
471 vbond = 0;
472 fbond = 0;
474 else if (dr <= up2)
476 drh = dr - up1;
477 drh2 = drh*drh;
478 vbond = 0.5*k*drh2;
479 fbond = -k*drh;
480 *dvdlambda += 0.5*dk*drh2 - k*dup1*drh;
481 } /* 11 */
482 else
484 drh = dr - up2;
485 vbond = k*(up2 - up1)*(0.5*(up2 - up1) + drh);
486 fbond = -k*(up2 - up1);
487 *dvdlambda += dk*(up2 - up1)*(0.5*(up2 - up1) + drh)
488 + k*(dup2 - dup1)*(up2 - up1 + drh)
489 - k*(up2 - up1)*dup2;
492 if (dr2 == 0.0)
494 continue;
497 vtot += vbond; /* 1*/
498 fbond *= gmx::invsqrt(dr2); /* 6 */
499 #ifdef DEBUG
500 if (debug)
502 fprintf(debug, "BONDS: dr = %10g vbond = %10g fbond = %10g\n",
503 dr, vbond, fbond);
505 #endif
506 if (g)
508 ivec_sub(SHIFT_IVEC(g, ai), SHIFT_IVEC(g, aj), dt);
509 ki = IVEC2IS(dt);
511 for (m = 0; (m < DIM); m++) /* 15 */
513 fij = fbond*dx[m];
514 f[ai][m] += fij;
515 f[aj][m] -= fij;
516 fshift[ki][m] += fij;
517 fshift[CENTRAL][m] -= fij;
519 } /* 59 TOTAL */
521 return vtot;
524 real polarize(int nbonds,
525 const t_iatom forceatoms[], const t_iparams forceparams[],
526 const rvec x[], rvec4 f[], rvec fshift[],
527 const t_pbc *pbc, const t_graph *g,
528 real lambda, real *dvdlambda,
529 const t_mdatoms *md, t_fcdata gmx_unused *fcd,
530 int gmx_unused *global_atom_index)
532 int i, m, ki, ai, aj, type;
533 real dr, dr2, fbond, vbond, fij, vtot, ksh;
534 rvec dx;
535 ivec dt;
537 vtot = 0.0;
538 for (i = 0; (i < nbonds); )
540 type = forceatoms[i++];
541 ai = forceatoms[i++];
542 aj = forceatoms[i++];
543 ksh = gmx::square(md->chargeA[aj])*ONE_4PI_EPS0/forceparams[type].polarize.alpha;
544 if (debug)
546 fprintf(debug, "POL: local ai = %d aj = %d ksh = %.3f\n", ai, aj, ksh);
549 ki = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /* 3 */
550 dr2 = iprod(dx, dx); /* 5 */
551 dr = std::sqrt(dr2); /* 10 */
553 *dvdlambda += harmonic(ksh, ksh, 0, 0, dr, lambda, &vbond, &fbond); /* 19 */
555 if (dr2 == 0.0)
557 continue;
560 vtot += vbond; /* 1*/
561 fbond *= gmx::invsqrt(dr2); /* 6 */
563 if (g)
565 ivec_sub(SHIFT_IVEC(g, ai), SHIFT_IVEC(g, aj), dt);
566 ki = IVEC2IS(dt);
568 for (m = 0; (m < DIM); m++) /* 15 */
570 fij = fbond*dx[m];
571 f[ai][m] += fij;
572 f[aj][m] -= fij;
573 fshift[ki][m] += fij;
574 fshift[CENTRAL][m] -= fij;
576 } /* 59 TOTAL */
577 return vtot;
580 real anharm_polarize(int nbonds,
581 const t_iatom forceatoms[], const t_iparams forceparams[],
582 const rvec x[], rvec4 f[], rvec fshift[],
583 const t_pbc *pbc, const t_graph *g,
584 real lambda, real *dvdlambda,
585 const t_mdatoms *md, t_fcdata gmx_unused *fcd,
586 int gmx_unused *global_atom_index)
588 int i, m, ki, ai, aj, type;
589 real dr, dr2, fbond, vbond, fij, vtot, ksh, khyp, drcut, ddr, ddr3;
590 rvec dx;
591 ivec dt;
593 vtot = 0.0;
594 for (i = 0; (i < nbonds); )
596 type = forceatoms[i++];
597 ai = forceatoms[i++];
598 aj = forceatoms[i++];
599 ksh = gmx::square(md->chargeA[aj])*ONE_4PI_EPS0/forceparams[type].anharm_polarize.alpha; /* 7*/
600 khyp = forceparams[type].anharm_polarize.khyp;
601 drcut = forceparams[type].anharm_polarize.drcut;
602 if (debug)
604 fprintf(debug, "POL: local ai = %d aj = %d ksh = %.3f\n", ai, aj, ksh);
607 ki = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /* 3 */
608 dr2 = iprod(dx, dx); /* 5 */
609 dr = dr2*gmx::invsqrt(dr2); /* 10 */
611 *dvdlambda += harmonic(ksh, ksh, 0, 0, dr, lambda, &vbond, &fbond); /* 19 */
613 if (dr2 == 0.0)
615 continue;
618 if (dr > drcut)
620 ddr = dr-drcut;
621 ddr3 = ddr*ddr*ddr;
622 vbond += khyp*ddr*ddr3;
623 fbond -= 4*khyp*ddr3;
625 fbond *= gmx::invsqrt(dr2); /* 6 */
626 vtot += vbond; /* 1*/
628 if (g)
630 ivec_sub(SHIFT_IVEC(g, ai), SHIFT_IVEC(g, aj), dt);
631 ki = IVEC2IS(dt);
633 for (m = 0; (m < DIM); m++) /* 15 */
635 fij = fbond*dx[m];
636 f[ai][m] += fij;
637 f[aj][m] -= fij;
638 fshift[ki][m] += fij;
639 fshift[CENTRAL][m] -= fij;
641 } /* 72 TOTAL */
642 return vtot;
645 real water_pol(int nbonds,
646 const t_iatom forceatoms[], const t_iparams forceparams[],
647 const rvec x[], rvec4 f[], rvec gmx_unused fshift[],
648 const t_pbc gmx_unused *pbc, const t_graph gmx_unused *g,
649 real gmx_unused lambda, real gmx_unused *dvdlambda,
650 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
651 int gmx_unused *global_atom_index)
653 /* This routine implements anisotropic polarizibility for water, through
654 * a shell connected to a dummy with spring constant that differ in the
655 * three spatial dimensions in the molecular frame.
657 int i, m, aO, aH1, aH2, aD, aS, type, type0, ki;
658 ivec dt;
659 rvec dOH1, dOH2, dHH, dOD, dDS, nW, kk, dx, kdx, proj;
660 #ifdef DEBUG
661 rvec df;
662 #endif
663 real vtot, fij, r_HH, r_OD, r_nW, tx, ty, tz, qS;
665 vtot = 0.0;
666 if (nbonds > 0)
668 type0 = forceatoms[0];
669 aS = forceatoms[5];
670 qS = md->chargeA[aS];
671 kk[XX] = gmx::square(qS)*ONE_4PI_EPS0/forceparams[type0].wpol.al_x;
672 kk[YY] = gmx::square(qS)*ONE_4PI_EPS0/forceparams[type0].wpol.al_y;
673 kk[ZZ] = gmx::square(qS)*ONE_4PI_EPS0/forceparams[type0].wpol.al_z;
674 r_HH = 1.0/forceparams[type0].wpol.rHH;
675 if (debug)
677 fprintf(debug, "WPOL: qS = %10.5f aS = %5d\n", qS, aS);
678 fprintf(debug, "WPOL: kk = %10.3f %10.3f %10.3f\n",
679 kk[XX], kk[YY], kk[ZZ]);
680 fprintf(debug, "WPOL: rOH = %10.3f rHH = %10.3f rOD = %10.3f\n",
681 forceparams[type0].wpol.rOH,
682 forceparams[type0].wpol.rHH,
683 forceparams[type0].wpol.rOD);
685 for (i = 0; (i < nbonds); i += 6)
687 type = forceatoms[i];
688 if (type != type0)
690 gmx_fatal(FARGS, "Sorry, type = %d, type0 = %d, file = %s, line = %d",
691 type, type0, __FILE__, __LINE__);
693 aO = forceatoms[i+1];
694 aH1 = forceatoms[i+2];
695 aH2 = forceatoms[i+3];
696 aD = forceatoms[i+4];
697 aS = forceatoms[i+5];
699 /* Compute vectors describing the water frame */
700 pbc_rvec_sub(pbc, x[aH1], x[aO], dOH1);
701 pbc_rvec_sub(pbc, x[aH2], x[aO], dOH2);
702 pbc_rvec_sub(pbc, x[aH2], x[aH1], dHH);
703 pbc_rvec_sub(pbc, x[aD], x[aO], dOD);
704 ki = pbc_rvec_sub(pbc, x[aS], x[aD], dDS);
705 cprod(dOH1, dOH2, nW);
707 /* Compute inverse length of normal vector
708 * (this one could be precomputed, but I'm too lazy now)
710 r_nW = gmx::invsqrt(iprod(nW, nW));
711 /* This is for precision, but does not make a big difference,
712 * it can go later.
714 r_OD = gmx::invsqrt(iprod(dOD, dOD));
716 /* Normalize the vectors in the water frame */
717 svmul(r_nW, nW, nW);
718 svmul(r_HH, dHH, dHH);
719 svmul(r_OD, dOD, dOD);
721 /* Compute displacement of shell along components of the vector */
722 dx[ZZ] = iprod(dDS, dOD);
723 /* Compute projection on the XY plane: dDS - dx[ZZ]*dOD */
724 for (m = 0; (m < DIM); m++)
726 proj[m] = dDS[m]-dx[ZZ]*dOD[m];
729 /*dx[XX] = iprod(dDS,nW);
730 dx[YY] = iprod(dDS,dHH);*/
731 dx[XX] = iprod(proj, nW);
732 for (m = 0; (m < DIM); m++)
734 proj[m] -= dx[XX]*nW[m];
736 dx[YY] = iprod(proj, dHH);
737 /*#define DEBUG*/
738 #ifdef DEBUG
739 if (debug)
741 fprintf(debug, "WPOL: dx2=%10g dy2=%10g dz2=%10g sum=%10g dDS^2=%10g\n",
742 gmx::square(dx[XX]), gmx::square(dx[YY]), gmx::square(dx[ZZ]), iprod(dx, dx), iprod(dDS, dDS));
743 fprintf(debug, "WPOL: dHH=(%10g,%10g,%10g)\n", dHH[XX], dHH[YY], dHH[ZZ]);
744 fprintf(debug, "WPOL: dOD=(%10g,%10g,%10g), 1/r_OD = %10g\n",
745 dOD[XX], dOD[YY], dOD[ZZ], 1/r_OD);
746 fprintf(debug, "WPOL: nW =(%10g,%10g,%10g), 1/r_nW = %10g\n",
747 nW[XX], nW[YY], nW[ZZ], 1/r_nW);
748 fprintf(debug, "WPOL: dx =%10g, dy =%10g, dz =%10g\n",
749 dx[XX], dx[YY], dx[ZZ]);
750 fprintf(debug, "WPOL: dDSx=%10g, dDSy=%10g, dDSz=%10g\n",
751 dDS[XX], dDS[YY], dDS[ZZ]);
753 #endif
754 /* Now compute the forces and energy */
755 kdx[XX] = kk[XX]*dx[XX];
756 kdx[YY] = kk[YY]*dx[YY];
757 kdx[ZZ] = kk[ZZ]*dx[ZZ];
758 vtot += iprod(dx, kdx);
760 if (g)
762 ivec_sub(SHIFT_IVEC(g, aS), SHIFT_IVEC(g, aD), dt);
763 ki = IVEC2IS(dt);
766 for (m = 0; (m < DIM); m++)
768 /* This is a tensor operation but written out for speed */
769 tx = nW[m]*kdx[XX];
770 ty = dHH[m]*kdx[YY];
771 tz = dOD[m]*kdx[ZZ];
772 fij = -tx-ty-tz;
773 #ifdef DEBUG
774 df[m] = fij;
775 #endif
776 f[aS][m] += fij;
777 f[aD][m] -= fij;
778 fshift[ki][m] += fij;
779 fshift[CENTRAL][m] -= fij;
781 #ifdef DEBUG
782 if (debug)
784 fprintf(debug, "WPOL: vwpol=%g\n", 0.5*iprod(dx, kdx));
785 fprintf(debug, "WPOL: df = (%10g, %10g, %10g)\n", df[XX], df[YY], df[ZZ]);
787 #endif
790 return 0.5*vtot;
793 static real do_1_thole(const rvec xi, const rvec xj, rvec fi, rvec fj,
794 const t_pbc *pbc, real qq,
795 rvec fshift[], real afac)
797 rvec r12;
798 real r12sq, r12_1, r12bar, v0, v1, fscal, ebar, fff;
799 int m, t;
801 t = pbc_rvec_sub(pbc, xi, xj, r12); /* 3 */
803 r12sq = iprod(r12, r12); /* 5 */
804 r12_1 = gmx::invsqrt(r12sq); /* 5 */
805 r12bar = afac/r12_1; /* 5 */
806 v0 = qq*ONE_4PI_EPS0*r12_1; /* 2 */
807 ebar = std::exp(-r12bar); /* 5 */
808 v1 = (1-(1+0.5*r12bar)*ebar); /* 4 */
809 fscal = ((v0*r12_1)*v1 - v0*0.5*afac*ebar*(r12bar+1))*r12_1; /* 9 */
810 if (debug)
812 fprintf(debug, "THOLE: v0 = %.3f v1 = %.3f r12= % .3f r12bar = %.3f fscal = %.3f ebar = %.3f\n", v0, v1, 1/r12_1, r12bar, fscal, ebar);
815 for (m = 0; (m < DIM); m++)
817 fff = fscal*r12[m];
818 fi[m] += fff;
819 fj[m] -= fff;
820 fshift[t][m] += fff;
821 fshift[CENTRAL][m] -= fff;
822 } /* 15 */
824 return v0*v1; /* 1 */
825 /* 54 */
828 real thole_pol(int nbonds,
829 const t_iatom forceatoms[], const t_iparams forceparams[],
830 const rvec x[], rvec4 f[], rvec fshift[],
831 const t_pbc *pbc, const t_graph gmx_unused *g,
832 real gmx_unused lambda, real gmx_unused *dvdlambda,
833 const t_mdatoms *md, t_fcdata gmx_unused *fcd,
834 int gmx_unused *global_atom_index)
836 /* Interaction between two pairs of particles with opposite charge */
837 int i, type, a1, da1, a2, da2;
838 real q1, q2, qq, a, al1, al2, afac;
839 real V = 0;
841 for (i = 0; (i < nbonds); )
843 type = forceatoms[i++];
844 a1 = forceatoms[i++];
845 da1 = forceatoms[i++];
846 a2 = forceatoms[i++];
847 da2 = forceatoms[i++];
848 q1 = md->chargeA[da1];
849 q2 = md->chargeA[da2];
850 a = forceparams[type].thole.a;
851 al1 = forceparams[type].thole.alpha1;
852 al2 = forceparams[type].thole.alpha2;
853 qq = q1*q2;
854 afac = a*gmx::invsixthroot(al1*al2);
855 V += do_1_thole(x[a1], x[a2], f[a1], f[a2], pbc, qq, fshift, afac);
856 V += do_1_thole(x[da1], x[a2], f[da1], f[a2], pbc, -qq, fshift, afac);
857 V += do_1_thole(x[a1], x[da2], f[a1], f[da2], pbc, -qq, fshift, afac);
858 V += do_1_thole(x[da1], x[da2], f[da1], f[da2], pbc, qq, fshift, afac);
860 /* 290 flops */
861 return V;
864 real bond_angle(const rvec xi, const rvec xj, const rvec xk, const t_pbc *pbc,
865 rvec r_ij, rvec r_kj, real *costh,
866 int *t1, int *t2)
867 /* Return value is the angle between the bonds i-j and j-k */
869 /* 41 FLOPS */
870 real th;
872 *t1 = pbc_rvec_sub(pbc, xi, xj, r_ij); /* 3 */
873 *t2 = pbc_rvec_sub(pbc, xk, xj, r_kj); /* 3 */
875 *costh = cos_angle(r_ij, r_kj); /* 25 */
876 th = std::acos(*costh); /* 10 */
877 /* 41 TOTAL */
878 return th;
881 real angles(int nbonds,
882 const t_iatom forceatoms[], const t_iparams forceparams[],
883 const rvec x[], rvec4 f[], rvec fshift[],
884 const t_pbc *pbc, const t_graph *g,
885 real lambda, real *dvdlambda,
886 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
887 int gmx_unused *global_atom_index)
889 int i, ai, aj, ak, t1, t2, type;
890 rvec r_ij, r_kj;
891 real cos_theta, cos_theta2, theta, dVdt, va, vtot;
892 ivec jt, dt_ij, dt_kj;
894 vtot = 0.0;
895 for (i = 0; i < nbonds; )
897 type = forceatoms[i++];
898 ai = forceatoms[i++];
899 aj = forceatoms[i++];
900 ak = forceatoms[i++];
902 theta = bond_angle(x[ai], x[aj], x[ak], pbc,
903 r_ij, r_kj, &cos_theta, &t1, &t2); /* 41 */
905 *dvdlambda += harmonic(forceparams[type].harmonic.krA,
906 forceparams[type].harmonic.krB,
907 forceparams[type].harmonic.rA*DEG2RAD,
908 forceparams[type].harmonic.rB*DEG2RAD,
909 theta, lambda, &va, &dVdt); /* 21 */
910 vtot += va;
912 cos_theta2 = gmx::square(cos_theta);
913 if (cos_theta2 < 1)
915 int m;
916 real st, sth;
917 real cik, cii, ckk;
918 real nrkj2, nrij2;
919 real nrkj_1, nrij_1;
920 rvec f_i, f_j, f_k;
922 st = dVdt*gmx::invsqrt(1 - cos_theta2); /* 12 */
923 sth = st*cos_theta; /* 1 */
924 #ifdef DEBUG
925 if (debug)
927 fprintf(debug, "ANGLES: theta = %10g vth = %10g dV/dtheta = %10g\n",
928 theta*RAD2DEG, va, dVdt);
930 #endif
931 nrij2 = iprod(r_ij, r_ij); /* 5 */
932 nrkj2 = iprod(r_kj, r_kj); /* 5 */
934 nrij_1 = gmx::invsqrt(nrij2); /* 10 */
935 nrkj_1 = gmx::invsqrt(nrkj2); /* 10 */
937 cik = st*nrij_1*nrkj_1; /* 2 */
938 cii = sth*nrij_1*nrij_1; /* 2 */
939 ckk = sth*nrkj_1*nrkj_1; /* 2 */
941 for (m = 0; m < DIM; m++)
942 { /* 39 */
943 f_i[m] = -(cik*r_kj[m] - cii*r_ij[m]);
944 f_k[m] = -(cik*r_ij[m] - ckk*r_kj[m]);
945 f_j[m] = -f_i[m] - f_k[m];
946 f[ai][m] += f_i[m];
947 f[aj][m] += f_j[m];
948 f[ak][m] += f_k[m];
950 if (g != nullptr)
952 copy_ivec(SHIFT_IVEC(g, aj), jt);
954 ivec_sub(SHIFT_IVEC(g, ai), jt, dt_ij);
955 ivec_sub(SHIFT_IVEC(g, ak), jt, dt_kj);
956 t1 = IVEC2IS(dt_ij);
957 t2 = IVEC2IS(dt_kj);
959 rvec_inc(fshift[t1], f_i);
960 rvec_inc(fshift[CENTRAL], f_j);
961 rvec_inc(fshift[t2], f_k);
962 } /* 161 TOTAL */
965 return vtot;
968 #if GMX_SIMD_HAVE_REAL
970 /* As angles, but using SIMD to calculate many angles at once.
971 * This routines does not calculate energies and shift forces.
973 void
974 angles_noener_simd(int nbonds,
975 const t_iatom forceatoms[], const t_iparams forceparams[],
976 const rvec x[], rvec4 f[],
977 const t_pbc *pbc, const t_graph gmx_unused *g,
978 real gmx_unused lambda,
979 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
980 int gmx_unused *global_atom_index)
982 const int nfa1 = 4;
983 int i, iu, s;
984 int type;
985 GMX_ALIGNED(int, GMX_SIMD_REAL_WIDTH) ai[GMX_SIMD_REAL_WIDTH];
986 GMX_ALIGNED(int, GMX_SIMD_REAL_WIDTH) aj[GMX_SIMD_REAL_WIDTH];
987 GMX_ALIGNED(int, GMX_SIMD_REAL_WIDTH) ak[GMX_SIMD_REAL_WIDTH];
988 GMX_ALIGNED(real, GMX_SIMD_REAL_WIDTH) coeff[2*GMX_SIMD_REAL_WIDTH];
989 SimdReal deg2rad_S(DEG2RAD);
990 SimdReal xi_S, yi_S, zi_S;
991 SimdReal xj_S, yj_S, zj_S;
992 SimdReal xk_S, yk_S, zk_S;
993 SimdReal k_S, theta0_S;
994 SimdReal rijx_S, rijy_S, rijz_S;
995 SimdReal rkjx_S, rkjy_S, rkjz_S;
996 SimdReal one_S(1.0);
997 SimdReal min_one_plus_eps_S(-1.0 + 2.0*GMX_REAL_EPS); // Smallest number > -1
999 SimdReal rij_rkj_S;
1000 SimdReal nrij2_S, nrij_1_S;
1001 SimdReal nrkj2_S, nrkj_1_S;
1002 SimdReal cos_S, invsin_S;
1003 SimdReal theta_S;
1004 SimdReal st_S, sth_S;
1005 SimdReal cik_S, cii_S, ckk_S;
1006 SimdReal f_ix_S, f_iy_S, f_iz_S;
1007 SimdReal f_kx_S, f_ky_S, f_kz_S;
1008 GMX_ALIGNED(real, GMX_SIMD_REAL_WIDTH) pbc_simd[9*GMX_SIMD_REAL_WIDTH];
1010 set_pbc_simd(pbc, pbc_simd);
1012 /* nbonds is the number of angles times nfa1, here we step GMX_SIMD_REAL_WIDTH angles */
1013 for (i = 0; (i < nbonds); i += GMX_SIMD_REAL_WIDTH*nfa1)
1015 /* Collect atoms for GMX_SIMD_REAL_WIDTH angles.
1016 * iu indexes into forceatoms, we should not let iu go beyond nbonds.
1018 iu = i;
1019 for (s = 0; s < GMX_SIMD_REAL_WIDTH; s++)
1021 type = forceatoms[iu];
1022 ai[s] = forceatoms[iu+1];
1023 aj[s] = forceatoms[iu+2];
1024 ak[s] = forceatoms[iu+3];
1026 /* At the end fill the arrays with the last atoms and 0 params */
1027 if (i + s*nfa1 < nbonds)
1029 coeff[s] = forceparams[type].harmonic.krA;
1030 coeff[GMX_SIMD_REAL_WIDTH+s] = forceparams[type].harmonic.rA;
1032 if (iu + nfa1 < nbonds)
1034 iu += nfa1;
1037 else
1039 coeff[s] = 0;
1040 coeff[GMX_SIMD_REAL_WIDTH+s] = 0;
1044 /* Store the non PBC corrected distances packed and aligned */
1045 gatherLoadUTranspose<3>(reinterpret_cast<const real *>(x), ai, &xi_S, &yi_S, &zi_S);
1046 gatherLoadUTranspose<3>(reinterpret_cast<const real *>(x), aj, &xj_S, &yj_S, &zj_S);
1047 gatherLoadUTranspose<3>(reinterpret_cast<const real *>(x), ak, &xk_S, &yk_S, &zk_S);
1048 rijx_S = xi_S - xj_S;
1049 rijy_S = yi_S - yj_S;
1050 rijz_S = zi_S - zj_S;
1051 rkjx_S = xk_S - xj_S;
1052 rkjy_S = yk_S - yj_S;
1053 rkjz_S = zk_S - zj_S;
1055 k_S = load<SimdReal>(coeff);
1056 theta0_S = load<SimdReal>(coeff+GMX_SIMD_REAL_WIDTH) * deg2rad_S;
1058 pbc_correct_dx_simd(&rijx_S, &rijy_S, &rijz_S, pbc_simd);
1059 pbc_correct_dx_simd(&rkjx_S, &rkjy_S, &rkjz_S, pbc_simd);
1061 rij_rkj_S = iprod(rijx_S, rijy_S, rijz_S,
1062 rkjx_S, rkjy_S, rkjz_S);
1064 nrij2_S = norm2(rijx_S, rijy_S, rijz_S);
1065 nrkj2_S = norm2(rkjx_S, rkjy_S, rkjz_S);
1067 nrij_1_S = invsqrt(nrij2_S);
1068 nrkj_1_S = invsqrt(nrkj2_S);
1070 cos_S = rij_rkj_S * nrij_1_S * nrkj_1_S;
1072 /* To allow for 180 degrees, we take the max of cos and -1 + 1bit,
1073 * so we can safely get the 1/sin from 1/sqrt(1 - cos^2).
1074 * This also ensures that rounding errors would cause the argument
1075 * of simdAcos to be < -1.
1076 * Note that we do not take precautions for cos(0)=1, so the outer
1077 * atoms in an angle should not be on top of each other.
1079 cos_S = max(cos_S, min_one_plus_eps_S);
1081 theta_S = acos(cos_S);
1083 invsin_S = invsqrt( one_S - cos_S * cos_S );
1085 st_S = k_S * (theta0_S - theta_S) * invsin_S;
1086 sth_S = st_S * cos_S;
1088 cik_S = st_S * nrij_1_S * nrkj_1_S;
1089 cii_S = sth_S * nrij_1_S * nrij_1_S;
1090 ckk_S = sth_S * nrkj_1_S * nrkj_1_S;
1092 f_ix_S = cii_S * rijx_S;
1093 f_ix_S = fnma(cik_S, rkjx_S, f_ix_S);
1094 f_iy_S = cii_S * rijy_S;
1095 f_iy_S = fnma(cik_S, rkjy_S, f_iy_S);
1096 f_iz_S = cii_S * rijz_S;
1097 f_iz_S = fnma(cik_S, rkjz_S, f_iz_S);
1098 f_kx_S = ckk_S * rkjx_S;
1099 f_kx_S = fnma(cik_S, rijx_S, f_kx_S);
1100 f_ky_S = ckk_S * rkjy_S;
1101 f_ky_S = fnma(cik_S, rijy_S, f_ky_S);
1102 f_kz_S = ckk_S * rkjz_S;
1103 f_kz_S = fnma(cik_S, rijz_S, f_kz_S);
1105 transposeScatterIncrU<4>(reinterpret_cast<real *>(f), ai, f_ix_S, f_iy_S, f_iz_S);
1106 transposeScatterDecrU<4>(reinterpret_cast<real *>(f), aj, f_ix_S + f_kx_S, f_iy_S + f_ky_S, f_iz_S + f_kz_S);
1107 transposeScatterIncrU<4>(reinterpret_cast<real *>(f), ak, f_kx_S, f_ky_S, f_kz_S);
1111 #endif // GMX_SIMD_HAVE_REAL
1113 real linear_angles(int nbonds,
1114 const t_iatom forceatoms[], const t_iparams forceparams[],
1115 const rvec x[], rvec4 f[], rvec fshift[],
1116 const t_pbc *pbc, const t_graph *g,
1117 real lambda, real *dvdlambda,
1118 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
1119 int gmx_unused *global_atom_index)
1121 int i, m, ai, aj, ak, t1, t2, type;
1122 rvec f_i, f_j, f_k;
1123 real L1, kA, kB, aA, aB, dr, dr2, va, vtot, a, b, klin;
1124 ivec jt, dt_ij, dt_kj;
1125 rvec r_ij, r_kj, r_ik, dx;
1127 L1 = 1-lambda;
1128 vtot = 0.0;
1129 for (i = 0; (i < nbonds); )
1131 type = forceatoms[i++];
1132 ai = forceatoms[i++];
1133 aj = forceatoms[i++];
1134 ak = forceatoms[i++];
1136 kA = forceparams[type].linangle.klinA;
1137 kB = forceparams[type].linangle.klinB;
1138 klin = L1*kA + lambda*kB;
1140 aA = forceparams[type].linangle.aA;
1141 aB = forceparams[type].linangle.aB;
1142 a = L1*aA+lambda*aB;
1143 b = 1-a;
1145 t1 = pbc_rvec_sub(pbc, x[ai], x[aj], r_ij);
1146 t2 = pbc_rvec_sub(pbc, x[ak], x[aj], r_kj);
1147 rvec_sub(r_ij, r_kj, r_ik);
1149 dr2 = 0;
1150 for (m = 0; (m < DIM); m++)
1152 dr = -a * r_ij[m] - b * r_kj[m];
1153 dr2 += dr*dr;
1154 dx[m] = dr;
1155 f_i[m] = a*klin*dr;
1156 f_k[m] = b*klin*dr;
1157 f_j[m] = -(f_i[m]+f_k[m]);
1158 f[ai][m] += f_i[m];
1159 f[aj][m] += f_j[m];
1160 f[ak][m] += f_k[m];
1162 va = 0.5*klin*dr2;
1163 *dvdlambda += 0.5*(kB-kA)*dr2 + klin*(aB-aA)*iprod(dx, r_ik);
1165 vtot += va;
1167 if (g)
1169 copy_ivec(SHIFT_IVEC(g, aj), jt);
1171 ivec_sub(SHIFT_IVEC(g, ai), jt, dt_ij);
1172 ivec_sub(SHIFT_IVEC(g, ak), jt, dt_kj);
1173 t1 = IVEC2IS(dt_ij);
1174 t2 = IVEC2IS(dt_kj);
1176 rvec_inc(fshift[t1], f_i);
1177 rvec_inc(fshift[CENTRAL], f_j);
1178 rvec_inc(fshift[t2], f_k);
1179 } /* 57 TOTAL */
1180 return vtot;
1183 real urey_bradley(int nbonds,
1184 const t_iatom forceatoms[], const t_iparams forceparams[],
1185 const rvec x[], rvec4 f[], rvec fshift[],
1186 const t_pbc *pbc, const t_graph *g,
1187 real lambda, real *dvdlambda,
1188 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
1189 int gmx_unused *global_atom_index)
1191 int i, m, ai, aj, ak, t1, t2, type, ki;
1192 rvec r_ij, r_kj, r_ik;
1193 real cos_theta, cos_theta2, theta;
1194 real dVdt, va, vtot, dr, dr2, vbond, fbond, fik;
1195 real kthA, th0A, kUBA, r13A, kthB, th0B, kUBB, r13B;
1196 ivec jt, dt_ij, dt_kj, dt_ik;
1198 vtot = 0.0;
1199 for (i = 0; (i < nbonds); )
1201 type = forceatoms[i++];
1202 ai = forceatoms[i++];
1203 aj = forceatoms[i++];
1204 ak = forceatoms[i++];
1205 th0A = forceparams[type].u_b.thetaA*DEG2RAD;
1206 kthA = forceparams[type].u_b.kthetaA;
1207 r13A = forceparams[type].u_b.r13A;
1208 kUBA = forceparams[type].u_b.kUBA;
1209 th0B = forceparams[type].u_b.thetaB*DEG2RAD;
1210 kthB = forceparams[type].u_b.kthetaB;
1211 r13B = forceparams[type].u_b.r13B;
1212 kUBB = forceparams[type].u_b.kUBB;
1214 theta = bond_angle(x[ai], x[aj], x[ak], pbc,
1215 r_ij, r_kj, &cos_theta, &t1, &t2); /* 41 */
1217 *dvdlambda += harmonic(kthA, kthB, th0A, th0B, theta, lambda, &va, &dVdt); /* 21 */
1218 vtot += va;
1220 ki = pbc_rvec_sub(pbc, x[ai], x[ak], r_ik); /* 3 */
1221 dr2 = iprod(r_ik, r_ik); /* 5 */
1222 dr = dr2*gmx::invsqrt(dr2); /* 10 */
1224 *dvdlambda += harmonic(kUBA, kUBB, r13A, r13B, dr, lambda, &vbond, &fbond); /* 19 */
1226 cos_theta2 = gmx::square(cos_theta); /* 1 */
1227 if (cos_theta2 < 1)
1229 real st, sth;
1230 real cik, cii, ckk;
1231 real nrkj2, nrij2;
1232 rvec f_i, f_j, f_k;
1234 st = dVdt*gmx::invsqrt(1 - cos_theta2); /* 12 */
1235 sth = st*cos_theta; /* 1 */
1236 #ifdef DEBUG
1237 if (debug)
1239 fprintf(debug, "ANGLES: theta = %10g vth = %10g dV/dtheta = %10g\n",
1240 theta*RAD2DEG, va, dVdt);
1242 #endif
1243 nrkj2 = iprod(r_kj, r_kj); /* 5 */
1244 nrij2 = iprod(r_ij, r_ij);
1246 cik = st*gmx::invsqrt(nrkj2*nrij2); /* 12 */
1247 cii = sth/nrij2; /* 10 */
1248 ckk = sth/nrkj2; /* 10 */
1250 for (m = 0; (m < DIM); m++) /* 39 */
1252 f_i[m] = -(cik*r_kj[m]-cii*r_ij[m]);
1253 f_k[m] = -(cik*r_ij[m]-ckk*r_kj[m]);
1254 f_j[m] = -f_i[m]-f_k[m];
1255 f[ai][m] += f_i[m];
1256 f[aj][m] += f_j[m];
1257 f[ak][m] += f_k[m];
1259 if (g)
1261 copy_ivec(SHIFT_IVEC(g, aj), jt);
1263 ivec_sub(SHIFT_IVEC(g, ai), jt, dt_ij);
1264 ivec_sub(SHIFT_IVEC(g, ak), jt, dt_kj);
1265 t1 = IVEC2IS(dt_ij);
1266 t2 = IVEC2IS(dt_kj);
1268 rvec_inc(fshift[t1], f_i);
1269 rvec_inc(fshift[CENTRAL], f_j);
1270 rvec_inc(fshift[t2], f_k);
1271 } /* 161 TOTAL */
1272 /* Time for the bond calculations */
1273 if (dr2 == 0.0)
1275 continue;
1278 vtot += vbond; /* 1*/
1279 fbond *= gmx::invsqrt(dr2); /* 6 */
1281 if (g)
1283 ivec_sub(SHIFT_IVEC(g, ai), SHIFT_IVEC(g, ak), dt_ik);
1284 ki = IVEC2IS(dt_ik);
1286 for (m = 0; (m < DIM); m++) /* 15 */
1288 fik = fbond*r_ik[m];
1289 f[ai][m] += fik;
1290 f[ak][m] -= fik;
1291 fshift[ki][m] += fik;
1292 fshift[CENTRAL][m] -= fik;
1295 return vtot;
1298 #if GMX_SIMD_HAVE_REAL
1300 /* As urey_bradley, but using SIMD to calculate many potentials at once.
1301 * This routines does not calculate energies and shift forces.
1303 void urey_bradley_noener_simd(int nbonds,
1304 const t_iatom forceatoms[], const t_iparams forceparams[],
1305 const rvec x[], rvec4 f[],
1306 const t_pbc *pbc, const t_graph gmx_unused *g,
1307 real gmx_unused lambda,
1308 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
1309 int gmx_unused *global_atom_index)
1311 constexpr int nfa1 = 4;
1312 GMX_ALIGNED(int, GMX_SIMD_REAL_WIDTH) ai[GMX_SIMD_REAL_WIDTH];
1313 GMX_ALIGNED(int, GMX_SIMD_REAL_WIDTH) aj[GMX_SIMD_REAL_WIDTH];
1314 GMX_ALIGNED(int, GMX_SIMD_REAL_WIDTH) ak[GMX_SIMD_REAL_WIDTH];
1315 GMX_ALIGNED(real, GMX_SIMD_REAL_WIDTH) coeff[4*GMX_SIMD_REAL_WIDTH];
1316 GMX_ALIGNED(real, GMX_SIMD_REAL_WIDTH) pbc_simd[9*GMX_SIMD_REAL_WIDTH];
1318 set_pbc_simd(pbc, pbc_simd);
1320 /* nbonds is the number of angles times nfa1, here we step GMX_SIMD_REAL_WIDTH angles */
1321 for (int i = 0; i < nbonds; i += GMX_SIMD_REAL_WIDTH*nfa1)
1323 /* Collect atoms for GMX_SIMD_REAL_WIDTH angles.
1324 * iu indexes into forceatoms, we should not let iu go beyond nbonds.
1326 int iu = i;
1327 for (int s = 0; s < GMX_SIMD_REAL_WIDTH; s++)
1329 const int type = forceatoms[iu];
1330 ai[s] = forceatoms[iu+1];
1331 aj[s] = forceatoms[iu+2];
1332 ak[s] = forceatoms[iu+3];
1334 /* At the end fill the arrays with the last atoms and 0 params */
1335 if (i + s*nfa1 < nbonds)
1337 coeff[s] = forceparams[type].u_b.kthetaA;
1338 coeff[GMX_SIMD_REAL_WIDTH+s] = forceparams[type].u_b.thetaA;
1339 coeff[GMX_SIMD_REAL_WIDTH*2+s] = forceparams[type].u_b.kUBA;
1340 coeff[GMX_SIMD_REAL_WIDTH*3+s] = forceparams[type].u_b.r13A;
1342 if (iu + nfa1 < nbonds)
1344 iu += nfa1;
1347 else
1349 coeff[s] = 0;
1350 coeff[GMX_SIMD_REAL_WIDTH+s] = 0;
1351 coeff[GMX_SIMD_REAL_WIDTH*2+s] = 0;
1352 coeff[GMX_SIMD_REAL_WIDTH*3+s] = 0;
1356 SimdReal xi_S, yi_S, zi_S;
1357 SimdReal xj_S, yj_S, zj_S;
1358 SimdReal xk_S, yk_S, zk_S;
1360 /* Store the non PBC corrected distances packed and aligned */
1361 gatherLoadUTranspose<3>(reinterpret_cast<const real *>(x), ai, &xi_S, &yi_S, &zi_S);
1362 gatherLoadUTranspose<3>(reinterpret_cast<const real *>(x), aj, &xj_S, &yj_S, &zj_S);
1363 gatherLoadUTranspose<3>(reinterpret_cast<const real *>(x), ak, &xk_S, &yk_S, &zk_S);
1364 SimdReal rijx_S = xi_S - xj_S;
1365 SimdReal rijy_S = yi_S - yj_S;
1366 SimdReal rijz_S = zi_S - zj_S;
1367 SimdReal rkjx_S = xk_S - xj_S;
1368 SimdReal rkjy_S = yk_S - yj_S;
1369 SimdReal rkjz_S = zk_S - zj_S;
1370 SimdReal rikx_S = xi_S - xk_S;
1371 SimdReal riky_S = yi_S - yk_S;
1372 SimdReal rikz_S = zi_S - zk_S;
1374 const SimdReal ktheta_S = load<SimdReal>(coeff);
1375 const SimdReal theta0_S = load<SimdReal>(coeff+GMX_SIMD_REAL_WIDTH) * DEG2RAD;
1376 const SimdReal kUB_S = load<SimdReal>(coeff+2*GMX_SIMD_REAL_WIDTH);
1377 const SimdReal r13_S = load<SimdReal>(coeff+3*GMX_SIMD_REAL_WIDTH);
1379 pbc_correct_dx_simd(&rijx_S, &rijy_S, &rijz_S, pbc_simd);
1380 pbc_correct_dx_simd(&rkjx_S, &rkjy_S, &rkjz_S, pbc_simd);
1381 pbc_correct_dx_simd(&rikx_S, &riky_S, &rikz_S, pbc_simd);
1383 const SimdReal rij_rkj_S = iprod(rijx_S, rijy_S, rijz_S,
1384 rkjx_S, rkjy_S, rkjz_S);
1386 const SimdReal dr2_S = iprod(rikx_S, riky_S, rikz_S,
1387 rikx_S, riky_S, rikz_S);
1389 const SimdReal nrij2_S = norm2(rijx_S, rijy_S, rijz_S);
1390 const SimdReal nrkj2_S = norm2(rkjx_S, rkjy_S, rkjz_S);
1392 const SimdReal nrij_1_S = invsqrt(nrij2_S);
1393 const SimdReal nrkj_1_S = invsqrt(nrkj2_S);
1394 const SimdReal invdr2_S = invsqrt(dr2_S);
1395 const SimdReal dr_S = dr2_S*invdr2_S;
1397 constexpr real min_one_plus_eps = -1.0 + 2.0*GMX_REAL_EPS; // Smallest number > -1
1399 /* To allow for 180 degrees, we take the max of cos and -1 + 1bit,
1400 * so we can safely get the 1/sin from 1/sqrt(1 - cos^2).
1401 * This also ensures that rounding errors would cause the argument
1402 * of simdAcos to be < -1.
1403 * Note that we do not take precautions for cos(0)=1, so the bonds
1404 * in an angle should not align at an angle of 0 degrees.
1406 const SimdReal cos_S = max(rij_rkj_S * nrij_1_S * nrkj_1_S, min_one_plus_eps);
1408 const SimdReal theta_S = acos(cos_S);
1409 const SimdReal invsin_S = invsqrt( 1.0 - cos_S * cos_S );
1410 const SimdReal st_S = ktheta_S * (theta0_S - theta_S) * invsin_S;
1411 const SimdReal sth_S = st_S * cos_S;
1413 const SimdReal cik_S = st_S * nrij_1_S * nrkj_1_S;
1414 const SimdReal cii_S = sth_S * nrij_1_S * nrij_1_S;
1415 const SimdReal ckk_S = sth_S * nrkj_1_S * nrkj_1_S;
1417 const SimdReal sUB_S = kUB_S * (r13_S - dr_S) * invdr2_S;
1419 const SimdReal f_ikx_S = sUB_S * rikx_S;
1420 const SimdReal f_iky_S = sUB_S * riky_S;
1421 const SimdReal f_ikz_S = sUB_S * rikz_S;
1423 const SimdReal f_ix_S = fnma(cik_S, rkjx_S, cii_S * rijx_S) + f_ikx_S;
1424 const SimdReal f_iy_S = fnma(cik_S, rkjy_S, cii_S * rijy_S) + f_iky_S;
1425 const SimdReal f_iz_S = fnma(cik_S, rkjz_S, cii_S * rijz_S) + f_ikz_S;
1426 const SimdReal f_kx_S = fnma(cik_S, rijx_S, ckk_S * rkjx_S) - f_ikx_S;
1427 const SimdReal f_ky_S = fnma(cik_S, rijy_S, ckk_S * rkjy_S) - f_iky_S;
1428 const SimdReal f_kz_S = fnma(cik_S, rijz_S, ckk_S * rkjz_S) - f_ikz_S;
1430 transposeScatterIncrU<4>(reinterpret_cast<real *>(f), ai, f_ix_S, f_iy_S, f_iz_S);
1431 transposeScatterDecrU<4>(reinterpret_cast<real *>(f), aj, f_ix_S + f_kx_S, f_iy_S + f_ky_S, f_iz_S + f_kz_S);
1432 transposeScatterIncrU<4>(reinterpret_cast<real *>(f), ak, f_kx_S, f_ky_S, f_kz_S);
1436 #endif // GMX_SIMD_HAVE_REAL
1438 real quartic_angles(int nbonds,
1439 const t_iatom forceatoms[], const t_iparams forceparams[],
1440 const rvec x[], rvec4 f[], rvec fshift[],
1441 const t_pbc *pbc, const t_graph *g,
1442 real gmx_unused lambda, real gmx_unused *dvdlambda,
1443 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
1444 int gmx_unused *global_atom_index)
1446 int i, j, ai, aj, ak, t1, t2, type;
1447 rvec r_ij, r_kj;
1448 real cos_theta, cos_theta2, theta, dt, dVdt, va, dtp, c, vtot;
1449 ivec jt, dt_ij, dt_kj;
1451 vtot = 0.0;
1452 for (i = 0; (i < nbonds); )
1454 type = forceatoms[i++];
1455 ai = forceatoms[i++];
1456 aj = forceatoms[i++];
1457 ak = forceatoms[i++];
1459 theta = bond_angle(x[ai], x[aj], x[ak], pbc,
1460 r_ij, r_kj, &cos_theta, &t1, &t2); /* 41 */
1462 dt = theta - forceparams[type].qangle.theta*DEG2RAD; /* 2 */
1464 dVdt = 0;
1465 va = forceparams[type].qangle.c[0];
1466 dtp = 1.0;
1467 for (j = 1; j <= 4; j++)
1469 c = forceparams[type].qangle.c[j];
1470 dVdt -= j*c*dtp;
1471 dtp *= dt;
1472 va += c*dtp;
1474 /* 20 */
1476 vtot += va;
1478 cos_theta2 = gmx::square(cos_theta); /* 1 */
1479 if (cos_theta2 < 1)
1481 int m;
1482 real st, sth;
1483 real cik, cii, ckk;
1484 real nrkj2, nrij2;
1485 rvec f_i, f_j, f_k;
1487 st = dVdt*gmx::invsqrt(1 - cos_theta2); /* 12 */
1488 sth = st*cos_theta; /* 1 */
1489 #ifdef DEBUG
1490 if (debug)
1492 fprintf(debug, "ANGLES: theta = %10g vth = %10g dV/dtheta = %10g\n",
1493 theta*RAD2DEG, va, dVdt);
1495 #endif
1496 nrkj2 = iprod(r_kj, r_kj); /* 5 */
1497 nrij2 = iprod(r_ij, r_ij);
1499 cik = st*gmx::invsqrt(nrkj2*nrij2); /* 12 */
1500 cii = sth/nrij2; /* 10 */
1501 ckk = sth/nrkj2; /* 10 */
1503 for (m = 0; (m < DIM); m++) /* 39 */
1505 f_i[m] = -(cik*r_kj[m]-cii*r_ij[m]);
1506 f_k[m] = -(cik*r_ij[m]-ckk*r_kj[m]);
1507 f_j[m] = -f_i[m]-f_k[m];
1508 f[ai][m] += f_i[m];
1509 f[aj][m] += f_j[m];
1510 f[ak][m] += f_k[m];
1512 if (g)
1514 copy_ivec(SHIFT_IVEC(g, aj), jt);
1516 ivec_sub(SHIFT_IVEC(g, ai), jt, dt_ij);
1517 ivec_sub(SHIFT_IVEC(g, ak), jt, dt_kj);
1518 t1 = IVEC2IS(dt_ij);
1519 t2 = IVEC2IS(dt_kj);
1521 rvec_inc(fshift[t1], f_i);
1522 rvec_inc(fshift[CENTRAL], f_j);
1523 rvec_inc(fshift[t2], f_k);
1524 } /* 153 TOTAL */
1526 return vtot;
1529 real dih_angle(const rvec xi, const rvec xj, const rvec xk, const rvec xl,
1530 const t_pbc *pbc,
1531 rvec r_ij, rvec r_kj, rvec r_kl, rvec m, rvec n,
1532 int *t1, int *t2, int *t3)
1534 *t1 = pbc_rvec_sub(pbc, xi, xj, r_ij); /* 3 */
1535 *t2 = pbc_rvec_sub(pbc, xk, xj, r_kj); /* 3 */
1536 *t3 = pbc_rvec_sub(pbc, xk, xl, r_kl); /* 3 */
1538 cprod(r_ij, r_kj, m); /* 9 */
1539 cprod(r_kj, r_kl, n); /* 9 */
1540 real phi = gmx_angle(m, n); /* 49 (assuming 25 for atan2) */
1541 real ipr = iprod(r_ij, n); /* 5 */
1542 real sign = (ipr < 0.0) ? -1.0 : 1.0;
1543 phi = sign*phi; /* 1 */
1544 /* 82 TOTAL */
1545 return phi;
1549 #if GMX_SIMD_HAVE_REAL
1551 /* As dih_angle above, but calculates 4 dihedral angles at once using SIMD,
1552 * also calculates the pre-factor required for the dihedral force update.
1553 * Note that bv and buf should be register aligned.
1555 static gmx_inline void
1556 dih_angle_simd(const rvec *x,
1557 const int *ai, const int *aj, const int *ak, const int *al,
1558 const real *pbc_simd,
1559 SimdReal *phi_S,
1560 SimdReal *mx_S, SimdReal *my_S, SimdReal *mz_S,
1561 SimdReal *nx_S, SimdReal *ny_S, SimdReal *nz_S,
1562 SimdReal *nrkj_m2_S,
1563 SimdReal *nrkj_n2_S,
1564 SimdReal *p_S,
1565 SimdReal *q_S)
1567 SimdReal xi_S, yi_S, zi_S;
1568 SimdReal xj_S, yj_S, zj_S;
1569 SimdReal xk_S, yk_S, zk_S;
1570 SimdReal xl_S, yl_S, zl_S;
1571 SimdReal rijx_S, rijy_S, rijz_S;
1572 SimdReal rkjx_S, rkjy_S, rkjz_S;
1573 SimdReal rklx_S, rkly_S, rklz_S;
1574 SimdReal cx_S, cy_S, cz_S;
1575 SimdReal cn_S;
1576 SimdReal s_S;
1577 SimdReal ipr_S;
1578 SimdReal iprm_S, iprn_S;
1579 SimdReal nrkj2_S, nrkj_1_S, nrkj_2_S, nrkj_S;
1580 SimdReal toler_S;
1581 SimdReal nrkj2_min_S;
1582 SimdReal real_eps_S;
1584 /* Used to avoid division by zero.
1585 * We take into acount that we multiply the result by real_eps_S.
1587 nrkj2_min_S = SimdReal(GMX_REAL_MIN/(2*GMX_REAL_EPS));
1589 /* The value of the last significant bit (GMX_REAL_EPS is half of that) */
1590 real_eps_S = SimdReal(2*GMX_REAL_EPS);
1592 /* Store the non PBC corrected distances packed and aligned */
1593 gatherLoadUTranspose<3>(reinterpret_cast<const real *>(x), ai, &xi_S, &yi_S, &zi_S);
1594 gatherLoadUTranspose<3>(reinterpret_cast<const real *>(x), aj, &xj_S, &yj_S, &zj_S);
1595 gatherLoadUTranspose<3>(reinterpret_cast<const real *>(x), ak, &xk_S, &yk_S, &zk_S);
1596 gatherLoadUTranspose<3>(reinterpret_cast<const real *>(x), al, &xl_S, &yl_S, &zl_S);
1597 rijx_S = xi_S - xj_S;
1598 rijy_S = yi_S - yj_S;
1599 rijz_S = zi_S - zj_S;
1600 rkjx_S = xk_S - xj_S;
1601 rkjy_S = yk_S - yj_S;
1602 rkjz_S = zk_S - zj_S;
1603 rklx_S = xk_S - xl_S;
1604 rkly_S = yk_S - yl_S;
1605 rklz_S = zk_S - zl_S;
1607 pbc_correct_dx_simd(&rijx_S, &rijy_S, &rijz_S, pbc_simd);
1608 pbc_correct_dx_simd(&rkjx_S, &rkjy_S, &rkjz_S, pbc_simd);
1609 pbc_correct_dx_simd(&rklx_S, &rkly_S, &rklz_S, pbc_simd);
1611 cprod(rijx_S, rijy_S, rijz_S,
1612 rkjx_S, rkjy_S, rkjz_S,
1613 mx_S, my_S, mz_S);
1615 cprod(rkjx_S, rkjy_S, rkjz_S,
1616 rklx_S, rkly_S, rklz_S,
1617 nx_S, ny_S, nz_S);
1619 cprod(*mx_S, *my_S, *mz_S,
1620 *nx_S, *ny_S, *nz_S,
1621 &cx_S, &cy_S, &cz_S);
1623 cn_S = sqrt(norm2(cx_S, cy_S, cz_S));
1625 s_S = iprod(*mx_S, *my_S, *mz_S, *nx_S, *ny_S, *nz_S);
1627 /* Determine the dihedral angle, the sign might need correction */
1628 *phi_S = atan2(cn_S, s_S);
1630 ipr_S = iprod(rijx_S, rijy_S, rijz_S,
1631 *nx_S, *ny_S, *nz_S);
1633 iprm_S = norm2(*mx_S, *my_S, *mz_S);
1634 iprn_S = norm2(*nx_S, *ny_S, *nz_S);
1636 nrkj2_S = norm2(rkjx_S, rkjy_S, rkjz_S);
1638 /* Avoid division by zero. When zero, the result is multiplied by 0
1639 * anyhow, so the 3 max below do not affect the final result.
1641 nrkj2_S = max(nrkj2_S, nrkj2_min_S);
1642 nrkj_1_S = invsqrt(nrkj2_S);
1643 nrkj_2_S = nrkj_1_S * nrkj_1_S;
1644 nrkj_S = nrkj2_S * nrkj_1_S;
1646 toler_S = nrkj2_S * real_eps_S;
1648 /* Here the plain-C code uses a conditional, but we can't do that in SIMD.
1649 * So we take a max with the tolerance instead. Since we multiply with
1650 * m or n later, the max does not affect the results.
1652 iprm_S = max(iprm_S, toler_S);
1653 iprn_S = max(iprn_S, toler_S);
1654 *nrkj_m2_S = nrkj_S * inv(iprm_S);
1655 *nrkj_n2_S = nrkj_S * inv(iprn_S);
1657 /* Set sign of phi_S with the sign of ipr_S; phi_S is currently positive */
1658 *phi_S = copysign(*phi_S, ipr_S);
1659 *p_S = iprod(rijx_S, rijy_S, rijz_S, rkjx_S, rkjy_S, rkjz_S);
1660 *p_S = *p_S * nrkj_2_S;
1662 *q_S = iprod(rklx_S, rkly_S, rklz_S, rkjx_S, rkjy_S, rkjz_S);
1663 *q_S = *q_S * nrkj_2_S;
1666 #endif // GMX_SIMD_HAVE_REAL
1668 void do_dih_fup(int i, int j, int k, int l, real ddphi,
1669 rvec r_ij, rvec r_kj, rvec r_kl,
1670 rvec m, rvec n, rvec4 f[], rvec fshift[],
1671 const t_pbc *pbc, const t_graph *g,
1672 const rvec x[], int t1, int t2, int t3)
1674 /* 143 FLOPS */
1675 rvec f_i, f_j, f_k, f_l;
1676 rvec uvec, vvec, svec, dx_jl;
1677 real iprm, iprn, nrkj, nrkj2, nrkj_1, nrkj_2;
1678 real a, b, p, q, toler;
1679 ivec jt, dt_ij, dt_kj, dt_lj;
1681 iprm = iprod(m, m); /* 5 */
1682 iprn = iprod(n, n); /* 5 */
1683 nrkj2 = iprod(r_kj, r_kj); /* 5 */
1684 toler = nrkj2*GMX_REAL_EPS;
1685 if ((iprm > toler) && (iprn > toler))
1687 nrkj_1 = gmx::invsqrt(nrkj2); /* 10 */
1688 nrkj_2 = nrkj_1*nrkj_1; /* 1 */
1689 nrkj = nrkj2*nrkj_1; /* 1 */
1690 a = -ddphi*nrkj/iprm; /* 11 */
1691 svmul(a, m, f_i); /* 3 */
1692 b = ddphi*nrkj/iprn; /* 11 */
1693 svmul(b, n, f_l); /* 3 */
1694 p = iprod(r_ij, r_kj); /* 5 */
1695 p *= nrkj_2; /* 1 */
1696 q = iprod(r_kl, r_kj); /* 5 */
1697 q *= nrkj_2; /* 1 */
1698 svmul(p, f_i, uvec); /* 3 */
1699 svmul(q, f_l, vvec); /* 3 */
1700 rvec_sub(uvec, vvec, svec); /* 3 */
1701 rvec_sub(f_i, svec, f_j); /* 3 */
1702 rvec_add(f_l, svec, f_k); /* 3 */
1703 rvec_inc(f[i], f_i); /* 3 */
1704 rvec_dec(f[j], f_j); /* 3 */
1705 rvec_dec(f[k], f_k); /* 3 */
1706 rvec_inc(f[l], f_l); /* 3 */
1708 if (g)
1710 copy_ivec(SHIFT_IVEC(g, j), jt);
1711 ivec_sub(SHIFT_IVEC(g, i), jt, dt_ij);
1712 ivec_sub(SHIFT_IVEC(g, k), jt, dt_kj);
1713 ivec_sub(SHIFT_IVEC(g, l), jt, dt_lj);
1714 t1 = IVEC2IS(dt_ij);
1715 t2 = IVEC2IS(dt_kj);
1716 t3 = IVEC2IS(dt_lj);
1718 else if (pbc)
1720 t3 = pbc_rvec_sub(pbc, x[l], x[j], dx_jl);
1722 else
1724 t3 = CENTRAL;
1727 rvec_inc(fshift[t1], f_i);
1728 rvec_dec(fshift[CENTRAL], f_j);
1729 rvec_dec(fshift[t2], f_k);
1730 rvec_inc(fshift[t3], f_l);
1732 /* 112 TOTAL */
1735 /* As do_dih_fup above, but without shift forces */
1736 static void
1737 do_dih_fup_noshiftf(int i, int j, int k, int l, real ddphi,
1738 rvec r_ij, rvec r_kj, rvec r_kl,
1739 rvec m, rvec n, rvec4 f[])
1741 rvec f_i, f_j, f_k, f_l;
1742 rvec uvec, vvec, svec;
1743 real iprm, iprn, nrkj, nrkj2, nrkj_1, nrkj_2;
1744 real a, b, p, q, toler;
1746 iprm = iprod(m, m); /* 5 */
1747 iprn = iprod(n, n); /* 5 */
1748 nrkj2 = iprod(r_kj, r_kj); /* 5 */
1749 toler = nrkj2*GMX_REAL_EPS;
1750 if ((iprm > toler) && (iprn > toler))
1752 nrkj_1 = gmx::invsqrt(nrkj2); /* 10 */
1753 nrkj_2 = nrkj_1*nrkj_1; /* 1 */
1754 nrkj = nrkj2*nrkj_1; /* 1 */
1755 a = -ddphi*nrkj/iprm; /* 11 */
1756 svmul(a, m, f_i); /* 3 */
1757 b = ddphi*nrkj/iprn; /* 11 */
1758 svmul(b, n, f_l); /* 3 */
1759 p = iprod(r_ij, r_kj); /* 5 */
1760 p *= nrkj_2; /* 1 */
1761 q = iprod(r_kl, r_kj); /* 5 */
1762 q *= nrkj_2; /* 1 */
1763 svmul(p, f_i, uvec); /* 3 */
1764 svmul(q, f_l, vvec); /* 3 */
1765 rvec_sub(uvec, vvec, svec); /* 3 */
1766 rvec_sub(f_i, svec, f_j); /* 3 */
1767 rvec_add(f_l, svec, f_k); /* 3 */
1768 rvec_inc(f[i], f_i); /* 3 */
1769 rvec_dec(f[j], f_j); /* 3 */
1770 rvec_dec(f[k], f_k); /* 3 */
1771 rvec_inc(f[l], f_l); /* 3 */
1775 #if GMX_SIMD_HAVE_REAL
1776 /* As do_dih_fup_noshiftf above, but with SIMD and pre-calculated pre-factors */
1777 static gmx_inline void gmx_simdcall
1778 do_dih_fup_noshiftf_simd(const int *ai, const int *aj, const int *ak, const int *al,
1779 SimdReal p, SimdReal q,
1780 SimdReal f_i_x, SimdReal f_i_y, SimdReal f_i_z,
1781 SimdReal mf_l_x, SimdReal mf_l_y, SimdReal mf_l_z,
1782 rvec4 f[])
1784 SimdReal sx = p * f_i_x + q * mf_l_x;
1785 SimdReal sy = p * f_i_y + q * mf_l_y;
1786 SimdReal sz = p * f_i_z + q * mf_l_z;
1787 SimdReal f_j_x = f_i_x - sx;
1788 SimdReal f_j_y = f_i_y - sy;
1789 SimdReal f_j_z = f_i_z - sz;
1790 SimdReal f_k_x = mf_l_x - sx;
1791 SimdReal f_k_y = mf_l_y - sy;
1792 SimdReal f_k_z = mf_l_z - sz;
1793 transposeScatterIncrU<4>(reinterpret_cast<real *>(f), ai, f_i_x, f_i_y, f_i_z);
1794 transposeScatterDecrU<4>(reinterpret_cast<real *>(f), aj, f_j_x, f_j_y, f_j_z);
1795 transposeScatterIncrU<4>(reinterpret_cast<real *>(f), ak, f_k_x, f_k_y, f_k_z);
1796 transposeScatterDecrU<4>(reinterpret_cast<real *>(f), al, mf_l_x, mf_l_y, mf_l_z);
1798 #endif // GMX_SIMD_HAVE_REAL
1800 static real dopdihs(real cpA, real cpB, real phiA, real phiB, int mult,
1801 real phi, real lambda, real *V, real *F)
1803 real v, dvdlambda, mdphi, v1, sdphi, ddphi;
1804 real L1 = 1.0 - lambda;
1805 real ph0 = (L1*phiA + lambda*phiB)*DEG2RAD;
1806 real dph0 = (phiB - phiA)*DEG2RAD;
1807 real cp = L1*cpA + lambda*cpB;
1809 mdphi = mult*phi - ph0;
1810 sdphi = std::sin(mdphi);
1811 ddphi = -cp*mult*sdphi;
1812 v1 = 1.0 + std::cos(mdphi);
1813 v = cp*v1;
1815 dvdlambda = (cpB - cpA)*v1 + cp*dph0*sdphi;
1817 *V = v;
1818 *F = ddphi;
1820 return dvdlambda;
1822 /* That was 40 flops */
1825 static void
1826 dopdihs_noener(real cpA, real cpB, real phiA, real phiB, int mult,
1827 real phi, real lambda, real *F)
1829 real mdphi, sdphi, ddphi;
1830 real L1 = 1.0 - lambda;
1831 real ph0 = (L1*phiA + lambda*phiB)*DEG2RAD;
1832 real cp = L1*cpA + lambda*cpB;
1834 mdphi = mult*phi - ph0;
1835 sdphi = std::sin(mdphi);
1836 ddphi = -cp*mult*sdphi;
1838 *F = ddphi;
1840 /* That was 20 flops */
1843 static real dopdihs_min(real cpA, real cpB, real phiA, real phiB, int mult,
1844 real phi, real lambda, real *V, real *F)
1845 /* similar to dopdihs, except for a minus sign *
1846 * and a different treatment of mult/phi0 */
1848 real v, dvdlambda, mdphi, v1, sdphi, ddphi;
1849 real L1 = 1.0 - lambda;
1850 real ph0 = (L1*phiA + lambda*phiB)*DEG2RAD;
1851 real dph0 = (phiB - phiA)*DEG2RAD;
1852 real cp = L1*cpA + lambda*cpB;
1854 mdphi = mult*(phi-ph0);
1855 sdphi = std::sin(mdphi);
1856 ddphi = cp*mult*sdphi;
1857 v1 = 1.0-std::cos(mdphi);
1858 v = cp*v1;
1860 dvdlambda = (cpB-cpA)*v1 + cp*dph0*sdphi;
1862 *V = v;
1863 *F = ddphi;
1865 return dvdlambda;
1867 /* That was 40 flops */
1870 real pdihs(int nbonds,
1871 const t_iatom forceatoms[], const t_iparams forceparams[],
1872 const rvec x[], rvec4 f[], rvec fshift[],
1873 const t_pbc *pbc, const t_graph *g,
1874 real lambda, real *dvdlambda,
1875 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
1876 int gmx_unused *global_atom_index)
1878 int i, type, ai, aj, ak, al;
1879 int t1, t2, t3;
1880 rvec r_ij, r_kj, r_kl, m, n;
1881 real phi, ddphi, vpd, vtot;
1883 vtot = 0.0;
1885 for (i = 0; (i < nbonds); )
1887 type = forceatoms[i++];
1888 ai = forceatoms[i++];
1889 aj = forceatoms[i++];
1890 ak = forceatoms[i++];
1891 al = forceatoms[i++];
1893 phi = dih_angle(x[ai], x[aj], x[ak], x[al], pbc, r_ij, r_kj, r_kl, m, n,
1894 &t1, &t2, &t3); /* 84 */
1895 *dvdlambda += dopdihs(forceparams[type].pdihs.cpA,
1896 forceparams[type].pdihs.cpB,
1897 forceparams[type].pdihs.phiA,
1898 forceparams[type].pdihs.phiB,
1899 forceparams[type].pdihs.mult,
1900 phi, lambda, &vpd, &ddphi);
1902 vtot += vpd;
1903 do_dih_fup(ai, aj, ak, al, ddphi, r_ij, r_kj, r_kl, m, n,
1904 f, fshift, pbc, g, x, t1, t2, t3); /* 112 */
1906 #ifdef DEBUG
1907 fprintf(debug, "pdih: (%d,%d,%d,%d) phi=%g\n",
1908 ai, aj, ak, al, phi);
1909 #endif
1910 } /* 223 TOTAL */
1912 return vtot;
1915 void make_dp_periodic(real *dp) /* 1 flop? */
1917 /* dp cannot be outside (-pi,pi) */
1918 if (*dp >= M_PI)
1920 *dp -= 2*M_PI;
1922 else if (*dp < -M_PI)
1924 *dp += 2*M_PI;
1926 return;
1929 /* As pdihs above, but without calculating energies and shift forces */
1930 void
1931 pdihs_noener(int nbonds,
1932 const t_iatom forceatoms[], const t_iparams forceparams[],
1933 const rvec x[], rvec4 f[],
1934 const t_pbc gmx_unused *pbc, const t_graph gmx_unused *g,
1935 real lambda,
1936 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
1937 int gmx_unused *global_atom_index)
1939 int i, type, ai, aj, ak, al;
1940 int t1, t2, t3;
1941 rvec r_ij, r_kj, r_kl, m, n;
1942 real phi, ddphi_tot, ddphi;
1944 for (i = 0; (i < nbonds); )
1946 ai = forceatoms[i+1];
1947 aj = forceatoms[i+2];
1948 ak = forceatoms[i+3];
1949 al = forceatoms[i+4];
1951 phi = dih_angle(x[ai], x[aj], x[ak], x[al], pbc, r_ij, r_kj, r_kl, m, n,
1952 &t1, &t2, &t3);
1954 ddphi_tot = 0;
1956 /* Loop over dihedrals working on the same atoms,
1957 * so we avoid recalculating angles and force distributions.
1961 type = forceatoms[i];
1962 dopdihs_noener(forceparams[type].pdihs.cpA,
1963 forceparams[type].pdihs.cpB,
1964 forceparams[type].pdihs.phiA,
1965 forceparams[type].pdihs.phiB,
1966 forceparams[type].pdihs.mult,
1967 phi, lambda, &ddphi);
1968 ddphi_tot += ddphi;
1970 i += 5;
1972 while (i < nbonds &&
1973 forceatoms[i+1] == ai &&
1974 forceatoms[i+2] == aj &&
1975 forceatoms[i+3] == ak &&
1976 forceatoms[i+4] == al);
1978 do_dih_fup_noshiftf(ai, aj, ak, al, ddphi_tot, r_ij, r_kj, r_kl, m, n, f);
1983 #if GMX_SIMD_HAVE_REAL
1985 /* As pdihs_noner above, but using SIMD to calculate many dihedrals at once */
1986 void
1987 pdihs_noener_simd(int nbonds,
1988 const t_iatom forceatoms[], const t_iparams forceparams[],
1989 const rvec x[], rvec4 f[],
1990 const t_pbc *pbc, const t_graph gmx_unused *g,
1991 real gmx_unused lambda,
1992 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
1993 int gmx_unused *global_atom_index)
1995 const int nfa1 = 5;
1996 int i, iu, s;
1997 int type;
1998 GMX_ALIGNED(int, GMX_SIMD_REAL_WIDTH) ai[GMX_SIMD_REAL_WIDTH];
1999 GMX_ALIGNED(int, GMX_SIMD_REAL_WIDTH) aj[GMX_SIMD_REAL_WIDTH];
2000 GMX_ALIGNED(int, GMX_SIMD_REAL_WIDTH) ak[GMX_SIMD_REAL_WIDTH];
2001 GMX_ALIGNED(int, GMX_SIMD_REAL_WIDTH) al[GMX_SIMD_REAL_WIDTH];
2002 GMX_ALIGNED(real, GMX_SIMD_REAL_WIDTH) buf[3*GMX_SIMD_REAL_WIDTH];
2003 real *cp, *phi0, *mult;
2004 SimdReal deg2rad_S(DEG2RAD);
2005 SimdReal p_S, q_S;
2006 SimdReal phi0_S, phi_S;
2007 SimdReal mx_S, my_S, mz_S;
2008 SimdReal nx_S, ny_S, nz_S;
2009 SimdReal nrkj_m2_S, nrkj_n2_S;
2010 SimdReal cp_S, mdphi_S, mult_S;
2011 SimdReal sin_S, cos_S;
2012 SimdReal mddphi_S;
2013 SimdReal sf_i_S, msf_l_S;
2014 GMX_ALIGNED(real, GMX_SIMD_REAL_WIDTH) pbc_simd[9*GMX_SIMD_REAL_WIDTH];
2016 /* Extract aligned pointer for parameters and variables */
2017 cp = buf + 0*GMX_SIMD_REAL_WIDTH;
2018 phi0 = buf + 1*GMX_SIMD_REAL_WIDTH;
2019 mult = buf + 2*GMX_SIMD_REAL_WIDTH;
2021 set_pbc_simd(pbc, pbc_simd);
2023 /* nbonds is the number of dihedrals times nfa1, here we step GMX_SIMD_REAL_WIDTH dihs */
2024 for (i = 0; (i < nbonds); i += GMX_SIMD_REAL_WIDTH*nfa1)
2026 /* Collect atoms quadruplets for GMX_SIMD_REAL_WIDTH dihedrals.
2027 * iu indexes into forceatoms, we should not let iu go beyond nbonds.
2029 iu = i;
2030 for (s = 0; s < GMX_SIMD_REAL_WIDTH; s++)
2032 type = forceatoms[iu];
2033 ai[s] = forceatoms[iu+1];
2034 aj[s] = forceatoms[iu+2];
2035 ak[s] = forceatoms[iu+3];
2036 al[s] = forceatoms[iu+4];
2038 /* At the end fill the arrays with the last atoms and 0 params */
2039 if (i + s*nfa1 < nbonds)
2041 cp[s] = forceparams[type].pdihs.cpA;
2042 phi0[s] = forceparams[type].pdihs.phiA;
2043 mult[s] = forceparams[type].pdihs.mult;
2045 if (iu + nfa1 < nbonds)
2047 iu += nfa1;
2050 else
2052 cp[s] = 0;
2053 phi0[s] = 0;
2054 mult[s] = 0;
2058 /* Caclulate GMX_SIMD_REAL_WIDTH dihedral angles at once */
2059 dih_angle_simd(x, ai, aj, ak, al, pbc_simd,
2060 &phi_S,
2061 &mx_S, &my_S, &mz_S,
2062 &nx_S, &ny_S, &nz_S,
2063 &nrkj_m2_S,
2064 &nrkj_n2_S,
2065 &p_S, &q_S);
2067 cp_S = load<SimdReal>(cp);
2068 phi0_S = load<SimdReal>(phi0) * deg2rad_S;
2069 mult_S = load<SimdReal>(mult);
2071 mdphi_S = fms(mult_S, phi_S, phi0_S);
2073 /* Calculate GMX_SIMD_REAL_WIDTH sines at once */
2074 sincos(mdphi_S, &sin_S, &cos_S);
2075 mddphi_S = cp_S * mult_S * sin_S;
2076 sf_i_S = mddphi_S * nrkj_m2_S;
2077 msf_l_S = mddphi_S * nrkj_n2_S;
2079 /* After this m?_S will contain f[i] */
2080 mx_S = sf_i_S * mx_S;
2081 my_S = sf_i_S * my_S;
2082 mz_S = sf_i_S * mz_S;
2084 /* After this m?_S will contain -f[l] */
2085 nx_S = msf_l_S * nx_S;
2086 ny_S = msf_l_S * ny_S;
2087 nz_S = msf_l_S * nz_S;
2089 do_dih_fup_noshiftf_simd(ai, aj, ak, al,
2090 p_S, q_S,
2091 mx_S, my_S, mz_S,
2092 nx_S, ny_S, nz_S,
2097 /* This is mostly a copy of pdihs_noener_simd above, but with using
2098 * the RB potential instead of a harmonic potential.
2099 * This function can replace rbdihs() when no energy and virial are needed.
2101 void
2102 rbdihs_noener_simd(int nbonds,
2103 const t_iatom forceatoms[], const t_iparams forceparams[],
2104 const rvec x[], rvec4 f[],
2105 const t_pbc *pbc, const t_graph gmx_unused *g,
2106 real gmx_unused lambda,
2107 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
2108 int gmx_unused *global_atom_index)
2110 const int nfa1 = 5;
2111 int i, iu, s, j;
2112 int type;
2113 GMX_ALIGNED(int, GMX_SIMD_REAL_WIDTH) ai[GMX_SIMD_REAL_WIDTH];
2114 GMX_ALIGNED(int, GMX_SIMD_REAL_WIDTH) aj[GMX_SIMD_REAL_WIDTH];
2115 GMX_ALIGNED(int, GMX_SIMD_REAL_WIDTH) ak[GMX_SIMD_REAL_WIDTH];
2116 GMX_ALIGNED(int, GMX_SIMD_REAL_WIDTH) al[GMX_SIMD_REAL_WIDTH];
2117 GMX_ALIGNED(real, GMX_SIMD_REAL_WIDTH) parm[NR_RBDIHS*GMX_SIMD_REAL_WIDTH];
2119 SimdReal p_S, q_S;
2120 SimdReal phi_S;
2121 SimdReal ddphi_S, cosfac_S;
2122 SimdReal mx_S, my_S, mz_S;
2123 SimdReal nx_S, ny_S, nz_S;
2124 SimdReal nrkj_m2_S, nrkj_n2_S;
2125 SimdReal parm_S, c_S;
2126 SimdReal sin_S, cos_S;
2127 SimdReal sf_i_S, msf_l_S;
2128 GMX_ALIGNED(real, GMX_SIMD_REAL_WIDTH) pbc_simd[9*GMX_SIMD_REAL_WIDTH];
2130 SimdReal pi_S(M_PI);
2131 SimdReal one_S(1.0);
2133 set_pbc_simd(pbc, pbc_simd);
2135 /* nbonds is the number of dihedrals times nfa1, here we step GMX_SIMD_REAL_WIDTH dihs */
2136 for (i = 0; (i < nbonds); i += GMX_SIMD_REAL_WIDTH*nfa1)
2138 /* Collect atoms quadruplets for GMX_SIMD_REAL_WIDTH dihedrals.
2139 * iu indexes into forceatoms, we should not let iu go beyond nbonds.
2141 iu = i;
2142 for (s = 0; s < GMX_SIMD_REAL_WIDTH; s++)
2144 type = forceatoms[iu];
2145 ai[s] = forceatoms[iu+1];
2146 aj[s] = forceatoms[iu+2];
2147 ak[s] = forceatoms[iu+3];
2148 al[s] = forceatoms[iu+4];
2150 /* At the end fill the arrays with the last atoms and 0 params */
2151 if (i + s*nfa1 < nbonds)
2153 /* We don't need the first parameter, since that's a constant
2154 * which only affects the energies, not the forces.
2156 for (j = 1; j < NR_RBDIHS; j++)
2158 parm[j*GMX_SIMD_REAL_WIDTH + s] =
2159 forceparams[type].rbdihs.rbcA[j];
2162 if (iu + nfa1 < nbonds)
2164 iu += nfa1;
2167 else
2169 for (j = 1; j < NR_RBDIHS; j++)
2171 parm[j*GMX_SIMD_REAL_WIDTH + s] = 0;
2176 /* Caclulate GMX_SIMD_REAL_WIDTH dihedral angles at once */
2177 dih_angle_simd(x, ai, aj, ak, al, pbc_simd,
2178 &phi_S,
2179 &mx_S, &my_S, &mz_S,
2180 &nx_S, &ny_S, &nz_S,
2181 &nrkj_m2_S,
2182 &nrkj_n2_S,
2183 &p_S, &q_S);
2185 /* Change to polymer convention */
2186 phi_S = phi_S - pi_S;
2188 sincos(phi_S, &sin_S, &cos_S);
2190 ddphi_S = setZero();
2191 c_S = one_S;
2192 cosfac_S = one_S;
2193 for (j = 1; j < NR_RBDIHS; j++)
2195 parm_S = load<SimdReal>(parm + j*GMX_SIMD_REAL_WIDTH);
2196 ddphi_S = fma(c_S * parm_S, cosfac_S, ddphi_S);
2197 cosfac_S = cosfac_S * cos_S;
2198 c_S = c_S + one_S;
2201 /* Note that here we do not use the minus sign which is present
2202 * in the normal RB code. This is corrected for through (m)sf below.
2204 ddphi_S = ddphi_S * sin_S;
2206 sf_i_S = ddphi_S * nrkj_m2_S;
2207 msf_l_S = ddphi_S * nrkj_n2_S;
2209 /* After this m?_S will contain f[i] */
2210 mx_S = sf_i_S * mx_S;
2211 my_S = sf_i_S * my_S;
2212 mz_S = sf_i_S * mz_S;
2214 /* After this m?_S will contain -f[l] */
2215 nx_S = msf_l_S * nx_S;
2216 ny_S = msf_l_S * ny_S;
2217 nz_S = msf_l_S * nz_S;
2219 do_dih_fup_noshiftf_simd(ai, aj, ak, al,
2220 p_S, q_S,
2221 mx_S, my_S, mz_S,
2222 nx_S, ny_S, nz_S,
2227 #endif // GMX_SIMD_HAVE_REAL
2230 real idihs(int nbonds,
2231 const t_iatom forceatoms[], const t_iparams forceparams[],
2232 const rvec x[], rvec4 f[], rvec fshift[],
2233 const t_pbc *pbc, const t_graph *g,
2234 real lambda, real *dvdlambda,
2235 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
2236 int gmx_unused *global_atom_index)
2238 int i, type, ai, aj, ak, al;
2239 int t1, t2, t3;
2240 real phi, phi0, dphi0, ddphi, vtot;
2241 rvec r_ij, r_kj, r_kl, m, n;
2242 real L1, kk, dp, dp2, kA, kB, pA, pB, dvdl_term;
2244 L1 = 1.0-lambda;
2245 dvdl_term = 0;
2246 vtot = 0.0;
2247 for (i = 0; (i < nbonds); )
2249 type = forceatoms[i++];
2250 ai = forceatoms[i++];
2251 aj = forceatoms[i++];
2252 ak = forceatoms[i++];
2253 al = forceatoms[i++];
2255 phi = dih_angle(x[ai], x[aj], x[ak], x[al], pbc, r_ij, r_kj, r_kl, m, n,
2256 &t1, &t2, &t3); /* 84 */
2258 /* phi can jump if phi0 is close to Pi/-Pi, which will cause huge
2259 * force changes if we just apply a normal harmonic.
2260 * Instead, we first calculate phi-phi0 and take it modulo (-Pi,Pi).
2261 * This means we will never have the periodicity problem, unless
2262 * the dihedral is Pi away from phiO, which is very unlikely due to
2263 * the potential.
2265 kA = forceparams[type].harmonic.krA;
2266 kB = forceparams[type].harmonic.krB;
2267 pA = forceparams[type].harmonic.rA;
2268 pB = forceparams[type].harmonic.rB;
2270 kk = L1*kA + lambda*kB;
2271 phi0 = (L1*pA + lambda*pB)*DEG2RAD;
2272 dphi0 = (pB - pA)*DEG2RAD;
2274 dp = phi-phi0;
2276 make_dp_periodic(&dp);
2278 dp2 = dp*dp;
2280 vtot += 0.5*kk*dp2;
2281 ddphi = -kk*dp;
2283 dvdl_term += 0.5*(kB - kA)*dp2 - kk*dphi0*dp;
2285 do_dih_fup(ai, aj, ak, al, -ddphi, r_ij, r_kj, r_kl, m, n,
2286 f, fshift, pbc, g, x, t1, t2, t3); /* 112 */
2287 /* 218 TOTAL */
2288 #ifdef DEBUG
2289 if (debug)
2291 fprintf(debug, "idih: (%d,%d,%d,%d) phi=%g\n",
2292 ai, aj, ak, al, phi);
2294 #endif
2297 *dvdlambda += dvdl_term;
2298 return vtot;
2301 static real low_angres(int nbonds,
2302 const t_iatom forceatoms[], const t_iparams forceparams[],
2303 const rvec x[], rvec4 f[], rvec fshift[],
2304 const t_pbc *pbc, const t_graph *g,
2305 real lambda, real *dvdlambda,
2306 gmx_bool bZAxis)
2308 int i, m, type, ai, aj, ak, al;
2309 int t1, t2;
2310 real phi, cos_phi, cos_phi2, vid, vtot, dVdphi;
2311 rvec r_ij, r_kl, f_i, f_k = {0, 0, 0};
2312 real st, sth, nrij2, nrkl2, c, cij, ckl;
2314 ivec dt;
2315 t2 = 0; /* avoid warning with gcc-3.3. It is never used uninitialized */
2317 vtot = 0.0;
2318 ak = al = 0; /* to avoid warnings */
2319 for (i = 0; i < nbonds; )
2321 type = forceatoms[i++];
2322 ai = forceatoms[i++];
2323 aj = forceatoms[i++];
2324 t1 = pbc_rvec_sub(pbc, x[aj], x[ai], r_ij); /* 3 */
2325 if (!bZAxis)
2327 ak = forceatoms[i++];
2328 al = forceatoms[i++];
2329 t2 = pbc_rvec_sub(pbc, x[al], x[ak], r_kl); /* 3 */
2331 else
2333 r_kl[XX] = 0;
2334 r_kl[YY] = 0;
2335 r_kl[ZZ] = 1;
2338 cos_phi = cos_angle(r_ij, r_kl); /* 25 */
2339 phi = std::acos(cos_phi); /* 10 */
2341 *dvdlambda += dopdihs_min(forceparams[type].pdihs.cpA,
2342 forceparams[type].pdihs.cpB,
2343 forceparams[type].pdihs.phiA,
2344 forceparams[type].pdihs.phiB,
2345 forceparams[type].pdihs.mult,
2346 phi, lambda, &vid, &dVdphi); /* 40 */
2348 vtot += vid;
2350 cos_phi2 = gmx::square(cos_phi); /* 1 */
2351 if (cos_phi2 < 1)
2353 st = -dVdphi*gmx::invsqrt(1 - cos_phi2); /* 12 */
2354 sth = st*cos_phi; /* 1 */
2355 nrij2 = iprod(r_ij, r_ij); /* 5 */
2356 nrkl2 = iprod(r_kl, r_kl); /* 5 */
2358 c = st*gmx::invsqrt(nrij2*nrkl2); /* 11 */
2359 cij = sth/nrij2; /* 10 */
2360 ckl = sth/nrkl2; /* 10 */
2362 for (m = 0; m < DIM; m++) /* 18+18 */
2364 f_i[m] = (c*r_kl[m]-cij*r_ij[m]);
2365 f[ai][m] += f_i[m];
2366 f[aj][m] -= f_i[m];
2367 if (!bZAxis)
2369 f_k[m] = (c*r_ij[m]-ckl*r_kl[m]);
2370 f[ak][m] += f_k[m];
2371 f[al][m] -= f_k[m];
2375 if (g)
2377 ivec_sub(SHIFT_IVEC(g, ai), SHIFT_IVEC(g, aj), dt);
2378 t1 = IVEC2IS(dt);
2380 rvec_inc(fshift[t1], f_i);
2381 rvec_dec(fshift[CENTRAL], f_i);
2382 if (!bZAxis)
2384 if (g)
2386 ivec_sub(SHIFT_IVEC(g, ak), SHIFT_IVEC(g, al), dt);
2387 t2 = IVEC2IS(dt);
2389 rvec_inc(fshift[t2], f_k);
2390 rvec_dec(fshift[CENTRAL], f_k);
2395 return vtot; /* 184 / 157 (bZAxis) total */
2398 real angres(int nbonds,
2399 const t_iatom forceatoms[], const t_iparams forceparams[],
2400 const rvec x[], rvec4 f[], rvec fshift[],
2401 const t_pbc *pbc, const t_graph *g,
2402 real lambda, real *dvdlambda,
2403 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
2404 int gmx_unused *global_atom_index)
2406 return low_angres(nbonds, forceatoms, forceparams, x, f, fshift, pbc, g,
2407 lambda, dvdlambda, FALSE);
2410 real angresz(int nbonds,
2411 const t_iatom forceatoms[], const t_iparams forceparams[],
2412 const rvec x[], rvec4 f[], rvec fshift[],
2413 const t_pbc *pbc, const t_graph *g,
2414 real lambda, real *dvdlambda,
2415 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
2416 int gmx_unused *global_atom_index)
2418 return low_angres(nbonds, forceatoms, forceparams, x, f, fshift, pbc, g,
2419 lambda, dvdlambda, TRUE);
2422 real dihres(int nbonds,
2423 const t_iatom forceatoms[], const t_iparams forceparams[],
2424 const rvec x[], rvec4 f[], rvec fshift[],
2425 const t_pbc *pbc, const t_graph *g,
2426 real lambda, real *dvdlambda,
2427 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
2428 int gmx_unused *global_atom_index)
2430 real vtot = 0;
2431 int ai, aj, ak, al, i, k, type, t1, t2, t3;
2432 real phi0A, phi0B, dphiA, dphiB, kfacA, kfacB, phi0, dphi, kfac;
2433 real phi, ddphi, ddp, ddp2, dp, d2r, L1;
2434 rvec r_ij, r_kj, r_kl, m, n;
2436 L1 = 1.0-lambda;
2438 d2r = DEG2RAD;
2439 k = 0;
2441 for (i = 0; (i < nbonds); )
2443 type = forceatoms[i++];
2444 ai = forceatoms[i++];
2445 aj = forceatoms[i++];
2446 ak = forceatoms[i++];
2447 al = forceatoms[i++];
2449 phi0A = forceparams[type].dihres.phiA*d2r;
2450 dphiA = forceparams[type].dihres.dphiA*d2r;
2451 kfacA = forceparams[type].dihres.kfacA;
2453 phi0B = forceparams[type].dihres.phiB*d2r;
2454 dphiB = forceparams[type].dihres.dphiB*d2r;
2455 kfacB = forceparams[type].dihres.kfacB;
2457 phi0 = L1*phi0A + lambda*phi0B;
2458 dphi = L1*dphiA + lambda*dphiB;
2459 kfac = L1*kfacA + lambda*kfacB;
2461 phi = dih_angle(x[ai], x[aj], x[ak], x[al], pbc, r_ij, r_kj, r_kl, m, n,
2462 &t1, &t2, &t3);
2463 /* 84 flops */
2465 if (debug)
2467 fprintf(debug, "dihres[%d]: %d %d %d %d : phi=%f, dphi=%f, kfac=%f\n",
2468 k++, ai, aj, ak, al, phi0, dphi, kfac);
2470 /* phi can jump if phi0 is close to Pi/-Pi, which will cause huge
2471 * force changes if we just apply a normal harmonic.
2472 * Instead, we first calculate phi-phi0 and take it modulo (-Pi,Pi).
2473 * This means we will never have the periodicity problem, unless
2474 * the dihedral is Pi away from phiO, which is very unlikely due to
2475 * the potential.
2477 dp = phi-phi0;
2478 make_dp_periodic(&dp);
2480 if (dp > dphi)
2482 ddp = dp-dphi;
2484 else if (dp < -dphi)
2486 ddp = dp+dphi;
2488 else
2490 ddp = 0;
2493 if (ddp != 0.0)
2495 ddp2 = ddp*ddp;
2496 vtot += 0.5*kfac*ddp2;
2497 ddphi = kfac*ddp;
2499 *dvdlambda += 0.5*(kfacB - kfacA)*ddp2;
2500 /* lambda dependence from changing restraint distances */
2501 if (ddp > 0)
2503 *dvdlambda -= kfac*ddp*((dphiB - dphiA)+(phi0B - phi0A));
2505 else if (ddp < 0)
2507 *dvdlambda += kfac*ddp*((dphiB - dphiA)-(phi0B - phi0A));
2509 do_dih_fup(ai, aj, ak, al, ddphi, r_ij, r_kj, r_kl, m, n,
2510 f, fshift, pbc, g, x, t1, t2, t3); /* 112 */
2513 return vtot;
2517 real unimplemented(int gmx_unused nbonds,
2518 const t_iatom gmx_unused forceatoms[], const t_iparams gmx_unused forceparams[],
2519 const rvec gmx_unused x[], rvec4 gmx_unused f[], rvec gmx_unused fshift[],
2520 const t_pbc gmx_unused *pbc, const t_graph gmx_unused *g,
2521 real gmx_unused lambda, real gmx_unused *dvdlambda,
2522 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
2523 int gmx_unused *global_atom_index)
2525 gmx_impl("*** you are using a not implemented function");
2527 return 0.0; /* To make the compiler happy */
2530 real restrangles(int nbonds,
2531 const t_iatom forceatoms[], const t_iparams forceparams[],
2532 const rvec x[], rvec4 f[], rvec fshift[],
2533 const t_pbc *pbc, const t_graph *g,
2534 real gmx_unused lambda, real gmx_unused *dvdlambda,
2535 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
2536 int gmx_unused *global_atom_index)
2538 int i, d, ai, aj, ak, type, m;
2539 int t1, t2;
2540 real v, vtot;
2541 ivec jt, dt_ij, dt_kj;
2542 rvec f_i, f_j, f_k;
2543 real prefactor, ratio_ante, ratio_post;
2544 rvec delta_ante, delta_post, vec_temp;
2546 vtot = 0.0;
2547 for (i = 0; (i < nbonds); )
2549 type = forceatoms[i++];
2550 ai = forceatoms[i++];
2551 aj = forceatoms[i++];
2552 ak = forceatoms[i++];
2554 t1 = pbc_rvec_sub(pbc, x[ai], x[aj], vec_temp);
2555 pbc_rvec_sub(pbc, x[aj], x[ai], delta_ante);
2556 t2 = pbc_rvec_sub(pbc, x[ak], x[aj], delta_post);
2559 /* This function computes factors needed for restricted angle potential.
2560 * The restricted angle potential is used in coarse-grained simulations to avoid singularities
2561 * when three particles align and the dihedral angle and dihedral potential
2562 * cannot be calculated. This potential is calculated using the formula:
2563 real restrangles(int nbonds,
2564 const t_iatom forceatoms[],const t_iparams forceparams[],
2565 const rvec x[],rvec4 f[],rvec fshift[],
2566 const t_pbc *pbc,const t_graph *g,
2567 real gmx_unused lambda,real gmx_unused *dvdlambda,
2568 const t_mdatoms gmx_unused *md,t_fcdata gmx_unused *fcd,
2569 int gmx_unused *global_atom_index)
2571 int i, d, ai, aj, ak, type, m;
2572 int t1, t2;
2573 rvec r_ij,r_kj;
2574 real v, vtot;
2575 ivec jt,dt_ij,dt_kj;
2576 rvec f_i, f_j, f_k;
2577 real prefactor, ratio_ante, ratio_post;
2578 rvec delta_ante, delta_post, vec_temp;
2580 vtot = 0.0;
2581 for(i=0; (i<nbonds); )
2583 type = forceatoms[i++];
2584 ai = forceatoms[i++];
2585 aj = forceatoms[i++];
2586 ak = forceatoms[i++];
2588 * \f[V_{\rm ReB}(\theta_i) = \frac{1}{2} k_{\theta} \frac{(\cos\theta_i - \cos\theta_0)^2}
2589 * {\sin^2\theta_i}\f] ({eq:ReB} and ref \cite{MonicaGoga2013} from the manual).
2590 * For more explanations see comments file "restcbt.h". */
2592 compute_factors_restangles(type, forceparams, delta_ante, delta_post,
2593 &prefactor, &ratio_ante, &ratio_post, &v);
2595 /* Forces are computed per component */
2596 for (d = 0; d < DIM; d++)
2598 f_i[d] = prefactor * (ratio_ante * delta_ante[d] - delta_post[d]);
2599 f_j[d] = prefactor * ((ratio_post + 1.0) * delta_post[d] - (ratio_ante + 1.0) * delta_ante[d]);
2600 f_k[d] = prefactor * (delta_ante[d] - ratio_post * delta_post[d]);
2603 /* Computation of potential energy */
2605 vtot += v;
2607 /* Update forces */
2609 for (m = 0; (m < DIM); m++)
2611 f[ai][m] += f_i[m];
2612 f[aj][m] += f_j[m];
2613 f[ak][m] += f_k[m];
2616 if (g)
2618 copy_ivec(SHIFT_IVEC(g, aj), jt);
2619 ivec_sub(SHIFT_IVEC(g, ai), jt, dt_ij);
2620 ivec_sub(SHIFT_IVEC(g, ak), jt, dt_kj);
2621 t1 = IVEC2IS(dt_ij);
2622 t2 = IVEC2IS(dt_kj);
2625 rvec_inc(fshift[t1], f_i);
2626 rvec_inc(fshift[CENTRAL], f_j);
2627 rvec_inc(fshift[t2], f_k);
2629 return vtot;
2633 real restrdihs(int nbonds,
2634 const t_iatom forceatoms[], const t_iparams forceparams[],
2635 const rvec x[], rvec4 f[], rvec fshift[],
2636 const t_pbc *pbc, const t_graph *g,
2637 real gmx_unused lambda, real gmx_unused *dvlambda,
2638 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
2639 int gmx_unused *global_atom_index)
2641 int i, d, type, ai, aj, ak, al;
2642 rvec f_i, f_j, f_k, f_l;
2643 rvec dx_jl;
2644 ivec jt, dt_ij, dt_kj, dt_lj;
2645 int t1, t2, t3;
2646 real v, vtot;
2647 rvec delta_ante, delta_crnt, delta_post, vec_temp;
2648 real factor_phi_ai_ante, factor_phi_ai_crnt, factor_phi_ai_post;
2649 real factor_phi_aj_ante, factor_phi_aj_crnt, factor_phi_aj_post;
2650 real factor_phi_ak_ante, factor_phi_ak_crnt, factor_phi_ak_post;
2651 real factor_phi_al_ante, factor_phi_al_crnt, factor_phi_al_post;
2652 real prefactor_phi;
2655 vtot = 0.0;
2656 for (i = 0; (i < nbonds); )
2658 type = forceatoms[i++];
2659 ai = forceatoms[i++];
2660 aj = forceatoms[i++];
2661 ak = forceatoms[i++];
2662 al = forceatoms[i++];
2664 t1 = pbc_rvec_sub(pbc, x[ai], x[aj], vec_temp);
2665 pbc_rvec_sub(pbc, x[aj], x[ai], delta_ante);
2666 t2 = pbc_rvec_sub(pbc, x[ak], x[aj], delta_crnt);
2667 pbc_rvec_sub(pbc, x[ak], x[al], vec_temp);
2668 pbc_rvec_sub(pbc, x[al], x[ak], delta_post);
2670 /* This function computes factors needed for restricted angle potential.
2671 * The restricted angle potential is used in coarse-grained simulations to avoid singularities
2672 * when three particles align and the dihedral angle and dihedral potential cannot be calculated.
2673 * This potential is calculated using the formula:
2674 * \f[V_{\rm ReB}(\theta_i) = \frac{1}{2} k_{\theta}
2675 * \frac{(\cos\theta_i - \cos\theta_0)^2}{\sin^2\theta_i}\f]
2676 * ({eq:ReB} and ref \cite{MonicaGoga2013} from the manual).
2677 * For more explanations see comments file "restcbt.h" */
2679 compute_factors_restrdihs(type, forceparams,
2680 delta_ante, delta_crnt, delta_post,
2681 &factor_phi_ai_ante, &factor_phi_ai_crnt, &factor_phi_ai_post,
2682 &factor_phi_aj_ante, &factor_phi_aj_crnt, &factor_phi_aj_post,
2683 &factor_phi_ak_ante, &factor_phi_ak_crnt, &factor_phi_ak_post,
2684 &factor_phi_al_ante, &factor_phi_al_crnt, &factor_phi_al_post,
2685 &prefactor_phi, &v);
2688 /* Computation of forces per component */
2689 for (d = 0; d < DIM; d++)
2691 f_i[d] = prefactor_phi * (factor_phi_ai_ante * delta_ante[d] + factor_phi_ai_crnt * delta_crnt[d] + factor_phi_ai_post * delta_post[d]);
2692 f_j[d] = prefactor_phi * (factor_phi_aj_ante * delta_ante[d] + factor_phi_aj_crnt * delta_crnt[d] + factor_phi_aj_post * delta_post[d]);
2693 f_k[d] = prefactor_phi * (factor_phi_ak_ante * delta_ante[d] + factor_phi_ak_crnt * delta_crnt[d] + factor_phi_ak_post * delta_post[d]);
2694 f_l[d] = prefactor_phi * (factor_phi_al_ante * delta_ante[d] + factor_phi_al_crnt * delta_crnt[d] + factor_phi_al_post * delta_post[d]);
2696 /* Computation of the energy */
2698 vtot += v;
2702 /* Updating the forces */
2704 rvec_inc(f[ai], f_i);
2705 rvec_inc(f[aj], f_j);
2706 rvec_inc(f[ak], f_k);
2707 rvec_inc(f[al], f_l);
2710 /* Updating the fshift forces for the pressure coupling */
2711 if (g)
2713 copy_ivec(SHIFT_IVEC(g, aj), jt);
2714 ivec_sub(SHIFT_IVEC(g, ai), jt, dt_ij);
2715 ivec_sub(SHIFT_IVEC(g, ak), jt, dt_kj);
2716 ivec_sub(SHIFT_IVEC(g, al), jt, dt_lj);
2717 t1 = IVEC2IS(dt_ij);
2718 t2 = IVEC2IS(dt_kj);
2719 t3 = IVEC2IS(dt_lj);
2721 else if (pbc)
2723 t3 = pbc_rvec_sub(pbc, x[al], x[aj], dx_jl);
2725 else
2727 t3 = CENTRAL;
2730 rvec_inc(fshift[t1], f_i);
2731 rvec_inc(fshift[CENTRAL], f_j);
2732 rvec_inc(fshift[t2], f_k);
2733 rvec_inc(fshift[t3], f_l);
2737 return vtot;
2741 real cbtdihs(int nbonds,
2742 const t_iatom forceatoms[], const t_iparams forceparams[],
2743 const rvec x[], rvec4 f[], rvec fshift[],
2744 const t_pbc *pbc, const t_graph *g,
2745 real gmx_unused lambda, real gmx_unused *dvdlambda,
2746 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
2747 int gmx_unused *global_atom_index)
2749 int type, ai, aj, ak, al, i, d;
2750 int t1, t2, t3;
2751 real v, vtot;
2752 rvec vec_temp;
2753 rvec f_i, f_j, f_k, f_l;
2754 ivec jt, dt_ij, dt_kj, dt_lj;
2755 rvec dx_jl;
2756 rvec delta_ante, delta_crnt, delta_post;
2757 rvec f_phi_ai, f_phi_aj, f_phi_ak, f_phi_al;
2758 rvec f_theta_ante_ai, f_theta_ante_aj, f_theta_ante_ak;
2759 rvec f_theta_post_aj, f_theta_post_ak, f_theta_post_al;
2764 vtot = 0.0;
2765 for (i = 0; (i < nbonds); )
2767 type = forceatoms[i++];
2768 ai = forceatoms[i++];
2769 aj = forceatoms[i++];
2770 ak = forceatoms[i++];
2771 al = forceatoms[i++];
2774 t1 = pbc_rvec_sub(pbc, x[ai], x[aj], vec_temp);
2775 pbc_rvec_sub(pbc, x[aj], x[ai], delta_ante);
2776 t2 = pbc_rvec_sub(pbc, x[ak], x[aj], vec_temp);
2777 pbc_rvec_sub(pbc, x[ak], x[aj], delta_crnt);
2778 pbc_rvec_sub(pbc, x[ak], x[al], vec_temp);
2779 pbc_rvec_sub(pbc, x[al], x[ak], delta_post);
2781 /* \brief Compute factors for CBT potential
2782 * The combined bending-torsion potential goes to zero in a very smooth manner, eliminating the numerical
2783 * instabilities, when three coarse-grained particles align and the dihedral angle and standard
2784 * dihedral potentials cannot be calculated. The CBT potential is calculated using the formula:
2785 * \f[V_{\rm CBT}(\theta_{i-1}, \theta_i, \phi_i) = k_{\phi} \sin^3\theta_{i-1} \sin^3\theta_{i}
2786 * \sum_{n=0}^4 { a_n \cos^n\phi_i}\f] ({eq:CBT} and ref \cite{MonicaGoga2013} from the manual).
2787 * It contains in its expression not only the dihedral angle \f$\phi\f$
2788 * but also \f[\theta_{i-1}\f] (theta_ante bellow) and \f[\theta_{i}\f] (theta_post bellow)
2789 * --- the adjacent bending angles.
2790 * For more explanations see comments file "restcbt.h". */
2792 compute_factors_cbtdihs(type, forceparams, delta_ante, delta_crnt, delta_post,
2793 f_phi_ai, f_phi_aj, f_phi_ak, f_phi_al,
2794 f_theta_ante_ai, f_theta_ante_aj, f_theta_ante_ak,
2795 f_theta_post_aj, f_theta_post_ak, f_theta_post_al,
2796 &v);
2799 /* Acumulate the resuts per beads */
2800 for (d = 0; d < DIM; d++)
2802 f_i[d] = f_phi_ai[d] + f_theta_ante_ai[d];
2803 f_j[d] = f_phi_aj[d] + f_theta_ante_aj[d] + f_theta_post_aj[d];
2804 f_k[d] = f_phi_ak[d] + f_theta_ante_ak[d] + f_theta_post_ak[d];
2805 f_l[d] = f_phi_al[d] + f_theta_post_al[d];
2808 /* Compute the potential energy */
2810 vtot += v;
2813 /* Updating the forces */
2814 rvec_inc(f[ai], f_i);
2815 rvec_inc(f[aj], f_j);
2816 rvec_inc(f[ak], f_k);
2817 rvec_inc(f[al], f_l);
2820 /* Updating the fshift forces for the pressure coupling */
2821 if (g)
2823 copy_ivec(SHIFT_IVEC(g, aj), jt);
2824 ivec_sub(SHIFT_IVEC(g, ai), jt, dt_ij);
2825 ivec_sub(SHIFT_IVEC(g, ak), jt, dt_kj);
2826 ivec_sub(SHIFT_IVEC(g, al), jt, dt_lj);
2827 t1 = IVEC2IS(dt_ij);
2828 t2 = IVEC2IS(dt_kj);
2829 t3 = IVEC2IS(dt_lj);
2831 else if (pbc)
2833 t3 = pbc_rvec_sub(pbc, x[al], x[aj], dx_jl);
2835 else
2837 t3 = CENTRAL;
2840 rvec_inc(fshift[t1], f_i);
2841 rvec_inc(fshift[CENTRAL], f_j);
2842 rvec_inc(fshift[t2], f_k);
2843 rvec_inc(fshift[t3], f_l);
2846 return vtot;
2849 real rbdihs(int nbonds,
2850 const t_iatom forceatoms[], const t_iparams forceparams[],
2851 const rvec x[], rvec4 f[], rvec fshift[],
2852 const t_pbc *pbc, const t_graph *g,
2853 real lambda, real *dvdlambda,
2854 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
2855 int gmx_unused *global_atom_index)
2857 const real c0 = 0.0, c1 = 1.0, c2 = 2.0, c3 = 3.0, c4 = 4.0, c5 = 5.0;
2858 int type, ai, aj, ak, al, i, j;
2859 int t1, t2, t3;
2860 rvec r_ij, r_kj, r_kl, m, n;
2861 real parmA[NR_RBDIHS];
2862 real parmB[NR_RBDIHS];
2863 real parm[NR_RBDIHS];
2864 real cos_phi, phi, rbp, rbpBA;
2865 real v, ddphi, sin_phi;
2866 real cosfac, vtot;
2867 real L1 = 1.0-lambda;
2868 real dvdl_term = 0;
2870 vtot = 0.0;
2871 for (i = 0; (i < nbonds); )
2873 type = forceatoms[i++];
2874 ai = forceatoms[i++];
2875 aj = forceatoms[i++];
2876 ak = forceatoms[i++];
2877 al = forceatoms[i++];
2879 phi = dih_angle(x[ai], x[aj], x[ak], x[al], pbc, r_ij, r_kj, r_kl, m, n,
2880 &t1, &t2, &t3); /* 84 */
2882 /* Change to polymer convention */
2883 if (phi < c0)
2885 phi += M_PI;
2887 else
2889 phi -= M_PI; /* 1 */
2892 cos_phi = std::cos(phi);
2893 /* Beware of accuracy loss, cannot use 1-sqrt(cos^2) ! */
2894 sin_phi = std::sin(phi);
2896 for (j = 0; (j < NR_RBDIHS); j++)
2898 parmA[j] = forceparams[type].rbdihs.rbcA[j];
2899 parmB[j] = forceparams[type].rbdihs.rbcB[j];
2900 parm[j] = L1*parmA[j]+lambda*parmB[j];
2902 /* Calculate cosine powers */
2903 /* Calculate the energy */
2904 /* Calculate the derivative */
2906 v = parm[0];
2907 dvdl_term += (parmB[0]-parmA[0]);
2908 ddphi = c0;
2909 cosfac = c1;
2911 rbp = parm[1];
2912 rbpBA = parmB[1]-parmA[1];
2913 ddphi += rbp*cosfac;
2914 cosfac *= cos_phi;
2915 v += cosfac*rbp;
2916 dvdl_term += cosfac*rbpBA;
2917 rbp = parm[2];
2918 rbpBA = parmB[2]-parmA[2];
2919 ddphi += c2*rbp*cosfac;
2920 cosfac *= cos_phi;
2921 v += cosfac*rbp;
2922 dvdl_term += cosfac*rbpBA;
2923 rbp = parm[3];
2924 rbpBA = parmB[3]-parmA[3];
2925 ddphi += c3*rbp*cosfac;
2926 cosfac *= cos_phi;
2927 v += cosfac*rbp;
2928 dvdl_term += cosfac*rbpBA;
2929 rbp = parm[4];
2930 rbpBA = parmB[4]-parmA[4];
2931 ddphi += c4*rbp*cosfac;
2932 cosfac *= cos_phi;
2933 v += cosfac*rbp;
2934 dvdl_term += cosfac*rbpBA;
2935 rbp = parm[5];
2936 rbpBA = parmB[5]-parmA[5];
2937 ddphi += c5*rbp*cosfac;
2938 cosfac *= cos_phi;
2939 v += cosfac*rbp;
2940 dvdl_term += cosfac*rbpBA;
2942 ddphi = -ddphi*sin_phi; /* 11 */
2944 do_dih_fup(ai, aj, ak, al, ddphi, r_ij, r_kj, r_kl, m, n,
2945 f, fshift, pbc, g, x, t1, t2, t3); /* 112 */
2946 vtot += v;
2948 *dvdlambda += dvdl_term;
2950 return vtot;
2953 //! \endcond
2955 /*! \brief Mysterious undocumented function */
2956 static int
2957 cmap_setup_grid_index(int ip, int grid_spacing, int *ipm1, int *ipp1, int *ipp2)
2959 int im1, ip1, ip2;
2961 if (ip < 0)
2963 ip = ip + grid_spacing - 1;
2965 else if (ip > grid_spacing)
2967 ip = ip - grid_spacing - 1;
2970 im1 = ip - 1;
2971 ip1 = ip + 1;
2972 ip2 = ip + 2;
2974 if (ip == 0)
2976 im1 = grid_spacing - 1;
2978 else if (ip == grid_spacing-2)
2980 ip2 = 0;
2982 else if (ip == grid_spacing-1)
2984 ip1 = 0;
2985 ip2 = 1;
2988 *ipm1 = im1;
2989 *ipp1 = ip1;
2990 *ipp2 = ip2;
2992 return ip;
2996 real
2997 cmap_dihs(int nbonds,
2998 const t_iatom forceatoms[], const t_iparams forceparams[],
2999 const gmx_cmap_t *cmap_grid,
3000 const rvec x[], rvec4 f[], rvec fshift[],
3001 const struct t_pbc *pbc, const struct t_graph *g,
3002 real gmx_unused lambda, real gmx_unused *dvdlambda,
3003 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
3004 int gmx_unused *global_atom_index)
3006 int i, n;
3007 int ai, aj, ak, al, am;
3008 int a1i, a1j, a1k, a1l, a2i, a2j, a2k, a2l;
3009 int type, cmapA;
3010 int t11, t21, t31, t12, t22, t32;
3011 int iphi1, ip1m1, ip1p1, ip1p2;
3012 int iphi2, ip2m1, ip2p1, ip2p2;
3013 int l1, l2, l3;
3014 int pos1, pos2, pos3, pos4;
3016 real ty[4], ty1[4], ty2[4], ty12[4], tx[16];
3017 real phi1, cos_phi1, sin_phi1, xphi1;
3018 real phi2, cos_phi2, sin_phi2, xphi2;
3019 real dx, tt, tu, e, df1, df2, vtot;
3020 real ra21, rb21, rg21, rg1, rgr1, ra2r1, rb2r1, rabr1;
3021 real ra22, rb22, rg22, rg2, rgr2, ra2r2, rb2r2, rabr2;
3022 real fg1, hg1, fga1, hgb1, gaa1, gbb1;
3023 real fg2, hg2, fga2, hgb2, gaa2, gbb2;
3024 real fac;
3026 rvec r1_ij, r1_kj, r1_kl, m1, n1;
3027 rvec r2_ij, r2_kj, r2_kl, m2, n2;
3028 rvec f1_i, f1_j, f1_k, f1_l;
3029 rvec f2_i, f2_j, f2_k, f2_l;
3030 rvec a1, b1, a2, b2;
3031 rvec f1, g1, h1, f2, g2, h2;
3032 rvec dtf1, dtg1, dth1, dtf2, dtg2, dth2;
3033 ivec jt1, dt1_ij, dt1_kj, dt1_lj;
3034 ivec jt2, dt2_ij, dt2_kj, dt2_lj;
3036 const real *cmapd;
3038 int loop_index[4][4] = {
3039 {0, 4, 8, 12},
3040 {1, 5, 9, 13},
3041 {2, 6, 10, 14},
3042 {3, 7, 11, 15}
3045 /* Total CMAP energy */
3046 vtot = 0;
3048 for (n = 0; n < nbonds; )
3050 /* Five atoms are involved in the two torsions */
3051 type = forceatoms[n++];
3052 ai = forceatoms[n++];
3053 aj = forceatoms[n++];
3054 ak = forceatoms[n++];
3055 al = forceatoms[n++];
3056 am = forceatoms[n++];
3058 /* Which CMAP type is this */
3059 cmapA = forceparams[type].cmap.cmapA;
3060 cmapd = cmap_grid->cmapdata[cmapA].cmap;
3062 /* First torsion */
3063 a1i = ai;
3064 a1j = aj;
3065 a1k = ak;
3066 a1l = al;
3068 phi1 = dih_angle(x[a1i], x[a1j], x[a1k], x[a1l], pbc, r1_ij, r1_kj, r1_kl, m1, n1,
3069 &t11, &t21, &t31); /* 84 */
3071 cos_phi1 = std::cos(phi1);
3073 a1[0] = r1_ij[1]*r1_kj[2]-r1_ij[2]*r1_kj[1];
3074 a1[1] = r1_ij[2]*r1_kj[0]-r1_ij[0]*r1_kj[2];
3075 a1[2] = r1_ij[0]*r1_kj[1]-r1_ij[1]*r1_kj[0]; /* 9 */
3077 b1[0] = r1_kl[1]*r1_kj[2]-r1_kl[2]*r1_kj[1];
3078 b1[1] = r1_kl[2]*r1_kj[0]-r1_kl[0]*r1_kj[2];
3079 b1[2] = r1_kl[0]*r1_kj[1]-r1_kl[1]*r1_kj[0]; /* 9 */
3081 pbc_rvec_sub(pbc, x[a1l], x[a1k], h1);
3083 ra21 = iprod(a1, a1); /* 5 */
3084 rb21 = iprod(b1, b1); /* 5 */
3085 rg21 = iprod(r1_kj, r1_kj); /* 5 */
3086 rg1 = sqrt(rg21);
3088 rgr1 = 1.0/rg1;
3089 ra2r1 = 1.0/ra21;
3090 rb2r1 = 1.0/rb21;
3091 rabr1 = sqrt(ra2r1*rb2r1);
3093 sin_phi1 = rg1 * rabr1 * iprod(a1, h1) * (-1);
3095 if (cos_phi1 < -0.5 || cos_phi1 > 0.5)
3097 phi1 = std::asin(sin_phi1);
3099 if (cos_phi1 < 0)
3101 if (phi1 > 0)
3103 phi1 = M_PI - phi1;
3105 else
3107 phi1 = -M_PI - phi1;
3111 else
3113 phi1 = std::acos(cos_phi1);
3115 if (sin_phi1 < 0)
3117 phi1 = -phi1;
3121 xphi1 = phi1 + M_PI; /* 1 */
3123 /* Second torsion */
3124 a2i = aj;
3125 a2j = ak;
3126 a2k = al;
3127 a2l = am;
3129 phi2 = dih_angle(x[a2i], x[a2j], x[a2k], x[a2l], pbc, r2_ij, r2_kj, r2_kl, m2, n2,
3130 &t12, &t22, &t32); /* 84 */
3132 cos_phi2 = std::cos(phi2);
3134 a2[0] = r2_ij[1]*r2_kj[2]-r2_ij[2]*r2_kj[1];
3135 a2[1] = r2_ij[2]*r2_kj[0]-r2_ij[0]*r2_kj[2];
3136 a2[2] = r2_ij[0]*r2_kj[1]-r2_ij[1]*r2_kj[0]; /* 9 */
3138 b2[0] = r2_kl[1]*r2_kj[2]-r2_kl[2]*r2_kj[1];
3139 b2[1] = r2_kl[2]*r2_kj[0]-r2_kl[0]*r2_kj[2];
3140 b2[2] = r2_kl[0]*r2_kj[1]-r2_kl[1]*r2_kj[0]; /* 9 */
3142 pbc_rvec_sub(pbc, x[a2l], x[a2k], h2);
3144 ra22 = iprod(a2, a2); /* 5 */
3145 rb22 = iprod(b2, b2); /* 5 */
3146 rg22 = iprod(r2_kj, r2_kj); /* 5 */
3147 rg2 = sqrt(rg22);
3149 rgr2 = 1.0/rg2;
3150 ra2r2 = 1.0/ra22;
3151 rb2r2 = 1.0/rb22;
3152 rabr2 = sqrt(ra2r2*rb2r2);
3154 sin_phi2 = rg2 * rabr2 * iprod(a2, h2) * (-1);
3156 if (cos_phi2 < -0.5 || cos_phi2 > 0.5)
3158 phi2 = std::asin(sin_phi2);
3160 if (cos_phi2 < 0)
3162 if (phi2 > 0)
3164 phi2 = M_PI - phi2;
3166 else
3168 phi2 = -M_PI - phi2;
3172 else
3174 phi2 = std::acos(cos_phi2);
3176 if (sin_phi2 < 0)
3178 phi2 = -phi2;
3182 xphi2 = phi2 + M_PI; /* 1 */
3184 /* Range mangling */
3185 if (xphi1 < 0)
3187 xphi1 = xphi1 + 2*M_PI;
3189 else if (xphi1 >= 2*M_PI)
3191 xphi1 = xphi1 - 2*M_PI;
3194 if (xphi2 < 0)
3196 xphi2 = xphi2 + 2*M_PI;
3198 else if (xphi2 >= 2*M_PI)
3200 xphi2 = xphi2 - 2*M_PI;
3203 /* Number of grid points */
3204 dx = 2*M_PI / cmap_grid->grid_spacing;
3206 /* Where on the grid are we */
3207 iphi1 = static_cast<int>(xphi1/dx);
3208 iphi2 = static_cast<int>(xphi2/dx);
3210 iphi1 = cmap_setup_grid_index(iphi1, cmap_grid->grid_spacing, &ip1m1, &ip1p1, &ip1p2);
3211 iphi2 = cmap_setup_grid_index(iphi2, cmap_grid->grid_spacing, &ip2m1, &ip2p1, &ip2p2);
3213 pos1 = iphi1*cmap_grid->grid_spacing+iphi2;
3214 pos2 = ip1p1*cmap_grid->grid_spacing+iphi2;
3215 pos3 = ip1p1*cmap_grid->grid_spacing+ip2p1;
3216 pos4 = iphi1*cmap_grid->grid_spacing+ip2p1;
3218 ty[0] = cmapd[pos1*4];
3219 ty[1] = cmapd[pos2*4];
3220 ty[2] = cmapd[pos3*4];
3221 ty[3] = cmapd[pos4*4];
3223 ty1[0] = cmapd[pos1*4+1];
3224 ty1[1] = cmapd[pos2*4+1];
3225 ty1[2] = cmapd[pos3*4+1];
3226 ty1[3] = cmapd[pos4*4+1];
3228 ty2[0] = cmapd[pos1*4+2];
3229 ty2[1] = cmapd[pos2*4+2];
3230 ty2[2] = cmapd[pos3*4+2];
3231 ty2[3] = cmapd[pos4*4+2];
3233 ty12[0] = cmapd[pos1*4+3];
3234 ty12[1] = cmapd[pos2*4+3];
3235 ty12[2] = cmapd[pos3*4+3];
3236 ty12[3] = cmapd[pos4*4+3];
3238 /* Switch to degrees */
3239 dx = 360.0 / cmap_grid->grid_spacing;
3240 xphi1 = xphi1 * RAD2DEG;
3241 xphi2 = xphi2 * RAD2DEG;
3243 for (i = 0; i < 4; i++) /* 16 */
3245 tx[i] = ty[i];
3246 tx[i+4] = ty1[i]*dx;
3247 tx[i+8] = ty2[i]*dx;
3248 tx[i+12] = ty12[i]*dx*dx;
3251 real tc[16] = {0};
3252 for (int idx = 0; idx < 16; idx++) /* 1056 */
3254 for (int k = 0; k < 16; k++)
3256 tc[idx] += cmap_coeff_matrix[k*16+idx]*tx[k];
3260 tt = (xphi1-iphi1*dx)/dx;
3261 tu = (xphi2-iphi2*dx)/dx;
3263 e = 0;
3264 df1 = 0;
3265 df2 = 0;
3267 for (i = 3; i >= 0; i--)
3269 l1 = loop_index[i][3];
3270 l2 = loop_index[i][2];
3271 l3 = loop_index[i][1];
3273 e = tt * e + ((tc[i*4+3]*tu+tc[i*4+2])*tu + tc[i*4+1])*tu+tc[i*4];
3274 df1 = tu * df1 + (3.0*tc[l1]*tt+2.0*tc[l2])*tt+tc[l3];
3275 df2 = tt * df2 + (3.0*tc[i*4+3]*tu+2.0*tc[i*4+2])*tu+tc[i*4+1];
3278 fac = RAD2DEG/dx;
3279 df1 = df1 * fac;
3280 df2 = df2 * fac;
3282 /* CMAP energy */
3283 vtot += e;
3285 /* Do forces - first torsion */
3286 fg1 = iprod(r1_ij, r1_kj);
3287 hg1 = iprod(r1_kl, r1_kj);
3288 fga1 = fg1*ra2r1*rgr1;
3289 hgb1 = hg1*rb2r1*rgr1;
3290 gaa1 = -ra2r1*rg1;
3291 gbb1 = rb2r1*rg1;
3293 for (i = 0; i < DIM; i++)
3295 dtf1[i] = gaa1 * a1[i];
3296 dtg1[i] = fga1 * a1[i] - hgb1 * b1[i];
3297 dth1[i] = gbb1 * b1[i];
3299 f1[i] = df1 * dtf1[i];
3300 g1[i] = df1 * dtg1[i];
3301 h1[i] = df1 * dth1[i];
3303 f1_i[i] = f1[i];
3304 f1_j[i] = -f1[i] - g1[i];
3305 f1_k[i] = h1[i] + g1[i];
3306 f1_l[i] = -h1[i];
3308 f[a1i][i] = f[a1i][i] + f1_i[i];
3309 f[a1j][i] = f[a1j][i] + f1_j[i]; /* - f1[i] - g1[i] */
3310 f[a1k][i] = f[a1k][i] + f1_k[i]; /* h1[i] + g1[i] */
3311 f[a1l][i] = f[a1l][i] + f1_l[i]; /* h1[i] */
3314 /* Do forces - second torsion */
3315 fg2 = iprod(r2_ij, r2_kj);
3316 hg2 = iprod(r2_kl, r2_kj);
3317 fga2 = fg2*ra2r2*rgr2;
3318 hgb2 = hg2*rb2r2*rgr2;
3319 gaa2 = -ra2r2*rg2;
3320 gbb2 = rb2r2*rg2;
3322 for (i = 0; i < DIM; i++)
3324 dtf2[i] = gaa2 * a2[i];
3325 dtg2[i] = fga2 * a2[i] - hgb2 * b2[i];
3326 dth2[i] = gbb2 * b2[i];
3328 f2[i] = df2 * dtf2[i];
3329 g2[i] = df2 * dtg2[i];
3330 h2[i] = df2 * dth2[i];
3332 f2_i[i] = f2[i];
3333 f2_j[i] = -f2[i] - g2[i];
3334 f2_k[i] = h2[i] + g2[i];
3335 f2_l[i] = -h2[i];
3337 f[a2i][i] = f[a2i][i] + f2_i[i]; /* f2[i] */
3338 f[a2j][i] = f[a2j][i] + f2_j[i]; /* - f2[i] - g2[i] */
3339 f[a2k][i] = f[a2k][i] + f2_k[i]; /* h2[i] + g2[i] */
3340 f[a2l][i] = f[a2l][i] + f2_l[i]; /* - h2[i] */
3343 /* Shift forces */
3344 if (g)
3346 copy_ivec(SHIFT_IVEC(g, a1j), jt1);
3347 ivec_sub(SHIFT_IVEC(g, a1i), jt1, dt1_ij);
3348 ivec_sub(SHIFT_IVEC(g, a1k), jt1, dt1_kj);
3349 ivec_sub(SHIFT_IVEC(g, a1l), jt1, dt1_lj);
3350 t11 = IVEC2IS(dt1_ij);
3351 t21 = IVEC2IS(dt1_kj);
3352 t31 = IVEC2IS(dt1_lj);
3354 copy_ivec(SHIFT_IVEC(g, a2j), jt2);
3355 ivec_sub(SHIFT_IVEC(g, a2i), jt2, dt2_ij);
3356 ivec_sub(SHIFT_IVEC(g, a2k), jt2, dt2_kj);
3357 ivec_sub(SHIFT_IVEC(g, a2l), jt2, dt2_lj);
3358 t12 = IVEC2IS(dt2_ij);
3359 t22 = IVEC2IS(dt2_kj);
3360 t32 = IVEC2IS(dt2_lj);
3362 else if (pbc)
3364 t31 = pbc_rvec_sub(pbc, x[a1l], x[a1j], h1);
3365 t32 = pbc_rvec_sub(pbc, x[a2l], x[a2j], h2);
3367 else
3369 t31 = CENTRAL;
3370 t32 = CENTRAL;
3373 rvec_inc(fshift[t11], f1_i);
3374 rvec_inc(fshift[CENTRAL], f1_j);
3375 rvec_inc(fshift[t21], f1_k);
3376 rvec_inc(fshift[t31], f1_l);
3378 rvec_inc(fshift[t21], f2_i);
3379 rvec_inc(fshift[CENTRAL], f2_j);
3380 rvec_inc(fshift[t22], f2_k);
3381 rvec_inc(fshift[t32], f2_l);
3383 return vtot;
3387 //! \cond
3388 /***********************************************************
3390 * G R O M O S 9 6 F U N C T I O N S
3392 ***********************************************************/
3393 static real g96harmonic(real kA, real kB, real xA, real xB, real x, real lambda,
3394 real *V, real *F)
3396 const real half = 0.5;
3397 real L1, kk, x0, dx, dx2;
3398 real v, f, dvdlambda;
3400 L1 = 1.0-lambda;
3401 kk = L1*kA+lambda*kB;
3402 x0 = L1*xA+lambda*xB;
3404 dx = x-x0;
3405 dx2 = dx*dx;
3407 f = -kk*dx;
3408 v = half*kk*dx2;
3409 dvdlambda = half*(kB-kA)*dx2 + (xA-xB)*kk*dx;
3411 *F = f;
3412 *V = v;
3414 return dvdlambda;
3416 /* That was 21 flops */
3419 real g96bonds(int nbonds,
3420 const t_iatom forceatoms[], const t_iparams forceparams[],
3421 const rvec x[], rvec4 f[], rvec fshift[],
3422 const t_pbc *pbc, const t_graph *g,
3423 real lambda, real *dvdlambda,
3424 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
3425 int gmx_unused *global_atom_index)
3427 int i, m, ki, ai, aj, type;
3428 real dr2, fbond, vbond, fij, vtot;
3429 rvec dx;
3430 ivec dt;
3432 vtot = 0.0;
3433 for (i = 0; (i < nbonds); )
3435 type = forceatoms[i++];
3436 ai = forceatoms[i++];
3437 aj = forceatoms[i++];
3439 ki = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /* 3 */
3440 dr2 = iprod(dx, dx); /* 5 */
3442 *dvdlambda += g96harmonic(forceparams[type].harmonic.krA,
3443 forceparams[type].harmonic.krB,
3444 forceparams[type].harmonic.rA,
3445 forceparams[type].harmonic.rB,
3446 dr2, lambda, &vbond, &fbond);
3448 vtot += 0.5*vbond; /* 1*/
3449 #ifdef DEBUG
3450 if (debug)
3452 fprintf(debug, "G96-BONDS: dr = %10g vbond = %10g fbond = %10g\n",
3453 sqrt(dr2), vbond, fbond);
3455 #endif
3457 if (g)
3459 ivec_sub(SHIFT_IVEC(g, ai), SHIFT_IVEC(g, aj), dt);
3460 ki = IVEC2IS(dt);
3462 for (m = 0; (m < DIM); m++) /* 15 */
3464 fij = fbond*dx[m];
3465 f[ai][m] += fij;
3466 f[aj][m] -= fij;
3467 fshift[ki][m] += fij;
3468 fshift[CENTRAL][m] -= fij;
3470 } /* 44 TOTAL */
3471 return vtot;
3474 static real g96bond_angle(const rvec xi, const rvec xj, const rvec xk, const t_pbc *pbc,
3475 rvec r_ij, rvec r_kj,
3476 int *t1, int *t2)
3477 /* Return value is the angle between the bonds i-j and j-k */
3479 real costh;
3481 *t1 = pbc_rvec_sub(pbc, xi, xj, r_ij); /* 3 */
3482 *t2 = pbc_rvec_sub(pbc, xk, xj, r_kj); /* 3 */
3484 costh = cos_angle(r_ij, r_kj); /* 25 */
3485 /* 41 TOTAL */
3486 return costh;
3489 real g96angles(int nbonds,
3490 const t_iatom forceatoms[], const t_iparams forceparams[],
3491 const rvec x[], rvec4 f[], rvec fshift[],
3492 const t_pbc *pbc, const t_graph *g,
3493 real lambda, real *dvdlambda,
3494 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
3495 int gmx_unused *global_atom_index)
3497 int i, ai, aj, ak, type, m, t1, t2;
3498 rvec r_ij, r_kj;
3499 real cos_theta, dVdt, va, vtot;
3500 real rij_1, rij_2, rkj_1, rkj_2, rijrkj_1;
3501 rvec f_i, f_j, f_k;
3502 ivec jt, dt_ij, dt_kj;
3504 vtot = 0.0;
3505 for (i = 0; (i < nbonds); )
3507 type = forceatoms[i++];
3508 ai = forceatoms[i++];
3509 aj = forceatoms[i++];
3510 ak = forceatoms[i++];
3512 cos_theta = g96bond_angle(x[ai], x[aj], x[ak], pbc, r_ij, r_kj, &t1, &t2);
3514 *dvdlambda += g96harmonic(forceparams[type].harmonic.krA,
3515 forceparams[type].harmonic.krB,
3516 forceparams[type].harmonic.rA,
3517 forceparams[type].harmonic.rB,
3518 cos_theta, lambda, &va, &dVdt);
3519 vtot += va;
3521 rij_1 = gmx::invsqrt(iprod(r_ij, r_ij));
3522 rkj_1 = gmx::invsqrt(iprod(r_kj, r_kj));
3523 rij_2 = rij_1*rij_1;
3524 rkj_2 = rkj_1*rkj_1;
3525 rijrkj_1 = rij_1*rkj_1; /* 23 */
3527 #ifdef DEBUG
3528 if (debug)
3530 fprintf(debug, "G96ANGLES: costheta = %10g vth = %10g dV/dct = %10g\n",
3531 cos_theta, va, dVdt);
3533 #endif
3534 for (m = 0; (m < DIM); m++) /* 42 */
3536 f_i[m] = dVdt*(r_kj[m]*rijrkj_1 - r_ij[m]*rij_2*cos_theta);
3537 f_k[m] = dVdt*(r_ij[m]*rijrkj_1 - r_kj[m]*rkj_2*cos_theta);
3538 f_j[m] = -f_i[m]-f_k[m];
3539 f[ai][m] += f_i[m];
3540 f[aj][m] += f_j[m];
3541 f[ak][m] += f_k[m];
3544 if (g)
3546 copy_ivec(SHIFT_IVEC(g, aj), jt);
3548 ivec_sub(SHIFT_IVEC(g, ai), jt, dt_ij);
3549 ivec_sub(SHIFT_IVEC(g, ak), jt, dt_kj);
3550 t1 = IVEC2IS(dt_ij);
3551 t2 = IVEC2IS(dt_kj);
3553 rvec_inc(fshift[t1], f_i);
3554 rvec_inc(fshift[CENTRAL], f_j);
3555 rvec_inc(fshift[t2], f_k); /* 9 */
3556 /* 163 TOTAL */
3558 return vtot;
3561 real cross_bond_bond(int nbonds,
3562 const t_iatom forceatoms[], const t_iparams forceparams[],
3563 const rvec x[], rvec4 f[], rvec fshift[],
3564 const t_pbc *pbc, const t_graph *g,
3565 real gmx_unused lambda, real gmx_unused *dvdlambda,
3566 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
3567 int gmx_unused *global_atom_index)
3569 /* Potential from Lawrence and Skimmer, Chem. Phys. Lett. 372 (2003)
3570 * pp. 842-847
3572 int i, ai, aj, ak, type, m, t1, t2;
3573 rvec r_ij, r_kj;
3574 real vtot, vrr, s1, s2, r1, r2, r1e, r2e, krr;
3575 rvec f_i, f_j, f_k;
3576 ivec jt, dt_ij, dt_kj;
3578 vtot = 0.0;
3579 for (i = 0; (i < nbonds); )
3581 type = forceatoms[i++];
3582 ai = forceatoms[i++];
3583 aj = forceatoms[i++];
3584 ak = forceatoms[i++];
3585 r1e = forceparams[type].cross_bb.r1e;
3586 r2e = forceparams[type].cross_bb.r2e;
3587 krr = forceparams[type].cross_bb.krr;
3589 /* Compute distance vectors ... */
3590 t1 = pbc_rvec_sub(pbc, x[ai], x[aj], r_ij);
3591 t2 = pbc_rvec_sub(pbc, x[ak], x[aj], r_kj);
3593 /* ... and their lengths */
3594 r1 = norm(r_ij);
3595 r2 = norm(r_kj);
3597 /* Deviations from ideality */
3598 s1 = r1-r1e;
3599 s2 = r2-r2e;
3601 /* Energy (can be negative!) */
3602 vrr = krr*s1*s2;
3603 vtot += vrr;
3605 /* Forces */
3606 svmul(-krr*s2/r1, r_ij, f_i);
3607 svmul(-krr*s1/r2, r_kj, f_k);
3609 for (m = 0; (m < DIM); m++) /* 12 */
3611 f_j[m] = -f_i[m] - f_k[m];
3612 f[ai][m] += f_i[m];
3613 f[aj][m] += f_j[m];
3614 f[ak][m] += f_k[m];
3617 /* Virial stuff */
3618 if (g)
3620 copy_ivec(SHIFT_IVEC(g, aj), jt);
3622 ivec_sub(SHIFT_IVEC(g, ai), jt, dt_ij);
3623 ivec_sub(SHIFT_IVEC(g, ak), jt, dt_kj);
3624 t1 = IVEC2IS(dt_ij);
3625 t2 = IVEC2IS(dt_kj);
3627 rvec_inc(fshift[t1], f_i);
3628 rvec_inc(fshift[CENTRAL], f_j);
3629 rvec_inc(fshift[t2], f_k); /* 9 */
3630 /* 163 TOTAL */
3632 return vtot;
3635 real cross_bond_angle(int nbonds,
3636 const t_iatom forceatoms[], const t_iparams forceparams[],
3637 const rvec x[], rvec4 f[], rvec fshift[],
3638 const t_pbc *pbc, const t_graph *g,
3639 real gmx_unused lambda, real gmx_unused *dvdlambda,
3640 const t_mdatoms gmx_unused *md, t_fcdata gmx_unused *fcd,
3641 int gmx_unused *global_atom_index)
3643 /* Potential from Lawrence and Skimmer, Chem. Phys. Lett. 372 (2003)
3644 * pp. 842-847
3646 int i, ai, aj, ak, type, m, t1, t2;
3647 rvec r_ij, r_kj, r_ik;
3648 real vtot, vrt, s1, s2, s3, r1, r2, r3, r1e, r2e, r3e, krt, k1, k2, k3;
3649 rvec f_i, f_j, f_k;
3650 ivec jt, dt_ij, dt_kj;
3652 vtot = 0.0;
3653 for (i = 0; (i < nbonds); )
3655 type = forceatoms[i++];
3656 ai = forceatoms[i++];
3657 aj = forceatoms[i++];
3658 ak = forceatoms[i++];
3659 r1e = forceparams[type].cross_ba.r1e;
3660 r2e = forceparams[type].cross_ba.r2e;
3661 r3e = forceparams[type].cross_ba.r3e;
3662 krt = forceparams[type].cross_ba.krt;
3664 /* Compute distance vectors ... */
3665 t1 = pbc_rvec_sub(pbc, x[ai], x[aj], r_ij);
3666 t2 = pbc_rvec_sub(pbc, x[ak], x[aj], r_kj);
3667 pbc_rvec_sub(pbc, x[ai], x[ak], r_ik);
3669 /* ... and their lengths */
3670 r1 = norm(r_ij);
3671 r2 = norm(r_kj);
3672 r3 = norm(r_ik);
3674 /* Deviations from ideality */
3675 s1 = r1-r1e;
3676 s2 = r2-r2e;
3677 s3 = r3-r3e;
3679 /* Energy (can be negative!) */
3680 vrt = krt*s3*(s1+s2);
3681 vtot += vrt;
3683 /* Forces */
3684 k1 = -krt*(s3/r1);
3685 k2 = -krt*(s3/r2);
3686 k3 = -krt*(s1+s2)/r3;
3687 for (m = 0; (m < DIM); m++)
3689 f_i[m] = k1*r_ij[m] + k3*r_ik[m];
3690 f_k[m] = k2*r_kj[m] - k3*r_ik[m];
3691 f_j[m] = -f_i[m] - f_k[m];
3694 for (m = 0; (m < DIM); m++) /* 12 */
3696 f[ai][m] += f_i[m];
3697 f[aj][m] += f_j[m];
3698 f[ak][m] += f_k[m];
3701 /* Virial stuff */
3702 if (g)
3704 copy_ivec(SHIFT_IVEC(g, aj), jt);
3706 ivec_sub(SHIFT_IVEC(g, ai), jt, dt_ij);
3707 ivec_sub(SHIFT_IVEC(g, ak), jt, dt_kj);
3708 t1 = IVEC2IS(dt_ij);
3709 t2 = IVEC2IS(dt_kj);
3711 rvec_inc(fshift[t1], f_i);
3712 rvec_inc(fshift[CENTRAL], f_j);
3713 rvec_inc(fshift[t2], f_k); /* 9 */
3714 /* 163 TOTAL */
3716 return vtot;
3719 static real bonded_tab(const char *type, int table_nr,
3720 const bondedtable_t *table, real kA, real kB, real r,
3721 real lambda, real *V, real *F)
3723 real k, tabscale, *VFtab, rt, eps, eps2, Yt, Ft, Geps, Heps2, Fp, VV, FF;
3724 int n0, nnn;
3725 real dvdlambda;
3727 k = (1.0 - lambda)*kA + lambda*kB;
3729 tabscale = table->scale;
3730 VFtab = table->data;
3732 rt = r*tabscale;
3733 n0 = static_cast<int>(rt);
3734 if (n0 >= table->n)
3736 gmx_fatal(FARGS, "A tabulated %s interaction table number %d is out of the table range: r %f, between table indices %d and %d, table length %d",
3737 type, table_nr, r, n0, n0+1, table->n);
3739 eps = rt - n0;
3740 eps2 = eps*eps;
3741 nnn = 4*n0;
3742 Yt = VFtab[nnn];
3743 Ft = VFtab[nnn+1];
3744 Geps = VFtab[nnn+2]*eps;
3745 Heps2 = VFtab[nnn+3]*eps2;
3746 Fp = Ft + Geps + Heps2;
3747 VV = Yt + Fp*eps;
3748 FF = Fp + Geps + 2.0*Heps2;
3750 *F = -k*FF*tabscale;
3751 *V = k*VV;
3752 dvdlambda = (kB - kA)*VV;
3754 return dvdlambda;
3756 /* That was 22 flops */
3759 real tab_bonds(int nbonds,
3760 const t_iatom forceatoms[], const t_iparams forceparams[],
3761 const rvec x[], rvec4 f[], rvec fshift[],
3762 const t_pbc *pbc, const t_graph *g,
3763 real lambda, real *dvdlambda,
3764 const t_mdatoms gmx_unused *md, t_fcdata *fcd,
3765 int gmx_unused *global_atom_index)
3767 int i, m, ki, ai, aj, type, table;
3768 real dr, dr2, fbond, vbond, fij, vtot;
3769 rvec dx;
3770 ivec dt;
3772 vtot = 0.0;
3773 for (i = 0; (i < nbonds); )
3775 type = forceatoms[i++];
3776 ai = forceatoms[i++];
3777 aj = forceatoms[i++];
3779 ki = pbc_rvec_sub(pbc, x[ai], x[aj], dx); /* 3 */
3780 dr2 = iprod(dx, dx); /* 5 */
3781 dr = dr2*gmx::invsqrt(dr2); /* 10 */
3783 table = forceparams[type].tab.table;
3785 *dvdlambda += bonded_tab("bond", table,
3786 &fcd->bondtab[table],
3787 forceparams[type].tab.kA,
3788 forceparams[type].tab.kB,
3789 dr, lambda, &vbond, &fbond); /* 22 */
3791 if (dr2 == 0.0)
3793 continue;
3797 vtot += vbond; /* 1*/
3798 fbond *= gmx::invsqrt(dr2); /* 6 */
3799 #ifdef DEBUG
3800 if (debug)
3802 fprintf(debug, "TABBONDS: dr = %10g vbond = %10g fbond = %10g\n",
3803 dr, vbond, fbond);
3805 #endif
3806 if (g)
3808 ivec_sub(SHIFT_IVEC(g, ai), SHIFT_IVEC(g, aj), dt);
3809 ki = IVEC2IS(dt);
3811 for (m = 0; (m < DIM); m++) /* 15 */
3813 fij = fbond*dx[m];
3814 f[ai][m] += fij;
3815 f[aj][m] -= fij;
3816 fshift[ki][m] += fij;
3817 fshift[CENTRAL][m] -= fij;
3819 } /* 62 TOTAL */
3820 return vtot;
3823 real tab_angles(int nbonds,
3824 const t_iatom forceatoms[], const t_iparams forceparams[],
3825 const rvec x[], rvec4 f[], rvec fshift[],
3826 const t_pbc *pbc, const t_graph *g,
3827 real lambda, real *dvdlambda,
3828 const t_mdatoms gmx_unused *md, t_fcdata *fcd,
3829 int gmx_unused *global_atom_index)
3831 int i, ai, aj, ak, t1, t2, type, table;
3832 rvec r_ij, r_kj;
3833 real cos_theta, cos_theta2, theta, dVdt, va, vtot;
3834 ivec jt, dt_ij, dt_kj;
3836 vtot = 0.0;
3837 for (i = 0; (i < nbonds); )
3839 type = forceatoms[i++];
3840 ai = forceatoms[i++];
3841 aj = forceatoms[i++];
3842 ak = forceatoms[i++];
3844 theta = bond_angle(x[ai], x[aj], x[ak], pbc,
3845 r_ij, r_kj, &cos_theta, &t1, &t2); /* 41 */
3847 table = forceparams[type].tab.table;
3849 *dvdlambda += bonded_tab("angle", table,
3850 &fcd->angletab[table],
3851 forceparams[type].tab.kA,
3852 forceparams[type].tab.kB,
3853 theta, lambda, &va, &dVdt); /* 22 */
3854 vtot += va;
3856 cos_theta2 = gmx::square(cos_theta); /* 1 */
3857 if (cos_theta2 < 1)
3859 int m;
3860 real st, sth;
3861 real cik, cii, ckk;
3862 real nrkj2, nrij2;
3863 rvec f_i, f_j, f_k;
3865 st = dVdt*gmx::invsqrt(1 - cos_theta2); /* 12 */
3866 sth = st*cos_theta; /* 1 */
3867 #ifdef DEBUG
3868 if (debug)
3870 fprintf(debug, "ANGLES: theta = %10g vth = %10g dV/dtheta = %10g\n",
3871 theta*RAD2DEG, va, dVdt);
3873 #endif
3874 nrkj2 = iprod(r_kj, r_kj); /* 5 */
3875 nrij2 = iprod(r_ij, r_ij);
3877 cik = st*gmx::invsqrt(nrkj2*nrij2); /* 12 */
3878 cii = sth/nrij2; /* 10 */
3879 ckk = sth/nrkj2; /* 10 */
3881 for (m = 0; (m < DIM); m++) /* 39 */
3883 f_i[m] = -(cik*r_kj[m]-cii*r_ij[m]);
3884 f_k[m] = -(cik*r_ij[m]-ckk*r_kj[m]);
3885 f_j[m] = -f_i[m]-f_k[m];
3886 f[ai][m] += f_i[m];
3887 f[aj][m] += f_j[m];
3888 f[ak][m] += f_k[m];
3890 if (g)
3892 copy_ivec(SHIFT_IVEC(g, aj), jt);
3894 ivec_sub(SHIFT_IVEC(g, ai), jt, dt_ij);
3895 ivec_sub(SHIFT_IVEC(g, ak), jt, dt_kj);
3896 t1 = IVEC2IS(dt_ij);
3897 t2 = IVEC2IS(dt_kj);
3899 rvec_inc(fshift[t1], f_i);
3900 rvec_inc(fshift[CENTRAL], f_j);
3901 rvec_inc(fshift[t2], f_k);
3902 } /* 169 TOTAL */
3904 return vtot;
3907 real tab_dihs(int nbonds,
3908 const t_iatom forceatoms[], const t_iparams forceparams[],
3909 const rvec x[], rvec4 f[], rvec fshift[],
3910 const t_pbc *pbc, const t_graph *g,
3911 real lambda, real *dvdlambda,
3912 const t_mdatoms gmx_unused *md, t_fcdata *fcd,
3913 int gmx_unused *global_atom_index)
3915 int i, type, ai, aj, ak, al, table;
3916 int t1, t2, t3;
3917 rvec r_ij, r_kj, r_kl, m, n;
3918 real phi, ddphi, vpd, vtot;
3920 vtot = 0.0;
3921 for (i = 0; (i < nbonds); )
3923 type = forceatoms[i++];
3924 ai = forceatoms[i++];
3925 aj = forceatoms[i++];
3926 ak = forceatoms[i++];
3927 al = forceatoms[i++];
3929 phi = dih_angle(x[ai], x[aj], x[ak], x[al], pbc, r_ij, r_kj, r_kl, m, n,
3930 &t1, &t2, &t3); /* 84 */
3932 table = forceparams[type].tab.table;
3934 /* Hopefully phi+M_PI never results in values < 0 */
3935 *dvdlambda += bonded_tab("dihedral", table,
3936 &fcd->dihtab[table],
3937 forceparams[type].tab.kA,
3938 forceparams[type].tab.kB,
3939 phi+M_PI, lambda, &vpd, &ddphi);
3941 vtot += vpd;
3942 do_dih_fup(ai, aj, ak, al, -ddphi, r_ij, r_kj, r_kl, m, n,
3943 f, fshift, pbc, g, x, t1, t2, t3); /* 112 */
3945 #ifdef DEBUG
3946 fprintf(debug, "pdih: (%d,%d,%d,%d) phi=%g\n",
3947 ai, aj, ak, al, phi);
3948 #endif
3949 } /* 227 TOTAL */
3951 return vtot;
3954 //! \endcond