static void calc_virial(FILE *fplog,int start,int homenr,rvec x[],rvec f[], tensor vir_part,t_graph *graph,matrix box, t_nrnb *nrnb,const t_forcerec *fr,int ePBC) { int i,j; tensor virtest; /* The short-range virial from surrounding boxes */ clear_mat(vir_part); calc_vir(fplog,SHIFTS,fr->shift_vec,fr->fshift,vir_part,ePBC==epbcSCREW,box); inc_nrnb(nrnb,eNR_VIRIAL,SHIFTS); /* Calculate partial virial, for local atoms only, based on short range. * Total virial is computed in global_stat, called from do_md */ f_calc_vir(fplog,start,start+homenr,x,f,vir_part,graph,box); inc_nrnb(nrnb,eNR_VIRIAL,homenr); /* Add position restraint contribution */ for(i=0; i<DIM; i++) { vir_part[i][i] += fr->vir_diag_posres[i]; } /* Add wall contribution */ for(i=0; i<DIM; i++) { vir_part[i][ZZ] += fr->vir_wall_z[i]; } if (debug) pr_rvecs(debug,0,"vir_part",vir_part,DIM); }
void solve_pppm(FILE *fp,t_commrec *cr, t_fftgrid *grid,real ***ghat,rvec box, bool bVerbose,t_nrnb *nrnb) { int ntot,npppm; /* if (bVerbose) print_fftgrid(fp,"Q-Real",grid,grid->nxyz,"qreal.pdb",box,TRUE);*/ gmxfft3D(grid,FFTW_FORWARD,cr); /* if (bVerbose) { print_fftgrid(fp,"Q-k",grid,1.0,"qk-re.pdb",box,TRUE); print_fftgrid(fp,"Q-k",grid,1.0,"qk-im.pdb",box,FALSE); fprintf(stderr,"Doing convolution\n"); }*/ convolution(fp,bVerbose,grid,ghat,cr); if (bVerbose) /* print_fftgrid(fp,"Convolution",grid,1.0, "convolute.pdb",box,TRUE);*/ gmxfft3D(grid,FFTW_BACKWARD,cr); /* if (bVerbose) print_fftgrid(fp,"Potential",grid,1.0,"pot.pdb",box,TRUE);*/ ntot = grid->nxyz; npppm = ntot*log((real)ntot)/log(2.0); inc_nrnb(nrnb,eNR_FFT,2*npppm); inc_nrnb(nrnb,eNR_CONV,ntot); }
void berendsen_pscale(t_inputrec *ir,matrix mu, matrix box,matrix box_rel, int start,int nr_atoms, rvec x[],unsigned short cFREEZE[], t_nrnb *nrnb) { ivec *nFreeze=ir->opts.nFreeze; int n,d,g=0; /* Scale the positions */ for (n=start; n<start+nr_atoms; n++) { if (cFREEZE) g = cFREEZE[n]; if (!nFreeze[g][XX]) x[n][XX] = mu[XX][XX]*x[n][XX]+mu[YY][XX]*x[n][YY]+mu[ZZ][XX]*x[n][ZZ]; if (!nFreeze[g][YY]) x[n][YY] = mu[YY][YY]*x[n][YY]+mu[ZZ][YY]*x[n][ZZ]; if (!nFreeze[g][ZZ]) x[n][ZZ] = mu[ZZ][ZZ]*x[n][ZZ]; } /* compute final boxlengths */ for (d=0; d<DIM; d++) { box[d][XX] = mu[XX][XX]*box[d][XX]+mu[YY][XX]*box[d][YY]+mu[ZZ][XX]*box[d][ZZ]; box[d][YY] = mu[YY][YY]*box[d][YY]+mu[ZZ][YY]*box[d][ZZ]; box[d][ZZ] = mu[ZZ][ZZ]*box[d][ZZ]; } preserve_box_shape(ir,box_rel,box); /* (un)shifting should NOT be done after this, * since the box vectors might have changed */ inc_nrnb(nrnb,eNR_PCOUPL,nr_atoms); }
void posres_wrapper(t_nrnb *nrnb, const t_idef *idef, const struct t_pbc *pbc, const rvec x[], gmx_enerdata_t *enerd, real *lambda, t_forcerec *fr) { real v, dvdl; dvdl = 0; v = posres(idef->il[F_POSRES].nr, idef->il[F_POSRES].iatoms, idef->iparams_posres, x, fr->f_novirsum, fr->vir_diag_posres, fr->ePBC == epbcNONE ? NULL : pbc, lambda[efptRESTRAINT], &dvdl, fr->rc_scaling, fr->ePBC, fr->posres_com, fr->posres_comB); enerd->term[F_POSRES] += v; /* If just the force constant changes, the FEP term is linear, * but if k changes, it is not. */ enerd->dvdl_nonlin[efptRESTRAINT] += dvdl; inc_nrnb(nrnb, eNR_POSRES, idef->il[F_POSRES].nr/2); }
void calc_ke_part_visc(matrix box,rvec x[],rvec v[], t_grpopts *opts,t_mdatoms *md, gmx_ekindata_t *ekind, t_nrnb *nrnb,real lambda) { int start=md->start,homenr=md->homenr; int g,d,n,gt=0; rvec v_corrt; real hm; t_grp_tcstat *tcstat=ekind->tcstat; t_cos_acc *cosacc=&(ekind->cosacc); real dekindl; real fac,cosz; double mvcos; for(g=0; g<opts->ngtc; g++) { copy_mat(ekind->tcstat[g].ekinh,ekind->tcstat[g].ekinh_old); clear_mat(ekind->tcstat[g].ekinh); } ekind->dekindl_old = ekind->dekindl; fac = 2*M_PI/box[ZZ][ZZ]; mvcos = 0; dekindl = 0; for(n=start; n<start+homenr; n++) { if (md->cTC) gt = md->cTC[n]; hm = 0.5*md->massT[n]; /* Note that the times of x and v differ by half a step */ cosz = cos(fac*x[n][ZZ]); /* Calculate the amplitude of the new velocity profile */ mvcos += 2*cosz*md->massT[n]*v[n][XX]; copy_rvec(v[n],v_corrt); /* Subtract the profile for the kinetic energy */ v_corrt[XX] -= cosz*cosacc->vcos; for(d=0; (d<DIM); d++) { tcstat[gt].ekinh[XX][d]+=hm*v_corrt[XX]*v_corrt[d]; tcstat[gt].ekinh[YY][d]+=hm*v_corrt[YY]*v_corrt[d]; tcstat[gt].ekinh[ZZ][d]+=hm*v_corrt[ZZ]*v_corrt[d]; } if(md->nPerturbed && md->bPerturbed[n]) dekindl -= 0.5*(md->massB[n] - md->massA[n])*iprod(v_corrt,v_corrt); } ekind->dekindl = dekindl; cosacc->mvcos = mvcos; inc_nrnb(nrnb,eNR_EKIN,homenr); }
/*! \brief Helper function that wraps calls to fbposres for free-energy perturbation */ void fbposres_wrapper(t_nrnb *nrnb, const t_idef *idef, const struct t_pbc *pbc, const rvec x[], gmx_enerdata_t *enerd, t_forcerec *fr) { real v; v = fbposres(idef->il[F_FBPOSRES].nr, idef->il[F_FBPOSRES].iatoms, idef->iparams_fbposres, x, fr->f_novirsum, fr->vir_diag_posres, fr->ePBC == epbcNONE ? NULL : pbc, fr->rc_scaling, fr->ePBC, fr->posres_com); enerd->term[F_FBPOSRES] += v; inc_nrnb(nrnb, eNR_FBPOSRES, idef->il[F_FBPOSRES].nr/2); }
void calc_ke_part(rvec v[],t_grpopts *opts,t_mdatoms *md, gmx_ekindata_t *ekind, t_nrnb *nrnb,real lambda) { int start=md->start,homenr=md->homenr; int g,d,n,ga=0,gt=0; rvec v_corrt; real hm; t_grp_tcstat *tcstat=ekind->tcstat; t_grp_acc *grpstat=ekind->grpstat; real dekindl; /* group velocities are calculated in update_ekindata and * accumulated in acumulate_groups. * Now the partial global and groups ekin. */ for(g=0; (g<opts->ngtc); g++) { copy_mat(ekind->tcstat[g].ekinh,ekind->tcstat[g].ekinh_old); clear_mat(ekind->tcstat[g].ekinh); } ekind->dekindl_old = ekind->dekindl; dekindl = 0; for(n=start; (n<start+homenr); n++) { if (md->cACC) ga = md->cACC[n]; if (md->cTC) gt = md->cTC[n]; hm = 0.5*md->massT[n]; for(d=0; (d<DIM); d++) { v_corrt[d] = v[n][d] - grpstat[ga].u[d]; } for(d=0; (d<DIM); d++) { tcstat[gt].ekinh[XX][d]+=hm*v_corrt[XX]*v_corrt[d]; tcstat[gt].ekinh[YY][d]+=hm*v_corrt[YY]*v_corrt[d]; tcstat[gt].ekinh[ZZ][d]+=hm*v_corrt[ZZ]*v_corrt[d]; } if (md->nMassPerturbed && md->bPerturbed[n]) dekindl -= 0.5*(md->massB[n] - md->massA[n])*iprod(v_corrt,v_corrt); } ekind->dekindl = dekindl; inc_nrnb(nrnb,eNR_EKIN,homenr); }
void calc_virial(FILE *log,int start,int homenr,rvec x[],rvec f[], tensor vir_part,tensor pme_vir, t_graph *graph,matrix box, t_nrnb *nrnb,t_forcerec *fr,bool bTweak) { int i,j; tensor virtest; /* Now it is time for the short range virial. At this timepoint vir_part * already contains the virial from surrounding boxes. * Calculate partial virial, for local atoms only, based on short range. * Total virial is computed in global_stat, called from do_md */ f_calc_vir(log,start,start+homenr,x,f,vir_part,graph,box); inc_nrnb(nrnb,eNR_VIRIAL,homenr); /* Add up the long range forces if necessary */ /* if (!bTweak) { sum_lrforces(f,fr,start,homenr); }*/ /* Add up virial if necessary */ if (EEL_LR(fr->eeltype) && (fr->eeltype != eelPPPM)) { if (debug && bTweak) { clear_mat(virtest); f_calc_vir(log,start,start+homenr,x,fr->f_pme,virtest,graph,box); pr_rvecs(debug,0,"virtest",virtest,DIM); pr_rvecs(debug,0,"pme_vir",pme_vir,DIM); } /* PPPM virial sucks */ if (!bTweak) for(i=0; (i<DIM); i++) for(j=0; (j<DIM); j++) vir_part[i][j]+=pme_vir[i][j]; } if (debug) pr_rvecs(debug,0,"vir_part",vir_part,DIM); }
gmx_bool constrain_lincs(FILE *fplog,gmx_bool bLog,gmx_bool bEner, t_inputrec *ir, gmx_large_int_t step, struct gmx_lincsdata *lincsd,t_mdatoms *md, t_commrec *cr, rvec *x,rvec *xprime,rvec *min_proj,matrix box, real lambda,real *dvdlambda, real invdt,rvec *v, gmx_bool bCalcVir,tensor rmdr, int econq, t_nrnb *nrnb, int maxwarn,int *warncount) { char buf[STRLEN],buf2[22],buf3[STRLEN]; int i,warn,p_imax,error; real ncons_loc,p_ssd,p_max; t_pbc pbc,*pbc_null; rvec dx; gmx_bool bOK; bOK = TRUE; if (lincsd->nc == 0 && cr->dd == NULL) { if (bLog || bEner) { lincsd->rmsd_data[0] = 0; if (ir->eI == eiSD2 && v == NULL) { i = 2; } else { i = 1; } lincsd->rmsd_data[i] = 0; } return bOK; } /* We do not need full pbc when constraints do not cross charge groups, * i.e. when dd->constraint_comm==NULL */ if ((cr->dd || ir->bPeriodicMols) && !(cr->dd && cr->dd->constraint_comm==NULL)) { /* With pbc=screw the screw has been changed to a shift * by the constraint coordinate communication routine, * so that here we can use normal pbc. */ pbc_null = set_pbc_dd(&pbc,ir->ePBC,cr->dd,FALSE,box); } else { pbc_null = NULL; } if (cr->dd) { /* Communicate the coordinates required for the non-local constraints */ dd_move_x_constraints(cr->dd,box,x,xprime); /* dump_conf(dd,lincsd,NULL,"con",TRUE,xprime,box); */ } else if (PARTDECOMP(cr)) { pd_move_x_constraints(cr,x,xprime); } if (econq == econqCoord) { if (ir->efep != efepNO) { if (md->nMassPerturbed && lincsd->matlam != md->lambda) { set_lincs_matrix(lincsd,md->invmass,md->lambda); } for(i=0; i<lincsd->nc; i++) { lincsd->bllen[i] = lincsd->bllen0[i] + lambda*lincsd->ddist[i]; } } if (lincsd->ncg_flex) { /* Set the flexible constraint lengths to the old lengths */ if (pbc_null) { for(i=0; i<lincsd->nc; i++) { if (lincsd->bllen[i] == 0) { pbc_dx_aiuc(pbc_null,x[lincsd->bla[2*i]],x[lincsd->bla[2*i+1]],dx); lincsd->bllen[i] = norm(dx); } } } else { for(i=0; i<lincsd->nc; i++) { if (lincsd->bllen[i] == 0) { lincsd->bllen[i] = sqrt(distance2(x[lincsd->bla[2*i]], x[lincsd->bla[2*i+1]])); } } } } if (bLog && fplog) { cconerr(cr->dd,lincsd->nc,lincsd->bla,lincsd->bllen,xprime,pbc_null, &ncons_loc,&p_ssd,&p_max,&p_imax); } do_lincs(x,xprime,box,pbc_null,lincsd,md->invmass,cr, ir->LincsWarnAngle,&warn, invdt,v,bCalcVir,rmdr); if (ir->efep != efepNO) { real dt_2,dvdl=0; dt_2 = 1.0/(ir->delta_t*ir->delta_t); for(i=0; (i<lincsd->nc); i++) { dvdl += lincsd->lambda[i]*dt_2*lincsd->ddist[i]; } *dvdlambda += dvdl; } if (bLog && fplog && lincsd->nc > 0) { fprintf(fplog," Rel. Constraint Deviation: RMS MAX between atoms\n"); fprintf(fplog," Before LINCS %.6f %.6f %6d %6d\n", sqrt(p_ssd/ncons_loc),p_max, ddglatnr(cr->dd,lincsd->bla[2*p_imax]), ddglatnr(cr->dd,lincsd->bla[2*p_imax+1])); } if (bLog || bEner) { cconerr(cr->dd,lincsd->nc,lincsd->bla,lincsd->bllen,xprime,pbc_null, &ncons_loc,&p_ssd,&p_max,&p_imax); /* Check if we are doing the second part of SD */ if (ir->eI == eiSD2 && v == NULL) { i = 2; } else { i = 1; } lincsd->rmsd_data[0] = ncons_loc; lincsd->rmsd_data[i] = p_ssd; } else { lincsd->rmsd_data[0] = 0; lincsd->rmsd_data[1] = 0; lincsd->rmsd_data[2] = 0; } if (bLog && fplog && lincsd->nc > 0) { fprintf(fplog, " After LINCS %.6f %.6f %6d %6d\n\n", sqrt(p_ssd/ncons_loc),p_max, ddglatnr(cr->dd,lincsd->bla[2*p_imax]), ddglatnr(cr->dd,lincsd->bla[2*p_imax+1])); } if (warn > 0) { if (maxwarn >= 0) { cconerr(cr->dd,lincsd->nc,lincsd->bla,lincsd->bllen,xprime,pbc_null, &ncons_loc,&p_ssd,&p_max,&p_imax); if (MULTISIM(cr)) { sprintf(buf3," in simulation %d", cr->ms->sim); } else { buf3[0] = 0; } sprintf(buf,"\nStep %s, time %g (ps) LINCS WARNING%s\n" "relative constraint deviation after LINCS:\n" "rms %.6f, max %.6f (between atoms %d and %d)\n", gmx_step_str(step,buf2),ir->init_t+step*ir->delta_t, buf3, sqrt(p_ssd/ncons_loc),p_max, ddglatnr(cr->dd,lincsd->bla[2*p_imax]), ddglatnr(cr->dd,lincsd->bla[2*p_imax+1])); if (fplog) { fprintf(fplog,"%s",buf); } fprintf(stderr,"%s",buf); lincs_warning(fplog,cr->dd,x,xprime,pbc_null, lincsd->nc,lincsd->bla,lincsd->bllen, ir->LincsWarnAngle,maxwarn,warncount); } bOK = (p_max < 0.5); } if (lincsd->ncg_flex) { for(i=0; (i<lincsd->nc); i++) if (lincsd->bllen0[i] == 0 && lincsd->ddist[i] == 0) lincsd->bllen[i] = 0; } } else { do_lincsp(x,xprime,min_proj,pbc_null,lincsd,md->invmass,econq,dvdlambda, bCalcVir,rmdr); } /* count assuming nit=1 */ inc_nrnb(nrnb,eNR_LINCS,lincsd->nc); inc_nrnb(nrnb,eNR_LINCSMAT,(2+lincsd->nOrder)*lincsd->ncc); if (lincsd->ntriangle > 0) { inc_nrnb(nrnb,eNR_LINCSMAT,lincsd->nOrder*lincsd->ncc_triangle); } if (v) { inc_nrnb(nrnb,eNR_CONSTR_V,lincsd->nc*2); } if (bCalcVir) { inc_nrnb(nrnb,eNR_CONSTR_VIR,lincsd->nc); } return bOK; }
void gmx_nb_generic_kernel(t_nblist * nlist, rvec * xx, rvec * ff, t_forcerec * fr, t_mdatoms * mdatoms, nb_kernel_data_t * kernel_data, t_nrnb * nrnb) { int ntype, table_nelements, ielec, ivdw; real facel; int n, ii, is3, ii3, k, nj0, nj1, jnr, j3, ggid, nnn, n0; real shX, shY, shZ; real fscal, felec, fvdw, velec, vvdw, tx, ty, tz; real rinvsq; real iq; real qq, vctot; int nti, nvdwparam; int tj; real rt, r, eps, eps2, Y, F, Geps, Heps2, VV, FF, Fp, fijD, fijR; real rinvsix; real vvdwtot; real vvdw_rep, vvdw_disp; real ix, iy, iz, fix, fiy, fiz; real jx, jy, jz; real dx, dy, dz, rsq, rinv; real c6, c12, c6grid, cexp1, cexp2, br; real * charge; real * shiftvec; real * vdwparam, *vdwgridparam; int * type; real * fshift; real * velecgrp; real * vvdwgrp; real tabscale; real * VFtab; real * x; real * f; int ewitab; real ewtabscale, eweps, ewrt, ewtabhalfspace; real * ewtab; real rcoulomb2, rvdw, rvdw2, sh_dispersion, sh_repulsion; real rcutoff, rcutoff2; real d, d2, sw, dsw, rinvcorr; real elec_swV3, elec_swV4, elec_swV5, elec_swF2, elec_swF3, elec_swF4; real vdw_swV3, vdw_swV4, vdw_swV5, vdw_swF2, vdw_swF3, vdw_swF4; real ewclj, ewclj2, ewclj6, ewcljrsq, poly, exponent, sh_lj_ewald; gmx_bool bExactElecCutoff, bExactVdwCutoff, bExactCutoff; gmx_bool do_tab; #ifdef BUILD_WITH_FDA FDA * fda; real pf_coul, pf_vdw; fda = fr->fda; pf_coul = 0.0; pf_vdw = 0.0; #endif x = xx[0]; f = ff[0]; ielec = nlist->ielec; ivdw = nlist->ivdw; fshift = fr->fshift[0]; velecgrp = kernel_data->energygrp_elec; vvdwgrp = kernel_data->energygrp_vdw; do_tab = (ielec == GMX_NBKERNEL_ELEC_CUBICSPLINETABLE || ivdw == GMX_NBKERNEL_VDW_CUBICSPLINETABLE); if (do_tab) { tabscale = kernel_data->table_elec_vdw->scale; VFtab = kernel_data->table_elec_vdw->data; } else { tabscale = 0; VFtab = nullptr; } const interaction_const_t *ic = fr->ic; ewtab = ic->tabq_coul_FDV0; ewtabscale = ic->tabq_scale; ewtabhalfspace = 0.5/ewtabscale; rcoulomb2 = ic->rcoulomb*ic->rcoulomb; rvdw = ic->rvdw; rvdw2 = rvdw*rvdw; sh_dispersion = ic->dispersion_shift.cpot; sh_repulsion = ic->repulsion_shift.cpot; sh_lj_ewald = ic->sh_lj_ewald; ewclj = ic->ewaldcoeff_lj; ewclj2 = ewclj*ewclj; ewclj6 = ewclj2*ewclj2*ewclj2; if (ic->coulomb_modifier == eintmodPOTSWITCH) { d = ic->rcoulomb - ic->rcoulomb_switch; elec_swV3 = -10.0/(d*d*d); elec_swV4 = 15.0/(d*d*d*d); elec_swV5 = -6.0/(d*d*d*d*d); elec_swF2 = -30.0/(d*d*d); elec_swF3 = 60.0/(d*d*d*d); elec_swF4 = -30.0/(d*d*d*d*d); } else { /* Avoid warnings from stupid compilers (looking at you, Clang!) */ elec_swV3 = elec_swV4 = elec_swV5 = elec_swF2 = elec_swF3 = elec_swF4 = 0.0; } if (ic->vdw_modifier == eintmodPOTSWITCH) { d = ic->rvdw - ic->rvdw_switch; vdw_swV3 = -10.0/(d*d*d); vdw_swV4 = 15.0/(d*d*d*d); vdw_swV5 = -6.0/(d*d*d*d*d); vdw_swF2 = -30.0/(d*d*d); vdw_swF3 = 60.0/(d*d*d*d); vdw_swF4 = -30.0/(d*d*d*d*d); } else { /* Avoid warnings from stupid compilers (looking at you, Clang!) */ vdw_swV3 = vdw_swV4 = vdw_swV5 = vdw_swF2 = vdw_swF3 = vdw_swF4 = 0.0; } bExactElecCutoff = (ic->coulomb_modifier != eintmodNONE) || ic->eeltype == eelRF_ZERO; bExactVdwCutoff = (ic->vdw_modifier != eintmodNONE); bExactCutoff = bExactElecCutoff && bExactVdwCutoff; if (bExactCutoff) { rcutoff = ( ic->rcoulomb > ic->rvdw ) ? ic->rcoulomb : ic->rvdw; rcutoff2 = rcutoff*rcutoff; } else { /* Fix warnings for stupid compilers */ rcutoff2 = 1e30; } /* avoid compiler warnings for cases that cannot happen */ nnn = 0; eps = 0.0; eps2 = 0.0; /* 3 VdW parameters for Buckingham, otherwise 2 */ nvdwparam = (ivdw == GMX_NBKERNEL_VDW_BUCKINGHAM) ? 3 : 2; table_nelements = 12; charge = mdatoms->chargeA; type = mdatoms->typeA; facel = fr->ic->epsfac; shiftvec = fr->shift_vec[0]; vdwparam = fr->nbfp; ntype = fr->ntype; vdwgridparam = fr->ljpme_c6grid; for (n = 0; (n < nlist->nri); n++) { is3 = 3*nlist->shift[n]; shX = shiftvec[is3]; shY = shiftvec[is3+1]; shZ = shiftvec[is3+2]; nj0 = nlist->jindex[n]; nj1 = nlist->jindex[n+1]; ii = nlist->iinr[n]; ii3 = 3*ii; ix = shX + x[ii3+0]; iy = shY + x[ii3+1]; iz = shZ + x[ii3+2]; iq = facel*charge[ii]; nti = nvdwparam*ntype*type[ii]; vctot = 0; vvdwtot = 0; fix = 0; fiy = 0; fiz = 0; for (k = nj0; (k < nj1); k++) { jnr = nlist->jjnr[k]; j3 = 3*jnr; jx = x[j3+0]; jy = x[j3+1]; jz = x[j3+2]; dx = ix - jx; dy = iy - jy; dz = iz - jz; rsq = dx*dx+dy*dy+dz*dz; rinv = gmx::invsqrt(rsq); rinvsq = rinv*rinv; felec = 0; fvdw = 0; velec = 0; vvdw = 0; if (bExactCutoff && rsq >= rcutoff2) { continue; } if (ielec == GMX_NBKERNEL_ELEC_CUBICSPLINETABLE || ivdw == GMX_NBKERNEL_VDW_CUBICSPLINETABLE) { r = rsq*rinv; rt = r*tabscale; n0 = rt; eps = rt-n0; eps2 = eps*eps; nnn = table_nelements*n0; } /* Coulomb interaction. ielec==0 means no interaction */ if (ielec != GMX_NBKERNEL_ELEC_NONE) { qq = iq*charge[jnr]; switch (ielec) { case GMX_NBKERNEL_ELEC_NONE: break; case GMX_NBKERNEL_ELEC_COULOMB: /* Vanilla cutoff coulomb */ velec = qq*rinv; felec = velec*rinvsq; #ifdef BUILD_WITH_FDA pf_coul = felec; #endif /* The shift for the Coulomb potential is stored in * the RF parameter c_rf, which is 0 without shift */ velec -= qq*ic->c_rf; break; case GMX_NBKERNEL_ELEC_REACTIONFIELD: /* Reaction-field */ velec = qq*(rinv + ic->k_rf*rsq-ic->c_rf); felec = qq*(rinv*rinvsq - 2.0*ic->k_rf); #ifdef BUILD_WITH_FDA pf_coul = felec; #endif break; case GMX_NBKERNEL_ELEC_CUBICSPLINETABLE: /* Tabulated coulomb */ Y = VFtab[nnn]; F = VFtab[nnn+1]; Geps = eps*VFtab[nnn+2]; Heps2 = eps2*VFtab[nnn+3]; Fp = F+Geps+Heps2; VV = Y+eps*Fp; FF = Fp+Geps+2.0*Heps2; velec = qq*VV; felec = -qq*FF*tabscale*rinv; #ifdef BUILD_WITH_FDA pf_coul = felec; #endif break; case GMX_NBKERNEL_ELEC_GENERALIZEDBORN: /* GB */ gmx_fatal(FARGS, "Death & horror! GB generic interaction not implemented.\n"); break; case GMX_NBKERNEL_ELEC_EWALD: ewrt = rsq*rinv*ewtabscale; ewitab = ewrt; eweps = ewrt-ewitab; ewitab = 4*ewitab; felec = ewtab[ewitab]+eweps*ewtab[ewitab+1]; rinvcorr = (ic->coulomb_modifier == eintmodPOTSHIFT) ? rinv - ic->sh_ewald : rinv; velec = qq*(rinvcorr-(ewtab[ewitab+2]-ewtabhalfspace*eweps*(ewtab[ewitab]+felec))); felec = qq*rinv*(rinvsq-felec); #ifdef BUILD_WITH_FDA pf_coul = felec; #endif break; default: gmx_fatal(FARGS, "Death & horror! No generic coulomb interaction for ielec=%d.\n", ielec); break; } if (ic->coulomb_modifier == eintmodPOTSWITCH) { d = rsq*rinv - ic->rcoulomb_switch; d = (d > 0.0) ? d : 0.0; d2 = d*d; sw = 1.0+d2*d*(elec_swV3+d*(elec_swV4+d*elec_swV5)); dsw = d2*(elec_swF2+d*(elec_swF3+d*elec_swF4)); /* Apply switch function. Note that felec=f/r since it will be multiplied * by the i-j displacement vector. This means felec'=f'/r=-(v*sw)'/r= * -(v'*sw+v*dsw)/r=-v'*sw/r-v*dsw/r=felec*sw-v*dsw/r */ felec = felec*sw - rinv*velec*dsw; /* Once we have used velec to update felec we can modify velec too */ velec *= sw; } if (bExactElecCutoff) { felec = (rsq < rcoulomb2) ? felec : 0.0; velec = (rsq < rcoulomb2) ? velec : 0.0; } vctot += velec; } /* End of coulomb interactions */ /* VdW interaction. ivdw==0 means no interaction */ if (ivdw != GMX_NBKERNEL_VDW_NONE) { tj = nti+nvdwparam*type[jnr]; switch (ivdw) { case GMX_NBKERNEL_VDW_NONE: break; case GMX_NBKERNEL_VDW_LENNARDJONES: /* Vanilla Lennard-Jones cutoff */ c6 = vdwparam[tj]; c12 = vdwparam[tj+1]; rinvsix = rinvsq*rinvsq*rinvsq; vvdw_disp = c6*rinvsix; vvdw_rep = c12*rinvsix*rinvsix; fvdw = (vvdw_rep-vvdw_disp)*rinvsq; #ifdef BUILD_WITH_FDA pf_vdw = fvdw; #endif if (ic->vdw_modifier == eintmodPOTSHIFT) { vvdw = (vvdw_rep + c12*sh_repulsion)/12.0 - (vvdw_disp + c6*sh_dispersion)/6.0; } else { vvdw = vvdw_rep/12.0-vvdw_disp/6.0; } break; case GMX_NBKERNEL_VDW_BUCKINGHAM: /* Buckingham */ c6 = vdwparam[tj]; cexp1 = vdwparam[tj+1]; cexp2 = vdwparam[tj+2]; rinvsix = rinvsq*rinvsq*rinvsq; vvdw_disp = c6*rinvsix; br = cexp2*rsq*rinv; vvdw_rep = cexp1*std::exp(-br); fvdw = (br*vvdw_rep-vvdw_disp)*rinvsq; #ifdef BUILD_WITH_FDA pf_vdw = fvdw; #endif if (ic->vdw_modifier == eintmodPOTSHIFT) { vvdw = (vvdw_rep-cexp1*std::exp(-cexp2*rvdw))-(vvdw_disp + c6*sh_dispersion)/6.0; } else { vvdw = vvdw_rep-vvdw_disp/6.0; } break; case GMX_NBKERNEL_VDW_CUBICSPLINETABLE: /* Tabulated VdW */ c6 = vdwparam[tj]; c12 = vdwparam[tj+1]; Y = VFtab[nnn+4]; F = VFtab[nnn+5]; Geps = eps*VFtab[nnn+6]; Heps2 = eps2*VFtab[nnn+7]; Fp = F+Geps+Heps2; VV = Y+eps*Fp; FF = Fp+Geps+2.0*Heps2; vvdw_disp = c6*VV; fijD = c6*FF; Y = VFtab[nnn+8]; F = VFtab[nnn+9]; Geps = eps*VFtab[nnn+10]; Heps2 = eps2*VFtab[nnn+11]; Fp = F+Geps+Heps2; VV = Y+eps*Fp; FF = Fp+Geps+2.0*Heps2; vvdw_rep = c12*VV; fijR = c12*FF; fvdw = -(fijD+fijR)*tabscale*rinv; #ifdef BUILD_WITH_FDA pf_vdw = fvdw; #endif vvdw = vvdw_disp + vvdw_rep; break; case GMX_NBKERNEL_VDW_LJEWALD: /* LJ-PME */ rinvsix = rinvsq*rinvsq*rinvsq; ewcljrsq = ewclj2*rsq; exponent = std::exp(-ewcljrsq); poly = exponent*(1.0 + ewcljrsq + ewcljrsq*ewcljrsq*0.5); c6 = vdwparam[tj]; c12 = vdwparam[tj+1]; c6grid = vdwgridparam[tj]; vvdw_disp = (c6-c6grid*(1.0-poly))*rinvsix; vvdw_rep = c12*rinvsix*rinvsix; fvdw = (vvdw_rep - vvdw_disp - c6grid*(1.0/6.0)*exponent*ewclj6)*rinvsq; #ifdef BUILD_WITH_FDA pf_vdw = fvdw; #endif if (ic->vdw_modifier == eintmodPOTSHIFT) { vvdw = (vvdw_rep + c12*sh_repulsion)/12.0 - (vvdw_disp + c6*sh_dispersion - c6grid*sh_lj_ewald)/6.0; } else { vvdw = vvdw_rep/12.0-vvdw_disp/6.0; } break; default: gmx_fatal(FARGS, "Death & horror! No generic VdW interaction for ivdw=%d.\n", ivdw); break; } if (ic->vdw_modifier == eintmodPOTSWITCH) { d = rsq*rinv - ic->rvdw_switch; d = (d > 0.0) ? d : 0.0; d2 = d*d; sw = 1.0+d2*d*(vdw_swV3+d*(vdw_swV4+d*vdw_swV5)); dsw = d2*(vdw_swF2+d*(vdw_swF3+d*vdw_swF4)); /* See coulomb interaction for the force-switch formula */ fvdw = fvdw*sw - rinv*vvdw*dsw; vvdw *= sw; } if (bExactVdwCutoff) { fvdw = (rsq < rvdw2) ? fvdw : 0.0; vvdw = (rsq < rvdw2) ? vvdw : 0.0; } vvdwtot += vvdw; } /* end VdW interactions */ fscal = felec+fvdw; tx = fscal*dx; ty = fscal*dy; tz = fscal*dz; fix = fix + tx; fiy = fiy + ty; fiz = fiz + tz; f[j3+0] = f[j3+0] - tx; f[j3+1] = f[j3+1] - ty; f[j3+2] = f[j3+2] - tz; #ifdef BUILD_WITH_FDA fda->add_nonbonded(ii, jnr, pf_coul, pf_vdw, dx, dy, dz); fda->add_virial_bond(ii, jnr, fscal, dx, dy, dz); #endif } f[ii3+0] = f[ii3+0] + fix; f[ii3+1] = f[ii3+1] + fiy; f[ii3+2] = f[ii3+2] + fiz; fshift[is3] = fshift[is3]+fix; fshift[is3+1] = fshift[is3+1]+fiy; fshift[is3+2] = fshift[is3+2]+fiz; ggid = nlist->gid[n]; velecgrp[ggid] += vctot; vvdwgrp[ggid] += vvdwtot; } /* Estimate flops, average for generic kernel: * 12 flops per outer iteration * 50 flops per inner iteration */ inc_nrnb(nrnb, eNR_NBKERNEL_GENERIC, nlist->nri*12 + nlist->jindex[n]*50); }
void do_force(FILE *log,t_commrec *cr,t_commrec *mcr, t_parm *parm,t_nsborder *nsb,tensor vir_part,tensor pme_vir, int step,t_nrnb *nrnb,t_topology *top,t_groups *grps, rvec x[],rvec v[],rvec f[],rvec buf[], t_mdatoms *mdatoms,real ener[],t_fcdata *fcd,bool bVerbose, real lambda,t_graph *graph, bool bNS,bool bNBFonly,t_forcerec *fr, rvec mu_tot, bool bGatherOnly) { static rvec box_size; static real dvdl_lr = 0; int cg0,cg1,i,j; int start,homenr; static real mu_and_q[DIM+1]; real qsum; start = START(nsb); homenr = HOMENR(nsb); cg0 = CG0(nsb); cg1 = CG1(nsb); update_forcerec(log,fr,parm->box); /* Calculate total (local) dipole moment in a temporary common array. * This makes it possible to sum them over nodes faster. */ calc_mu_and_q(nsb,x,mdatoms->chargeT,mu_and_q,mu_and_q+DIM); if (fr->ePBC != epbcNONE) { /* Compute shift vectors every step, because of pressure coupling! */ if (parm->ir.epc != epcNO) calc_shifts(parm->box,box_size,fr->shift_vec); if (bNS) { put_charge_groups_in_box(log,cg0,cg1,parm->box,box_size, &(top->blocks[ebCGS]),x,fr->cg_cm); inc_nrnb(nrnb,eNR_RESETX,homenr); } else if (parm->ir.eI==eiSteep || parm->ir.eI==eiCG) unshift_self(graph,parm->box,x); } else if (bNS) calc_cgcm(log,cg0,cg1,&(top->blocks[ebCGS]),x,fr->cg_cm); if (bNS) { inc_nrnb(nrnb,eNR_CGCM,cg1-cg0); if (PAR(cr)) move_cgcm(log,cr,fr->cg_cm,nsb->workload); if (debug) pr_rvecs(debug,0,"cgcm",fr->cg_cm,nsb->cgtotal); } /* Communicate coordinates and sum dipole and net charge if necessary */ if (PAR(cr)) { move_x(log,cr->left,cr->right,x,nsb,nrnb); gmx_sum(DIM+1,mu_and_q,cr); } for(i=0;i<DIM;i++) mu_tot[i]=mu_and_q[i]; qsum=mu_and_q[DIM]; /* Reset energies */ reset_energies(&(parm->ir.opts),grps,fr,bNS,ener); if (bNS) { if (fr->ePBC != epbcNONE) /* Calculate intramolecular shift vectors to make molecules whole */ mk_mshift(log,graph,parm->box,x); /* Reset long range forces if necessary */ if (fr->bTwinRange) { clear_rvecs(nsb->natoms,fr->f_twin); clear_rvecs(SHIFTS,fr->fshift_twin); } /* Do the actual neighbour searching and if twin range electrostatics * also do the calculation of long range forces and energies. */ dvdl_lr = 0; ns(log,fr,x,f,parm->box,grps,&(parm->ir.opts),top,mdatoms, cr,nrnb,nsb,step,lambda,&dvdl_lr); } /* Reset PME/Ewald forces if necessary */ if (EEL_LR(fr->eeltype)) clear_rvecs(homenr,fr->f_pme+start); /* Copy long range forces into normal buffers */ if (fr->bTwinRange) { for(i=0; i<nsb->natoms; i++) copy_rvec(fr->f_twin[i],f[i]); for(i=0; i<SHIFTS; i++) copy_rvec(fr->fshift_twin[i],fr->fshift[i]); } else { clear_rvecs(nsb->natoms,f); clear_rvecs(SHIFTS,fr->fshift); } /* Compute the forces */ force(log,step,fr,&(parm->ir),&(top->idef),nsb,cr,mcr,nrnb,grps,mdatoms, top->atoms.grps[egcENER].nr,&(parm->ir.opts), x,f,ener,fcd,bVerbose,parm->box,lambda,graph,&(top->atoms.excl), bNBFonly,pme_vir,mu_tot,qsum,bGatherOnly); /* Take long range contribution to free energy into account */ ener[F_DVDL] += dvdl_lr; #ifdef DEBUG if (bNS) print_nrnb(log,nrnb); #endif /* The short-range virial from surrounding boxes */ clear_mat(vir_part); calc_vir(log,SHIFTS,fr->shift_vec,fr->fshift,vir_part); inc_nrnb(nrnb,eNR_VIRIAL,SHIFTS); if (debug) pr_rvecs(debug,0,"vir_shifts",vir_part,DIM); /* Compute forces due to electric field */ calc_f_el(start,homenr,mdatoms->chargeT,f,parm->ir.ex); /* When using PME/Ewald we compute the long range virial (pme_vir) there. * otherwise we do it based on long range forces from twin range * cut-off based calculation (or not at all). */ /* Communicate the forces */ if (PAR(cr)) move_f(log,cr->left,cr->right,f,buf,nsb,nrnb); }
void compute_globals(FILE *fplog, gmx_global_stat_t gstat, t_commrec *cr, t_inputrec *ir, t_forcerec *fr, gmx_ekindata_t *ekind, t_state *state, t_state *state_global, t_mdatoms *mdatoms, t_nrnb *nrnb, t_vcm *vcm, gmx_wallcycle_t wcycle, gmx_enerdata_t *enerd, tensor force_vir, tensor shake_vir, tensor total_vir, tensor pres, rvec mu_tot, gmx_constr_t constr, globsig_t *gs, gmx_bool bInterSimGS, matrix box, gmx_mtop_t *top_global, gmx_bool *bSumEkinhOld, int flags) { int i, gsi; real gs_buf[eglsNR]; tensor corr_vir, corr_pres; gmx_bool bEner, bPres, bTemp; gmx_bool bStopCM, bGStat, bReadEkin, bEkinAveVel, bScaleEkin, bConstrain; real prescorr, enercorr, dvdlcorr, dvdl_ekin; /* translate CGLO flags to gmx_booleans */ bStopCM = flags & CGLO_STOPCM; bGStat = flags & CGLO_GSTAT; bReadEkin = (flags & CGLO_READEKIN); bScaleEkin = (flags & CGLO_SCALEEKIN); bEner = flags & CGLO_ENERGY; bTemp = flags & CGLO_TEMPERATURE; bPres = (flags & CGLO_PRESSURE); bConstrain = (flags & CGLO_CONSTRAINT); /* we calculate a full state kinetic energy either with full-step velocity verlet or half step where we need the pressure */ bEkinAveVel = (ir->eI == eiVV || (ir->eI == eiVVAK && bPres) || bReadEkin); /* in initalization, it sums the shake virial in vv, and to sums ekinh_old in leapfrog (or if we are calculating ekinh_old) for other reasons */ /* ########## Kinetic energy ############## */ if (bTemp) { /* Non-equilibrium MD: this is parallellized, but only does communication * when there really is NEMD. */ if (PAR(cr) && (ekind->bNEMD)) { accumulate_u(cr, &(ir->opts), ekind); } debug_gmx(); if (bReadEkin) { restore_ekinstate_from_state(cr, ekind, &state_global->ekinstate); } else { calc_ke_part(state, &(ir->opts), mdatoms, ekind, nrnb, bEkinAveVel); } debug_gmx(); } /* Calculate center of mass velocity if necessary, also parallellized */ if (bStopCM) { calc_vcm_grp(0, mdatoms->homenr, mdatoms, state->x, state->v, vcm); } if (bTemp || bStopCM || bPres || bEner || bConstrain) { if (!bGStat) { /* We will not sum ekinh_old, * so signal that we still have to do it. */ *bSumEkinhOld = TRUE; } else { if (gs != NULL) { for (i = 0; i < eglsNR; i++) { gs_buf[i] = gs->sig[i]; } } if (PAR(cr)) { wallcycle_start(wcycle, ewcMoveE); global_stat(fplog, gstat, cr, enerd, force_vir, shake_vir, mu_tot, ir, ekind, constr, bStopCM ? vcm : NULL, gs != NULL ? eglsNR : 0, gs_buf, top_global, state, *bSumEkinhOld, flags); wallcycle_stop(wcycle, ewcMoveE); } if (gs != NULL) { if (MULTISIM(cr) && bInterSimGS) { if (MASTER(cr)) { /* Communicate the signals between the simulations */ gmx_sum_sim(eglsNR, gs_buf, cr->ms); } /* Communicate the signals form the master to the others */ gmx_bcast(eglsNR*sizeof(gs_buf[0]), gs_buf, cr); } for (i = 0; i < eglsNR; i++) { if (bInterSimGS || gs_simlocal[i]) { /* Set the communicated signal only when it is non-zero, * since signals might not be processed at each MD step. */ gsi = (gs_buf[i] >= 0 ? (int)(gs_buf[i] + 0.5) : (int)(gs_buf[i] - 0.5)); if (gsi != 0) { gs->set[i] = gsi; } /* Turn off the local signal */ gs->sig[i] = 0; } } } *bSumEkinhOld = FALSE; } } if (!ekind->bNEMD && debug && bTemp && (vcm->nr > 0)) { correct_ekin(debug, 0, mdatoms->homenr, state->v, vcm->group_p[0], mdatoms->massT, mdatoms->tmass, ekind->ekin); } /* Do center of mass motion removal */ if (bStopCM) { check_cm_grp(fplog, vcm, ir, 1); do_stopcm_grp(0, mdatoms->homenr, mdatoms->cVCM, state->x, state->v, vcm); inc_nrnb(nrnb, eNR_STOPCM, mdatoms->homenr); } if (bEner) { /* Calculate the amplitude of the cosine velocity profile */ ekind->cosacc.vcos = ekind->cosacc.mvcos/mdatoms->tmass; } if (bTemp) { /* Sum the kinetic energies of the groups & calc temp */ /* compute full step kinetic energies if vv, or if vv-avek and we are computing the pressure with IR_NPT_TROTTER */ /* three maincase: VV with AveVel (md-vv), vv with AveEkin (md-vv-avek), leap with AveEkin (md). Leap with AveVel is not supported; it's not clear that it will actually work. bEkinAveVel: If TRUE, we simply multiply ekin by ekinscale to get a full step kinetic energy. If FALSE, we average ekinh_old and ekinh*ekinscale_nhc to get an averaged half step kinetic energy. */ enerd->term[F_TEMP] = sum_ekin(&(ir->opts), ekind, &dvdl_ekin, bEkinAveVel, bScaleEkin); enerd->dvdl_lin[efptMASS] = (double) dvdl_ekin; enerd->term[F_EKIN] = trace(ekind->ekin); } /* ########## Long range energy information ###### */ if (bEner || bPres || bConstrain) { calc_dispcorr(ir, fr, top_global->natoms, box, state->lambda[efptVDW], corr_pres, corr_vir, &prescorr, &enercorr, &dvdlcorr); } if (bEner) { enerd->term[F_DISPCORR] = enercorr; enerd->term[F_EPOT] += enercorr; enerd->term[F_DVDL_VDW] += dvdlcorr; } /* ########## Now pressure ############## */ if (bPres || bConstrain) { m_add(force_vir, shake_vir, total_vir); /* Calculate pressure and apply LR correction if PPPM is used. * Use the box from last timestep since we already called update(). */ enerd->term[F_PRES] = calc_pres(fr->ePBC, ir->nwall, box, ekind->ekin, total_vir, pres); /* Calculate long range corrections to pressure and energy */ /* this adds to enerd->term[F_PRES] and enerd->term[F_ETOT], and computes enerd->term[F_DISPCORR]. Also modifies the total_vir and pres tesors */ m_add(total_vir, corr_vir, total_vir); m_add(pres, corr_pres, pres); enerd->term[F_PDISPCORR] = prescorr; enerd->term[F_PRES] += prescorr; } }
bool constrain(FILE *fplog,bool bLog,bool bEner, struct gmx_constr *constr, t_idef *idef,t_inputrec *ir, t_commrec *cr, gmx_step_t step,int delta_step, t_mdatoms *md, rvec *x,rvec *xprime,rvec *min_proj,matrix box, real lambda,real *dvdlambda, rvec *v,tensor *vir, t_nrnb *nrnb,int econq) { bool bOK; int start,homenr; int i,j; int ncons,error; tensor rmdr; real invdt,vir_fac,t; t_ilist *settle; int nsettle; t_pbc pbc; char buf[22]; if (econq == econqForceDispl && !EI_ENERGY_MINIMIZATION(ir->eI)) { gmx_incons("constrain called for forces displacements while not doing energy minimization, can not do this while the LINCS and SETTLE constraint connection matrices are mass weighted"); } bOK = TRUE; start = md->start; homenr = md->homenr; if (ir->delta_t == 0) { invdt = 0; } else { invdt = 1/ir->delta_t; } if (ir->efep != efepNO && EI_DYNAMICS(ir->eI)) { /* Set the constraint lengths for the step at which this configuration * is meant to be. The invmasses should not be changed. */ lambda += delta_step*ir->delta_lambda; } if (vir != NULL) { clear_mat(rmdr); } where(); if (constr->lincsd) { bOK = constrain_lincs(fplog,bLog,bEner,ir,step,constr->lincsd,md,cr, x,xprime,min_proj,box,lambda,dvdlambda, invdt,v,vir!=NULL,rmdr, econq,nrnb, constr->maxwarn,&constr->warncount_lincs); if (!bOK && constr->maxwarn >= 0 && fplog) { fprintf(fplog,"Constraint error in algorithm %s at step %s\n", econstr_names[econtLINCS],gmx_step_str(step,buf)); } } if (constr->nblocks > 0) { if (econq != econqCoord) { gmx_fatal(FARGS,"Internal error, SHAKE called for constraining something else than coordinates"); } bOK = bshakef(fplog,constr->shaked, homenr,md->invmass,constr->nblocks,constr->sblock, idef,ir,box,x,xprime,nrnb, constr->lagr,lambda,dvdlambda, invdt,v,vir!=NULL,rmdr,constr->maxwarn>=0); if (!bOK && constr->maxwarn >= 0 && fplog) { fprintf(fplog,"Constraint error in algorithm %s at step %s\n", econstr_names[econtSHAKE],gmx_step_str(step,buf)); } } settle = &idef->il[F_SETTLE]; if (settle->nr > 0) { nsettle = settle->nr/2; switch (econq) { case econqCoord: csettle(constr->settled, nsettle,settle->iatoms,x[0],xprime[0], invdt,v[0],vir!=NULL,rmdr,&error); inc_nrnb(nrnb,eNR_SETTLE,nsettle); if (v != NULL) { inc_nrnb(nrnb,eNR_CONSTR_V,nsettle*3); } if (vir != NULL) { inc_nrnb(nrnb,eNR_CONSTR_VIR,nsettle*3); } bOK = (error < 0); if (!bOK && constr->maxwarn >= 0) { char buf[256]; sprintf(buf, "\nt = %.3f ps: Water molecule starting at atom %d can not be " "settled.\nCheck for bad contacts and/or reduce the timestep.\n", ir->init_t+step*ir->delta_t, ddglatnr(cr->dd,settle->iatoms[error*2+1])); if (fplog) { fprintf(fplog,"%s",buf); } fprintf(stderr,"%s",buf); constr->warncount_settle++; if (constr->warncount_settle > constr->maxwarn) { too_many_constraint_warnings(-1,constr->warncount_settle); } break; case econqVeloc: case econqDeriv: case econqForce: case econqForceDispl: settle_proj(fplog,constr->settled,econq, nsettle,settle->iatoms,x, xprime,min_proj,vir!=NULL,rmdr); /* This is an overestimate */ inc_nrnb(nrnb,eNR_SETTLE,nsettle); break; case econqDeriv_FlexCon: /* Nothing to do, since the are no flexible constraints in settles */ break; default: gmx_incons("Unknown constraint quantity for settle"); } } } if (vir != NULL) { switch (econq) { case econqCoord: vir_fac = 0.5/(ir->delta_t*ir->delta_t); break; case econqVeloc: /* Assume that these are velocities */ vir_fac = 0.5/ir->delta_t; break; case econqForce: case econqForceDispl: vir_fac = 0.5; break; default: vir_fac = 0; gmx_incons("Unsupported constraint quantity for virial"); } for(i=0; i<DIM; i++) { for(j=0; j<DIM; j++) { (*vir)[i][j] = vir_fac*rmdr[i][j]; } } } if (!bOK && constr->maxwarn >= 0) { dump_confs(fplog,step,constr->warn_mtop,start,homenr,cr,x,xprime,box); } if (econq == econqCoord) { if (ir->ePull == epullCONSTRAINT) { if (EI_DYNAMICS(ir->eI)) { t = ir->init_t + (step + delta_step)*ir->delta_t; } else { t = ir->init_t; } set_pbc(&pbc,ir->ePBC,box); pull_constraint(ir->pull,md,&pbc,cr,ir->delta_t,t,x,xprime,v,*vir); } if (constr->ed && delta_step > 0) { /* apply the essential dynamcs constraints here */ do_edsam(ir,step,md,cr,xprime,v,box,constr->ed); } } return bOK; }
void do_nonbonded(t_commrec *cr,t_forcerec *fr, rvec x[],rvec f[],t_mdatoms *mdatoms,t_blocka *excl, real egnb[],real egcoul[],real egpol[],rvec box_size, t_nrnb *nrnb,real lambda,real *dvdlambda, int nls,int eNL,int flags) { gmx_bool bLR,bDoForces,bForeignLambda; t_nblist * nlist; real * fshift; int n,n0,n1,i,i0,i1,nrnb_ind,sz; t_nblists *nblists; gmx_bool bWater; nb_kernel_t * kernelptr; pf_nb_kernel_t *pf_kernelptr; FILE * fp; int fac=0; int nthreads = 1; int tabletype; int outeriter,inneriter; real * tabledata = NULL; gmx_gbdata_t gbdata; bLR = (flags & GMX_DONB_LR); bDoForces = (flags & GMX_DONB_FORCES); bForeignLambda = (flags & GMX_DONB_FOREIGNLAMBDA); gbdata.gb_epsilon_solvent = fr->gb_epsilon_solvent; gbdata.epsilon_r = fr->epsilon_r; gbdata.gpol = egpol; if(fr->bAllvsAll) { if(fr->bGB) { #if (defined GMX_SSE2 || defined GMX_X86_64_SSE || defined GMX_X86_64_SSE2 || defined GMX_IA32_SSE || defined GMX_IA32_SSE2) # ifdef GMX_DOUBLE if(fr->UseOptimizedKernels) { nb_kernel_allvsallgb_sse2_double(fr,mdatoms,excl,x[0],f[0],egcoul,egnb,egpol, &outeriter,&inneriter,&fr->AllvsAll_work); } else { nb_kernel_allvsallgb(fr,mdatoms,excl,x[0],f[0],egcoul,egnb,egpol, &outeriter,&inneriter,&fr->AllvsAll_work); } # else /* not double */ if(fr->UseOptimizedKernels) { nb_kernel_allvsallgb_sse2_single(fr,mdatoms,excl,x[0],f[0],egcoul,egnb,egpol, &outeriter,&inneriter,&fr->AllvsAll_work); } else { nb_kernel_allvsallgb(fr,mdatoms,excl,x[0],f[0],egcoul,egnb,egpol, &outeriter,&inneriter,&fr->AllvsAll_work); } # endif /* double/single alt. */ #else /* no SSE support compiled in */ nb_kernel_allvsallgb(fr,mdatoms,excl,x[0],f[0],egcoul,egnb,egpol, &outeriter,&inneriter,&fr->AllvsAll_work); #endif inc_nrnb(nrnb,eNR_NBKERNEL_ALLVSALLGB,inneriter); } else { #if (defined GMX_SSE2 || defined GMX_X86_64_SSE || defined GMX_X86_64_SSE2 || defined GMX_IA32_SSE || defined GMX_IA32_SSE2) # ifdef GMX_DOUBLE if(fr->UseOptimizedKernels) { nb_kernel_allvsall_sse2_double(fr,mdatoms,excl,x[0],f[0],egcoul,egnb, &outeriter,&inneriter,&fr->AllvsAll_work); } else { nb_kernel_allvsall(fr,mdatoms,excl,x[0],f[0],egcoul,egnb, &outeriter,&inneriter,&fr->AllvsAll_work); } # else /* not double */ if(fr->UseOptimizedKernels) { nb_kernel_allvsall_sse2_single(fr,mdatoms,excl,x[0],f[0],egcoul,egnb, &outeriter,&inneriter,&fr->AllvsAll_work); } else { nb_kernel_allvsall(fr,mdatoms,excl,x[0],f[0],egcoul,egnb, &outeriter,&inneriter,&fr->AllvsAll_work); } # endif /* double/single check */ #else /* No SSE2 support compiled in */ nb_kernel_allvsall(fr,mdatoms,excl,x[0],f[0],egcoul,egnb, &outeriter,&inneriter,&fr->AllvsAll_work); #endif inc_nrnb(nrnb,eNR_NBKERNEL_ALLVSALL,inneriter); } inc_nrnb(nrnb,eNR_NBKERNEL_OUTER,outeriter); return; } if (eNL >= 0) { i0 = eNL; i1 = i0+1; } else { i0 = 0; i1 = eNL_NR; } if (nls >= 0) { n0 = nls; n1 = nls+1; } else { n0 = 0; n1 = fr->nnblists; } if(nb_kernel_list == NULL) { gmx_fatal(FARGS,"gmx_setup_kernels has not been called"); } fshift = fr->fshift[0]; for(n=n0; (n<n1); n++) { nblists = &fr->nblists[n]; for(i=i0; (i<i1); i++) { outeriter = inneriter = 0; if (bLR) { nlist = &(nblists->nlist_lr[i]); } else { nlist = &(nblists->nlist_sr[i]); } if (nlist->nri > 0) { nrnb_ind = nlist->il_code; if(nrnb_ind==eNR_NBKERNEL_FREE_ENERGY) { /* generic free energy, use combined table */ tabledata = nblists->tab.tab; } else { if (bForeignLambda) { /* We don't need the non-perturbed interactions */ continue; } tabletype = nb_kernel_table[nrnb_ind]; /* normal kernels, not free energy */ if (!bDoForces) { nrnb_ind += eNR_NBKERNEL_NR/2; } if(tabletype == TABLE_COMBINED) { tabledata = nblists->tab.tab; } else if(tabletype == TABLE_COUL) { tabledata = nblists->coultab; } else if(tabletype == TABLE_VDW) { tabledata = nblists->vdwtab; } else { tabledata = NULL; } } nlist->count = 0; if(nlist->free_energy) { if(nlist->ivdw==2) { gmx_fatal(FARGS,"Cannot do free energy Buckingham interactions."); } gmx_nb_free_energy_kernel(nlist->icoul, nlist->ivdw, nlist->nri, nlist->iinr, nlist->jindex, nlist->jjnr, nlist->shift, fr->shift_vec[0], fshift, nlist->gid, x[0], f[0], mdatoms->chargeA, mdatoms->chargeB, fr->epsfac, fr->k_rf, fr->c_rf, fr->ewaldcoeff, egcoul, mdatoms->typeA, mdatoms->typeB, fr->ntype, fr->nbfp, egnb, nblists->tab.scale, tabledata, lambda, dvdlambda, fr->sc_alpha, fr->sc_power, fr->sc_sigma6_def, fr->sc_sigma6_min, bDoForces, &outeriter, &inneriter); } else if (nlist->enlist == enlistCG_CG) { /* Call the charge group based inner loop */ gmx_nb_generic_cg_kernel(nlist, fr, mdatoms, x[0], f[0], fshift, egcoul, egnb, nblists->tab.scale, tabledata, &outeriter, &inneriter); } else { /* Not free energy */ /* Pairwise forces between solute and solvent don't bring much information, as the molecules of solvent * move around. For this reason, only pairwise forces between solute atoms are calculated. * This allows the normal (non-pairwise force) kernels to be used for solute-solvent and solvent-solvent * interactions; the main reason is performance, as the normal kernels are not slowed down by the * checking whether atom is involved in an interesting interaction. */ if ((fr->pf_global) && (nlist->enlist == enlistATOM_ATOM)) { pf_kernelptr = pf_nb_kernel_list[nrnb_ind]; (*pf_kernelptr)( &(nlist->nri), nlist->iinr, nlist->jindex, nlist->jjnr, nlist->shift, fr->shift_vec[0], fshift, nlist->gid, x[0], f[0], mdatoms->chargeA, &(fr->epsfac), &(fr->k_rf), &(fr->c_rf), egcoul, mdatoms->typeA, &(fr->ntype), fr->nbfp, egnb, &(nblists->tab.scale), tabledata, fr->invsqrta, fr->dvda, &(fr->gbtabscale), fr->gbtab.tab, &nthreads, &(nlist->count), nlist->mtx, &outeriter, &inneriter, (real *)&gbdata, fr->pf_global); } else { /* non pairwise force kernel */ kernelptr = nb_kernel_list[nrnb_ind]; if (kernelptr == NULL) { /* Call a generic nonbonded kernel */ /* If you want to hack/test your own interactions, * do it in this routine and make sure it is called * by setting the environment variable GMX_NB_GENERIC. */ gmx_nb_generic_kernel(nlist, fr, mdatoms, x[0], f[0], fshift, egcoul, egnb, nblists->tab.scale, tabledata, &outeriter, &inneriter); } else { /* Call nonbonded kernel from function pointer */ (*kernelptr)( &(nlist->nri), nlist->iinr, nlist->jindex, nlist->jjnr, nlist->shift, fr->shift_vec[0], fshift, nlist->gid, x[0], f[0], mdatoms->chargeA, &(fr->epsfac), &(fr->k_rf), &(fr->c_rf), egcoul, mdatoms->typeA, &(fr->ntype), fr->nbfp, egnb, &(nblists->tab.scale), tabledata, fr->invsqrta, fr->dvda, &(fr->gbtabscale), fr->gbtab.tab, &nthreads, &(nlist->count), nlist->mtx, &outeriter, &inneriter, (real *)&gbdata); } /* end of non pairwise force kernel */ } } /* Update flop accounting */ /* Outer loop in kernel */ switch (nlist->enlist) { case enlistATOM_ATOM: fac = 1; break; case enlistSPC_ATOM: fac = 3; break; case enlistSPC_SPC: fac = 9; break; case enlistTIP4P_ATOM: fac = 4; break; case enlistTIP4P_TIP4P: fac = 16; break; case enlistCG_CG: fac = 1; break; } inc_nrnb(nrnb,eNR_NBKERNEL_OUTER,fac*outeriter); /* inner loop in kernel */ inc_nrnb(nrnb,nrnb_ind,inneriter); } } } }
gmx_bool bshakef(FILE *log, gmx_shakedata_t shaked, real invmass[], int nblocks, int sblock[], t_idef *idef, t_inputrec *ir, rvec x_s[], rvec prime[], t_nrnb *nrnb, real *scaled_lagrange_multiplier, real lambda, real *dvdlambda, real invdt, rvec *v, gmx_bool bCalcVir, tensor vir_r_m_dr, gmx_bool bDumpOnError, int econq) { t_iatom *iatoms; real dt_2, dvdl; int i, n0, ncon, blen, type, ll; int tnit = 0, trij = 0; #ifdef DEBUG fprintf(log, "nblocks=%d, sblock[0]=%d\n", nblocks, sblock[0]); #endif ncon = idef->il[F_CONSTR].nr/3; for (ll = 0; ll < ncon; ll++) { scaled_lagrange_multiplier[ll] = 0; } iatoms = &(idef->il[F_CONSTR].iatoms[sblock[0]]); for (i = 0; (i < nblocks); ) { blen = (sblock[i+1]-sblock[i]); blen /= 3; n0 = vec_shakef(log, shaked, invmass, blen, idef->iparams, iatoms, ir->shake_tol, x_s, prime, shaked->omega, ir->efep != efepNO, lambda, scaled_lagrange_multiplier, invdt, v, bCalcVir, vir_r_m_dr, econq); #ifdef DEBUGSHAKE check_cons(log, blen, x_s, prime, v, idef->iparams, iatoms, invmass, econq); #endif if (n0 == 0) { if (bDumpOnError && log) { { check_cons(log, blen, x_s, prime, v, idef->iparams, iatoms, invmass, econq); } } return FALSE; } tnit += n0*blen; trij += blen; iatoms += 3*blen; /* Increment pointer! */ scaled_lagrange_multiplier += blen; i++; } /* only for position part? */ if (econq == econqCoord) { if (ir->efep != efepNO) { real bondA, bondB; /* TODO This should probably use invdt, so that sd integrator scaling works properly */ dt_2 = 1/gmx::square(ir->delta_t); dvdl = 0; for (ll = 0; ll < ncon; ll++) { type = idef->il[F_CONSTR].iatoms[3*ll]; /* Per equations in the manual, dv/dl = -2 \sum_ll lagrangian_ll * r_ll * (d_B - d_A) */ /* The vector scaled_lagrange_multiplier[ll] contains the value -2 r_ll eta_ll (eta_ll is the estimate of the Langrangian, definition on page 336 of Ryckaert et al 1977), so the pre-factors are already present. */ bondA = idef->iparams[type].constr.dA; bondB = idef->iparams[type].constr.dB; dvdl += scaled_lagrange_multiplier[ll] * dt_2 * (bondB - bondA); } *dvdlambda += dvdl; } } #ifdef DEBUG fprintf(log, "tnit: %5d omega: %10.5f\n", tnit, omega); #endif if (ir->bShakeSOR) { if (tnit > shaked->gamma) { shaked->delta *= -0.5; } shaked->omega += shaked->delta; shaked->gamma = tnit; } inc_nrnb(nrnb, eNR_SHAKE, tnit); inc_nrnb(nrnb, eNR_SHAKE_RIJ, trij); if (v) { inc_nrnb(nrnb, eNR_CONSTR_V, trij*2); } if (bCalcVir) { inc_nrnb(nrnb, eNR_CONSTR_VIR, trij); } return TRUE; }
void spread_q(FILE *log,bool bVerbose, int start,int nr, rvec x[],real charge[],rvec box, t_fftgrid *grid,t_nrnb *nrnb) { static bool bFirst = TRUE; static int *nnx,*nny,*nnz; rvec invh; real qi,qwt; #ifdef DEBUG real qt; #endif real WXYZ[27]; ivec ixyz; int i,iX,iY,iZ,index; int jx,jy,jz,jcx,jcy,jcz; int nxyz; int nx,ny,nz,la2,la12; t_fft_r *ptr; unpack_fftgrid(grid,&nx,&ny,&nz,&la2,&la12,TRUE,&ptr); calc_invh(box,nx,ny,nz,invh); if (bFirst) { fprintf(log,"Spreading Charges using Triangle Shaped on %dx%dx%d grid\n", nx,ny,nz); fprintf(log,"invh = %10g,%10g,%10g\n",invh[XX],invh[YY],invh[ZZ]); calc_nxyz(nx,ny,nz,&nnx,&nny,&nnz); bFirst = FALSE; } for(i=start; (i<start+nr); i++) { qi=charge[i]; /* Each charge is spread over the nearest 27 grid cells, * thus we loop over -1..1 in X,Y and Z direction * We apply the TSC (triangle shaped charge) * see Luty et. al, JCP 103 (1995) 3014 */ if (fabs(qi) > GMX_REAL_MIN) { calc_weights(i,nx,ny,nz,x[i],box,invh,ixyz,WXYZ); iX = ixyz[XX] + nx; iY = ixyz[YY] + ny; iZ = ixyz[ZZ] + nz; #ifdef DEBUG qt=0; #endif nxyz = 0; for(jx=-1; (jx<=1); jx++) { jcx = nnx[iX + jx]; for(jy=-1; (jy<=1); jy++) { jcy = nny[iY + jy]; for(jz=-1; (jz<=1); jz++,nxyz++) { jcz = nnz[iZ + jz]; index = INDEX(jcx,jcy,jcz); qwt = qi*WXYZ[nxyz]; grid->ptr[index]+=qwt; #ifdef DEBUG qt += qwt; if (bVerbose) fprintf(log,"spread %4d %2d %2d %2d %10.3e, weight=%10.3e\n", index,jcx,jcy,jcz,grid->ptr[index],WXYZ[nxyz]); #endif } } } #ifdef DEBUG fprintf(log,"q[%3d] = %6.3f, qwt = %6.3f\n",i,qi,qt); #endif } } inc_nrnb(nrnb,eNR_SPREADQ,9*nr); inc_nrnb(nrnb,eNR_WEIGHTS,3*nr); }
void do_force(FILE *fplog,t_commrec *cr, t_inputrec *inputrec, int step,t_nrnb *nrnb,gmx_wallcycle_t wcycle, gmx_localtop_t *top, gmx_groups_t *groups, matrix box,rvec x[],history_t *hist, rvec f[],rvec buf[], tensor vir_force, t_mdatoms *mdatoms, gmx_enerdata_t *enerd,t_fcdata *fcd, real lambda,t_graph *graph, t_forcerec *fr,gmx_vsite_t *vsite,rvec mu_tot, real t,FILE *field,gmx_edsam_t ed, int flags) { static rvec box_size; int cg0,cg1,i,j; int start,homenr; static double mu[2*DIM]; rvec mu_tot_AB[2]; bool bSepDVDL,bStateChanged,bNS,bFillGrid,bCalcCGCM,bBS,bDoForces; matrix boxs; real e,v,dvdl; t_pbc pbc; float cycles_ppdpme,cycles_pme,cycles_force; start = mdatoms->start; homenr = mdatoms->homenr; bSepDVDL = (fr->bSepDVDL && do_per_step(step,inputrec->nstlog)); clear_mat(vir_force); if (PARTDECOMP(cr)) { pd_cg_range(cr,&cg0,&cg1); } else { cg0 = 0; if (DOMAINDECOMP(cr)) cg1 = cr->dd->ncg_tot; else cg1 = top->cgs.nr; if (fr->n_tpi > 0) cg1--; } bStateChanged = (flags & GMX_FORCE_STATECHANGED); bNS = (flags & GMX_FORCE_NS); bFillGrid = (bNS && bStateChanged); bCalcCGCM = (bFillGrid && !DOMAINDECOMP(cr)); bDoForces = (flags & GMX_FORCE_FORCES); if (bStateChanged) { update_forcerec(fplog,fr,box); /* Calculate total (local) dipole moment in a temporary common array. * This makes it possible to sum them over nodes faster. */ calc_mu(start,homenr, x,mdatoms->chargeA,mdatoms->chargeB,mdatoms->nChargePerturbed, mu,mu+DIM); } if (fr->ePBC != epbcNONE) { /* Compute shift vectors every step, * because of pressure coupling or box deformation! */ if (DYNAMIC_BOX(*inputrec) && bStateChanged) calc_shifts(box,fr->shift_vec); if (bCalcCGCM) { put_charge_groups_in_box(fplog,cg0,cg1,fr->ePBC,box, &(top->cgs),x,fr->cg_cm); inc_nrnb(nrnb,eNR_CGCM,homenr); inc_nrnb(nrnb,eNR_RESETX,cg1-cg0); } else if (EI_ENERGY_MINIMIZATION(inputrec->eI) && graph) { unshift_self(graph,box,x); } } else if (bCalcCGCM) { calc_cgcm(fplog,cg0,cg1,&(top->cgs),x,fr->cg_cm); inc_nrnb(nrnb,eNR_CGCM,homenr); } if (bCalcCGCM) { if (PAR(cr)) { move_cgcm(fplog,cr,fr->cg_cm); } if (gmx_debug_at) pr_rvecs(debug,0,"cgcm",fr->cg_cm,top->cgs.nr); } #ifdef GMX_MPI if (!(cr->duty & DUTY_PME)) { /* Send particle coordinates to the pme nodes. * Since this is only implemented for domain decomposition * and domain decomposition does not use the graph, * we do not need to worry about shifting. */ wallcycle_start(wcycle,ewcPP_PMESENDX); GMX_MPE_LOG(ev_send_coordinates_start); bBS = (inputrec->nwall == 2); if (bBS) { copy_mat(box,boxs); svmul(inputrec->wall_ewald_zfac,boxs[ZZ],boxs[ZZ]); } gmx_pme_send_x(cr,bBS ? boxs : box,x,mdatoms->nChargePerturbed,lambda); GMX_MPE_LOG(ev_send_coordinates_finish); wallcycle_stop(wcycle,ewcPP_PMESENDX); } #endif /* GMX_MPI */ /* Communicate coordinates and sum dipole if necessary */ if (PAR(cr)) { wallcycle_start(wcycle,ewcMOVEX); if (DOMAINDECOMP(cr)) { dd_move_x(cr->dd,box,x,buf); } else { move_x(fplog,cr,GMX_LEFT,GMX_RIGHT,x,nrnb); } /* When we don't need the total dipole we sum it in global_stat */ if (NEED_MUTOT(*inputrec)) gmx_sumd(2*DIM,mu,cr); wallcycle_stop(wcycle,ewcMOVEX); } for(i=0; i<2; i++) for(j=0;j<DIM;j++) mu_tot_AB[i][j] = mu[i*DIM + j]; if (fr->efep == efepNO) copy_rvec(mu_tot_AB[0],mu_tot); else for(j=0; j<DIM; j++) mu_tot[j] = (1.0 - lambda)*mu_tot_AB[0][j] + lambda*mu_tot_AB[1][j]; /* Reset energies */ reset_energies(&(inputrec->opts),fr,bNS,enerd,MASTER(cr)); if (bNS) { wallcycle_start(wcycle,ewcNS); if (graph && bStateChanged) /* Calculate intramolecular shift vectors to make molecules whole */ mk_mshift(fplog,graph,fr->ePBC,box,x); /* Reset long range forces if necessary */ if (fr->bTwinRange) { clear_rvecs(fr->f_twin_n,fr->f_twin); clear_rvecs(SHIFTS,fr->fshift_twin); } /* Do the actual neighbour searching and if twin range electrostatics * also do the calculation of long range forces and energies. */ dvdl = 0; ns(fplog,fr,x,f,box,groups,&(inputrec->opts),top,mdatoms, cr,nrnb,step,lambda,&dvdl,&enerd->grpp,bFillGrid,bDoForces); if (bSepDVDL) fprintf(fplog,sepdvdlformat,"LR non-bonded",0,dvdl); enerd->dvdl_lr = dvdl; enerd->term[F_DVDL] += dvdl; wallcycle_stop(wcycle,ewcNS); } if (DOMAINDECOMP(cr)) { if (!(cr->duty & DUTY_PME)) { wallcycle_start(wcycle,ewcPPDURINGPME); dd_force_flop_start(cr->dd,nrnb); } } /* Start the force cycle counter. * This counter is stopped in do_forcelow_level. * No parallel communication should occur while this counter is running, * since that will interfere with the dynamic load balancing. */ wallcycle_start(wcycle,ewcFORCE); if (bDoForces) { /* Reset PME/Ewald forces if necessary */ if (fr->bF_NoVirSum) { GMX_BARRIER(cr->mpi_comm_mygroup); if (fr->bDomDec) clear_rvecs(fr->f_novirsum_n,fr->f_novirsum); else clear_rvecs(homenr,fr->f_novirsum+start); GMX_BARRIER(cr->mpi_comm_mygroup); } /* Copy long range forces into normal buffers */ if (fr->bTwinRange) { for(i=0; i<fr->f_twin_n; i++) copy_rvec(fr->f_twin[i],f[i]); for(i=0; i<SHIFTS; i++) copy_rvec(fr->fshift_twin[i],fr->fshift[i]); } else { if (DOMAINDECOMP(cr)) clear_rvecs(cr->dd->nat_tot,f); else clear_rvecs(mdatoms->nr,f); clear_rvecs(SHIFTS,fr->fshift); } clear_rvec(fr->vir_diag_posres); GMX_BARRIER(cr->mpi_comm_mygroup); } if (inputrec->ePull == epullCONSTRAINT) clear_pull_forces(inputrec->pull); /* update QMMMrec, if necessary */ if(fr->bQMMM) update_QMMMrec(cr,fr,x,mdatoms,box,top); if ((flags & GMX_FORCE_BONDED) && top->idef.il[F_POSRES].nr > 0) { /* Position restraints always require full pbc */ set_pbc(&pbc,inputrec->ePBC,box); v = posres(top->idef.il[F_POSRES].nr,top->idef.il[F_POSRES].iatoms, top->idef.iparams_posres, (const rvec*)x,fr->f_novirsum,fr->vir_diag_posres, inputrec->ePBC==epbcNONE ? NULL : &pbc,lambda,&dvdl, fr->rc_scaling,fr->ePBC,fr->posres_com,fr->posres_comB); if (bSepDVDL) { fprintf(fplog,sepdvdlformat, interaction_function[F_POSRES].longname,v,dvdl); } enerd->term[F_POSRES] += v; enerd->term[F_DVDL] += dvdl; inc_nrnb(nrnb,eNR_POSRES,top->idef.il[F_POSRES].nr/2); } /* Compute the bonded and non-bonded forces */ do_force_lowlevel(fplog,step,fr,inputrec,&(top->idef), cr,nrnb,wcycle,mdatoms,&(inputrec->opts), x,hist,f,enerd,fcd,box,lambda,graph,&(top->excls),mu_tot_AB, flags,&cycles_force); GMX_BARRIER(cr->mpi_comm_mygroup); if (ed) { do_flood(fplog,cr,x,f,ed,box,step); } if (DOMAINDECOMP(cr)) { dd_force_flop_stop(cr->dd,nrnb); if (wcycle) dd_cycles_add(cr->dd,cycles_force,ddCyclF); } if (bDoForces) { /* Compute forces due to electric field */ calc_f_el(MASTER(cr) ? field : NULL, start,homenr,mdatoms->chargeA,x,f,inputrec->ex,inputrec->et,t); /* When using PME/Ewald we compute the long range virial there. * otherwise we do it based on long range forces from twin range * cut-off based calculation (or not at all). */ /* Communicate the forces */ if (PAR(cr)) { wallcycle_start(wcycle,ewcMOVEF); if (DOMAINDECOMP(cr)) { dd_move_f(cr->dd,f,buf,fr->fshift); /* Position restraint do not introduce inter-cg forces */ if (EEL_FULL(fr->eeltype) && cr->dd->n_intercg_excl) dd_move_f(cr->dd,fr->f_novirsum,buf,NULL); } else { move_f(fplog,cr,GMX_LEFT,GMX_RIGHT,f,buf,nrnb); } wallcycle_stop(wcycle,ewcMOVEF); } } if (bDoForces) { if (vsite) { wallcycle_start(wcycle,ewcVSITESPREAD); spread_vsite_f(fplog,vsite,x,f,fr->fshift,nrnb, &top->idef,fr->ePBC,fr->bMolPBC,graph,box,cr); wallcycle_stop(wcycle,ewcVSITESPREAD); } /* Calculation of the virial must be done after vsites! */ calc_virial(fplog,mdatoms->start,mdatoms->homenr,x,f, vir_force,graph,box,nrnb,fr,inputrec->ePBC); } if (inputrec->ePull == epullUMBRELLA || inputrec->ePull == epullCONST_F) { /* Calculate the center of mass forces, this requires communication, * which is why pull_potential is called close to other communication. * The virial contribution is calculated directly, * which is why we call pull_potential after calc_virial. */ set_pbc(&pbc,inputrec->ePBC,box); dvdl = 0; enerd->term[F_COM_PULL] = pull_potential(inputrec->ePull,inputrec->pull,mdatoms,&pbc, cr,t,lambda,x,f,vir_force,&dvdl); if (bSepDVDL) fprintf(fplog,sepdvdlformat,"Com pull",enerd->term[F_COM_PULL],dvdl); enerd->term[F_DVDL] += dvdl; } if (!(cr->duty & DUTY_PME)) { cycles_ppdpme = wallcycle_stop(wcycle,ewcPPDURINGPME); dd_cycles_add(cr->dd,cycles_ppdpme,ddCyclPPduringPME); } #ifdef GMX_MPI if (PAR(cr) && !(cr->duty & DUTY_PME)) { /* In case of node-splitting, the PP nodes receive the long-range * forces, virial and energy from the PME nodes here. */ wallcycle_start(wcycle,ewcPP_PMEWAITRECVF); dvdl = 0; gmx_pme_receive_f(cr,fr->f_novirsum,fr->vir_el_recip,&e,&dvdl, &cycles_pme); if (bSepDVDL) fprintf(fplog,sepdvdlformat,"PME mesh",e,dvdl); enerd->term[F_COUL_RECIP] += e; enerd->term[F_DVDL] += dvdl; if (wcycle) dd_cycles_add(cr->dd,cycles_pme,ddCyclPME); wallcycle_stop(wcycle,ewcPP_PMEWAITRECVF); } #endif if (bDoForces && fr->bF_NoVirSum) { if (vsite) { /* Spread the mesh force on virtual sites to the other particles... * This is parallellized. MPI communication is performed * if the constructing atoms aren't local. */ wallcycle_start(wcycle,ewcVSITESPREAD); spread_vsite_f(fplog,vsite,x,fr->f_novirsum,NULL,nrnb, &top->idef,fr->ePBC,fr->bMolPBC,graph,box,cr); wallcycle_stop(wcycle,ewcVSITESPREAD); } /* Now add the forces, this is local */ if (fr->bDomDec) { sum_forces(0,fr->f_novirsum_n,f,fr->f_novirsum); } else { sum_forces(start,start+homenr,f,fr->f_novirsum); } if (EEL_FULL(fr->eeltype)) { /* Add the mesh contribution to the virial */ m_add(vir_force,fr->vir_el_recip,vir_force); } if (debug) pr_rvecs(debug,0,"vir_force",vir_force,DIM); } /* Sum the potential energy terms from group contributions */ sum_epot(&(inputrec->opts),enerd); if (fr->print_force >= 0 && bDoForces) print_large_forces(stderr,mdatoms,cr,step,fr->print_force,x,f); }
void do_force_lowlevel(t_forcerec *fr, t_inputrec *ir, t_idef *idef, t_commrec *cr, t_nrnb *nrnb, gmx_wallcycle_t wcycle, t_mdatoms *md, rvec x[], history_t *hist, rvec f[], rvec f_longrange[], gmx_enerdata_t *enerd, t_fcdata *fcd, gmx_localtop_t *top, gmx_genborn_t *born, gmx_bool bBornRadii, matrix box, t_lambda *fepvals, real *lambda, t_graph *graph, t_blocka *excl, rvec mu_tot[], int flags, float *cycles_pme) { int i, j; int donb_flags; gmx_bool bSB; int pme_flags; matrix boxs; rvec box_size; t_pbc pbc; real dvdl_dum[efptNR], dvdl_nb[efptNR]; #ifdef GMX_MPI double t0 = 0.0, t1, t2, t3; /* time measurement for coarse load balancing */ #endif set_pbc(&pbc, fr->ePBC, box); /* reset free energy components */ for (i = 0; i < efptNR; i++) { dvdl_nb[i] = 0; dvdl_dum[i] = 0; } /* Reset box */ for (i = 0; (i < DIM); i++) { box_size[i] = box[i][i]; } debug_gmx(); /* do QMMM first if requested */ if (fr->bQMMM) { enerd->term[F_EQM] = calculate_QMMM(cr, x, f, fr); } /* Call the short range functions all in one go. */ #ifdef GMX_MPI /*#define TAKETIME ((cr->npmenodes) && (fr->timesteps < 12))*/ #define TAKETIME FALSE if (TAKETIME) { MPI_Barrier(cr->mpi_comm_mygroup); t0 = MPI_Wtime(); } #endif if (ir->nwall) { /* foreign lambda component for walls */ real dvdl_walls = do_walls(ir, fr, box, md, x, f, lambda[efptVDW], enerd->grpp.ener[egLJSR], nrnb); enerd->dvdl_lin[efptVDW] += dvdl_walls; } /* If doing GB, reset dvda and calculate the Born radii */ if (ir->implicit_solvent) { wallcycle_sub_start(wcycle, ewcsNONBONDED); for (i = 0; i < born->nr; i++) { fr->dvda[i] = 0; } if (bBornRadii) { calc_gb_rad(cr, fr, ir, top, x, &(fr->gblist), born, md, nrnb); } wallcycle_sub_stop(wcycle, ewcsNONBONDED); } where(); /* We only do non-bonded calculation with group scheme here, the verlet * calls are done from do_force_cutsVERLET(). */ if (fr->cutoff_scheme == ecutsGROUP && (flags & GMX_FORCE_NONBONDED)) { donb_flags = 0; /* Add short-range interactions */ donb_flags |= GMX_NONBONDED_DO_SR; /* Currently all group scheme kernels always calculate (shift-)forces */ if (flags & GMX_FORCE_FORCES) { donb_flags |= GMX_NONBONDED_DO_FORCE; } if (flags & GMX_FORCE_VIRIAL) { donb_flags |= GMX_NONBONDED_DO_SHIFTFORCE; } if (flags & GMX_FORCE_ENERGY) { donb_flags |= GMX_NONBONDED_DO_POTENTIAL; } if (flags & GMX_FORCE_DO_LR) { donb_flags |= GMX_NONBONDED_DO_LR; } wallcycle_sub_start(wcycle, ewcsNONBONDED); do_nonbonded(fr, x, f, f_longrange, md, excl, &enerd->grpp, nrnb, lambda, dvdl_nb, -1, -1, donb_flags); /* If we do foreign lambda and we have soft-core interactions * we have to recalculate the (non-linear) energies contributions. */ if (fepvals->n_lambda > 0 && (flags & GMX_FORCE_DHDL) && fepvals->sc_alpha != 0) { for (i = 0; i < enerd->n_lambda; i++) { real lam_i[efptNR]; for (j = 0; j < efptNR; j++) { lam_i[j] = (i == 0 ? lambda[j] : fepvals->all_lambda[j][i-1]); } reset_foreign_enerdata(enerd); do_nonbonded(fr, x, f, f_longrange, md, excl, &(enerd->foreign_grpp), nrnb, lam_i, dvdl_dum, -1, -1, (donb_flags & ~GMX_NONBONDED_DO_FORCE) | GMX_NONBONDED_DO_FOREIGNLAMBDA); sum_epot(&(enerd->foreign_grpp), enerd->foreign_term); enerd->enerpart_lambda[i] += enerd->foreign_term[F_EPOT]; } } wallcycle_sub_stop(wcycle, ewcsNONBONDED); where(); } /* If we are doing GB, calculate bonded forces and apply corrections * to the solvation forces */ /* MRS: Eventually, many need to include free energy contribution here! */ if (ir->implicit_solvent) { wallcycle_sub_start(wcycle, ewcsLISTED); calc_gb_forces(cr, md, born, top, x, f, fr, idef, ir->gb_algorithm, ir->sa_algorithm, nrnb, &pbc, graph, enerd); wallcycle_sub_stop(wcycle, ewcsLISTED); } #ifdef GMX_MPI if (TAKETIME) { t1 = MPI_Wtime(); fr->t_fnbf += t1-t0; } #endif if (fepvals->sc_alpha != 0) { enerd->dvdl_nonlin[efptVDW] += dvdl_nb[efptVDW]; } else { enerd->dvdl_lin[efptVDW] += dvdl_nb[efptVDW]; } if (fepvals->sc_alpha != 0) /* even though coulomb part is linear, we already added it, beacuse we need to go through the vdw calculation anyway */ { enerd->dvdl_nonlin[efptCOUL] += dvdl_nb[efptCOUL]; } else { enerd->dvdl_lin[efptCOUL] += dvdl_nb[efptCOUL]; } debug_gmx(); if (debug) { pr_rvecs(debug, 0, "fshift after SR", fr->fshift, SHIFTS); } /* Shift the coordinates. Must be done before listed forces and PPPM, * but is also necessary for SHAKE and update, therefore it can NOT * go when no listed forces have to be evaluated. * * The shifting and PBC code is deliberately not timed, since with * the Verlet scheme it only takes non-zero time with triclinic * boxes, and even then the time is around a factor of 100 less * than the next smallest counter. */ /* Here sometimes we would not need to shift with NBFonly, * but we do so anyhow for consistency of the returned coordinates. */ if (graph) { shift_self(graph, box, x); if (TRICLINIC(box)) { inc_nrnb(nrnb, eNR_SHIFTX, 2*graph->nnodes); } else { inc_nrnb(nrnb, eNR_SHIFTX, graph->nnodes); } } /* Check whether we need to do listed interactions or correct for exclusions */ if (fr->bMolPBC && ((flags & GMX_FORCE_LISTED) || EEL_RF(fr->eeltype) || EEL_FULL(fr->eeltype) || EVDW_PME(fr->vdwtype))) { /* TODO There are no electrostatics methods that require this transformation, when using the Verlet scheme, so update the above conditional. */ /* Since all atoms are in the rectangular or triclinic unit-cell, * only single box vector shifts (2 in x) are required. */ set_pbc_dd(&pbc, fr->ePBC, cr->dd, TRUE, box); } debug_gmx(); do_force_listed(wcycle, box, ir->fepvals, cr->ms, idef, (const rvec *) x, hist, f, fr, &pbc, graph, enerd, nrnb, lambda, md, fcd, DOMAINDECOMP(cr) ? cr->dd->gatindex : NULL, flags); where(); *cycles_pme = 0; clear_mat(fr->vir_el_recip); clear_mat(fr->vir_lj_recip); /* Do long-range electrostatics and/or LJ-PME, including related short-range * corrections. */ if (EEL_FULL(fr->eeltype) || EVDW_PME(fr->vdwtype)) { int status = 0; real Vlr_q = 0, Vlr_lj = 0, Vcorr_q = 0, Vcorr_lj = 0; real dvdl_long_range_q = 0, dvdl_long_range_lj = 0; bSB = (ir->nwall == 2); if (bSB) { copy_mat(box, boxs); svmul(ir->wall_ewald_zfac, boxs[ZZ], boxs[ZZ]); box_size[ZZ] *= ir->wall_ewald_zfac; } if (EEL_PME_EWALD(fr->eeltype) || EVDW_PME(fr->vdwtype)) { real dvdl_long_range_correction_q = 0; real dvdl_long_range_correction_lj = 0; /* With the Verlet scheme exclusion forces are calculated * in the non-bonded kernel. */ /* The TPI molecule does not have exclusions with the rest * of the system and no intra-molecular PME grid * contributions will be calculated in * gmx_pme_calc_energy. */ if ((ir->cutoff_scheme == ecutsGROUP && fr->n_tpi == 0) || ir->ewald_geometry != eewg3D || ir->epsilon_surface != 0) { int nthreads, t; wallcycle_sub_start(wcycle, ewcsEWALD_CORRECTION); if (fr->n_tpi > 0) { gmx_fatal(FARGS, "TPI with PME currently only works in a 3D geometry with tin-foil boundary conditions"); } nthreads = gmx_omp_nthreads_get(emntBonded); #pragma omp parallel for num_threads(nthreads) schedule(static) for (t = 0; t < nthreads; t++) { int i; rvec *fnv; tensor *vir_q, *vir_lj; real *Vcorrt_q, *Vcorrt_lj, *dvdlt_q, *dvdlt_lj; if (t == 0) { fnv = fr->f_novirsum; vir_q = &fr->vir_el_recip; vir_lj = &fr->vir_lj_recip; Vcorrt_q = &Vcorr_q; Vcorrt_lj = &Vcorr_lj; dvdlt_q = &dvdl_long_range_correction_q; dvdlt_lj = &dvdl_long_range_correction_lj; } else { fnv = fr->f_t[t].f; vir_q = &fr->f_t[t].vir_q; vir_lj = &fr->f_t[t].vir_lj; Vcorrt_q = &fr->f_t[t].Vcorr_q; Vcorrt_lj = &fr->f_t[t].Vcorr_lj; dvdlt_q = &fr->f_t[t].dvdl[efptCOUL]; dvdlt_lj = &fr->f_t[t].dvdl[efptVDW]; for (i = 0; i < fr->natoms_force; i++) { clear_rvec(fnv[i]); } clear_mat(*vir_q); clear_mat(*vir_lj); } *dvdlt_q = 0; *dvdlt_lj = 0; ewald_LRcorrection(fr->excl_load[t], fr->excl_load[t+1], cr, t, fr, md->chargeA, md->chargeB, md->sqrt_c6A, md->sqrt_c6B, md->sigmaA, md->sigmaB, md->sigma3A, md->sigma3B, md->nChargePerturbed || md->nTypePerturbed, ir->cutoff_scheme != ecutsVERLET, excl, x, bSB ? boxs : box, mu_tot, ir->ewald_geometry, ir->epsilon_surface, fnv, *vir_q, *vir_lj, Vcorrt_q, Vcorrt_lj, lambda[efptCOUL], lambda[efptVDW], dvdlt_q, dvdlt_lj); } if (nthreads > 1) { reduce_thread_forces(fr->natoms_force, fr->f_novirsum, fr->vir_el_recip, fr->vir_lj_recip, &Vcorr_q, &Vcorr_lj, &dvdl_long_range_correction_q, &dvdl_long_range_correction_lj, nthreads, fr->f_t); } wallcycle_sub_stop(wcycle, ewcsEWALD_CORRECTION); } if (EEL_PME_EWALD(fr->eeltype) && fr->n_tpi == 0) { /* This is not in a subcounter because it takes a negligible and constant-sized amount of time */ Vcorr_q += ewald_charge_correction(cr, fr, lambda[efptCOUL], box, &dvdl_long_range_correction_q, fr->vir_el_recip); } enerd->dvdl_lin[efptCOUL] += dvdl_long_range_correction_q; enerd->dvdl_lin[efptVDW] += dvdl_long_range_correction_lj; if ((EEL_PME(fr->eeltype) || EVDW_PME(fr->vdwtype)) && (cr->duty & DUTY_PME)) { /* Do reciprocal PME for Coulomb and/or LJ. */ assert(fr->n_tpi >= 0); if (fr->n_tpi == 0 || (flags & GMX_FORCE_STATECHANGED)) { pme_flags = GMX_PME_SPREAD | GMX_PME_SOLVE; if (EEL_PME(fr->eeltype)) { pme_flags |= GMX_PME_DO_COULOMB; } if (EVDW_PME(fr->vdwtype)) { pme_flags |= GMX_PME_DO_LJ; } if (flags & GMX_FORCE_FORCES) { pme_flags |= GMX_PME_CALC_F; } if (flags & GMX_FORCE_VIRIAL) { pme_flags |= GMX_PME_CALC_ENER_VIR; } if (fr->n_tpi > 0) { /* We don't calculate f, but we do want the potential */ pme_flags |= GMX_PME_CALC_POT; } wallcycle_start(wcycle, ewcPMEMESH); status = gmx_pme_do(fr->pmedata, 0, md->homenr - fr->n_tpi, x, fr->f_novirsum, md->chargeA, md->chargeB, md->sqrt_c6A, md->sqrt_c6B, md->sigmaA, md->sigmaB, bSB ? boxs : box, cr, DOMAINDECOMP(cr) ? dd_pme_maxshift_x(cr->dd) : 0, DOMAINDECOMP(cr) ? dd_pme_maxshift_y(cr->dd) : 0, nrnb, wcycle, fr->vir_el_recip, fr->ewaldcoeff_q, fr->vir_lj_recip, fr->ewaldcoeff_lj, &Vlr_q, &Vlr_lj, lambda[efptCOUL], lambda[efptVDW], &dvdl_long_range_q, &dvdl_long_range_lj, pme_flags); *cycles_pme = wallcycle_stop(wcycle, ewcPMEMESH); if (status != 0) { gmx_fatal(FARGS, "Error %d in reciprocal PME routine", status); } /* We should try to do as little computation after * this as possible, because parallel PME synchronizes * the nodes, so we want all load imbalance of the * rest of the force calculation to be before the PME * call. DD load balancing is done on the whole time * of the force call (without PME). */ } if (fr->n_tpi > 0) { if (EVDW_PME(ir->vdwtype)) { gmx_fatal(FARGS, "Test particle insertion not implemented with LJ-PME"); } /* Determine the PME grid energy of the test molecule * with the PME grid potential of the other charges. */ gmx_pme_calc_energy(fr->pmedata, fr->n_tpi, x + md->homenr - fr->n_tpi, md->chargeA + md->homenr - fr->n_tpi, &Vlr_q); } } } if (!EEL_PME(fr->eeltype) && EEL_PME_EWALD(fr->eeltype)) { Vlr_q = do_ewald(ir, x, fr->f_novirsum, md->chargeA, md->chargeB, box_size, cr, md->homenr, fr->vir_el_recip, fr->ewaldcoeff_q, lambda[efptCOUL], &dvdl_long_range_q, fr->ewald_table); } /* Note that with separate PME nodes we get the real energies later */ enerd->dvdl_lin[efptCOUL] += dvdl_long_range_q; enerd->dvdl_lin[efptVDW] += dvdl_long_range_lj; enerd->term[F_COUL_RECIP] = Vlr_q + Vcorr_q; enerd->term[F_LJ_RECIP] = Vlr_lj + Vcorr_lj; if (debug) { fprintf(debug, "Vlr_q = %g, Vcorr_q = %g, Vlr_corr_q = %g\n", Vlr_q, Vcorr_q, enerd->term[F_COUL_RECIP]); pr_rvecs(debug, 0, "vir_el_recip after corr", fr->vir_el_recip, DIM); pr_rvecs(debug, 0, "fshift after LR Corrections", fr->fshift, SHIFTS); fprintf(debug, "Vlr_lj: %g, Vcorr_lj = %g, Vlr_corr_lj = %g\n", Vlr_lj, Vcorr_lj, enerd->term[F_LJ_RECIP]); pr_rvecs(debug, 0, "vir_lj_recip after corr", fr->vir_lj_recip, DIM); } } else { /* Is there a reaction-field exclusion correction needed? */ if (EEL_RF(fr->eeltype) && eelRF_NEC != fr->eeltype) { /* With the Verlet scheme, exclusion forces are calculated * in the non-bonded kernel. */ if (ir->cutoff_scheme != ecutsVERLET) { real dvdl_rf_excl = 0; enerd->term[F_RF_EXCL] = RF_excl_correction(fr, graph, md, excl, x, f, fr->fshift, &pbc, lambda[efptCOUL], &dvdl_rf_excl); enerd->dvdl_lin[efptCOUL] += dvdl_rf_excl; } } } where(); debug_gmx(); if (debug) { print_nrnb(debug, nrnb); } debug_gmx(); #ifdef GMX_MPI if (TAKETIME) { t2 = MPI_Wtime(); MPI_Barrier(cr->mpi_comm_mygroup); t3 = MPI_Wtime(); fr->t_wait += t3-t2; if (fr->timesteps == 11) { char buf[22]; fprintf(stderr, "* PP load balancing info: rank %d, step %s, rel wait time=%3.0f%% , load string value: %7.2f\n", cr->nodeid, gmx_step_str(fr->timesteps, buf), 100*fr->t_wait/(fr->t_wait+fr->t_fnbf), (fr->t_fnbf+fr->t_wait)/fr->t_fnbf); } fr->timesteps++; } #endif if (debug) { pr_rvecs(debug, 0, "fshift after bondeds", fr->fshift, SHIFTS); } }
static real gather_f(FILE *log,bool bVerbose, int start,int nr,rvec x[],rvec f[],real charge[],rvec box, real pot[],t_fftgrid *grid,rvec beta,t_nrnb *nrnb) { static bool bFirst=TRUE; static int *nnx,*nny,*nnz; static int JCXYZ[81]; int i,m; real energy; real qi,pi; ivec ixyz; rvec invh,c1,c2; real WXYZ[27]; real c1x,c1y,c1z,c2x,c2y,c2z; int ixw[7],iyw[7],izw[7]; int ll; int nx,ny,nz,la2,la12; t_fft_r *ptr; unpack_fftgrid(grid,&nx,&ny,&nz,&la2,&la12,TRUE,&ptr); calc_invh(box,nx,ny,nz,invh); for(m=0; (m<DIM); m++) { c1[m] = (beta[m]/2.0)*invh[m]; c2[m] = ((1.0-beta[m])/4.0)*invh[m]; } c1x = c1[XX]; c1y = c1[YY]; c1z = c1[ZZ]; c2x = c2[XX]; c2y = c2[YY]; c2z = c2[ZZ]; if (bFirst) { fprintf(log,"Gathering Forces using Triangle Shaped on %dx%dx%d grid\n", nx,ny,nz); fprintf(log,"beta = %10g,%10g,%10g\n",beta[XX],beta[YY],beta[ZZ]); fprintf(log,"c1 = %10g,%10g,%10g\n",c1[XX],c1[YY],c1[ZZ]); fprintf(log,"c2 = %10g,%10g,%10g\n",c2[XX],c2[YY],c2[ZZ]); fprintf(log,"invh = %10g,%10g,%10g\n",invh[XX],invh[YY],invh[ZZ]); calc_nxyz(nx,ny,nz,&nnx,&nny,&nnz); for(i=0; (i<27); i++) { JCXYZ[3*i] = 2 + (i/9); JCXYZ[3*i+1] = 2 + (i/3) % 3; JCXYZ[3*i+2] = 2 + (i % 3); } bFirst = FALSE; } energy=0.0; for(i=start; (i<start+nr); i++) { /* Each charge is spread over the nearest 27 grid cells, * thus we loop over -1..1 in X,Y and Z direction * We apply the TSC (triangle shaped charge) * see Luty et. al, JCP 103 (1995) 3014 */ calc_weights(i,nx,ny,nz,x[i],box,invh,ixyz,WXYZ); for(ll=llim2; (ll<=ulim2); ll++) { ixw[ll-llim2] = nnx[ixyz[XX]+ll+nx]; iyw[ll-llim2] = nny[ixyz[YY]+ll+ny]; izw[ll-llim2] = nnz[ixyz[ZZ]+ll+nz]; } qi = charge[i]; pi = gather_inner(JCXYZ,WXYZ,ixw,iyw,izw,la2,la12, c1x,c1y,c1z,c2x,c2y,c2z, qi,f[i],ptr); energy += pi*qi; pot[i] = pi; } inc_nrnb(nrnb,eNR_GATHERF,27*nr); inc_nrnb(nrnb,eNR_WEIGHTS,3*nr); return energy*0.5; }
void gmx_nb_free_energy_kernel(t_nblist * nlist, rvec * xx, rvec * ff, t_forcerec * fr, t_mdatoms * mdatoms, nb_kernel_data_t * kernel_data, t_nrnb * nrnb) { #define STATE_A 0 #define STATE_B 1 #define NSTATES 2 int i, j, n, ii, is3, ii3, k, nj0, nj1, jnr, j3, ggid; real shX, shY, shZ; real Fscal, FscalC[NSTATES], FscalV[NSTATES], tx, ty, tz; real Vcoul[NSTATES], Vvdw[NSTATES]; real rinv6, r, rt, rtC, rtV; real iqA, iqB; real qq[NSTATES], vctot, krsq; int ntiA, ntiB, tj[NSTATES]; real Vvdw6, Vvdw12, vvtot; real ix, iy, iz, fix, fiy, fiz; real dx, dy, dz, rsq, rinv; real c6[NSTATES], c12[NSTATES]; real LFC[NSTATES], LFV[NSTATES], DLF[NSTATES]; double dvdl_coul, dvdl_vdw; real lfac_coul[NSTATES], dlfac_coul[NSTATES], lfac_vdw[NSTATES], dlfac_vdw[NSTATES]; real sigma6[NSTATES], alpha_vdw_eff, alpha_coul_eff, sigma2_def, sigma2_min; real rp, rpm2, rC, rV, rinvC, rpinvC, rinvV, rpinvV; real sigma2[NSTATES], sigma_pow[NSTATES], sigma_powm2[NSTATES], rs, rs2; int do_coultab, do_vdwtab, do_tab, tab_elemsize; int n0, n1C, n1V, nnn; real Y, F, G, H, Fp, Geps, Heps2, epsC, eps2C, epsV, eps2V, VV, FF; int icoul, ivdw; int nri; int * iinr; int * jindex; int * jjnr; int * shift; int * gid; int * typeA; int * typeB; int ntype; real * shiftvec; real dvdl_part; real * fshift; real tabscale; real * VFtab; real * x; real * f; real facel, krf, crf; real * chargeA; real * chargeB; real sigma6_min, sigma6_def, lam_power, sc_power, sc_r_power; real alpha_coul, alpha_vdw, lambda_coul, lambda_vdw, ewc; real * nbfp; real * dvdl; real * Vv; real * Vc; gmx_bool bDoForces; real rcoulomb, rvdw, sh_invrc6; gmx_bool bExactElecCutoff, bExactVdwCutoff; real rcutoff, rcutoff2, rswitch, d, d2, swV3, swV4, swV5, swF2, swF3, swF4, sw, dsw, rinvcorr; x = xx[0]; f = ff[0]; fshift = fr->fshift[0]; Vc = kernel_data->energygrp_elec; Vv = kernel_data->energygrp_vdw; tabscale = kernel_data->table_elec_vdw->scale; VFtab = kernel_data->table_elec_vdw->data; nri = nlist->nri; iinr = nlist->iinr; jindex = nlist->jindex; jjnr = nlist->jjnr; icoul = nlist->ielec; ivdw = nlist->ivdw; shift = nlist->shift; gid = nlist->gid; shiftvec = fr->shift_vec[0]; chargeA = mdatoms->chargeA; chargeB = mdatoms->chargeB; facel = fr->epsfac; krf = fr->k_rf; crf = fr->c_rf; ewc = fr->ewaldcoeff; Vc = kernel_data->energygrp_elec; typeA = mdatoms->typeA; typeB = mdatoms->typeB; ntype = fr->ntype; nbfp = fr->nbfp; Vv = kernel_data->energygrp_vdw; tabscale = kernel_data->table_elec_vdw->scale; VFtab = kernel_data->table_elec_vdw->data; lambda_coul = kernel_data->lambda[efptCOUL]; lambda_vdw = kernel_data->lambda[efptVDW]; dvdl = kernel_data->dvdl; alpha_coul = fr->sc_alphacoul; alpha_vdw = fr->sc_alphavdw; lam_power = fr->sc_power; sc_r_power = fr->sc_r_power; sigma6_def = fr->sc_sigma6_def; sigma6_min = fr->sc_sigma6_min; bDoForces = kernel_data->flags & GMX_NONBONDED_DO_FORCE; rcoulomb = fr->rcoulomb; rvdw = fr->rvdw; sh_invrc6 = fr->ic->sh_invrc6; if (fr->coulomb_modifier == eintmodPOTSWITCH || fr->vdw_modifier == eintmodPOTSWITCH) { rcutoff = (fr->coulomb_modifier == eintmodPOTSWITCH) ? fr->rcoulomb : fr->rvdw; rcutoff2 = rcutoff*rcutoff; rswitch = (fr->coulomb_modifier == eintmodPOTSWITCH) ? fr->rcoulomb_switch : fr->rvdw_switch; d = rcutoff-rswitch; swV3 = -10.0/(d*d*d); swV4 = 15.0/(d*d*d*d); swV5 = -6.0/(d*d*d*d*d); swF2 = -30.0/(d*d*d); swF3 = 60.0/(d*d*d*d); swF4 = -30.0/(d*d*d*d*d); } else { /* Stupid compilers dont realize these variables will not be used */ rswitch = 0.0; swV3 = 0.0; swV4 = 0.0; swV5 = 0.0; swF2 = 0.0; swF3 = 0.0; swF4 = 0.0; } bExactElecCutoff = (fr->coulomb_modifier != eintmodNONE) || fr->eeltype == eelRF_ZERO; bExactVdwCutoff = (fr->vdw_modifier != eintmodNONE); /* fix compiler warnings */ nj1 = 0; n1C = n1V = 0; epsC = epsV = 0; eps2C = eps2V = 0; dvdl_coul = 0; dvdl_vdw = 0; /* Lambda factor for state A, 1-lambda*/ LFC[STATE_A] = 1.0 - lambda_coul; LFV[STATE_A] = 1.0 - lambda_vdw; /* Lambda factor for state B, lambda*/ LFC[STATE_B] = lambda_coul; LFV[STATE_B] = lambda_vdw; /*derivative of the lambda factor for state A and B */ DLF[STATE_A] = -1; DLF[STATE_B] = 1; for (i = 0; i < NSTATES; i++) { lfac_coul[i] = (lam_power == 2 ? (1-LFC[i])*(1-LFC[i]) : (1-LFC[i])); dlfac_coul[i] = DLF[i]*lam_power/sc_r_power*(lam_power == 2 ? (1-LFC[i]) : 1); lfac_vdw[i] = (lam_power == 2 ? (1-LFV[i])*(1-LFV[i]) : (1-LFV[i])); dlfac_vdw[i] = DLF[i]*lam_power/sc_r_power*(lam_power == 2 ? (1-LFV[i]) : 1); } /* precalculate */ sigma2_def = pow(sigma6_def, 1.0/3.0); sigma2_min = pow(sigma6_min, 1.0/3.0); /* Ewald (not PME) table is special (icoul==enbcoulFEWALD) */ do_coultab = (icoul == GMX_NBKERNEL_ELEC_CUBICSPLINETABLE); do_vdwtab = (ivdw == GMX_NBKERNEL_VDW_CUBICSPLINETABLE); do_tab = do_coultab || do_vdwtab; /* we always use the combined table here */ tab_elemsize = 12; for (n = 0; (n < nri); n++) { is3 = 3*shift[n]; shX = shiftvec[is3]; shY = shiftvec[is3+1]; shZ = shiftvec[is3+2]; nj0 = jindex[n]; nj1 = jindex[n+1]; ii = iinr[n]; ii3 = 3*ii; ix = shX + x[ii3+0]; iy = shY + x[ii3+1]; iz = shZ + x[ii3+2]; iqA = facel*chargeA[ii]; iqB = facel*chargeB[ii]; ntiA = 2*ntype*typeA[ii]; ntiB = 2*ntype*typeB[ii]; vctot = 0; vvtot = 0; fix = 0; fiy = 0; fiz = 0; for (k = nj0; (k < nj1); k++) { jnr = jjnr[k]; j3 = 3*jnr; dx = ix - x[j3]; dy = iy - x[j3+1]; dz = iz - x[j3+2]; rsq = dx*dx+dy*dy+dz*dz; rinv = gmx_invsqrt(rsq); r = rsq*rinv; if (sc_r_power == 6.0) { rpm2 = rsq*rsq; /* r4 */ rp = rpm2*rsq; /* r6 */ } else if (sc_r_power == 48.0) { rp = rsq*rsq*rsq; /* r6 */ rp = rp*rp; /* r12 */ rp = rp*rp; /* r24 */ rp = rp*rp; /* r48 */ rpm2 = rp/rsq; /* r46 */ } else { rp = pow(r, sc_r_power); /* not currently supported as input, but can handle it */ rpm2 = rp/rsq; } tj[STATE_A] = ntiA+2*typeA[jnr]; tj[STATE_B] = ntiB+2*typeB[jnr]; qq[STATE_A] = iqA*chargeA[jnr]; qq[STATE_B] = iqB*chargeB[jnr]; for (i = 0; i < NSTATES; i++) { c6[i] = nbfp[tj[i]]; c12[i] = nbfp[tj[i]+1]; if ((c6[i] > 0) && (c12[i] > 0)) { /* c12 is stored scaled with 12.0 and c6 is scaled with 6.0 - correct for this */ sigma6[i] = 0.5*c12[i]/c6[i]; sigma2[i] = pow(sigma6[i], 1.0/3.0); /* should be able to get rid of this ^^^ internal pow call eventually. Will require agreement on what data to store externally. Can't be fixed without larger scale changes, so not 4.6 */ if (sigma6[i] < sigma6_min) /* for disappearing coul and vdw with soft core at the same time */ { sigma6[i] = sigma6_min; sigma2[i] = sigma2_min; } } else { sigma6[i] = sigma6_def; sigma2[i] = sigma2_def; } if (sc_r_power == 6.0) { sigma_pow[i] = sigma6[i]; sigma_powm2[i] = sigma6[i]/sigma2[i]; } else if (sc_r_power == 48.0) { sigma_pow[i] = sigma6[i]*sigma6[i]; /* sigma^12 */ sigma_pow[i] = sigma_pow[i]*sigma_pow[i]; /* sigma^24 */ sigma_pow[i] = sigma_pow[i]*sigma_pow[i]; /* sigma^48 */ sigma_powm2[i] = sigma_pow[i]/sigma2[i]; } else { /* not really supported as input, but in here for testing the general case*/ sigma_pow[i] = pow(sigma2[i], sc_r_power/2); sigma_powm2[i] = sigma_pow[i]/(sigma2[i]); } } /* only use softcore if one of the states has a zero endstate - softcore is for avoiding infinities!*/ if ((c12[STATE_A] > 0) && (c12[STATE_B] > 0)) { alpha_vdw_eff = 0; alpha_coul_eff = 0; } else { alpha_vdw_eff = alpha_vdw; alpha_coul_eff = alpha_coul; } for (i = 0; i < NSTATES; i++) { FscalC[i] = 0; FscalV[i] = 0; Vcoul[i] = 0; Vvdw[i] = 0; /* Only spend time on A or B state if it is non-zero */ if ( (qq[i] != 0) || (c6[i] != 0) || (c12[i] != 0) ) { /* this section has to be inside the loop becaue of the dependence on sigma_pow */ rpinvC = 1.0/(alpha_coul_eff*lfac_coul[i]*sigma_pow[i]+rp); rinvC = pow(rpinvC, 1.0/sc_r_power); rC = 1.0/rinvC; rpinvV = 1.0/(alpha_vdw_eff*lfac_vdw[i]*sigma_pow[i]+rp); rinvV = pow(rpinvV, 1.0/sc_r_power); rV = 1.0/rinvV; if (do_tab) { rtC = rC*tabscale; n0 = rtC; epsC = rtC-n0; eps2C = epsC*epsC; n1C = tab_elemsize*n0; rtV = rV*tabscale; n0 = rtV; epsV = rtV-n0; eps2V = epsV*epsV; n1V = tab_elemsize*n0; } /* With Ewald and soft-core we should put the cut-off on r, * not on the soft-cored rC, as the real-space and * reciprocal space contributions should (almost) cancel. */ if (qq[i] != 0 && !(bExactElecCutoff && ((icoul != GMX_NBKERNEL_ELEC_EWALD && rC >= rcoulomb) || (icoul == GMX_NBKERNEL_ELEC_EWALD && r >= rcoulomb)))) { switch (icoul) { case GMX_NBKERNEL_ELEC_COULOMB: case GMX_NBKERNEL_ELEC_EWALD: /* simple cutoff (yes, ewald is done all on direct space for free energy) */ Vcoul[i] = qq[i]*rinvC; FscalC[i] = Vcoul[i]*rpinvC; break; case GMX_NBKERNEL_ELEC_REACTIONFIELD: /* reaction-field */ Vcoul[i] = qq[i]*(rinvC+krf*rC*rC-crf); FscalC[i] = qq[i]*(rinvC*rpinvC-2.0*krf); break; case GMX_NBKERNEL_ELEC_CUBICSPLINETABLE: /* non-Ewald tabulated coulomb */ nnn = n1C; Y = VFtab[nnn]; F = VFtab[nnn+1]; Geps = epsC*VFtab[nnn+2]; Heps2 = eps2C*VFtab[nnn+3]; Fp = F+Geps+Heps2; VV = Y+epsC*Fp; FF = Fp+Geps+2.0*Heps2; Vcoul[i] = qq[i]*VV; FscalC[i] = -qq[i]*tabscale*FF*rC*rpinvC; break; default: FscalC[i] = 0.0; Vcoul[i] = 0.0; break; } if (fr->coulomb_modifier == eintmodPOTSWITCH) { d = rC-rswitch; d = (d > 0.0) ? d : 0.0; d2 = d*d; sw = 1.0+d2*d*(swV3+d*(swV4+d*swV5)); dsw = d2*(swF2+d*(swF3+d*swF4)); Vcoul[i] *= sw; FscalC[i] = FscalC[i]*sw + Vcoul[i]*dsw; } } if ((c6[i] != 0 || c12[i] != 0) && !(bExactVdwCutoff && rV >= rvdw)) { switch (ivdw) { case GMX_NBKERNEL_VDW_LENNARDJONES: /* cutoff LJ */ if (sc_r_power == 6.0) { rinv6 = rpinvV; } else { rinv6 = pow(rinvV, 6.0); } Vvdw6 = c6[i]*rinv6; Vvdw12 = c12[i]*rinv6*rinv6; if (fr->vdw_modifier == eintmodPOTSHIFT) { Vvdw[i] = ( (Vvdw12-c12[i]*sh_invrc6*sh_invrc6)*(1.0/12.0) -(Vvdw6-c6[i]*sh_invrc6)*(1.0/6.0)); } else { Vvdw[i] = Vvdw12*(1.0/12.0)-Vvdw6*(1.0/6.0); } FscalV[i] = (Vvdw12-Vvdw6)*rpinvV; break; case GMX_NBKERNEL_VDW_BUCKINGHAM: gmx_fatal(FARGS, "Buckingham free energy not supported."); break; case GMX_NBKERNEL_VDW_CUBICSPLINETABLE: /* Table LJ */ nnn = n1V+4; /* dispersion */ Y = VFtab[nnn]; F = VFtab[nnn+1]; Geps = epsV*VFtab[nnn+2]; Heps2 = eps2V*VFtab[nnn+3]; Fp = F+Geps+Heps2; VV = Y+epsV*Fp; FF = Fp+Geps+2.0*Heps2; Vvdw[i] += c6[i]*VV; FscalV[i] -= c6[i]*tabscale*FF*rV*rpinvV; /* repulsion */ Y = VFtab[nnn+4]; F = VFtab[nnn+5]; Geps = epsV*VFtab[nnn+6]; Heps2 = eps2V*VFtab[nnn+7]; Fp = F+Geps+Heps2; VV = Y+epsV*Fp; FF = Fp+Geps+2.0*Heps2; Vvdw[i] += c12[i]*VV; FscalV[i] -= c12[i]*tabscale*FF*rV*rpinvV; break; default: Vvdw[i] = 0.0; FscalV[i] = 0.0; break; } if (fr->vdw_modifier == eintmodPOTSWITCH) { d = rV-rswitch; d = (d > 0.0) ? d : 0.0; d2 = d*d; sw = 1.0+d2*d*(swV3+d*(swV4+d*swV5)); dsw = d2*(swF2+d*(swF3+d*swF4)); Vvdw[i] *= sw; FscalV[i] = FscalV[i]*sw + Vvdw[i]*dsw; FscalV[i] = (rV < rvdw) ? FscalV[i] : 0.0; Vvdw[i] = (rV < rvdw) ? Vvdw[i] : 0.0; } } } } Fscal = 0; if (icoul == GMX_NBKERNEL_ELEC_EWALD && !(bExactElecCutoff && r >= rcoulomb)) { /* because we compute the softcore normally, we have to remove the ewald short range portion. Done outside of the states loop because this part doesn't depend on the scaled R */ #ifdef GMX_DOUBLE /* Relative accuracy at R_ERF_R_INACC of 3e-10 */ #define R_ERF_R_INACC 0.006 #else /* Relative accuracy at R_ERF_R_INACC of 2e-5 */ #define R_ERF_R_INACC 0.1 #endif if (ewc*r > R_ERF_R_INACC) { VV = gmx_erf(ewc*r)*rinv; FF = rinv*rinv*(VV - ewc*M_2_SQRTPI*exp(-ewc*ewc*rsq)); } else { VV = ewc*M_2_SQRTPI; FF = ewc*ewc*ewc*M_2_SQRTPI*(2.0/3.0 - 0.4*ewc*ewc*rsq); } for (i = 0; i < NSTATES; i++) { vctot -= LFC[i]*qq[i]*VV; Fscal -= LFC[i]*qq[i]*FF; dvdl_coul -= (DLF[i]*qq[i])*VV; } } /* Assemble A and B states */ for (i = 0; i < NSTATES; i++) { vctot += LFC[i]*Vcoul[i]; vvtot += LFV[i]*Vvdw[i]; Fscal += LFC[i]*FscalC[i]*rpm2; Fscal += LFV[i]*FscalV[i]*rpm2; dvdl_coul += Vcoul[i]*DLF[i] + LFC[i]*alpha_coul_eff*dlfac_coul[i]*FscalC[i]*sigma_pow[i]; dvdl_vdw += Vvdw[i]*DLF[i] + LFV[i]*alpha_vdw_eff*dlfac_vdw[i]*FscalV[i]*sigma_pow[i]; } if (bDoForces) { tx = Fscal*dx; ty = Fscal*dy; tz = Fscal*dz; fix = fix + tx; fiy = fiy + ty; fiz = fiz + tz; f[j3] = f[j3] - tx; f[j3+1] = f[j3+1] - ty; f[j3+2] = f[j3+2] - tz; } } if (bDoForces) { f[ii3] = f[ii3] + fix; f[ii3+1] = f[ii3+1] + fiy; f[ii3+2] = f[ii3+2] + fiz; fshift[is3] = fshift[is3] + fix; fshift[is3+1] = fshift[is3+1] + fiy; fshift[is3+2] = fshift[is3+2] + fiz; } ggid = gid[n]; Vc[ggid] = Vc[ggid] + vctot; Vv[ggid] = Vv[ggid] + vvtot; } dvdl[efptCOUL] += dvdl_coul; dvdl[efptVDW] += dvdl_vdw; /* Estimate flops, average for free energy stuff: * 12 flops per outer iteration * 150 flops per inner iteration */ inc_nrnb(nrnb, eNR_NBKERNEL_FREE_ENERGY, nlist->nri*12 + nlist->jindex[n]*150); }
real do_walls(t_inputrec *ir,t_forcerec *fr,matrix box,t_mdatoms *md, rvec x[],rvec f[],real lambda,real Vlj[],t_nrnb *nrnb) { int nwall,w,lam,i; int ntw[2],at,ntype,ngid,ggid,*egp_flags,*type; real *nbfp,lamfac,fac_d[2],fac_r[2],Cd,Cr,Vtot,Fwall[2]; real wall_z[2],r,mr,r1,r2,r4,Vd,Vr,V=0,Fd,Fr,F=0,dvdlambda; dvec xf_z; int n0,nnn; real tabscale,*VFtab,rt,eps,eps2,Yt,Ft,Geps,Heps,Heps2,Fp,VV,FF; unsigned short *gid=md->cENER; t_forcetable *tab; nwall = ir->nwall; ngid = ir->opts.ngener; ntype = fr->ntype; nbfp = fr->nbfp; egp_flags = fr->egp_flags; for(w=0; w<nwall; w++) { ntw[w] = 2*ntype*ir->wall_atomtype[w]; switch (ir->wall_type) { case ewt93: fac_d[w] = ir->wall_density[w]*M_PI/6; fac_r[w] = ir->wall_density[w]*M_PI/45; break; case ewt104: fac_d[w] = ir->wall_density[w]*M_PI/2; fac_r[w] = ir->wall_density[w]*M_PI/5; break; default: break; } Fwall[w] = 0; } wall_z[0] = 0; wall_z[1] = box[ZZ][ZZ]; Vtot = 0; dvdlambda = 0; clear_dvec(xf_z); for(lam=0; lam<(md->nPerturbed ? 2 : 1); lam++) { if (md->nPerturbed) { if (lam == 0) { lamfac = 1 - lambda; type = md->typeA; } else { lamfac = 0; type = md->typeB; } } else { lamfac = 1; type = md->typeA; } for(i=md->start; i<md->start+md->homenr; i++) { for(w=0; w<nwall; w++) { /* The wall energy groups are always at the end of the list */ ggid = gid[i]*ngid + ngid - nwall + w; at = type[i]; Cd = nbfp[ntw[w]+2*at]; Cr = nbfp[ntw[w]+2*at+1]; if (!((Cd==0 && Cr==0) || (egp_flags[ggid] & EGP_EXCL))) { if (w == 0) { r = x[i][ZZ]; } else { r = wall_z[1] - x[i][ZZ]; } if (r < ir->wall_r_linpot) { mr = ir->wall_r_linpot - r; r = ir->wall_r_linpot; } else { mr = 0; } switch (ir->wall_type) { case ewtTABLE: if (r < 0) { wall_error(i,x,r); } tab = &(fr->wall_tab[w][gid[i]]); tabscale = tab->scale; VFtab = tab->tab; rt = r*tabscale; n0 = rt; if (n0 >= tab->n) { /* Beyond the table range, set V and F to zero */ V = 0; F = 0; } else { eps = rt - n0; eps2 = eps*eps; /* Dispersion */ nnn = 8*n0; Yt = VFtab[nnn]; Ft = VFtab[nnn+1]; Geps = VFtab[nnn+2]*eps; Heps2 = VFtab[nnn+3]*eps2; Fp = Ft + Geps + Heps2; VV = Yt + Fp*eps; FF = Fp + Geps + 2.0*Heps2; Vd = Cd*VV; Fd = Cd*FF; /* Repulsion */ nnn = nnn + 4; Yt = VFtab[nnn]; Ft = VFtab[nnn+1]; Geps = VFtab[nnn+2]*eps; Heps2 = VFtab[nnn+3]*eps2; Fp = Ft + Geps + Heps2; VV = Yt + Fp*eps; FF = Fp + Geps + 2.0*Heps2; Vr = Cr*VV; Fr = Cr*FF; V = Vd + Vr; F = -lamfac*(Fd + Fr)*tabscale; } break; case ewt93: if (r <= 0) { wall_error(i,x,r); } r1 = 1/r; r2 = r1*r1; r4 = r2*r2; Vd = fac_d[w]*Cd*r2*r1; Vr = fac_r[w]*Cr*r4*r4*r1; V = Vr - Vd; F = lamfac*(9*Vr - 3*Vd)*r1; break; case ewt104: if (r <= 0) { wall_error(i,x,r); } r1 = 1/r; r2 = r1*r1; r4 = r2*r2; Vd = fac_d[w]*Cd*r4; Vr = fac_r[w]*Cr*r4*r4*r2; V = Vr - Vd; F = lamfac*(10*Vr - 4*Vd)*r1; break; case ewt126: if (r <= 0) { wall_error(i,x,r); } r1 = 1/r; r2 = r1*r1; r4 = r2*r2; Vd = Cd*r4*r2; Vr = Cr*r4*r4*r4; V = Vr - Vd; F = lamfac*(12*Vr - 6*Vd)*r1; break; default: break; } if (mr > 0) { V += mr*F; } if (w == 1) { F = -F; } Vlj[ggid] += lamfac*V; Vtot += V; f[i][ZZ] += F; /* Because of the single sum virial calculation we need * to add the full virial contribution of the walls. * Since the force only has a z-component, there is only * a contribution to the z component of the virial tensor. * We could also determine the virial contribution directly, * which would be cheaper here, but that would require extra * communication for f_novirsum for with virtual sites * in parallel. */ xf_z[XX] -= x[i][XX]*F; xf_z[YY] -= x[i][YY]*F; xf_z[ZZ] -= wall_z[w]*F; } } } if (md->nPerturbed) { dvdlambda += (lam==0 ? -1 : 1)*Vtot; } inc_nrnb(nrnb,eNR_WALLS,md->homenr); } for(i=0; i<DIM; i++) { fr->vir_wall_z[i] = -0.5*xf_z[i]; } return dvdlambda; }
/* TODO Specialize this routine into init-time and loop-time versions? e.g. bReadEkin is only true when restoring from checkpoint */ void compute_globals(FILE *fplog, gmx_global_stat *gstat, t_commrec *cr, t_inputrec *ir, t_forcerec *fr, gmx_ekindata_t *ekind, t_state *state, t_mdatoms *mdatoms, t_nrnb *nrnb, t_vcm *vcm, gmx_wallcycle_t wcycle, gmx_enerdata_t *enerd, tensor force_vir, tensor shake_vir, tensor total_vir, tensor pres, rvec mu_tot, gmx_constr_t constr, gmx::SimulationSignaller *signalCoordinator, matrix box, int *totalNumberOfBondedInteractions, gmx_bool *bSumEkinhOld, int flags) { tensor corr_vir, corr_pres; gmx_bool bEner, bPres, bTemp; gmx_bool bStopCM, bGStat, bReadEkin, bEkinAveVel, bScaleEkin, bConstrain; real prescorr, enercorr, dvdlcorr, dvdl_ekin; /* translate CGLO flags to gmx_booleans */ bStopCM = flags & CGLO_STOPCM; bGStat = flags & CGLO_GSTAT; bReadEkin = (flags & CGLO_READEKIN); bScaleEkin = (flags & CGLO_SCALEEKIN); bEner = flags & CGLO_ENERGY; bTemp = flags & CGLO_TEMPERATURE; bPres = (flags & CGLO_PRESSURE); bConstrain = (flags & CGLO_CONSTRAINT); /* we calculate a full state kinetic energy either with full-step velocity verlet or half step where we need the pressure */ bEkinAveVel = (ir->eI == eiVV || (ir->eI == eiVVAK && bPres) || bReadEkin); /* in initalization, it sums the shake virial in vv, and to sums ekinh_old in leapfrog (or if we are calculating ekinh_old) for other reasons */ /* ########## Kinetic energy ############## */ if (bTemp) { /* Non-equilibrium MD: this is parallellized, but only does communication * when there really is NEMD. */ if (PAR(cr) && (ekind->bNEMD)) { accumulate_u(cr, &(ir->opts), ekind); } if (!bReadEkin) { calc_ke_part(state, &(ir->opts), mdatoms, ekind, nrnb, bEkinAveVel); } } /* Calculate center of mass velocity if necessary, also parallellized */ if (bStopCM) { calc_vcm_grp(0, mdatoms->homenr, mdatoms, state->x, state->v, vcm); } if (bTemp || bStopCM || bPres || bEner || bConstrain) { if (!bGStat) { /* We will not sum ekinh_old, * so signal that we still have to do it. */ *bSumEkinhOld = TRUE; } else { gmx::ArrayRef<real> signalBuffer = signalCoordinator->getCommunicationBuffer(); if (PAR(cr)) { wallcycle_start(wcycle, ewcMoveE); global_stat(gstat, cr, enerd, force_vir, shake_vir, mu_tot, ir, ekind, constr, bStopCM ? vcm : NULL, signalBuffer.size(), signalBuffer.data(), totalNumberOfBondedInteractions, *bSumEkinhOld, flags); wallcycle_stop(wcycle, ewcMoveE); } signalCoordinator->finalizeSignals(); *bSumEkinhOld = FALSE; } } if (!ekind->bNEMD && debug && bTemp && (vcm->nr > 0)) { correct_ekin(debug, 0, mdatoms->homenr, state->v, vcm->group_p[0], mdatoms->massT, mdatoms->tmass, ekind->ekin); } /* Do center of mass motion removal */ if (bStopCM) { check_cm_grp(fplog, vcm, ir, 1); do_stopcm_grp(0, mdatoms->homenr, mdatoms->cVCM, state->x, state->v, vcm); inc_nrnb(nrnb, eNR_STOPCM, mdatoms->homenr); } if (bEner) { /* Calculate the amplitude of the cosine velocity profile */ ekind->cosacc.vcos = ekind->cosacc.mvcos/mdatoms->tmass; } if (bTemp) { /* Sum the kinetic energies of the groups & calc temp */ /* compute full step kinetic energies if vv, or if vv-avek and we are computing the pressure with inputrecNptTrotter */ /* three maincase: VV with AveVel (md-vv), vv with AveEkin (md-vv-avek), leap with AveEkin (md). Leap with AveVel is not supported; it's not clear that it will actually work. bEkinAveVel: If TRUE, we simply multiply ekin by ekinscale to get a full step kinetic energy. If FALSE, we average ekinh_old and ekinh*ekinscale_nhc to get an averaged half step kinetic energy. */ enerd->term[F_TEMP] = sum_ekin(&(ir->opts), ekind, &dvdl_ekin, bEkinAveVel, bScaleEkin); enerd->dvdl_lin[efptMASS] = (double) dvdl_ekin; enerd->term[F_EKIN] = trace(ekind->ekin); } /* ########## Long range energy information ###### */ if (bEner || bPres || bConstrain) { calc_dispcorr(ir, fr, box, state->lambda[efptVDW], corr_pres, corr_vir, &prescorr, &enercorr, &dvdlcorr); } if (bEner) { enerd->term[F_DISPCORR] = enercorr; enerd->term[F_EPOT] += enercorr; enerd->term[F_DVDL_VDW] += dvdlcorr; } /* ########## Now pressure ############## */ if (bPres || bConstrain) { m_add(force_vir, shake_vir, total_vir); /* Calculate pressure and apply LR correction if PPPM is used. * Use the box from last timestep since we already called update(). */ enerd->term[F_PRES] = calc_pres(fr->ePBC, ir->nwall, box, ekind->ekin, total_vir, pres); /* Calculate long range corrections to pressure and energy */ /* this adds to enerd->term[F_PRES] and enerd->term[F_ETOT], and computes enerd->term[F_DISPCORR]. Also modifies the total_vir and pres tesors */ m_add(total_vir, corr_vir, total_vir); m_add(pres, corr_pres, pres); enerd->term[F_PDISPCORR] = prescorr; enerd->term[F_PRES] += prescorr; } }
void do_force_lowlevel(t_forcerec *fr, t_inputrec *ir, t_idef *idef, t_commrec *cr, t_nrnb *nrnb, gmx_wallcycle_t wcycle, t_mdatoms *md, rvec x[], history_t *hist, rvec f[], rvec f_longrange[], gmx_enerdata_t *enerd, t_fcdata *fcd, gmx_localtop_t *top, gmx_genborn_t *born, gmx_bool bBornRadii, matrix box, t_lambda *fepvals, real *lambda, t_graph *graph, t_blocka *excl, rvec mu_tot[], int flags, float *cycles_pme) { int i, j; int donb_flags; gmx_bool bSB; int pme_flags; matrix boxs; rvec box_size; t_pbc pbc; real dvdl_dum[efptNR], dvdl_nb[efptNR]; #ifdef GMX_MPI double t0 = 0.0, t1, t2, t3; /* time measurement for coarse load balancing */ #endif set_pbc(&pbc, fr->ePBC, box); /* reset free energy components */ for (i = 0; i < efptNR; i++) { dvdl_nb[i] = 0; dvdl_dum[i] = 0; } /* Reset box */ for (i = 0; (i < DIM); i++) { box_size[i] = box[i][i]; } debug_gmx(); /* do QMMM first if requested */ if (fr->bQMMM) { enerd->term[F_EQM] = calculate_QMMM(cr, x, f, fr); } /* Call the short range functions all in one go. */ #ifdef GMX_MPI /*#define TAKETIME ((cr->npmenodes) && (fr->timesteps < 12))*/ #define TAKETIME FALSE if (TAKETIME) { MPI_Barrier(cr->mpi_comm_mygroup); t0 = MPI_Wtime(); } #endif if (ir->nwall) { /* foreign lambda component for walls */ real dvdl_walls = do_walls(ir, fr, box, md, x, f, lambda[efptVDW], enerd->grpp.ener[egLJSR], nrnb); enerd->dvdl_lin[efptVDW] += dvdl_walls; } /* If doing GB, reset dvda and calculate the Born radii */ if (ir->implicit_solvent) { wallcycle_sub_start(wcycle, ewcsNONBONDED); for (i = 0; i < born->nr; i++) { fr->dvda[i] = 0; } if (bBornRadii) { calc_gb_rad(cr, fr, ir, top, x, &(fr->gblist), born, md, nrnb); } wallcycle_sub_stop(wcycle, ewcsNONBONDED); } where(); /* We only do non-bonded calculation with group scheme here, the verlet * calls are done from do_force_cutsVERLET(). */ if (fr->cutoff_scheme == ecutsGROUP && (flags & GMX_FORCE_NONBONDED)) { donb_flags = 0; /* Add short-range interactions */ donb_flags |= GMX_NONBONDED_DO_SR; /* Currently all group scheme kernels always calculate (shift-)forces */ if (flags & GMX_FORCE_FORCES) { donb_flags |= GMX_NONBONDED_DO_FORCE; } if (flags & GMX_FORCE_VIRIAL) { donb_flags |= GMX_NONBONDED_DO_SHIFTFORCE; } if (flags & GMX_FORCE_ENERGY) { donb_flags |= GMX_NONBONDED_DO_POTENTIAL; } if (flags & GMX_FORCE_DO_LR) { donb_flags |= GMX_NONBONDED_DO_LR; } wallcycle_sub_start(wcycle, ewcsNONBONDED); do_nonbonded(fr, x, f, f_longrange, md, excl, &enerd->grpp, nrnb, lambda, dvdl_nb, -1, -1, donb_flags); /* If we do foreign lambda and we have soft-core interactions * we have to recalculate the (non-linear) energies contributions. */ if (fepvals->n_lambda > 0 && (flags & GMX_FORCE_DHDL) && fepvals->sc_alpha != 0) { for (i = 0; i < enerd->n_lambda; i++) { real lam_i[efptNR]; for (j = 0; j < efptNR; j++) { lam_i[j] = (i == 0 ? lambda[j] : fepvals->all_lambda[j][i-1]); } reset_foreign_enerdata(enerd); do_nonbonded(fr, x, f, f_longrange, md, excl, &(enerd->foreign_grpp), nrnb, lam_i, dvdl_dum, -1, -1, (donb_flags & ~GMX_NONBONDED_DO_FORCE) | GMX_NONBONDED_DO_FOREIGNLAMBDA); sum_epot(&(enerd->foreign_grpp), enerd->foreign_term); enerd->enerpart_lambda[i] += enerd->foreign_term[F_EPOT]; } } wallcycle_sub_stop(wcycle, ewcsNONBONDED); where(); } /* If we are doing GB, calculate bonded forces and apply corrections * to the solvation forces */ /* MRS: Eventually, many need to include free energy contribution here! */ if (ir->implicit_solvent) { wallcycle_sub_start(wcycle, ewcsLISTED); calc_gb_forces(cr, md, born, top, x, f, fr, idef, ir->gb_algorithm, ir->sa_algorithm, nrnb, &pbc, graph, enerd); wallcycle_sub_stop(wcycle, ewcsLISTED); } #ifdef GMX_MPI if (TAKETIME) { t1 = MPI_Wtime(); fr->t_fnbf += t1-t0; } #endif if (fepvals->sc_alpha != 0) { enerd->dvdl_nonlin[efptVDW] += dvdl_nb[efptVDW]; } else { enerd->dvdl_lin[efptVDW] += dvdl_nb[efptVDW]; } if (fepvals->sc_alpha != 0) /* even though coulomb part is linear, we already added it, beacuse we need to go through the vdw calculation anyway */ { enerd->dvdl_nonlin[efptCOUL] += dvdl_nb[efptCOUL]; } else { enerd->dvdl_lin[efptCOUL] += dvdl_nb[efptCOUL]; } debug_gmx(); if (debug) { pr_rvecs(debug, 0, "fshift after SR", fr->fshift, SHIFTS); } /* Shift the coordinates. Must be done before listed forces and PPPM, * but is also necessary for SHAKE and update, therefore it can NOT * go when no listed forces have to be evaluated. * * The shifting and PBC code is deliberately not timed, since with * the Verlet scheme it only takes non-zero time with triclinic * boxes, and even then the time is around a factor of 100 less * than the next smallest counter. */ /* Here sometimes we would not need to shift with NBFonly, * but we do so anyhow for consistency of the returned coordinates. */ if (graph) { shift_self(graph, box, x); if (TRICLINIC(box)) { inc_nrnb(nrnb, eNR_SHIFTX, 2*graph->nnodes); } else { inc_nrnb(nrnb, eNR_SHIFTX, graph->nnodes); } } /* Check whether we need to do listed interactions or correct for exclusions */ if (fr->bMolPBC && ((flags & GMX_FORCE_LISTED) || EEL_RF(fr->eeltype) || EEL_FULL(fr->eeltype) || EVDW_PME(fr->vdwtype))) { /* TODO There are no electrostatics methods that require this transformation, when using the Verlet scheme, so update the above conditional. */ /* Since all atoms are in the rectangular or triclinic unit-cell, * only single box vector shifts (2 in x) are required. */ set_pbc_dd(&pbc, fr->ePBC, cr->dd, TRUE, box); } debug_gmx(); do_force_listed(wcycle, box, ir->fepvals, cr->ms, idef, (const rvec *) x, hist, f, fr, &pbc, graph, enerd, nrnb, lambda, md, fcd, DOMAINDECOMP(cr) ? cr->dd->gatindex : NULL, flags); where(); *cycles_pme = 0; clear_mat(fr->vir_el_recip); clear_mat(fr->vir_lj_recip); /* Do long-range electrostatics and/or LJ-PME, including related short-range * corrections. */ if (EEL_FULL(fr->eeltype) || EVDW_PME(fr->vdwtype)) { int status = 0; real Vlr_q = 0, Vlr_lj = 0, Vcorr_q = 0, Vcorr_lj = 0; real dvdl_long_range_q = 0, dvdl_long_range_lj = 0; bSB = (ir->nwall == 2); if (bSB) { copy_mat(box, boxs); svmul(ir->wall_ewald_zfac, boxs[ZZ], boxs[ZZ]); box_size[ZZ] *= ir->wall_ewald_zfac; } if (EEL_PME_EWALD(fr->eeltype) || EVDW_PME(fr->vdwtype)) { real dvdl_long_range_correction_q = 0; real dvdl_long_range_correction_lj = 0; /* With the Verlet scheme exclusion forces are calculated * in the non-bonded kernel. */ /* The TPI molecule does not have exclusions with the rest * of the system and no intra-molecular PME grid * contributions will be calculated in * gmx_pme_calc_energy. */ if ((ir->cutoff_scheme == ecutsGROUP && fr->n_tpi == 0) || ir->ewald_geometry != eewg3D || ir->epsilon_surface != 0) { int nthreads, t; wallcycle_sub_start(wcycle, ewcsEWALD_CORRECTION); if (fr->n_tpi > 0) { gmx_fatal(FARGS, "TPI with PME currently only works in a 3D geometry with tin-foil boundary conditions"); } nthreads = fr->nthread_ewc; #pragma omp parallel for num_threads(nthreads) schedule(static) for (t = 0; t < nthreads; t++) { try { tensor *vir_q, *vir_lj; real *Vcorrt_q, *Vcorrt_lj, *dvdlt_q, *dvdlt_lj; if (t == 0) { vir_q = &fr->vir_el_recip; vir_lj = &fr->vir_lj_recip; Vcorrt_q = &Vcorr_q; Vcorrt_lj = &Vcorr_lj; dvdlt_q = &dvdl_long_range_correction_q; dvdlt_lj = &dvdl_long_range_correction_lj; } else { vir_q = &fr->ewc_t[t].vir_q; vir_lj = &fr->ewc_t[t].vir_lj; Vcorrt_q = &fr->ewc_t[t].Vcorr_q; Vcorrt_lj = &fr->ewc_t[t].Vcorr_lj; dvdlt_q = &fr->ewc_t[t].dvdl[efptCOUL]; dvdlt_lj = &fr->ewc_t[t].dvdl[efptVDW]; clear_mat(*vir_q); clear_mat(*vir_lj); } *dvdlt_q = 0; *dvdlt_lj = 0; /* Threading is only supported with the Verlet cut-off * scheme and then only single particle forces (no * exclusion forces) are calculated, so we can store * the forces in the normal, single fr->f_novirsum array. */ ewald_LRcorrection(fr->excl_load[t], fr->excl_load[t+1], cr, t, fr, md->chargeA, md->chargeB, md->sqrt_c6A, md->sqrt_c6B, md->sigmaA, md->sigmaB, md->sigma3A, md->sigma3B, md->nChargePerturbed || md->nTypePerturbed, ir->cutoff_scheme != ecutsVERLET, excl, x, bSB ? boxs : box, mu_tot, ir->ewald_geometry, ir->epsilon_surface, fr->f_novirsum, *vir_q, *vir_lj, Vcorrt_q, Vcorrt_lj, lambda[efptCOUL], lambda[efptVDW], dvdlt_q, dvdlt_lj); } GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR; } if (nthreads > 1) { reduce_thread_energies(fr->vir_el_recip, fr->vir_lj_recip, &Vcorr_q, &Vcorr_lj, &dvdl_long_range_correction_q, &dvdl_long_range_correction_lj, nthreads, fr->ewc_t); } wallcycle_sub_stop(wcycle, ewcsEWALD_CORRECTION); }
void do_force_lowlevel(FILE *fplog, gmx_large_int_t step, t_forcerec *fr, t_inputrec *ir, t_idef *idef, t_commrec *cr, t_nrnb *nrnb, gmx_wallcycle_t wcycle, t_mdatoms *md, t_grpopts *opts, rvec x[], history_t *hist, rvec f[], gmx_enerdata_t *enerd, t_fcdata *fcd, gmx_mtop_t *mtop, gmx_localtop_t *top, gmx_genborn_t *born, t_atomtypes *atype, gmx_bool bBornRadii, matrix box, real lambda, t_graph *graph, t_blocka *excl, rvec mu_tot[], int flags, float *cycles_pme) { int i,status; int donb_flags; gmx_bool bDoEpot,bSepDVDL,bSB; int pme_flags; matrix boxs; rvec box_size; real dvdlambda,Vsr,Vlr,Vcorr=0,vdip,vcharge; t_pbc pbc; real dvdgb; char buf[22]; gmx_enerdata_t ed_lam; double lam_i; real dvdl_dum; #ifdef GMX_MPI double t0=0.0,t1,t2,t3; /* time measurement for coarse load balancing */ #endif #define PRINT_SEPDVDL(s,v,dvdl) if (bSepDVDL) fprintf(fplog,sepdvdlformat,s,v,dvdl); GMX_MPE_LOG(ev_force_start); set_pbc(&pbc,fr->ePBC,box); /* Reset box */ for(i=0; (i<DIM); i++) { box_size[i]=box[i][i]; } bSepDVDL=(fr->bSepDVDL && do_per_step(step,ir->nstlog)); debug_gmx(); /* do QMMM first if requested */ if(fr->bQMMM) { enerd->term[F_EQM] = calculate_QMMM(cr,x,f,fr,md); } if (bSepDVDL) { fprintf(fplog,"Step %s: non-bonded V and dVdl for node %d:\n", gmx_step_str(step,buf),cr->nodeid); } /* Call the short range functions all in one go. */ GMX_MPE_LOG(ev_do_fnbf_start); dvdlambda = 0; #ifdef GMX_MPI /*#define TAKETIME ((cr->npmenodes) && (fr->timesteps < 12))*/ #define TAKETIME FALSE if (TAKETIME) { MPI_Barrier(cr->mpi_comm_mygroup); t0=MPI_Wtime(); } #endif if (ir->nwall) { dvdlambda = do_walls(ir,fr,box,md,x,f,lambda, enerd->grpp.ener[egLJSR],nrnb); PRINT_SEPDVDL("Walls",0.0,dvdlambda); enerd->dvdl_lin += dvdlambda; } /* If doing GB, reset dvda and calculate the Born radii */ if (ir->implicit_solvent) { /* wallcycle_start(wcycle,ewcGB); */ for(i=0; i<born->nr; i++) { fr->dvda[i]=0; } if(bBornRadii) { calc_gb_rad(cr,fr,ir,top,atype,x,&(fr->gblist),born,md,nrnb); } /* wallcycle_stop(wcycle, ewcGB); */ } where(); donb_flags = 0; if (flags & GMX_FORCE_FORCES) { donb_flags |= GMX_DONB_FORCES; } do_nonbonded(cr,fr,x,f,md,excl, fr->bBHAM ? enerd->grpp.ener[egBHAMSR] : enerd->grpp.ener[egLJSR], enerd->grpp.ener[egCOULSR], enerd->grpp.ener[egGB],box_size,nrnb, lambda,&dvdlambda,-1,-1,donb_flags); /* If we do foreign lambda and we have soft-core interactions * we have to recalculate the (non-linear) energies contributions. */ if (ir->n_flambda > 0 && (flags & GMX_FORCE_DHDL) && ir->sc_alpha != 0) { init_enerdata(mtop->groups.grps[egcENER].nr,ir->n_flambda,&ed_lam); for(i=0; i<enerd->n_lambda; i++) { lam_i = (i==0 ? lambda : ir->flambda[i-1]); dvdl_dum = 0; reset_enerdata(&ir->opts,fr,TRUE,&ed_lam,FALSE); do_nonbonded(cr,fr,x,f,md,excl, fr->bBHAM ? ed_lam.grpp.ener[egBHAMSR] : ed_lam.grpp.ener[egLJSR], ed_lam.grpp.ener[egCOULSR], enerd->grpp.ener[egGB], box_size,nrnb, lam_i,&dvdl_dum,-1,-1, GMX_DONB_FOREIGNLAMBDA); sum_epot(&ir->opts,&ed_lam); enerd->enerpart_lambda[i] += ed_lam.term[F_EPOT]; } destroy_enerdata(&ed_lam); } where(); /* If we are doing GB, calculate bonded forces and apply corrections * to the solvation forces */ if (ir->implicit_solvent) { calc_gb_forces(cr,md,born,top,atype,x,f,fr,idef, ir->gb_algorithm,ir->sa_algorithm,nrnb,bBornRadii,&pbc,graph,enerd); } #ifdef GMX_MPI if (TAKETIME) { t1=MPI_Wtime(); fr->t_fnbf += t1-t0; } #endif if (ir->sc_alpha != 0) { enerd->dvdl_nonlin += dvdlambda; } else { enerd->dvdl_lin += dvdlambda; } Vsr = 0; if (bSepDVDL) { for(i=0; i<enerd->grpp.nener; i++) { Vsr += (fr->bBHAM ? enerd->grpp.ener[egBHAMSR][i] : enerd->grpp.ener[egLJSR][i]) + enerd->grpp.ener[egCOULSR][i] + enerd->grpp.ener[egGB][i]; } } PRINT_SEPDVDL("VdW and Coulomb SR particle-p.",Vsr,dvdlambda); debug_gmx(); GMX_MPE_LOG(ev_do_fnbf_finish); if (debug) { pr_rvecs(debug,0,"fshift after SR",fr->fshift,SHIFTS); } /* Shift the coordinates. Must be done before bonded forces and PPPM, * but is also necessary for SHAKE and update, therefore it can NOT * go when no bonded forces have to be evaluated. */ /* Here sometimes we would not need to shift with NBFonly, * but we do so anyhow for consistency of the returned coordinates. */ if (graph) { shift_self(graph,box,x); if (TRICLINIC(box)) { inc_nrnb(nrnb,eNR_SHIFTX,2*graph->nnodes); } else { inc_nrnb(nrnb,eNR_SHIFTX,graph->nnodes); } } /* Check whether we need to do bondeds or correct for exclusions */ if (fr->bMolPBC && ((flags & GMX_FORCE_BONDED) || EEL_RF(fr->eeltype) || EEL_FULL(fr->eeltype))) { /* Since all atoms are in the rectangular or triclinic unit-cell, * only single box vector shifts (2 in x) are required. */ set_pbc_dd(&pbc,fr->ePBC,cr->dd,TRUE,box); } debug_gmx(); if (flags & GMX_FORCE_BONDED) { GMX_MPE_LOG(ev_calc_bonds_start); calc_bonds(fplog,cr->ms, idef,x,hist,f,fr,&pbc,graph,enerd,nrnb,lambda,md,fcd, DOMAINDECOMP(cr) ? cr->dd->gatindex : NULL, atype, born, fr->bSepDVDL && do_per_step(step,ir->nstlog),step); /* Check if we have to determine energy differences * at foreign lambda's. */ if (ir->n_flambda > 0 && (flags & GMX_FORCE_DHDL) && idef->ilsort != ilsortNO_FE) { if (idef->ilsort != ilsortFE_SORTED) { gmx_incons("The bonded interactions are not sorted for free energy"); } init_enerdata(mtop->groups.grps[egcENER].nr,ir->n_flambda,&ed_lam); for(i=0; i<enerd->n_lambda; i++) { lam_i = (i==0 ? lambda : ir->flambda[i-1]); dvdl_dum = 0; reset_enerdata(&ir->opts,fr,TRUE,&ed_lam,FALSE); calc_bonds_lambda(fplog, idef,x,fr,&pbc,graph,&ed_lam,nrnb,lam_i,md, fcd, DOMAINDECOMP(cr) ? cr->dd->gatindex : NULL); sum_epot(&ir->opts,&ed_lam); enerd->enerpart_lambda[i] += ed_lam.term[F_EPOT]; } destroy_enerdata(&ed_lam); } debug_gmx(); GMX_MPE_LOG(ev_calc_bonds_finish); } where(); *cycles_pme = 0; if (EEL_FULL(fr->eeltype)) { bSB = (ir->nwall == 2); if (bSB) { copy_mat(box,boxs); svmul(ir->wall_ewald_zfac,boxs[ZZ],boxs[ZZ]); box_size[ZZ] *= ir->wall_ewald_zfac; } clear_mat(fr->vir_el_recip); if (fr->bEwald) { if (fr->n_tpi == 0) { dvdlambda = 0; Vcorr = ewald_LRcorrection(fplog,md->start,md->start+md->homenr, cr,fr, md->chargeA, md->nChargePerturbed ? md->chargeB : NULL, excl,x,bSB ? boxs : box,mu_tot, ir->ewald_geometry, ir->epsilon_surface, lambda,&dvdlambda,&vdip,&vcharge); PRINT_SEPDVDL("Ewald excl./charge/dip. corr.",Vcorr,dvdlambda); enerd->dvdl_lin += dvdlambda; } else { if (ir->ewald_geometry != eewg3D || ir->epsilon_surface != 0) { gmx_fatal(FARGS,"TPI with PME currently only works in a 3D geometry with tin-foil boundary conditions"); } /* The TPI molecule does not have exclusions with the rest * of the system and no intra-molecular PME grid contributions * will be calculated in gmx_pme_calc_energy. */ Vcorr = 0; } } else { Vcorr = shift_LRcorrection(fplog,md->start,md->homenr,cr,fr, md->chargeA,excl,x,TRUE,box, fr->vir_el_recip); } dvdlambda = 0; status = 0; switch (fr->eeltype) { case eelPPPM: status = gmx_pppm_do(fplog,fr->pmedata,FALSE,x,fr->f_novirsum, md->chargeA, box_size,fr->phi,cr,md->start,md->homenr, nrnb,ir->pme_order,&Vlr); break; case eelPME: case eelPMESWITCH: case eelPMEUSER: case eelPMEUSERSWITCH: if (cr->duty & DUTY_PME) { if (fr->n_tpi == 0 || (flags & GMX_FORCE_STATECHANGED)) { pme_flags = GMX_PME_SPREAD_Q | GMX_PME_SOLVE; if (flags & GMX_FORCE_FORCES) { pme_flags |= GMX_PME_CALC_F; } if (flags & GMX_FORCE_VIRIAL) { pme_flags |= GMX_PME_CALC_ENER_VIR; } if (fr->n_tpi > 0) { /* We don't calculate f, but we do want the potential */ pme_flags |= GMX_PME_CALC_POT; } wallcycle_start(wcycle,ewcPMEMESH); status = gmx_pme_do(fr->pmedata, md->start,md->homenr - fr->n_tpi, x,fr->f_novirsum, md->chargeA,md->chargeB, bSB ? boxs : box,cr, DOMAINDECOMP(cr) ? dd_pme_maxshift_x(cr->dd) : 0, DOMAINDECOMP(cr) ? dd_pme_maxshift_y(cr->dd) : 0, nrnb,wcycle, fr->vir_el_recip,fr->ewaldcoeff, &Vlr,lambda,&dvdlambda, pme_flags); *cycles_pme = wallcycle_stop(wcycle,ewcPMEMESH); /* We should try to do as little computation after * this as possible, because parallel PME synchronizes * the nodes, so we want all load imbalance of the rest * of the force calculation to be before the PME call. * DD load balancing is done on the whole time of * the force call (without PME). */ } if (fr->n_tpi > 0) { /* Determine the PME grid energy of the test molecule * with the PME grid potential of the other charges. */ gmx_pme_calc_energy(fr->pmedata,fr->n_tpi, x + md->homenr - fr->n_tpi, md->chargeA + md->homenr - fr->n_tpi, &Vlr); } PRINT_SEPDVDL("PME mesh",Vlr,dvdlambda); } else { /* Energies and virial are obtained later from the PME nodes */ /* but values have to be zeroed out here */ Vlr=0.0; } break; case eelEWALD: Vlr = do_ewald(fplog,FALSE,ir,x,fr->f_novirsum, md->chargeA,md->chargeB, box_size,cr,md->homenr, fr->vir_el_recip,fr->ewaldcoeff, lambda,&dvdlambda,fr->ewald_table); PRINT_SEPDVDL("Ewald long-range",Vlr,dvdlambda); break; default: Vlr = 0; gmx_fatal(FARGS,"No such electrostatics method implemented %s", eel_names[fr->eeltype]); } if (status != 0) { gmx_fatal(FARGS,"Error %d in long range electrostatics routine %s", status,EELTYPE(fr->eeltype)); } enerd->dvdl_lin += dvdlambda; enerd->term[F_COUL_RECIP] = Vlr + Vcorr; if (debug) { fprintf(debug,"Vlr = %g, Vcorr = %g, Vlr_corr = %g\n", Vlr,Vcorr,enerd->term[F_COUL_RECIP]); pr_rvecs(debug,0,"vir_el_recip after corr",fr->vir_el_recip,DIM); pr_rvecs(debug,0,"fshift after LR Corrections",fr->fshift,SHIFTS); } } else { if (EEL_RF(fr->eeltype)) { dvdlambda = 0; if (fr->eeltype != eelRF_NEC) { enerd->term[F_RF_EXCL] = RF_excl_correction(fplog,fr,graph,md,excl,x,f, fr->fshift,&pbc,lambda,&dvdlambda); } enerd->dvdl_lin += dvdlambda; PRINT_SEPDVDL("RF exclusion correction", enerd->term[F_RF_EXCL],dvdlambda); } } where(); debug_gmx(); if (debug) { print_nrnb(debug,nrnb); } debug_gmx(); #ifdef GMX_MPI if (TAKETIME) { t2=MPI_Wtime(); MPI_Barrier(cr->mpi_comm_mygroup); t3=MPI_Wtime(); fr->t_wait += t3-t2; if (fr->timesteps == 11) { fprintf(stderr,"* PP load balancing info: node %d, step %s, rel wait time=%3.0f%% , load string value: %7.2f\n", cr->nodeid, gmx_step_str(fr->timesteps,buf), 100*fr->t_wait/(fr->t_wait+fr->t_fnbf), (fr->t_fnbf+fr->t_wait)/fr->t_fnbf); } fr->timesteps++; } #endif if (debug) { pr_rvecs(debug,0,"fshift after bondeds",fr->fshift,SHIFTS); } GMX_MPE_LOG(ev_force_finish); }
void do_force_lowlevel(FILE *fplog, gmx_large_int_t step, t_forcerec *fr, t_inputrec *ir, t_idef *idef, t_commrec *cr, t_nrnb *nrnb, gmx_wallcycle_t wcycle, t_mdatoms *md, t_grpopts *opts, rvec x[], history_t *hist, rvec f[], rvec f_longrange[], gmx_enerdata_t *enerd, t_fcdata *fcd, gmx_mtop_t *mtop, gmx_localtop_t *top, gmx_genborn_t *born, t_atomtypes *atype, gmx_bool bBornRadii, matrix box, t_lambda *fepvals, real *lambda, t_graph *graph, t_blocka *excl, rvec mu_tot[], int flags, float *cycles_pme) { int i, j, status; int donb_flags; gmx_bool bDoEpot, bSepDVDL, bSB; int pme_flags; matrix boxs; rvec box_size; real Vsr, Vlr, Vcorr = 0; t_pbc pbc; real dvdgb; char buf[22]; double clam_i, vlam_i; real dvdl_dum[efptNR], dvdl, dvdl_nb[efptNR], lam_i[efptNR]; real dvdlsum; #ifdef GMX_MPI double t0 = 0.0, t1, t2, t3; /* time measurement for coarse load balancing */ #endif #define PRINT_SEPDVDL(s, v, dvdlambda) if (bSepDVDL) {fprintf(fplog, sepdvdlformat, s, v, dvdlambda); } GMX_MPE_LOG(ev_force_start); set_pbc(&pbc, fr->ePBC, box); /* reset free energy components */ for (i = 0; i < efptNR; i++) { dvdl_nb[i] = 0; dvdl_dum[i] = 0; } /* Reset box */ for (i = 0; (i < DIM); i++) { box_size[i] = box[i][i]; } bSepDVDL = (fr->bSepDVDL && do_per_step(step, ir->nstlog)); debug_gmx(); /* do QMMM first if requested */ if (fr->bQMMM) { enerd->term[F_EQM] = calculate_QMMM(cr, x, f, fr, md); } if (bSepDVDL) { fprintf(fplog, "Step %s: non-bonded V and dVdl for node %d:\n", gmx_step_str(step, buf), cr->nodeid); } /* Call the short range functions all in one go. */ GMX_MPE_LOG(ev_do_fnbf_start); #ifdef GMX_MPI /*#define TAKETIME ((cr->npmenodes) && (fr->timesteps < 12))*/ #define TAKETIME FALSE if (TAKETIME) { MPI_Barrier(cr->mpi_comm_mygroup); t0 = MPI_Wtime(); } #endif if (ir->nwall) { /* foreign lambda component for walls */ dvdl = do_walls(ir, fr, box, md, x, f, lambda[efptVDW], enerd->grpp.ener[egLJSR], nrnb); PRINT_SEPDVDL("Walls", 0.0, dvdl); enerd->dvdl_lin[efptVDW] += dvdl; } /* If doing GB, reset dvda and calculate the Born radii */ if (ir->implicit_solvent) { wallcycle_sub_start(wcycle, ewcsNONBONDED); for (i = 0; i < born->nr; i++) { fr->dvda[i] = 0; } if (bBornRadii) { calc_gb_rad(cr, fr, ir, top, atype, x, &(fr->gblist), born, md, nrnb); } wallcycle_sub_stop(wcycle, ewcsNONBONDED); } where(); /* We only do non-bonded calculation with group scheme here, the verlet * calls are done from do_force_cutsVERLET(). */ if (fr->cutoff_scheme == ecutsGROUP && (flags & GMX_FORCE_NONBONDED)) { donb_flags = 0; /* Add short-range interactions */ donb_flags |= GMX_NONBONDED_DO_SR; if (flags & GMX_FORCE_FORCES) { donb_flags |= GMX_NONBONDED_DO_FORCE; } if (flags & GMX_FORCE_ENERGY) { donb_flags |= GMX_NONBONDED_DO_POTENTIAL; } if (flags & GMX_FORCE_DO_LR) { donb_flags |= GMX_NONBONDED_DO_LR; } wallcycle_sub_start(wcycle, ewcsNONBONDED); do_nonbonded(cr, fr, x, f, f_longrange, md, excl, &enerd->grpp, box_size, nrnb, lambda, dvdl_nb, -1, -1, donb_flags); /* If we do foreign lambda and we have soft-core interactions * we have to recalculate the (non-linear) energies contributions. */ if (fepvals->n_lambda > 0 && (flags & GMX_FORCE_DHDL) && fepvals->sc_alpha != 0) { for (i = 0; i < enerd->n_lambda; i++) { for (j = 0; j < efptNR; j++) { lam_i[j] = (i == 0 ? lambda[j] : fepvals->all_lambda[j][i-1]); } reset_foreign_enerdata(enerd); do_nonbonded(cr, fr, x, f, f_longrange, md, excl, &(enerd->foreign_grpp), box_size, nrnb, lam_i, dvdl_dum, -1, -1, (donb_flags & ~GMX_NONBONDED_DO_FORCE) | GMX_NONBONDED_DO_FOREIGNLAMBDA); sum_epot(&ir->opts, &(enerd->foreign_grpp), enerd->foreign_term); enerd->enerpart_lambda[i] += enerd->foreign_term[F_EPOT]; } } wallcycle_sub_stop(wcycle, ewcsNONBONDED); where(); } /* If we are doing GB, calculate bonded forces and apply corrections * to the solvation forces */ /* MRS: Eventually, many need to include free energy contribution here! */ if (ir->implicit_solvent) { wallcycle_sub_start(wcycle, ewcsBONDED); calc_gb_forces(cr, md, born, top, atype, x, f, fr, idef, ir->gb_algorithm, ir->sa_algorithm, nrnb, bBornRadii, &pbc, graph, enerd); wallcycle_sub_stop(wcycle, ewcsBONDED); } #ifdef GMX_MPI if (TAKETIME) { t1 = MPI_Wtime(); fr->t_fnbf += t1-t0; } #endif if (fepvals->sc_alpha != 0) { enerd->dvdl_nonlin[efptVDW] += dvdl_nb[efptVDW]; } else { enerd->dvdl_lin[efptVDW] += dvdl_nb[efptVDW]; } if (fepvals->sc_alpha != 0) /* even though coulomb part is linear, we already added it, beacuse we need to go through the vdw calculation anyway */ { enerd->dvdl_nonlin[efptCOUL] += dvdl_nb[efptCOUL]; } else { enerd->dvdl_lin[efptCOUL] += dvdl_nb[efptCOUL]; } Vsr = 0; if (bSepDVDL) { for (i = 0; i < enerd->grpp.nener; i++) { Vsr += (fr->bBHAM ? enerd->grpp.ener[egBHAMSR][i] : enerd->grpp.ener[egLJSR][i]) + enerd->grpp.ener[egCOULSR][i] + enerd->grpp.ener[egGB][i]; } dvdlsum = dvdl_nb[efptVDW] + dvdl_nb[efptCOUL]; PRINT_SEPDVDL("VdW and Coulomb SR particle-p.", Vsr, dvdlsum); } debug_gmx(); GMX_MPE_LOG(ev_do_fnbf_finish); if (debug) { pr_rvecs(debug, 0, "fshift after SR", fr->fshift, SHIFTS); } /* Shift the coordinates. Must be done before bonded forces and PPPM, * but is also necessary for SHAKE and update, therefore it can NOT * go when no bonded forces have to be evaluated. */ /* Here sometimes we would not need to shift with NBFonly, * but we do so anyhow for consistency of the returned coordinates. */ if (graph) { shift_self(graph, box, x); if (TRICLINIC(box)) { inc_nrnb(nrnb, eNR_SHIFTX, 2*graph->nnodes); } else { inc_nrnb(nrnb, eNR_SHIFTX, graph->nnodes); } } /* Check whether we need to do bondeds or correct for exclusions */ if (fr->bMolPBC && ((flags & GMX_FORCE_BONDED) || EEL_RF(fr->eeltype) || EEL_FULL(fr->eeltype))) { /* Since all atoms are in the rectangular or triclinic unit-cell, * only single box vector shifts (2 in x) are required. */ set_pbc_dd(&pbc, fr->ePBC, cr->dd, TRUE, box); } debug_gmx(); if (flags & GMX_FORCE_BONDED) { GMX_MPE_LOG(ev_calc_bonds_start); wallcycle_sub_start(wcycle, ewcsBONDED); calc_bonds(fplog, cr->ms, idef, x, hist, f, fr, &pbc, graph, enerd, nrnb, lambda, md, fcd, DOMAINDECOMP(cr) ? cr->dd->gatindex : NULL, atype, born, flags, fr->bSepDVDL && do_per_step(step, ir->nstlog), step); /* Check if we have to determine energy differences * at foreign lambda's. */ if (fepvals->n_lambda > 0 && (flags & GMX_FORCE_DHDL) && idef->ilsort != ilsortNO_FE) { if (idef->ilsort != ilsortFE_SORTED) { gmx_incons("The bonded interactions are not sorted for free energy"); } for (i = 0; i < enerd->n_lambda; i++) { reset_foreign_enerdata(enerd); for (j = 0; j < efptNR; j++) { lam_i[j] = (i == 0 ? lambda[j] : fepvals->all_lambda[j][i-1]); } calc_bonds_lambda(fplog, idef, x, fr, &pbc, graph, &(enerd->foreign_grpp), enerd->foreign_term, nrnb, lam_i, md, fcd, DOMAINDECOMP(cr) ? cr->dd->gatindex : NULL); sum_epot(&ir->opts, &(enerd->foreign_grpp), enerd->foreign_term); enerd->enerpart_lambda[i] += enerd->foreign_term[F_EPOT]; } } debug_gmx(); GMX_MPE_LOG(ev_calc_bonds_finish); wallcycle_sub_stop(wcycle, ewcsBONDED); } where(); *cycles_pme = 0; if (EEL_FULL(fr->eeltype)) { bSB = (ir->nwall == 2); if (bSB) { copy_mat(box, boxs); svmul(ir->wall_ewald_zfac, boxs[ZZ], boxs[ZZ]); box_size[ZZ] *= ir->wall_ewald_zfac; } clear_mat(fr->vir_el_recip); if (fr->bEwald) { Vcorr = 0; dvdl = 0; /* With the Verlet scheme exclusion forces are calculated * in the non-bonded kernel. */ /* The TPI molecule does not have exclusions with the rest * of the system and no intra-molecular PME grid contributions * will be calculated in gmx_pme_calc_energy. */ if ((ir->cutoff_scheme == ecutsGROUP && fr->n_tpi == 0) || ir->ewald_geometry != eewg3D || ir->epsilon_surface != 0) { int nthreads, t; wallcycle_sub_start(wcycle, ewcsEWALD_CORRECTION); if (fr->n_tpi > 0) { gmx_fatal(FARGS, "TPI with PME currently only works in a 3D geometry with tin-foil boundary conditions"); } nthreads = gmx_omp_nthreads_get(emntBonded); #pragma omp parallel for num_threads(nthreads) schedule(static) for (t = 0; t < nthreads; t++) { int s, e, i; rvec *fnv; tensor *vir; real *Vcorrt, *dvdlt; if (t == 0) { fnv = fr->f_novirsum; vir = &fr->vir_el_recip; Vcorrt = &Vcorr; dvdlt = &dvdl; } else { fnv = fr->f_t[t].f; vir = &fr->f_t[t].vir; Vcorrt = &fr->f_t[t].Vcorr; dvdlt = &fr->f_t[t].dvdl[efptCOUL]; for (i = 0; i < fr->natoms_force; i++) { clear_rvec(fnv[i]); } clear_mat(*vir); } *dvdlt = 0; *Vcorrt = ewald_LRcorrection(fplog, fr->excl_load[t], fr->excl_load[t+1], cr, t, fr, md->chargeA, md->nChargePerturbed ? md->chargeB : NULL, ir->cutoff_scheme != ecutsVERLET, excl, x, bSB ? boxs : box, mu_tot, ir->ewald_geometry, ir->epsilon_surface, fnv, *vir, lambda[efptCOUL], dvdlt); } if (nthreads > 1) { reduce_thread_forces(fr->natoms_force, fr->f_novirsum, fr->vir_el_recip, &Vcorr, efptCOUL, &dvdl, nthreads, fr->f_t); } wallcycle_sub_stop(wcycle, ewcsEWALD_CORRECTION); } if (fr->n_tpi == 0) { Vcorr += ewald_charge_correction(cr, fr, lambda[efptCOUL], box, &dvdl, fr->vir_el_recip); } PRINT_SEPDVDL("Ewald excl./charge/dip. corr.", Vcorr, dvdl); enerd->dvdl_lin[efptCOUL] += dvdl; } status = 0; Vlr = 0; dvdl = 0; switch (fr->eeltype) { case eelPME: case eelPMESWITCH: case eelPMEUSER: case eelPMEUSERSWITCH: case eelP3M_AD: if (cr->duty & DUTY_PME) { assert(fr->n_tpi >= 0); if (fr->n_tpi == 0 || (flags & GMX_FORCE_STATECHANGED)) { pme_flags = GMX_PME_SPREAD_Q | GMX_PME_SOLVE; if (flags & GMX_FORCE_FORCES) { pme_flags |= GMX_PME_CALC_F; } if (flags & (GMX_FORCE_VIRIAL | GMX_FORCE_ENERGY)) { pme_flags |= GMX_PME_CALC_ENER_VIR; } if (fr->n_tpi > 0) { /* We don't calculate f, but we do want the potential */ pme_flags |= GMX_PME_CALC_POT; } wallcycle_start(wcycle, ewcPMEMESH); status = gmx_pme_do(fr->pmedata, md->start, md->homenr - fr->n_tpi, x, fr->f_novirsum, md->chargeA, md->chargeB, bSB ? boxs : box, cr, DOMAINDECOMP(cr) ? dd_pme_maxshift_x(cr->dd) : 0, DOMAINDECOMP(cr) ? dd_pme_maxshift_y(cr->dd) : 0, nrnb, wcycle, fr->vir_el_recip, fr->ewaldcoeff, &Vlr, lambda[efptCOUL], &dvdl, pme_flags); *cycles_pme = wallcycle_stop(wcycle, ewcPMEMESH); /* We should try to do as little computation after * this as possible, because parallel PME synchronizes * the nodes, so we want all load imbalance of the rest * of the force calculation to be before the PME call. * DD load balancing is done on the whole time of * the force call (without PME). */ } if (fr->n_tpi > 0) { /* Determine the PME grid energy of the test molecule * with the PME grid potential of the other charges. */ gmx_pme_calc_energy(fr->pmedata, fr->n_tpi, x + md->homenr - fr->n_tpi, md->chargeA + md->homenr - fr->n_tpi, &Vlr); } PRINT_SEPDVDL("PME mesh", Vlr, dvdl); } break; case eelEWALD: Vlr = do_ewald(fplog, FALSE, ir, x, fr->f_novirsum, md->chargeA, md->chargeB, box_size, cr, md->homenr, fr->vir_el_recip, fr->ewaldcoeff, lambda[efptCOUL], &dvdl, fr->ewald_table); PRINT_SEPDVDL("Ewald long-range", Vlr, dvdl); break; default: gmx_fatal(FARGS, "No such electrostatics method implemented %s", eel_names[fr->eeltype]); } if (status != 0) { gmx_fatal(FARGS, "Error %d in long range electrostatics routine %s", status, EELTYPE(fr->eeltype)); } /* Note that with separate PME nodes we get the real energies later */ enerd->dvdl_lin[efptCOUL] += dvdl; enerd->term[F_COUL_RECIP] = Vlr + Vcorr; if (debug) { fprintf(debug, "Vlr = %g, Vcorr = %g, Vlr_corr = %g\n", Vlr, Vcorr, enerd->term[F_COUL_RECIP]); pr_rvecs(debug, 0, "vir_el_recip after corr", fr->vir_el_recip, DIM); pr_rvecs(debug, 0, "fshift after LR Corrections", fr->fshift, SHIFTS); } } else { if (EEL_RF(fr->eeltype)) { /* With the Verlet scheme exclusion forces are calculated * in the non-bonded kernel. */ if (ir->cutoff_scheme != ecutsVERLET && fr->eeltype != eelRF_NEC) { dvdl = 0; enerd->term[F_RF_EXCL] = RF_excl_correction(fplog, fr, graph, md, excl, x, f, fr->fshift, &pbc, lambda[efptCOUL], &dvdl); } enerd->dvdl_lin[efptCOUL] += dvdl; PRINT_SEPDVDL("RF exclusion correction", enerd->term[F_RF_EXCL], dvdl); } } where(); debug_gmx(); if (debug) { print_nrnb(debug, nrnb); } debug_gmx(); #ifdef GMX_MPI if (TAKETIME) { t2 = MPI_Wtime(); MPI_Barrier(cr->mpi_comm_mygroup); t3 = MPI_Wtime(); fr->t_wait += t3-t2; if (fr->timesteps == 11) { fprintf(stderr, "* PP load balancing info: node %d, step %s, rel wait time=%3.0f%% , load string value: %7.2f\n", cr->nodeid, gmx_step_str(fr->timesteps, buf), 100*fr->t_wait/(fr->t_wait+fr->t_fnbf), (fr->t_fnbf+fr->t_wait)/fr->t_fnbf); } fr->timesteps++; } #endif if (debug) { pr_rvecs(debug, 0, "fshift after bondeds", fr->fshift, SHIFTS); } GMX_MPE_LOG(ev_force_finish); }
static bool constrain_lincs(FILE *log,t_topology *top,t_inputrec *ir, int step,t_mdatoms *md,int start,int homenr, int *nbl,int **sbl, rvec *x,rvec *xprime,rvec *min_proj,matrix box, real lambda,real *dvdlambda,bool bCoordinates, bool bInit,t_nrnb *nrnb,bool bDumpOnError) { static int *bla1,*bla2,*blnr,*blbnb,nrtot=0; static rvec *r; static real *bllen,*blc,*blcc,*blm,*tmp1,*tmp2,*tmp3,*lincslam, *bllen0,*ddist; static int nc; static bool bItEqOrder; char buf[STRLEN]; int b,i,j,nit,warn,p_imax,error; real wang,p_max,p_rms; real dt,dt_2; bool bOK; bOK = TRUE; if (bInit) { nc = top->idef.il[F_SHAKE].nr/3; init_lincs(stdlog,top,ir,md,start,homenr, &nrtot, &r,&bla1,&bla2,&blnr,&blbnb, &bllen,&blc,&blcc,&blm,&tmp1,&tmp2,&tmp3,&lincslam, &bllen0,&ddist); #ifdef SPEC_CPU bItEqOrder = FALSE; #else bItEqOrder = (getenv("GMX_ACCURATE_LINCS") != NULL); #endif } else if (nc != 0) { /* If there are any constraints */ if (bCoordinates) { dt = ir->delta_t; dt_2 = 1.0/(dt*dt); if (ir->efep != efepNO) for(i=0;i<nc;i++) bllen[i]=bllen0[i]+lambda*ddist[i]; /* Set the zero lengths to the old lengths */ for(b=0; b<nc; b++) if (bllen0[b]<GMX_REAL_MIN) { i = bla1[b]; j = bla2[b]; bllen[b] = sqrt(sqr(x[i][XX]-x[j][XX])+ sqr(x[i][YY]-x[j][YY])+ sqr(x[i][ZZ]-x[j][ZZ])); } wang=ir->LincsWarnAngle; if (do_per_step(step,ir->nstlog) || step<0) cconerr(&p_max,&p_rms,&p_imax,xprime,nc,bla1,bla2,bllen); if ((ir->eI == eiSteep) || (ir->eI == eiCG) || bItEqOrder) /* Use more iterations when doing energy minimization, * * because we need very accurate positions and forces. */ nit = ir->nProjOrder; else nit = 1; #ifdef USE_FORTRAN #ifdef DOUBLE F77_FUNC(flincsd,FLINCSD)(x[0],xprime[0],&nc,bla1,bla2,blnr,blbnb, bllen,blc,blcc,blm,&nit,&ir->nProjOrder, md->invmass,r[0],tmp1,tmp2,tmp3,&wang,&warn, lincslam); #else F77_FUNC(flincs,FLINCS)(x[0],xprime[0],&nc,bla1,bla2,blnr,blbnb, bllen,blc,blcc,blm,&nit,&ir->nProjOrder, md->invmass,r[0],tmp1,tmp2,tmp3,&wang,&warn, lincslam); #endif #else clincs(x,xprime,nc,bla1,bla2,blnr,blbnb, bllen,blc,blcc,blm,nit,ir->nProjOrder, md->invmass,r,tmp1,tmp2,tmp3,wang,&warn,lincslam); #endif if (ir->efep != efepNO) { real dvdl=0; for(i=0; (i<nc); i++) dvdl+=lincslam[i]*dt_2*ddist[i]; *dvdlambda+=dvdl; } if(stdlog) { if (do_per_step(step,ir->nstlog) || (step<0)) { fprintf(stdlog," Rel. Constraint Deviation: Max between atoms RMS\n"); fprintf(stdlog," Before LINCS %.6f %6d %6d %.6f\n", p_max,bla1[p_imax]+1,bla2[p_imax]+1,p_rms); cconerr(&p_max,&p_rms,&p_imax,xprime,nc,bla1,bla2,bllen); fprintf(stdlog," After LINCS %.6f %6d %6d %.6f\n\n", p_max,bla1[p_imax]+1,bla2[p_imax]+1,p_rms); } } if (warn > 0) { if (bDumpOnError && stdlog) { cconerr(&p_max,&p_rms,&p_imax,xprime,nc,bla1,bla2,bllen); sprintf(buf,"\nStep %d, time %g (ps) LINCS WARNING\n" "relative constraint deviation after LINCS:\n" "max %.6f (between atoms %d and %d) rms %.6f\n", step,ir->init_t+step*ir->delta_t, p_max,bla1[p_imax]+1,bla2[p_imax]+1,p_rms); fprintf(stdlog,"%s",buf); fprintf(stderr,"%s",buf); lincs_warning(x,xprime,nc,bla1,bla2,bllen,wang); } bOK = (p_max < 0.5); } for(b=0; (b<nc); b++) if (bllen0[b] < GMX_REAL_MIN) bllen[b] = 0; } else { #ifdef USE_FORTRAN #ifdef DOUBLE F77_FUNC(flincspd,FLINCSPD)(x[0],xprime[0],min_proj[0],&nc,bla1,bla2,blnr,blbnb, blc,blcc,blm,&ir->nProjOrder, md->invmass,r[0],tmp1,tmp2,tmp3); #else F77_FUNC(flincsp,FLINCSP)(x[0],xprime[0],min_proj[0],&nc,bla1,bla2,blnr,blbnb, blc,blcc,blm,&ir->nProjOrder, md->invmass,r[0],tmp1,tmp2,tmp3); #endif #else clincsp(x,xprime,min_proj,nc,bla1,bla2,blnr,blbnb, blc,blcc,blm,ir->nProjOrder, md->invmass,r,tmp1,tmp2,tmp3); #endif } /* count assuming nit=1 */ inc_nrnb(nrnb,eNR_LINCS,nc); inc_nrnb(nrnb,eNR_LINCSMAT,(2+ir->nProjOrder)*nrtot); } return bOK; }
gmx_bool constrain(FILE *fplog, gmx_bool bLog, gmx_bool bEner, struct gmx_constr *constr, t_idef *idef, t_inputrec *ir, gmx_ekindata_t *ekind, t_commrec *cr, gmx_int64_t step, int delta_step, t_mdatoms *md, rvec *x, rvec *xprime, rvec *min_proj, gmx_bool bMolPBC, matrix box, real lambda, real *dvdlambda, rvec *v, tensor *vir, t_nrnb *nrnb, int econq, gmx_bool bPscal, real veta, real vetanew) { gmx_bool bOK, bDump; int start, homenr, nrend; int i, j, d; int ncons, settle_error; tensor vir_r_m_dr; rvec *vstor; real invdt, vir_fac, t; t_ilist *settle; int nsettle; t_pbc pbc, *pbc_null; char buf[22]; t_vetavars vetavar; int nth, th; if (econq == econqForceDispl && !EI_ENERGY_MINIMIZATION(ir->eI)) { gmx_incons("constrain called for forces displacements while not doing energy minimization, can not do this while the LINCS and SETTLE constraint connection matrices are mass weighted"); } bOK = TRUE; bDump = FALSE; start = 0; homenr = md->homenr; nrend = start+homenr; /* set constants for pressure control integration */ init_vetavars(&vetavar, econq != econqCoord, veta, vetanew, ir, ekind, bPscal); if (ir->delta_t == 0) { invdt = 0; } else { invdt = 1/ir->delta_t; } if (ir->efep != efepNO && EI_DYNAMICS(ir->eI)) { /* Set the constraint lengths for the step at which this configuration * is meant to be. The invmasses should not be changed. */ lambda += delta_step*ir->fepvals->delta_lambda; } if (vir != NULL) { clear_mat(vir_r_m_dr); } where(); settle = &idef->il[F_SETTLE]; nsettle = settle->nr/(1+NRAL(F_SETTLE)); if (nsettle > 0) { nth = gmx_omp_nthreads_get(emntSETTLE); } else { nth = 1; } if (nth > 1 && constr->vir_r_m_dr_th == NULL) { snew(constr->vir_r_m_dr_th, nth); snew(constr->settle_error, nth); } settle_error = -1; /* We do not need full pbc when constraints do not cross charge groups, * i.e. when dd->constraint_comm==NULL. * Note that PBC for constraints is different from PBC for bondeds. * For constraints there is both forward and backward communication. */ if (ir->ePBC != epbcNONE && (cr->dd || bMolPBC) && !(cr->dd && cr->dd->constraint_comm == NULL)) { /* With pbc=screw the screw has been changed to a shift * by the constraint coordinate communication routine, * so that here we can use normal pbc. */ pbc_null = set_pbc_dd(&pbc, ir->ePBC, cr->dd, FALSE, box); } else { pbc_null = NULL; } /* Communicate the coordinates required for the non-local constraints * for LINCS and/or SETTLE. */ if (cr->dd) { dd_move_x_constraints(cr->dd, box, x, xprime, econq == econqCoord); } if (constr->lincsd != NULL) { bOK = constrain_lincs(fplog, bLog, bEner, ir, step, constr->lincsd, md, cr, x, xprime, min_proj, box, pbc_null, lambda, dvdlambda, invdt, v, vir != NULL, vir_r_m_dr, econq, nrnb, constr->maxwarn, &constr->warncount_lincs); if (!bOK && constr->maxwarn >= 0) { if (fplog != NULL) { fprintf(fplog, "Constraint error in algorithm %s at step %s\n", econstr_names[econtLINCS], gmx_step_str(step, buf)); } bDump = TRUE; } } if (constr->nblocks > 0) { switch (econq) { case (econqCoord): bOK = bshakef(fplog, constr->shaked, md->invmass, constr->nblocks, constr->sblock, idef, ir, x, xprime, nrnb, constr->lagr, lambda, dvdlambda, invdt, v, vir != NULL, vir_r_m_dr, constr->maxwarn >= 0, econq, &vetavar); break; case (econqVeloc): bOK = bshakef(fplog, constr->shaked, md->invmass, constr->nblocks, constr->sblock, idef, ir, x, min_proj, nrnb, constr->lagr, lambda, dvdlambda, invdt, NULL, vir != NULL, vir_r_m_dr, constr->maxwarn >= 0, econq, &vetavar); break; default: gmx_fatal(FARGS, "Internal error, SHAKE called for constraining something else than coordinates"); break; } if (!bOK && constr->maxwarn >= 0) { if (fplog != NULL) { fprintf(fplog, "Constraint error in algorithm %s at step %s\n", econstr_names[econtSHAKE], gmx_step_str(step, buf)); } bDump = TRUE; } } if (nsettle > 0) { int calcvir_atom_end; if (vir == NULL) { calcvir_atom_end = 0; } else { calcvir_atom_end = md->homenr; } switch (econq) { case econqCoord: #pragma omp parallel for num_threads(nth) schedule(static) for (th = 0; th < nth; th++) { int start_th, end_th; if (th > 0) { clear_mat(constr->vir_r_m_dr_th[th]); } start_th = (nsettle* th )/nth; end_th = (nsettle*(th+1))/nth; if (start_th >= 0 && end_th - start_th > 0) { csettle(constr->settled, end_th-start_th, settle->iatoms+start_th*(1+NRAL(F_SETTLE)), pbc_null, x[0], xprime[0], invdt, v ? v[0] : NULL, calcvir_atom_end, th == 0 ? vir_r_m_dr : constr->vir_r_m_dr_th[th], th == 0 ? &settle_error : &constr->settle_error[th], &vetavar); } } inc_nrnb(nrnb, eNR_SETTLE, nsettle); if (v != NULL) { inc_nrnb(nrnb, eNR_CONSTR_V, nsettle*3); } if (vir != NULL) { inc_nrnb(nrnb, eNR_CONSTR_VIR, nsettle*3); } break; case econqVeloc: case econqDeriv: case econqForce: case econqForceDispl: #pragma omp parallel for num_threads(nth) schedule(static) for (th = 0; th < nth; th++) { int start_th, end_th; if (th > 0) { clear_mat(constr->vir_r_m_dr_th[th]); } start_th = (nsettle* th )/nth; end_th = (nsettle*(th+1))/nth; if (start_th >= 0 && end_th - start_th > 0) { settle_proj(constr->settled, econq, end_th-start_th, settle->iatoms+start_th*(1+NRAL(F_SETTLE)), pbc_null, x, xprime, min_proj, calcvir_atom_end, th == 0 ? vir_r_m_dr : constr->vir_r_m_dr_th[th], &vetavar); } } /* This is an overestimate */ inc_nrnb(nrnb, eNR_SETTLE, nsettle); break; case econqDeriv_FlexCon: /* Nothing to do, since the are no flexible constraints in settles */ break; default: gmx_incons("Unknown constraint quantity for settle"); } } if (settle->nr > 0) { /* Combine virial and error info of the other threads */ for (i = 1; i < nth; i++) { m_add(vir_r_m_dr, constr->vir_r_m_dr_th[i], vir_r_m_dr); settle_error = constr->settle_error[i]; } if (econq == econqCoord && settle_error >= 0) { bOK = FALSE; if (constr->maxwarn >= 0) { char buf[256]; sprintf(buf, "\nstep " "%"GMX_PRId64 ": Water molecule starting at atom %d can not be " "settled.\nCheck for bad contacts and/or reduce the timestep if appropriate.\n", step, ddglatnr(cr->dd, settle->iatoms[settle_error*(1+NRAL(F_SETTLE))+1])); if (fplog) { fprintf(fplog, "%s", buf); } fprintf(stderr, "%s", buf); constr->warncount_settle++; if (constr->warncount_settle > constr->maxwarn) { too_many_constraint_warnings(-1, constr->warncount_settle); } bDump = TRUE; } } } free_vetavars(&vetavar); if (vir != NULL) { switch (econq) { case econqCoord: vir_fac = 0.5/(ir->delta_t*ir->delta_t); break; case econqVeloc: vir_fac = 0.5/ir->delta_t; break; case econqForce: case econqForceDispl: vir_fac = 0.5; break; default: vir_fac = 0; gmx_incons("Unsupported constraint quantity for virial"); } if (EI_VV(ir->eI)) { vir_fac *= 2; /* only constraining over half the distance here */ } for (i = 0; i < DIM; i++) { for (j = 0; j < DIM; j++) { (*vir)[i][j] = vir_fac*vir_r_m_dr[i][j]; } } } if (bDump) { dump_confs(fplog, step, constr->warn_mtop, start, homenr, cr, x, xprime, box); } if (econq == econqCoord) { if (ir->ePull == epullCONSTRAINT) { if (EI_DYNAMICS(ir->eI)) { t = ir->init_t + (step + delta_step)*ir->delta_t; } else { t = ir->init_t; } set_pbc(&pbc, ir->ePBC, box); pull_constraint(ir->pull, md, &pbc, cr, ir->delta_t, t, x, xprime, v, *vir); } if (constr->ed && delta_step > 0) { /* apply the essential dynamcs constraints here */ do_edsam(ir, step, cr, xprime, v, box, constr->ed); } } return bOK; }
static bool low_constrain(FILE *log,t_topology *top,t_inputrec *ir, int step,t_mdatoms *md,int start,int homenr, rvec *x,rvec *xprime,rvec *min_proj,matrix box, real lambda,real *dvdlambda,t_nrnb *nrnb, bool bCoordinates,bool bInit) { static int nblocks=0; static int *sblock=NULL; static int nsettle,settle_type; static int *owptr; static bool bDumpOnError = TRUE; char buf[STRLEN]; bool bOK; t_sortblock *sb; t_block *blocks=&(top->blocks[ebSBLOCKS]); t_idef *idef=&(top->idef); t_iatom *iatom; atom_id *inv_sblock; int i,j,m,bnr; int ncons,bstart,error; bOK = TRUE; if (bInit) { /* Output variables, initiate them right away */ if ((ir->etc==etcBERENDSEN) || (ir->epc==epcBERENDSEN)) please_cite(log,"Berendsen84a"); #ifdef SPEC_CPU bDumpOnError = TRUE; #else bDumpOnError = (getenv("NO_SHAKE_ERROR") == NULL); #endif /* Put the oxygen atoms in the owptr array */ nsettle=idef->il[F_SETTLE].nr/2; if (nsettle > 0) { snew(owptr,nsettle); settle_type=idef->il[F_SETTLE].iatoms[0]; for (j=0; (j<idef->il[F_SETTLE].nr); j+=2) { if (idef->il[F_SETTLE].iatoms[j] != settle_type) fatal_error(0,"More than one settle type (%d and %d)", settle_type,idef->il[F_SETTLE].iatoms[j]); owptr[j/2]=idef->il[F_SETTLE].iatoms[j+1]; #ifdef DEBUG fprintf(log,"owptr[%d]=%d\n",j/2,owptr[j/2]); #endif } /* We used to free this memory, but ED sampling needs it later on * sfree(idef->il[F_SETTLE].iatoms); */ please_cite(log,"Miyamoto92a"); } ncons=idef->il[F_SHAKE].nr/3; if (ncons > 0) { bstart=(idef->nodeid > 0) ? blocks->multinr[idef->nodeid-1] : 0; nblocks=blocks->multinr[idef->nodeid] - bstart; if (debug) fprintf(debug,"ncons: %d, bstart: %d, nblocks: %d\n", ncons,bstart,nblocks); /* Calculate block number for each atom */ inv_sblock=make_invblock(blocks,md->nr); /* Store the block number in temp array and * sort the constraints in order of the sblock number * and the atom numbers, really sorting a segment of the array! */ #ifdef DEBUGIDEF pr_idef(stdlog,0,"Before Sort",idef); #endif iatom=idef->il[F_SHAKE].iatoms; snew(sb,ncons); for(i=0; (i<ncons); i++,iatom+=3) { for(m=0; (m<3); m++) sb[i].iatom[m]=iatom[m]; sb[i].blocknr=inv_sblock[iatom[1]]; } /* Now sort the blocks */ if (debug) { pr_sortblock(debug,"Before sorting",ncons,sb); fprintf(debug,"Going to sort constraints\n"); } qsort(sb,ncons,(size_t)sizeof(*sb),pcomp); if (debug) { fprintf(debug,"I used %d calls to pcomp\n",pcount); pr_sortblock(debug,"After sorting",ncons,sb); } iatom=idef->il[F_SHAKE].iatoms; for(i=0; (i<ncons); i++,iatom+=3) for(m=0; (m<DIM); m++) iatom[m]=sb[i].iatom[m]; #ifdef DEBUGIDEF pr_idef(stdlog,0,"After Sort",idef); #endif j=0; snew(sblock,nblocks+1); bnr=-2; for(i=0; (i<ncons); i++) { if (sb[i].blocknr != bnr) { bnr=sb[i].blocknr; sblock[j++]=3*i; } } /* Last block... */ sblock[j++]=3*ncons; if (j != (nblocks+1) && log) { fprintf(log,"bstart: %d\n",bstart); fprintf(log,"j: %d, nblocks: %d, ncons: %d\n", j,nblocks,ncons); for(i=0; (i<ncons); i++) fprintf(log,"i: %5d sb[i].blocknr: %5u\n",i,sb[i].blocknr); for(j=0; (j<=nblocks); j++) fprintf(log,"sblock[%3d]=%5d\n",j,(int) sblock[j]); fatal_error(0,"DEATH HORROR: " "top->blocks[ebSBLOCKS] does not match idef->il[F_SHAKE]"); } sfree(sb); sfree(inv_sblock); } if (idef->il[F_SHAKE].nr) { if (ir->eConstrAlg == estLINCS || !bCoordinates) { please_cite(stdlog,"Hess97a"); bOK = constrain_lincs(stdlog,top,ir,0,md,start,homenr,&nblocks,&sblock, NULL,NULL,NULL,NULL,0,NULL,bCoordinates,TRUE,nrnb, bDumpOnError); } else please_cite(stdlog,"Ryckaert77a"); } } else { /* !bInit */ if (nblocks > 0) { where(); if (ir->eConstrAlg == estSHAKE) bOK = bshakef(stdlog,homenr,md->invmass,nblocks,sblock,idef, ir,box,x,xprime,nrnb,lambda,dvdlambda,bDumpOnError); else if (ir->eConstrAlg == estLINCS) bOK = constrain_lincs(stdlog,top,ir,step,md, start,homenr,&nblocks,&sblock, x,xprime,min_proj,box,lambda,dvdlambda, bCoordinates,FALSE,nrnb,bDumpOnError); if (!bOK && bDumpOnError && stdlog) fprintf(stdlog,"Constraint error in algorithm %s at step %d\n", eshake_names[ir->eConstrAlg],step); } if (nsettle > 0) { int ow1; real mO,mH,dOH,dHH; ow1 = owptr[0]; mO = md->massA[ow1]; mH = md->massA[ow1+1]; dOH = top->idef.iparams[settle_type].settle.doh; dHH = top->idef.iparams[settle_type].settle.dhh; #ifdef USE_FORTRAN #ifdef DOUBLE F77_FUNC(fsettled,FSETTLED)(&nsettle,owptr,x[0],xprime[0], &dOH,&dHH,&mO,&mH,&error); #else F77_FUNC(fsettle,FSETTLE)(&nsettle,owptr,x[0],xprime[0], &dOH,&dHH,&mO,&mH,&error); #endif #else csettle(stdlog,nsettle,owptr,x[0],xprime[0],dOH,dHH,mO,mH,&error); #endif inc_nrnb(nrnb,eNR_SETTLE,nsettle); bOK = (error < 0); if (!bOK && bDumpOnError && stdlog) fprintf(stdlog,"\nt = %.3f ps: Water molecule starting at atom %d can not be " "settled.\nCheck for bad contacts and/or reduce the timestep.", ir->init_t+step*ir->delta_t,owptr[error]+1); } if (!bOK && bDumpOnError) dump_confs(step,&(top->atoms),x,xprime,box); } return bOK; }
void gmx_nb_generic_adress_kernel(t_nblist * nlist, rvec * xx, rvec * ff, t_forcerec * fr, t_mdatoms * mdatoms, nb_kernel_data_t * kernel_data, t_nrnb * nrnb) { int nri, ntype, table_nelements, ielec, ivdw; real facel, gbtabscale; int n, ii, is3, ii3, k, nj0, nj1, jnr, j3, ggid, nnn, n0; real shX, shY, shZ; real fscal, felec, fvdw, velec, vvdw, tx, ty, tz; real rinvsq; real iq; real qq, vctot; int nti, nvdwparam; int tj; real rt, r, eps, eps2, Y, F, Geps, Heps2, VV, FF, Fp, fijD, fijR; real rinvsix; real vvdwtot; real vvdw_rep, vvdw_disp; real ix, iy, iz, fix, fiy, fiz; real jx, jy, jz; real dx, dy, dz, rsq, rinv; real c6, c12, cexp1, cexp2, br; real * charge; real * shiftvec; real * vdwparam; int * shift; int * type; real * fshift; real * velecgrp; real * vvdwgrp; real tabscale; real * VFtab; real * x; real * f; int ewitab; real ewtabscale, eweps, sh_ewald, ewrt, ewtabhalfspace; real * ewtab; real rcoulomb2, rvdw, rvdw2, sh_dispersion, sh_repulsion; real rcutoff, rcutoff2; real rswitch_elec, rswitch_vdw, d, d2, sw, dsw, rinvcorr; real elec_swV3, elec_swV4, elec_swV5, elec_swF2, elec_swF3, elec_swF4; real vdw_swV3, vdw_swV4, vdw_swV5, vdw_swF2, vdw_swF3, vdw_swF4; gmx_bool bExactElecCutoff, bExactVdwCutoff, bExactCutoff; real * wf; real weight_cg1; real weight_cg2; real weight_product; real hybscal; /* the multiplicator to the force for hybrid interactions*/ real force_cap; gmx_bool bCG; int egp_nr; wf = mdatoms->wf; force_cap = fr->adress_ex_forcecap; x = xx[0]; f = ff[0]; ielec = nlist->ielec; ivdw = nlist->ivdw; fshift = fr->fshift[0]; velecgrp = kernel_data->energygrp_elec; vvdwgrp = kernel_data->energygrp_vdw; tabscale = kernel_data->table_elec_vdw->scale; VFtab = kernel_data->table_elec_vdw->data; sh_ewald = fr->ic->sh_ewald; ewtab = fr->ic->tabq_coul_FDV0; ewtabscale = fr->ic->tabq_scale; ewtabhalfspace = 0.5/ewtabscale; rcoulomb2 = fr->rcoulomb*fr->rcoulomb; rvdw = fr->rvdw; rvdw2 = rvdw*rvdw; sh_dispersion = fr->ic->dispersion_shift.cpot; sh_repulsion = fr->ic->repulsion_shift.cpot; if (fr->coulomb_modifier == eintmodPOTSWITCH) { d = fr->rcoulomb-fr->rcoulomb_switch; elec_swV3 = -10.0/(d*d*d); elec_swV4 = 15.0/(d*d*d*d); elec_swV5 = -6.0/(d*d*d*d*d); elec_swF2 = -30.0/(d*d*d); elec_swF3 = 60.0/(d*d*d*d); elec_swF4 = -30.0/(d*d*d*d*d); } else { /* Avoid warnings from stupid compilers (looking at you, Clang!) */ elec_swV3 = elec_swV4 = elec_swV5 = elec_swF2 = elec_swF3 = elec_swF4 = 0.0; } if (fr->vdw_modifier == eintmodPOTSWITCH) { d = fr->rvdw-fr->rvdw_switch; vdw_swV3 = -10.0/(d*d*d); vdw_swV4 = 15.0/(d*d*d*d); vdw_swV5 = -6.0/(d*d*d*d*d); vdw_swF2 = -30.0/(d*d*d); vdw_swF3 = 60.0/(d*d*d*d); vdw_swF4 = -30.0/(d*d*d*d*d); } else { /* Avoid warnings from stupid compilers (looking at you, Clang!) */ vdw_swV3 = vdw_swV4 = vdw_swV5 = vdw_swF2 = vdw_swF3 = vdw_swF4 = 0.0; } bExactElecCutoff = (fr->coulomb_modifier != eintmodNONE) || fr->eeltype == eelRF_ZERO; bExactVdwCutoff = (fr->vdw_modifier != eintmodNONE); bExactCutoff = bExactElecCutoff || bExactVdwCutoff; if (bExactCutoff) { rcutoff = ( fr->rcoulomb > fr->rvdw ) ? fr->rcoulomb : fr->rvdw; rcutoff2 = rcutoff*rcutoff; } else { /* Fix warnings for stupid compilers */ rcutoff = rcutoff2 = 1e30; } /* avoid compiler warnings for cases that cannot happen */ nnn = 0; eps = 0.0; eps2 = 0.0; /* 3 VdW parameters for buckingham, otherwise 2 */ nvdwparam = (ivdw == GMX_NBKERNEL_VDW_BUCKINGHAM) ? 3 : 2; table_nelements = 12; charge = mdatoms->chargeA; type = mdatoms->typeA; facel = fr->epsfac; shiftvec = fr->shift_vec[0]; vdwparam = fr->nbfp; ntype = fr->ntype; for (n = 0; (n < nlist->nri); n++) { is3 = 3*nlist->shift[n]; shX = shiftvec[is3]; shY = shiftvec[is3+1]; shZ = shiftvec[is3+2]; nj0 = nlist->jindex[n]; nj1 = nlist->jindex[n+1]; ii = nlist->iinr[n]; ii3 = 3*ii; ix = shX + x[ii3+0]; iy = shY + x[ii3+1]; iz = shZ + x[ii3+2]; iq = facel*charge[ii]; nti = nvdwparam*ntype*type[ii]; vctot = 0; vvdwtot = 0; fix = 0; fiy = 0; fiz = 0; /* We need to find out if this i atom is part of an all-atom or CG energy group */ egp_nr = mdatoms->cENER[ii]; bCG = !fr->adress_group_explicit[egp_nr]; weight_cg1 = wf[ii]; if ((!bCG) && weight_cg1 < ALMOST_ZERO) { continue; } for (k = nj0; (k < nj1); k++) { jnr = nlist->jjnr[k]; weight_cg2 = wf[jnr]; weight_product = weight_cg1*weight_cg2; if (weight_product < ALMOST_ZERO) { /* if it's a explicit loop, skip this atom */ if (!bCG) { continue; } else /* if it's a coarse grained loop, include this atom */ { hybscal = 1.0; } } else if (weight_product >= ALMOST_ONE) { /* if it's a explicit loop, include this atom */ if (!bCG) { hybscal = 1.0; } else /* if it's a coarse grained loop, skip this atom */ { continue; } } /* both have double identity, get hybrid scaling factor */ else { hybscal = weight_product; if (bCG) { hybscal = 1.0 - hybscal; } } j3 = 3*jnr; jx = x[j3+0]; jy = x[j3+1]; jz = x[j3+2]; dx = ix - jx; dy = iy - jy; dz = iz - jz; rsq = dx*dx+dy*dy+dz*dz; rinv = gmx_invsqrt(rsq); rinvsq = rinv*rinv; felec = 0; fvdw = 0; velec = 0; vvdw = 0; if (bExactCutoff && rsq > rcutoff2) { continue; } if (ielec == GMX_NBKERNEL_ELEC_CUBICSPLINETABLE || ivdw == GMX_NBKERNEL_VDW_CUBICSPLINETABLE) { r = rsq*rinv; rt = r*tabscale; n0 = rt; eps = rt-n0; eps2 = eps*eps; nnn = table_nelements*n0; } /* Coulomb interaction. ielec==0 means no interaction */ if (ielec != GMX_NBKERNEL_ELEC_NONE) { qq = iq*charge[jnr]; switch (ielec) { case GMX_NBKERNEL_ELEC_NONE: break; case GMX_NBKERNEL_ELEC_COULOMB: /* Vanilla cutoff coulomb */ velec = qq*rinv; felec = velec*rinvsq; break; case GMX_NBKERNEL_ELEC_REACTIONFIELD: /* Reaction-field */ velec = qq*(rinv+fr->k_rf*rsq-fr->c_rf); felec = qq*(rinv*rinvsq-2.0*fr->k_rf); break; case GMX_NBKERNEL_ELEC_CUBICSPLINETABLE: /* Tabulated coulomb */ Y = VFtab[nnn]; F = VFtab[nnn+1]; Geps = eps*VFtab[nnn+2]; Heps2 = eps2*VFtab[nnn+3]; Fp = F+Geps+Heps2; VV = Y+eps*Fp; FF = Fp+Geps+2.0*Heps2; velec = qq*VV; felec = -qq*FF*tabscale*rinv; break; case GMX_NBKERNEL_ELEC_GENERALIZEDBORN: /* GB */ gmx_fatal(FARGS, "Death & horror! GB generic interaction not implemented.\n"); break; case GMX_NBKERNEL_ELEC_EWALD: ewrt = rsq*rinv*ewtabscale; ewitab = ewrt; eweps = ewrt-ewitab; ewitab = 4*ewitab; felec = ewtab[ewitab]+eweps*ewtab[ewitab+1]; rinvcorr = (fr->coulomb_modifier == eintmodPOTSHIFT) ? rinv-fr->ic->sh_ewald : rinv; velec = qq*(rinvcorr-(ewtab[ewitab+2]-ewtabhalfspace*eweps*(ewtab[ewitab]+felec))); felec = qq*rinv*(rinvsq-felec); break; default: gmx_fatal(FARGS, "Death & horror! No generic coulomb interaction for ielec=%d.\n", ielec); break; } if (fr->coulomb_modifier == eintmodPOTSWITCH) { d = rsq*rinv-fr->rcoulomb_switch; d = (d > 0.0) ? d : 0.0; d2 = d*d; sw = 1.0+d2*d*(elec_swV3+d*(elec_swV4+d*elec_swV5)); dsw = d2*(elec_swF2+d*(elec_swF3+d*elec_swF4)); /* Apply switch function. Note that felec=f/r since it will be multiplied * by the i-j displacement vector. This means felec'=f'/r=-(v*sw)'/r= * -(v'*sw+v*dsw)/r=-v'*sw/r-v*dsw/r=felec*sw-v*dsw/r */ felec = felec*sw - rinv*velec*dsw; /* Once we have used velec to update felec we can modify velec too */ velec *= sw; } if (bExactElecCutoff) { felec = (rsq <= rcoulomb2) ? felec : 0.0; velec = (rsq <= rcoulomb2) ? velec : 0.0; } vctot += velec; } /* End of coulomb interactions */ /* VdW interaction. ivdw==0 means no interaction */ if (ivdw != GMX_NBKERNEL_VDW_NONE) { tj = nti+nvdwparam*type[jnr]; switch (ivdw) { case GMX_NBKERNEL_VDW_NONE: break; case GMX_NBKERNEL_VDW_LENNARDJONES: /* Vanilla Lennard-Jones cutoff */ c6 = vdwparam[tj]; c12 = vdwparam[tj+1]; rinvsix = rinvsq*rinvsq*rinvsq; vvdw_disp = c6*rinvsix; vvdw_rep = c12*rinvsix*rinvsix; fvdw = (vvdw_rep-vvdw_disp)*rinvsq; if (fr->vdw_modifier == eintmodPOTSHIFT) { vvdw = (vvdw_rep + c12*sh_repulsion)/12.0 - (vvdw_disp + c6*sh_dispersion)/6.0; } else { vvdw = vvdw_rep/12.0-vvdw_disp/6.0; } break; case GMX_NBKERNEL_VDW_BUCKINGHAM: /* Buckingham */ c6 = vdwparam[tj]; cexp1 = vdwparam[tj+1]; cexp2 = vdwparam[tj+2]; rinvsix = rinvsq*rinvsq*rinvsq; vvdw_disp = c6*rinvsix; br = cexp2*rsq*rinv; vvdw_rep = cexp1*exp(-br); fvdw = (br*vvdw_rep-vvdw_disp)*rinvsq; if (fr->vdw_modifier == eintmodPOTSHIFT) { vvdw = (vvdw_rep-cexp1*exp(-cexp2*rvdw)) - (vvdw_disp + c6*sh_dispersion)/6.0; } else { vvdw = vvdw_rep-vvdw_disp/6.0; } break; case GMX_NBKERNEL_VDW_CUBICSPLINETABLE: /* Tabulated VdW */ c6 = vdwparam[tj]; c12 = vdwparam[tj+1]; Y = VFtab[nnn+4]; F = VFtab[nnn+5]; Geps = eps*VFtab[nnn+6]; Heps2 = eps2*VFtab[nnn+7]; Fp = F+Geps+Heps2; VV = Y+eps*Fp; FF = Fp+Geps+2.0*Heps2; vvdw_disp = c6*VV; fijD = c6*FF; Y = VFtab[nnn+8]; F = VFtab[nnn+9]; Geps = eps*VFtab[nnn+10]; Heps2 = eps2*VFtab[nnn+11]; Fp = F+Geps+Heps2; VV = Y+eps*Fp; FF = Fp+Geps+2.0*Heps2; vvdw_rep = c12*VV; fijR = c12*FF; fvdw = -(fijD+fijR)*tabscale*rinv; vvdw = vvdw_disp + vvdw_rep; break; default: gmx_fatal(FARGS, "Death & horror! No generic VdW interaction for ivdw=%d.\n", ivdw); break; } if (fr->vdw_modifier == eintmodPOTSWITCH) { d = rsq*rinv-fr->rvdw_switch; d = (d > 0.0) ? d : 0.0; d2 = d*d; sw = 1.0+d2*d*(vdw_swV3+d*(vdw_swV4+d*vdw_swV5)); dsw = d2*(vdw_swF2+d*(vdw_swF3+d*vdw_swF4)); /* See coulomb interaction for the force-switch formula */ fvdw = fvdw*sw - rinv*vvdw*dsw; vvdw *= sw; } if (bExactVdwCutoff) { fvdw = (rsq <= rvdw2) ? fvdw : 0.0; vvdw = (rsq <= rvdw2) ? vvdw : 0.0; } vvdwtot += vvdw; } /* end VdW interactions */ fscal = felec+fvdw; if (!bCG && force_cap > 0 && (fabs(fscal) > force_cap)) { fscal = force_cap*fscal/fabs(fscal); } fscal *= hybscal; tx = fscal*dx; ty = fscal*dy; tz = fscal*dz; fix = fix + tx; fiy = fiy + ty; fiz = fiz + tz; f[j3+0] = f[j3+0] - tx; f[j3+1] = f[j3+1] - ty; f[j3+2] = f[j3+2] - tz; } f[ii3+0] = f[ii3+0] + fix; f[ii3+1] = f[ii3+1] + fiy; f[ii3+2] = f[ii3+2] + fiz; fshift[is3] = fshift[is3]+fix; fshift[is3+1] = fshift[is3+1]+fiy; fshift[is3+2] = fshift[is3+2]+fiz; ggid = nlist->gid[n]; velecgrp[ggid] += vctot; vvdwgrp[ggid] += vvdwtot; } /* Estimate flops, average for generic adress kernel: * 14 flops per outer iteration * 54 flops per inner iteration */ inc_nrnb(nrnb, eNR_NBKERNEL_GENERIC_ADRESS, nlist->nri*14 + nlist->jindex[n]*54); }
void mc_pscale(t_inputrec *ir,matrix mu, matrix box,matrix box_rel, int start,int nr_atoms, rvec x[],unsigned short cFREEZE[], t_nrnb *nrnb,t_block *mols,rvec *xcm,t_graph *graph) { ivec *nFreeze=ir->opts.nFreeze; int n,m,d,g=0,natoms; real dv; rvec dxcm,dx,*xs; snew(xs,nr_atoms); for(n=start;n<nr_atoms;n++) { copy_rvec(x[n],xs[n]); } shift_self(graph,box,xs); for (d=0; d<DIM; d++) { box[d][XX] = mu[XX][XX]*box[d][XX]+mu[YY][XX]*box[d][YY]+mu[ZZ][XX]*box[d][ZZ]; box[d][YY] = mu[YY][YY]*box[d][YY]+mu[ZZ][YY]*box[d][ZZ]; box[d][ZZ] = mu[ZZ][ZZ]*box[d][ZZ]; } preserve_box_shape(ir,box_rel,box); /* Scale the positions */ shift_self(graph,box,x); for (n=0; n<mols->nr; n++) { clear_rvec(dxcm); natoms = mols->index[n+1]-mols->index[n]; dxcm[XX] = mu[XX][XX]*xcm[n][XX]+mu[YY][XX]*xcm[n][YY]+mu[ZZ][XX]*xcm[n][ZZ]; dxcm[YY] = mu[YY][YY]*xcm[n][YY]+mu[ZZ][YY]*xcm[n][ZZ]; dxcm[ZZ] = mu[ZZ][ZZ]*xcm[n][ZZ]; for(m=mols->index[n];m<mols->index[n+1];m++) { //rvec_sub(x[m],xcm[n],dx); rvec_sub(dxcm,xcm[n],dx); rvec_add(xs[m],dx,x[m]); } } unshift_self(graph,box,x); /*for (n=start; n<start+nr_atoms; n++) { x[n][XX] = mu[XX][XX]*x[n][XX]+mu[YY][XX]*x[n][YY]+mu[ZZ][XX]*x[n][ZZ]; x[n][YY] = mu[YY][YY]*x[n][YY]+mu[ZZ][YY]*x[n][ZZ]; x[n][ZZ] = mu[ZZ][ZZ]*x[n][ZZ]; }*/ /* (un)shifting should NOT be done after this, * since the box vectors might have changed */ inc_nrnb(nrnb,eNR_PCOUPL,nr_atoms); sfree(xs); }