static void cconerr(gmx_domdec_t *dd, int ncons,int *bla,real *bllen,rvec *x,t_pbc *pbc, real *ncons_loc,real *ssd,real *max,int *imax) { real len,d,ma,ssd2,r2; int *nlocat,count,b,im; rvec dx; if (dd && dd->constraints) { nlocat = dd_constraints_nlocalatoms(dd); } else { nlocat = 0; } ma = 0; ssd2 = 0; im = 0; count = 0; for(b=0;b<ncons;b++) { if (pbc) { pbc_dx_aiuc(pbc,x[bla[2*b]],x[bla[2*b+1]],dx); } else { rvec_sub(x[bla[2*b]],x[bla[2*b+1]],dx); } r2 = norm2(dx); len = r2*gmx_invsqrt(r2); d = fabs(len/bllen[b]-1); if (d > ma && (nlocat==NULL || nlocat[b])) { ma = d; im = b; } if (nlocat == NULL) { ssd2 += d*d; count++; } else { ssd2 += nlocat[b]*d*d; count += nlocat[b]; } } *ncons_loc = (nlocat ? 0.5 : 1)*count; *ssd = (nlocat ? 0.5 : 1)*ssd2; *max = ma; *imax = im; }
static bool in_box(t_pbc *pbc,rvec x) { rvec box_center,dx; int shift; calc_box_center(ecenterTRIC,pbc->box,box_center); shift = pbc_dx_aiuc(pbc,x,box_center,dx); return (shift == CENTRAL); }
static gmx_bool in_box(t_pbc *pbc, rvec x) { rvec box_center, dx; int shift; /* pbc_dx_aiuc only works correctly with the rectangular box center */ calc_box_center(ecenterRECT, pbc->box, box_center); shift = pbc_dx_aiuc(pbc, x, box_center, dx); return (shift == CENTRAL); }
// The position to look for the closest periodic image // ref_pos The reference position void colvarproxy_gromacs::select_closest_image (cvm::atom_pos &pos, cvm::atom_pos const &ref_pos) { rvec r1, r2, dr; r1[0] = pos.x; r1[1] = pos.y; r1[2] = pos.z; r2[0] = ref_pos.x; r2[1] = ref_pos.y; r2[2] = ref_pos.z; pbc_dx_aiuc(&gmx_pbc, r1, r2, dr); // dr is the closest distance vector. pos.x = r2[0]+dr[0]; pos.y = r1[1]+dr[1]; pos.z = r1[2]+dr[2]; }
real do_listed_vdw_q(int ftype,int nbonds, const t_iatom iatoms[],const t_iparams iparams[], const rvec x[],rvec f[],rvec fshift[], const t_pbc *pbc,const t_graph *g, real lambda,real *dvdlambda, const t_mdatoms *md, const t_forcerec *fr,gmx_grppairener_t *grppener, int *global_atom_index) { static gmx_bool bWarn=FALSE; real eps,r2,*tab,rtab2=0; rvec dx,x14[2],f14[2]; int i,ai,aj,itype; int typeA[2]={0,0},typeB[2]={0,1}; real chargeA[2]={0,0},chargeB[2]; int gid,shift_vir,shift_f; int j_index[] = { 0, 1 }; int i0=0,i1=1,i2=2; ivec dt; int outeriter,inneriter; int nthreads = 1; int count; real krf,crf,tabscale; int ntype=0; real *nbfp=NULL; real *egnb=NULL,*egcoul=NULL; t_nblist tmplist; int icoul,ivdw; gmx_bool bMolPBC,bFreeEnergy; t_pf_global *pf_global; #if GMX_THREAD_SHM_FDECOMP pthread_mutex_t mtx; #else void * mtx = NULL; #endif #if GMX_THREAD_SHM_FDECOMP pthread_mutex_initialize(&mtx); #endif bMolPBC = fr->bMolPBC; pf_global = fr->pf_global; switch (ftype) { case F_LJ14: case F_LJC14_Q: eps = fr->epsfac*fr->fudgeQQ; ntype = 1; egnb = grppener->ener[egLJ14]; egcoul = grppener->ener[egCOUL14]; break; case F_LJC_PAIRS_NB: eps = fr->epsfac; ntype = 1; egnb = grppener->ener[egLJSR]; egcoul = grppener->ener[egCOULSR]; break; default: gmx_fatal(FARGS,"Unknown function type %d in do_nonbonded14", ftype); } tab = fr->tab14.tab; rtab2 = sqr(fr->tab14.r); tabscale = fr->tab14.scale; krf = fr->k_rf; crf = fr->c_rf; /* Determine the values for icoul/ivdw. */ if (fr->bEwald) { icoul = 1; } else if(fr->bcoultab) { icoul = 3; } else if(fr->eeltype == eelRF_NEC) { icoul = 2; } else { icoul = 1; } if(fr->bvdwtab) { ivdw = 3; } else if(fr->bBHAM) { ivdw = 2; } else { ivdw = 1; } /* We don't do SSE or altivec here, due to large overhead for 4-fold * unrolling on short lists */ bFreeEnergy = FALSE; for(i=0; (i<nbonds); ) { itype = iatoms[i++]; ai = iatoms[i++]; aj = iatoms[i++]; gid = GID(md->cENER[ai],md->cENER[aj],md->nenergrp); switch (ftype) { case F_LJ14: bFreeEnergy = (fr->efep != efepNO && ((md->nPerturbed && (md->bPerturbed[ai] || md->bPerturbed[aj])) || iparams[itype].lj14.c6A != iparams[itype].lj14.c6B || iparams[itype].lj14.c12A != iparams[itype].lj14.c12B)); chargeA[0] = md->chargeA[ai]; chargeA[1] = md->chargeA[aj]; nbfp = (real *)&(iparams[itype].lj14.c6A); break; case F_LJC14_Q: eps = fr->epsfac*iparams[itype].ljc14.fqq; chargeA[0] = iparams[itype].ljc14.qi; chargeA[1] = iparams[itype].ljc14.qj; nbfp = (real *)&(iparams[itype].ljc14.c6); break; case F_LJC_PAIRS_NB: chargeA[0] = iparams[itype].ljcnb.qi; chargeA[1] = iparams[itype].ljcnb.qj; nbfp = (real *)&(iparams[itype].ljcnb.c6); break; } if (!bMolPBC) { /* This is a bonded interaction, atoms are in the same box */ shift_f = CENTRAL; r2 = distance2(x[ai],x[aj]); } else { /* Apply full periodic boundary conditions */ shift_f = pbc_dx_aiuc(pbc,x[ai],x[aj],dx); r2 = norm2(dx); } if (r2 >= rtab2) { if (!bWarn) { fprintf(stderr,"Warning: 1-4 interaction between %d and %d " "at distance %.3f which is larger than the 1-4 table size %.3f nm\n", glatnr(global_atom_index,ai), glatnr(global_atom_index,aj), sqrt(r2), sqrt(rtab2)); fprintf(stderr,"These are ignored for the rest of the simulation\n"); fprintf(stderr,"This usually means your system is exploding,\n" "if not, you should increase table-extension in your mdp file\n" "or with user tables increase the table size\n"); bWarn = TRUE; } if (debug) fprintf(debug,"%8f %8f %8f\n%8f %8f %8f\n1-4 (%d,%d) interaction not within cut-off! r=%g. Ignored\n", x[ai][XX],x[ai][YY],x[ai][ZZ], x[aj][XX],x[aj][YY],x[aj][ZZ], glatnr(global_atom_index,ai), glatnr(global_atom_index,aj), sqrt(r2)); } else { copy_rvec(x[ai],x14[0]); copy_rvec(x[aj],x14[1]); clear_rvec(f14[0]); clear_rvec(f14[1]); #ifdef DEBUG fprintf(debug,"LJ14: grp-i=%2d, grp-j=%2d, ngrp=%2d, GID=%d\n", md->cENER[ai],md->cENER[aj],md->nenergrp,gid); #endif outeriter = inneriter = count = 0; if (bFreeEnergy) { chargeB[0] = md->chargeB[ai]; chargeB[1] = md->chargeB[aj]; /* We pass &(iparams[itype].lj14.c6A) as LJ parameter matrix * to the innerloops. * Here we use that the LJ-14 parameters are stored in iparams * as c6A,c12A,c6B,c12B, which are referenced correctly * in the innerloops if we assign type combinations 0-0 and 0-1 * to atom pair ai-aj in topologies A and B respectively. */ if(ivdw==2) { gmx_fatal(FARGS,"Cannot do free energy Buckingham interactions."); } count = 0; gmx_nb_free_energy_kernel(icoul, ivdw, i1, &i0, j_index, &i1, &shift_f, fr->shift_vec[0], fshift[0], &gid, x14[0], f14[0], chargeA, chargeB, eps, krf, crf, fr->ewaldcoeff, egcoul, typeA, typeB, ntype, nbfp, egnb, tabscale, tab, lambda, dvdlambda, fr->sc_alpha, fr->sc_power, fr->sc_sigma6_def, fr->sc_sigma6_min, TRUE, &outeriter, &inneriter); } else { /* Not perturbed - call kernel 330 */ nb_kernel330 ( &i1, &i0, j_index, &i1, &shift_f, fr->shift_vec[0], fshift[0], &gid, x14[0], f14[0], chargeA, &eps, &krf, &crf, egcoul, typeA, &ntype, nbfp, egnb, &tabscale, tab, NULL, NULL, NULL, NULL, &nthreads, &count, (void *)&mtx, &outeriter, &inneriter, NULL); } /* Add the forces */ rvec_inc(f[ai],f14[0]); rvec_dec(f[aj],f14[0]); if (pf_global->bInitialized) pf_atom_add_bonded(pf_global, ai, aj, PF_INTER_NB14, f14[0]); if (g) { /* Correct the shift forces using the graph */ ivec_sub(SHIFT_IVEC(g,ai),SHIFT_IVEC(g,aj),dt); shift_vir = IVEC2IS(dt); rvec_inc(fshift[shift_vir],f14[0]); rvec_dec(fshift[CENTRAL],f14[0]); } /* flops: eNR_KERNEL_OUTER + eNR_KERNEL330 + 12 */ } } return 0.0; }
real orires(int nfa,const t_iatom forceatoms[],const t_iparams ip[], const rvec x[],rvec f[],rvec fshift[], const t_pbc *pbc,const t_graph *g, real lambda,real *dvdlambda, const t_mdatoms *md,t_fcdata *fcd, int *global_atom_index,int ftype,gmx_mc_move *mc_move) { atom_id ai,aj; int fa,d,i,type,ex,power,ki=CENTRAL; ivec dt; real r2,invr,invr2,fc,smooth_fc,dev,devins,pfac; rvec r,Sr,fij; real vtot; const t_oriresdata *od; bool bTAV; vtot = 0; od = &(fcd->orires); if (od->fc != 0) { bTAV = (od->edt != 0); smooth_fc = od->fc; if (bTAV) { /* Smoothly switch on the restraining when time averaging is used */ smooth_fc *= (1.0 - od->exp_min_t_tau); } d = 0; for(fa=0; fa<nfa; fa+=3) { type = forceatoms[fa]; ai = forceatoms[fa+1]; aj = forceatoms[fa+2]; if (pbc) { ki = pbc_dx_aiuc(pbc,x[ai],x[aj],r); } else { rvec_sub(x[ai],x[aj],r); } r2 = norm2(r); invr = invsqrt(r2); invr2 = invr*invr; ex = ip[type].orires.ex; power = ip[type].orires.power; fc = smooth_fc*ip[type].orires.kfac; dev = od->otav[d] - ip[type].orires.obs; /* NOTE: * there is no real potential when time averaging is applied */ vtot += 0.5*fc*sqr(dev); if (bTAV) { /* Calculate the force as the sqrt of tav times instantaneous */ devins = od->oins[d] - ip[type].orires.obs; if (dev*devins <= 0) { dev = 0; } else { dev = sqrt(dev*devins); if (devins < 0) { dev = -dev; } } } pfac = fc*ip[type].orires.c*invr2; for(i=0; i<power; i++) { pfac *= invr; } mvmul(od->S[ex],r,Sr); for(i=0; i<DIM; i++) { fij[i] = -pfac*dev*(4*Sr[i] - 2*(2+power)*invr2*iprod(Sr,r)*r[i]); } if (g) { ivec_sub(SHIFT_IVEC(g,ai),SHIFT_IVEC(g,aj),dt); ki=IVEC2IS(dt); } for(i=0; i<DIM; i++) { f[ai][i] += fij[i]; f[aj][i] -= fij[i]; fshift[ki][i] += fij[i]; fshift[CENTRAL][i] -= fij[i]; } d++; } } return vtot; /* Approx. 80*nfa/3 flops */ }
real calc_orires_dev(const gmx_multisim_t *ms, int nfa,const t_iatom forceatoms[],const t_iparams ip[], const t_mdatoms *md,const rvec x[],const t_pbc *pbc, t_fcdata *fcd,history_t *hist) { int fa,d,i,j,type,ex,nref; real edt,edt1,invn,pfac,r2,invr,corrfac,weight,wsv2,sw,dev; tensor *S,R,TMP; rvec5 *Dinsl,*Dins,*Dtav,*rhs; real *mref,***T; double mtot; rvec *xref,*xtmp,com,r_unrot,r; t_oriresdata *od; bool bTAV; const real two_thr=2.0/3.0; od = &(fcd->orires); if (od->nr == 0) { /* This means that this is not the master node */ gmx_fatal(FARGS,"Orientation restraints are only supported on the master node, use less processors"); } bTAV = (od->edt != 0); edt = od->edt; edt1 = od->edt1; S = od->S; Dinsl= od->Dinsl; Dins = od->Dins; Dtav = od->Dtav; T = od->TMP; rhs = od->tmp; nref = od->nref; mref = od->mref; xref = od->xref; xtmp = od->xtmp; if (bTAV) { od->exp_min_t_tau = hist->orire_initf*edt; /* Correction factor to correct for the lack of history * at short times. */ corrfac = 1.0/(1.0 - od->exp_min_t_tau); } else { corrfac = 1.0; } if (ms) { invn = 1.0/ms->nsim; } else { invn = 1.0; } clear_rvec(com); mtot = 0; j=0; for(i=0; i<md->nr; i++) { if (md->cORF[i] == 0) { copy_rvec(x[i],xtmp[j]); mref[j] = md->massT[i]; for(d=0; d<DIM; d++) { com[d] += mref[j]*xref[j][d]; } mtot += mref[j]; j++; } } svmul(1.0/mtot,com,com); for(j=0; j<nref; j++) { rvec_dec(xtmp[j],com); } /* Calculate the rotation matrix to rotate x to the reference orientation */ calc_fit_R(DIM,nref,mref,xref,xtmp,R); copy_mat(R,od->R); d = 0; for(fa=0; fa<nfa; fa+=3) { type = forceatoms[fa]; if (pbc) { pbc_dx_aiuc(pbc,x[forceatoms[fa+1]],x[forceatoms[fa+2]],r_unrot); } else { rvec_sub(x[forceatoms[fa+1]],x[forceatoms[fa+2]],r_unrot); } mvmul(R,r_unrot,r); r2 = norm2(r); invr = invsqrt(r2); /* Calculate the prefactor for the D tensor, this includes the factor 3! */ pfac = ip[type].orires.c*invr*invr*3; for(i=0; i<ip[type].orires.power; i++) { pfac *= invr; } Dinsl[d][0] = pfac*(2*r[0]*r[0] + r[1]*r[1] - r2); Dinsl[d][1] = pfac*(2*r[0]*r[1]); Dinsl[d][2] = pfac*(2*r[0]*r[2]); Dinsl[d][3] = pfac*(2*r[1]*r[1] + r[0]*r[0] - r2); Dinsl[d][4] = pfac*(2*r[1]*r[2]); if (ms) { for(i=0; i<5; i++) { Dins[d][i] = Dinsl[d][i]*invn; } } d++; } if (ms) { gmx_sum_sim(5*od->nr,Dins[0],ms); } /* Calculate the order tensor S for each experiment via optimization */ for(ex=0; ex<od->nex; ex++) { for(i=0; i<5; i++) { rhs[ex][i] = 0; for(j=0; j<=i; j++) { T[ex][i][j] = 0; } } } d = 0; for(fa=0; fa<nfa; fa+=3) { if (bTAV) { /* Here we update Dtav in t_fcdata using the data in history_t. * Thus the results stay correct when this routine * is called multiple times. */ for(i=0; i<5; i++) { Dtav[d][i] = edt*hist->orire_Dtav[d*5+i] + edt1*Dins[d][i]; } } type = forceatoms[fa]; ex = ip[type].orires.ex; weight = ip[type].orires.kfac; /* Calculate the vector rhs and half the matrix T for the 5 equations */ for(i=0; i<5; i++) { rhs[ex][i] += Dtav[d][i]*ip[type].orires.obs*weight; for(j=0; j<=i; j++) { T[ex][i][j] += Dtav[d][i]*Dtav[d][j]*weight; } } d++; } /* Now we have all the data we can calculate S */ for(ex=0; ex<od->nex; ex++) { /* Correct corrfac and copy one half of T to the other half */ for(i=0; i<5; i++) { rhs[ex][i] *= corrfac; T[ex][i][i] *= sqr(corrfac); for(j=0; j<i; j++) { T[ex][i][j] *= sqr(corrfac); T[ex][j][i] = T[ex][i][j]; } } m_inv_gen(T[ex],5,T[ex]); /* Calculate the orientation tensor S for this experiment */ S[ex][0][0] = 0; S[ex][0][1] = 0; S[ex][0][2] = 0; S[ex][1][1] = 0; S[ex][1][2] = 0; for(i=0; i<5; i++) { S[ex][0][0] += 1.5*T[ex][0][i]*rhs[ex][i]; S[ex][0][1] += 1.5*T[ex][1][i]*rhs[ex][i]; S[ex][0][2] += 1.5*T[ex][2][i]*rhs[ex][i]; S[ex][1][1] += 1.5*T[ex][3][i]*rhs[ex][i]; S[ex][1][2] += 1.5*T[ex][4][i]*rhs[ex][i]; } S[ex][1][0] = S[ex][0][1]; S[ex][2][0] = S[ex][0][2]; S[ex][2][1] = S[ex][1][2]; S[ex][2][2] = -S[ex][0][0] - S[ex][1][1]; } wsv2 = 0; sw = 0; d = 0; for(fa=0; fa<nfa; fa+=3) { type = forceatoms[fa]; ex = ip[type].orires.ex; od->otav[d] = two_thr* corrfac*(S[ex][0][0]*Dtav[d][0] + S[ex][0][1]*Dtav[d][1] + S[ex][0][2]*Dtav[d][2] + S[ex][1][1]*Dtav[d][3] + S[ex][1][2]*Dtav[d][4]); if (bTAV) { od->oins[d] = two_thr*(S[ex][0][0]*Dins[d][0] + S[ex][0][1]*Dins[d][1] + S[ex][0][2]*Dins[d][2] + S[ex][1][1]*Dins[d][3] + S[ex][1][2]*Dins[d][4]); } if (ms) { /* When ensemble averaging is used recalculate the local orientation * for output to the energy file. */ od->oinsl[d] = two_thr* (S[ex][0][0]*Dinsl[d][0] + S[ex][0][1]*Dinsl[d][1] + S[ex][0][2]*Dinsl[d][2] + S[ex][1][1]*Dinsl[d][3] + S[ex][1][2]*Dinsl[d][4]); } dev = od->otav[d] - ip[type].orires.obs; wsv2 += ip[type].orires.kfac*sqr(dev); sw += ip[type].orires.kfac; d++; } od->rmsdev = sqrt(wsv2/sw); /* Rotate the S matrices back, so we get the correct grad(tr(S D)) */ for(ex=0; ex<od->nex; ex++) { tmmul(R,S[ex],TMP); mmul(TMP,R,S[ex]); } return od->rmsdev; /* Approx. 120*nfa/3 flops */ }
static void lincs_warning(FILE *fplog, gmx_domdec_t *dd,rvec *x,rvec *xprime,t_pbc *pbc, int ncons,int *bla,real *bllen,real wangle, int maxwarn,int *warncount) { int b,i,j; rvec v0,v1; real wfac,d0,d1,cosine; char buf[STRLEN]; wfac=cos(DEG2RAD*wangle); sprintf(buf,"bonds that rotated more than %g degrees:\n" " atom 1 atom 2 angle previous, current, constraint length\n", wangle); fprintf(stderr,"%s",buf); if (fplog) { fprintf(fplog,"%s",buf); } for(b=0;b<ncons;b++) { i = bla[2*b]; j = bla[2*b+1]; if (pbc) { pbc_dx_aiuc(pbc,x[i],x[j],v0); pbc_dx_aiuc(pbc,xprime[i],xprime[j],v1); } else { rvec_sub(x[i],x[j],v0); rvec_sub(xprime[i],xprime[j],v1); } d0 = norm(v0); d1 = norm(v1); cosine = iprod(v0,v1)/(d0*d1); if (cosine < wfac) { sprintf(buf," %6d %6d %5.1f %8.4f %8.4f %8.4f\n", ddglatnr(dd,i),ddglatnr(dd,j), RAD2DEG*acos(cosine),d0,d1,bllen[b]); fprintf(stderr,"%s",buf); if (fplog) { fprintf(fplog,"%s",buf); } if (!gmx_isfinite(d1)) { gmx_fatal(FARGS,"Bond length not finite."); } (*warncount)++; } } if (*warncount > maxwarn) { too_many_constraint_warnings(econtLINCS,*warncount); } }
static void do_lincs(rvec *x,rvec *xp,matrix box,t_pbc *pbc, struct gmx_lincsdata *lincsd,real *invmass, t_commrec *cr, real wangle,int *warn, real invdt,rvec *v, gmx_bool bCalcVir,tensor rmdr) { int b,i,j,k,n,iter; real tmp0,tmp1,tmp2,im1,im2,mvb,rlen,len,len2,dlen2,wfac,lam; rvec dx; int ncons,*bla,*blnr,*blbnb; rvec *r; real *blc,*blmf,*bllen,*blcc,*rhs1,*rhs2,*sol,*lambda; int *nlocat; ncons = lincsd->nc; bla = lincsd->bla; r = lincsd->tmpv; blnr = lincsd->blnr; blbnb = lincsd->blbnb; blc = lincsd->blc; blmf = lincsd->blmf; bllen = lincsd->bllen; blcc = lincsd->tmpncc; rhs1 = lincsd->tmp1; rhs2 = lincsd->tmp2; sol = lincsd->tmp3; lambda = lincsd->lambda; if (DOMAINDECOMP(cr) && cr->dd->constraints) { nlocat = dd_constraints_nlocalatoms(cr->dd); } else if (PARTDECOMP(cr)) { nlocat = pd_constraints_nlocalatoms(cr->pd); } else { nlocat = NULL; } *warn = 0; if (pbc) { /* Compute normalized i-j vectors */ for(b=0; b<ncons; b++) { pbc_dx_aiuc(pbc,x[bla[2*b]],x[bla[2*b+1]],dx); unitv(dx,r[b]); } for(b=0; b<ncons; b++) { for(n=blnr[b]; n<blnr[b+1]; n++) { blcc[n] = blmf[n]*iprod(r[b],r[blbnb[n]]); } pbc_dx_aiuc(pbc,xp[bla[2*b]],xp[bla[2*b+1]],dx); mvb = blc[b]*(iprod(r[b],dx) - bllen[b]); rhs1[b] = mvb; sol[b] = mvb; } } else { /* Compute normalized i-j vectors */ for(b=0; b<ncons; b++) { i = bla[2*b]; j = bla[2*b+1]; tmp0 = x[i][0] - x[j][0]; tmp1 = x[i][1] - x[j][1]; tmp2 = x[i][2] - x[j][2]; rlen = gmx_invsqrt(tmp0*tmp0+tmp1*tmp1+tmp2*tmp2); r[b][0] = rlen*tmp0; r[b][1] = rlen*tmp1; r[b][2] = rlen*tmp2; } /* 16 ncons flops */ for(b=0; b<ncons; b++) { tmp0 = r[b][0]; tmp1 = r[b][1]; tmp2 = r[b][2]; len = bllen[b]; i = bla[2*b]; j = bla[2*b+1]; for(n=blnr[b]; n<blnr[b+1]; n++) { k = blbnb[n]; blcc[n] = blmf[n]*(tmp0*r[k][0] + tmp1*r[k][1] + tmp2*r[k][2]); } /* 6 nr flops */ mvb = blc[b]*(tmp0*(xp[i][0] - xp[j][0]) + tmp1*(xp[i][1] - xp[j][1]) + tmp2*(xp[i][2] - xp[j][2]) - len); rhs1[b] = mvb; sol[b] = mvb; /* 10 flops */ } /* Together: 26*ncons + 6*nrtot flops */ } lincs_matrix_expand(lincsd,blcc,rhs1,rhs2,sol); /* nrec*(ncons+2*nrtot) flops */ for(b=0; b<ncons; b++) { i = bla[2*b]; j = bla[2*b+1]; mvb = blc[b]*sol[b]; lambda[b] = -mvb; im1 = invmass[i]; im2 = invmass[j]; tmp0 = r[b][0]*mvb; tmp1 = r[b][1]*mvb; tmp2 = r[b][2]*mvb; xp[i][0] -= tmp0*im1; xp[i][1] -= tmp1*im1; xp[i][2] -= tmp2*im1; xp[j][0] += tmp0*im2; xp[j][1] += tmp1*im2; xp[j][2] += tmp2*im2; } /* 16 ncons flops */ /* ******** Correction for centripetal effects ******** */ wfac = cos(DEG2RAD*wangle); wfac = wfac*wfac; for(iter=0; iter<lincsd->nIter; iter++) { if (DOMAINDECOMP(cr) && cr->dd->constraints) { /* Communicate the corrected non-local coordinates */ dd_move_x_constraints(cr->dd,box,xp,NULL); } else if (PARTDECOMP(cr)) { pd_move_x_constraints(cr,xp,NULL); } for(b=0; b<ncons; b++) { len = bllen[b]; if (pbc) { pbc_dx_aiuc(pbc,xp[bla[2*b]],xp[bla[2*b+1]],dx); } else { rvec_sub(xp[bla[2*b]],xp[bla[2*b+1]],dx); } len2 = len*len; dlen2 = 2*len2 - norm2(dx); if (dlen2 < wfac*len2 && (nlocat==NULL || nlocat[b])) { *warn = b; } if (dlen2 > 0) { mvb = blc[b]*(len - dlen2*gmx_invsqrt(dlen2)); } else { mvb = blc[b]*len; } rhs1[b] = mvb; sol[b] = mvb; } /* 20*ncons flops */ lincs_matrix_expand(lincsd,blcc,rhs1,rhs2,sol); /* nrec*(ncons+2*nrtot) flops */ for(b=0; b<ncons; b++) { i = bla[2*b]; j = bla[2*b+1]; lam = lambda[b]; mvb = blc[b]*sol[b]; lambda[b] = lam - mvb; im1 = invmass[i]; im2 = invmass[j]; tmp0 = r[b][0]*mvb; tmp1 = r[b][1]*mvb; tmp2 = r[b][2]*mvb; xp[i][0] -= tmp0*im1; xp[i][1] -= tmp1*im1; xp[i][2] -= tmp2*im1; xp[j][0] += tmp0*im2; xp[j][1] += tmp1*im2; xp[j][2] += tmp2*im2; } /* 17 ncons flops */ } /* nit*ncons*(37+9*nrec) flops */ if (v) { /* Correct the velocities */ for(b=0; b<ncons; b++) { i = bla[2*b]; j = bla[2*b+1]; im1 = invmass[i]*lambda[b]*invdt; im2 = invmass[j]*lambda[b]*invdt; v[i][0] += im1*r[b][0]; v[i][1] += im1*r[b][1]; v[i][2] += im1*r[b][2]; v[j][0] -= im2*r[b][0]; v[j][1] -= im2*r[b][1]; v[j][2] -= im2*r[b][2]; } /* 16 ncons flops */ } if (nlocat) { /* Only account for local atoms */ for(b=0; b<ncons; b++) { lambda[b] *= 0.5*nlocat[b]; } } if (bCalcVir) { /* Constraint virial */ for(b=0; b<ncons; b++) { tmp0 = bllen[b]*lambda[b]; for(i=0; i<DIM; i++) { tmp1 = tmp0*r[b][i]; for(j=0; j<DIM; j++) { rmdr[i][j] -= tmp1*r[b][j]; } } } /* 22 ncons flops */ } /* Total: * 26*ncons + 6*nrtot + nrec*(ncons+2*nrtot) * + nit * (20*ncons + nrec*(ncons+2*nrtot) + 17 ncons) * * (26+nrec)*ncons + (6+2*nrec)*nrtot * + nit * ((37+nrec)*ncons + 2*nrec*nrtot) * if nit=1 * (63+nrec)*ncons + (6+4*nrec)*nrtot */ }
/* LINCS projection, works on derivatives of the coordinates */ static void do_lincsp(rvec *x,rvec *f,rvec *fp,t_pbc *pbc, struct gmx_lincsdata *lincsd,int th, real *invmass, int econq,real *dvdlambda, gmx_bool bCalcVir,tensor rmdf) { int b0,b1,b,i,j,k,n; real tmp0,tmp1,tmp2,im1,im2,mvb,rlen,len,wfac,lam; rvec dx; int *bla,*blnr,*blbnb; rvec *r; real *blc,*blmf,*blcc,*rhs1,*rhs2,*sol; b0 = lincsd->th[th].b0; b1 = lincsd->th[th].b1; bla = lincsd->bla; r = lincsd->tmpv; blnr = lincsd->blnr; blbnb = lincsd->blbnb; if (econq != econqForce) { /* Use mass-weighted parameters */ blc = lincsd->blc; blmf = lincsd->blmf; } else { /* Use non mass-weighted parameters */ blc = lincsd->blc1; blmf = lincsd->blmf1; } blcc = lincsd->tmpncc; rhs1 = lincsd->tmp1; rhs2 = lincsd->tmp2; sol = lincsd->tmp3; /* Compute normalized i-j vectors */ if (pbc) { for(b=b0; b<b1; b++) { pbc_dx_aiuc(pbc,x[bla[2*b]],x[bla[2*b+1]],dx); unitv(dx,r[b]); } } else { for(b=b0; b<b1; b++) { rvec_sub(x[bla[2*b]],x[bla[2*b+1]],dx); unitv(dx,r[b]); } /* 16 ncons flops */ } #pragma omp barrier for(b=b0; b<b1; b++) { tmp0 = r[b][0]; tmp1 = r[b][1]; tmp2 = r[b][2]; i = bla[2*b]; j = bla[2*b+1]; for(n=blnr[b]; n<blnr[b+1]; n++) { k = blbnb[n]; blcc[n] = blmf[n]*(tmp0*r[k][0] + tmp1*r[k][1] + tmp2*r[k][2]); } /* 6 nr flops */ mvb = blc[b]*(tmp0*(f[i][0] - f[j][0]) + tmp1*(f[i][1] - f[j][1]) + tmp2*(f[i][2] - f[j][2])); rhs1[b] = mvb; sol[b] = mvb; /* 7 flops */ } /* Together: 23*ncons + 6*nrtot flops */ lincs_matrix_expand(lincsd,b0,b1,blcc,rhs1,rhs2,sol); /* nrec*(ncons+2*nrtot) flops */ if (econq == econqDeriv_FlexCon) { /* We only want to constraint the flexible constraints, * so we mask out the normal ones by setting sol to 0. */ for(b=b0; b<b1; b++) { if (!(lincsd->bllen0[b] == 0 && lincsd->ddist[b] == 0)) { sol[b] = 0; } } } if (econq != econqForce) { lincs_update_atoms(lincsd,th,1.0,sol,r,invmass,fp); } else { for(b=b0; b<b1; b++) { i = bla[2*b]; j = bla[2*b+1]; mvb = blc[b]*sol[b]; tmp0 = r[b][0]*mvb; tmp1 = r[b][1]*mvb; tmp2 = r[b][2]*mvb; fp[i][0] -= tmp0; fp[i][1] -= tmp1; fp[i][2] -= tmp2; fp[j][0] += tmp0; fp[j][1] += tmp1; fp[j][2] += tmp2; } if (dvdlambda != NULL) { #pragma omp barrier for(b=b0; b<b1; b++) { *dvdlambda -= blc[b]*sol[b]*lincsd->ddist[b]; } } /* 10 ncons flops */ } if (bCalcVir) { /* Constraint virial, * determines sum r_bond x delta f, * where delta f is the constraint correction * of the quantity that is being constrained. */ for(b=b0; b<b1; b++) { mvb = lincsd->bllen[b]*blc[b]*sol[b]; for(i=0; i<DIM; i++) { tmp1 = mvb*r[b][i]; for(j=0; j<DIM; j++) { rmdf[i][j] += tmp1*r[b][j]; } } } /* 23 ncons flops */ } }
void csettle(gmx_settledata_t settled, int nsettle, t_iatom iatoms[], const t_pbc *pbc, real b4[], real after[], real invdt, real *v, int CalcVirAtomEnd, tensor vir_r_m_dr, int *error) { /* ***************************************************************** */ /* ** */ /* Subroutine : setlep - reset positions of TIP3P waters ** */ /* Author : Shuichi Miyamoto ** */ /* Date of last update : Oct. 1, 1992 ** */ /* ** */ /* Reference for the SETTLE algorithm ** */ /* S. Miyamoto et al., J. Comp. Chem., 13, 952 (1992). ** */ /* ** */ /* ***************************************************************** */ /* Initialized data */ settleparam_t *p; real wh, ra, rb, rc, irc2; real mO, mH; /* Local variables */ real gama, beta, alpa, xcom, ycom, zcom, al2be2, tmp, tmp2; real axlng, aylng, azlng, trns11, trns21, trns31, trns12, trns22, trns32, trns13, trns23, trns33, cosphi, costhe, sinphi, sinthe, cospsi, xaksxd, yaksxd, xakszd, yakszd, zakszd, zaksxd, xaksyd, xb0, yb0, zb0, xc0, yc0, zc0, xa1; real ya1, za1, xb1, yb1; real zb1, xc1, yc1, zc1, yaksyd, zaksyd, sinpsi, xa3, ya3, za3, xb3, yb3, zb3, xc3, yc3, zc3, xb0d, yb0d, xc0d, yc0d, za1d, xb1d, yb1d, zb1d, xc1d, yc1d, zc1d, ya2d, xb2d, yb2d, yc2d, xa3d, ya3d, za3d, xb3d, yb3d, zb3d, xc3d, yc3d, zc3d; real t1, t2; real dax, day, daz, dbx, dby, dbz, dcx, dcy, dcz; real mdax, mday, mdaz, mdbx, mdby, mdbz, mdcx, mdcy, mdcz; gmx_bool bOK; int i, ow1, hw2, hw3; rvec dx, sh_hw2 = {0, 0, 0}, sh_hw3 = {0, 0, 0}; rvec doh2, doh3; int is; *error = -1; CalcVirAtomEnd *= 3; p = &settled->massw; wh = p->wh; rc = p->rc; ra = p->ra; rb = p->rb; irc2 = p->irc2; mO = p->mO; mH = p->mH; #ifdef PRAGMAS #pragma ivdep #endif for (i = 0; i < nsettle; ++i) { bOK = TRUE; /* --- Step1 A1' --- */ ow1 = iatoms[i*4+1] * 3; hw2 = iatoms[i*4+2] * 3; hw3 = iatoms[i*4+3] * 3; if (pbc == NULL) { xb0 = b4[hw2 + XX] - b4[ow1 + XX]; yb0 = b4[hw2 + YY] - b4[ow1 + YY]; zb0 = b4[hw2 + ZZ] - b4[ow1 + ZZ]; xc0 = b4[hw3 + XX] - b4[ow1 + XX]; yc0 = b4[hw3 + YY] - b4[ow1 + YY]; zc0 = b4[hw3 + ZZ] - b4[ow1 + ZZ]; /* 6 flops */ rvec_sub(after+hw2, after+ow1, doh2); rvec_sub(after+hw3, after+ow1, doh3); /* 6 flops */ } else { pbc_dx_aiuc(pbc, b4+hw2, b4+ow1, dx); xb0 = dx[XX]; yb0 = dx[YY]; zb0 = dx[ZZ]; pbc_dx_aiuc(pbc, b4+hw3, b4+ow1, dx); xc0 = dx[XX]; yc0 = dx[YY]; zc0 = dx[ZZ]; /* Tedious way of doing pbc */ is = pbc_dx_aiuc(pbc, after+hw2, after+ow1, doh2); if (is == CENTRAL) { clear_rvec(sh_hw2); } else { sh_hw2[XX] = after[hw2 + XX] - (after[ow1 + XX] + doh2[XX]); sh_hw2[YY] = after[hw2 + YY] - (after[ow1 + YY] + doh2[YY]); sh_hw2[ZZ] = after[hw2 + ZZ] - (after[ow1 + ZZ] + doh2[ZZ]); rvec_dec(after+hw2, sh_hw2); } is = pbc_dx_aiuc(pbc, after+hw3, after+ow1, doh3); if (is == CENTRAL) { clear_rvec(sh_hw3); } else { sh_hw3[XX] = after[hw3 + XX] - (after[ow1 + XX] + doh3[XX]); sh_hw3[YY] = after[hw3 + YY] - (after[ow1 + YY] + doh3[YY]); sh_hw3[ZZ] = after[hw3 + ZZ] - (after[ow1 + ZZ] + doh3[ZZ]); rvec_dec(after+hw3, sh_hw3); } } /* Not calculating the center of mass using the oxygen position * and the O-H distances, as done below, will make SETTLE * the largest source of energy drift for simulations of water, * as then the oxygen coordinate is multiplied by 0.89 at every step, * which can then transfer a systematic rounding to the oxygen velocity. */ xa1 = -(doh2[XX] + doh3[XX]) * wh; ya1 = -(doh2[YY] + doh3[YY]) * wh; za1 = -(doh2[ZZ] + doh3[ZZ]) * wh; xcom = after[ow1 + XX] - xa1; ycom = after[ow1 + YY] - ya1; zcom = after[ow1 + ZZ] - za1; xb1 = after[hw2 + XX] - xcom; yb1 = after[hw2 + YY] - ycom; zb1 = after[hw2 + ZZ] - zcom; xc1 = after[hw3 + XX] - xcom; yc1 = after[hw3 + YY] - ycom; zc1 = after[hw3 + ZZ] - zcom; /* 15 flops */ xakszd = yb0 * zc0 - zb0 * yc0; yakszd = zb0 * xc0 - xb0 * zc0; zakszd = xb0 * yc0 - yb0 * xc0; xaksxd = ya1 * zakszd - za1 * yakszd; yaksxd = za1 * xakszd - xa1 * zakszd; zaksxd = xa1 * yakszd - ya1 * xakszd; xaksyd = yakszd * zaksxd - zakszd * yaksxd; yaksyd = zakszd * xaksxd - xakszd * zaksxd; zaksyd = xakszd * yaksxd - yakszd * xaksxd; /* 27 flops */ axlng = gmx_invsqrt(xaksxd * xaksxd + yaksxd * yaksxd + zaksxd * zaksxd); aylng = gmx_invsqrt(xaksyd * xaksyd + yaksyd * yaksyd + zaksyd * zaksyd); azlng = gmx_invsqrt(xakszd * xakszd + yakszd * yakszd + zakszd * zakszd); trns11 = xaksxd * axlng; trns21 = yaksxd * axlng; trns31 = zaksxd * axlng; trns12 = xaksyd * aylng; trns22 = yaksyd * aylng; trns32 = zaksyd * aylng; trns13 = xakszd * azlng; trns23 = yakszd * azlng; trns33 = zakszd * azlng; /* 24 flops */ xb0d = trns11 * xb0 + trns21 * yb0 + trns31 * zb0; yb0d = trns12 * xb0 + trns22 * yb0 + trns32 * zb0; xc0d = trns11 * xc0 + trns21 * yc0 + trns31 * zc0; yc0d = trns12 * xc0 + trns22 * yc0 + trns32 * zc0; /* xa1d = trns11 * xa1 + trns21 * ya1 + trns31 * za1; ya1d = trns12 * xa1 + trns22 * ya1 + trns32 * za1; */ za1d = trns13 * xa1 + trns23 * ya1 + trns33 * za1; xb1d = trns11 * xb1 + trns21 * yb1 + trns31 * zb1; yb1d = trns12 * xb1 + trns22 * yb1 + trns32 * zb1; zb1d = trns13 * xb1 + trns23 * yb1 + trns33 * zb1; xc1d = trns11 * xc1 + trns21 * yc1 + trns31 * zc1; yc1d = trns12 * xc1 + trns22 * yc1 + trns32 * zc1; zc1d = trns13 * xc1 + trns23 * yc1 + trns33 * zc1; /* 65 flops */ sinphi = za1d * gmx_invsqrt(ra*ra); tmp = 1.0 - sinphi * sinphi; if (tmp <= 0) { bOK = FALSE; } else { tmp2 = gmx_invsqrt(tmp); cosphi = tmp*tmp2; sinpsi = (zb1d - zc1d) * irc2 * tmp2; tmp2 = 1.0 - sinpsi * sinpsi; if (tmp2 <= 0) { bOK = FALSE; } else { cospsi = tmp2*gmx_invsqrt(tmp2); } } /* 46 flops */ if (bOK) { ya2d = ra * cosphi; xb2d = -rc * cospsi; t1 = -rb * cosphi; t2 = rc * sinpsi * sinphi; yb2d = t1 - t2; yc2d = t1 + t2; /* 7 flops */ /* --- Step3 al,be,ga --- */ alpa = xb2d * (xb0d - xc0d) + yb0d * yb2d + yc0d * yc2d; beta = xb2d * (yc0d - yb0d) + xb0d * yb2d + xc0d * yc2d; gama = xb0d * yb1d - xb1d * yb0d + xc0d * yc1d - xc1d * yc0d; al2be2 = alpa * alpa + beta * beta; tmp2 = (al2be2 - gama * gama); sinthe = (alpa * gama - beta * tmp2*gmx_invsqrt(tmp2)) * gmx_invsqrt(al2be2*al2be2); /* 47 flops */ /* --- Step4 A3' --- */ tmp2 = 1.0 - sinthe * sinthe; costhe = tmp2*gmx_invsqrt(tmp2); xa3d = -ya2d * sinthe; ya3d = ya2d * costhe; za3d = za1d; xb3d = xb2d * costhe - yb2d * sinthe; yb3d = xb2d * sinthe + yb2d * costhe; zb3d = zb1d; xc3d = -xb2d * costhe - yc2d * sinthe; yc3d = -xb2d * sinthe + yc2d * costhe; zc3d = zc1d; /* 26 flops */ /* --- Step5 A3 --- */ xa3 = trns11 * xa3d + trns12 * ya3d + trns13 * za3d; ya3 = trns21 * xa3d + trns22 * ya3d + trns23 * za3d; za3 = trns31 * xa3d + trns32 * ya3d + trns33 * za3d; xb3 = trns11 * xb3d + trns12 * yb3d + trns13 * zb3d; yb3 = trns21 * xb3d + trns22 * yb3d + trns23 * zb3d; zb3 = trns31 * xb3d + trns32 * yb3d + trns33 * zb3d; xc3 = trns11 * xc3d + trns12 * yc3d + trns13 * zc3d; yc3 = trns21 * xc3d + trns22 * yc3d + trns23 * zc3d; zc3 = trns31 * xc3d + trns32 * yc3d + trns33 * zc3d; /* 45 flops */ after[ow1] = xcom + xa3; after[ow1 + 1] = ycom + ya3; after[ow1 + 2] = zcom + za3; after[hw2] = xcom + xb3; after[hw2 + 1] = ycom + yb3; after[hw2 + 2] = zcom + zb3; after[hw3] = xcom + xc3; after[hw3 + 1] = ycom + yc3; after[hw3 + 2] = zcom + zc3; /* 9 flops */ if (pbc != NULL) { rvec_inc(after+hw2, sh_hw2); rvec_inc(after+hw3, sh_hw3); } dax = xa3 - xa1; day = ya3 - ya1; daz = za3 - za1; dbx = xb3 - xb1; dby = yb3 - yb1; dbz = zb3 - zb1; dcx = xc3 - xc1; dcy = yc3 - yc1; dcz = zc3 - zc1; /* 9 flops, counted with the virial */ if (v != NULL) { v[ow1] += dax*invdt; v[ow1 + 1] += day*invdt; v[ow1 + 2] += daz*invdt; v[hw2] += dbx*invdt; v[hw2 + 1] += dby*invdt; v[hw2 + 2] += dbz*invdt; v[hw3] += dcx*invdt; v[hw3 + 1] += dcy*invdt; v[hw3 + 2] += dcz*invdt; /* 3*6 flops */ } if (ow1 < CalcVirAtomEnd) { mdax = mO*dax; mday = mO*day; mdaz = mO*daz; mdbx = mH*dbx; mdby = mH*dby; mdbz = mH*dbz; mdcx = mH*dcx; mdcy = mH*dcy; mdcz = mH*dcz; vir_r_m_dr[XX][XX] -= b4[ow1 ]*mdax + (b4[ow1 ]+xb0)*mdbx + (b4[ow1 ]+xc0)*mdcx; vir_r_m_dr[XX][YY] -= b4[ow1 ]*mday + (b4[ow1 ]+xb0)*mdby + (b4[ow1 ]+xc0)*mdcy; vir_r_m_dr[XX][ZZ] -= b4[ow1 ]*mdaz + (b4[ow1 ]+xb0)*mdbz + (b4[ow1 ]+xc0)*mdcz; vir_r_m_dr[YY][XX] -= b4[ow1+1]*mdax + (b4[ow1+1]+yb0)*mdbx + (b4[ow1+1]+yc0)*mdcx; vir_r_m_dr[YY][YY] -= b4[ow1+1]*mday + (b4[ow1+1]+yb0)*mdby + (b4[ow1+1]+yc0)*mdcy; vir_r_m_dr[YY][ZZ] -= b4[ow1+1]*mdaz + (b4[ow1+1]+yb0)*mdbz + (b4[ow1+1]+yc0)*mdcz; vir_r_m_dr[ZZ][XX] -= b4[ow1+2]*mdax + (b4[ow1+2]+zb0)*mdbx + (b4[ow1+2]+zc0)*mdcx; vir_r_m_dr[ZZ][YY] -= b4[ow1+2]*mday + (b4[ow1+2]+zb0)*mdby + (b4[ow1+2]+zc0)*mdcy; vir_r_m_dr[ZZ][ZZ] -= b4[ow1+2]*mdaz + (b4[ow1+2]+zb0)*mdbz + (b4[ow1+2]+zc0)*mdcz; /* 3*24 - 9 flops */ } } else { *error = i; } #ifdef DEBUG if (debug) { check_cons(debug, "settle", after, ow1, hw2, hw3); } #endif } }
void settle_proj(gmx_settledata_t settled, int econq, int nsettle, t_iatom iatoms[], const t_pbc *pbc, rvec x[], rvec *der, rvec *derp, int calcvir_atom_end, tensor vir_r_m_dder) { /* Settle for projection out constraint components * of derivatives of the coordinates. * Berk Hess 2008-1-10 */ settleparam_t *p; real imO, imH, dOH, dHH, invdOH, invdHH; matrix invmat; int i, m, m2, ow1, hw2, hw3; rvec roh2, roh3, rhh, dc, fc; calcvir_atom_end *= DIM; if (econq == econqForce) { p = &settled->mass1; } else { p = &settled->massw; } imO = p->imO; imH = p->imH; copy_mat(p->invmat, invmat); dOH = p->dOH; dHH = p->dHH; invdOH = p->invdOH; invdHH = p->invdHH; #ifdef PRAGMAS #pragma ivdep #endif for (i = 0; i < nsettle; i++) { ow1 = iatoms[i*4+1]; hw2 = iatoms[i*4+2]; hw3 = iatoms[i*4+3]; if (pbc == NULL) { rvec_sub(x[ow1], x[hw2], roh2); rvec_sub(x[ow1], x[hw3], roh3); rvec_sub(x[hw2], x[hw3], rhh); } else { pbc_dx_aiuc(pbc, x[ow1], x[hw2], roh2); pbc_dx_aiuc(pbc, x[ow1], x[hw3], roh3); pbc_dx_aiuc(pbc, x[hw2], x[hw3], rhh); } svmul(invdOH, roh2, roh2); svmul(invdOH, roh3, roh3); svmul(invdHH, rhh, rhh); /* 18 flops */ /* Determine the projections of der on the bonds */ clear_rvec(dc); for (m = 0; m < DIM; m++) { dc[0] += (der[ow1][m] - der[hw2][m])*roh2[m]; dc[1] += (der[ow1][m] - der[hw3][m])*roh3[m]; dc[2] += (der[hw2][m] - der[hw3][m])*rhh [m]; } /* 27 flops */ /* Determine the correction for the three bonds */ mvmul(invmat, dc, fc); /* 15 flops */ /* Subtract the corrections from derp */ for (m = 0; m < DIM; m++) { derp[ow1][m] -= imO*( fc[0]*roh2[m] + fc[1]*roh3[m]); derp[hw2][m] -= imH*(-fc[0]*roh2[m] + fc[2]*rhh [m]); derp[hw3][m] -= imH*(-fc[1]*roh3[m] - fc[2]*rhh [m]); } /* 45 flops */ if (ow1 < calcvir_atom_end) { /* Determining r \dot m der is easy, * since fc contains the mass weighted corrections for der. */ for (m = 0; m < DIM; m++) { for (m2 = 0; m2 < DIM; m2++) { vir_r_m_dder[m][m2] += dOH*roh2[m]*roh2[m2]*fc[0] + dOH*roh3[m]*roh3[m2]*fc[1] + dHH*rhh [m]*rhh [m2]*fc[2]; } } } } }
/*! \brief * Does a grid search. */ static gmx_bool grid_search(gmx_ana_nbsearch_t *d, gmx_bool (*action)(gmx_ana_nbsearch_t *d, int i, real r2)) { int i; rvec dx; real r2; if (d->bGrid) { int nbi, ci, cai; nbi = d->prevnbi; cai = d->prevcai + 1; for (; nbi < d->ngridnb; ++nbi) { ivec cell; ivec_add(d->testcell, d->gnboffs[nbi], cell); /* TODO: Support for 2D and screw PBC */ cell[XX] = (cell[XX] + d->ncelldim[XX]) % d->ncelldim[XX]; cell[YY] = (cell[YY] + d->ncelldim[YY]) % d->ncelldim[YY]; cell[ZZ] = (cell[ZZ] + d->ncelldim[ZZ]) % d->ncelldim[ZZ]; ci = grid_index(d, cell); /* TODO: Calculate the required PBC shift outside the inner loop */ for (; cai < d->ncatoms[ci]; ++cai) { i = d->catom[ci][cai]; if (is_excluded(d, i)) { continue; } pbc_dx_aiuc(d->pbc, d->xtest, d->xref[i], dx); r2 = norm2(dx); if (r2 <= d->cutoff2) { if (action(d, i, r2)) { d->prevnbi = nbi; d->prevcai = cai; d->previ = i; return TRUE; } } } d->exclind = 0; cai = 0; } } else { i = d->previ + 1; for (; i < d->nref; ++i) { if (is_excluded(d, i)) { continue; } if (d->pbc) { pbc_dx(d->pbc, d->xtest, d->xref[i], dx); } else { rvec_sub(d->xtest, d->xref[i], dx); } r2 = norm2(dx); if (r2 <= d->cutoff2) { if (action(d, i, r2)) { d->previ = i; return TRUE; } } } } return FALSE; }
static void make_cyl_refgrps(t_commrec *cr, struct pull_t *pull, t_mdatoms *md, t_pbc *pbc, double t, rvec *x) { /* The size and stride per coord for the reduction buffer */ const int stride = 9; int c, i, ii, m, start, end; rvec g_x, dx, dir; double inv_cyl_r2; pull_comm_t *comm; gmx_ga2la_t *ga2la = NULL; comm = &pull->comm; if (comm->dbuf_cyl == NULL) { snew(comm->dbuf_cyl, pull->ncoord*stride); } if (cr && DOMAINDECOMP(cr)) { ga2la = cr->dd->ga2la; } start = 0; end = md->homenr; inv_cyl_r2 = 1.0/gmx::square(pull->params.cylinder_r); /* loop over all groups to make a reference group for each*/ for (c = 0; c < pull->ncoord; c++) { pull_coord_work_t *pcrd; double sum_a, wmass, wwmass; dvec radf_fac0, radf_fac1; pcrd = &pull->coord[c]; sum_a = 0; wmass = 0; wwmass = 0; clear_dvec(radf_fac0); clear_dvec(radf_fac1); if (pcrd->params.eGeom == epullgCYL) { pull_group_work_t *pref, *pgrp, *pdyna; /* pref will be the same group for all pull coordinates */ pref = &pull->group[pcrd->params.group[0]]; pgrp = &pull->group[pcrd->params.group[1]]; pdyna = &pull->dyna[c]; copy_rvec(pcrd->vec, dir); pdyna->nat_loc = 0; /* We calculate distances with respect to the reference location * of this cylinder group (g_x), which we already have now since * we reduced the other group COM over the ranks. This resolves * any PBC issues and we don't need to use a PBC-atom here. */ if (pcrd->params.rate != 0) { /* With rate=0, value_ref is set initially */ pcrd->value_ref = pcrd->params.init + pcrd->params.rate*t; } for (m = 0; m < DIM; m++) { g_x[m] = pgrp->x[m] - pcrd->vec[m]*pcrd->value_ref; } /* loop over all atoms in the main ref group */ for (i = 0; i < pref->params.nat; i++) { ii = pref->params.ind[i]; if (ga2la) { if (!ga2la_get_home(ga2la, pref->params.ind[i], &ii)) { ii = -1; } } if (ii >= start && ii < end) { double dr2, dr2_rel, inp; dvec dr; pbc_dx_aiuc(pbc, x[ii], g_x, dx); inp = iprod(dir, dx); dr2 = 0; for (m = 0; m < DIM; m++) { /* Determine the radial components */ dr[m] = dx[m] - inp*dir[m]; dr2 += dr[m]*dr[m]; } dr2_rel = dr2*inv_cyl_r2; if (dr2_rel < 1) { double mass, weight, dweight_r; dvec mdw; /* add to index, to sum of COM, to weight array */ if (pdyna->nat_loc >= pdyna->nalloc_loc) { pdyna->nalloc_loc = over_alloc_large(pdyna->nat_loc+1); srenew(pdyna->ind_loc, pdyna->nalloc_loc); srenew(pdyna->weight_loc, pdyna->nalloc_loc); srenew(pdyna->mdw, pdyna->nalloc_loc); srenew(pdyna->dv, pdyna->nalloc_loc); } pdyna->ind_loc[pdyna->nat_loc] = ii; mass = md->massT[ii]; /* The radial weight function is 1-2x^2+x^4, * where x=r/cylinder_r. Since this function depends * on the radial component, we also get radial forces * on both groups. */ weight = 1 + (-2 + dr2_rel)*dr2_rel; dweight_r = (-4 + 4*dr2_rel)*inv_cyl_r2; pdyna->weight_loc[pdyna->nat_loc] = weight; sum_a += mass*weight*inp; wmass += mass*weight; wwmass += mass*weight*weight; dsvmul(mass*dweight_r, dr, mdw); copy_dvec(mdw, pdyna->mdw[pdyna->nat_loc]); /* Currently we only have the axial component of the * distance (inp) up to an unkown offset. We add this * offset after the reduction needs to determine the * COM of the cylinder group. */ pdyna->dv[pdyna->nat_loc] = inp; for (m = 0; m < DIM; m++) { radf_fac0[m] += mdw[m]; radf_fac1[m] += mdw[m]*inp; } pdyna->nat_loc++; } } } } comm->dbuf_cyl[c*stride+0] = wmass; comm->dbuf_cyl[c*stride+1] = wwmass; comm->dbuf_cyl[c*stride+2] = sum_a; comm->dbuf_cyl[c*stride+3] = radf_fac0[XX]; comm->dbuf_cyl[c*stride+4] = radf_fac0[YY]; comm->dbuf_cyl[c*stride+5] = radf_fac0[ZZ]; comm->dbuf_cyl[c*stride+6] = radf_fac1[XX]; comm->dbuf_cyl[c*stride+7] = radf_fac1[YY]; comm->dbuf_cyl[c*stride+8] = radf_fac1[ZZ]; } if (cr != NULL && PAR(cr)) { /* Sum the contributions over the ranks */ pull_reduce_double(cr, comm, pull->ncoord*stride, comm->dbuf_cyl); } for (c = 0; c < pull->ncoord; c++) { pull_coord_work_t *pcrd; pcrd = &pull->coord[c]; if (pcrd->params.eGeom == epullgCYL) { pull_group_work_t *pdyna, *pgrp; double wmass, wwmass, dist; pdyna = &pull->dyna[c]; pgrp = &pull->group[pcrd->params.group[1]]; wmass = comm->dbuf_cyl[c*stride+0]; wwmass = comm->dbuf_cyl[c*stride+1]; pdyna->mwscale = 1.0/wmass; /* Cylinder pulling can't be used with constraints, but we set * wscale and invtm anyhow, in case someone would like to use them. */ pdyna->wscale = wmass/wwmass; pdyna->invtm = wwmass/(wmass*wmass); /* We store the deviation of the COM from the reference location * used above, since we need it when we apply the radial forces * to the atoms in the cylinder group. */ pcrd->cyl_dev = 0; for (m = 0; m < DIM; m++) { g_x[m] = pgrp->x[m] - pcrd->vec[m]*pcrd->value_ref; dist = -pcrd->vec[m]*comm->dbuf_cyl[c*stride+2]*pdyna->mwscale; pdyna->x[m] = g_x[m] - dist; pcrd->cyl_dev += dist; } /* Now we know the exact COM of the cylinder reference group, * we can determine the radial force factor (ffrad) that when * multiplied with the axial pull force will give the radial * force on the pulled (non-cylinder) group. */ for (m = 0; m < DIM; m++) { pcrd->ffrad[m] = (comm->dbuf_cyl[c*stride+6+m] + comm->dbuf_cyl[c*stride+3+m]*pcrd->cyl_dev)/wmass; } if (debug) { fprintf(debug, "Pull cylinder group %d:%8.3f%8.3f%8.3f m:%8.3f\n", c, pdyna->x[0], pdyna->x[1], pdyna->x[2], 1.0/pdyna->invtm); fprintf(debug, "ffrad %8.3f %8.3f %8.3f\n", pcrd->ffrad[XX], pcrd->ffrad[YY], pcrd->ffrad[ZZ]); } } } }
real ta_disres(int nfa,const t_iatom forceatoms[],const t_iparams ip[], const rvec x[],rvec f[],rvec fshift[], const t_pbc *pbc,const t_graph *g, real lambda,real *dvdlambda, const t_mdatoms *md,t_fcdata *fcd, int *global_atom_index) { const real sixth=1.0/6.0; const real seven_three=7.0/3.0; atom_id ai,aj; int fa,res,npair,p,pair,ki=CENTRAL,m; int type; rvec dx; real weight_rt_1; real smooth_fc,Rt,Rtav,rt2,*Rtl_6,*Rt_6,*Rtav_6; real k0,f_scal=0,fmax_scal,fk_scal,fij; real tav_viol,instant_viol,mixed_viol,violtot,vtot; real tav_viol_Rtav7,instant_viol_Rtav7; real up1,up2,low; gmx_bool bConservative,bMixed,bViolation; ivec it,jt,dt; t_disresdata *dd; int dr_weighting; gmx_bool dr_bMixed; dd = &(fcd->disres); dr_weighting = dd->dr_weighting; dr_bMixed = dd->dr_bMixed; Rtl_6 = dd->Rtl_6; Rt_6 = dd->Rt_6; Rtav_6 = dd->Rtav_6; tav_viol=instant_viol=mixed_viol=tav_viol_Rtav7=instant_viol_Rtav7=0; smooth_fc = dd->dr_fc; if (dd->dr_tau != 0) { /* scaling factor to smoothly turn on the restraint forces * * when using time averaging */ smooth_fc *= (1.0 - dd->exp_min_t_tau); } violtot = 0; vtot = 0; /* 'loop' over all atom pairs (pair_nr=fa/3) involved in restraints, * * the total number of atoms pairs is nfa/3 */ res = 0; fa = 0; while (fa < nfa) { type = forceatoms[fa]; /* Take action depending on restraint, calculate scalar force */ npair = ip[type].disres.npair; up1 = ip[type].disres.up1; up2 = ip[type].disres.up2; low = ip[type].disres.low; k0 = smooth_fc*ip[type].disres.kfac; /* save some flops when there is only one pair */ if (ip[type].disres.type != 2) { bConservative = (dr_weighting == edrwConservative) && (npair > 1); bMixed = dr_bMixed; Rt = pow(Rt_6[res],-sixth); Rtav = pow(Rtav_6[res],-sixth); } else { /* When rtype=2 use instantaneous not ensemble avereged distance */ bConservative = (npair > 1); bMixed = FALSE; Rt = pow(Rtl_6[res],-sixth); Rtav = Rt; } if (Rtav > up1) { bViolation = TRUE; tav_viol = Rtav - up1; } else if (Rtav < low) { bViolation = TRUE; tav_viol = Rtav - low; } else { bViolation = FALSE; } if (bViolation) { /* NOTE: * there is no real potential when time averaging is applied */ vtot += 0.5*k0*sqr(tav_viol); if (1/vtot == 0) { printf("vtot is inf: %f\n",vtot); } if (!bMixed) { f_scal = -k0*tav_viol; violtot += fabs(tav_viol); } else { if (Rt > up1) { if (tav_viol > 0) { instant_viol = Rt - up1; } else { bViolation = FALSE; } } else if (Rt < low) { if (tav_viol < 0) { instant_viol = Rt - low; } else { bViolation = FALSE; } } else { bViolation = FALSE; } if (bViolation) { mixed_viol = sqrt(tav_viol*instant_viol); f_scal = -k0*mixed_viol; violtot += mixed_viol; } } } if (bViolation) { fmax_scal = -k0*(up2-up1); /* Correct the force for the number of restraints */ if (bConservative) { f_scal = max(f_scal,fmax_scal); if (!bMixed) { f_scal *= Rtav/Rtav_6[res]; } else { f_scal /= 2*mixed_viol; tav_viol_Rtav7 = tav_viol*Rtav/Rtav_6[res]; instant_viol_Rtav7 = instant_viol*Rt/Rt_6[res]; } } else { f_scal /= (real)npair; f_scal = max(f_scal,fmax_scal); } /* Exert the force ... */ /* Loop over the atom pairs of 'this' restraint */ for(p=0; p<npair; p++) { pair = fa/3; ai = forceatoms[fa+1]; aj = forceatoms[fa+2]; if (pbc) { ki = pbc_dx_aiuc(pbc,x[ai],x[aj],dx); } else { rvec_sub(x[ai],x[aj],dx); } rt2 = iprod(dx,dx); weight_rt_1 = gmx_invsqrt(rt2); if (bConservative) { if (!dr_bMixed) { weight_rt_1 *= pow(dd->rm3tav[pair],seven_three); } else { weight_rt_1 *= tav_viol_Rtav7*pow(dd->rm3tav[pair],seven_three)+ instant_viol_Rtav7*pow(dd->rt[pair],-7); } } fk_scal = f_scal*weight_rt_1; if (g) { ivec_sub(SHIFT_IVEC(g,ai),SHIFT_IVEC(g,aj),dt); ki=IVEC2IS(dt); } for(m=0; m<DIM; m++) { fij = fk_scal*dx[m]; f[ai][m] += fij; f[aj][m] -= fij; fshift[ki][m] += fij; fshift[CENTRAL][m] -= fij; } fa += 3; } } else { /* No violation so force and potential contributions */ fa += 3*npair; } res++; } dd->sumviol = violtot; /* Return energy */ return vtot; }
void calc_disres_R_6(const gmx_multisim_t *ms, int nfa,const t_iatom forceatoms[],const t_iparams ip[], const rvec x[],const t_pbc *pbc, t_fcdata *fcd,history_t *hist) { atom_id ai,aj; int fa,res,i,pair,ki,kj,m; int type,npair,np; rvec dx; real *rt,*rm3tav,*Rtl_6,*Rt_6,*Rtav_6; real rt_1,rt_3,rt2; ivec it,jt,dt; t_disresdata *dd; real ETerm,ETerm1,cf1=0,cf2=0,invn=0; gmx_bool bTav; dd = &(fcd->disres); bTav = (dd->dr_tau != 0); ETerm = dd->ETerm; ETerm1 = dd->ETerm1; rt = dd->rt; rm3tav = dd->rm3tav; Rtl_6 = dd->Rtl_6; Rt_6 = dd->Rt_6; Rtav_6 = dd->Rtav_6; if (bTav) { /* scaling factor to smoothly turn on the restraint forces * * when using time averaging */ dd->exp_min_t_tau = hist->disre_initf*ETerm; cf1 = dd->exp_min_t_tau; cf2 = 1.0/(1.0 - dd->exp_min_t_tau); } if (dd->nsystems > 1) { invn = 1.0/dd->nsystems; } /* 'loop' over all atom pairs (pair_nr=fa/3) involved in restraints, * * the total number of atoms pairs is nfa/3 */ res = 0; fa = 0; while (fa < nfa) { type = forceatoms[fa]; npair = ip[type].disres.npair; Rtav_6[res] = 0.0; Rt_6[res] = 0.0; /* Loop over the atom pairs of 'this' restraint */ np = 0; while (fa < nfa && np < npair) { pair = fa/3; ai = forceatoms[fa+1]; aj = forceatoms[fa+2]; if (pbc) { pbc_dx_aiuc(pbc,x[ai],x[aj],dx); } else { rvec_sub(x[ai],x[aj],dx); } rt2 = iprod(dx,dx); rt_1 = gmx_invsqrt(rt2); rt_3 = rt_1*rt_1*rt_1; rt[pair] = sqrt(rt2); if (bTav) { /* Here we update rm3tav in t_fcdata using the data * in history_t. * Thus the results stay correct when this routine * is called multiple times. */ rm3tav[pair] = cf2*((ETerm - cf1)*hist->disre_rm3tav[pair] + ETerm1*rt_3); } else { rm3tav[pair] = rt_3; } Rt_6[res] += rt_3*rt_3; Rtav_6[res] += rm3tav[pair]*rm3tav[pair]; fa += 3; np++; } if (dd->nsystems > 1) { Rtl_6[res] = Rt_6[res]; Rt_6[res] *= invn; Rtav_6[res] *= invn; } res++; } #ifdef GMX_MPI if (dd->nsystems > 1) { gmx_sum_comm(2*dd->nres,Rt_6,dd->mpi_comm_ensemble); } #endif }
real RF_excl_correction(FILE *log, const t_forcerec *fr,t_graph *g, const t_mdatoms *mdatoms,const t_blocka *excl, rvec x[],rvec f[],rvec *fshift,const t_pbc *pbc, real lambda,real *dvdlambda) { /* Calculate the reaction-field energy correction for this node: * epsfac q_i q_j (k_rf r_ij^2 - c_rf) * and force correction for all excluded pairs, including self pairs. */ int top,i,j,j1,j2,k,ki; double q2sumA,q2sumB,ener; const real *chargeA,*chargeB; real ek,ec,L1,qiA,qiB,qqA,qqB,qqL,v; rvec dx,df; atom_id *AA; ivec dt; int start = mdatoms->start; int end = mdatoms->homenr+start; int niat; gmx_bool bMolPBC = fr->bMolPBC; if (fr->n_tpi) /* For test particle insertion we only correct for the test molecule */ start = mdatoms->nr - fr->n_tpi; ek = fr->epsfac*fr->k_rf; ec = fr->epsfac*fr->c_rf; chargeA = mdatoms->chargeA; chargeB = mdatoms->chargeB; AA = excl->a; ki = CENTRAL; if (fr->bDomDec) niat = excl->nr; else niat = end; q2sumA = 0; q2sumB = 0; ener = 0; if (mdatoms->nChargePerturbed == 0) { for(i=start; i<niat; i++) { qiA = chargeA[i]; if (i < end) q2sumA += qiA*qiA; /* Do the exclusions */ j1 = excl->index[i]; j2 = excl->index[i+1]; for(j=j1; j<j2; j++) { k = AA[j]; if (k > i) { qqA = qiA*chargeA[k]; if (qqA != 0) { if (g) { rvec_sub(x[i],x[k],dx); ivec_sub(SHIFT_IVEC(g,i),SHIFT_IVEC(g,k),dt); ki=IVEC2IS(dt); } else if (bMolPBC) { ki = pbc_dx_aiuc(pbc,x[i],x[k],dx); } else rvec_sub(x[i],x[k],dx); ener += qqA*(ek*norm2(dx) - ec); svmul(-2*qqA*ek,dx,df); rvec_inc(f[i],df); rvec_dec(f[k],df); rvec_inc(fshift[ki],df); rvec_dec(fshift[CENTRAL],df); } } } } ener += -0.5*ec*q2sumA; } else { L1 = 1.0 - lambda; for(i=start; i<niat; i++) { qiA = chargeA[i]; qiB = chargeB[i]; if (i < end) { q2sumA += qiA*qiA; q2sumB += qiB*qiB; } /* Do the exclusions */ j1 = excl->index[i]; j2 = excl->index[i+1]; for(j=j1; j<j2; j++) { k = AA[j]; if (k > i) { qqA = qiA*chargeA[k]; qqB = qiB*chargeB[k]; if (qqA != 0 || qqB != 0) { qqL = L1*qqA + lambda*qqB; if (g) { rvec_sub(x[i],x[k],dx); ivec_sub(SHIFT_IVEC(g,i),SHIFT_IVEC(g,k),dt); ki=IVEC2IS(dt); } else if (bMolPBC) { ki = pbc_dx_aiuc(pbc,x[i],x[k],dx); } else rvec_sub(x[i],x[k],dx); v = ek*norm2(dx) - ec; ener += qqL*v; svmul(-2*qqL*ek,dx,df); rvec_inc(f[i],df); rvec_dec(f[k],df); rvec_inc(fshift[ki],df); rvec_dec(fshift[CENTRAL],df); *dvdlambda += (qqB - qqA)*v; } } } } ener += -0.5*ec*(L1*q2sumA + lambda*q2sumB); *dvdlambda += -0.5*ec*(q2sumB - q2sumA); } if (debug) fprintf(debug,"RF exclusion energy: %g\n",ener); return ener; }
real do_nonbonded_listed(int ftype, int nbonds, const t_iatom iatoms[], const t_iparams iparams[], const rvec x[], rvec f[], rvec fshift[], const t_pbc *pbc, const t_graph *g, real *lambda, real *dvdl, const t_mdatoms *md, const t_forcerec *fr, gmx_grppairener_t *grppener, int *global_atom_index) { int ielec, ivdw; real qq, c6, c12; rvec dx; ivec dt; int i, j, itype, ai, aj, gid; int fshift_index; real r2, rinv; real fscal, velec, vvdw; real * energygrp_elec; real * energygrp_vdw; static gmx_bool warned_rlimit = FALSE; /* Free energy stuff */ gmx_bool bFreeEnergy; real LFC[2], LFV[2], DLF[2], lfac_coul[2], lfac_vdw[2], dlfac_coul[2], dlfac_vdw[2]; real qqB, c6B, c12B, sigma2_def, sigma2_min; switch (ftype) { case F_LJ14: case F_LJC14_Q: energygrp_elec = grppener->ener[egCOUL14]; energygrp_vdw = grppener->ener[egLJ14]; break; case F_LJC_PAIRS_NB: energygrp_elec = grppener->ener[egCOULSR]; energygrp_vdw = grppener->ener[egLJSR]; break; default: energygrp_elec = NULL; /* Keep compiler happy */ energygrp_vdw = NULL; /* Keep compiler happy */ gmx_fatal(FARGS, "Unknown function type %d in do_nonbonded14", ftype); break; } if (fr->efep != efepNO) { /* Lambda factor for state A=1-lambda and B=lambda */ LFC[0] = 1.0 - lambda[efptCOUL]; LFV[0] = 1.0 - lambda[efptVDW]; LFC[1] = lambda[efptCOUL]; LFV[1] = lambda[efptVDW]; /*derivative of the lambda factor for state A and B */ DLF[0] = -1; DLF[1] = 1; /* precalculate */ sigma2_def = pow(fr->sc_sigma6_def, 1.0/3.0); sigma2_min = pow(fr->sc_sigma6_min, 1.0/3.0); for (i = 0; i < 2; i++) { lfac_coul[i] = (fr->sc_power == 2 ? (1-LFC[i])*(1-LFC[i]) : (1-LFC[i])); dlfac_coul[i] = DLF[i]*fr->sc_power/fr->sc_r_power*(fr->sc_power == 2 ? (1-LFC[i]) : 1); lfac_vdw[i] = (fr->sc_power == 2 ? (1-LFV[i])*(1-LFV[i]) : (1-LFV[i])); dlfac_vdw[i] = DLF[i]*fr->sc_power/fr->sc_r_power*(fr->sc_power == 2 ? (1-LFV[i]) : 1); } } else { sigma2_min = sigma2_def = 0; } bFreeEnergy = FALSE; for (i = 0; (i < nbonds); ) { itype = iatoms[i++]; ai = iatoms[i++]; aj = iatoms[i++]; gid = GID(md->cENER[ai], md->cENER[aj], md->nenergrp); /* Get parameters */ switch (ftype) { case F_LJ14: bFreeEnergy = (fr->efep != efepNO && ((md->nPerturbed && (md->bPerturbed[ai] || md->bPerturbed[aj])) || iparams[itype].lj14.c6A != iparams[itype].lj14.c6B || iparams[itype].lj14.c12A != iparams[itype].lj14.c12B)); qq = md->chargeA[ai]*md->chargeA[aj]*fr->epsfac*fr->fudgeQQ; c6 = iparams[itype].lj14.c6A; c12 = iparams[itype].lj14.c12A; break; case F_LJC14_Q: qq = iparams[itype].ljc14.qi*iparams[itype].ljc14.qj*fr->epsfac*iparams[itype].ljc14.fqq; c6 = iparams[itype].ljc14.c6; c12 = iparams[itype].ljc14.c12; break; case F_LJC_PAIRS_NB: qq = iparams[itype].ljcnb.qi*iparams[itype].ljcnb.qj*fr->epsfac; c6 = iparams[itype].ljcnb.c6; c12 = iparams[itype].ljcnb.c12; break; default: /* Cannot happen since we called gmx_fatal() above in this case */ qq = c6 = c12 = 0; /* Keep compiler happy */ break; } /* To save flops in the optimized kernels, c6/c12 have 6.0/12.0 derivative prefactors * included in the general nfbp array now. This means the tables are scaled down by the * same factor, so when we use the original c6/c12 parameters from iparams[] they must * be scaled up. */ c6 *= 6.0; c12 *= 12.0; /* Do we need to apply full periodic boundary conditions? */ if (fr->bMolPBC == TRUE) { fshift_index = pbc_dx_aiuc(pbc, x[ai], x[aj], dx); } else { fshift_index = CENTRAL; rvec_sub(x[ai], x[aj], dx); } r2 = norm2(dx); if (r2 >= fr->tab14.r*fr->tab14.r) { if (warned_rlimit == FALSE) { nb_listed_warning_rlimit(x, ai, aj, global_atom_index, sqrt(r2), fr->tab14.r); warned_rlimit = TRUE; } continue; } if (bFreeEnergy) { /* Currently free energy is only supported for F_LJ14, so no need to check for that if we got here */ qqB = md->chargeB[ai]*md->chargeB[aj]*fr->epsfac*fr->fudgeQQ; c6B = iparams[itype].lj14.c6B*6.0; c12B = iparams[itype].lj14.c12B*12.0; fscal = nb_free_energy_evaluate_single(r2, fr->sc_r_power, fr->sc_alphacoul, fr->sc_alphavdw, fr->tab14.scale, fr->tab14.data, qq, c6, c12, qqB, c6B, c12B, LFC, LFV, DLF, lfac_coul, lfac_vdw, dlfac_coul, dlfac_vdw, fr->sc_sigma6_def, fr->sc_sigma6_min, sigma2_def, sigma2_min, &velec, &vvdw, dvdl); } else { /* Evaluate tabulated interaction without free energy */ fscal = nb_evaluate_single(r2, fr->tab14.scale, fr->tab14.data, qq, c6, c12, &velec, &vvdw); } energygrp_elec[gid] += velec; energygrp_vdw[gid] += vvdw; svmul(fscal, dx, dx); /* Add the forces */ rvec_inc(f[ai], dx); rvec_dec(f[aj], dx); if (g) { /* Correct the shift forces using the graph */ ivec_sub(SHIFT_IVEC(g, ai), SHIFT_IVEC(g, aj), dt); fshift_index = IVEC2IS(dt); } if (fshift_index != CENTRAL) { rvec_inc(fshift[fshift_index], dx); rvec_dec(fshift[CENTRAL], dx); } } return 0.0; }
static void make_cyl_refgrps(t_commrec *cr, t_pull *pull, t_mdatoms *md, t_pbc *pbc, double t, rvec *x, rvec *xp) { int c, i, ii, m, start, end; rvec g_x, dx, dir; double r0_2, sum_a, sum_ap, dr2, mass, weight, wmass, wwmass, inp; t_pull_coord *pcrd; t_pull_group *pref, *pgrp, *pdyna; gmx_ga2la_t ga2la = NULL; if (pull->dbuf_cyl == NULL) { snew(pull->dbuf_cyl, pull->ncoord*4); } if (cr && DOMAINDECOMP(cr)) { ga2la = cr->dd->ga2la; } start = 0; end = md->homenr; r0_2 = dsqr(pull->cyl_r0); /* loop over all groups to make a reference group for each*/ for (c = 0; c < pull->ncoord; c++) { pcrd = &pull->coord[c]; /* pref will be the same group for all pull coordinates */ pref = &pull->group[pcrd->group[0]]; pgrp = &pull->group[pcrd->group[1]]; pdyna = &pull->dyna[c]; copy_rvec(pcrd->vec, dir); sum_a = 0; sum_ap = 0; wmass = 0; wwmass = 0; pdyna->nat_loc = 0; for (m = 0; m < DIM; m++) { g_x[m] = pgrp->x[m] - pcrd->vec[m]*(pcrd->init + pcrd->rate*t); } /* loop over all atoms in the main ref group */ for (i = 0; i < pref->nat; i++) { ii = pref->ind[i]; if (ga2la) { if (!ga2la_get_home(ga2la, pref->ind[i], &ii)) { ii = -1; } } if (ii >= start && ii < end) { pbc_dx_aiuc(pbc, x[ii], g_x, dx); inp = iprod(dir, dx); dr2 = 0; for (m = 0; m < DIM; m++) { dr2 += dsqr(dx[m] - inp*dir[m]); } if (dr2 < r0_2) { /* add to index, to sum of COM, to weight array */ if (pdyna->nat_loc >= pdyna->nalloc_loc) { pdyna->nalloc_loc = over_alloc_large(pdyna->nat_loc+1); srenew(pdyna->ind_loc, pdyna->nalloc_loc); srenew(pdyna->weight_loc, pdyna->nalloc_loc); } pdyna->ind_loc[pdyna->nat_loc] = ii; mass = md->massT[ii]; weight = get_weight(sqrt(dr2), pull->cyl_r1, pull->cyl_r0); pdyna->weight_loc[pdyna->nat_loc] = weight; sum_a += mass*weight*inp; if (xp) { pbc_dx_aiuc(pbc, xp[ii], g_x, dx); inp = iprod(dir, dx); sum_ap += mass*weight*inp; } wmass += mass*weight; wwmass += mass*sqr(weight); pdyna->nat_loc++; } } } pull->dbuf_cyl[c*4+0] = wmass; pull->dbuf_cyl[c*4+1] = wwmass; pull->dbuf_cyl[c*4+2] = sum_a; pull->dbuf_cyl[c*4+3] = sum_ap; } if (cr && PAR(cr)) { /* Sum the contributions over the nodes */ gmx_sumd(pull->ncoord*4, pull->dbuf_cyl, cr); } for (c = 0; c < pull->ncoord; c++) { pcrd = &pull->coord[c]; pdyna = &pull->dyna[c]; pgrp = &pull->group[pcrd->group[1]]; wmass = pull->dbuf_cyl[c*4+0]; wwmass = pull->dbuf_cyl[c*4+1]; pdyna->wscale = wmass/wwmass; pdyna->invtm = 1.0/(pdyna->wscale*wmass); for (m = 0; m < DIM; m++) { g_x[m] = pgrp->x[m] - pcrd->vec[m]*(pcrd->init + pcrd->rate*t); pdyna->x[m] = g_x[m] + pcrd->vec[m]*pull->dbuf_cyl[c*4+2]/wmass; if (xp) { pdyna->xp[m] = g_x[m] + pcrd->vec[m]*pull->dbuf_cyl[c*4+3]/wmass; } } if (debug) { fprintf(debug, "Pull cylinder group %d:%8.3f%8.3f%8.3f m:%8.3f\n", c, pdyna->x[0], pdyna->x[1], pdyna->x[2], 1.0/pdyna->invtm); } } }
void update_QMMMrec(t_commrec *cr, t_forcerec *fr, rvec x[], t_mdatoms *md, matrix box, gmx_localtop_t *top) { /* updates the coordinates of both QM atoms and MM atoms and stores * them in the QMMMrec. * * NOTE: is NOT yet working if there are no PBC. Also in ns.c, simple * ns needs to be fixed! */ int mm_max=0,mm_nr=0,mm_nr_new,i,j,is,k,shift; t_j_particle *mm_j_particles=NULL,*qm_i_particles=NULL; t_QMMMrec *qr; t_nblist QMMMlist; rvec dx,crd; int *MMatoms; t_QMrec *qm; t_MMrec *mm; t_pbc pbc; int *parallelMMarray=NULL; real c12au,c6au; c6au = (HARTREE2KJ*AVOGADRO*pow(BOHR2NM,6)); c12au = (HARTREE2KJ*AVOGADRO*pow(BOHR2NM,12)); /* every cpu has this array. On every processor we fill this array * with 1's and 0's. 1's indicate the atoms is a QM atom on the * current cpu in a later stage these arrays are all summed. indexes * > 0 indicate the atom is a QM atom. Every node therefore knows * whcih atoms are part of the QM subsystem. */ /* copy some pointers */ qr = fr->qr; mm = qr->mm; QMMMlist = fr->QMMMlist; /* init_pbc(box); needs to be called first, see pbc.h */ set_pbc_dd(&pbc,fr->ePBC,DOMAINDECOMP(cr) ? cr->dd : NULL,FALSE,box); /* only in standard (normal) QMMM we need the neighbouring MM * particles to provide a electric field of point charges for the QM * atoms. */ if(qr->QMMMscheme==eQMMMschemenormal){ /* also implies 1 QM-layer */ /* we NOW create/update a number of QMMMrec entries: * * 1) the shiftQM, containing the shifts of the QM atoms * * 2) the indexMM array, containing the index of the MM atoms * * 3) the shiftMM, containing the shifts of the MM atoms * * 4) the shifted coordinates of the MM atoms * * the shifts are used for computing virial of the QM/MM particles. */ qm = qr->qm[0]; /* in case of normal QMMM, there is only one group */ snew(qm_i_particles,QMMMlist.nri); if(QMMMlist.nri){ qm_i_particles[0].shift = XYZ2IS(0,0,0); for(i=0;i<QMMMlist.nri;i++){ qm_i_particles[i].j = QMMMlist.iinr[i]; if(i){ qm_i_particles[i].shift = pbc_dx_aiuc(&pbc,x[QMMMlist.iinr[0]], x[QMMMlist.iinr[i]],dx); } /* However, since nri >= nrQMatoms, we do a quicksort, and throw * out double, triple, etc. entries later, as we do for the MM * list too. */ /* compute the shift for the MM j-particles with respect to * the QM i-particle and store them. */ crd[0] = IS2X(QMMMlist.shift[i]) + IS2X(qm_i_particles[i].shift); crd[1] = IS2Y(QMMMlist.shift[i]) + IS2Y(qm_i_particles[i].shift); crd[2] = IS2Z(QMMMlist.shift[i]) + IS2Z(qm_i_particles[i].shift); is = XYZ2IS(crd[0],crd[1],crd[2]); for(j=QMMMlist.jindex[i]; j<QMMMlist.jindex[i+1]; j++){ if(mm_nr >= mm_max){ mm_max += 1000; srenew(mm_j_particles,mm_max); } mm_j_particles[mm_nr].j = QMMMlist.jjnr[j]; mm_j_particles[mm_nr].shift = is; mm_nr++; } } /* quicksort QM and MM shift arrays and throw away multiple entries */ qsort(qm_i_particles,QMMMlist.nri, (size_t)sizeof(qm_i_particles[0]), struct_comp); qsort(mm_j_particles,mm_nr, (size_t)sizeof(mm_j_particles[0]), struct_comp); /* remove multiples in the QM shift array, since in init_QMMM() we * went through the atom numbers from 0 to md.nr, the order sorted * here matches the one of QMindex already. */ j=0; for(i=0;i<QMMMlist.nri;i++){ if (i==0 || qm_i_particles[i].j!=qm_i_particles[i-1].j){ qm_i_particles[j++] = qm_i_particles[i]; } } mm_nr_new = 0; if(qm->bTS||qm->bOPT){ /* only remove double entries for the MM array */ for(i=0;i<mm_nr;i++){ if((i==0 || mm_j_particles[i].j!=mm_j_particles[i-1].j) && !md->bQM[mm_j_particles[i].j]){ mm_j_particles[mm_nr_new++] = mm_j_particles[i]; } } } /* we also remove mm atoms that have no charges! * actually this is already done in the ns.c */ else{ for(i=0;i<mm_nr;i++){ if((i==0 || mm_j_particles[i].j!=mm_j_particles[i-1].j) && !md->bQM[mm_j_particles[i].j] && (md->chargeA[mm_j_particles[i].j] || (md->chargeB && md->chargeB[mm_j_particles[i].j]))) { mm_j_particles[mm_nr_new++] = mm_j_particles[i]; } } } mm_nr = mm_nr_new; /* store the data retrieved above into the QMMMrec */ k=0; /* Keep the compiler happy, * shift will always be set in the loop for i=0 */ shift = 0; for(i=0;i<qm->nrQMatoms;i++){ /* not all qm particles might have appeared as i * particles. They might have been part of the same charge * group for instance. */ if (qm->indexQM[i] == qm_i_particles[k].j) { shift = qm_i_particles[k++].shift; } /* use previous shift, assuming they belong the same charge * group anyway, */ qm->shiftQM[i] = shift; } } /* parallel excecution */ if(PAR(cr)){ snew(parallelMMarray,2*(md->nr)); /* only MM particles have a 1 at their atomnumber. The second part * of the array contains the shifts. Thus: * p[i]=1/0 depending on wether atomnumber i is a MM particle in the QM * step or not. p[i+md->nr] is the shift of atomnumber i. */ for(i=0;i<2*(md->nr);i++){ parallelMMarray[i]=0; } for(i=0;i<mm_nr;i++){ parallelMMarray[mm_j_particles[i].j]=1; parallelMMarray[mm_j_particles[i].j+(md->nr)]=mm_j_particles[i].shift; } gmx_sumi(md->nr,parallelMMarray,cr); mm_nr=0; mm_max = 0; for(i=0;i<md->nr;i++){ if(parallelMMarray[i]){ if(mm_nr >= mm_max){ mm_max += 1000; srenew(mm->indexMM,mm_max); srenew(mm->shiftMM,mm_max); } mm->indexMM[mm_nr] = i; mm->shiftMM[mm_nr++]= parallelMMarray[i+md->nr]/parallelMMarray[i]; } } mm->nrMMatoms=mm_nr; free(parallelMMarray); } /* serial execution */ else{ mm->nrMMatoms = mm_nr; srenew(mm->shiftMM,mm_nr); srenew(mm->indexMM,mm_nr); for(i=0;i<mm_nr;i++){ mm->indexMM[i]=mm_j_particles[i].j; mm->shiftMM[i]=mm_j_particles[i].shift; } } /* (re) allocate memory for the MM coordiate array. The QM * coordinate array was already allocated in init_QMMM, and is * only (re)filled in the update_QMMM_coordinates routine */ srenew(mm->xMM,mm->nrMMatoms); /* now we (re) fill the array that contains the MM charges with * the forcefield charges. If requested, these charges will be * scaled by a factor */ srenew(mm->MMcharges,mm->nrMMatoms); for(i=0;i<mm->nrMMatoms;i++){/* no free energy yet */ mm->MMcharges[i]=md->chargeA[mm->indexMM[i]]*mm->scalefactor; } if(qm->bTS||qm->bOPT){ /* store (copy) the c6 and c12 parameters into the MMrec struct */ srenew(mm->c6,mm->nrMMatoms); srenew(mm->c12,mm->nrMMatoms); for (i=0;i<mm->nrMMatoms;i++){ mm->c6[i] = C6(fr->nbfp,top->idef.atnr, md->typeA[mm->indexMM[i]], md->typeA[mm->indexMM[i]])/c6au; mm->c12[i] =C12(fr->nbfp,top->idef.atnr, md->typeA[mm->indexMM[i]], md->typeA[mm->indexMM[i]])/c12au; } punch_QMMM_excl(qr->qm[0],mm,&(top->excls)); } /* the next routine fills the coordinate fields in the QMMM rec of * both the qunatum atoms and the MM atoms, using the shifts * calculated above. */ update_QMMM_coord(x,fr,qr->qm[0],qr->mm); free(qm_i_particles); free(mm_j_particles); } else { /* ONIOM */ /* ????? */ mm->nrMMatoms=0; /* do for each layer */ for (j=0;j<qr->nrQMlayers;j++){ qm = qr->qm[j]; qm->shiftQM[0]=XYZ2IS(0,0,0); for(i=1;i<qm->nrQMatoms;i++){ qm->shiftQM[i] = pbc_dx_aiuc(&pbc,x[qm->indexQM[0]],x[qm->indexQM[i]], dx); } update_QMMM_coord(x,fr,qm,mm); } } } /* update_QMMM_rec */
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; }
static void do_lincsp(rvec *x,rvec *f,rvec *fp,t_pbc *pbc, struct gmx_lincsdata *lincsd,real *invmass, int econq,real *dvdlambda, gmx_bool bCalcVir,tensor rmdf) { int b,i,j,k,n; real tmp0,tmp1,tmp2,im1,im2,mvb,rlen,len,wfac,lam; rvec dx; int ncons,*bla,*blnr,*blbnb; rvec *r; real *blc,*blmf,*blcc,*rhs1,*rhs2,*sol; ncons = lincsd->nc; bla = lincsd->bla; r = lincsd->tmpv; blnr = lincsd->blnr; blbnb = lincsd->blbnb; if (econq != econqForce) { /* Use mass-weighted parameters */ blc = lincsd->blc; blmf = lincsd->blmf; } else { /* Use non mass-weighted parameters */ blc = lincsd->blc1; blmf = lincsd->blmf1; } blcc = lincsd->tmpncc; rhs1 = lincsd->tmp1; rhs2 = lincsd->tmp2; sol = lincsd->tmp3; if (econq != econqForce) { dvdlambda = NULL; } /* Compute normalized i-j vectors */ if (pbc) { for(b=0; b<ncons; b++) { pbc_dx_aiuc(pbc,x[bla[2*b]],x[bla[2*b+1]],dx); unitv(dx,r[b]); } } else { for(b=0; b<ncons; b++) { rvec_sub(x[bla[2*b]],x[bla[2*b+1]],dx); unitv(dx,r[b]); } /* 16 ncons flops */ } for(b=0; b<ncons; b++) { tmp0 = r[b][0]; tmp1 = r[b][1]; tmp2 = r[b][2]; i = bla[2*b]; j = bla[2*b+1]; for(n=blnr[b]; n<blnr[b+1]; n++) { k = blbnb[n]; blcc[n] = blmf[n]*(tmp0*r[k][0] + tmp1*r[k][1] + tmp2*r[k][2]); } /* 6 nr flops */ mvb = blc[b]*(tmp0*(f[i][0] - f[j][0]) + tmp1*(f[i][1] - f[j][1]) + tmp2*(f[i][2] - f[j][2])); rhs1[b] = mvb; sol[b] = mvb; /* 7 flops */ } /* Together: 23*ncons + 6*nrtot flops */ lincs_matrix_expand(lincsd,blcc,rhs1,rhs2,sol); /* nrec*(ncons+2*nrtot) flops */ if (econq != econqForce) { for(b=0; b<ncons; b++) { /* With econqDeriv_FlexCon only use the flexible constraints */ if (econq != econqDeriv_FlexCon || (lincsd->bllen0[b] == 0 && lincsd->ddist[b] == 0)) { i = bla[2*b]; j = bla[2*b+1]; mvb = blc[b]*sol[b]; im1 = invmass[i]; im2 = invmass[j]; tmp0 = r[b][0]*mvb; tmp1 = r[b][1]*mvb; tmp2 = r[b][2]*mvb; fp[i][0] -= tmp0*im1; fp[i][1] -= tmp1*im1; fp[i][2] -= tmp2*im1; fp[j][0] += tmp0*im2; fp[j][1] += tmp1*im2; fp[j][2] += tmp2*im2; if (dvdlambda) { /* This is only correct with forces and invmass=1 */ *dvdlambda -= mvb*lincsd->ddist[b]; } } } /* 16 ncons flops */ } else { for(b=0; b<ncons; b++) { i = bla[2*b]; j = bla[2*b+1]; mvb = blc[b]*sol[b]; tmp0 = r[b][0]*mvb; tmp1 = r[b][1]*mvb; tmp2 = r[b][2]*mvb; fp[i][0] -= tmp0; fp[i][1] -= tmp1; fp[i][2] -= tmp2; fp[j][0] += tmp0; fp[j][1] += tmp1; fp[j][2] += tmp2; if (dvdlambda) { *dvdlambda -= mvb*lincsd->ddist[b]; } } /* 10 ncons flops */ } if (bCalcVir) { /* Constraint virial, * determines sum r_bond x delta f, * where delta f is the constraint correction * of the quantity that is being constrained. */ for(b=0; b<ncons; b++) { mvb = lincsd->bllen[b]*blc[b]*sol[b]; for(i=0; i<DIM; i++) { tmp1 = mvb*r[b][i]; for(j=0; j<DIM; j++) { rmdf[i][j] += tmp1*r[b][j]; } } } /* 23 ncons flops */ } }
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,t_pbc *pbc, real lambda,real *dvdlambda, real invdt,rvec *v, gmx_bool bCalcVir,tensor vir_r_m_dr, 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=0; 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; } 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,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, &ncons_loc,&p_ssd,&p_max,&p_imax); } /* This warn var can be updated by multiple threads * at the same time. But as we only need to detect * if a warning occured or not, this is not an issue. */ warn = -1; /* The OpenMP parallel region of constrain_lincs for coords */ #pragma omp parallel num_threads(lincsd->nth) { int th=gmx_omp_get_thread_num(); clear_mat(lincsd->th[th].vir_r_m_dr); do_lincs(x,xprime,box,pbc,lincsd,th, md->invmass,cr, bCalcVir || (ir->efep != efepNO), ir->LincsWarnAngle,&warn, invdt,v,bCalcVir, th==0 ? vir_r_m_dr : lincsd->th[th].vir_r_m_dr); } 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->mlambda[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, &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, &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, 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 { /* The OpenMP parallel region of constrain_lincs for derivatives */ #pragma omp parallel num_threads(lincsd->nth) { int th=gmx_omp_get_thread_num(); do_lincsp(x,xprime,min_proj,pbc,lincsd,th, md->invmass,econq,ir->efep != efepNO ? dvdlambda : NULL, bCalcVir,th==0 ? vir_r_m_dr : lincsd->th[th].vir_r_m_dr); } } if (bCalcVir && lincsd->nth > 1) { for(i=1; i<lincsd->nth; i++) { m_add(vir_r_m_dr,lincsd->th[i].vir_r_m_dr,vir_r_m_dr); } } /* 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; }