1 /* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*-
4 * This source code is part of
8 * GROningen MAchine for Chemical Simulations
11 * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
12 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
13 * Copyright (c) 2001-2004, The GROMACS development team,
14 * check out http://www.gromacs.org for more information.
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation; either version 2
19 * of the License, or (at your option) any later version.
21 * If you want to redistribute modifications, please consider that
22 * scientific software is very special. Version control is crucial -
23 * bugs must be traceable. We will be happy to consider code for
24 * inclusion in the official distribution, but derived work must not
25 * be called official GROMACS. Details are found in the README & COPYING
26 * files - if they are missing, get the official version at www.gromacs.org.
28 * To help us fund GROMACS development, we humbly ask that you cite
29 * the papers on the package - you can find them in the top README file.
31 * For more info, check our website at http://www.gromacs.org
34 * GROningen Mixture of Alchemy and Childrens' Stories
44 #include "nonbonded.h"
45 #include "nb_kernel.h"
49 gmx_nb_free_energy_kernel(t_nblist * nlist,
54 nb_kernel_data_t * kernel_data,
61 int i, j, n, ii, is3, ii3, k, nj0, nj1, jnr, j3, ggid;
63 real Fscal, FscalC[NSTATES], FscalV[NSTATES], tx, ty, tz;
64 real Vcoul[NSTATES], Vvdw[NSTATES];
65 real rinv6, r, rt, rtC, rtV;
67 real qq[NSTATES], vctot, krsq;
68 int ntiA, ntiB, tj[NSTATES];
69 real Vvdw6, Vvdw12, vvtot;
70 real ix, iy, iz, fix, fiy, fiz;
71 real dx, dy, dz, rsq, rinv;
72 real c6[NSTATES], c12[NSTATES];
73 real LFC[NSTATES], LFV[NSTATES], DLF[NSTATES];
74 double dvdl_coul, dvdl_vdw;
75 real lfac_coul[NSTATES], dlfac_coul[NSTATES], lfac_vdw[NSTATES], dlfac_vdw[NSTATES];
76 real sigma6[NSTATES], alpha_vdw_eff, alpha_coul_eff, sigma2_def, sigma2_min;
77 real rp, rpm2, rC, rV, rinvC, rpinvC, rinvV, rpinvV;
78 real sigma2[NSTATES], sigma_pow[NSTATES], sigma_powm2[NSTATES], rs, rs2;
79 int do_coultab, do_vdwtab, do_tab, tab_elemsize;
80 int n0, n1C, n1V, nnn;
81 real Y, F, G, H, Fp, Geps, Heps2, epsC, eps2C, epsV, eps2V, VV, FF;
102 real sigma6_min, sigma6_def, lam_power, sc_power, sc_r_power;
103 real alpha_coul, alpha_vdw, lambda_coul, lambda_vdw, ewc;
109 real rcoulomb, rvdw, sh_invrc6;
110 gmx_bool bExactElecCutoff, bExactVdwCutoff;
111 real rcutoff, rcutoff2, rswitch, d, d2, swV3, swV4, swV5, swF2, swF3, swF4, sw, dsw, rinvcorr;
116 fshift = fr->fshift[0];
117 Vc = kernel_data->energygrp_elec;
118 Vv = kernel_data->energygrp_vdw;
119 tabscale = kernel_data->table_elec_vdw->scale;
120 VFtab = kernel_data->table_elec_vdw->data;
124 jindex = nlist->jindex;
126 icoul = nlist->ielec;
128 shift = nlist->shift;
131 shiftvec = fr->shift_vec[0];
132 chargeA = mdatoms->chargeA;
133 chargeB = mdatoms->chargeB;
137 ewc = fr->ewaldcoeff;
138 Vc = kernel_data->energygrp_elec;
139 typeA = mdatoms->typeA;
140 typeB = mdatoms->typeB;
143 Vv = kernel_data->energygrp_vdw;
144 tabscale = kernel_data->table_elec_vdw->scale;
145 VFtab = kernel_data->table_elec_vdw->data;
146 lambda_coul = kernel_data->lambda[efptCOUL];
147 lambda_vdw = kernel_data->lambda[efptVDW];
148 dvdl = kernel_data->dvdl;
149 alpha_coul = fr->sc_alphacoul;
150 alpha_vdw = fr->sc_alphavdw;
151 lam_power = fr->sc_power;
152 sc_r_power = fr->sc_r_power;
153 sigma6_def = fr->sc_sigma6_def;
154 sigma6_min = fr->sc_sigma6_min;
155 bDoForces = kernel_data->flags & GMX_NONBONDED_DO_FORCE;
157 rcoulomb = fr->rcoulomb;
159 sh_invrc6 = fr->ic->sh_invrc6;
161 if (fr->coulomb_modifier == eintmodPOTSWITCH || fr->vdw_modifier == eintmodPOTSWITCH)
163 rcutoff = (fr->coulomb_modifier == eintmodPOTSWITCH) ? fr->rcoulomb : fr->rvdw;
164 rcutoff2 = rcutoff*rcutoff;
165 rswitch = (fr->coulomb_modifier == eintmodPOTSWITCH) ? fr->rcoulomb_switch : fr->rvdw_switch;
167 swV3 = -10.0/(d*d*d);
168 swV4 = 15.0/(d*d*d*d);
169 swV5 = -6.0/(d*d*d*d*d);
170 swF2 = -30.0/(d*d*d);
171 swF3 = 60.0/(d*d*d*d);
172 swF4 = -30.0/(d*d*d*d*d);
176 /* Stupid compilers dont realize these variables will not be used */
186 bExactElecCutoff = (fr->coulomb_modifier != eintmodNONE) || fr->eeltype == eelRF_ZERO;
187 bExactVdwCutoff = (fr->vdw_modifier != eintmodNONE);
189 /* fix compiler warnings */
198 /* Lambda factor for state A, 1-lambda*/
199 LFC[STATE_A] = 1.0 - lambda_coul;
200 LFV[STATE_A] = 1.0 - lambda_vdw;
202 /* Lambda factor for state B, lambda*/
203 LFC[STATE_B] = lambda_coul;
204 LFV[STATE_B] = lambda_vdw;
206 /*derivative of the lambda factor for state A and B */
210 for (i = 0; i < NSTATES; i++)
212 lfac_coul[i] = (lam_power == 2 ? (1-LFC[i])*(1-LFC[i]) : (1-LFC[i]));
213 dlfac_coul[i] = DLF[i]*lam_power/sc_r_power*(lam_power == 2 ? (1-LFC[i]) : 1);
214 lfac_vdw[i] = (lam_power == 2 ? (1-LFV[i])*(1-LFV[i]) : (1-LFV[i]));
215 dlfac_vdw[i] = DLF[i]*lam_power/sc_r_power*(lam_power == 2 ? (1-LFV[i]) : 1);
218 sigma2_def = pow(sigma6_def, 1.0/3.0);
219 sigma2_min = pow(sigma6_min, 1.0/3.0);
221 /* Ewald (not PME) table is special (icoul==enbcoulFEWALD) */
223 do_coultab = (icoul == GMX_NBKERNEL_ELEC_CUBICSPLINETABLE);
224 do_vdwtab = (ivdw == GMX_NBKERNEL_VDW_CUBICSPLINETABLE);
226 do_tab = do_coultab || do_vdwtab;
228 /* we always use the combined table here */
231 for (n = 0; (n < nri); n++)
235 shY = shiftvec[is3+1];
236 shZ = shiftvec[is3+2];
244 iqA = facel*chargeA[ii];
245 iqB = facel*chargeB[ii];
246 ntiA = 2*ntype*typeA[ii];
247 ntiB = 2*ntype*typeB[ii];
254 for (k = nj0; (k < nj1); k++)
261 rsq = dx*dx+dy*dy+dz*dz;
262 rinv = gmx_invsqrt(rsq);
264 if (sc_r_power == 6.0)
266 rpm2 = rsq*rsq; /* r4 */
267 rp = rpm2*rsq; /* r6 */
269 else if (sc_r_power == 48.0)
271 rp = rsq*rsq*rsq; /* r6 */
272 rp = rp*rp; /* r12 */
273 rp = rp*rp; /* r24 */
274 rp = rp*rp; /* r48 */
275 rpm2 = rp/rsq; /* r46 */
279 rp = pow(r, sc_r_power); /* not currently supported as input, but can handle it */
283 tj[STATE_A] = ntiA+2*typeA[jnr];
284 tj[STATE_B] = ntiB+2*typeB[jnr];
285 qq[STATE_A] = iqA*chargeA[jnr];
286 qq[STATE_B] = iqB*chargeB[jnr];
288 for (i = 0; i < NSTATES; i++)
292 c12[i] = nbfp[tj[i]+1];
293 if ((c6[i] > 0) && (c12[i] > 0))
295 /* c12 is stored scaled with 12.0 and c6 is scaled with 6.0 - correct for this */
296 sigma6[i] = 0.5*c12[i]/c6[i];
297 sigma2[i] = pow(sigma6[i], 1.0/3.0);
298 /* should be able to get rid of this ^^^ internal pow call eventually. Will require agreement on
299 what data to store externally. Can't be fixed without larger scale changes, so not 4.6 */
300 if (sigma6[i] < sigma6_min) /* for disappearing coul and vdw with soft core at the same time */
302 sigma6[i] = sigma6_min;
303 sigma2[i] = sigma2_min;
308 sigma6[i] = sigma6_def;
309 sigma2[i] = sigma2_def;
311 if (sc_r_power == 6.0)
313 sigma_pow[i] = sigma6[i];
314 sigma_powm2[i] = sigma6[i]/sigma2[i];
316 else if (sc_r_power == 48.0)
318 sigma_pow[i] = sigma6[i]*sigma6[i]; /* sigma^12 */
319 sigma_pow[i] = sigma_pow[i]*sigma_pow[i]; /* sigma^24 */
320 sigma_pow[i] = sigma_pow[i]*sigma_pow[i]; /* sigma^48 */
321 sigma_powm2[i] = sigma_pow[i]/sigma2[i];
324 { /* not really supported as input, but in here for testing the general case*/
325 sigma_pow[i] = pow(sigma2[i], sc_r_power/2);
326 sigma_powm2[i] = sigma_pow[i]/(sigma2[i]);
330 /* only use softcore if one of the states has a zero endstate - softcore is for avoiding infinities!*/
331 if ((c12[STATE_A] > 0) && (c12[STATE_B] > 0))
338 alpha_vdw_eff = alpha_vdw;
339 alpha_coul_eff = alpha_coul;
342 for (i = 0; i < NSTATES; i++)
349 /* Only spend time on A or B state if it is non-zero */
350 if ( (qq[i] != 0) || (c6[i] != 0) || (c12[i] != 0) )
353 /* this section has to be inside the loop becaue of the dependence on sigma_pow */
354 rpinvC = 1.0/(alpha_coul_eff*lfac_coul[i]*sigma_pow[i]+rp);
355 rinvC = pow(rpinvC, 1.0/sc_r_power);
358 rpinvV = 1.0/(alpha_vdw_eff*lfac_vdw[i]*sigma_pow[i]+rp);
359 rinvV = pow(rpinvV, 1.0/sc_r_power);
368 n1C = tab_elemsize*n0;
374 n1V = tab_elemsize*n0;
377 /* With Ewald and soft-core we should put the cut-off on r,
378 * not on the soft-cored rC, as the real-space and
379 * reciprocal space contributions should (almost) cancel.
382 !(bExactElecCutoff &&
383 ((icoul != GMX_NBKERNEL_ELEC_EWALD && rC >= rcoulomb) ||
384 (icoul == GMX_NBKERNEL_ELEC_EWALD && r >= rcoulomb))))
388 case GMX_NBKERNEL_ELEC_COULOMB:
389 case GMX_NBKERNEL_ELEC_EWALD:
390 /* simple cutoff (yes, ewald is done all on direct space for free energy) */
391 Vcoul[i] = qq[i]*rinvC;
392 FscalC[i] = Vcoul[i]*rpinvC;
395 case GMX_NBKERNEL_ELEC_REACTIONFIELD:
397 Vcoul[i] = qq[i]*(rinvC+krf*rC*rC-crf);
398 FscalC[i] = qq[i]*(rinvC*rpinvC-2.0*krf);
401 case GMX_NBKERNEL_ELEC_CUBICSPLINETABLE:
402 /* non-Ewald tabulated coulomb */
406 Geps = epsC*VFtab[nnn+2];
407 Heps2 = eps2C*VFtab[nnn+3];
410 FF = Fp+Geps+2.0*Heps2;
412 FscalC[i] = -qq[i]*tabscale*FF*rC*rpinvC;
415 case GMX_NBKERNEL_ELEC_GENERALIZEDBORN:
416 gmx_fatal(FARGS, "Free energy and GB not implemented.\n");
419 case GMX_NBKERNEL_ELEC_NONE:
425 gmx_incons("Invalid icoul in free energy kernel");
429 if (fr->coulomb_modifier == eintmodPOTSWITCH)
432 d = (d > 0.0) ? d : 0.0;
434 sw = 1.0+d2*d*(swV3+d*(swV4+d*swV5));
435 dsw = d2*(swF2+d*(swF3+d*swF4));
438 FscalC[i] = FscalC[i]*sw + Vcoul[i]*dsw;
442 if ((c6[i] != 0 || c12[i] != 0) &&
443 !(bExactVdwCutoff && rV >= rvdw))
447 case GMX_NBKERNEL_VDW_LENNARDJONES:
449 if (sc_r_power == 6.0)
455 rinv6 = pow(rinvV, 6.0);
458 Vvdw12 = c12[i]*rinv6*rinv6;
459 if (fr->vdw_modifier == eintmodPOTSHIFT)
461 Vvdw[i] = ( (Vvdw12-c12[i]*sh_invrc6*sh_invrc6)*(1.0/12.0)
462 -(Vvdw6-c6[i]*sh_invrc6)*(1.0/6.0));
466 Vvdw[i] = Vvdw12*(1.0/12.0)-Vvdw6*(1.0/6.0);
468 FscalV[i] = (Vvdw12-Vvdw6)*rpinvV;
471 case GMX_NBKERNEL_VDW_BUCKINGHAM:
472 gmx_fatal(FARGS, "Buckingham free energy not supported.");
475 case GMX_NBKERNEL_VDW_CUBICSPLINETABLE:
481 Geps = epsV*VFtab[nnn+2];
482 Heps2 = eps2V*VFtab[nnn+3];
485 FF = Fp+Geps+2.0*Heps2;
487 FscalV[i] -= c6[i]*tabscale*FF*rV*rpinvV;
492 Geps = epsV*VFtab[nnn+6];
493 Heps2 = eps2V*VFtab[nnn+7];
496 FF = Fp+Geps+2.0*Heps2;
497 Vvdw[i] += c12[i]*VV;
498 FscalV[i] -= c12[i]*tabscale*FF*rV*rpinvV;
501 case GMX_NBKERNEL_VDW_NONE:
507 gmx_incons("Invalid ivdw in free energy kernel");
511 if (fr->vdw_modifier == eintmodPOTSWITCH)
514 d = (d > 0.0) ? d : 0.0;
516 sw = 1.0+d2*d*(swV3+d*(swV4+d*swV5));
517 dsw = d2*(swF2+d*(swF3+d*swF4));
520 FscalV[i] = FscalV[i]*sw + Vvdw[i]*dsw;
522 FscalV[i] = (rV < rvdw) ? FscalV[i] : 0.0;
523 Vvdw[i] = (rV < rvdw) ? Vvdw[i] : 0.0;
531 if (icoul == GMX_NBKERNEL_ELEC_EWALD &&
532 !(bExactElecCutoff && r >= rcoulomb))
534 /* because we compute the softcore normally,
535 we have to remove the ewald short range portion. Done outside of
536 the states loop because this part doesn't depend on the scaled R */
539 /* Relative accuracy at R_ERF_R_INACC of 3e-10 */
540 #define R_ERF_R_INACC 0.006
542 /* Relative accuracy at R_ERF_R_INACC of 2e-5 */
543 #define R_ERF_R_INACC 0.1
545 if (ewc*r > R_ERF_R_INACC)
547 VV = gmx_erf(ewc*r)*rinv;
548 FF = rinv*rinv*(VV - ewc*M_2_SQRTPI*exp(-ewc*ewc*rsq));
553 FF = ewc*ewc*ewc*M_2_SQRTPI*(2.0/3.0 - 0.4*ewc*ewc*rsq);
556 for (i = 0; i < NSTATES; i++)
558 vctot -= LFC[i]*qq[i]*VV;
559 Fscal -= LFC[i]*qq[i]*FF;
560 dvdl_coul -= (DLF[i]*qq[i])*VV;
564 /* Assemble A and B states */
565 for (i = 0; i < NSTATES; i++)
567 vctot += LFC[i]*Vcoul[i];
568 vvtot += LFV[i]*Vvdw[i];
570 Fscal += LFC[i]*FscalC[i]*rpm2;
571 Fscal += LFV[i]*FscalV[i]*rpm2;
573 dvdl_coul += Vcoul[i]*DLF[i] + LFC[i]*alpha_coul_eff*dlfac_coul[i]*FscalC[i]*sigma_pow[i];
574 dvdl_vdw += Vvdw[i]*DLF[i] + LFV[i]*alpha_vdw_eff*dlfac_vdw[i]*FscalV[i]*sigma_pow[i];
586 f[j3+1] = f[j3+1] - ty;
587 f[j3+2] = f[j3+2] - tz;
593 f[ii3] = f[ii3] + fix;
594 f[ii3+1] = f[ii3+1] + fiy;
595 f[ii3+2] = f[ii3+2] + fiz;
596 fshift[is3] = fshift[is3] + fix;
597 fshift[is3+1] = fshift[is3+1] + fiy;
598 fshift[is3+2] = fshift[is3+2] + fiz;
601 Vc[ggid] = Vc[ggid] + vctot;
602 Vv[ggid] = Vv[ggid] + vvtot;
605 dvdl[efptCOUL] += dvdl_coul;
606 dvdl[efptVDW] += dvdl_vdw;
608 /* Estimate flops, average for free energy stuff:
609 * 12 flops per outer iteration
610 * 150 flops per inner iteration
612 inc_nrnb(nrnb, eNR_NBKERNEL_FREE_ENERGY, nlist->nri*12 + nlist->jindex[n]*150);
616 nb_free_energy_evaluate_single(real r2, real sc_r_power, real alpha_coul, real alpha_vdw,
617 real tabscale, real *vftab,
618 real qqA, real c6A, real c12A, real qqB, real c6B, real c12B,
619 real LFC[2], real LFV[2], real DLF[2],
620 real lfac_coul[2], real lfac_vdw[2], real dlfac_coul[2], real dlfac_vdw[2],
621 real sigma6_def, real sigma6_min, real sigma2_def, real sigma2_min,
622 real *velectot, real *vvdwtot, real *dvdl)
624 real r, rp, rpm2, rtab, eps, eps2, Y, F, Geps, Heps2, Fp, VV, FF, fscal;
625 real qq[2], c6[2], c12[2], sigma6[2], sigma2[2], sigma_pow[2], sigma_powm2[2];
626 real alpha_coul_eff, alpha_vdw_eff, dvdl_coul, dvdl_vdw;
627 real rpinv, r_coul, r_vdw, velecsum, vvdwsum;
628 real fscal_vdw[2], fscal_elec[2];
629 real velec[2], vvdw[2];
639 if (sc_r_power == 6.0)
641 rpm2 = r2*r2; /* r4 */
642 rp = rpm2*r2; /* r6 */
644 else if (sc_r_power == 48.0)
646 rp = r2*r2*r2; /* r6 */
647 rp = rp*rp; /* r12 */
648 rp = rp*rp; /* r24 */
649 rp = rp*rp; /* r48 */
650 rpm2 = rp/r2; /* r46 */
654 rp = pow(r2, 0.5*sc_r_power); /* not currently supported as input, but can handle it */
658 /* Loop over state A(0) and B(1) */
659 for (i = 0; i < 2; i++)
661 if ((c6[i] > 0) && (c12[i] > 0))
663 /* The c6 & c12 coefficients now contain the constants 6.0 and 12.0, respectively.
664 * Correct for this by multiplying with (1/12.0)/(1/6.0)=6.0/12.0=0.5.
666 sigma6[i] = 0.5*c12[i]/c6[i];
667 sigma2[i] = pow(0.5*c12[i]/c6[i], 1.0/3.0);
668 /* should be able to get rid of this ^^^ internal pow call eventually. Will require agreement on
669 what data to store externally. Can't be fixed without larger scale changes, so not 4.6 */
670 if (sigma6[i] < sigma6_min) /* for disappearing coul and vdw with soft core at the same time */
672 sigma6[i] = sigma6_min;
673 sigma2[i] = sigma2_min;
678 sigma6[i] = sigma6_def;
679 sigma2[i] = sigma2_def;
681 if (sc_r_power == 6.0)
683 sigma_pow[i] = sigma6[i];
684 sigma_powm2[i] = sigma6[i]/sigma2[i];
686 else if (sc_r_power == 48.0)
688 sigma_pow[i] = sigma6[i]*sigma6[i]; /* sigma^12 */
689 sigma_pow[i] = sigma_pow[i]*sigma_pow[i]; /* sigma^24 */
690 sigma_pow[i] = sigma_pow[i]*sigma_pow[i]; /* sigma^48 */
691 sigma_powm2[i] = sigma_pow[i]/sigma2[i];
694 { /* not really supported as input, but in here for testing the general case*/
695 sigma_pow[i] = pow(sigma2[i], sc_r_power/2);
696 sigma_powm2[i] = sigma_pow[i]/(sigma2[i]);
700 /* only use softcore if one of the states has a zero endstate - softcore is for avoiding infinities!*/
701 if ((c12[0] > 0) && (c12[1] > 0))
708 alpha_vdw_eff = alpha_vdw;
709 alpha_coul_eff = alpha_coul;
712 /* Loop over A and B states again */
713 for (i = 0; i < 2; i++)
720 /* Only spend time on A or B state if it is non-zero */
721 if ( (qq[i] != 0) || (c6[i] != 0) || (c12[i] != 0) )
724 rpinv = 1.0/(alpha_coul_eff*lfac_coul[i]*sigma_pow[i]+rp);
725 r_coul = pow(rpinv, -1.0/sc_r_power);
727 /* Electrostatics table lookup data */
728 rtab = r_coul*tabscale;
736 Geps = eps*vftab[ntab+2];
737 Heps2 = eps2*vftab[ntab+3];
740 FF = Fp+Geps+2.0*Heps2;
742 fscal_elec[i] = -qq[i]*FF*r_coul*rpinv*tabscale;
745 rpinv = 1.0/(alpha_vdw_eff*lfac_vdw[i]*sigma_pow[i]+rp);
746 r_vdw = pow(rpinv, -1.0/sc_r_power);
747 /* Vdw table lookup data */
748 rtab = r_vdw*tabscale;
756 Geps = eps*vftab[ntab+6];
757 Heps2 = eps2*vftab[ntab+7];
760 FF = Fp+Geps+2.0*Heps2;
762 fscal_vdw[i] = -c6[i]*FF;
767 Geps = eps*vftab[ntab+10];
768 Heps2 = eps2*vftab[ntab+11];
771 FF = Fp+Geps+2.0*Heps2;
772 vvdw[i] += c12[i]*VV;
773 fscal_vdw[i] -= c12[i]*FF;
774 fscal_vdw[i] *= r_vdw*rpinv*tabscale;
777 /* Now we have velec[i], vvdw[i], and fscal[i] for both states */
778 /* Assemble A and B states */
784 for (i = 0; i < 2; i++)
786 velecsum += LFC[i]*velec[i];
787 vvdwsum += LFV[i]*vvdw[i];
789 fscal += (LFC[i]*fscal_elec[i]+LFV[i]*fscal_vdw[i])*rpm2;
791 dvdl_coul += velec[i]*DLF[i] + LFC[i]*alpha_coul_eff*dlfac_coul[i]*fscal_elec[i]*sigma_pow[i];
792 dvdl_vdw += vvdw[i]*DLF[i] + LFV[i]*alpha_vdw_eff*dlfac_vdw[i]*fscal_vdw[i]*sigma_pow[i];
795 dvdl[efptCOUL] += dvdl_coul;
796 dvdl[efptVDW] += dvdl_vdw;
798 *velectot = velecsum;