static void fill_table(t_tabledata *td,int tp,const t_forcerec *fr) { /* Fill the table according to the formulas in the manual. * In principle, we only need the potential and the second * derivative, but then we would have to do lots of calculations * in the inner loop. By precalculating some terms (see manual) * we get better eventual performance, despite a larger table. * * Since some of these higher-order terms are very small, * we always use double precision to calculate them here, in order * to avoid unnecessary loss of precision. */ #ifdef DEBUG_SWITCH FILE *fp; #endif int i; double reppow,p; double r1,rc,r12,r13; double r,r2,r6,rc6; double expr,Vtab,Ftab; /* Parameters for David's function */ double A=0,B=0,C=0,A_3=0,B_4=0; /* Parameters for the switching function */ double ksw,swi,swi1; /* Temporary parameters */ gmx_bool bSwitch,bShift; double ewc=fr->ewaldcoeff; double isp= 0.564189583547756; bSwitch = ((tp == etabLJ6Switch) || (tp == etabLJ12Switch) || (tp == etabCOULSwitch) || (tp == etabEwaldSwitch) || (tp == etabEwaldUserSwitch)); bShift = ((tp == etabLJ6Shift) || (tp == etabLJ12Shift) || (tp == etabShift)); reppow = fr->reppow; if (tprops[tp].bCoulomb) { r1 = fr->rcoulomb_switch; rc = fr->rcoulomb; } else { r1 = fr->rvdw_switch; rc = fr->rvdw; } if (bSwitch) ksw = 1.0/(pow5(rc-r1)); else ksw = 0.0; if (bShift) { if (tp == etabShift) p = 1; else if (tp == etabLJ6Shift) p = 6; else p = reppow; A = p * ((p+1)*r1-(p+4)*rc)/(pow(rc,p+2)*pow2(rc-r1)); B = -p * ((p+1)*r1-(p+3)*rc)/(pow(rc,p+2)*pow3(rc-r1)); C = 1.0/pow(rc,p)-A/3.0*pow3(rc-r1)-B/4.0*pow4(rc-r1); if (tp == etabLJ6Shift) { A=-A; B=-B; C=-C; } A_3=A/3.0; B_4=B/4.0; } if (debug) { fprintf(debug,"Setting up tables\n"); fflush(debug); } #ifdef DEBUG_SWITCH fp=xvgropen("switch.xvg","switch","r","s"); #endif for(i=td->nx0; (i<td->nx); i++) { r = td->x[i]; r2 = r*r; r6 = 1.0/(r2*r2*r2); if (gmx_within_tol(reppow,12.0,10*GMX_DOUBLE_EPS)) { r12 = r6*r6; } else { r12 = pow(r,-reppow); } Vtab = 0.0; Ftab = 0.0; if (bSwitch) { /* swi is function, swi1 1st derivative and swi2 2nd derivative */ /* The switch function is 1 for r<r1, 0 for r>rc, and smooth for * r1<=r<=rc. The 1st and 2nd derivatives are both zero at * r1 and rc. * ksw is just the constant 1/(rc-r1)^5, to save some calculations... */ if(r<=r1) { swi = 1.0; swi1 = 0.0; } else if (r>=rc) { swi = 0.0; swi1 = 0.0; } else { swi = 1 - 10*pow3(r-r1)*ksw*pow2(rc-r1) + 15*pow4(r-r1)*ksw*(rc-r1) - 6*pow5(r-r1)*ksw; swi1 = -30*pow2(r-r1)*ksw*pow2(rc-r1) + 60*pow3(r-r1)*ksw*(rc-r1) - 30*pow4(r-r1)*ksw; } } else { /* not really needed, but avoids compiler warnings... */ swi = 1.0; swi1 = 0.0; } #ifdef DEBUG_SWITCH fprintf(fp,"%10g %10g %10g %10g\n",r,swi,swi1,swi2); #endif rc6 = rc*rc*rc; rc6 = 1.0/(rc6*rc6); switch (tp) { case etabLJ6: /* Dispersion */ Vtab = -r6; Ftab = 6.0*Vtab/r; break; case etabLJ6Switch: case etabLJ6Shift: /* Dispersion */ if (r < rc) { Vtab = -r6; Ftab = 6.0*Vtab/r; } break; case etabLJ12: /* Repulsion */ Vtab = r12; Ftab = reppow*Vtab/r; break; case etabLJ12Switch: case etabLJ12Shift: /* Repulsion */ if (r < rc) { Vtab = r12; Ftab = reppow*Vtab/r; } break; case etabLJ6Encad: if(r < rc) { Vtab = -(r6-6.0*(rc-r)*rc6/rc-rc6); Ftab = -(6.0*r6/r-6.0*rc6/rc); } else { /* r>rc */ Vtab = 0; Ftab = 0; } break; case etabLJ12Encad: if(r < rc) { Vtab = r12-12.0*(rc-r)*rc6*rc6/rc-1.0*rc6*rc6; Ftab = 12.0*r12/r-12.0*rc6*rc6/rc; } else { /* r>rc */ Vtab = 0; Ftab = 0; } break; case etabCOUL: Vtab = 1.0/r; Ftab = 1.0/r2; break; case etabCOULSwitch: case etabShift: if (r < rc) { Vtab = 1.0/r; Ftab = 1.0/r2; } break; case etabEwald: case etabEwaldSwitch: Vtab = gmx_erfc(ewc*r)/r; Ftab = gmx_erfc(ewc*r)/r2+2*exp(-(ewc*ewc*r2))*ewc*isp/r; break; case etabEwaldUser: case etabEwaldUserSwitch: /* Only calculate minus the reciprocal space contribution */ Vtab = -gmx_erf(ewc*r)/r; Ftab = -gmx_erf(ewc*r)/r2+2*exp(-(ewc*ewc*r2))*ewc*isp/r; break; case etabRF: case etabRF_ZERO: Vtab = 1.0/r + fr->k_rf*r2 - fr->c_rf; Ftab = 1.0/r2 - 2*fr->k_rf*r; if (tp == etabRF_ZERO && r >= rc) { Vtab = 0; Ftab = 0; } break; case etabEXPMIN: expr = exp(-r); Vtab = expr; Ftab = expr; break; case etabCOULEncad: if(r < rc) { Vtab = 1.0/r-(rc-r)/(rc*rc)-1.0/rc; Ftab = 1.0/r2-1.0/(rc*rc); } else { /* r>rc */ Vtab = 0; Ftab = 0; } break; default: gmx_fatal(FARGS,"Table type %d not implemented yet. (%s,%d)", tp,__FILE__,__LINE__); } if (bShift) { /* Normal coulomb with cut-off correction for potential */ if (r < rc) { Vtab -= C; /* If in Shifting range add something to it */ if (r > r1) { r12 = (r-r1)*(r-r1); r13 = (r-r1)*r12; Vtab += - A_3*r13 - B_4*r12*r12; Ftab += A*r12 + B*r13; } } } if (ETAB_USER(tp)) { Vtab += td->v[i]; Ftab += td->f[i]; } if ((r > r1) && bSwitch) { Ftab = Ftab*swi - Vtab*swi1; Vtab = Vtab*swi; } /* Convert to single precision when we store to mem */ td->v[i] = Vtab; td->f[i] = Ftab; } /* Continue the table linearly from nx0 to 0. * These values are only required for energy minimization with overlap or TPI. */ for(i=td->nx0-1; i>=0; i--) { td->v[i] = td->v[i+1] + td->f[i+1]*(td->x[i+1] - td->x[i]); td->f[i] = td->f[i+1]; } #ifdef DEBUG_SWITCH gmx_fio_fclose(fp); #endif }
t_forcetable make_tables(FILE *out,const output_env_t oenv, const t_forcerec *fr, gmx_bool bVerbose,const char *fn, real rtab,int flags) { const char *fns[3] = { "ctab.xvg", "dtab.xvg", "rtab.xvg" }; const char *fns14[3] = { "ctab14.xvg", "dtab14.xvg", "rtab14.xvg" }; FILE *fp; t_tabledata *td; gmx_bool b14only,bReadTab,bGenTab; real x0,y0,yp; int i,j,k,nx,nx0,tabsel[etiNR]; t_forcetable table; b14only = (flags & GMX_MAKETABLES_14ONLY); if (flags & GMX_MAKETABLES_FORCEUSER) { tabsel[etiCOUL] = etabUSER; tabsel[etiLJ6] = etabUSER; tabsel[etiLJ12] = etabUSER; } else { set_table_type(tabsel,fr,b14only); } snew(td,etiNR); table.r = rtab; table.scale = 0; table.n = 0; table.scale_exp = 0; nx0 = 10; nx = 0; /* Check whether we have to read or generate */ bReadTab = FALSE; bGenTab = FALSE; for(i=0; (i<etiNR); i++) { if (ETAB_USER(tabsel[i])) bReadTab = TRUE; if (tabsel[i] != etabUSER) bGenTab = TRUE; } if (bReadTab) { read_tables(out,fn,etiNR,0,td); if (rtab == 0 || (flags & GMX_MAKETABLES_14ONLY)) { rtab = td[0].x[td[0].nx-1]; table.n = td[0].nx; nx = table.n; } else { if (td[0].x[td[0].nx-1] < rtab) gmx_fatal(FARGS,"Tables in file %s not long enough for cut-off:\n" "\tshould be at least %f nm\n",fn,rtab); nx = table.n = (int)(rtab*td[0].tabscale + 0.5); } table.scale = td[0].tabscale; nx0 = td[0].nx0; } if (bGenTab) { if (!bReadTab) { #ifdef GMX_DOUBLE table.scale = 2000.0; #else table.scale = 500.0; #endif nx = table.n = rtab*table.scale; } } if (fr->bBHAM) { if(fr->bham_b_max!=0) table.scale_exp = table.scale/fr->bham_b_max; else table.scale_exp = table.scale; } /* Each table type (e.g. coul,lj6,lj12) requires four * numbers per nx+1 data points. For performance reasons we want * the table data to be aligned to 16-byte. */ snew_aligned(table.tab, 12*(nx+1)*sizeof(real),16); for(k=0; (k<etiNR); k++) { if (tabsel[k] != etabUSER) { init_table(out,nx,nx0, (tabsel[k] == etabEXPMIN) ? table.scale_exp : table.scale, &(td[k]),!bReadTab); fill_table(&(td[k]),tabsel[k],fr); if (out) fprintf(out,"%s table with %d data points for %s%s.\n" "Tabscale = %g points/nm\n", ETAB_USER(tabsel[k]) ? "Modified" : "Generated", td[k].nx,b14only?"1-4 ":"",tprops[tabsel[k]].name, td[k].tabscale); } copy2table(table.n,k*4,12,td[k].x,td[k].v,td[k].f,table.tab); if (bDebugMode() && bVerbose) { if (b14only) fp=xvgropen(fns14[k],fns14[k],"r","V",oenv); else fp=xvgropen(fns[k],fns[k],"r","V",oenv); /* plot the output 5 times denser than the table data */ for(i=5*((nx0+1)/2); i<5*table.n; i++) { x0 = i*table.r/(5*(table.n-1)); evaluate_table(table.tab,4*k,12,table.scale,x0,&y0,&yp); fprintf(fp,"%15.10e %15.10e %15.10e\n",x0,y0,yp); } gmx_fio_fclose(fp); } done_tabledata(&(td[k])); } sfree(td); return table; }
t_forcetable make_tables(FILE *out,const output_env_t oenv, const t_forcerec *fr, gmx_bool bVerbose,const char *fn, real rtab,int flags) { const char *fns[3] = { "ctab.xvg", "dtab.xvg", "rtab.xvg" }; const char *fns14[3] = { "ctab14.xvg", "dtab14.xvg", "rtab14.xvg" }; FILE *fp; t_tabledata *td; gmx_bool b14only,bReadTab,bGenTab; real x0,y0,yp; int i,j,k,nx,nx0,tabsel[etiNR]; real scalefactor; t_forcetable table; b14only = (flags & GMX_MAKETABLES_14ONLY); if (flags & GMX_MAKETABLES_FORCEUSER) { tabsel[etiCOUL] = etabUSER; tabsel[etiLJ6] = etabUSER; tabsel[etiLJ12] = etabUSER; } else { set_table_type(tabsel,fr,b14only); } snew(td,etiNR); table.r = rtab; table.scale = 0; table.n = 0; table.scale_exp = 0; nx0 = 10; nx = 0; table.interaction = GMX_TABLE_INTERACTION_ELEC_VDWREP_VDWDISP; table.format = GMX_TABLE_FORMAT_CUBICSPLINE_YFGH; table.formatsize = 4; table.ninteractions = 3; table.stride = table.formatsize*table.ninteractions; /* Check whether we have to read or generate */ bReadTab = FALSE; bGenTab = FALSE; for(i=0; (i<etiNR); i++) { if (ETAB_USER(tabsel[i])) bReadTab = TRUE; if (tabsel[i] != etabUSER) bGenTab = TRUE; } if (bReadTab) { read_tables(out,fn,etiNR,0,td); if (rtab == 0 || (flags & GMX_MAKETABLES_14ONLY)) { rtab = td[0].x[td[0].nx-1]; table.n = td[0].nx; nx = table.n; } else { if (td[0].x[td[0].nx-1] < rtab) gmx_fatal(FARGS,"Tables in file %s not long enough for cut-off:\n" "\tshould be at least %f nm\n",fn,rtab); nx = table.n = (int)(rtab*td[0].tabscale + 0.5); } table.scale = td[0].tabscale; nx0 = td[0].nx0; } if (bGenTab) { if (!bReadTab) { #ifdef GMX_DOUBLE table.scale = 2000.0; #else table.scale = 500.0; #endif nx = table.n = rtab*table.scale; } } if (fr->bBHAM) { if(fr->bham_b_max!=0) table.scale_exp = table.scale/fr->bham_b_max; else table.scale_exp = table.scale; } /* Each table type (e.g. coul,lj6,lj12) requires four * numbers per nx+1 data points. For performance reasons we want * the table data to be aligned to 16-byte. */ snew_aligned(table.data, 12*(nx+1)*sizeof(real),16); for(k=0; (k<etiNR); k++) { if (tabsel[k] != etabUSER) { init_table(out,nx,nx0, (tabsel[k] == etabEXPMIN) ? table.scale_exp : table.scale, &(td[k]),!bReadTab); fill_table(&(td[k]),tabsel[k],fr); if (out) fprintf(out,"%s table with %d data points for %s%s.\n" "Tabscale = %g points/nm\n", ETAB_USER(tabsel[k]) ? "Modified" : "Generated", td[k].nx,b14only?"1-4 ":"",tprops[tabsel[k]].name, td[k].tabscale); } /* Set scalefactor for c6/c12 tables. This is because we save flops in the non-table kernels * by including the derivative constants (6.0 or 12.0) in the parameters, since * we no longer calculate force in most steps. This means the c6/c12 parameters * have been scaled up, so we need to scale down the table interactions too. * It comes here since we need to scale user tables too. */ if(k==etiLJ6) { scalefactor = 1.0/6.0; } else if(k==etiLJ12 && tabsel[k]!=etabEXPMIN) { scalefactor = 1.0/12.0; } else { scalefactor = 1.0; } copy2table(table.n,k*4,12,td[k].x,td[k].v,td[k].f,scalefactor,table.data); if (bDebugMode() && bVerbose) { if (b14only) fp=xvgropen(fns14[k],fns14[k],"r","V",oenv); else fp=xvgropen(fns[k],fns[k],"r","V",oenv); /* plot the output 5 times denser than the table data */ for(i=5*((nx0+1)/2); i<5*table.n; i++) { x0 = i*table.r/(5*(table.n-1)); evaluate_table(table.data,4*k,12,table.scale,x0,&y0,&yp); fprintf(fp,"%15.10e %15.10e %15.10e\n",x0,y0,yp); } gmx_fio_fclose(fp); } done_tabledata(&(td[k])); } sfree(td); return table; }